feat(obs): record the model that answered, not only the backend dialled #137
No reviewers
Labels
No labels
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/agent-proxy!137
Loading…
Reference in a new issue
No description provided.
Delete branch "task/served-model-attribute"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #136.
The correction that made this a one-liner
I filed #136 saying nothing records which backend served. That was imprecise, and reading the code fixed it:
agentproxy.backendalready exists and dispatch stamps it fromresult.served_by.It is the right answer for a route this proxy load-balances across its own chain. It cannot answer for a route it forwards.
sirens-echo/deepseekisdirect: nullwith anupstream_alias, so the chain is one hop andagentproxy.backendnames the upstream regardless of which model actually ran.coilyco-bridge/deploy#681 puts a Baseten fallback behind that route inside LiteLLM. From here those two backends are the same hop, so a turn served by the fallback and one served by the primary were indistinguishable in this proxy's telemetry.
The fix
The response already carries the answer, and
upstream.pyalready parses it intoresult.model. It was simply never emitted, whilegen_ai.request.modelis. So this is the sibling attribute under the same OTel GenAI convention, not a new concept:Omitted when upstream names no model, so an absent attribute stays a fact rather than an empty string.
Why it earns the line
deploy#681 measures 1.23s time to first token on first-party DeepSeek against 8.44s on Baseten, and the sirens lanes make short, TTFT-dominated turns. Without this a failover reads as a sevenfold latency regression, with nothing in this proxy's data separating "we failed over, as designed" from "the primary degraded" — at exactly the moment nobody has time to correlate LiteLLM logs by hand.
Tests
Two, in the existing
set_result_span_attributesidiom:agentproxy.backend, asserting both, because they are different facts and a LiteLLM fallback moves only the secondjust test402 passed,just lintclean.Scope
One attribute. No metric, no dashboard, no change to what is dialled or how failover behaves. Deciding what to chart from it is separate work.
Related: coilyco-bridge/deploy#681, coilyco-bridge/deploy#684, coilyco-bridge/deploy#685.