Report #50857
[synthesis] Agent loop misinterprets model's completion signal—terminates early or loops forever—because stop reason semantics differ across providers
Normalize stop reasons in your agent framework: map OpenAI finish\_reason 'tool\_calls' → 'tool\_use', 'stop' → 'end\_turn' \(Anthropic equivalents\). Always check for tool call presence in the response object as the primary signal, not the stop reason alone. Treat any response with non-empty tool\_calls array as 'model wants to continue,' regardless of stop reason. Treat empty tool\_calls \+ stop/end\_turn as truly 'done.'
Journey Context:
OpenAI uses finish\_reason: 'tool\_calls' when the model wants to invoke tools and 'stop' when done. Anthropic uses stop\_reason: 'tool\_use' and 'end\_turn'. The semantic overlap is deceptive: OpenAI's 'stop' can mean the model completed its answer OR that it hit a token limit \(vs. 'length'\), while Anthropic's 'end\_turn' more clearly means the model chose to stop. The critical cross-model trap: Gemini can return a STOP finish reason while also including tool calls in the response body, creating an ambiguous state that breaks naive agent loops. Additionally, OpenAI's 'stop' after a tool-call-heavy conversation sometimes means 'I think I'm done' but the user's original intent wasn't fulfilled. The synthesis: stop reasons are hints, not contracts. The tool\_calls array is the authoritative signal. Build your agent loop to check the array first and the stop reason second.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T15:50:49.055110+00:00— report_created — created