Skip to content

Python: Replay Anthropic redacted_thinking blocks in tool loops - #10106

Merged
Eduard van Valkenburg (eavanvalkenburg) merged 1 commit into
microsoft:mainfrom
atty57:fix/anthropic-redacted-thinking
Nov 5, 2026
Merged

Eduard van Valkenburg (eavanvalkenburg) merged 1 commit into
microsoft:mainfrom
atty57:fix/anthropic-redacted-thinking

Conversation

@atty57

@atty57 Atharva Vichare (atty57) commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Motivation & Context

agent-framework-anthropic drops redacted_thinking content blocks while parsing a Claude response. The normal function-invocation loop then replays the assistant turn without that block, so the follow-up request carrying the tool_result is missing reasoning that Anthropic requires to be returned unmodified. Only the pause_turn continuation looked at the dropped-content bookkeeping, so ordinary tool loops lost the block silently.

Description & Review Guide

  • What are the major changes?

    • _parse_contents_from_anthropic now maps redacted_thinking to its own reasoning item: Content.protected_data carries the opaque data payload and additional_properties["anthropic"]["reasoning_block"] records the native block type. This mirrors the existing Bedrock redacted-reasoning handling and spec 005's rule that opaque provider reasoning payloads use Content.protected_data.
    • _prepare_message_for_anthropic serializes a marked item back as {"type": "redacted_thinking", "data": ...}, so [thinking, redacted_thinking, tool_use] and [redacted_thinking, tool_use] are replayed in order. A marked item without its payload raises ContentError before the request instead of being dropped silently.
    • Each parsed reasoning block gets its own identity so response aggregation does not fold a redacted_thinking block into an adjacent thinking block when a stream is finalized, and holds its own block in non-streaming responses too.
    • The pause_turn replay guard treats a marked redacted item as replayable only when it has a payload, so continuations over redacted reasoning now proceed instead of stopping early.
    • Native reasoning items are marked so the generated identity does not route an unsigned Anthropic thinking block through the provider-summary path that serializes reasoning without a payload as text.
  • What is the impact of these changes?

    • Redacted reasoning round-trips unchanged in streaming and non-streaming runs, through provider request replay, and after persistence (raw_representation is not required).
    • pause_turn continuations that previously stopped because redacted reasoning was dropped now continue with a faithful transcript.
    • No public API change and no new content type; behavior matches the existing Bedrock and spec 005 provider-metadata conventions.
  • What do you want reviewers to focus on?

    The identity assignment on reasoning items (needed so streamed thinking and redacted_thinking blocks stay separate), and the choice to fail loudly rather than skip a redacted item whose payload is missing.

Related Issue

Fixes #10104

The issue is triaged, reproduced, and assigned, but I could not confirm a ready-for-implementation label or a maintainer comment agreeing with this direction yet. The change follows the direction proposed in the issue and the existing Bedrock redacted-reasoning implementation; I'm happy to adjust if reviewers prefer a different approach. No other open PR addresses this issue.

AI Assistance

  • No material AI assistance was used.
  • This is an AI-assisted contribution. I reviewed, understood, and verified all submitted content and accept responsibility for it.

AI assistance details:
Implementation, tests, and this PR description were drafted with AI assistance. I reviewed and verified the diff, ran the package test suite, and confirmed the reproduction from the issue now passes.

Contribution Checklist

  • The code builds clean without any errors or warnings
  • All unit tests pass, and I have added new tests where possible
  • The PR follows the Contribution Guidelines
  • This PR links to an agreed issue with no competing open PR, or the Related Issue section documents a trivial-change or repository-automation exception.
  • This is not a breaking change. If it is a breaking change, add the breaking change label (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.

redacted_thinking blocks were parsed through the default branch and recorded as dropped content, so the function-invocation loop replayed the assistant turn without them. Anthropic requires the thinking blocks of the last assistant turn, including redacted ones, to be returned unmodified while tool use continues.

Parse redacted_thinking into its own reasoning item carrying the opaque payload in Content.protected_data plus an anthropic namespace marker, following the existing Bedrock redacted-reasoning pattern. Serialize marked items back as redacted_thinking blocks, give each parsed reasoning block its own identity so streaming aggregation keeps thinking and redacted_thinking blocks separate, and fail before the request when a marked item cannot be reconstructed. pause_turn continuations can now replay redacted reasoning instead of stopping early.

Fixes microsoft#10104

Copilot AI 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.

🔵 Needs a closer look

Core-team agreement required by Spec 004 remains unconfirmed for the provider/history serialization and continuation changes, so a maintainer must confirm the intended scope and direction.

No open issues 🎉

What changed in this PR

This PR addresses #10104 by preserving Anthropic redacted_thinking blocks in Agent Framework’s Python integration, allowing tool loops and paused turns to replay assistant reasoning faithfully.

Changes:

  • Stores opaque redacted payloads in Content.protected_data with provider metadata and separate reasoning identities.
  • Replays redacted blocks in order, rejects missing payloads, and enables faithful pause_turn continuation.
  • Adds regression coverage for streaming, non-streaming, and persisted-history replay, and updates the related specifications.
File Description
python/​packages/​anthropic/​tests/​test_anthropic_client.py Adds redacted-reasoning replay, persistence, validation, and continuation tests.
python/​packages/​anthropic/​agent_framework_anthropic/​_chat_client.py Preserves and serializes redacted blocks, separates reasoning identities, and updates replay eligibility.
docs/​specs/​005-python-content-identity-and-protocol-metadata.md Documents the Anthropic redacted-thinking marker and regression coverage.
docs/​specs/​004-python-function-calling-loop.md Updates pause-turn behavior and test references to reflect supported redacted reasoning.

Review effort: Balanced

Merged via the queue into microsoft:main with commit 07b9b3f Nov 5, 2026
52 checks passed

This branch was previously deployed

1 inactive deployment
github-app-auth — 42d6ea8d Deployed Nov 4, 2026 by atty57 via add_label #27135
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Usage: [Issues, PRs], Target: documentation in the code base and learn docs python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: [Bug]: Anthropic redacted_thinking blocks are dropped and never replayed in tool loops

3 participants