From 5a2ff8c8364f45e97f2334f551ed1e5e8651e7fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BE=84=E6=BD=AD?= Date: Sat, 14 Feb 2026 21:52:25 +0800 Subject: [PATCH] fix(ai-proxy): convert Claude tool_use stop_reason to OpenAI tool_calls format (#3506) --- .../extensions/ai-proxy/provider/claude.go | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/plugins/wasm-go/extensions/ai-proxy/provider/claude.go b/plugins/wasm-go/extensions/ai-proxy/provider/claude.go index ca8bf5704..3ace49bd4 100644 --- a/plugins/wasm-go/extensions/ai-proxy/provider/claude.go +++ b/plugins/wasm-go/extensions/ai-proxy/provider/claude.go @@ -562,9 +562,29 @@ func (c *claudeProvider) buildClaudeTextGenRequest(origRequest *chatCompletionRe } func (c *claudeProvider) responseClaude2OpenAI(ctx wrapper.HttpContext, origResponse *claudeTextGenResponse) *chatCompletionResponse { + // Extract text content and tool calls from Claude response + var textContent string + var toolCalls []toolCall + for _, content := range origResponse.Content { + switch content.Type { + case contentTypeText: + textContent = content.Text + case "tool_use": + args, _ := json.Marshal(content.Input) + toolCalls = append(toolCalls, toolCall{ + Id: content.Id, + Type: "function", + Function: functionCall{ + Name: content.Name, + Arguments: string(args), + }, + }) + } + } + choice := chatCompletionChoice{ Index: 0, - Message: &chatMessage{Role: roleAssistant, Content: origResponse.Content[0].Text}, + Message: &chatMessage{Role: roleAssistant, Content: textContent, ToolCalls: toolCalls}, FinishReason: util.Ptr(stopReasonClaude2OpenAI(origResponse.StopReason)), } @@ -600,6 +620,8 @@ func stopReasonClaude2OpenAI(reason *string) string { return finishReasonStop case "max_tokens": return finishReasonLength + case "tool_use": + return finishReasonToolCall default: return *reason }