repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
The Living OS cockpit
stars
latest
clone command
git clone gitlawb://did:key:z6Mku78K...XywC/living-os-cockp...git clone gitlawb://did:key:z6Mku78K.../living-os-cockp...59751530feat: surface worker supervisor health in live work5h ago| #1 | 'use client'; |
| #2 | |
| #3 | import { useEffect, useState } from 'react'; |
| #4 | import useSWR from 'swr'; |
| #5 | import { swrFetcher } from '@/lib/client-api'; |
| #6 | |
| #7 | type BrainRole = { |
| #8 | id: string; |
| #9 | label: string; |
| #10 | model: string; |
| #11 | locked: boolean; |
| #12 | swappable: boolean; |
| #13 | source: string; |
| #14 | note: string; |
| #15 | }; |
| #16 | |
| #17 | type BrainOption = { |
| #18 | id: string; |
| #19 | label: string; |
| #20 | provider: string; |
| #21 | projectedDiemPer1kIn: number; |
| #22 | projectedDiemPer1kOut: number; |
| #23 | note: string; |
| #24 | }; |
| #25 | |
| #26 | type BrainPayload = { |
| #27 | ok: boolean; |
| #28 | activeDelegationModel: string; |
| #29 | options: BrainOption[]; |
| #30 | activeOption?: BrainOption; |
| #31 | roles: BrainRole[]; |
| #32 | spineGuard?: { |
| #33 | model?: string; |
| #34 | before?: string; |
| #35 | after?: string; |
| #36 | unchangedBySwap?: boolean; |
| #37 | assertion?: string; |
| #38 | }; |
| #39 | updatedAt?: string | null; |
| #40 | }; |
| #41 | |
| #42 | function diemRate(option?: BrainOption) { |
| #43 | if (!option) return 'unknown'; |
| #44 | const total = option.projectedDiemPer1kIn + option.projectedDiemPer1kOut; |
| #45 | if (total === 0) return '0 DIEM / 1K in+out'; |
| #46 | return `${total.toFixed(4)} DIEM / 1K in+out`; |
| #47 | } |
| #48 | |
| #49 | export default function BrainSwapPanel() { |
| #50 | const { data, mutate, isLoading } = useSWR<BrainPayload>('/api/brain-swap', swrFetcher, { refreshInterval: 15000 }); |
| #51 | const [selected, setSelected] = useState(''); |
| #52 | const [saving, setSaving] = useState(false); |
| #53 | const [error, setError] = useState(''); |
| #54 | |
| #55 | useEffect(() => { |
| #56 | if (data?.activeDelegationModel) setSelected(data.activeDelegationModel); |
| #57 | }, [data?.activeDelegationModel]); |
| #58 | |
| #59 | async function swapBrain() { |
| #60 | if (!selected || selected === data?.activeDelegationModel) return; |
| #61 | setSaving(true); |
| #62 | setError(''); |
| #63 | try { |
| #64 | const res = await fetch('/api/brain-swap', { |
| #65 | method: 'POST', |
| #66 | headers: { 'Content-Type': 'application/json' }, |
| #67 | body: JSON.stringify({ model: selected }), |
| #68 | }); |
| #69 | const payload = await res.json().catch(() => ({})); |
| #70 | if (!res.ok || payload?.spineGuard?.unchangedBySwap === false) { |
| #71 | throw new Error(payload?.error || 'Brain swap failed the spine safety guard.'); |
| #72 | } |
| #73 | await mutate(payload, { revalidate: true }); |
| #74 | } catch (err) { |
| #75 | setError(err instanceof Error ? err.message : 'Brain swap failed.'); |
| #76 | } finally { |
| #77 | setSaving(false); |
| #78 | } |
| #79 | } |
| #80 | |
| #81 | if (isLoading && !data) { |
| #82 | return ( |
| #83 | <div className="rounded-lg border border-[color:var(--border)] bg-[color:var(--bg-2)]/60 p-3 text-xs text-[color:var(--text-3)]"> |
| #84 | Loading brain schematic... |
| #85 | </div> |
| #86 | ); |
| #87 | } |
| #88 | |
| #89 | const options = data?.options ?? []; |
| #90 | const active = options.find(option => option.id === data?.activeDelegationModel) || data?.activeOption; |
| #91 | const selectedOption = options.find(option => option.id === selected) || active; |
| #92 | |
| #93 | return ( |
| #94 | <div className="space-y-3 rounded-lg border border-[color:var(--border)] bg-[color:var(--bg-2)]/60 p-3"> |
| #95 | <div> |
| #96 | <div className="text-[color:var(--gold-2)] text-xs uppercase tracking-wider">Brain swap schematic</div> |
| #97 | <div className="mt-1 text-[11px] text-[color:var(--text-3)]"> |
| #98 | The swap controls King's delegation brain only. The member spine stays locked. |
| #99 | </div> |
| #100 | </div> |
| #101 | |
| #102 | <div className="space-y-2"> |
| #103 | {(data?.roles ?? []).map(role => ( |
| #104 | <div key={role.id} className="rounded-md border border-[color:var(--border)] bg-black/15 p-2"> |
| #105 | <div className="flex items-start justify-between gap-2"> |
| #106 | <div> |
| #107 | <div className="text-xs text-[color:var(--text-1)]">{role.label}</div> |
| #108 | <div className="font-mono text-[11px] text-[color:var(--gold-1)]">{role.model}</div> |
| #109 | </div> |
| #110 | <span className={`rounded-full px-2 py-0.5 text-[10px] uppercase tracking-wide ${role.locked ? 'bg-red-500/15 text-red-300' : role.swappable ? 'bg-[color:var(--gold-2)]/15 text-[color:var(--gold-1)]' : 'bg-white/10 text-[color:var(--text-2)]'}`}> |
| #111 | {role.locked ? 'locked' : role.swappable ? 'swappable' : 'wired'} |
| #112 | </span> |
| #113 | </div> |
| #114 | <div className="mt-1 text-[10px] text-[color:var(--text-3)]">{role.note}</div> |
| #115 | </div> |
| #116 | ))} |
| #117 | </div> |
| #118 | |
| #119 | <div className="space-y-2 rounded-md border border-[color:var(--gold-2)]/25 bg-[color:var(--gold-2)]/5 p-2"> |
| #120 | <div className="flex items-center justify-between gap-2"> |
| #121 | <label className="text-xs text-[color:var(--text-2)]" htmlFor="delegation-brain-select"> |
| #122 | Active delegation brain |
| #123 | </label> |
| #124 | <span className="font-mono text-[10px] text-[color:var(--text-3)]">{diemRate(active)}</span> |
| #125 | </div> |
| #126 | <select |
| #127 | id="delegation-brain-select" |
| #128 | className="w-full rounded-md border border-[color:var(--border)] bg-[color:var(--bg-3)] px-2 py-2 text-xs text-[color:var(--text-1)] outline-none focus:border-[color:var(--gold-2)]" |
| #129 | value={selected} |
| #130 | onChange={event => setSelected(event.target.value)} |
| #131 | > |
| #132 | {options.map(option => ( |
| #133 | <option key={option.id} value={option.id}> |
| #134 | {option.label} |
| #135 | </option> |
| #136 | ))} |
| #137 | </select> |
| #138 | <div className="text-[10px] text-[color:var(--text-3)]"> |
| #139 | Selected burn projection: {diemRate(selectedOption)}. Actual DIEM debits still come from the inference ledger. |
| #140 | </div> |
| #141 | <button |
| #142 | type="button" |
| #143 | onClick={swapBrain} |
| #144 | disabled={saving || !selected || selected === data?.activeDelegationModel} |
| #145 | className="w-full rounded-md bg-[color:var(--gold-2)] px-3 py-2 text-xs font-semibold text-black disabled:cursor-not-allowed disabled:opacity-50" |
| #146 | > |
| #147 | {saving ? 'Saving...' : 'Swap delegation brain'} |
| #148 | </button> |
| #149 | {error ? <div className="text-[11px] text-red-300">{error}</div> : null} |
| #150 | <div className="text-[10px] text-[color:var(--text-3)]"> |
| #151 | Spine guard: {data?.spineGuard?.model ?? 'deepseek-v4-flash'} remains member-facing and untouched. |
| #152 | </div> |
| #153 | </div> |
| #154 | </div> |
| #155 | ); |
| #156 | } |
| #157 |