Repository navigation
fix(formatters): keep tool_calls when replaying instruct/react turns - #1787
Draft
simonyang08 wants to merge 1 commit into
Draft
simonyang08 wants to merge 1 commit into
simonyang08 wants to merge 1 commit into
Conversation
Components whose _parse reduces a model turn to text (Instruction, ReactThought) lost the turn's tool_calls in ChatFormatter.to_chat_messages, so a following tool message referenced a call the provider never saw and strict providers rejected the second turn of the loop. When a tool message immediately follows the turn, rebuild it through Message._parse_output, which preserves provider-shaped tool_calls and captured reasoning; turns without an answering tool message stay text-only so unanswered calls do not go out as dangling tool_calls. Assisted-by: ZCode (GLM)
This branch has not been deployed
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.
Opening as a follow-up to my claim comment on #1784 — happy to yield or close if a team member prefers to take this; the issue looked unclaimed so I prepared the fix while awaiting assignment.
Problem
With a
ChatContext, tool loops built oninstruct()(andreact()) replay the tool-calling assistant turn without itstool_calls:Instruction._parseandReactThought._parsereduce the turn to text, andChatFormatter.to_chat_messagesrebuilt it as a plain assistant message. The followingtoolmessage then answers a call the provider never saw, and strict providers reject the second turn of the loop (OpenAI 400 on an orphaned tool message, LiteLLMAPIConnectionError, Anthropic orphanedtool_result).session.chat()loops were unaffected becauseMessage._parsealready preserves tool calls.Fix
ChatFormatter.to_chat_messagesgains a small repair pass: when a computedModelOutputThunkcarriestool_callsand the next message has roletool, the turn is rebuilt through the provider-shaped parsing (now exposed as the staticMessage._parse_output, withMessage._parsedelegating to it). Turns without an answering tool message stay text-only, so calls the caller never ran don't go out as danglingtool_calls— strict providers reject those too.Verification
tool_callswhen atoolmessage follows, and gains none when it doesn't (2 passed).pytest test/formatters/ test/stdlib/components/test_chat.py test/backends/test_tool_serialization_unit.py test/backends/test_utils.py— 234 passed / 5 skipped.ruff format/ruff checkclean on touched files; docs quality gate (audit_coverage --quality) reports 0 issues.Closes #1784