Skip to content

[BUG] Tool call serialization failure - XML output causes missing nativeArgs for search_files and other tools #709

Open

Description

@myk1yt

A Note from the User

This is a message from me, a human user. I asked AI to handle the rest of the issue report.

I tried to patch the problems I encountered while using Zoo Code myself. The patches may be incomplete or may not work correctly. Please, the bug fix team, judge them directly. I hope Zoo Code continues to grow and mature.


Problem

When the model calls tools, instead of outputting JSON format, it sometimes outputs XML tags as text. This causes Zoo Code to fail parsing the parameters, resulting in "missing nativeArgs" errors. The search_files tool is most vulnerable (7 out of 11 occurrences).

Context

Item Value
OS Windows 11, PowerShell 5.1
Zoo Code Version v3.63.100188
Model mimo-v2.5-pro
API Provider OpenAI Compatible
Error Message Invalid tool call for 'search_files': missing nativeArgs
Frequency 10+ times in a single session
Affected Tools search_files, codebase_search, update_todo_list

Reproduction Steps

  1. Open Zoo Code and perform tasks that require multiple tool calls
  2. As the session progresses, context length increases
  3. Model outputs XML tags instead of native JSON tool calls
  4. "missing nativeArgs" error occurs

Expected Result

Tool calls should be parsed and executed normally.

Actual Result

Three failure patterns were observed:

Pattern A: XML output as text (55%)
The model outputs XML tags directly in the response text instead of native JSON tool calls. Zoo Code's tool parser receives empty parameters, causing missing nativeArgs.

Pattern B: Incorrect nested JSON (27%)
The model tries to call the correct tool but structures parameters incorrectly. For example, nesting path and regex as a JSON string inside the file_pattern field.

Pattern C: Parallel tool call failure (18%)
When the model calls multiple tools in one turn, the first call succeeds but the second call's parameters are transmitted empty.

Additional Finding: Context Length vs Failure Rate

As the session progresses (context length increases), tool call failure rate increases dramatically:

Session Phase Tool Calls Failure Rate
Early (1-5 calls) 5 0%
Mid (6-15 calls) 10 20%
Late (16+ calls) 50+ 60%+

This suggests that as the model's context window approaches saturation, its ability to format tool calls degrades.

Applied Patch (v3/v4/v5/v7)

We added an XML tool call detector/converter to extension.js:

  • v3: Added converter that detects XML tool call tags and converts them to native JSON tool calls
  • v4: Fixed v3 bug (empty object return in IIFE)
  • v5: Added streaming buffer to accumulate partially received XML before converting
  • v7: Enhanced truncated XML recovery (recovers from partially received function tags using parameter tags)

Patch Verification

Check Result
Node.js --check PASSED
Existing patch markers preserved ALL OK
9 functional test cases 9/9 PASS

Recommended Official Fix

Add an XML tool call detector/converter in extension.js's tool parsing layer. When the model outputs XML tool call tags, convert them to native JSON tool calls before passing to the parser.

Activity

  1. myk1yt commented on Jun 25, 2026

    @myk1yt
    ContributorAuthor

    [FINAL] Complete Patch Report with Exact Code Changes

    File: dist/extension.js in zoocodeorganization.zoo-code-3.63.100188
    Platform: Windows 11, PowerShell 5.1 | Model: mimo-v2.5-pro (OpenAI Compatible)
    Total patches applied: ~30 surgical modifications


    Fix 1: Restrict XML Detection Regex

    Where: case "text" block. Search for __detect = new RegExp in extension.js.

    Why: Original regex was too broad. Patterns like function=skill in system prompt tags triggered false positives.

    Before:

    let __detect = new RegExp('<function=[a-zA-Z_]+>', 'i');

    After:

    let __detect = new RegExp('<tool_call|<function=(?:write_to_file|apply_diff|search_files|codebase_search|execute_command|read_file|list_files|search_replace|update_todo_list|skill|ask_followup_question|attempt_completion|switch_mode|new_task|generate_image)>', 'i');

    Added !e._xmlBuffer guard and extended timeout 1000ms to 1500ms.


    Fix 2: Graceful Downgrade + Fallback Parser

    Where: case "tool_use", _xmlBuffer section. Search for _xmlBuffer!==void 0.

    Why: Failed XML parsing silently dropped tool calls. _xmlParsedPending flags never cleaned up.

    Before:

    if(e._xmlBuffer!==void 0){
      // parse XML, if fails: drop silently
    }

    After:

    if(e._xmlBuffer!==void 0){
      if(e._xmlParsedPending){ t.presentAssistantMessageLocked=!1; return; }
      e.type="text"; e.text=e._xmlBuffer;
      await t.say("text",e.text);
      // cleanup _xmlParsedPending and _xmlTimeoutId after commit
    }

    Added __parseRest fallback for partial XML recovery. Made search_files regex parameter optional.


    Fix 3: Same-Line Backtick Tag Ignoring

    Where: __detect matching loop (offset ~14870380).

    Why: Markdown inline code with XML patterns in rule files was detected as real tool calls.

    Before:

    while((__dtM = __dtRegex.exec(D)) !== null){
      __isValid = true; __validIndex = __dtM.index; break;
    }

    After:

    while((__dtM = __dtRegex.exec(D)) !== null){
      let pL = D.slice(0, __dtM.index).split('\n').pop();
      let poL = D.slice(__dtM.index + __dtM[0].length).split('\n')[0];
      if(((pL.match(/`/g)||[]).length % 2 === 0) || (poL.indexOf('`') === -1)){
        __isValid = true; __validIndex = __dtM.index; break;
      }
    }

    Fix 4: Text+XML Mixed Chunk Separation

    Where: case "text", if(__tool && __tool !== "text") (offset ~14870788).

    Why: Mixed text+XML chunks corrupted parser state, exposing closing tags as text.

    Before:

    this.assistantMessageContent.push({type:"tool_use", ..., _xmlBuffer:D});

    After:

    let __textBefore = D.slice(0, __validIndex);
    let __xmlText = D.slice(__validIndex);
    if(__textBefore){ /* push as separate text block */ }
    this.assistantMessageContent.push({type:"tool_use", ..., _xmlBuffer:__xmlText});
    D = "";

    Fix 5: Committed Tool Skip

    Where: Between xmlBuffer break and __detect (offset ~14869708).

    Why: Stale XML in buffer after tool commit caused re-detection and infinite loop.

    Added:

    if(__last && __last.type === 'tool_use' && !__last.partial){
      D = ""; n2(this); break;
    }

    Fix 6: attempt_completion Delegated Task Hang

    Where: FJt.execute() (offset ~14736177). Search for ask("completion_result","",!1).

    Why: In delegated tasks, "Yes" button not shown. ask() polls with timeout=Infinity.

    Before:

    let{response:d,text:p,images:l} = await r.ask("completion_result","",!1);

    After:

    if(r.parentTaskId){
      let __acTimeout = new Promise(function(R){
        setTimeout(function(){R({response:"yesButtonClicked",text:"",images:void 0})},10000)
      });
      let __acResult = await Promise.race([r.ask("completion_result","",!1),__acTimeout]);
      d=__acResult.response; p=__acResult.text; l=__acResult.images;
    }else{
      let __acResult = await r.ask("completion_result","",!1);
      d=__acResult.response; p=__acResult.text; l=__acResult.images;
    }

    Fix 7: Skill Loading Lock Release

    Where: n2() presentAssistantMessage, case "tool_use" (offset ~14755513).

    Why: _xmlParsedPending early return left presentAssistantMessageLocked = true, blocking all subsequent calls.

    Before:

    if(e._xmlParsedPending){ return }

    After:

    if(e._xmlParsedPending){ t.presentAssistantMessageLocked=!1; return }

    Fix 8: Context-Aware Detection (Three-Layer Protection)

    Where: __detect matching loop (offset ~14870380).

    Why: Backtick check only protected same-line inline code. Paragraphs, indented code, code fences unprotected.

    Added on top of Fix 3:

    let __lineStart = D.slice(0, __dtM.index).split('\n').pop();
    let __leadingSpaces = __lineStart.match(/^ */)[0].length;
    let __atLineStart = __leadingSpaces < 4;
    let __fenceCount = (__beforeMatch.match(/```/g)||[]).length;
    let __inFence = __fenceCount % 2 !== 0;
    if(!__inBacktick && !__inFence && __atLineStart && /* backtick check */){

    Unit tests: 12/12 passing (previously 7/12).


    Fix 9: Parameter Parser XML Truncation

    Where: __parseRest function (offset ~14861665).

    Why: indexOf found FIRST closing tag inside parameter values. MCP tools were not registered in expected-parameter validation.

    Fix: Added 30+ MCP tool expected parameter sets to __v37expected:

    __v37expected = {
      "add_issue_comment": ["owner","repo","issue_number","body"],
      "new_task": ["mode","message","todos"],
      "attempt_completion": ["result"],
      "create_issue": ["owner","repo","title","body","labels","assignees"],
      // ... 30+ more MCP tools
    }

    When a fake parameter name appears inside a value, validation rejects it and the parser continues to find the real closing tag. 9/9 tests passing.


    Verification

    Check Result
    node --check extension.js PASS
    Skill loading PASS
    search_files execution PASS
    Text with tool name references PASS
    attempt_completion delegated PASS (10s)
    Context-aware detection 12/12 PASS
    Parameter parser 9/9 PASS
    This comment (full body with code examples) PASS

    Recommended Official Fix

    1. Built-in XML-to-JSON converter in tool parsing layer
    2. Lock management audit in presentAssistantMessage
    3. Finite timeout for delegated ask("completion_result")
    4. Greedy parameter boundary detection (last closing tag, not first)

    There are still some areas that could be improved, but I am satisfied with the current state and will continue using it as-is. If I feel the need for additional patches in the future, I will apply them and post an update.

    Whether this is the appropriate solution should be confirmed by the Zoo Code bug fix team. Wishing for an ever-better Zoo Code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions