fix(responses): attribute per-PK telemetry tags on /v1/responses usage events - #646
Conversation
…e events Codex talks to the gateway over /v1/responses, and its dashboard Logs rows were missing the provider attribution that Claude-Code (/v1/messages) rows show: provider_kind, provider_featured, branded_provider, and pk_label. The /v1/responses usage-event helpers left those five fields at default — they were wired for the chat surface only. Resolve the winning target's ProviderKey telemetry_tags from the snapshot (same lookup as /v1/messages and /v1/chat/completions) and populate them on every emit path: the non-streaming handler emit, the verbatim and cross-provider streaming Drop guards, and the failed-attempt zero-token events. The dispatch loop now records each attempt's provider_key_id so failed attempts attribute it too. Integration tests cover the streaming (Codex's always-streaming path) and non-streaming OpenAI paths, asserting the emitted UsageEvent carries the resolved PK's tags; both fail before the fix and pass after. Fixes api7/AISIX-Cloud#867
📝 WalkthroughWalkthrough
ChangesProvider-key telemetry propagation
Sequence Diagram(s)sequenceDiagram
participant emit_usage_event
participant emit_zero_token_event
participant provider_telemetry_tags
participant sanitize_tag
participant UsageEvent
emit_usage_event->>provider_telemetry_tags: provider_key_id
provider_telemetry_tags-->>emit_usage_event: telemetry_tags
emit_usage_event->>sanitize_tag: provider_kind / provider_featured / branded_provider / pk_label / byo_label
sanitize_tag-->>emit_usage_event: sanitized labels
emit_usage_event->>UsageEvent: set provider attribution fields
emit_zero_token_event->>provider_telemetry_tags: provider_key_id
provider_telemetry_tags-->>emit_zero_token_event: telemetry_tags
emit_zero_token_event->>sanitize_tag: provider_kind / provider_featured / branded_provider / pk_label / byo_label
sanitize_tag-->>emit_zero_token_event: sanitized labels
emit_zero_token_event->>UsageEvent: set provider attribution fields
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes 🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
crates/aisix-proxy/src/responses.rs (1)
3327-3453: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd coverage for the other changed attribution paths.
These tests pin OpenAI success events, but the PR also changed bridged streaming and failed-attempt zero-token attribution. Add a tagged cross-provider case and a tagged upstream-failure case so Lines 1153 and 1757 are exercised too.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/aisix-proxy/src/responses.rs` around lines 3327 - 3453, The current tests only cover OpenAI success attribution in the `/v1/responses` path, but they miss the other changed telemetry branches. Add a tagged cross-provider test for the bridged streaming path and a tagged upstream-failure test for zero-token attribution, using the same `UsageSink`/`ProxyState` setup pattern so the updated provider telemetry is exercised. Anchor the new coverage around the `/v1/responses` handler flow and the existing response-event assertions so the changed bridged streaming and failed-attempt paths are verified too.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/aisix-proxy/src/responses.rs`:
- Around line 1648-1649: The streaming usage emitters are re-resolving provider
tags at completion time via provider_telemetry_tags, which can misattribute logs
if the snapshot changes mid-flight. Update the dispatch path in responses.rs to
resolve and store the TelemetryTags together with provider_key_id when the
target is created, then thread those frozen tags through the usage/event
emitters instead of calling snapshot.load() again. Use the existing
target-dispatch flow around provider_key_id and TelemetryTags to locate the
change.
---
Nitpick comments:
In `@crates/aisix-proxy/src/responses.rs`:
- Around line 3327-3453: The current tests only cover OpenAI success attribution
in the `/v1/responses` path, but they miss the other changed telemetry branches.
Add a tagged cross-provider test for the bridged streaming path and a tagged
upstream-failure test for zero-token attribution, using the same
`UsageSink`/`ProxyState` setup pattern so the updated provider telemetry is
exercised. Anchor the new coverage around the `/v1/responses` handler flow and
the existing response-event assertions so the changed bridged streaming and
failed-attempt paths are verified too.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: d9d17f9b-1fd2-4221-8c9b-ea571902a45d
📒 Files selected for processing (1)
crates/aisix-proxy/src/responses.rs
Problem
Codex talks to the gateway over
/v1/responses. After #613 made streaming/v1/responsescalls log at all, their dashboard Logs rows were still missing the provider attribution that Claude-Code (/v1/messages) rows carry —服务商类型(provider_kind),品牌服务商(branded_provider), andPK 标签(pk_label).claude-codelogs show them;codexlogs show none.Root cause
The
/v1/responsesusage-event helpers (emit_usage_event/emit_zero_token_event) left the five per-PK telemetry attribution fields —provider_kind,provider_featured,branded_provider,pk_label,byo_label— atDefault. They were wired for the chat surface only; the responses handler never resolved the target's ProviderKeytelemetry_tags. These fields reach cp-api (and the dashboard'sdpmgr_usage_events-backed Logs) via the usage-sink POST.Fix
Resolve the winning target's ProviderKey
telemetry_tagsfrom the live snapshot — the same lookup/v1/messagesand/v1/chat/completionsalready do — and populate the fields on every emit path:provider_key_idonResponseDispatchSuccess),The dispatch loop now records each attempt's
provider_key_idon itsAttemptRecord, so failed attempts attribute it too. A smallprovider_telemetry_tagshelper shares the snapshot lookup between the two emit helpers; an empty/unknownprovider_key_id(pre-dispatch error) yields all-empty tags → wire NULL, matching the chat/messages contract.Behavior change
/v1/responsesusage events now carry the upstream vendor + PK label, so Codex logs match Claude-Code logs. No wire/schema change — the cp-api columns already exist; they were simply never filled by this endpoint.Tests
Integration tests (real router + OpenAI bridge + mock upstream + usage sink) assert the emitted
UsageEventcarries the resolved PK's tags, on both the streaming path (Codex's always-streaming path) and the non-streaming path. Both fail before the fix (empty tags) and pass after.E2E note: these attribution tags don't traverse the OTLP fan-out the standalone DP E2E harness observes (the OTLP encoder is an intentional allowlist, shared with chat/messages, that excludes them) — they only reach cp-api via the usage-sink POST, which the standalone harness doesn't receive. This matches how the original telemetry-attribution feature (chat/messages) was tested: Rust integration tests, no standalone E2E.
Fixes api7/AISIX-Cloud#867
Summary by CodeRabbit
Bug Fixes
/v1/responsesusage telemetry so events now include the correct provider attribution tags more consistently.Tests
/v1/responsesto verify usage events include the correct provider kind, featured status, branding, and label fields.