// Import useInput from vendored Ink for bracketed paste support import { Box, Text, useInput } from "ink"; import { useMemo, useState } from "react"; import { colors } from "./colors"; type ToolsetId = | "codex" | "codex_snake" | "default" | "gemini" | "gemini_snake" | "none"; interface ToolsetOption { id: ToolsetId; label: string; description: string; tools: string[]; isFeatured?: boolean; } const toolsets: ToolsetOption[] = [ { id: "default", label: "Default Tools", description: "Toolset optimized for Claude models", tools: [ "Bash", "BashOutput", "Edit", "Glob", "Grep", "LS", "MultiEdit", "Read", "TodoWrite", "Write", ], isFeatured: true, }, { id: "codex", label: "Codex Tools", description: "Toolset optimized for GPT/Codex models", tools: [ "ShellCommand", "Shell", "ReadFile", "ListDir", "GrepFiles", "ApplyPatch", "UpdatePlan", ], isFeatured: true, }, { id: "codex_snake", label: "Codex Tools (snake_case)", description: "Toolset optimized for GPT/Codex models (snake_case)", tools: [ "shell_command", "shell", "read_file", "list_dir", "grep_files", "apply_patch", "update_plan", ], }, { id: "gemini", label: "Gemini Tools", description: "Toolset optimized for Gemini models", tools: [ "RunShellCommand", "ReadFileGemini", "ListDirectory", "GlobGemini", "SearchFileContent", "Replace", "WriteFileGemini", "WriteTodos", "ReadManyFiles", ], isFeatured: true, }, { id: "gemini_snake", label: "Gemini Tools (snake_case)", description: "Toolset optimized for Gemini models (snake_case)", tools: [ "run_shell_command", "read_file_gemini", "list_directory", "glob_gemini", "search_file_content", "replace", "write_file_gemini", "write_todos", "read_many_files", ], }, { id: "none", label: "None (Disable Tools)", description: "Remove all Letta Code tools from the agent", tools: [], isFeatured: true, }, ]; interface ToolsetSelectorProps { currentToolset?: ToolsetId; onSelect: (toolsetId: ToolsetId) => void; onCancel: () => void; } export function ToolsetSelector({ currentToolset, onSelect, onCancel, }: ToolsetSelectorProps) { const [showAll, setShowAll] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); const featuredToolsets = useMemo( () => toolsets.filter((toolset) => toolset.isFeatured), [], ); const visibleToolsets = useMemo(() => { if (showAll) return toolsets; if (featuredToolsets.length > 0) return featuredToolsets; return toolsets.slice(0, 3); }, [featuredToolsets, showAll]); const hasHiddenToolsets = visibleToolsets.length < toolsets.length; const hasShowAllOption = !showAll && hasHiddenToolsets; const totalItems = visibleToolsets.length + (hasShowAllOption ? 1 : 0); useInput((_input, key) => { if (key.upArrow) { setSelectedIndex((prev) => Math.max(0, prev - 1)); } else if (key.downArrow) { setSelectedIndex((prev) => Math.min(totalItems - 1, prev + 1)); } else if (key.return) { if (hasShowAllOption && selectedIndex === visibleToolsets.length) { setShowAll(true); setSelectedIndex(0); } else { const selectedToolset = visibleToolsets[selectedIndex]; if (selectedToolset) { onSelect(selectedToolset.id); } } } else if (key.escape) { onCancel(); } }); return ( Select Toolset (↑↓ to navigate, Enter to select, ESC to cancel) {visibleToolsets.map((toolset, index) => { const isSelected = index === selectedIndex; const isCurrent = toolset.id === currentToolset; return ( {isSelected ? "›" : " "} {toolset.label} {isCurrent && ( {" "} (current) )} {toolset.description} ); })} {hasShowAllOption && ( {selectedIndex === visibleToolsets.length ? "›" : " "} Show all toolsets )} ); }