From ee00ac7280e5947040b8734599a41b319b9b0045 Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Wed, 4 Mar 2026 16:21:01 -0800 Subject: [PATCH] feat(headless): exclude AskUserQuestion from headless mode toolset (#1266) Co-authored-by: Letta Code --- src/index.ts | 3 ++- src/tools/manager.ts | 14 +++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/index.ts b/src/index.ts index 931bd1c..ad3dd01 100755 --- a/src/index.ts +++ b/src/index.ts @@ -910,7 +910,8 @@ async function main(): Promise { specifiedModel, specifiedToolset as "auto" | "codex" | "default" | "gemini" | undefined, ); - await loadTools(modelForTools); + // Exclude interactive-only tools that can't function without a live user session + await loadTools(modelForTools, { exclude: ["AskUserQuestion"] }); markMilestone("TOOLS_LOADED"); // Keep headless startup in sync with interactive name resolution. diff --git a/src/tools/manager.ts b/src/tools/manager.ts index b66d1df..74b85f9 100644 --- a/src/tools/manager.ts +++ b/src/tools/manager.ts @@ -787,9 +787,15 @@ export async function loadSpecificTools(toolNames: string[]): Promise { * Acquires the toolset switch lock during loading to prevent message sends from * reading stale tools. Callers should use waitForToolsetReady() before sending messages. * + * @param modelIdentifier - Optional model identifier to select the appropriate toolset + * @param options - Optional configuration + * @param options.exclude - Tool names to exclude from the loaded toolset * @returns Promise that resolves when all tools are loaded */ -export async function loadTools(modelIdentifier?: string): Promise { +export async function loadTools( + modelIdentifier?: string, + options?: { exclude?: ToolName[] }, +): Promise { // Acquire lock to signal that a switch is in progress acquireSwitchLock(); @@ -823,6 +829,12 @@ export async function loadTools(modelIdentifier?: string): Promise { baseToolNames = TOOL_NAMES; } + // Apply exclusions (e.g. remove interactive-only tools in headless mode) + if (options?.exclude && options.exclude.length > 0) { + const excludeSet = new Set(options.exclude); + baseToolNames = baseToolNames.filter((name) => !excludeSet.has(name)); + } + // Build new registry in a temporary map (all async work happens above) const newRegistry: ToolRegistry = new Map();