-
Notifications
You must be signed in to change notification settings - Fork 2.7k
feat: Support XML tool call fallback when using native tool protocol #10326
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
When native tool protocol is enabled, some models may still output XML-formatted tool calls in their text stream instead of using the native tool_call chunks. This change adds an XML fallback parser that runs alongside the native protocol handler to detect and parse these XML tool calls. The implementation: 1. Initializes an XML fallback parser when in native protocol mode 2. Feeds text chunks to the fallback parser during streaming 3. After stream completes, if no native tool_call chunks were received but the XML fallback parser found tool calls, uses those parsed blocks instead This ensures tool calls are properly detected and executed regardless of whether the model outputs them in native or XML format. Fixes #10325
Reviewed the XML fallback implementation for native tool protocol. Found 1 issue that needs addressing before merge.
Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues. |
| // If native protocol didn't find tools but XML fallback did, use the fallback results | ||
| if (!nativeHasToolUses && fallbackHasToolUses) { | ||
| console.log( | ||
| `[Task#${this.taskId}] XML fallback detected tool calls in native protocol text stream. Using fallback parser results.`, | ||
| ) | ||
| this.assistantMessageContent = fallbackBlocks | ||
| // Mark that we have new content to process | ||
| this.userMessageContentReady = false |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the XML fallback parser is triggered, the parsed tool blocks will lack the id property that native protocol requires. The AssistantMessageParser creates tool_use blocks without IDs, but later in the code (around line 3289), tool uses are only added to assistantContent for API history if toolCallId is truthy. This means when XML fallback is used, the tool calls won't be recorded in the API conversation history, which could cause API errors on subsequent requests since tool_use blocks in assistant messages expect corresponding tool_result blocks.
Consider generating synthetic IDs for fallback-parsed tool uses (e.g., using crypto.randomUUID()) after the fallback is triggered:
| // If native protocol didn't find tools but XML fallback did, use the fallback results | |
| if (!nativeHasToolUses && fallbackHasToolUses) { | |
| console.log( | |
| `[Task#${this.taskId}] XML fallback detected tool calls in native protocol text stream. Using fallback parser results.`, | |
| ) | |
| this.assistantMessageContent = fallbackBlocks | |
| // Mark that we have new content to process | |
| this.userMessageContentReady = false | |
| // If native protocol didn't find tools but XML fallback did, use the fallback results | |
| if (!nativeHasToolUses && fallbackHasToolUses) { | |
| console.log( | |
| `[Task#${this.taskId}] XML fallback detected tool calls in native protocol text stream. Using fallback parser results.`, | |
| ) | |
| // Assign synthetic IDs to fallback tool uses since XML parser doesn't generate them | |
| // but native protocol requires IDs for API history tracking | |
| for (const block of fallbackBlocks) { | |
| if ((block.type === "tool_use" || block.type === "mcp_tool_use") && !(block as any).id) { | |
| (block as any).id = crypto.randomUUID() | |
| } | |
| } | |
| this.assistantMessageContent = fallbackBlocks |
Fix it with Roo Code or mention @roomote and request a fix.
Related GitHub Issue
Closes: #10325
Description
This PR attempts to address Issue #10325. Feedback and guidance are welcome.
When native tool protocol is enabled (v3.37+), some models may still output XML-formatted tool calls in their text stream instead of using the native tool_call chunks. This change adds an XML fallback parser that runs alongside the native protocol handler to detect and parse these XML tool calls.
Key implementation details:
xmlFallbackParserfield to the Task class to hold the fallback parser instanceThis ensures tool calls are properly detected and executed regardless of whether the model outputs them in native or XML format.
Test Procedure
To manually test:
Pre-Submission Checklist
Documentation Updates
Additional Notes
The implementation is minimal and non-invasive: