TurnMetricsCollector
Collects per-turn timing marks and emits a TurnMetricsSummary when each turn finishes.
Defined in: src/core/pipeline/TurnMetrics.ts:206
Collects per-turn timing marks and emits a TurnMetricsSummary when each turn finishes.
Remarks
The collector is deliberately forgiving about call order:
- Marks with no active turn are routed to the pending-eager buffer when a preflight was marked, and dropped otherwise (e.g. greeting audio from an agent provider).
- “First” marks (
llmStart,llmFirstToken,ttsFirstAudio,playbackStart) are first-write-wins, so streaming loops can call them unconditionally per chunk. - “Last” marks (
llmComplete,playbackEnd) overwrite, so multi-round tool loops and bursty playback report their final occurrence. - Starting a new turn while one is active finishes the old turn as
interrupted— barge-in needs no special handling at call sites.
Example
const collector = new TurnMetricsCollector((summary) => {
console.log(`turn ${summary.turnId}: ${summary.durations.voiceToVoice}ms voice-to-voice`);
});
collector.startTurn('what time is it', { modality: 'voice' });
collector.markLLMStart();
collector.markLLMFirstToken();
collector.markTTSFirstAudio();
collector.markPlaybackStart();
collector.finishTurn(); // emits the summary
Constructors
Constructor
new TurnMetricsCollector(onSummary, now?): TurnMetricsCollector;
Defined in: src/core/pipeline/TurnMetrics.ts:217
Parameters
| Parameter | Type | Default value | Description |
|---|---|---|---|
onSummary | (summary) => void | undefined | Invoked once per finished turn with the computed summary. |
now | () => number | Date.now | Clock function, injectable for tests. Defaults to Date.now. |
Returns
TurnMetricsCollector
Accessors
hasActiveTurn
Get Signature
get hasActiveTurn(): boolean;
Defined in: src/core/pipeline/TurnMetrics.ts:223
Whether a turn is currently in progress.
Returns
boolean
Methods
abortTurn()
abortTurn(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:361
Finish the active turn as interrupted and emit its summary.
Returns
void
Remarks
Used for barge-in, stopSpeaking(), and pipeline errors. No-op when no turn is active.
finishTurn()
finishTurn(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:350
Finish the active turn as completed and emit its summary.
Returns
void
markLLMComplete()
markLLMComplete(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:311
Record LLM generation completion (last-write-wins).
Returns
void
markLLMFirstToken()
markLLMFirstToken(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:303
Record first LLM token arrival (first-write-wins).
Returns
void
markLLMStart()
markLLMStart(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:295
Record LLM request dispatch (first-write-wins).
Returns
void
markPlaybackEnd()
markPlaybackEnd(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:342
Record playback ending (last-write-wins).
Returns
void
Remarks
Output providers can report several start/end cycles within one turn when synthesis is slower than playback, so this does not finish the turn — finishTurn does, driven by the pipeline.
markPlaybackStart()
markPlaybackStart(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:327
Record audible playback start (first-write-wins).
Returns
void
markPreflight()
markPreflight(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:240
Record a preflight (early end-of-turn) signal.
Returns
void
Remarks
Opens a fresh pending-eager buffer; a subsequent eager LLM generation’s marks accumulate there until startTurn adopts or discards them.
Providers can emit several preflights for one utterance. Later ones move the mark while the buffer is still empty, but once an eager generation has recorded a mark the buffer is frozen: that generation is still running, and its first-write-wins marks will not fire again, so replacing the buffer would lose them for good.
markTTSFirstAudio()
markTTSFirstAudio(): void;
Defined in: src/core/pipeline/TurnMetrics.ts:319
Record first TTS audio chunk arrival (first-write-wins).
Returns
void
startTurn()
startTurn(transcript, options): void;
Defined in: src/core/pipeline/TurnMetrics.ts:266
Start a new turn, anchored at the current time.
Parameters
| Parameter | Type | Description |
|---|---|---|
transcript | string | The user text that starts the turn. |
options | { adoptEager?: boolean; modality: "voice" | "text"; } | Turn modality and whether to adopt buffered eager marks. |
options.adoptEager? | boolean | - |
options.modality | "voice" | "text" | - |
Returns
void
Remarks
If a turn is already active it is finished as interrupted first. With adoptEager: true, every mark buffered since the last markPreflight is copied into the new turn (this is how an accepted eager generation’s llmFirstToken can precede sttFinal, and how a generation that finished before confirmation still reports llmComplete / playback). The buffered preflight timestamp is carried over either way — the early end-of-turn signal describes this utterance whether or not a speculative generation ran on it, or was accepted. The pending-eager buffer is cleared either way — a new turn always invalidates old speculative marks.