"use client"; // System Configuration → AI Provider section for the Account Settings modal. // // Optional Internal AI (OllaBridge) only. Adapted from the System Configuration UI in // ruslanmv/3D-Avatar-Chatbot (index.html): provider selector, Device Pairing / API Key / Local // Trust modes, Base URL, Model, Fetch Models. Everything is browser-local and assist-only; the // deterministic Matrix contract is never affected by anything chosen here. import { useEffect, useState } from "react"; import { getAISettings, saveAISettings } from "@/lib/ai-settings-store"; import { getDefaultCoder, setDefaultCoder } from "@/lib/default-coder-store"; import { AI_CODERS } from "@/lib/constants"; import type { CoderId } from "@/types/coder"; import { assertRootBaseUrl, fetchOllaBridgeModels, isLocalhostLike, pairWithOllaBridge, stripTrailingSlash, } from "@/lib/ollabridge-client"; import { DEFAULT_AI_SETTINGS, type AIProvider, type MatrixAISettings, type OllaBridgeAuthMode, } from "@/types/ai-settings"; type Note = { kind: "ok" | "err" | "info"; text: string } | null; export default function AiConfigurationSection() { const [settings, setSettings] = useState(DEFAULT_AI_SETTINGS); const [hasSavedKey, setHasSavedKey] = useState(false); const [hasPairToken, setHasPairToken] = useState(false); const [apiKeyDraft, setApiKeyDraft] = useState(""); const [pairCode, setPairCode] = useState(""); const [models, setModels] = useState([]); const [pairing, setPairing] = useState(false); const [fetching, setFetching] = useState(false); const [pairNote, setPairNote] = useState(null); const [modelNote, setModelNote] = useState(null); const [saveNote, setSaveNote] = useState(null); // Default AI coder preference. "" = None (no override). const [defaultCoder, setDefaultCoderDraft] = useState(""); useEffect(() => { const s = getAISettings(); setSettings(s); setHasSavedKey(Boolean(s.ollabridge.apiKey)); setHasPairToken(Boolean(s.ollabridge.pairToken)); setDefaultCoderDraft(getDefaultCoder() ?? ""); }, []); function onDefaultCoderChange(value: string) { const next = (value || null) as CoderId | null; setDefaultCoderDraft((next ?? "") as CoderId | ""); setDefaultCoder(next); } // Optional Matrix Designer enhancement — persist immediately, like the default-coder preference. function onToggleMatrixDesigner(enabled: boolean) { setSettings((s) => { const next = { ...s, matrixDesigner: { ...s.matrixDesigner, enabled } }; saveAISettings(next); return next; }); setSaveNote(null); } const ob = settings.ollabridge; const localhost = isLocalhostLike(ob.baseUrl); function patchOb(patch: Partial) { setSettings((s) => ({ ...s, ollabridge: { ...s.ollabridge, ...patch } })); setSaveNote(null); } function setProvider(provider: AIProvider) { setSettings((s) => ({ ...s, provider, mode: provider === "none" ? "deterministic" : s.mode })); setSaveNote(null); } function setAuthMode(authMode: OllaBridgeAuthMode) { // Local Trust is only safe against a localhost OllaBridge; block it for remote URLs. if (authMode === "local-trust" && !localhost) { setPairNote({ kind: "err", text: "Local Trust is only allowed for localhost / 127.0.0.1 base URLs." }); return; } patchOb({ authMode }); setPairNote(null); } function persist(next: MatrixAISettings) { saveAISettings(next); setSettings(next); setHasSavedKey(Boolean(next.ollabridge.apiKey)); setHasPairToken(Boolean(next.ollabridge.pairToken)); } function onSave() { try { if (settings.provider === "ollabridge") assertRootBaseUrl(ob.baseUrl); } catch (e) { setSaveNote({ kind: "err", text: e instanceof Error ? e.message : "Invalid Base URL." }); return; } const next: MatrixAISettings = { ...settings, ollabridge: { ...ob, baseUrl: stripTrailingSlash(ob.baseUrl), // Only overwrite the saved key if the user typed a new one; never echo it back. apiKey: apiKeyDraft ? apiKeyDraft : ob.apiKey, }, }; persist(next); setApiKeyDraft(""); setSaveNote({ kind: "ok", text: "AI configuration saved." }); } async function onPair() { setPairNote(null); try { assertRootBaseUrl(ob.baseUrl); } catch (e) { setPairNote({ kind: "err", text: e instanceof Error ? e.message : "Invalid Base URL." }); return; } setPairing(true); try { const result = await pairWithOllaBridge(ob, pairCode); // Store the token (never displayed) and persist immediately so it isn't lost. const next: MatrixAISettings = { ...settings, ollabridge: { ...ob, pairToken: result.pairToken, deviceId: result.deviceId }, }; persist(next); setPairCode(""); setPairNote({ kind: "ok", text: "Paired. This device is now connected to OllaBridge." }); } catch (e) { // Keep any existing working token; only the attempt failed. setPairNote({ kind: "err", text: e instanceof Error ? e.message : "Pairing failed." }); } finally { setPairing(false); } } async function onFetchModels() { setModelNote({ kind: "info", text: "Fetching…" }); setFetching(true); try { const result = await fetchOllaBridgeModels(ob); setModels(result.models); patchOb({ model: result.selected }); setModelNote({ kind: "ok", text: `Loaded ${result.models.length} model${result.models.length === 1 ? "" : "s"}.` }); } catch { setModelNote({ kind: "err", text: "Could not fetch models. Check Base URL and authentication." }); } finally { setFetching(false); } } const modelOptions = models.length > 0 ? models : [ob.model]; return (

System Configuration

Optional Internal AI assist. OllaBridge can improve explanations and candidate wording, but it cannot change the Matrix contract.

{/* Default AI coder — which coder new builds preselect. None = no override. */}
Default AI coder

New builds start on this coder. Default is None.

{/* Provider */}
AI Provider
{settings.provider === "none" && (

AI assist is off. Matrix Builder will run deterministically.

)} {/* Optional enhancement: Matrix Designer — the design brain. Default OFF. */}
{settings.provider === "ollabridge" && ( <> {/* Assisted-mode toggle */}

API Configuration

{/* Auth mode */}
{/* Base URL */}
patchOb({ baseUrl: e.target.value })} />
{/* Pairing */} {ob.authMode === "pairing" && (
Device Pairing {hasPairToken && • connected}

Enter the OllaBridge pairing code and click Pair.

setPairCode(e.target.value)} onKeyDown={(e) => e.key === "Enter" && onPair()} />
)} {/* API Key */} {ob.authMode === "api_key" && (
{ setApiKeyDraft(e.target.value); setSaveNote(null); }} />
)} {/* Local Trust */} {ob.authMode === "local-trust" && (

Local Trust is intended only for trusted localhost/development OllaBridge instances. No Authorization header will be sent.

)} {pairNote &&
{pairNote.text}
} {/* Model */}
{modelNote &&
{modelNote.text}
}
{saveNote &&
{saveNote.text}
}
)}
); } function noteClass(note: NonNullable): string { if (note.kind === "ok") return "settings-success"; if (note.kind === "err") return "auth-err"; return "ai-note-info"; }