From 8f67e00160a50564495d3a171eead0215060bc05 Mon Sep 17 00:00:00 2001 From: Tiago Freitas Date: Mon, 8 Dec 2025 20:30:43 +0000 Subject: [PATCH] fix: include empty tools param when conversation has tool history (#150) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Anthropic (via LiteLLM/proxy) requires the `tools` parameter to be present when messages include tool_calls or tool role messages, even if no tools are currently being provided. This adds a `hasToolHistory()` helper to detect if the conversation contains tool calls or tool results, and ensures `tools: []` is included in the request params when needed. Fixes #149 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Ubuntu Co-authored-by: Claude Opus 4.5 --- .../ai/src/providers/openai-completions.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index 1637b289..cd81bc93 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -26,6 +26,26 @@ import { parseStreamingJson } from "../utils/json-parse.js"; import { sanitizeSurrogates } from "../utils/sanitize-unicode.js"; import { transformMessages } from "./transorm-messages.js"; +import type { Message } from "../types.js"; + +/** + * Check if conversation messages contain tool calls or tool results. + * This is needed because Anthropic (via proxy) requires the tools param + * to be present when messages include tool_calls or tool role messages. + */ +function hasToolHistory(messages: Message[]): boolean { + for (const msg of messages) { + if (msg.role === "toolResult") { + return true; + } + if (msg.role === "assistant") { + if (msg.content.some((block) => block.type === "toolCall")) { + return true; + } + } + } + return false; +} export interface OpenAICompletionsOptions extends StreamOptions { toolChoice?: "auto" | "none" | "required" | { type: "function"; function: { name: string } }; @@ -296,6 +316,9 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio if (context.tools) { params.tools = convertTools(context.tools); + } else if (hasToolHistory(context.messages)) { + // Anthropic (via LiteLLM/proxy) requires tools param when conversation has tool_calls/tool_results + params.tools = []; } if (options?.toolChoice) {