/** * ComputeSourcesSettings — the "Sources" tab. * * Connect, edit, and disconnect compute sources: local, an OllaBridge linked * device/relay, or a direct OpenAI-compatible endpoint. Credentials are * write-only — the field is send-once and never read back; the backend keeps the * secret server-side and returns only a credentialRef. */ import React, { useCallback, useEffect, useState } from "react"; import { Loader2, Plus, Save, Trash2, Wifi } from "lucide-react"; import type { ComputeSource, SourceKind } from "@homepilot/types"; import { computeClient } from "../../api"; const KINDS: { value: SourceKind; label: string; wantsUrl: boolean; wantsCred: boolean }[] = [ { value: "ollabridge", label: "OllaBridge linked device", wantsUrl: false, wantsCred: false }, { value: "openai_compatible", label: "OpenAI-compatible endpoint", wantsUrl: true, wantsCred: true }, { value: "comfyui", label: "Remote ComfyUI endpoint", wantsUrl: true, wantsCred: false }, { value: "custom", label: "Custom", wantsUrl: true, wantsCred: true }, ]; interface DraftSource { id: string; name: string; kind: SourceKind; baseUrl: string; credential: string; enabled: boolean; } const EMPTY: DraftSource = { id: "", name: "", kind: "openai_compatible", baseUrl: "", credential: "", enabled: true, }; export default function ComputeSourcesSettings() { const [sources, setSources] = useState([]); const [draft, setDraft] = useState(null); const [busy, setBusy] = useState(false); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [tested, setTested] = useState>({}); const [testingId, setTestingId] = useState(null); const load = useCallback(async () => { setLoading(true); try { setSources(await computeClient.listComputeSources()); setError(null); } catch (e) { setError(e instanceof Error ? e.message : "Failed to load sources"); } finally { setLoading(false); } }, []); useEffect(() => { void load(); }, [load]); const save = useCallback(async () => { if (!draft) return; if (!draft.id.trim()) { setError("An id is required (e.g. my-vllm)."); return; } setBusy(true); setError(null); try { await computeClient.upsertComputeSource({ id: draft.id.trim(), name: draft.name.trim() || draft.id.trim(), kind: draft.kind, baseUrl: draft.baseUrl.trim() || undefined, enabled: draft.enabled, ...(draft.credential ? { credential: draft.credential } : {}), }); setDraft(null); await load(); } catch (e) { setError(e instanceof Error ? e.message : "Save failed"); } finally { setBusy(false); } }, [draft, load]); const toggle = useCallback( async (s: ComputeSource) => { await computeClient.upsertComputeSource({ id: s.id, kind: s.kind, enabled: !s.enabled }); await load(); }, [load], ); const remove = useCallback( async (id: string) => { await computeClient.deleteComputeSource(id); await load(); }, [load], ); const test = useCallback(async (id: string) => { setTestingId(id); try { const r = await computeClient.testComputeSource(id); setTested((t) => ({ ...t, [id]: r.ok ? "✓ Reachable" : r.reason || "Unreachable" })); } catch (e) { setTested((t) => ({ ...t, [id]: e instanceof Error ? e.message : "Test failed" })); } finally { setTestingId(null); } }, []); const kindMeta = draft ? KINDS.find((k) => k.value === draft.kind) : undefined; return (

Compute sources

Where HomePilot may run models.

{error && (
{error}
)} {loading && }
    {sources.map((s) => (
  • {s.name}
    {s.kind} {s.baseUrl ? ` · ${s.baseUrl}` : ""} {s.credentialRef ? " · key set" : ""}
    {tested[s.id] &&
    {tested[s.id]}
    }
  • ))} {!loading && sources.length === 0 && (
  • No sources yet.
  • )}
{draft && (
setDraft({ ...draft, id: e.target.value })} placeholder="my-vllm" className="w-full h-10 rounded-xl bg-black/40 border border-white/10 px-3 text-sm text-white placeholder:text-white/30 outline-none focus:border-cyan-400/50" /> setDraft({ ...draft, name: e.target.value })} placeholder="My vLLM" className="w-full h-10 rounded-xl bg-black/40 border border-white/10 px-3 text-sm text-white placeholder:text-white/30 outline-none focus:border-cyan-400/50" />
{kindMeta?.wantsUrl && ( setDraft({ ...draft, baseUrl: e.target.value })} placeholder="https://host:port" className="w-full h-10 rounded-xl bg-black/40 border border-white/10 px-3 text-sm text-white placeholder:text-white/30 outline-none focus:border-cyan-400/50" /> )} {kindMeta?.wantsCred && ( setDraft({ ...draft, credential: e.target.value })} placeholder="stored server-side, never shown again" className="w-full h-10 rounded-xl bg-black/40 border border-white/10 px-3 text-sm text-white placeholder:text-white/30 outline-none focus:border-cyan-400/50" /> )}
)}
); } function Field({ label, children }: { label: string; children: React.ReactNode }) { return ( ); }