Skip to content

Conversation

@roomote
Copy link
Contributor

@roomote roomote bot commented Dec 24, 2025

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:

  1. Added xmlFallbackParser field to the Task class to hold the fallback parser instance
  2. Initialize fallback parser when in native protocol mode at the start of each API request
  3. Feed text chunks to the fallback parser during streaming (in addition to normal native protocol handling)
  4. After stream completes, check if:
    • No native tool_call chunks were received (nativeHasToolUses is false)
    • The XML fallback parser found tool calls (fallbackHasToolUses is true)
    • If both conditions are met, use the fallback parser results instead

This ensures tool calls are properly detected and executed regardless of whether the model outputs them in native or XML format.

Test Procedure

  1. TypeScript compilation passes with no errors
  2. All existing Task tests pass (124 tests)
  3. All AssistantMessageParser tests pass (83 tests)

To manually test:

  1. Enable native tool protocol in settings
  2. Use a model that outputs XML tool calls despite native tools being enabled
  3. Verify that tool calls are properly detected and executed

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Testing: New and/or updated tests have been added to cover my changes (if applicable).
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Documentation Updates

  • No documentation updates are required.

Additional Notes

The implementation is minimal and non-invasive:

  • Only adds ~50 lines of code
  • Does not change existing behavior for XML protocol
  • Does not change existing behavior when native tool_call chunks are received
  • Only activates the fallback when native protocol is used AND no native tool calls are detected

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
@roomote
Copy link
Contributor Author

roomote bot commented Dec 24, 2025

Rooviewer Clock   See task on Roo Cloud

Reviewed the XML fallback implementation for native tool protocol. Found 1 issue that needs addressing before merge.

  • XML fallback tool uses need synthetic IDs for native protocol API history tracking

Mention @roomote in a comment to request specific changes to this pull request or fix all unresolved issues.

Comment on lines +3178 to +3185
// 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
Copy link
Contributor Author

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:

Suggested change
// 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.

@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Dec 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels.

Projects

Status: Triage

Development

Successfully merging this pull request may close these issues.

[ENHANCEMENT] Both XML and native tool calls are supported when parsing model tool calls returned

3 participants