import { useState, useEffect } from "react"; import { cn } from "@/lib/utils"; import { trpc } from "@/lib/trpc"; import { X, Save, Key, Cpu, Sliders, Shield, Server, DollarSign, FileText, Loader2, } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { toast } from "sonner"; const TABS = [ { id: "model", label: "Model", icon: Cpu }, { id: "params", label: "Parameters", icon: Sliders }, { id: "permissions", label: "Permissions", icon: Shield }, { id: "mcp", label: "MCP", icon: Server }, { id: "costs", label: "Costs", icon: DollarSign }, { id: "memory", label: "Memory", icon: FileText }, ]; // Full parity with original claw-code (19 core + 18 extended + 4 MCP) const TOOL_LIST = [ // Core 19 tools (original names) "bash", "PowerShell", "read_file", "write_file", "edit_file", "glob_search", "grep_search", "NotebookEdit", "WebSearch", "WebFetch", "TodoWrite", "Agent", "SendUserMessage", "Brief", "TestingPermission", "ToolSearch", "Config", "Skill", "Sleep", "REPL", "StructuredOutput", // Extended tools (full parity) "TaskCreate", "TaskGet", "TaskList", "TaskOutput", "TaskStop", "TaskUpdate", "CronCreate", "CronDelete", "CronList", "LSP", "EnterPlanMode", "ExitPlanMode", "EnterWorktree", "ExitWorktree", "TeamCreate", "TeamDelete", "RemoteTrigger", "SyntheticOutput", // MCP "mcp_tool", "list_mcp_resources", "read_mcp_resource", "mcp_auth", ]; interface SettingsPanelProps { open: boolean; onClose: () => void; } export function SettingsPanel({ open, onClose }: SettingsPanelProps) { const [tab, setTab] = useState("model"); const utils = trpc.useUtils(); const { data: settings, isLoading } = trpc.settings.get.useQuery(undefined, { enabled: open, }); const updateSettings = trpc.settings.update.useMutation({ onSuccess: () => { utils.settings.get.invalidate(); toast.success("Settings saved"); }, }); const { data: permissions } = trpc.permissions.list.useQuery(undefined, { enabled: open && tab === "permissions", }); const updatePermission = trpc.permissions.update.useMutation({ onSuccess: () => utils.permissions.list.invalidate(), }); const { data: mcpServers } = trpc.mcp.list.useQuery(undefined, { enabled: open && tab === "mcp", }); const addMcp = trpc.mcp.add.useMutation({ onSuccess: () => utils.mcp.list.invalidate(), }); const deleteMcp = trpc.mcp.delete.useMutation({ onSuccess: () => utils.mcp.list.invalidate(), }); const { data: costSummary } = trpc.costs.summary.useQuery(undefined, { enabled: open && tab === "costs", }); // Local state for form const [formState, setFormState] = useState>({}); useEffect(() => { if (settings) { setFormState({ model: settings.model || "", apiProvider: settings.apiProvider || "default", apiKey: settings.apiKey || "", apiBaseUrl: settings.apiBaseUrl || "", maxTokens: settings.maxTokens || 32768, temperature: settings.temperature ?? 0.5, topP: settings.topP ?? 0.95, systemPrompt: settings.systemPrompt || "", memoryContent: settings.memoryContent || "", expandToolCalls: settings.expandToolCalls ?? 1, autoApproveSafeTools: settings.autoApproveSafeTools ?? 1, }); } }, [settings]); const saveField = (field: string, value: any) => { updateSettings.mutate({ [field]: value }); }; // MCP form state const [mcpName, setMcpName] = useState(""); const [mcpUrl, setMcpUrl] = useState(""); if (!open) return null; return (
{/* Backdrop */}
{/* Panel */}
{/* Header */}

Settings

{/* Tab navigation */}
{TABS.map((t) => ( ))}
{/* Content */}
{isLoading && (
)} {/* Model tab */} {tab === "model" && !isLoading && (
setFormState((s) => ({ ...s, model: e.target.value })) } placeholder="e.g. mimo, mimo-flash, qwen3-8b, llama-70b, deepseek" className="font-mono text-sm" />

Use aliases (qwen-coder, deepseek, hermes, llama) or full model IDs. Default: Qwen3-Coder-480B-Turbo

{[ { id: "Qwen/Qwen3-Coder-480B-A35B-Instruct-Turbo", label: "\u2B50 Qwen Coder 480B" }, { id: "Qwen/Qwen3-235B-A22B-Instruct-2507", label: "Qwen3 235B" }, { id: "deepseek-ai/DeepSeek-V3.2", label: "DeepSeek V3.2" }, { id: "NousResearch/Hermes-3-Llama-3.1-70B", label: "\uD83D\uDD13 Hermes 70B" }, { id: "stepfun-ai/Step-3.5-Flash", label: "Step 3.5 Flash" }, { id: "nvidia/NVIDIA-Nemotron-3-Super-120B-A12B", label: "Nemotron 120B" }, { id: "meta-llama/Llama-4-Maverick-17B-128E", label: "Llama 4 1M ctx" }, { id: "Qwen/Qwen3.5-397B-A17B", label: "Qwen3.5 397B" }, ].map((m) => ( ))}
{/* API: Hardcoded to DeepInfra — no user config needed */}

API: DeepInfra (Qwen3-Coder-480B-Turbo) — hardcoded

)} {/* Parameters tab */} {tab === "params" && !isLoading && (
setFormState((s) => ({ ...s, maxTokens: parseInt(e.target.value), })) } className="w-full accent-primary" />
{[4096, 8192, 16384, 24576, 32000].map((v) => ( ))}
setFormState((s) => ({ ...s, temperature: parseFloat(e.target.value), })) } className="w-full accent-primary" />
setFormState((s) => ({ ...s, topP: parseFloat(e.target.value), })) } className="w-full accent-primary" />