Skip to content

fix: preserve Anthropic redacted_thinking blocks in message sanitization#980

Merged
threepointone merged 1 commit into
mainfrom
fix/redacted-thinking-sanitization
Feb 24, 2026
Merged

fix: preserve Anthropic redacted_thinking blocks in message sanitization#980
threepointone merged 1 commit into
mainfrom
fix/redacted-thinking-sanitization

Conversation

@threepointone

Copy link
Copy Markdown
Contributor

Problem

_sanitizeMessageForPersistence in AIChatAgent was incorrectly stripping Anthropic's redacted_thinking blocks. These blocks are stored as reasoning parts with empty text but carry critical data in providerMetadata.anthropic.redactedData. When stripped, the Anthropic API rejects subsequent requests because the conversation history is incomplete.

Fixes #978

Root Cause

The sanitizer filtered out all empty reasoning parts unconditionally. This was designed for OpenAI's ephemeral reasoning placeholders but also caught Anthropic's redacted_thinking blocks, which must be preserved for round-tripping.

Solution

Refactored _sanitizeMessageForPersistence from a filter-then-strip approach to a strip-then-filter approach:

  1. Strip OpenAI ephemeral metadata (itemId, reasoningEncryptedContent) from all parts first
  2. Filter reasoning parts that are truly empty — no text AND no remaining providerMetadata

This is provider-agnostic: any provider that stores meaningful data in providerMetadata on reasoning parts will be preserved automatically. OpenAI placeholders (whose metadata was stripped in step 1) are still correctly removed. Future providers with similar patterns will work without code changes.

How providers use providerMetadata on reasoning parts

Provider Metadata Empty text? Must preserve?
Anthropic { anthropic: { redactedData: "..." } } Yes Yes — required for API round-trip
Anthropic { anthropic: { signature: "..." } } No (has thinking text) Yes — but was never affected
OpenAI { openai: { itemId: "...", reasoningEncryptedContent: "..." } } Can be No — ephemeral, stripped

Changes

  • packages/ai-chat/src/index.ts — Reordered sanitization steps + updated JSDoc
  • packages/ai-chat/src/tests/sanitize-messages.test.ts — Added 2 new tests:
    • Anthropic redacted_thinking blocks (empty text + providerMetadata.anthropic) are preserved
    • OpenAI empty reasoning placeholders are still removed after strip-then-filter

Testing

All 219 tests pass across 24 test files (npm run test).

Change _sanitizeMessageForPersistence to first strip OpenAI ephemeral fields (e.g., itemId, reasoningEncryptedContent) from all parts, then remove only reasoning parts that are truly empty (no text and no remaining providerMetadata). This preserves Anthropic redacted_thinking blocks (empty text with providerMetadata.anthropic.redactedData) while still filtering out OpenAI placeholder reasoning parts. Adds tests covering preservation of Anthropic redacted_thinking and removal of OpenAI placeholders, and includes a changeset. Fixes #978.
@changeset-bot

changeset-bot Bot commented Feb 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 14a93f6

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

This PR includes changesets to release 1 package
Name Type
@cloudflare/ai-chat 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

@pkg-pr-new

pkg-pr-new Bot commented Feb 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/cloudflare/agents@980
npm i https://pkg.pr.new/cloudflare/agents/@cloudflare/ai-chat@980
npm i https://pkg.pr.new/cloudflare/agents/@cloudflare/codemode@980
npm i https://pkg.pr.new/cloudflare/agents/hono-agents@980

commit: 14a93f6

@threepointone
threepointone merged commit 00c576d into main Feb 24, 2026
4 checks passed
@threepointone
threepointone deleted the fix/redacted-thinking-sanitization branch February 24, 2026 23:47
@github-actions github-actions Bot mentioned this pull request Feb 24, 2026
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.

_sanitizeMessageForPersistence strips Anthropic redacted_thinking blocks

1 participant