diff --git a/apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts b/apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts index 4c10d87ca3..1c68e1fd75 100644 --- a/apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts +++ b/apps/web/src/lib/ai-gateway/providers/openrouter/request-helpers.ts @@ -286,6 +286,14 @@ export function removeChatCompletionsReasoning(request: OpenRouterChatCompletion } } +export function removeChatCompletionsToolNames(request: OpenRouterChatCompletionRequest) { + for (const message of request.messages) { + if (message.role === 'tool' && 'name' in message) { + delete message.name; + } + } +} + /** * Inverse of the `mapReasoningContentToDetails` response transform: folds * OpenRouter-style `reasoning_details` back into the DeepSeek-style diff --git a/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts b/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts index b524040e9b..bd546f2b0b 100644 --- a/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts +++ b/apps/web/src/lib/ai-gateway/providers/provider-definitions.ts @@ -1,5 +1,8 @@ import { getEnvVariable } from '@/lib/dotenvx'; -import { isReasoningExplicitlyDisabled } from '@/lib/ai-gateway/providers/openrouter/request-helpers'; +import { + isReasoningExplicitlyDisabled, + removeChatCompletionsToolNames, +} from '@/lib/ai-gateway/providers/openrouter/request-helpers'; import type { Provider } from '@/lib/ai-gateway/providers/types'; import { applyVercelSettings } from '@/lib/ai-gateway/providers/vercel'; @@ -118,8 +121,10 @@ export default { context.request.body.reasoning_effort ?? undefined); delete context.request.body.reasoning; + removeChatCompletionsToolNames(context.request.body); } delete context.request.body.provider; + delete context.request.body.user; }, }, STREAMLAKE: { diff --git a/apps/web/src/tests/openrouter-request-helpers.test.ts b/apps/web/src/tests/openrouter-request-helpers.test.ts index aa7ec89d7d..68f02fbc86 100644 --- a/apps/web/src/tests/openrouter-request-helpers.test.ts +++ b/apps/web/src/tests/openrouter-request-helpers.test.ts @@ -1,8 +1,34 @@ import { describe, expect, test } from '@jest/globals'; -import { addCacheBreakpoints } from '@/lib/ai-gateway/providers/openrouter/request-helpers'; -import type { GatewayRequest } from '@/lib/ai-gateway/providers/openrouter/types'; +import { + addCacheBreakpoints, + removeChatCompletionsToolNames, +} from '@/lib/ai-gateway/providers/openrouter/request-helpers'; +import type { + GatewayRequest, + OpenRouterChatCompletionRequest, +} from '@/lib/ai-gateway/providers/openrouter/types'; import type OpenAI from 'openai'; +describe('removeChatCompletionsToolNames', () => { + test('removes names from tool messages only', () => { + const toolMessage: OpenAI.ChatCompletionToolMessageParam & { name?: string } = { + role: 'tool', + content: 'Tool result', + tool_call_id: 'call_123', + name: 'read_file', + }; + const request: OpenRouterChatCompletionRequest = { + model: 'test-model', + messages: [{ role: 'user', content: 'Run the tool', name: 'user-name' }, toolMessage], + }; + + removeChatCompletionsToolNames(request); + + expect(toolMessage.name).toBeUndefined(); + expect(request.messages[0]).toHaveProperty('name', 'user-name'); + }); +}); + describe('addCacheBreakpoints', () => { test('adds a cache breakpoint to the system message and the last eligible chat completions message when none exist', () => { const request: GatewayRequest = {