From 5590b94994f8e267b380be6f8f85b950fc3c8d91 Mon Sep 17 00:00:00 2001 From: viettranx Date: Wed, 15 Apr 2026 12:46:48 +0700 Subject: [PATCH] fix(providers/openai): gate tool-msg name field to Gemini routes only MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Red-team feedback: the new `name` field on role=tool messages was being sent to ALL OpenAI-compat hosts including Together, Groq, vLLM. Those hosts typically reject unknown fields with HTTP 400 — Gemini is the only backend that requires `name` (via FunctionResponse.name in Google's OpenAI-compat shim). Scope the field to Gemini-only via supportsThoughtSignature, matching how we already gate thought_signature forwarding. Trace: 019d8f33-2de1-7ab2-9a32-9df92cd610dd --- internal/providers/openai_request.go | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/internal/providers/openai_request.go b/internal/providers/openai_request.go index d152339d..b3cac636 100644 --- a/internal/providers/openai_request.go +++ b/internal/providers/openai_request.go @@ -112,11 +112,17 @@ func (p *OpenAIProvider) buildRequestBody(model string, req ChatRequest, stream if m.ToolCallID != "" { msg["tool_call_id"] = p.wireToolCallID(m.ToolCallID) - if name := toolNameByID[m.ToolCallID]; name != "" { - msg["name"] = name - } else if m.Role == "tool" { - slog.Warn("openai: tool msg without matching tool_call", - "provider", p.name, "tool_call_id", m.ToolCallID) + // `name` on role=tool is required by Google Gemini's OpenAI-compat shim + // (FunctionResponse.name). Most other OpenAI-compat hosts (Together, Groq, + // vLLM) either ignore or reject unknown fields — gate to Gemini only to + // avoid silent 400s on stricter proxies. + if supportsThoughtSignature { + if name := toolNameByID[m.ToolCallID]; name != "" { + msg["name"] = name + } else if m.Role == "tool" { + slog.Warn("openai: tool msg without matching tool_call", + "provider", p.name, "tool_call_id", m.ToolCallID) + } } }