Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions pkg/functions/parse.go
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,7 @@ func ParseFunctionCall(llmresult string, functionConfig FunctionsConfig) []FuncC
results := []FuncCallResults{}
llmResults := []string{}

returnResult := func(results []string) (result []FuncCallResults, e error) {
extractJSON := func(results []string) (result []FuncCallResults, e error) {
// As we have to change the result before processing, we can't stream the answer token-by-token (yet?)
result = make([]FuncCallResults, 0)

Expand Down Expand Up @@ -1593,7 +1593,7 @@ func ParseFunctionCall(llmresult string, functionConfig FunctionsConfig) []FuncC
if len(llmResults) == 0 {
llmResults = append(llmResults, llmresult)
}
results, _ = returnResult(llmResults)
results, _ = extractJSON(llmResults)
}

// Determine which XML format to use (if any)
Expand Down Expand Up @@ -1632,8 +1632,16 @@ func ParseFunctionCall(llmresult string, functionConfig FunctionsConfig) []FuncC
// But skip if JSONRegexMatch or ResponseRegex was used (they already extracted the content)
xmlResults, err := ParseXML(llmresult, xmlFormat)
if err == nil && len(xmlResults) > 0 {
xlog.Debug("Found additional XML tool calls alongside JSON", "xml_count", len(xmlResults))
results = append(results, xmlResults...)
// Check if JSON is inside XML tags, if so, skip it
for _, result := range xmlResults {
jsonResults, _ := extractJSON([]string{result.Name})
if len(jsonResults) > 0 {
xlog.Debug("Found valid JSON inside XML tags, skipping XML parsing", "json_count", len(jsonResults))
} else {
xlog.Debug("Found additional XML tool calls alongside JSON", "xml_count", len(xmlResults))
results = append(results, xmlResults...)
}
}
}
}

Expand Down
17 changes: 17 additions & 0 deletions pkg/functions/parse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,23 @@ Final text`
Expect(results[0].Name).To(Equal("first"))
Expect(results[1].Name).To(Equal("second"))
})

It("should not duplicate parse JSON inside tool_call tags", func() {
// This test reproduces a bug where JSON inside <tool_call> tags
// gets parsed twice: once as JSON (correctly) and once as XML (incorrectly)
// The XML parser should not run when JSON parsing already found valid results
input := `<tool_call>
{"name": "get_current_weather", "arguments": {"location": "Beijing", "unit": "celsius"}}
</tool_call>`

results := ParseFunctionCall(input, functionConfig)
// Should only have 1 result, not 2 (one correct + one malformed)
Expect(results).To(HaveLen(1), "Should not create duplicate entries when JSON is inside XML tags")
Expect(results[0].Name).To(Equal("get_current_weather"))
Expect(results[0].Arguments).To(Equal(`{"location":"Beijing","unit":"celsius"}`))
// Verify the name is not the entire JSON object (which would indicate malformed XML parsing)
Expect(results[0].Name).NotTo(ContainSubstring(`{"name"`), "Function name should not contain JSON object")
})
})

Context("Iterative Parser (ChatMsgParser)", func() {
Expand Down
Loading