Skip to content

fix(ai-amazon-bedrock): emit finish part after metadata event to preserve token usage in streaming#6160

Open
jamesone wants to merge 1 commit intoEffect-TS:mainfrom
jamesone:fix/ai-bedrock-streaming-cached-tokens
Open

fix(ai-amazon-bedrock): emit finish part after metadata event to preserve token usage in streaming#6160
jamesone wants to merge 1 commit intoEffect-TS:mainfrom
jamesone:fix/ai-bedrock-streaming-cached-tokens

Conversation

@jamesone
Copy link
Copy Markdown

@jamesone jamesone commented Apr 8, 2026

Type

  • Bug Fix

Description

In the Bedrock ConverseStream API, events arrive in the order: messageStopmetadata. The metadata event carries all token usage data (inputTokens, outputTokens, totalTokens, cacheReadInputTokens, cacheWriteInputTokens) as well as trace information.

Previously, the streaming handler emitted the finish part during the messageStop event, before the metadata event had populated the usage object. Because the downstream LanguageModel layer decodes stream parts through a schema (creating new instances), the finish part was captured with uninitialized usage values — causing all token counts (including cachedInputTokens) to be lost in streaming responses.

Fix

The fix introduces a tryEmitFinish guard that defers the finish part until both messageStop (which provides the stop reason) and metadata (which provides usage/trace) have been received. This:

  • Ensures cachedInputTokens, inputTokens, outputTokens, totalTokens are all correctly populated in streaming responses
  • Ensures trace and cacheWriteInputTokens metadata are present
  • Handles event ordering defensively (emits on whichever arrives second)
  • Preserves correct behavior when errors interrupt the stream between messageStop and metadata (no misleading finish part with empty usage)

The non-streaming (Converse) path was already correct since it reads directly from the decoded ConverseResponse.

Tests

Adds comprehensive test suite for AmazonBedrockLanguageModel covering both streaming and non-streaming paths:

  • Token usage population in the happy path
  • Cached token counts (cacheReadInputTokens / cacheWriteInputTokens)
  • Explicit zero cache counts preserved as 0 (not undefined)
  • Trace metadata propagation
  • Tool call content blocks with cached tokens
  • Error after messageStop (no misleading finish part)
  • Missing messageStop edge case (no finish part without a stop reason)
  • Stop reason mapping
  • Text part ordering relative to finish

Related

  • Closes #

…erve token usage in streaming

In the Bedrock ConverseStream API, events arrive in the order:
messageStop → metadata. The metadata event carries all token usage
data (inputTokens, outputTokens, totalTokens, cacheReadInputTokens,
cacheWriteInputTokens) as well as trace information.

Previously, the streaming handler emitted the finish part during the
messageStop event, before the metadata event had populated the usage
object. Because the downstream LanguageModel layer decodes stream
parts through a schema (creating new instances), the finish part was
captured with uninitialized usage values — causing all token counts
(including cachedInputTokens) to be lost in streaming responses.

The fix introduces a `tryEmitFinish` guard that defers the finish
part until both messageStop (which provides the stop reason) and
metadata (which provides usage/trace) have been received. This:

- Ensures cachedInputTokens, inputTokens, outputTokens, totalTokens
  are all correctly populated in streaming responses
- Ensures trace and cacheWriteInputTokens metadata are present
- Handles event ordering defensively (emits on whichever arrives
  second)
- Preserves correct behavior when errors interrupt the stream between
  messageStop and metadata (no misleading finish part with empty usage)

The non-streaming (Converse) path was already correct since it reads
directly from the decoded ConverseResponse.

Adds comprehensive test suite for AmazonBedrockLanguageModel covering
both streaming and non-streaming paths: token usage, cached tokens,
explicit zero cache counts, trace metadata, tool calls, error
scenarios, and missing event edge cases.
@jamesone jamesone requested a review from IMax153 as a code owner April 8, 2026 01:52
@github-project-automation github-project-automation bot moved this to Discussion Ongoing in PR Backlog Apr 8, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: 924be6f

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@effect/ai-amazon-bedrock Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Discussion Ongoing

Development

Successfully merging this pull request may close these issues.

1 participant