Repository navigation
fix: decode OpenRouter usage cost fields in ChatResponse.Usage - #50
Conversation
Extend ChatResponse.Usage to decode cost, cost_details, and prompt_tokens_details that OpenRouter returns on chat completions. These fields were previously silently dropped during JSON decoding. - Add optional cost (Double?) for credits charged per request - Add CostDetails nested type for upstream inference cost breakdown - Add PromptTokensDetails for cached/audio/video prompt token counts - Mirror new fields on StreamingDelta.Usage via shared nested types - Add UsageCostTests with representative OpenRouter response fixture Fixes #49 Co-authored-by: Aditya Dhar <[email protected]>
📝 WalkthroughWalkthrough
ChangesUsage Cost & Token Breakdown
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Extend ChatResponse.Usage.OutputTokensDetails with optional audio_tokens and image_tokens fields returned by OpenRouter. StreamingDelta.Usage reuses the shared OutputTokensDetails type. Co-authored-by: Aditya Dhar <[email protected]>
Assert that a simple non-streaming text chat completion returns usage with a non-nil cost field from the OpenRouter API. Co-authored-by: Aditya Dhar <[email protected]>
|
@CodeRabbit review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
🧹 Nitpick comments (1)
Tests/OpenRouterKitTests/UsageCostTests.swift (1)
102-108: ⚡ Quick winAssert missing
completion_tokens_detailsin the backward-compat test.
decodesWithoutCostFieldsvalidates other new optionals asnil, but it skipscompletion_tokens_details. Adding this assertion tightens compatibility coverage for the expandedUsageshape.Proposed patch
`#expect`(usage.cost == nil) `#expect`(usage.cost_details == nil) `#expect`(usage.prompt_tokens_details == nil) + `#expect`(usage.completion_tokens_details == nil)🤖 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 `@Tests/OpenRouterKitTests/UsageCostTests.swift` around lines 102 - 108, The decodesWithoutCostFields test is missing an assertion for the completion_tokens_details field. Add a `#expect`(usage.completion_tokens_details == nil) assertion alongside the existing nil checks for cost, cost_details, and prompt_tokens_details to ensure complete backward compatibility coverage for the expanded Usage shape.
🤖 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.
Nitpick comments:
In `@Tests/OpenRouterKitTests/UsageCostTests.swift`:
- Around line 102-108: The decodesWithoutCostFields test is missing an assertion
for the completion_tokens_details field. Add a
`#expect`(usage.completion_tokens_details == nil) assertion alongside the existing
nil checks for cost, cost_details, and prompt_tokens_details to ensure complete
backward compatibility coverage for the expanded Usage shape.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 0ee76bfa-cf6e-497c-b68f-dc18ab0bbbb0
📒 Files selected for processing (3)
Sources/OpenRouterKit/Models/Chat/ChatResponse.swiftSources/OpenRouterKit/Models/Chat/StreamingDelta.swiftTests/OpenRouterKitTests/UsageCostTests.swift
Summary
Fixes #49 by extending
ChatResponse.Usageto decode inlinecost,cost_details, andprompt_tokens_detailsfields that OpenRouter already returns on chat completion responses. Previously these fields were silently dropped during JSON decoding (same class of bug as openrouter-python-sdk#65).This is the upstream prerequisite for accurate per-call cost capture in maia-server observability.
Changes
ChatResponse.Usage— added optionalcost,cost_details, andprompt_tokens_detailswith nestedCostDetailsandPromptTokensDetailstypesStreamingDelta.Usage— mirrors the same fields using shared nested types fromChatResponse.Usage(passive decoding only; no streaming behavior changes)UsageCostTests— new unit tests with a representative OpenRouter response fixture proving cost fields decode correctly, plus backward-compat test for responses without cost fieldsAcceptance criteria
ChatResponse.Usagedecodescost(nullable)ChatResponse.Usagedecodescost_detailswhen presentChatResponse.Usagedecodesprompt_tokens_details(cached/audio tokens) when presentcostis decoded from a representative OpenRouter chat response fixtureOut of scope (per issue)
StreamingDelta.Usage)is_byok,server_tool_use, and extendedcompletion_tokens_detailsfields (audio/image tokens)Test plan
swift test --parallel— all 180 tests passswiftlinton changed files — 0 violationsSummary by CodeRabbit
Release Notes