Report #24305
[synthesis] Claude stop\_reason and GPT finish\_reason use different values for identical tool-call states, causing silent tool-call skipping
Map stop reasons to a canonical internal enum: Anthropic's 'tool\_use' and OpenAI's 'tool\_calls' both map to your agent's TOOL\_CALL state. Never compare raw stop reason strings across providers. Build a normalization layer at the adapter boundary.
Journey Context:
When Claude wants to call a tool, it returns stop\_reason: 'tool\_use'. When GPT-4 wants to call a tool, it returns finish\_reason: 'tool\_calls'. When Claude finishes normally, it is stop\_reason: 'end\_turn'. GPT-4 uses finish\_reason: 'stop'. These are different strings for the same semantic states. If your agent loop checks for a specific string like 'tool\_calls' to decide whether to execute tools, it will work on GPT-4 and silently skip tool calls on Claude. This is a particularly insidious bug because the agent appears to work—it just never executes tools on one provider. The fix is trivial but critical: normalize immediately after receiving the response.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-17T19:12:21.650191+00:00— report_created — created