admin

Get Performance Analytics

System-wide pause-latency aggregates, grouped by (language, had_image, eou_backend, stt_provider).

Pause anchor: actual_pause_ms (ground truth, anchored on the user's last-word end, computed post-hoc by agent/actual_eou.py) when present; falls back to pause_ms (framework-estimated, anchored on the EOU decision moment) when not. The pct_truth_anchored column shows what fraction of each bucket's turns are on the truth-anchored value vs the estimate-anchored fallback — 100% means fully trustworthy comparison.

Bucket decomposition (same as the per-conversation UI in web/src/lib/timingBreakdown.ts): recognition = max(eou_delay_ms, transcription_delay_ms) ← they overlap hook = on_user_turn_completed_delay_ms llm_ttft = llm_ttft_ms tts_ttfb = tts_ttfb_ms residual = pause_authoritative − (recognition + hook + ttft + ttfb)

Also returns EOU-effectiveness signals — the only way to evaluate whether a turn-taking change actually helped without trading pause for cutoffs: avg_estimation_error_ms — signed avg(eou_estimation_error_ms) (>0 = waited past real end; <0 = cut off) p5/p95 estimation error — the distribution shape, since the mean alone hides cut-offs hiding under late waits cutoff_rate — fraction of turns flagged was_premature_jump_in by the agent's post-hoc tagging pass

eou_estimation_error_ms and was_premature_jump_in come from agent/actual_eou.py's ground-truth pass on the settled STT transcript (last-word timestamp = true end of speech). Older turns lacking the post-hoc pass simply contribute NULLs to the means; cutoff_rate counts NULL as not-a-cutoff (conservative).

eou_backend is read from telemetry.eou_effective.backend (the resolved per-session value, respects template overrides — added in PR #598). For sessions predating that field, falls back to the system-wide telemetry.audio_config_at_session_start.eou.turn_detector_backend. Final default is 'text' (the only historical option).

Aggregation is on-demand over the existing sessions.transcript JSONB + telemetry — no new tables, no backfill. If the JSONB scan becomes slow at scale, materialise into a rollup table; until then this is the simplest correct thing.

Sessions without a recorded telemetry.stt_config.language are excluded (per the plan — they would group under unknown which isn't actionable).

Param days is "7" | "30" | "all"; default 7.

get/v1/admin/performance

Query parameters

daysstring

Response

Successful Response

{"stackTrail":"paths:/v1/admin/performance:get:responses:200:content:application/json:schema","oasType":"schema","type":"unknown"}

Changes

No recorded changes to this endpoint across all 1 revision of this API.