mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-02-20 21:30:50 +08:00
fix: handle tool_reference nested inside tool_result.content[]
tool_reference blocks can appear nested inside tool_result.content[] arrays, not just at the top level of messages[].content[]. The prefix logic now iterates into tool_result blocks with array content to find and prefix/strip nested tool_reference.tool_name fields.
This commit is contained in:
@@ -799,6 +799,21 @@ func applyClaudeToolPrefix(body []byte, prefix string) []byte {
|
||||
}
|
||||
path := fmt.Sprintf("messages.%d.content.%d.tool_name", msgIndex.Int(), contentIndex.Int())
|
||||
body, _ = sjson.SetBytes(body, path, prefix+toolName)
|
||||
} else if partType == "tool_result" {
|
||||
// Handle nested tool_reference blocks inside tool_result.content[]
|
||||
nestedContent := part.Get("content")
|
||||
if nestedContent.Exists() && nestedContent.IsArray() {
|
||||
nestedContent.ForEach(func(nestedIndex, nestedPart gjson.Result) bool {
|
||||
if nestedPart.Get("type").String() == "tool_reference" {
|
||||
nestedToolName := nestedPart.Get("tool_name").String()
|
||||
if nestedToolName != "" && !strings.HasPrefix(nestedToolName, prefix) {
|
||||
nestedPath := fmt.Sprintf("messages.%d.content.%d.content.%d.tool_name", msgIndex.Int(), contentIndex.Int(), nestedIndex.Int())
|
||||
body, _ = sjson.SetBytes(body, nestedPath, prefix+nestedToolName)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
@@ -833,6 +848,21 @@ func stripClaudeToolPrefixFromResponse(body []byte, prefix string) []byte {
|
||||
}
|
||||
path := fmt.Sprintf("content.%d.tool_name", index.Int())
|
||||
body, _ = sjson.SetBytes(body, path, strings.TrimPrefix(toolName, prefix))
|
||||
} else if partType == "tool_result" {
|
||||
// Handle nested tool_reference blocks inside tool_result.content[]
|
||||
nestedContent := part.Get("content")
|
||||
if nestedContent.Exists() && nestedContent.IsArray() {
|
||||
nestedContent.ForEach(func(nestedIndex, nestedPart gjson.Result) bool {
|
||||
if nestedPart.Get("type").String() == "tool_reference" {
|
||||
nestedToolName := nestedPart.Get("tool_name").String()
|
||||
if strings.HasPrefix(nestedToolName, prefix) {
|
||||
nestedPath := fmt.Sprintf("content.%d.content.%d.tool_name", index.Int(), nestedIndex.Int())
|
||||
body, _ = sjson.SetBytes(body, nestedPath, strings.TrimPrefix(nestedToolName, prefix))
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
@@ -98,3 +98,31 @@ func TestStripClaudeToolPrefixFromStreamLine_WithToolReference(t *testing.T) {
|
||||
t.Fatalf("content_block.tool_name = %q, want %q", got, "beta")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyClaudeToolPrefix_NestedToolReference(t *testing.T) {
|
||||
input := []byte(`{"messages":[{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_123","content":[{"type":"tool_reference","tool_name":"mcp__nia__manage_resource"}]}]}]}`)
|
||||
out := applyClaudeToolPrefix(input, "proxy_")
|
||||
got := gjson.GetBytes(out, "messages.0.content.0.content.0.tool_name").String()
|
||||
if got != "proxy_mcp__nia__manage_resource" {
|
||||
t.Fatalf("nested tool_reference tool_name = %q, want %q", got, "proxy_mcp__nia__manage_resource")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStripClaudeToolPrefixFromResponse_NestedToolReference(t *testing.T) {
|
||||
input := []byte(`{"content":[{"type":"tool_result","tool_use_id":"toolu_123","content":[{"type":"tool_reference","tool_name":"proxy_mcp__nia__manage_resource"}]}]}`)
|
||||
out := stripClaudeToolPrefixFromResponse(input, "proxy_")
|
||||
got := gjson.GetBytes(out, "content.0.content.0.tool_name").String()
|
||||
if got != "mcp__nia__manage_resource" {
|
||||
t.Fatalf("nested tool_reference tool_name = %q, want %q", got, "mcp__nia__manage_resource")
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyClaudeToolPrefix_NestedToolReferenceWithStringContent(t *testing.T) {
|
||||
// tool_result.content can be a string - should not be processed
|
||||
input := []byte(`{"messages":[{"role":"user","content":[{"type":"tool_result","tool_use_id":"toolu_123","content":"plain string result"}]}]}`)
|
||||
out := applyClaudeToolPrefix(input, "proxy_")
|
||||
got := gjson.GetBytes(out, "messages.0.content.0.content").String()
|
||||
if got != "plain string result" {
|
||||
t.Fatalf("string content should remain unchanged = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user