Skip to content

fix(amazon-bedrock): support reasoningContent.redactedContent from the Converse API - #19058

Merged
gr2m merged 1 commit into
vercel:mainfrom
yu-ya4:fix/bedrock-openai-redacted-content
Aug 19, 2026
Merged

gr2m merged 1 commit into
vercel:mainfrom
yu-ya4:fix/bedrock-openai-redacted-content

Conversation

@yu-ya4

@yu-ya4 yu-ya4 commented Aug 19, 2026 •

Copy link
Copy Markdown
Contributor

Background

redactedContent is the second member of the documented ReasoningContentBlock union (reasoningText | redactedContent) and a member of ReasoningContentBlockDelta, but neither the response schema nor the stream schema accepts it. Models that emit it — e.g. OpenAI models on Converse such as us.openai.gpt-5.6-luna, which return their encrypted reasoning in this shape alongside tool calls — currently fail validation:

  • generateText / generateObject with tools throw AI_APICallError: Invalid JSON response on an HTTP 200 response, making tool calling unusable
  • streamText with tools emits a spurious AI_TypeValidationError error part on every request and loses the reasoning block

Summary

  • Both Zod schemas accept redactedContent (response ReasoningContentBlock and stream contentBlockDelta.delta).
  • The payload is surfaced as a reasoning part carrying providerMetadata.{amazonBedrock,bedrock}.redactedContent, mirroring how redactedReasoning is surfaced today.
  • convert-to-amazon-bedrock-chat-messages replays it as reasoningContent: { redactedContent } on subsequent turns.
  • Streaming deltas are accumulated in the content-block state and attached once via reasoning-end: a reasoning part's merged provider metadata is last-write-wins, so per-delta metadata would drop earlier chunks if the payload ever arrives split.
  • Existing redactedReasoning / data handling is left untouched.

Surfacing + replay (rather than accept-and-drop) matters because the encrypted payload restores the model's reasoning state across tool-use turns. Verified against the raw Converse API with a two-turn tool conversation: replaying the block verbatim yields a correct answer from restored state (22 output tokens); stripping it forces the model to re-reason from scratch (509 output tokens) and it loses its earlier conclusion. Replaying via the legacy redactedReasoning: { data } shape is silently ignored by the current API, so a dedicated replay path for the documented shape is required.

Verification

  • pnpm test in packages/amazon-bedrock: 465 tests pass. The new tests (response mapping, stream accumulation across split deltas, multi-block separation, replay conversion) fail without the fix.
  • End-to-end against real Bedrock (us-east-1, us.openai.gpt-5.6-luna), both doGenerate and doStream: turn 1 surfaces the reasoning part with redactedContent metadata, the turn-2 request contains the replayed reasoningContent.redactedContent block on the wire, no error parts, and the model answers from its restored reasoning state.

Tasks

  • Tests have been added / updated (for bug fixes / features)
  • Documentation has been added / updated (for bug fixes / features) — provider docs describe reasoning provider metadata generically; no doc change needed
  • A patch changeset for relevant packages has been added (for bug fixes / features - run pnpm changeset in the project root)
  • Formatting issues have been fixed (run pnpm prettier-fix in the project root)

Future Work

Anthropic models' redacted reasoning on the current Converse API is also documented as redactedContent; this change covers them as well, while keeping the legacy redactedReasoning / data paths for compatibility.

Related Issues

Closes #19062 (full reproduction and multi-turn replay measurements). Related: #19024 (closed; streaming variant of this validation error), #14720 (precedent for OpenAI-on-Converse reasoning handling).

…nt` from the Converse API

`redactedContent` is the second member of the documented
ReasoningContentBlock union (and a member of ReasoningContentBlockDelta),
but neither the response schema nor the stream schema accepted it, so tool
calling with models that emit it (e.g. OpenAI models such as
`us.openai.gpt-5.6-luna`) failed validation: generateText threw
AI_APICallError on a successful response, and streamText emitted a spurious
error part.

The encrypted payload is now surfaced as a reasoning part carrying
`providerMetadata.{amazonBedrock,bedrock}.redactedContent` and replayed on
subsequent turns as `reasoningContent: { redactedContent }`, restoring the
model's reasoning state across tool calls. Streaming deltas are accumulated
and attached once via `reasoning-end`, because the merged provider metadata
of a reasoning part is last-write-wins.
@yu-ya4
yu-ya4 force-pushed the fix/bedrock-openai-redacted-content branch from c521b45 to 1531c67 Compare August 19, 2026 08:11
@yu-ya4
yu-ya4 marked this pull request as ready for review August 19, 2026 08:22
@ai-sdk-factory

Copy link
Copy Markdown
Contributor

Bugfix review

Outcome: approved

Fixes issue

Status: fully-addresses

The response and streaming schemas now accept the documented redactedContent union member, surface it as provider metadata, accumulate split streaming payloads, and replay it unchanged on subsequent turns.

Side effects

Risk: low

Existing reasoningText and legacy redactedReasoning handling remain intact; the only observable addition is a reasoning part with redactedContent metadata for responses previously rejected or discarded.

Performance

Risk: low

Streaming retains one encrypted payload per active reasoning block until block completion. This adds memory proportional to the payload size but no unbounded state beyond data required for replay.

Backwards compatibility

Risk: low

Existing stored messages and legacy redactedData metadata remain supported. Newly persisted response messages may contain the additive redactedContent metadata and will replay it without requiring migration.

Breaking changes

Risk: none

No public exports, types, defaults, configurations, accepted inputs, or existing output shapes are removed or narrowed. Validation becomes more permissive, and the new provider metadata field is additive.

Architecture

Risk: none

All changes remain inside the Amazon Bedrock provider and reuse its existing API types, reasoning metadata schema, response mapping, and message conversion boundaries; no cross-package source imports or dependency violations were introduced.

Change scope

Status: minimal

The changed production files cover schema validation, provider metadata, streaming accumulation, request typing, and replay; the remaining changes are focused regression tests and the required patch changeset.

Security

Risk: low

The change transports provider-encrypted data without decoding or executing it and introduces no credential, URL-handling, parsing, or authorization changes.

Testing

Status: appropriate

Tests cover non-streaming mapping, split streaming-delta accumulation, separation of multiple reasoning blocks, absence of stream errors, and outbound replay. The complete Amazon Bedrock Node and Edge suites each passed all 465 tests.

Verification

Inspected every diff hunk against origin/main and the surrounding provider/core metadata flow. The Amazon Bedrock Node and Edge suites passed, workspace type checking and formatting/lint checks passed, and git diff validation reported no whitespace errors.

Relevant Documentation

@gr2m gr2m left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good thank you Yuya!

@gr2m
gr2m merged commit aabc617 into vercel:main Aug 19, 2026
54 of 55 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

🚀 Published in:

Package Version
ai 7.0.70 github npm
@ai-sdk/alibaba 2.0.33 github npm
@ai-sdk/amazon-bedrock 5.0.59 github npm
@ai-sdk/angular 3.0.70 github npm
@ai-sdk/anthropic 4.0.40 github npm
@ai-sdk/anthropic-aws 2.0.32 github npm
@ai-sdk/assemblyai 3.0.28 github npm
@ai-sdk/azure 4.0.45 github npm
@ai-sdk/baseten 2.1.10 github npm
@ai-sdk/black-forest-labs 2.0.29 github npm
@ai-sdk/bytedance 2.0.30 github npm
@ai-sdk/cartesia 3.0.23 github npm
@ai-sdk/cerebras 3.0.32 github npm
@ai-sdk/code-mode 1.0.27 github npm
@ai-sdk/cohere 4.0.28 github npm
@ai-sdk/deepgram 3.0.28 github npm
@ai-sdk/deepinfra 3.0.32 github npm
@ai-sdk/deepseek 3.0.29 github npm
@ai-sdk/elevenlabs 3.0.29 github npm
@ai-sdk/fal 3.0.29 github npm
@ai-sdk/fireworks 3.0.35 github npm
@ai-sdk/fish-audio 3.0.6 github npm
@ai-sdk/gateway 4.0.56 github npm
@ai-sdk/gladia 3.0.28 github npm
@ai-sdk/gmicloud 3.0.3 github npm
@ai-sdk/google 4.0.47 github npm
@ai-sdk/google-vertex 5.0.58 github npm
@ai-sdk/groq 4.0.29 github npm
@ai-sdk/harness 1.0.77 github npm
@ai-sdk/harness-acp 1.0.15 github npm
@ai-sdk/harness-claude-code 1.0.80 github npm
@ai-sdk/harness-cline 1.0.5 github npm
@ai-sdk/harness-codex 1.0.79 github npm
@ai-sdk/harness-deepagents 1.0.77 github npm
@ai-sdk/harness-grok-build 1.0.14 github npm
@ai-sdk/harness-opencode 1.0.78 github npm
@ai-sdk/harness-pi 1.0.79 github npm
@ai-sdk/huggingface 2.0.32 github npm
@ai-sdk/hume 3.0.28 github npm
@ai-sdk/klingai 4.0.30 github npm
@ai-sdk/langchain 3.0.70 github npm
@ai-sdk/llamaindex 3.0.70 github npm
@ai-sdk/lmnt 3.0.28 github npm
@ai-sdk/luma 3.0.29 github npm
@ai-sdk/mcp 2.0.34 github npm
@ai-sdk/minimax 3.0.16 github npm
@ai-sdk/mistral 4.0.30 github npm
@ai-sdk/moonshotai 3.0.36 github npm
@ai-sdk/open-responses 2.0.29 github npm
@ai-sdk/openai 4.0.44 github npm
@ai-sdk/openai-compatible 3.0.32 github npm
@ai-sdk/otel 1.0.70 github npm
@ai-sdk/perplexity 4.0.30 github npm
@ai-sdk/policy-opa 1.0.70 github npm
@ai-sdk/prodia 2.0.29 github npm
@ai-sdk/provider-utils 5.0.28 github npm
@ai-sdk/quiverai 2.0.28 github npm
@ai-sdk/react 4.0.73 github npm
@ai-sdk/replicate 3.0.29 github npm
@ai-sdk/revai 3.0.28 github npm
@ai-sdk/rsc 3.0.70 github npm
@ai-sdk/sandbox-just-bash 1.0.77 github npm
@ai-sdk/sandbox-vercel 1.0.77 github npm
@ai-sdk/svelte 5.0.70 github npm
@ai-sdk/togetherai 3.0.33 github npm
@ai-sdk/tui 1.0.71 github npm
@ai-sdk/valibot 3.0.28 github npm
@ai-sdk/voyage 2.0.28 github npm
@ai-sdk/vue 4.0.70 github npm
@ai-sdk/workflow 2.0.0 github npm
@ai-sdk/workflow-harness 1.0.77 github npm
@ai-sdk/xai 4.0.41 github npm

gr2m added a commit that referenced this pull request Aug 19, 2026
…` from the Converse API (#19139)

## Background

`redactedContent` is the second member of the documented
[`ReasoningContentBlock`](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ReasoningContentBlock.html)
union (`reasoningText | redactedContent`) and a member of
[`ReasoningContentBlockDelta`](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ReasoningContentBlockDelta.html),
but neither the response schema nor the stream schema accepts it. Models
that emit it — e.g. OpenAI models on Converse such as
`us.openai.gpt-5.6-luna`, which return their encrypted reasoning in this
shape alongside tool calls — currently fail validation:

- `generateText` / `generateObject` with tools throw `AI_APICallError:
Invalid JSON response` on an HTTP 200 response, making tool calling
unusable
- `streamText` with tools emits a spurious `AI_TypeValidationError`
error part on every request and loses the reasoning block

## Summary

- Both Zod schemas accept `redactedContent` (response
`ReasoningContentBlock` and stream `contentBlockDelta.delta`).
- The payload is surfaced as a `reasoning` part carrying
`providerMetadata.{amazonBedrock,bedrock}.redactedContent`, mirroring
how `redactedReasoning` is surfaced today.
- `convert-to-amazon-bedrock-chat-messages` replays it as
`reasoningContent: { redactedContent }` on subsequent turns.
- Streaming deltas are accumulated in the content-block state and
attached once via `reasoning-end`: a reasoning part's merged provider
metadata is last-write-wins, so per-delta metadata would drop earlier
chunks if the payload ever arrives split.
- Existing `redactedReasoning` / `data` handling is left untouched.

Surfacing + replay (rather than accept-and-drop) matters because the
encrypted payload restores the model's reasoning state across tool-use
turns. Verified against the raw Converse API with a two-turn tool
conversation: replaying the block verbatim yields a correct answer from
restored state (22 output tokens); stripping it forces the model to
re-reason from scratch (509 output tokens) and it loses its earlier
conclusion. Replaying via the legacy `redactedReasoning: { data }` shape
is silently ignored by the current API, so a dedicated replay path for
the documented shape is required.

## Verification

- `pnpm test` in `packages/amazon-bedrock`: 465 tests pass. The new
tests (response mapping, stream accumulation across split deltas,
multi-block separation, replay conversion) fail without the fix.
- End-to-end against real Bedrock (`us-east-1`,
`us.openai.gpt-5.6-luna`), both `doGenerate` and `doStream`: turn 1
surfaces the reasoning part with `redactedContent` metadata, the turn-2
request contains the replayed `reasoningContent.redactedContent` block
on the wire, no error parts, and the model answers from its restored
reasoning state.

## Tasks

- [x] Tests have been added / updated (for bug fixes / features)
- [x] Documentation has been added / updated (for bug fixes / features)
— provider docs describe reasoning provider metadata generically; no doc
change needed
- [x] A _patch changeset_ for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] Formatting issues have been fixed (run `pnpm prettier-fix` in the
project root)

## Future Work

Anthropic models' redacted reasoning on the current Converse API is also
documented as `redactedContent`; this change covers them as well, while
keeping the legacy `redactedReasoning` / `data` paths for compatibility.

## Related Issues

Closes #19062 (full reproduction and multi-turn replay measurements).
Related: #19024 (closed; streaming variant of this validation error),
#14720 (precedent for OpenAI-on-Converse reasoning handling).

Closes #19115

Backport of #19058

---------

Co-authored-by: Yuya Matsumura <[email protected]>
Co-authored-by: ai-sdk-factory <[email protected]>
Co-authored-by: Gregor Martynus <[email protected]>
gr2m added a commit that referenced this pull request Aug 19, 2026
…` from the Converse API (#19142)

## Background

`redactedContent` is the second member of the documented
[`ReasoningContentBlock`](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ReasoningContentBlock.html)
union (`reasoningText | redactedContent`) and a member of
[`ReasoningContentBlockDelta`](https://docs.aws.amazon.com/bedrock/latest/APIReference/API_runtime_ReasoningContentBlockDelta.html),
but neither the response schema nor the stream schema accepts it. Models
that emit it — e.g. OpenAI models on Converse such as
`us.openai.gpt-5.6-luna`, which return their encrypted reasoning in this
shape alongside tool calls — currently fail validation:

- `generateText` / `generateObject` with tools throw `AI_APICallError:
Invalid JSON response` on an HTTP 200 response, making tool calling
unusable
- `streamText` with tools emits a spurious `AI_TypeValidationError`
error part on every request and loses the reasoning block

## Summary

- Both Zod schemas accept `redactedContent` (response
`ReasoningContentBlock` and stream `contentBlockDelta.delta`).
- The payload is surfaced as a `reasoning` part carrying
`providerMetadata.{amazonBedrock,bedrock}.redactedContent`, mirroring
how `redactedReasoning` is surfaced today.
- `convert-to-amazon-bedrock-chat-messages` replays it as
`reasoningContent: { redactedContent }` on subsequent turns.
- Streaming deltas are accumulated in the content-block state and
attached once via `reasoning-end`: a reasoning part's merged provider
metadata is last-write-wins, so per-delta metadata would drop earlier
chunks if the payload ever arrives split.
- Existing `redactedReasoning` / `data` handling is left untouched.

Surfacing + replay (rather than accept-and-drop) matters because the
encrypted payload restores the model's reasoning state across tool-use
turns. Verified against the raw Converse API with a two-turn tool
conversation: replaying the block verbatim yields a correct answer from
restored state (22 output tokens); stripping it forces the model to
re-reason from scratch (509 output tokens) and it loses its earlier
conclusion. Replaying via the legacy `redactedReasoning: { data }` shape
is silently ignored by the current API, so a dedicated replay path for
the documented shape is required.

## Verification

- `pnpm test` in `packages/amazon-bedrock`: 465 tests pass. The new
tests (response mapping, stream accumulation across split deltas,
multi-block separation, replay conversion) fail without the fix.
- End-to-end against real Bedrock (`us-east-1`,
`us.openai.gpt-5.6-luna`), both `doGenerate` and `doStream`: turn 1
surfaces the reasoning part with `redactedContent` metadata, the turn-2
request contains the replayed `reasoningContent.redactedContent` block
on the wire, no error parts, and the model answers from its restored
reasoning state.

## Tasks

- [x] Tests have been added / updated (for bug fixes / features)
- [x] Documentation has been added / updated (for bug fixes / features)
— provider docs describe reasoning provider metadata generically; no doc
change needed
- [x] A _patch changeset_ for relevant packages has been added (for bug
fixes / features - run `pnpm changeset` in the project root)
- [x] Formatting issues have been fixed (run `pnpm prettier-fix` in the
project root)

## Future Work

Anthropic models' redacted reasoning on the current Converse API is also
documented as `redactedContent`; this change covers them as well, while
keeping the legacy `redactedReasoning` / `data` paths for compatibility.

## Related Issues

Closes #19062 (full reproduction and multi-turn replay measurements).
Related: #19024 (closed; streaming variant of this validation error),
#14720 (precedent for OpenAI-on-Converse reasoning handling).

Closes #19111

Backport of #19058

---------

Co-authored-by: Yuya Matsumura <[email protected]>
Co-authored-by: ai-sdk-factory <[email protected]>
Co-authored-by: Gregor Martynus <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug(amazon-bedrock): reasoningContent.redactedContent (documented Converse union member) is missing from both response and stream schemas

2 participants