fix: preserve agent_message boundaries to prevent Anthropic signed-thinking replay failures - #93
Closed
Wibias wants to merge 2 commits into
Closed
fix: preserve agent_message boundaries to prevent Anthropic signed-thinking replay failures#93Wibias wants to merge 2 commits into
Wibias wants to merge 2 commits into
Conversation
…g replay failures
…ted sub-agents receive spawn payloads sanitizeEncryptedContentInPlace now runs on the raw body BEFORE parseRequest, for every path. Previously it ran only for native-bound models (no provider prefix) and only after parsing, so routed models (anthropic/*, opencode-go/*) built their parsed messages from the unsanitized input: the agent_message branch dropped the encrypted_content part carrying the actual task text, and spawned sub-agents received an empty NEW_TASK envelope. _rawBody shares the same object reference, so the native passthrough keeps the rewritten parts too; genuine Fernet ciphertext stays byte-identical (looksLikeBackendCiphertext). Adds a regression test mirroring the exact handleResponses order (sanitize, then parse).
Owner
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.
Preserve
agent_messageboundaries to prevent Anthropic signed-thinking replay failuresSummary
This change adds explicit parsing support for Responses API
agent_messageitems.Previously,
agent_messageitems were silently ignored while reconstructing the conversation history. This could remove an important turn boundary between two assistant responses and cause separately generated Anthropic thinking blocks to be combined into a single assistant message.For Anthropic models using extended or adaptive thinking, those thinking blocks are cryptographically signed and must be replayed exactly as they appeared in the original response. Combining them with content from a later assistant response changes the structure of the signed message and causes Anthropic to reject the request with HTTP 400.
The parser now preserves an
agent_messageas a user-role message, ensuring that assistant turns on either side remain separate.Problem
The failure occurred in conversations involving subagents.
A typical sequence looked like this:
Because the parser did not handle
agent_message, the subagent message disappeared from the reconstructed conversation.The resulting Anthropic request effectively became:
This was not the original assistant response structure.
Anthropic therefore rejected the replayed request with an error similar to:
The issue only appeared after a particular combination of events:
agent_message.This made the failure appear to be an Anthropic provider, streaming, serialization, or tool-call issue, even though the actual corruption occurred earlier while parsing and rebuilding the conversation history.
Root cause
agent_messagewas a valid input item but had no dedicated handling in the Responses parser.Since the item was skipped entirely, it could not act as a boundary between the assistant response before it and the assistant response after it.
The parser subsequently reconstructed adjacent assistant content as though it belonged to the same logical assistant turn.
That behavior is especially problematic for Anthropic thinking blocks because their signatures are tied to the original response structure. Their contents and placement cannot be modified during replay.
The thinking data itself was not invalid. The problem was that valid thinking blocks from separate responses were being placed into a newly constructed assistant message that never existed in the original conversation.
Fix
The parser now handles
agent_messageexplicitly.Its content is converted using the existing
inputContentParts()normalization and stored as a user-role message:Treating the message as external input to the parent agent preserves the required conversational structure:
This ensures that the assistant response after the subagent message can still be assembled normally, while the earlier signed thinking block remains in its original assistant turn.
Why a user-role message is used
An
agent_messageis delivered to the parent agent rather than generated by the parent agent itself.From the parent agent's perspective, it is new external input. Representing it as a user-role turn therefore provides the correct structural boundary without pretending that the message was part of either surrounding assistant response.
The primary requirement is not merely preserving the subagent text. It is preserving the separation between the two assistant turns.
Without that boundary, signed thinking blocks from different Anthropic responses can be merged again.
Regression test
A regression test was added for the exact sequence that previously caused the failure:
The test asserts that the parsed message roles are:
It also verifies that:
The regression test passes with:
Impact
This fixes conversation continuation failures for Anthropic models when subagent messages appear between signed assistant reasoning turns.
It prevents:
The change is intentionally limited to parser behavior. No provider-specific workaround or mutation of Anthropic thinking blocks is required.
Validation
The fix was validated by:
agent_messageparsing