fix(functions): validate auto-detected XML tool-call names — robust glm-4.5/Hermes guard (#9722, supersedes #9940)#10059
Merged
Conversation
The XML tool-call auto-detector tries every preset, including glm-4.5 whose
tool block is <tool_call>name...</tool_call>. When a Hermes/NousResearch model
emits <tool_call>{"name":"bash","arguments":{...}}</tool_call>, glm-4.5
mis-claims the block and returns the entire JSON object (or leading prose, or a
JSON array) as the function NAME. The misparse then wins over the JSON parser,
so streaming clients receive a tool call whose name is a JSON blob.
Guard the auto-detect paths in ParseXMLIterative: a returned tool name must look
like a real function name ([A-Za-z0-9_.-]+). Results that don't are dropped so
auto-detection falls through to the next format and ultimately to JSON parsing,
which handles Hermes correctly. An explicitly forced format (format != nil) is
left untouched and trusted verbatim.
This supersedes PR #9940, which dropped only names with a leading "{". That
narrower check misses leading prose ("Sure: {...}"), JSON arrays ("[{...}]")
and brace-less garbage ("name: bash, ..."); the name-shape check rejects all of
them while still accepting legitimate glm-4.5 calls. The fix applies to both the
streaming worker and the non-streaming ParseFunctionCall path, which both call
ParseXMLIterative with auto-detection.
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Assisted-by: Claude:claude-opus-4-8 [Claude Code]
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.
What
Robust fix for the XML tool-call auto-detect misparse behind #9722, and a supersession of #9940.
Problem
ParseXMLIterative(auto-detect,format == nil) tries every preset. glm-4.5's tool block is<tool_call>name…</tool_call>, so when a Hermes/NousResearch model emits:glm-4.5 mis-claims the block and returns the entire JSON object as the function name. That misparse wins over the JSON parser, so streaming clients get a tool call whose
nameis a JSON blob (and the correct call can getlastEmittedCount-suppressed downstream).Fix
Guard the auto-detect paths: a returned tool-call name must look like a real function name (
^[A-Za-z0-9_.\-]+$). Results that don't are dropped, so auto-detection falls through to the next format and ultimately to JSON parsing, which handles Hermes correctly.format != nil, e.g.xml_format_preset: glm-4.5) is trusted verbatim.ParseFunctionCallpath (both callParseXMLIterativewith auto-detect).Supersedes #9940
#9940 dropped only names with a leading
{. That misses other misparse shapes. The name-shape check rejects them all while still accepting legitimate glm-4.5 calls:<tool_call>…</tool_call>body{-filter (#9940){"name":"bash",…}{"name":…}Sure: {…}(leading prose)Sure: {…}[{…}](parallel calls)[{…}]name: bash, …(brace-less)name: bash, …Tests (TDD)
pkg/functions/parse_glm_9722_test.go:<tool_call>get_weather<arg_key>…</arg_key><arg_value>…</arg_value></tool_call>still parses toget_weather.pkg/functions/...andcore/http/endpoints/openaisuites pass;golangci-lint --new-from-merge-base=master→ 0 issues.Note on the broader #9722
The streaming double-emission originally reported in #9722 was against pre-2026-05-22 code; the streaming worker has since been refactored (autoparser tool calls are deferred-only and
lastEmittedCount-guarded), and #10055 added the autoparser-active skip. This PR addresses the remaining non-autoparser brittleness (the glm-4.5 name misparse) that #9940 targeted.🤖 Generated with Claude Code