diff --git a/src/components/ops/kb-panel.tsx b/src/components/ops/kb-panel.tsx index f9d56c3..091b662 100644 --- a/src/components/ops/kb-panel.tsx +++ b/src/components/ops/kb-panel.tsx @@ -71,14 +71,27 @@ const errMsg = (e: unknown) => (e instanceof Error ? e.message : String(e)); type LibraryView = "documents" | "graph"; export function KbPanel() { - // Gate on activation BEFORE mounting the library: KbList fetches on mount - // and a 503 from a disabled/keyless KB stacked error panels under the - // activation card (plan 106). Older gateways omit `enabled`; treat - // configured-as-enabled there. + // Gate on activation BEFORE mounting the library. The library lives in a + // CHILD component (KbPanelBody) because hooks fire on mount regardless of + // what is rendered — a `useAsync(kbGroups)` in THIS component would fetch + // even while the early-return shows only the activation card. Caught by + // the live browser drive: the render was gated but the request was not + // (plan 106 requires no kb/groups call while off). Older gateways omit + // `enabled`; treat configured-as-enabled there. const kbStatus = useAsync(() => api.getKnowledge(), []); const kbEnabled = kbStatus.data ? (kbStatus.data.enabled ?? kbStatus.data.embedding_configured) : false; + + if (kbStatus.loading) return null; + if (!kbEnabled) { + // Activation screen only — no Documents/Graph chrome, no doomed fetches. + return ; + } + return ; +} + +function KbPanelBody({ onStatusChanged }: { onStatusChanged: () => void }) { const groups = useAsync(() => api.kbGroups(), []); const [selected, setSelected] = React.useState(null); const [view, setView] = React.useState("documents"); @@ -93,15 +106,9 @@ export function KbPanel() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [groups.data]); - if (kbStatus.loading) return null; - if (!kbEnabled) { - // Activation screen only — no Documents/Graph chrome, no doomed fetches. - return ; - } - return (
- +