"use client"; import { useState, useEffect, useRef, useCallback } from "react"; import { Card, Button, ModelSelectModal, ManualConfigModal } from "@/shared/components"; import { useModelCaps } from "@/shared/hooks/useModelCaps"; import Image from "next/image"; import BaseUrlSelect from "./BaseUrlSelect"; import { rememberEndpoint } from "./cliEndpointPresets"; import ApiKeySelect from "./ApiKeySelect"; import { matchKnownEndpoint } from "./cliEndpointMatch"; const ENDPOINT = "/api/cli-tools/grok-build-settings"; const MODEL_SLOT = "9router"; const SUBAGENT_TYPES = [ { id: "general-purpose", label: "General-purpose", help: "Implementation, testing, and full-capability delegated tasks" }, { id: "explore", label: "Explore", help: "Read-only codebase research and investigation" }, { id: "plan", label: "Plan", help: "Architecture and implementation planning" }, ]; function ModelField({ label, value, placeholder, onChange, onSelect, disabled, help }) { return (
{label} {help &&

{help}

}
arrow_forward
onChange(event.target.value)} placeholder={placeholder} className="w-full min-w-0 pl-2 pr-7 py-2 bg-surface rounded border border-border text-xs focus:outline-none focus:ring-1 focus:ring-primary/50 sm:py-1.5" /> {value && ( )}
); } export default function GrokBuildToolCard({ tool, isExpanded, onToggle, hasActiveProviders, apiKeys, activeProviders, cloudEnabled, initialStatus, tunnelEnabled, tunnelPublicUrl, tailscaleEnabled, tailscaleUrl, }) { const { getCaps } = useModelCaps(); const getContextWindow = (model) => getCaps(model)?.contextWindow || null; const initialModel = initialStatus?.settings?.model?.model || ""; const initialSubagents = Object.fromEntries( SUBAGENT_TYPES .map((type) => [type.id, initialStatus?.settings?.subagentModels?.[type.id]?.model]) .filter(([, model]) => Boolean(model)), ); const [grokStatus, setGrokStatus] = useState(initialStatus || null); const [checking, setChecking] = useState(false); const [applying, setApplying] = useState(false); const [restoring, setRestoring] = useState(false); const [message, setMessage] = useState(null); const [selectedApiKey, setSelectedApiKey] = useState(apiKeys?.[0]?.key || ""); const [selectedModel, setSelectedModel] = useState(initialModel); const [subagentModels, setSubagentModels] = useState(initialSubagents); const [modelTarget, setModelTarget] = useState(null); // "main" or subagent type const [modelAliases, setModelAliases] = useState({}); const [showManualConfigModal, setShowManualConfigModal] = useState(false); const [customBaseUrl, setCustomBaseUrl] = useState(""); const hasFetchedStatus = useRef(Boolean(initialStatus)); const configuredModel = grokStatus?.settings?.model; const currentBaseUrl = configuredModel?.base_url || ""; const configStatus = !grokStatus?.installed ? null : !configuredModel?.base_url ? "not_configured" : matchKnownEndpoint(configuredModel.base_url, { tunnelPublicUrl, tailscaleUrl }) ? "configured" : "other"; const hydrateForm = useCallback((status) => { const mainModel = status?.settings?.model?.model || ""; const configuredSubagents = Object.fromEntries( SUBAGENT_TYPES .map((type) => [type.id, status?.settings?.subagentModels?.[type.id]?.model]) .filter(([, model]) => Boolean(model)), ); setSelectedModel(mainModel); setSubagentModels(configuredSubagents); }, []); const fetchModelAliases = useCallback(async () => { try { const res = await fetch("/api/models/alias"); const data = await res.json(); if (res.ok) setModelAliases(data.aliases || {}); } catch (error) { console.log("Error fetching model aliases:", error); } }, []); const checkStatus = useCallback(async ({ hydrate = false } = {}) => { setChecking(true); try { const res = await fetch(ENDPOINT); const status = await res.json(); setGrokStatus(status); hasFetchedStatus.current = true; if (hydrate) hydrateForm(status); } catch (error) { setGrokStatus({ installed: false, error: error.message }); } finally { setChecking(false); } }, [hydrateForm]); useEffect(() => { if (!isExpanded) return; let cancelled = false; const synchronize = async () => { if (!hasFetchedStatus.current) await checkStatus({ hydrate: true }); if (!cancelled) await fetchModelAliases(); }; synchronize(); return () => { cancelled = true; }; }, [isExpanded, checkStatus, fetchModelAliases]); const getEffectiveBaseUrl = () => { const url = customBaseUrl || (typeof window !== "undefined" ? window.location.origin.replace("://localhost", "://127.0.0.1") : "http://127.0.0.1:20128"); return url.endsWith("/v1") ? url : `${url}/v1`; }; const handleApply = async () => { setApplying(true); setMessage(null); try { const keyToUse = selectedApiKey?.trim() || (apiKeys?.length > 0 ? apiKeys[0].key : null) || (!cloudEnabled ? "sk_9router" : null); const mappedSubagents = {}; for (const type of SUBAGENT_TYPES) { const model = subagentModels[type.id]?.trim(); if (model) mappedSubagents[type.id] = { model, contextWindow: getContextWindow(model) }; } const res = await fetch(ENDPOINT, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ baseUrl: getEffectiveBaseUrl(), apiKey: keyToUse, model: selectedModel, contextWindow: getContextWindow(selectedModel), subagentModels: mappedSubagents, }), }); const data = await res.json(); if (res.ok) { // Remember the endpoint so it stays selectable next time rememberEndpoint(getEffectiveBaseUrl(), { tunnelPublicUrl, tailscaleUrl }); setMessage({ type: "success", text: "Main and subagent models applied successfully!" }); checkStatus(); } else { setMessage({ type: "error", text: data.error || "Failed to apply settings" }); } } catch (error) { setMessage({ type: "error", text: error.message }); } finally { setApplying(false); } }; const handleReset = async () => { setRestoring(true); setMessage(null); try { const res = await fetch(ENDPOINT, { method: "DELETE" }); const data = await res.json(); if (res.ok) { setMessage({ type: "success", text: "Settings reset successfully!" }); setSelectedModel(""); setSubagentModels({}); checkStatus(); } else { setMessage({ type: "error", text: data.error || "Failed to reset settings" }); } } catch (error) { setMessage({ type: "error", text: error.message }); } finally { setRestoring(false); } }; const handleModelSelect = (model) => { if (modelTarget === "main") { setSelectedModel(model.value); } else if (modelTarget) { setSubagentModels((current) => ({ ...current, [modelTarget]: model.value })); } setModelTarget(null); }; const getManualConfigs = () => { const keyToUse = selectedApiKey?.trim() || (!cloudEnabled ? "sk_9router" : ""); const baseUrl = getEffectiveBaseUrl(); const mainModel = selectedModel || "provider/model-id"; const blocks = [ `[models]\ndefault = "${MODEL_SLOT}"`, `[model.${MODEL_SLOT}]\nmodel = "${mainModel}"\nbase_url = "${baseUrl}"\nname = "9Router"\ndescription = "Routed via 9Router gateway"\napi_backend = "chat_completions"\napi_key = "${keyToUse}"\ncontext_window = ${getContextWindow(mainModel) || 200000}`, ]; const mappings = []; for (const type of SUBAGENT_TYPES) { const model = subagentModels[type.id]?.trim(); if (!model) continue; const slot = `${MODEL_SLOT}-${type.id}`; mappings.push(`${type.id} = "${slot}"`); blocks.push(`[model.${slot}]\nmodel = "${model}"\nbase_url = "${baseUrl}"\nname = "9Router ${type.id}"\ndescription = "Routed via 9Router gateway"\napi_backend = "chat_completions"\napi_key = "${keyToUse}"\ncontext_window = ${getContextWindow(model) || 200000}`); } if (mappings.length) blocks.splice(1, 0, `[subagents.models]\n${mappings.join("\n")}`); return [{ filename: "~/.grok/config.toml", content: `${blocks.join("\n\n")}\n` }]; }; return (
{tool.name} { e.target.style.display = "none"; }} loading="lazy" decoding="async" />

{tool.name}

{configStatus === "configured" && Connected} {configStatus === "not_configured" && Not configured} {configStatus === "other" && Other}

{tool.description}

expand_more
{isExpanded && (
{checking &&
progress_activityChecking Grok Build...
} {!checking && grokStatus && !grokStatus.installed && (
warning

Grok Build not detected locally

curl -fsSL https://x.ai/cli/install.sh | bash
)} {!checking && grokStatus?.installed && ( <>
{tool.notes?.length > 0 && (
{tool.notes.map((note, index) => (
{note.type === "warning" ? "warning" : "info"} {note.text}
))}
)}
Select Endpoint arrow_forward
{configuredModel?.base_url && (
Current arrow_forward {configuredModel.base_url} · {configuredModel.model}{configuredModel.context_window ? ` · ${(configuredModel.context_window / 1000).toLocaleString()}K ctx` : ""}
)}
API Key arrow_forward
setModelTarget("main")} disabled={!hasActiveProviders} />
account_tree

Subagent model overrides

Leave blank to inherit Main Model. Each override keeps its own context window.

{SUBAGENT_TYPES.map((type) => ( setSubagentModels((current) => ({ ...current, [type.id]: value }))} placeholder={`${selectedModel || "Main Model"} (inherit)`} onSelect={() => setModelTarget(type.id)} disabled={!hasActiveProviders} /> ))}
{message &&
{message.type === "success" ? "check_circle" : "error"}{message.text}
}
)}
)} {modelTarget && ( setModelTarget(null)} onSelect={handleModelSelect} selectedModel={modelTarget === "main" ? selectedModel : subagentModels[modelTarget] || ""} activeProviders={activeProviders} modelAliases={modelAliases} title={modelTarget === "main" ? "Select Main Model for Grok Build" : `Select ${SUBAGENT_TYPES.find((type) => type.id === modelTarget)?.label || "Subagent"} Model`} /> )} setShowManualConfigModal(false)} title="Grok Build - Manual Configuration" configs={getManualConfigs()} />
); }