Skip to content

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

ParameterTypeDefault valueDescription
onSummary(summary) => voidundefinedInvoked once per finished turn with the computed summary.
now() => numberDate.nowClock 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

ParameterTypeDescription
transcriptstringThe 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.

© 2026 CompositeVoice. All rights reserved.

Font size
Contrast
Motion
Transparency