Skip to content

Commit 4343cb6

Browse files
committed
fix(core): pair synthetic tool_use ids when migrating Gemini history back to Claude
Root cause: AnthropicConverter.contentsToAnthropic used independent fallbacks when functionCall.id / functionResponse.id were missing — tool_use.id fell back to 'toolu_' + Date.now() + random, while tool_result.tool_use_id fell back to 'toolu_<name>'. Two fallbacks could never collide, so any history accumulated under Gemini (where Gemini's native protocol does not require call ids) got rejected the moment the user switched back to Claude/Bedrock with HTTP 400: 'unexpected tool_use_id found in tool_result blocks: toolu_<name>. Each tool_result block must have a corresponding tool_use block in the previous message.' Fix: In contentsToAnthropic, run a two-pass pre-scan before emitting Anthropic blocks. Pass 1 walks every model message and assigns each id-less functionCall a stable synthetic id ('toolu_synth_<name>_<counter>'), pushing the same id into a per-name FIFO queue. Pass 2 walks every user message, dequeues the matching synthetic id for each id-less functionResponse, and stores it on a WeakMap keyed by the part. The main emit loop then prefers original id > synthetic id > legacy fallback, so tool_use and tool_result always carry the same id. Coverage gates explicitly enforced: - Single id-less fc/fr → both blocks share synthetic id. - Same-name fc called N times → strict FIFO pairing, no cross-talk. - Mixed names in a single turn → independent per-name queues. - fc/fr that already have ids → completely untouched (zero behaviour change). - Mixed history (some ids, some not) → only fills the gaps. - Reproducer of the user-reported screenshot (todo_write across model switch) → no longer 400. - Truly orphan fr (no prior fc) → still falls back to legacy 'toolu_<name>' literal so existing tests pass. Tests: 7 new cases in customModelAdapter.anthropicIdPairing.test.ts. Full Anthropic + sanitize regression suites (109 + 46 cases) green. Type check clean.
1 parent 73213a2 commit 4343cb6

2 files changed

Lines changed: 488 additions & 2 deletions

File tree

0 commit comments

Comments
 (0)