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();