Parent issue
#756
Depends on
#759
Context
The Agent SDK SDKResultSuccess message includes full token usage (BetaUsage shape) and subscription_type. This maps cleanly to ApiStreamUsageChunk. Pattern mirrors normalizeUsage() in OpenAiCodexHandler, with the addition of subscription-type-aware cost reporting.
Files
src/api/providers/claude-code.ts (extend)
src/api/providers/__tests__/claude-code-usage.spec.ts (new)
Work
private normalizeUsage(result: SDKResultSuccess): ApiStreamUsageChunk
inputTokens: result.usage.input_tokens
outputTokens: result.usage.output_tokens
cacheWriteTokens: result.usage.cache_creation_input_tokens ?? 0
cacheReadTokens: result.usage.cache_read_input_tokens ?? 0
totalCost: result.subscription_type !== null ? 0 : result.total_cost_usd
- Yield usage chunk from
createMessage() when SDKResultSuccess is received
Tests
- Subscription session (
subscription_type: "pro") → totalCost: 0
- API key session (
subscription_type: null) → totalCost equals total_cost_usd
- Cache tokens map to correct fields
- Missing/null cache fields default to
0
- Usage chunk has
type: "usage"
Acceptance criteria
ApiStreamUsageChunk is yielded at end of each createMessage() call
- Subscription sessions always report
totalCost: 0
- All tests pass
Parent issue
#756
Depends on
#759
Context
The Agent SDK
SDKResultSuccessmessage includes full token usage (BetaUsageshape) andsubscription_type. This maps cleanly toApiStreamUsageChunk. Pattern mirrorsnormalizeUsage()inOpenAiCodexHandler, with the addition of subscription-type-aware cost reporting.Files
src/api/providers/claude-code.ts(extend)src/api/providers/__tests__/claude-code-usage.spec.ts(new)Work
private normalizeUsage(result: SDKResultSuccess): ApiStreamUsageChunkinputTokens:result.usage.input_tokensoutputTokens:result.usage.output_tokenscacheWriteTokens:result.usage.cache_creation_input_tokens ?? 0cacheReadTokens:result.usage.cache_read_input_tokens ?? 0totalCost:result.subscription_type !== null ? 0 : result.total_cost_usdcreateMessage()whenSDKResultSuccessis receivedTests
subscription_type: "pro") →totalCost: 0subscription_type: null) →totalCostequalstotal_cost_usd0type: "usage"Acceptance criteria
ApiStreamUsageChunkis yielded at end of eachcreateMessage()calltotalCost: 0