From 8ec55a50a83d73ab9e66e627bd924aeb77b008dd Mon Sep 17 00:00:00 2001 From: Badgerbees Date: Fri, 13 Mar 2026 19:59:43 +0700 Subject: [PATCH 1/2] fix: strip extra_content from tool calls for non-Google providers --- pkg/providers/openai_compat/provider.go | 24 ++++++++++++++++++-- pkg/providers/openai_compat/provider_test.go | 8 +++---- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index f97bf3acd..2f8fd44a3 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -117,7 +117,7 @@ func (p *Provider) Chat( requestBody := map[string]any{ "model": model, - "messages": serializeMessages(messages), + "messages": serializeMessages(messages, p.apiBase), } if len(tools) > 0 { @@ -401,13 +401,33 @@ type openaiMessage struct { ToolCallID string `json:"tool_call_id,omitempty"` } +func supportsExtraContent(apiBase string) bool { + u, err := url.Parse(apiBase) + if err != nil { + return false + } + host := u.Hostname() + return strings.HasPrefix(host, "generativelanguage") || strings.HasSuffix(host, ".googleapis.com") +} + // serializeMessages converts internal Message structs to the OpenAI wire format. // - Strips SystemParts (unknown to third-party endpoints) // - Converts messages with Media to multipart content format (text + image_url parts) // - Preserves ToolCallID, ToolCalls, and ReasoningContent for all messages -func serializeMessages(messages []Message) []any { +func serializeMessages(messages []Message, apiBase string) []any { + supportsExtra := supportsExtraContent(apiBase) + out := make([]any, 0, len(messages)) for _, m := range messages { + if len(m.ToolCalls) > 0 && !supportsExtra { + cleanCalls := make([]ToolCall, len(m.ToolCalls)) + for i, tc := range m.ToolCalls { + tc.ExtraContent = nil + cleanCalls[i] = tc + } + m.ToolCalls = cleanCalls + } + if len(m.Media) == 0 { out = append(out, openaiMessage{ Role: m.Role, diff --git a/pkg/providers/openai_compat/provider_test.go b/pkg/providers/openai_compat/provider_test.go index 41f278a1b..358832aad 100644 --- a/pkg/providers/openai_compat/provider_test.go +++ b/pkg/providers/openai_compat/provider_test.go @@ -648,7 +648,7 @@ func TestSerializeMessages_PlainText(t *testing.T) { {Role: "user", Content: "hello"}, {Role: "assistant", Content: "hi", ReasoningContent: "thinking..."}, } - result := serializeMessages(messages) + result := serializeMessages(messages, "") data, err := json.Marshal(result) if err != nil { @@ -670,7 +670,7 @@ func TestSerializeMessages_WithMedia(t *testing.T) { messages := []protocoltypes.Message{ {Role: "user", Content: "describe this", Media: []string{"data:image/png;base64,abc123"}}, } - result := serializeMessages(messages) + result := serializeMessages(messages, "") data, _ := json.Marshal(result) var msgs []map[string]any @@ -703,7 +703,7 @@ func TestSerializeMessages_MediaWithToolCallID(t *testing.T) { messages := []protocoltypes.Message{ {Role: "tool", Content: "image result", Media: []string{"data:image/png;base64,xyz"}, ToolCallID: "call_1"}, } - result := serializeMessages(messages) + result := serializeMessages(messages, "") data, _ := json.Marshal(result) var msgs []map[string]any @@ -833,7 +833,7 @@ func TestSerializeMessages_StripsSystemParts(t *testing.T) { }, }, } - result := serializeMessages(messages) + result := serializeMessages(messages, "") data, _ := json.Marshal(result) raw := string(data) From 8fab3761abcb4d2ba949413453140de0ff48aa79 Mon Sep 17 00:00:00 2001 From: Badgerbees Date: Sat, 14 Mar 2026 14:01:54 +0700 Subject: [PATCH 2/2] style(openai_compat): fix gci formatting on provider.go --- pkg/providers/openai_compat/provider.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/providers/openai_compat/provider.go b/pkg/providers/openai_compat/provider.go index 2f8fd44a3..c570480f4 100644 --- a/pkg/providers/openai_compat/provider.go +++ b/pkg/providers/openai_compat/provider.go @@ -416,7 +416,7 @@ func supportsExtraContent(apiBase string) bool { // - Preserves ToolCallID, ToolCalls, and ReasoningContent for all messages func serializeMessages(messages []Message, apiBase string) []any { supportsExtra := supportsExtraContent(apiBase) - + out := make([]any, 0, len(messages)) for _, m := range messages { if len(m.ToolCalls) > 0 && !supportsExtra {