fix(anthropic): store redacted thinking as bytes and re-encode on send by BlueX888 · Pull Request #4593 · strands-agents/harness-sdk · GitHub
Skip to content

fix(anthropic): store redacted thinking as bytes and re-encode on send - #4593

Merged
pgrayy merged 1 commit into
strands-agents:mainfrom
BlueX888:fix/prep-anthropic-redacted-thinking-roundtrip-corruption
Oct 1, 2026
Merged

pgrayy merged 1 commit into
strands-agents:mainfrom
BlueX888:fix/prep-anthropic-redacted-thinking-roundtrip-corruption

Conversation

@BlueX888

Copy link
Copy Markdown
Contributor

Description

The Messages API delivers redacted thinking as a base64 string (RedactedThinkingBlock.data), but AnthropicModel.stream stored that string straight into ReasoningBlock.redactedContent — declared Uint8Array, with a base64 toJSON()/fromJSON() contract — through a compile-time-only cast (strands-ts/src/models/anthropic.ts:307).

The first turn works by luck: the string passes through untouched. But the first Message.clone() or session save/restore round-trips the block through toJSON()/fromJSON(), which re-encodes the value into the ASCII bytes of the base64 string. The next request's redacted_thinking block then serialized as an indexed object ({"0":69,"1":109,...}) instead of the verbatim base64 string (anthropic.ts:836-839), which the Messages API rejects — breaking multi-turn tool use for conversations whose reasoning comes back encrypted.

This decodes the data to bytes on ingestion and encodes it back to base64 when formatting the request, matching the Bedrock path (which already stores the AWS SDK's Uint8Array directly) and the documented ReasoningBlock JSON contract.

Related Issues

Fixes #4587

Documentation PR

Not needed — the stored representation now matches the already-documented ReasoningBlock contract (strands-ts/src/types/messages.ts:534,548); no public API surface changes.

Type of Change

Bug fix

Testing

From strands-ts/ on this branch:

  • npx vitest run --project unit-node src/models/__tests__/anthropic.test.ts — 137 passed, including the new regression test (fails on main at the first assertion: the streamed redactedContent is the raw string, not the bytes its type declares)

  • npx vitest run --project unit-node src/models/ — 941 passed (15 files)

  • npm test — 4762 passed (169 files)

  • npx vitest run --project unit-browser src/models/__tests__/anthropic.test.ts — 135 passed

  • npm run lint, npm run format:check, npm run type-check — all clean

  • I ran hatch run prepare — TS-only change; the npm gates above cover it

Checklist

  • I have read the CONTRIBUTING document
  • I have reviewed and understand every line of code in this PR, including any generated by AI tools, and I can explain why it works
  • My change is focused and reasonably small; I have split unrelated work into separate PRs
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

The Messages API delivers redacted thinking data as a base64 string
(RedactedThinkingBlock.data). AnthropicModel passed that string straight
into ReasoningBlock.redactedContent, whose contract is Uint8Array with a
base64 toJSON/fromJSON round-trip, via a compile-time-only cast. Every
Message.clone() or session save/restore therefore re-encoded the value,
and the redacted_thinking block sent back to Anthropic serialized the
bytes as {"0":69,"1":109,...} instead of the verbatim base64 string,
which the Messages API rejects for multi-turn tool use.

Decode the data to bytes on the way in and encode it back to base64 on
the way out, matching the Bedrock path and the ReasoningBlock contract.
@BlueX888
BlueX888 requested a review from a team as a code owner September 25, 2026 07:25
@BlueX888
BlueX888 requested a review from mehtarac September 25, 2026 07:25
@github-actions github-actions Bot added typescript Pull requests that update typescript code area-model Related to models or model providers area-sessions Related to session or session managment bug Something isn't working labels Sep 25, 2026
Comment thread strands-ts/src/models/__tests__/anthropic.test.ts
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot added complexity/low Touched functions have low cognitive complexity (<=10) size/xs and removed strands-running labels Oct 1, 2026
@pgrayy
pgrayy merged commit 3b11e82 into strands-agents:main Oct 1, 2026
33 of 34 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-model Related to models or model providers area-sessions Related to session or session managment bug Something isn't working complexity/low Touched functions have low cognitive complexity (<=10) size/xs typescript Pull requests that update typescript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] strands-ts AnthropicModel redacted_thinking: Message.clone()/session save+restore corrupts the base64 data into an indexed object sent to the API

2 participants