From 82d89fd5fcfd4c6d28f9870fbfbd84874e7c97d1 Mon Sep 17 00:00:00 2001 From: MoerAI Date: Fri, 27 Mar 2026 11:11:56 +0900 Subject: [PATCH] fix(tools): add max_tools config to cap registered tools for OpenAI compatibility (fixes #2848) --- src/config/schema/experimental.ts | 2 ++ src/plugin/tool-registry.ts | 29 ++++++++++++++++++++++++++++- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/config/schema/experimental.ts b/src/config/schema/experimental.ts index 6abbf1a48..fbcefb3b1 100644 --- a/src/config/schema/experimental.ts +++ b/src/config/schema/experimental.ts @@ -21,6 +21,8 @@ export const ExperimentalConfigSchema = z.object({ hashline_edit: z.boolean().optional(), /** Append fallback model info to session title when a runtime fallback occurs (default: false) */ model_fallback_title: z.boolean().optional(), + /** Maximum number of tools to register. When set, lower-priority tools are excluded to stay within provider limits (e.g., OpenAI's 128-tool cap). Accounts for ~20 OpenCode built-in tools. */ + max_tools: z.number().int().min(1).optional(), }) export type ExperimentalConfig = z.infer diff --git a/src/plugin/tool-registry.ts b/src/plugin/tool-registry.ts index 82a9a2ceb..556ee49e8 100644 --- a/src/plugin/tool-registry.ts +++ b/src/plugin/tool-registry.ts @@ -150,7 +150,34 @@ export function createToolRegistry(args: { normalizeToolArgSchemas(toolDefinition) } - const filteredTools = filterDisabledTools(allTools, pluginConfig.disabled_tools) + const filteredTools: ToolsRecord = filterDisabledTools(allTools, pluginConfig.disabled_tools) + + const maxTools = pluginConfig.experimental?.max_tools + if (maxTools) { + const estimatedBuiltinTools = 20 + const pluginToolBudget = maxTools - estimatedBuiltinTools + const toolEntries = Object.entries(filteredTools) + if (pluginToolBudget > 0 && toolEntries.length > pluginToolBudget) { + const excess = toolEntries.length - pluginToolBudget + log(`[tool-registry] Tool count (${toolEntries.length} plugin + ~${estimatedBuiltinTools} builtin = ~${toolEntries.length + estimatedBuiltinTools}) exceeds max_tools=${maxTools}. Trimming ${excess} lower-priority tools.`) + const lowPriorityTools = [ + "session_list", "session_read", "session_search", "session_info", + "call_omo_agent", "interactive_bash", "look_at", + "task_create", "task_get", "task_list", "task_update", + ] + let removed = 0 + for (const toolName of lowPriorityTools) { + if (removed >= excess) break + if (filteredTools[toolName]) { + delete filteredTools[toolName] + removed += 1 + } + } + if (removed < excess) { + log(`[tool-registry] WARNING: Could not trim enough tools. ${toolEntries.length - removed} plugin tools remain.`) + } + } + } return { filteredTools,