fix(middleware): skip raw tool-call fallback when invalid view carries the same call - #4693
Open
Baldwinzc wants to merge 1 commit into
Open
fix(middleware): skip raw tool-call fallback when invalid view carries the same call#4693Baldwinzc wants to merge 1 commit into
Baldwinzc wants to merge 1 commit into
Conversation
…s the same call DanglingToolCallMiddleware._message_tool_calls collected the raw additional_kwargs tool_calls payload whenever structured tool_calls was empty, even when invalid_tool_calls was non-empty. The raw payload is a fallback serialization of the SAME calls — the OpenAI serializer reaches for it only once both structured views are empty, which is exactly the gating _normalize_tool_call_ids documents and implements. Collecting it alongside a same-id invalid entry counted the call twice and emitted two placeholder ToolMessages for one id — the duplicate-id shape strict OpenAI-compatible providers reject with HTTP 400, the failure this middleware exists to prevent. Gate the raw collection on both structured views being empty, aligning _message_tool_calls with _normalize_tool_call_ids.
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.
Why
DanglingToolCallMiddleware._message_tool_callscollected the rawadditional_kwargs["tool_calls"]payload whenever the structuredtool_callslist was empty — even wheninvalid_tool_callswas non-empty and carried an entry with the same id. The raw payload is a fallback serialization of the same calls: the OpenAI serializer reaches for it only once both structured views are empty, which is exactly the gating_normalize_tool_call_idsdocuments and implements. Collecting it alongside the invalid entry counted the call twice, and_build_patched_messagesthen emitted two placeholder ToolMessages for onetool_call_id— the duplicate-id shape strict OpenAI-compatible providers reject with HTTP 400, which is the failure this middleware exists to prevent.(Defensive consistency fix: the internal gating between
_message_tool_callsand_normalize_tool_call_idsdisagreed; standardlangchain_openainever produces this shape, but patched OpenAI-compatible providers do write rawtool_callsintoadditional_kwargs, so the duplicate-placeholder path is reachable in principle.)What changed
tool_callsandinvalid_tool_calls) are empty, matching the documented serializer behavior and the gating in_normalize_tool_call_ids. The raw-only fallback case is unchanged.Surface area
DanglingToolCallMiddlewaretool-call collectionBug fix verification
backend/tests/test_dangling_tool_call_middleware.py::TestBuildPatchedMessagesPatching::test_raw_fallback_is_skipped_when_invalid_view_carries_the_same_callmain, green on this branch: yes (fails on main with 2 placeholders forcall_x; passes here with exactly 1)Validation
AI assistance
Tool(s) used: Claude Code
How you used it: AI located the inconsistency during a codebase audit, wrote the fix and test; I reviewed the change and verified the red/green test run locally.