From 5b7cdaa729ea7163a6b393898d459244bca96c84 Mon Sep 17 00:00:00 2001 From: "CJACK." <155826701+CJackHwang@users.noreply.github.com> Date: Sun, 19 Apr 2026 23:11:24 +0800 Subject: [PATCH] Fix XML tool-call parsing for fenced markdown examples --- internal/toolcall/toolcalls_parse.go | 57 ++++++++++++++++++++++++++++ internal/toolcall/toolcalls_test.go | 19 ++++++++++ 2 files changed, 76 insertions(+) diff --git a/internal/toolcall/toolcalls_parse.go b/internal/toolcall/toolcalls_parse.go index f0cb2ac..e1e934c 100644 --- a/internal/toolcall/toolcalls_parse.go +++ b/internal/toolcall/toolcalls_parse.go @@ -39,6 +39,11 @@ func parseToolCallsDetailedXMLOnly(text string) ToolCallParseResult { return result } result.SawToolCallSyntax = looksLikeToolCallSyntax(trimmed) + trimmed = stripFencedCodeBlocks(trimmed) + trimmed = strings.TrimSpace(trimmed) + if trimmed == "" { + return result + } parsed := parseXMLToolCalls(trimmed) if len(parsed) == 0 { @@ -83,3 +88,55 @@ func looksLikeToolCallSyntax(text string) bool { strings.Contains(lower, "\n```\nDo not execute it." + res := ParseToolCallsDetailed(text, []string{"read_file"}) + if len(res.Calls) != 0 { + t.Fatalf("expected no parsed calls for fenced example, got %#v", res.Calls) + } +} + +func TestParseToolCallsParsesOnlyNonFencedXMLToolCall(t *testing.T) { + text := "```xml\nread_file{\"path\":\"README.md\"}\n```\nsearch{\"q\":\"golang\"}" + res := ParseToolCallsDetailed(text, []string{"read_file", "search"}) + if len(res.Calls) != 1 { + t.Fatalf("expected exactly one parsed call outside fence, got %#v", res.Calls) + } + if res.Calls[0].Name != "search" { + t.Fatalf("expected non-fenced tool call to be parsed, got %#v", res.Calls[0]) + } +}