Skip to content

Python: [Bug]: Empty signed thinking blocks are dropped during Anthropic streaming replay #8168

Closed

Description

@coding-totoro

Description

An empty signed Anthropic thinking block is lost when streaming updates are combined and serialized for tool-result replay.

The stream contains a thinking block with thinking: "", followed by a signature_delta. ChatResponse.from_updates() merges these into reasoning content with text=None. The Anthropic serializer then skips it as an orphan signature. The associated tool_use block survives.

Expected: preserve {"type": "thinking", "thinking": "", "signature": "synthetic-signature"} before the tool call. Anthropic requires thinking blocks to be replayed unchanged, including empty thinking text.

Actual: only the tool call is serialized. Nonempty thinking text passes the control assertion below.

Code Sample

Offline reproduction using synthetic SDK events and signatures. No network call or real credentials are required; the model name is an unused constructor argument.

python -m pip install agent-framework-core==1.17.0 agent-framework-anthropic==1.0.0b260827 anthropic==0.116.0
import json
from agent_framework import ChatResponse
from agent_framework_anthropic import AnthropicClient
from anthropic.types.beta import (
    BetaRawContentBlockStartEvent,
    BetaRawContentBlockDeltaEvent,
)

client = AnthropicClient(api_key='unused-offline-test', model='claude-sonnet-4-6')

def replay(thinking_text):
    # Synthetic API events: no network, real provider parsing and SDK aggregation.
    events = [
        BetaRawContentBlockStartEvent.model_validate({
            'type': 'content_block_start', 'index': 0,
            'content_block': {'type': 'thinking', 'thinking': thinking_text, 'signature': ''},
        }),
        BetaRawContentBlockDeltaEvent.model_validate({
            'type': 'content_block_delta', 'index': 0,
            'delta': {'type': 'signature_delta', 'signature': 'synthetic-signature'},
        }),
        BetaRawContentBlockStartEvent.model_validate({
            'type': 'content_block_start', 'index': 1,
            'content_block': {'type': 'tool_use', 'id': 'toolu_test', 'name': 'lookup', 'input': {}},
        }),
    ]
    updates = [client._process_stream_event(event) for event in events]
    response = ChatResponse.from_updates([u for u in updates if u is not None])
    message = response.messages[0]
    reasoning = next(c for c in message.contents if c.type == 'text_reasoning')
    prepared = client._prepare_message_for_anthropic(message)
    return {
        'input_thinking': thinking_text,
        'merged_thinking': reasoning.text,
        'merged_signature': reasoning.protected_data,
        'replayed_content': prepared['content'],
    }

print(json.dumps(replay(''), indent=2))
assert replay('Visible summary.')['replayed_content'][0]['type'] == 'thinking'
assert replay('')['replayed_content'][0]['type'] == 'thinking'  # Fails

Error Messages / Stack Traces

The final assertion fails. Before serialization, merged_thinking is null while merged_signature is still "synthetic-signature". replayed_content contains only tool_use.

This reports silent block loss, not a reproduced API error or a measured effect on model answers.

Package Versions

agent-framework-core==1.17.0, agent-framework-anthropic==1.0.0b260827, anthropic==0.116.0.

Python Version

3.13.15

Additional Context

Related to #5783 / #5784. Those cover orphan signatures; this case begins with an actual empty thinking block that aggregation turns into an apparent orphan.

The relevant code remains in upstream commit a03bb909c694ad27f0b14d310d39e7f9e232ad39 (source inspection): reasoning-content merge and Anthropic serializer.

Suggested regression coverage: preserve empty thinking text and its signature through stream parsing, aggregation, and replay, while retaining the existing true-orphan-signature behavior.

Activity

  1. added
    pythonUsage: [Issues, PRs], Target: Python
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Sep 8, 2026
  2. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Sep 8, 2026
  3. github-actions commented on Sep 8, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    Repro: python/packages/core/agent_framework/_types.py::Content._add_text_reasoning_content at lines 1561-1570 turns an actual empty Anthropic thinking block plus its signature delta into reasoning with text=None and retained protected data; python/packages/anthropic/agent_framework_anthropic/_chat_client.py::_prepare_message_for_anthropic then omits it at lines 992-1001. The trigger is a streaming thinking block with thinking="", followed by signature_delta and tool_use. Minimal repro: run test_streaming_replay_preserves_empty_signed_thinking_block, which observes only the tool call in serialized replay.

    • Failing test: python/packages/anthropic/tests/test_anthropic_client.py::test_streaming_replay_preserves_empty_signed_thinking_block
    • Files examined: python/packages/core/agent_framework/_types.py, python/packages/anthropic/agent_framework_anthropic/_chat_client.py, python/packages/anthropic/tests/test_anthropic_client.py, python/packages/core/pyproject.toml, python/packages/anthropic/pyproject.toml
    • Tests run: test_prepare_message_for_anthropic_text_reasoning_with_signature, test_prepare_message_for_anthropic_skips_orphan_signature_only_reasoning, test_streaming_replay_preserves_empty_signed_thinking_block
    • Reported version: agent-framework-core==1.17.0, agent-framework-anthropic==1.0.0b260827
    • Current version: agent-framework-core==1.17.0, agent-framework-anthropic==1.0.0b260827
  4. added
    agentsUsage: [Issues, PRs], Target: Single agent
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Sep 8, 2026
  5. leilei3167 commented on Sep 9, 2026

    @leilei3167
    Contributor

    looking at this

  6. added a commit that references this issue on Sep 9, 2026
    2cb63d3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

agentsUsage: [Issues, PRs], Target: Single agentpythonUsage: [Issues, PRs], Target: PythonreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions