microsoft / microsoft/amplifier
Cross-provider resume: thinking blocks with null signature passed to Anthropic API cause invalid_request_error
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.1k
- Forks
- 261
- Avg merge
- 3h 28m
- Merged PRs (30d)
- 13
Description
Summary
When a session created with an OpenAI provider (e.g., gpt-5.6-sol) is later resumed while routing sends requests to Anthropic, the first new user message fails with HTTP 400: messages.9.content.0.thinking.signature.str: Input should be a valid string. The session becomes unusable until thinking blocks are manually stripped from the transcript.
Repro
- Create and run a session with OpenAI provider (e.g., gpt-5.6-sol) — transcript gets assistant messages containing
thinkingcontent blocks withsignature: null(per OpenAI's reasoning-state usage of the canonicalThinkingBlockmodel inamplifier_core/message_models.py:42-49) - Later resume the session while routing-matrix is active and routes to Anthropic provider
- Send a new user message → HTTP 400 error:
invalid_request_error: "messages.9.content.0.thinking.signature.str: Input should be a valid string" - Session is now broken until thinking blocks are manually removed from transcript.jsonl
Real example:
- Session ID:
3aaf5712-7e3c-4d70-9b6e-a1743b84e745(project: iago) - Created with: gpt-5.6-sol (OpenAI)
- Resumed with: anthropic/claude-fable-5 (routing-matrix "balanced")
- Error:
[PROVIDER] Anthropic API error: {"type": "error", "error": {"type": "invalid_request_error", "message": "messages.9.content.0.thinking.signature.str: Input should be a valid string"}...
Root Cause
File: amplifier-module-provider-anthropic/__init__.py
Location: _clean_content_block() at approximately lines 3256–3276
The sanitizer checks only for the presence of the signature key, not its value validity:
if "signature" in block:
cleaned["signature"] = block["signature"] # copies None straight through
OpenAI-origin thinking blocks have signature: null, which Anthropic's API rejects. The core message model (amplifier_core/message_models.py:42-49) intentionally allows signature: str | None — None is the expected value for OpenAI reasoning blocks. Each provider module is responsible for sanitizing that canonical shape for its own API.
Proposed Fix
In provider-anthropic's _clean_content_block():
- If
signatureis not a non-empty string, drop the entire thinking block (Anthropic requires a valid signature to accept a thinking block at all — you cannot omit the field and keep the block). - The two call sites (~lines 3404–3411 and 3457–3461) must gracefully skip a None return.
- Message assembly must tolerate an assistant turn whose only content was thinking blocks (fall back to remaining text/tool_use content, or emit a minimal text block if all content was thinking).
This is provider-specific policy and correctly belongs in the provider module, not core (core's ThinkingBlock intentionally remains provider-neutral).
Module Responsibility
Per Amplifier's kernel architecture (mechanism, not policy):
- Core: Canonical message shape, provider-neutral (correctly allows
signature: None) - Provider module: Translates canonical shape to wire format, validates against its own API constraints
🤖 Generated with Amplifier
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in amplifier-module-provider-anthropic/init.py at _clean_content_block() and inspect its two call sites around lines 3404–3411 and 3457–3461. Read amplifier_core/message_models.py:42-49 to confirm the provider-neutral ThinkingBlock shape. Done means invalid or null signatures are removed with safe handling of None returns, and assistant messages containing only thinking blocks still assemble valid content for Anthropic.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend-api-design
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 65/100