From 53de27417d4f2e4acec63ff86f8b02a6a1544617 Mon Sep 17 00:00:00 2001 From: Oleg Saprykin Date: Mon, 16 Mar 2026 11:37:40 +0300 Subject: [PATCH] fix(chat): handle Anthropic-format tools in empty-name filter (#346) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The filter introduced in #346 only checked OpenAI-format tool names (tool.function.name), silently dropping all tools when the request arrives in Anthropic Messages API format (tool.name without .function). This happens when LiteLLM proxies requests with anthropic/ model prefix — it translates to Anthropic format before forwarding, so OmniRoute receives Claude-format tools. The filter drops them all, causing Anthropic API to return 400: 'tool_choice.any may only be specified while providing tools'. Fix: check both formats with fn?.name ?? tool.name. --- open-sse/handlers/chatCore.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/open-sse/handlers/chatCore.ts b/open-sse/handlers/chatCore.ts index f940984f82..1919add060 100644 --- a/open-sse/handlers/chatCore.ts +++ b/open-sse/handlers/chatCore.ts @@ -217,14 +217,16 @@ export async function handleChatCore({ return item; }); } - // ── #346: Strip tools with empty function.name ── + // ── #346: Strip tools with empty name ── // Claude Code sometimes forwards tool definitions with empty names, causing // OpenAI-compatible upstream providers to reject with: // "Invalid 'input[N].name': empty string. Expected minimum length 1." + // Handles both OpenAI format ({ function: { name } }) and Anthropic format ({ name }). if (Array.isArray(translatedBody.tools)) { translatedBody.tools = translatedBody.tools.filter((tool: Record) => { const fn = tool.function as Record | undefined; - return fn?.name && String(fn.name).trim().length > 0; + const name = fn?.name ?? tool.name; + return name && String(name).trim().length > 0; }); }