(tool: Tool)
| 60 | * _meta['anthropic/alwaysLoad']). This check runs first, before any other rule. |
| 61 | */ |
| 62 | export function isDeferredTool(tool: Tool): boolean { |
| 63 | // Explicit opt-out via _meta['anthropic/alwaysLoad'] — tool appears in the |
| 64 | // initial prompt with full schema. Checked first so MCP tools can opt out. |
| 65 | if (tool.alwaysLoad === true) return false |
| 66 | |
| 67 | // MCP tools are always deferred (workflow-specific) |
| 68 | if (tool.isMcp === true) return true |
| 69 | |
| 70 | // Never defer ToolSearch itself — the model needs it to load everything else |
| 71 | if (tool.name === TOOL_SEARCH_TOOL_NAME) return false |
| 72 | |
| 73 | // Fork-first experiment: Agent must be available turn 1, not behind ToolSearch. |
| 74 | // Lazy require: static import of forkSubagent → coordinatorMode creates a cycle |
| 75 | // through constants/tools.ts at module init. |
| 76 | if (feature('FORK_SUBAGENT') && tool.name === AGENT_TOOL_NAME) { |
| 77 | type ForkMod = typeof import('../AgentTool/forkSubagent.js') |
| 78 | // eslint-disable-next-line @typescript-eslint/no-require-imports |
| 79 | const m = require('../AgentTool/forkSubagent.js') as ForkMod |
| 80 | if (m.isForkSubagentEnabled()) return false |
| 81 | } |
| 82 | |
| 83 | // Brief is the primary communication channel whenever the tool is present. |
| 84 | // Its prompt contains the text-visibility contract, which the model must |
| 85 | // see without a ToolSearch round-trip. No runtime gate needed here: this |
| 86 | // tool's isEnabled() IS isBriefEnabled(), so being asked about its deferral |
| 87 | // status implies the gate already passed. |
| 88 | if ( |
| 89 | (feature('KAIROS') || feature('KAIROS_BRIEF')) && |
| 90 | BRIEF_TOOL_NAME && |
| 91 | tool.name === BRIEF_TOOL_NAME |
| 92 | ) { |
| 93 | return false |
| 94 | } |
| 95 | |
| 96 | // SendUserFile is a file-delivery communication channel (sibling of Brief). |
| 97 | // Must be immediately available without a ToolSearch round-trip. |
| 98 | if ( |
| 99 | feature('KAIROS') && |
| 100 | SEND_USER_FILE_TOOL_NAME && |
| 101 | tool.name === SEND_USER_FILE_TOOL_NAME && |
| 102 | isReplBridgeActive() |
| 103 | ) { |
| 104 | return false |
| 105 | } |
| 106 | |
| 107 | return tool.shouldDefer === true |
| 108 | } |
| 109 | |
| 110 | /** |
| 111 | * Format one deferred-tool line for the <available-deferred-tools> user |
no test coverage detected