Supervisor Observability Integration
This document explains how to consume Stimm supervisor observability logs from an integration.
Scope
Applies to logs emitted by ConversationSupervisor in src/stimm/conversation_supervisor.py.
The supervisor now emits machine-parseable JSON lines prefixed with OBS_JSON.
Log line format
Each observability line looks like:
... INFO ... OBS_JSON {"component":"conversation_supervisor","event":"inference_started",...}
Parsing rule:
- Keep only lines containing
OBS_JSON(with trailing space). - Extract the substring after
OBS_JSON. - Parse that substring as JSON.
Event model
All events share these base fields:
component(string): alwaysconversation_supervisorevent(string): event namets_ms(int): Unix epoch timestamp in millisecondsinference_seq(int): monotonically increasing sequence per supervisor instance
inference_started
When a supervisor inference starts.
Additional fields:
history_len(int): number of turns currently in supervisor historyprocessed_up_to(int): history index snapshot used for this inference
inference_completed
When a supervisor inference returns and is parsed.
Additional fields:
latency_ms(int): end-to-end backend latency measured by supervisorstructured_json(bool): whether parsing indicates a structured JSON responseaction(string): parsed decision action (TRIGGERorNO_ACTION)reason(string): parse/backend reason (empty string when absent)
no_action
Emitted when decision action is not TRIGGER.
No extra fields.
trigger_sent
Emitted after a trigger is pushed to the voice agent context.
Additional fields:
text_chars(int): trigger text lengthpreview(string): first 120 chars of trigger text
Correlation
Use (component, inference_seq) as the primary correlation key for one inference lifecycle:
inference_startedinference_completed- optional
no_actionortrigger_sent
Minimal state machine
For each inference_seq:
- On
inference_started: createrunningrecord - On
inference_completed: storelatency_ms,structured_json,action,reason - On
trigger_sent: mark outcometriggered - On
no_action: mark outcomeno_action
Practical alerts
You can implement simple counters/windows in your app logs processor:
- High
structured_json=falseratio over last N inferences - Missing terminal event (
trigger_sent/no_action) afterinference_completed - Repeated high
latency_msoutliers
Python parsing example
import json
def iter_supervisor_events(lines):
marker = "OBS_JSON "
for line in lines:
idx = line.find(marker)
if idx == -1:
continue
payload = line[idx + len(marker):].strip()
try:
event = json.loads(payload)
except json.JSONDecodeError:
continue
if event.get("component") == "conversation_supervisor":
yield event
Node.js parsing example
function* iterSupervisorEvents(lines) {
const marker = 'OBS_JSON ';
for (const line of lines) {
const idx = line.indexOf(marker);
if (idx === -1) continue;
const payload = line.slice(idx + marker.length).trim();
let evt;
try {
evt = JSON.parse(payload);
} catch {
continue;
}
if (evt.component === 'conversation_supervisor') {
yield evt;
}
}
}
Compatibility notes
- Unknown fields should be ignored by consumers.
- New event types may be added in the future; unknown
eventvalues should not break parsing. previewis informational only and should not be treated as full content.