Summary
Every streaming request is persisted to requests_log with latency_ms = 0, silently poisoning the p50/p99 numbers in GET /v1/analytics/latency and any latency-based routing narrative. Cache hits log 0 as well.
Root cause chain
- The adapter deliberately does not attach
_orca_meta to streams (packages/litellm_adapter/client.py:197-204 — stream wrappers aren't dicts; documented tradeoff).
- So in the SSE aggregator,
agg_latency stays at its initial value 0 (app/routes/chat.py:486) — nothing ever updates it.
- The synthetic meta therefore always includes the key:
"latency_ms": agg_latency (chat.py:524).
_build_log_row then does meta.get("latency_ms", latency_ms) (chat.py:156). Because the key is present with value 0, the default isn't taken and the real measured latency computed three lines above (chat.py:133, wall-clock of the whole request) is discarded.
The cache-hit path hardcodes the same zero (chat.py:423: "_orca_meta": {"provider": "cache", "latency_ms": 0}), so serving from cache also logs 0 ms instead of the measured serve time.
Impact
/v1/analytics/latency percentiles dragged toward zero as streaming share grows — the dashboard's core performance tile lies.
- Any future "fastest provider" logic trained on this column inherits the bias.
Proposed fix
One-line semantic change at the merge point:
latency_ms=meta.get("latency_ms") or latency_ms,
…plus the same treatment for the cache-hit synthetic meta (simply omit the zero, letting the measured value win). or (not is None) is intentional: both known-bad producers emit literal 0.
Acceptance criteria
Summary
Every streaming request is persisted to
requests_logwithlatency_ms = 0, silently poisoning the p50/p99 numbers inGET /v1/analytics/latencyand any latency-based routing narrative. Cache hits log 0 as well.Root cause chain
_orca_metato streams (packages/litellm_adapter/client.py:197-204— stream wrappers aren't dicts; documented tradeoff).agg_latencystays at its initial value0(app/routes/chat.py:486) — nothing ever updates it."latency_ms": agg_latency(chat.py:524)._build_log_rowthen doesmeta.get("latency_ms", latency_ms)(chat.py:156). Because the key is present with value0, the default isn't taken and the real measured latency computed three lines above (chat.py:133, wall-clock of the whole request) is discarded.The cache-hit path hardcodes the same zero (
chat.py:423:"_orca_meta": {"provider": "cache", "latency_ms": 0}), so serving from cache also logs 0 ms instead of the measured serve time.Impact
/v1/analytics/latencypercentiles dragged toward zero as streaming share grows — the dashboard's core performance tile lies.Proposed fix
One-line semantic change at the merge point:
…plus the same treatment for the cache-hit synthetic meta (simply omit the zero, letting the measured value win).
or(notis None) is intentional: both known-bad producers emit literal0.Acceptance criteria
_orca_meta.latency_mskeep using it (regression guard).