diff --git a/internal/providers/openai.go b/internal/providers/openai.go index 5cbb8bf1..49692143 100644 --- a/internal/providers/openai.go +++ b/internal/providers/openai.go @@ -259,8 +259,9 @@ func (p *OpenAIProvider) buildRequestBody(model string, req ChatRequest, stream inputMessages := req.Messages // Compute provider capability once: does this endpoint support Google's thought_signature? - // We check name, apiBase, and the model string (which covers OpenRouter/LiteLLM routing to Gemini). - supportsThoughtSignature := strings.Contains(strings.ToLower(p.name), "gemini") || + // We check providerType, name, apiBase, and the model string (robust detection for proxies/OpenRouter). + supportsThoughtSignature := strings.Contains(strings.ToLower(p.providerType), "gemini") || + strings.Contains(strings.ToLower(p.name), "gemini") || strings.Contains(strings.ToLower(p.apiBase), "generativelanguage") || strings.Contains(strings.ToLower(model), "gemini") diff --git a/internal/providers/openai_gemini.go b/internal/providers/openai_gemini.go index 55678187..3b2916ec 100644 --- a/internal/providers/openai_gemini.go +++ b/internal/providers/openai_gemini.go @@ -17,7 +17,17 @@ func collapseToolCallsWithoutSig(msgs []Message) []Message { continue } for _, tc := range m.ToolCalls { - if tc.Metadata["thought_signature"] == "" { + // If meta is nil or signature is empty/whitespace, collapse the whole message's tool cycle. + // Checks both snake_case and camelCase for cross-proxy reliability. + sig := "" + if tc.Metadata != nil { + sig = tc.Metadata["thought_signature"] + if sig == "" { + sig = tc.Metadata["thoughtSignature"] + } + } + + if strings.TrimSpace(sig) == "" { for _, tc2 := range m.ToolCalls { collapseIDs[tc2.ID] = true }