Repository navigation
fix(openai): report max_tokens when a Responses function call is cut off - #4139
Merged
liramon2 merged 1 commit intoSep 3, 2026
Conversation
When response.incomplete arrives with reason max_output_tokens after a function_call output item has started, tool_calls took precedence over the length stop reason, so the event loop executed the truncated tool call (with an empty input) instead of running max-tokens recovery. Check the length stop reason first, matching OpenAIModel. Fixes strands-agents#4135
3 tasks done
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
liramon2
approved these changes
Sep 3, 2026
6 of 9 tasks
7 of 9 tasks
14 tasks done
3 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
When the OpenAI Responses API returns
response.incompletewithincomplete_details.reason == "max_output_tokens"after afunction_calloutput item has started,OpenAIResponsesModelreportedstopReason: "tool_use"instead of"max_tokens". The event loop then executed the truncated tool call (withinput: {}because the partial JSON does not parse) instead of runningrecover_message_on_max_tokens_reachedand raisingMaxTokensReachedException.Root cause:
tool_callsis populated onresponse.output_item.added, i.e. before any arguments have streamed, and the finish-reason mapping gavetool_callsprecedence over thelengthstop reason. So any function call in flight when the response was cut off won overlength.Changes:
openai_responses.py: checkstop_reason == "length"beforetool_callswhen computingfinish_reason. This matchesOpenAIModel(Chat Completions), which forwardsfinish_reason == "length"regardless of accumulated tool-call deltas.test_openai_responses.py: add a regression test for a function call cut off bymax_output_tokens, assertingmax_tokensis reported andtool_useis not.Note: #3419 contains the same two-line reordering as part of a much larger change. This PR isolates the stop-reason fix so it can land on its own; the resulting code in that block is identical, so there is no conflict in outcome.
The TypeScript Responses adapter has the same precedence (
responses-adapter.ts,stopReason = 'toolUse'aftermaxTokenswas set). I left it out to keep this PR focused and can follow up separately.Related Issues
Fixes #4135
Documentation PR
No documentation change needed.
Type of Change
Bug fix
Testing
pytest tests/strands/models/test_openai_responses.py: 137 passed (136 existing + 1 new).New test fails on
mainwithout the source change and passes with it.pytest tests/strands/event_loop: 173 passed.ruff format --check,ruff check,mypyon the two changed files: clean.Full
tests/run: 5174 passed; the 2 failures intest_mcp_client.py::test_mcp_client_client_info_passedalso fail on unmodifiedupstream/mainin my environment, and the collection errors are optional-dependency modules (a2a, writer, cedar) not installed in my env.Repro from [BUG] OpenAIResponsesModel reports tool_use instead of max_tokens when a function call is cut off by max_output_tokens #4135 now prints
messageStop: [{'messageStop': {'stopReason': 'max_tokens'}}]and the agent raisesMaxTokensReachedExceptioninstead of invoking the tool with empty input.I ran
hatch run prepare(hatch is not installed locally; I ran the equivalent ruff/mypy/pytest commands above)Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.