fix: drop thinking blocks without valid signatures instead of sending signature=None - #82
Open
Dan Shapiro (danshapiro) wants to merge 1 commit into
Conversation
… signature=None Sessions that run partly on non-Anthropic providers (e.g. OpenAI reasoning turns in a mixed-provider routing setup) persist thinking blocks with signature=None or no signature field. The Anthropic history serialization copied the signature through as-is, so every resume sent signature=None and the API rejected the request with HTTP 400 (messages.N.content.0.thinking.signature.str: Input should be a valid string), permanently bricking the session. Anthropic requires a valid non-empty signature to accept a thinking block as input -- the field cannot simply be omitted -- so unsigned blocks are now dropped entirely: - _clean_content_block() returns None for thinking blocks whose signature is not a non-empty string - Call sites in _convert_messages() skip dropped blocks; if an assistant message loses ALL its content this way, a minimal placeholder text block is emitted instead of an empty content array (which Anthropic rejects) - _convert_to_chat_response() no longer persists response thinking blocks without a valid signature, so unsigned blocks can't re-enter history Fixes microsoft/amplifier#330 Generated with Amplifier Co-Authored-By: Amplifier <240397093+microsoft-amplifier@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes microsoft/amplifier#330
Root cause
Sessions that run partly on non-Anthropic providers (e.g. OpenAI reasoning turns under a mixed-provider routing matrix) persist canonical
ThinkingBlocks withsignature: None(or no signature field at all — OpenAI reasoning blocks use encryptedcontentpayloads instead of Anthropic's cryptographic signature). On resume, this provider's history serialization copied the signature through as-is, so the request was sent withsignature: nulland Anthropic rejected it with HTTP 400:Because the same persisted history is replayed on every resume, the session is permanently bricked.
Fix
Anthropic requires a valid non-empty signature to accept a thinking block as input — the field cannot simply be omitted — so unsigned thinking blocks are now dropped entirely:
_clean_content_block(): returnsNonefor a thinking block whosesignatureis not a non-empty string (valid blocks pass through unchanged)._convert_messages()(all three call sites —thinking_block+ tool_calls path,thinking_block-only path, structured-content path): skips dropped blocks. If an assistant message loses ALL of its content this way, a minimal placeholder text block ((internal reasoning omitted)) is emitted instead of an empty content array, which Anthropic also rejects._convert_to_chat_response(): no longer persists response thinking blocks without a valid signature (getattr(block, "signature", None)previously flowedNoneinto canonical history), so unsigned blocks cannot re-enter the transcript from this side either.Evidence / prevalence
messages.137, repaired by stripping 7 unsigned thinking blocks).Tests
New
tests/test_thinking_signature_guard.py(10 tests) covering:signature: None→ dropped, sibling text/tool_use blocks preservedthinking_blockand structured-content paths)_convert_to_chat_responseskips unsigned / keeps signed thinking blocksFull suite: 585 passed (
uv run --with amplifier-core pytest).ruff format --checkclean;ruff checkintroduces no new findings vs. main.Generated with Amplifier