diff --git a/src/cli/App.tsx b/src/cli/App.tsx index 1dc45e1..446e94a 100644 --- a/src/cli/App.tsx +++ b/src/cli/App.tsx @@ -9798,7 +9798,7 @@ Plan file path: ${planFilePath}`; {/* Hooks Manager - for managing hooks configuration */} {activeOverlay === "hooks" && ( - + )} {/* New Agent Dialog - for naming new agent before creation */} diff --git a/src/cli/components/HooksManager.tsx b/src/cli/components/HooksManager.tsx index 73bbed4..a577b82 100644 --- a/src/cli/components/HooksManager.tsx +++ b/src/cli/components/HooksManager.tsx @@ -37,6 +37,7 @@ const BOX_VERTICAL = "│"; interface HooksManagerProps { onClose: () => void; + agentId?: string; } type Screen = @@ -62,8 +63,8 @@ const HOOK_EVENTS: { event: HookEvent; description: string }[] = [ { event: "SessionEnd", description: "When a session ends" }, ]; -// Available tools for matcher suggestions -const TOOL_NAMES = [ +// Fallback tool names if agent tools can't be fetched +const FALLBACK_TOOL_NAMES = [ "Task", "Bash", "Glob", @@ -71,14 +72,13 @@ const TOOL_NAMES = [ "Read", "Edit", "Write", - "WebFetch", "TodoWrite", - "WebSearch", "AskUserQuestion", "Skill", "EnterPlanMode", "ExitPlanMode", - "KillShell", + "BashOutput", + "KillBash", ]; // Save location options @@ -130,6 +130,7 @@ function boxBottom(width: number): string { export const HooksManager = memo(function HooksManager({ onClose, + agentId, }: HooksManagerProps) { const terminalWidth = useTerminalWidth(); const boxWidth = Math.min(terminalWidth - 4, 70); @@ -141,6 +142,37 @@ export const HooksManager = memo(function HooksManager({ const [hooks, setHooks] = useState([]); const [totalHooks, setTotalHooks] = useState(0); + // Dynamic tool names from agent + const [toolNames, setToolNames] = useState(FALLBACK_TOOL_NAMES); + + // Fetch agent tools on mount + useEffect(() => { + if (!agentId) return; + + const fetchAgentTools = async () => { + try { + const { getClient } = await import("../../agent/client"); + const client = await getClient(); + // Use dedicated tools endpoint instead of fetching whole agent + // Pass limit to avoid pagination issues + const toolsPage = await client.agents.tools.list(agentId, { + limit: 50, + }); + const names = toolsPage.items + ?.map((t) => t.name) + .filter((n): n is string => !!n); + if (names && names.length > 0) { + // Sort alphabetically for easier scanning + setToolNames(names.sort()); + } + } catch { + // Keep fallback tool names on error + } + }; + + fetchAgentTools(); + }, [agentId]); + // New hook state const [newMatcher, setNewMatcher] = useState(""); const [newCommand, setNewCommand] = useState(""); @@ -476,7 +508,7 @@ export const HooksManager = memo(function HooksManager({ Possible matcher values for field tool_name: - {TOOL_NAMES.join(", ")} + {toolNames.join(", ")} Tool matcher: diff --git a/src/cli/components/McpSelector.tsx b/src/cli/components/McpSelector.tsx index b315832..c2e0c33 100644 --- a/src/cli/components/McpSelector.tsx +++ b/src/cli/components/McpSelector.tsx @@ -111,10 +111,10 @@ export const McpSelector = memo(function McpSelector({ const fetchAttachedToolIds = useCallback( async (client: Awaited>) => { - const agent = await client.agents.retrieve(agentId, { - include: ["agent.tools"], - }); - return new Set(agent.tools?.map((t) => t.id) || []); + // Use dedicated tools endpoint instead of fetching whole agent + // Pass limit to avoid pagination issues + const toolsPage = await client.agents.tools.list(agentId, { limit: 50 }); + return new Set(toolsPage.items?.map((t) => t.id) || []); }, [agentId], ); diff --git a/src/tools/toolset.ts b/src/tools/toolset.ts index 66c335c..a90f3ea 100644 --- a/src/tools/toolset.ts +++ b/src/tools/toolset.ts @@ -48,6 +48,7 @@ export async function ensureCorrectMemoryTool( : isOpenAIModel(resolvedModel); try { + // Need full agent state for tool_rules, so use retrieve with include const agentWithTools = await client.agents.retrieve(agentId, { include: ["agent.tools"], });