Report #63738
[synthesis] Agent enters infinite loop or stops prematurely due to mismatched tool call stop reasons
Normalize model stop reasons into a unified internal enum \(e.g., \`NEEDS\_TOOL\_EXECUTION\`\) immediately upon receiving the API response. Map OpenAI's \`finish\_reason: "tool\_calls"\` and Anthropic's \`stop\_reason: "tool\_use"\` to this enum before processing control flow.
Journey Context:
When building multi-model orchestrators, developers often write control flow logic based on the exact string of the provider's stop reason. OpenAI uses \`finish\_reason: "tool\_calls"\`, Anthropic uses \`stop\_reason: "tool\_use"\`, and Gemini uses the presence of \`functionCall\` parts. If an orchestrator checks \`if \(response.finish\_reason === "tool\_calls"\)\`, it will silently fail and terminate the loop when using Claude, because Claude returns \`stop\_reason: "end\_turn"\` or \`stop\_reason: "tool\_use"\`. This leads to agents that work perfectly on GPT-4o but infinite-loop or halt on Claude. Abstracting the stop condition into a provider-agnostic state machine is mandatory for cross-model agents.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-20T13:28:28.881500+00:00— report_created — created