Skip to content

fix(api): adopt cumulative message_delta output tokens in Anthropic/MiniMax cost - #2242

Merged
edelauna merged 3 commits into
Zoo-Code-Org:mainfrom
myk1yt:fix/anthropic-minimax-output-cost
Oct 31, 2026
Merged

edelauna merged 3 commits into
Zoo-Code-Org:mainfrom
myk1yt:fix/anthropic-minimax-output-cost

Conversation

@myk1yt

@myk1yt myk1yt commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Supersedes #1733, which was auto-closed by the stale bot after CodeRabbit APPROVED — the only remaining gate then was 'resolve merge conflicts', now resolved: this branch includes a merge of current main (post #1906/#2034 era). Full context and review history: #1733


Related GitHub Issue

Closes: #1727

Description

For Anthropic and MiniMax models, the task cost shown in the UI omits the output-token portion of the bill, because the streaming loop never adopts the cumulative message_delta.usage.output_tokens into the local accumulator used for the final totalCost chunk — only the message_start seed (0/1) is counted.

This PR adopts the cumulative value (replace, not add — the final message_delta carries the message total, per the pinned SDK's replace semantics) in both src/api/providers/anthropic.ts and src/api/providers/minimax.ts, so the end-of-stream cost chunk reflects the real output tokens. Scope note: anthropic-vertex.ts never emits a totalCost chunk and is unaffected; opencode-go.ts consumes the same cumulative delta but with pre-existing += accumulation in streamAnthropicMessage — that file is intentionally not changed here and will be addressed in a separate follow-up.

Test Procedure

  • New regression test in each provider spec: stream message_start usage {input:100, output:1} + message_delta usage {output_tokens:500} → final usage chunk's totalCost equals calculateApiCostAnthropic(info, 100, 500), not the starved (info, 100, 1). Verified failing before the fix, passing after.
  • vitest run api/providers/__tests__/anthropic.spec.ts api/providers/__tests__/minimax.spec.ts → 147/147 passed (2 files, incl. describe-nested cases).
  • pnpm run test:coverage:core → exit 0 (162 files / 3015 passed).
  • vitest run --coverage --config vitest.api.config.ts → exit 0; changed lines covered (anthropic.ts:295, minimax.ts:153).
  • pnpm run check-types → 0 errors. ESLint on changed files → clean, suppression counts unchanged.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Visual Snapshot (UI changes only): N/A.
  • Documentation Impact: No documentation updates are required.
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Visual Snapshots

N/A.

Videos (interaction / animation only)

N/A.

Documentation Updates

  • No documentation updates are required.

Additional Notes

Pre-existing (out of scope): the consumer in Task.ts sums the cumulative delta yield into its own display accumulator, so displayed tokensOut can read ~1 over — cosmetic; the cost figure this PR fixes is now exact.

Get in Touch

GitHub: @myk1yt — please tag me here; I monitor notifications.

Zoo (VP) and others added 3 commits September 21, 2026 06:45
…put-cost

- src/api/providers/anthropic.ts: additive both-sides resolution in the
  message_delta case. Kept main's deltaThinkingTokens decomposition block
  (reasoningTokens telemetry) and placed the branch's cumulative
  output_tokens adoption immediately after it, so the accumulator used for
  the final totalCost is the adopted cumulative count, not the
  message_start seed.
- src/api/providers/__tests__/minimax.spec.ts: import collision union.
  Kept the branch's calculateApiCostAnthropic import alongside main's
  MAX_TIMEOUT_MS import, and dropped the duplicate ApiStreamUsageChunk /
  MiniMaxHandler lines the conflict hunk re-inserted.
- src/api/providers/minimax.ts: auto-merged; verified the cumulative
  output_tokens adoption line survived unchanged.
@coderabbitai

coderabbitai Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Corrected usage-based cost calculations for Anthropic and MiniMax streaming responses. Final costs now reflect the latest cumulative output-token count, while later zero-value updates no longer overwrite an existing count.

Anthropic and MiniMax now use cumulative message_delta output-token counts when calculating final streaming costs. Regression tests check that a later zero-valued delta does not replace a previously reported count.

Changes: Streaming cost calculation

Layer / File(s) Summary
Cumulative output-token handling and cost tests
src/api/providers/anthropic.ts, src/api/providers/minimax.ts, src/api/providers/__tests__/anthropic.spec.ts, src/api/providers/__tests__/minimax.spec.ts
Both handlers adopt nonzero cumulative output-token counts from message_delta and retain the prior count when the reported count is zero. Tests verify that final cost uses the cumulative count.

Priority: Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related issues

  • Issue 2215, “This issue requires cost and token data in local task usage history.” This change corrects task cost values but does not implement local usage history.
Merge Risk: Minimal · up to 36c9a

The change corrects final streaming costs to use cumulative output-token counts. No actionable merge-blocking risk is identified in the supplied evidence; merge after normal checks pass.

Pre-merge checks: Passed 8
Check name Status Explanation
Title check Passed The title clearly and concisely identifies the API fix: adopting cumulative output tokens for Anthropic and MiniMax cost calculations.
Linked Issues check Passed Issue #1727 is the only direct linked issue, and it is open. Its coding requirement is to adopt the cumulative message_delta output-token count, not add it to the message_start seed, so the end-of-str…
Out of Scope Changes check Passed The PR changes four files, per the change summary. Two are source files: anthropic.ts and minimax.ts. Two are provider test files: anthropic.spec.ts and minimax.spec.ts. Each source change is a single…
Regression Evidence Passed Focused provider-level coverage is present for both changed handlers. Each new test streams a message_start seed, a positive cumulative message_delta, and a zero delta, then asserts the final totalCos…
Security Boundaries Passed PASS. The changed paths only replace the local output-token accumulator with the cumulative message_delta.usage.output_tokens value in src/api/providers/anthropic.ts:301-303 and `src/api/providers…
Persistence Integrity Passed PASS. The pull request changes only Anthropic/MiniMax streaming token accumulation and provider tests. The changed paths do not create, update, or delete persisted state, so no changed persistence pat…
Lifecycle Resource Cleanup Passed No changed lifecycle path can leak a resource or duplicate work. The provider diff adds only cumulative-token assignments inside existing for await loops. Both loops already wrap the stream with `wi…
Description check Passed The description follows the repository template. It links issue #1727, explains the fix and scope, documents test procedures and results, completes the checklist, and addresses documentation, snapshot…
Full details: Linked Issues check

Explanation

Issue #1727 is the only direct linked issue, and it is open. Its coding requirement is to adopt the cumulative message_delta output-token count, not add it to the message_start seed, so the end-of-stream totalCost uses the real output count. Diffs at head versus merge base: src/api/providers/anthropic.ts adds outputTokens = chunk.usage.output_tokens || outputTokens in the message_delta case. src/api/providers/minimax.ts adds the same statement in its message_delta case. In minimax.ts, the final totalCost chunk calls calculateApiCostAnthropic with the outputTokens accumulator, so the fix reaches the reported cost. The summary reports regression tests in anthropic.spec.ts and minimax.spec.ts. These tests stream message_start output 1 and message_delta output 500, then assert totalCost equals cost for 500 output tokens. The test assertions were not read directly. The anthropic.ts final cost path was not read directly. It is taken from the issue text and the PR summary, and the change mirrors the minimax.ts pattern. Both requirements are met by the code evidence.

Full details: Out of Scope Changes check

Explanation

The PR changes four files, per the change summary. Two are source files: anthropic.ts and minimax.ts. Two are provider test files: anthropic.spec.ts and minimax.spec.ts. Each source change is a single statement with a short explanatory comment, and it implements #1727. The test additions support that fix. The PR states that anthropic-vertex.ts and the Task.ts display token count are unchanged. The Task.ts display discrepancy is pre-existing and is not changed here. The merge with main does not add unrelated file changes in the reviewed summary. No out-of-scope change was found.

Full details: Regression Evidence

Explanation

Focused provider-level coverage is present for both changed handlers. Each new test streams a message_start seed, a positive cumulative message_delta, and a zero delta, then asserts the final totalCost uses the cumulative count and not the seed. This covers adoption, replacement rather than addition, and zero-value fallback. No changed UI component requires a Playwright snapshot.

Full details: Security Boundaries

Explanation

PASS. The changed paths only replace the local output-token accumulator with the cumulative message_delta.usage.output_tokens value in src/api/providers/anthropic.ts:301-303 and src/api/providers/minimax.ts:168-172. The value is used only for numeric cost calculation. The changes do not expose secrets or PII, execute input, or bypass approval or allowlist controls.

Full details: Persistence Integrity

Explanation

PASS. The pull request changes only Anthropic/MiniMax streaming token accumulation and provider tests. The changed paths do not create, update, or delete persisted state, so no changed persistence path can lose or corrupt state through missing awaits, non-atomic writes, missing rollback, or an unpropagated persisted default.

Full details: Lifecycle Resource Cleanup

Explanation

No changed lifecycle path can leak a resource or duplicate work. The provider diff adds only cumulative-token assignments inside existing for await loops. Both loops already wrap the stream with withFinallyCleanup, which detaches the abort listener on completion, failure, or consumer cancellation. The test changes only add coverage and imports.

Full details: Description check

Explanation

The description follows the repository template. It links issue #1727, explains the fix and scope, documents test procedures and results, completes the checklist, and addresses documentation, snapshots, videos, and reviewer notes.

Finishing Touches
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review status

Thanks for contributing. This comment tracks the review sequence and the next action.

Current step: The required review sequence passed. Remaining merge requirements apply.

Review-state labels are managed by this workflow; do not edit them manually. community-approved is managed the same way — do not add or remove it manually. It signals a fresh community code approval for the current head as an advisory priority only; maintainer review is still required.

@codecov

codecov Bot commented Oct 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@github-actions github-actions Bot added coderabbit-review-active Required CI passed; CodeRabbit review is active awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit labels Oct 30, 2026
@github-actions github-actions Bot added awaiting-maintainer CodeRabbit approved; waiting for a human maintainer and removed coderabbit-review-active Required CI passed; CodeRabbit review is active awaiting-coderabbit Waiting for CodeRabbit to approve the latest commit labels Oct 30, 2026
@github-actions github-actions Bot added the community-approved Fresh community approval on the current head; maintainer review still required label Oct 30, 2026
@edelauna
edelauna added this pull request to the merge queue Oct 31, 2026
@github-actions github-actions Bot removed awaiting-maintainer CodeRabbit approved; waiting for a human maintainer community-approved Fresh community approval on the current head; maintainer review still required labels Oct 31, 2026
Merged via the queue into Zoo-Code-Org:main with commit 87523ba Oct 31, 2026
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Anthropic/MiniMax streaming: reported task cost omits output-token cost

3 participants