Skip to content

keep pricing objects in anthropic path for ai-sdk compatibility - #5886

Merged
akshaydeo merged 4 commits into
devfrom
08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility
Aug 6, 2026
Merged

keep pricing objects in anthropic path for ai-sdk compatibility#5886
akshaydeo merged 4 commits into
devfrom
08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility

Conversation

@akshaydeo

@akshaydeo akshaydeo commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #5885. @ai-sdk/anthropic (versions 4.0.6–4.0.32) marks message.usage and message.usage.input_tokens as required fields in its message_start schema, while id, model, and role are nullable. When Bifrost omitted the usage key entirely on message_start frames — which happened for every non-Anthropic provider, including Bedrock Converse, because usage figures aren't available until the terminal event — the SDK aborted the stream before the first token reached the client.

The fix emits an all-zero usage object on message_start when no real figures are available. Zeros are chosen over Anthropic's own output_tokens: 1 placeholder because Bedrock's message_delta carries absolute totals rather than cumulative deltas; a client summing both frames would over-count by one. Zero is neutral under both interpretations, and Bifrost's passthrough accumulator uses max-merge, so a zero can never displace a real figure later in the stream.

Changes

  • responses.go: The else branch that previously left messageUsage nil now populates an all-zero AnthropicUsage struct, ensuring the usage key is always present on the wire regardless of omitempty.
  • invoke.go: message_start frames built for the Bedrock /invoke-with-response-stream path now include a usage map with zero placeholders by default. When resp.Response.Usage is non-nil, real figures replace the zeros and cache token fields are conditionally included.
  • Tests updated to assert that usage is present and zero when unknown, and that real figures are preferred when available. A second test marshals the struct to raw JSON and validates the wire representation directly, since the original omitempty bug was invisible to struct-level nil checks.

Type of change

  • Bug fix
  • Feature
  • Refactor
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (React)
  • Docs

How to test

go test ./core/providers/anthropic/... ./core/providers/bedrock/...

Validate that streaming through a Bedrock-backed model with an @ai-sdk/anthropic client no longer aborts on the first frame. The message_start event should contain message.usage.input_tokens = 0 and message.usage.output_tokens = 0, with authoritative totals arriving on message_delta.

Breaking changes

  • No

Related issues

Closes #5885
See also #5821 (the prior fix that introduced the omission)

Security considerations

None.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes
    • Anthropic-compatible streaming responses now consistently include usage details at message start.
    • When usage is unavailable, responses provide zero-valued input and output token counts instead of omitting usage.
    • When available, token counts and cache read and creation metrics are reported accurately.
    • Improved consistency and reliability of usage reporting across supported streaming providers.

Walkthrough

Anthropic and Bedrock streaming responses now always include message_start.usage, with zero counters when usage is unavailable and known token and cache counts when available. DeepSeek test handlers now return HTTP errors instead of calling fatal test methods from handler goroutines.

Changes

Message-start usage emission

Layer / File(s) Summary
Anthropic usage handling
core/providers/anthropic/responses.go, core/providers/anthropic/messagestartusage_test.go
Anthropic message_start frames include zero-valued usage when usage is unknown. Tests verify object presence and numeric zero serialization.
Bedrock usage handling
core/providers/bedrock/invoke.go, core/providers/bedrock/invoke_test.go
Bedrock frames include zero-valued usage by default and preserve known input, output, and cache token counts. Tests cover both cases.

DeepSeek test handler validation

Layer / File(s) Summary
Handler error response handling
core/providers/deepseek/anthropic_test.go
Anthropic and OpenAI test handlers report validation failures with t.Errorf, send HTTP error responses, and return early.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

  • maximhq/bifrost issue 5885: Covers the omission of message_start.message.usage in Anthropic and Bedrock streaming responses.

Possibly related PRs

  • maximhq/bifrost#5907: Modifies Anthropic message_start usage handling and regression tests for zero-valued usage.

Suggested reviewers: tejasghatte, pratham-mishra04, sammaji

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 53.85% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ⚠️ Warning The title refers to pricing objects, but the changes add usage objects to Anthropic-compatible streaming responses. Rename the title to describe always emitting zero or known usage objects in Anthropic-compatible message_start frames.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description follows the template and clearly documents the bug, implementation, tests, affected areas, breaking changes, and related issue.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility

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

@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
18 tasks
@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
17 tasks
@akshaydeo
akshaydeo marked this pull request as ready for review August 6, 2026 04:29
@coderabbitai
coderabbitai Bot requested a review from Pratham-Mishra04 August 6, 2026 04:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@core/providers/anthropic/messagestartusage_test.go`:
- Around line 85-90: Extend the serialized-frame assertions in the message start
usage test alongside the existing inputTokens checks: read
message.usage.output_tokens, verify it is a gjson.Number, and assert its value
is zero so omitted output_tokens fails the test.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: befd93a1-14ec-4d6b-9e2b-951079442cfe

📥 Commits

Reviewing files that changed from the base of the PR and between 7192207 and c710223.

📒 Files selected for processing (4)
  • core/providers/anthropic/messagestartusage_test.go
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/invoke_test.go

Comment thread core/providers/anthropic/messagestartusage_test.go
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from c710223 to 534271b Compare August 6, 2026 05:05
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
18 tasks

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@core/providers/deepseek/anthropic_test.go`:
- Around line 54-70: Synchronize all six httptest handlers in
core/providers/deepseek/anthropic_test.go at lines 54-70, 104-121, 165-175,
227-237, 289-295, and 329-338 with their test goroutines: remove direct t.Fatalf
calls and unsynchronized access to captured or capturedPath, send validation
errors and captured values through buffered channels, then perform assertions in
the test goroutine.
🪄 Autofix

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 851696df-1928-405d-927d-8489f69c3dc0

📥 Commits

Reviewing files that changed from the base of the PR and between 7192207 and 534271b.

📒 Files selected for processing (5)
  • core/providers/anthropic/messagestartusage_test.go
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/invoke.go
  • core/providers/bedrock/invoke_test.go
  • core/providers/deepseek/anthropic_test.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • core/providers/bedrock/invoke.go
  • core/providers/anthropic/responses.go
  • core/providers/bedrock/invoke_test.go
  • core/providers/anthropic/messagestartusage_test.go

Comment thread core/providers/deepseek/anthropic_test.go
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from 534271b to f86fb1e Compare August 6, 2026 09:11
@akshaydeo
akshaydeo force-pushed the 08-05-file_type_mapping_bug_fix branch from 7192207 to cf642b7 Compare August 6, 2026 09:11
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-05-file_type_mapping_bug_fix branch from cf642b7 to a906f5c Compare August 6, 2026 17:18
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from f86fb1e to 071106e Compare August 6, 2026 17:18
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo akshaydeo mentioned this pull request Aug 6, 2026
18 tasks
@coderabbitai
coderabbitai Bot requested review from TejasGhatte and sammaji August 6, 2026 17:19
coderabbitai[bot]
coderabbitai Bot previously approved these changes Aug 6, 2026
@akshaydeo
akshaydeo force-pushed the 08-05-file_type_mapping_bug_fix branch from a906f5c to fa93a62 Compare August 6, 2026 18:01
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from 071106e to 947280d Compare August 6, 2026 18:01
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-05-file_type_mapping_bug_fix branch from fa93a62 to 647b82b Compare August 6, 2026 19:38
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from 947280d to 3d9fd15 Compare August 6, 2026 19:38
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@akshaydeo
akshaydeo force-pushed the 08-05-file_type_mapping_bug_fix branch from 647b82b to ce5a846 Compare August 6, 2026 19:57
@akshaydeo
akshaydeo force-pushed the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch from 3d9fd15 to 25b850d Compare August 6, 2026 19:57
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

akshaydeo commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Merge activity

  • Aug 6, 7:58 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Aug 6, 8:01 PM UTC: @akshaydeo merged this pull request with Graphite.

@akshaydeo
akshaydeo changed the base branch from 08-05-file_type_mapping_bug_fix to graphite-base/5886 August 6, 2026 20:00
@akshaydeo
akshaydeo changed the base branch from graphite-base/5886 to dev August 6, 2026 20:00
@akshaydeo
akshaydeo dismissed coderabbitai[bot]’s stale review August 6, 2026 20:00

The base branch was changed.

@akshaydeo
akshaydeo requested a review from a team as a code owner August 6, 2026 20:00
@akshaydeo
akshaydeo merged commit 8ab75f3 into dev Aug 6, 2026
6 checks passed
@akshaydeo
akshaydeo deleted the 08-05-keep_pricing_objects_in_anthropic_path_for_ai-sdk_compatibility branch August 6, 2026 20:01
akshaydeo added a commit that referenced this pull request Aug 7, 2026
## Summary

Fixes #5885. `@ai-sdk/anthropic` (versions 4.0.6–4.0.32) marks `message.usage` and `message.usage.input_tokens` as required fields in its `message_start` schema, while `id`, `model`, and `role` are nullable. When Bifrost omitted the `usage` key entirely on `message_start` frames — which happened for every non-Anthropic provider, including Bedrock Converse, because usage figures aren't available until the terminal event — the SDK aborted the stream before the first token reached the client.

The fix emits an all-zero `usage` object on `message_start` when no real figures are available. Zeros are chosen over Anthropic's own `output_tokens: 1` placeholder because Bedrock's `message_delta` carries absolute totals rather than cumulative deltas; a client summing both frames would over-count by one. Zero is neutral under both interpretations, and Bifrost's passthrough accumulator uses max-merge, so a zero can never displace a real figure later in the stream.

## Changes

- `responses.go`: The `else` branch that previously left `messageUsage` nil now populates an all-zero `AnthropicUsage` struct, ensuring the `usage` key is always present on the wire regardless of `omitempty`.
- `invoke.go`: `message_start` frames built for the Bedrock `/invoke-with-response-stream` path now include a `usage` map with zero placeholders by default. When `resp.Response.Usage` is non-nil, real figures replace the zeros and cache token fields are conditionally included.
- Tests updated to assert that `usage` is present and zero when unknown, and that real figures are preferred when available. A second test marshals the struct to raw JSON and validates the wire representation directly, since the original `omitempty` bug was invisible to struct-level nil checks.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/providers/anthropic/... ./core/providers/bedrock/...
```

Validate that streaming through a Bedrock-backed model with an `@ai-sdk/anthropic` client no longer aborts on the first frame. The `message_start` event should contain `message.usage.input_tokens = 0` and `message.usage.output_tokens = 0`, with authoritative totals arriving on `message_delta`.

## Breaking changes

- [x] No

## Related issues

Closes #5885
See also #5821 (the prior fix that introduced the omission)

## Security considerations

None.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
@akshaydeo akshaydeo mentioned this pull request Aug 7, 2026
18 tasks
atharvamhaske pushed a commit to atharvamhaske/bifrost that referenced this pull request Aug 13, 2026
…mhq#5886)

## Summary

Fixes maximhq#5885. `@ai-sdk/anthropic` (versions 4.0.6–4.0.32) marks `message.usage` and `message.usage.input_tokens` as required fields in its `message_start` schema, while `id`, `model`, and `role` are nullable. When Bifrost omitted the `usage` key entirely on `message_start` frames — which happened for every non-Anthropic provider, including Bedrock Converse, because usage figures aren't available until the terminal event — the SDK aborted the stream before the first token reached the client.

The fix emits an all-zero `usage` object on `message_start` when no real figures are available. Zeros are chosen over Anthropic's own `output_tokens: 1` placeholder because Bedrock's `message_delta` carries absolute totals rather than cumulative deltas; a client summing both frames would over-count by one. Zero is neutral under both interpretations, and Bifrost's passthrough accumulator uses max-merge, so a zero can never displace a real figure later in the stream.

## Changes

- `responses.go`: The `else` branch that previously left `messageUsage` nil now populates an all-zero `AnthropicUsage` struct, ensuring the `usage` key is always present on the wire regardless of `omitempty`.
- `invoke.go`: `message_start` frames built for the Bedrock `/invoke-with-response-stream` path now include a `usage` map with zero placeholders by default. When `resp.Response.Usage` is non-nil, real figures replace the zeros and cache token fields are conditionally included.
- Tests updated to assert that `usage` is present and zero when unknown, and that real figures are preferred when available. A second test marshals the struct to raw JSON and validates the wire representation directly, since the original `omitempty` bug was invisible to struct-level nil checks.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (React)
- [ ] Docs

## How to test

```sh
go test ./core/providers/anthropic/... ./core/providers/bedrock/...
```

Validate that streaming through a Bedrock-backed model with an `@ai-sdk/anthropic` client no longer aborts on the first frame. The `message_start` event should contain `message.usage.input_tokens = 0` and `message.usage.output_tokens = 0`, with authoritative totals arriving on `message_delta`.

## Breaking changes

- [x] No

## Related issues

Closes maximhq#5885
See also maximhq#5821 (the prior fix that introduced the omission)

## Security considerations

None.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable
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.

[Bug]: v1.6.8 omits message_start.message.usage on Bedrock-backed providers, breaking @ai-sdk/anthropic streaming

1 participant