fix(providers/openai): gate tool-msg name field to Gemini routes only

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
This commit is contained in:
viettranx committed 2026-04-15 12:46:48 +07:00
1 parent 666bfbaf3c
commit 5590b94994
1 file changed
+11 -5
+11 -5
View File
@@ -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)
}
}
}