pi-mega-compact 0.13.4 → 0.13.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -8
- package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +50 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-metrics.js +1 -0
- package/dist/extensions/dashboard-server/api-contracts/rag-settings.js +3 -3
- package/dist/extensions/dashboard-server/api-contracts/wiki.js +1 -0
- package/dist/extensions/dashboard-server/routes-rag-metrics.js +60 -0
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +167 -0
- package/dist/extensions/dashboard-server/routes-rag-settings.js +136 -77
- package/dist/extensions/dashboard-server/routes-wiki-helpers.js +97 -0
- package/dist/extensions/dashboard-server/routes-wiki.js +330 -0
- package/dist/extensions/dashboard-server/routes.js +2 -0
- package/dist/extensions/dashboard-server/server.js +17 -3
- package/dist/extensions/mega-events/context-handler/afterCompact.js +35 -2
- package/dist/extensions/mega-pipeline/recall.js +31 -0
- package/dist/extensions/mega-turn-store.js +2 -1
- package/dist/src/config/turns.js +10 -0
- package/dist/src/config.js +2 -0
- package/dist/src/recall/async.js +10 -1
- package/dist/src/recall/format.js +10 -1
- package/dist/src/recall/hydeTelemetry.js +22 -0
- package/dist/src/recall/sync.js +28 -2
- package/dist/src/store/turns/hydeStore.js +32 -0
- package/dist/src/store/turns/index.js +1 -0
- package/dist/src/store/turns/schema.js +102 -1
- package/dist/src/store/turns/sqlite-store/rows.js +23 -0
- package/dist/src/store/turns/sqlite-store/write.js +7 -3
- package/dist/src/topics/durability.js +187 -0
- package/dist/src/topics/index.js +2 -1
- package/dist/src/topics/store.js +28 -9
- package/dist/src/wiki/curation-helpers.js +71 -0
- package/dist/src/wiki/curation.js +147 -0
- package/dist/src/wiki/incremental.js +126 -0
- package/dist/src/wiki/index.js +5 -0
- package/extensions/dashboard-client/dist/assets/AreaChart-KAmp_6bL.js +70 -0
- package/extensions/dashboard-client/dist/assets/{SessionsTab-C30AwyoF.js.map → AreaChart-KAmp_6bL.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Bk-gm-R0.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js +2 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-Cyylo0of.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js +2 -0
- package/extensions/dashboard-client/dist/assets/HealthTab-D-IzmV29.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js +2 -0
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-CrlkCFVj.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js +2 -0
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-DHUdZ7RR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-B7I4HWVg.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js +2 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-K6j4ZI7u.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-BSRWhn56.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-BXdizHN1.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js +2 -0
- package/extensions/dashboard-client/dist/assets/SetupTab-CAgyfqY3.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-DwgCzPD9.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js +5 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-CVKcStBp.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js +2 -0
- package/extensions/dashboard-client/dist/assets/WikiTab-BNohxTbs.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js +2 -0
- package/extensions/dashboard-client/dist/assets/button-B4A-_dCA.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js +2 -0
- package/extensions/dashboard-client/dist/assets/card-Cjn7Ifoe.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js +137 -0
- package/extensions/dashboard-client/dist/assets/index-CQjCLvv7.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-CUA6EDRF.css +1 -0
- package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js +2 -0
- package/extensions/dashboard-client/dist/assets/switch-CcdXX0Zm.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js +2 -0
- package/extensions/dashboard-client/dist/assets/toggle-KdBnFLu3.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js → useSSE-B6t44vzc.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-p1pOI_-P.js.map → useSSE-B6t44vzc.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/package-lock.json +1995 -191
- package/extensions/dashboard-client/package.json +12 -1
- package/extensions/dashboard-client/postcss.config.js +6 -0
- package/extensions/dashboard-client/src/App.tsx +127 -88
- package/extensions/dashboard-client/src/api/client.ts +109 -10
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +15 -7
- package/extensions/dashboard-client/src/components/ActiveSessionsTable.tsx +67 -55
- package/extensions/dashboard-client/src/components/CacheHitRateTrendCard.tsx +17 -13
- package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +35 -30
- package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +33 -28
- package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +5 -6
- package/extensions/dashboard-client/src/components/EventStream.tsx +17 -13
- package/extensions/dashboard-client/src/components/HydeDetailPanel.tsx +173 -0
- package/extensions/dashboard-client/src/components/LegendCard.tsx +16 -9
- package/extensions/dashboard-client/src/components/PerfCards.tsx +28 -20
- package/extensions/dashboard-client/src/components/PerfChart.tsx +9 -6
- package/extensions/dashboard-client/src/components/ProviderCacheCard.tsx +15 -7
- package/extensions/dashboard-client/src/components/RagDashboard.tsx +253 -0
- package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +15 -10
- package/extensions/dashboard-client/src/components/RepoContextStack.tsx +24 -16
- package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +52 -49
- package/extensions/dashboard-client/src/components/RepoTable.tsx +26 -17
- package/extensions/dashboard-client/src/components/SessionContextGauges.tsx +11 -14
- package/extensions/dashboard-client/src/components/SessionInfo.tsx +20 -15
- package/extensions/dashboard-client/src/components/SessionsMemoryChart.tsx +8 -5
- package/extensions/dashboard-client/src/components/SummaryTiles.tsx +26 -17
- package/extensions/dashboard-client/src/components/TabBar.tsx +1 -3
- package/extensions/dashboard-client/src/components/layout/AppShell.tsx +42 -0
- package/extensions/dashboard-client/src/components/layout/BottomBar.tsx +88 -0
- package/extensions/dashboard-client/src/components/layout/Sidebar.tsx +83 -0
- package/extensions/dashboard-client/src/components/ui/badge.tsx +30 -0
- package/extensions/dashboard-client/src/components/ui/button.tsx +44 -0
- package/extensions/dashboard-client/src/components/ui/card.tsx +32 -0
- package/extensions/dashboard-client/src/components/ui/select.tsx +64 -0
- package/extensions/dashboard-client/src/components/ui/switch.tsx +26 -0
- package/extensions/dashboard-client/src/components/ui/tabs.tsx +36 -0
- package/extensions/dashboard-client/src/components/ui/toggle.tsx +28 -0
- package/extensions/dashboard-client/src/components/ui/tooltip.tsx +27 -0
- package/extensions/dashboard-client/src/config.ts +10 -0
- package/extensions/dashboard-client/src/main.tsx +2 -2
- package/extensions/dashboard-client/src/memory-map-layout.ts +1 -2
- package/extensions/dashboard-client/src/styles/index.css +79 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +33 -26
- package/extensions/dashboard-client/src/tabs/EventsTab.tsx +22 -7
- package/extensions/dashboard-client/src/tabs/HealthTab.tsx +77 -46
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +60 -50
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +61 -35
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +34 -23
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +62 -43
- package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +53 -32
- package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +2 -2
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +29 -46
- package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +10 -34
- package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +14 -34
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +5 -2
- package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +11 -5
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +5 -5
- package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +47 -33
- package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +6 -2
- package/extensions/dashboard-client/src/tabs/SetupTab/RagHealthCard.tsx +78 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsPanel.tsx +198 -0
- package/extensions/dashboard-client/src/tabs/SetupTab/SettingsSection.tsx +50 -0
- package/extensions/dashboard-client/src/tabs/SetupTab.tsx +21 -59
- package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +75 -40
- package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +150 -112
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionGraph.tsx +274 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicEvolutionView.tsx +71 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/TopicTimeline.tsx +103 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPage.tsx +213 -0
- package/extensions/dashboard-client/src/tabs/WikiTab/WikiPageControls.tsx +188 -0
- package/extensions/dashboard-client/src/tabs/WikiTab.tsx +222 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +57 -0
- package/extensions/dashboard-client/src/utils/cn.ts +7 -0
- package/extensions/dashboard-client/tailwind.config.js +46 -0
- package/extensions/dashboard-server/api-contracts/core.ts +59 -0
- package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +79 -0
- package/extensions/dashboard-server/api-contracts/index.ts +48 -2
- package/extensions/dashboard-server/api-contracts/rag-metrics.ts +22 -0
- package/extensions/dashboard-server/api-contracts/rag-settings.ts +30 -20
- package/extensions/dashboard-server/api-contracts/wiki.ts +138 -0
- package/extensions/dashboard-server/routes-rag-metrics.ts +82 -0
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +314 -0
- package/extensions/dashboard-server/routes-rag-settings.ts +147 -97
- package/extensions/dashboard-server/routes-wiki-helpers.ts +126 -0
- package/extensions/dashboard-server/routes-wiki.ts +376 -0
- package/extensions/dashboard-server/routes.ts +2 -0
- package/extensions/dashboard-server/server.ts +18 -2
- package/extensions/mega-events/context-handler/afterCompact.ts +44 -1
- package/extensions/mega-pipeline/recall.ts +31 -0
- package/extensions/mega-turn-store.ts +13 -0
- package/package.json +1 -1
- package/src/config/turns.ts +17 -0
- package/src/config.ts +3 -0
- package/src/recall/async.ts +10 -1
- package/src/recall/format.ts +15 -2
- package/src/recall/hydeTelemetry.ts +44 -0
- package/src/recall/sync.ts +34 -2
- package/src/recall/types.ts +36 -0
- package/src/store/turns/hydeStore.ts +82 -0
- package/src/store/turns/index.ts +4 -0
- package/src/store/turns/schema.ts +126 -1
- package/src/store/turns/sqlite-store/rows.ts +25 -0
- package/src/store/turns/sqlite-store/write.ts +20 -2
- package/src/store/turns/types.ts +33 -0
- package/src/topics/durability.ts +231 -0
- package/src/topics/index.ts +7 -1
- package/src/topics/store.ts +35 -9
- package/src/wiki/curation-helpers.ts +140 -0
- package/src/wiki/curation.ts +217 -0
- package/src/wiki/incremental.ts +164 -0
- package/src/wiki/index.ts +13 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js +0 -2
- package/extensions/dashboard-client/dist/assets/CacheTab-Cqnc7lMg.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js +0 -2
- package/extensions/dashboard-client/dist/assets/EventsTab-tYk3VFAp.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js +0 -2
- package/extensions/dashboard-client/dist/assets/HealthTab-D2_kjgxw.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js +0 -2
- package/extensions/dashboard-client/dist/assets/MaintenanceTab-Bc-uPYrz.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js +0 -2
- package/extensions/dashboard-client/dist/assets/MemoryMapTab-D1V9g_NC.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-DT_XfL96.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js +0 -2
- package/extensions/dashboard-client/dist/assets/OverviewTab-BY6KZCme.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-CeS-tpDM.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/SessionsTab-C30AwyoF.js +0 -70
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js +0 -2
- package/extensions/dashboard-client/dist/assets/SetupTab-BJUHOVK2.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js +0 -2
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-p55K1tFP.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js +0 -2
- package/extensions/dashboard-client/dist/assets/TopicsTab-D8FqyAbK.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js +0 -2
- package/extensions/dashboard-client/dist/assets/TurnsTab-ju-nXDys.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js +0 -42
- package/extensions/dashboard-client/dist/assets/index-BEj1Zahy.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-CUNn22iV.css +0 -1
- package/extensions/dashboard-client/src/styles/metrics-extra.css +0 -69
- package/extensions/dashboard-client/src/styles/turns.css +0 -142
- package/extensions/dashboard-client/src/tabs/SetupTab/RagSettingsCard.tsx +0 -160
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetupTab/SettingsPanel.tsx — comprehensive adjustable-settings panel.
|
|
3
|
+
*
|
|
4
|
+
* Renders every MEGACOMPACT_* setting from /api/rag-settings, grouped into
|
|
5
|
+
* collapsible categories. Each setting renders by type (boolean → Switch,
|
|
6
|
+
* number/string → styled input) and writes back via POST /api/rag-settings on
|
|
7
|
+
* change. Switches POST immediately; text/number inputs POST after a 500ms
|
|
8
|
+
* debounce. Requires-LLM settings show an amber badge when no LLM embedder is
|
|
9
|
+
* active. A restart-required toast appears after a successful write.
|
|
10
|
+
*
|
|
11
|
+
* PREVENT-PI-004: all data comes from localhost dashboard API endpoints.
|
|
12
|
+
*/
|
|
13
|
+
import type React from "react";
|
|
14
|
+
import { useState, useEffect, useCallback, useRef } from "react";
|
|
15
|
+
import type { SettingsResponse, SettingState } from "@contracts";
|
|
16
|
+
import { fetchSettings, postSetting } from "../../api/client";
|
|
17
|
+
import { Switch } from "../../components/ui/switch";
|
|
18
|
+
import SettingsSection from "./SettingsSection";
|
|
19
|
+
|
|
20
|
+
const INPUT_CLASS =
|
|
21
|
+
"rounded-md border border-border bg-bg-elevated/50 px-2 py-1 text-sm outline-none transition-colors focus:border-primary disabled:cursor-not-allowed disabled:opacity-50";
|
|
22
|
+
|
|
23
|
+
function LlmBadge(): React.ReactElement {
|
|
24
|
+
return (
|
|
25
|
+
<span
|
|
26
|
+
className="ml-2 inline-flex items-center rounded-md border border-warning/40 bg-warning/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-warning"
|
|
27
|
+
title="Requires an LLM embedder (Ollama/HTTP) to be effective"
|
|
28
|
+
>
|
|
29
|
+
LLM
|
|
30
|
+
</span>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface RowProps {
|
|
35
|
+
readonly setting: SettingState;
|
|
36
|
+
readonly id: string;
|
|
37
|
+
readonly llmActive: boolean;
|
|
38
|
+
readonly saving: boolean;
|
|
39
|
+
readonly onUpdate: (key: string, raw: string) => Promise<string | null>;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function SettingRow({
|
|
43
|
+
setting,
|
|
44
|
+
id,
|
|
45
|
+
llmActive,
|
|
46
|
+
saving,
|
|
47
|
+
onUpdate,
|
|
48
|
+
}: RowProps): React.ReactElement {
|
|
49
|
+
const [error, setError] = useState<string | null>(null);
|
|
50
|
+
const locked = setting.requiresLlm && !llmActive;
|
|
51
|
+
const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
return () => {
|
|
55
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
const submit = useCallback(
|
|
60
|
+
(raw: string) => {
|
|
61
|
+
onUpdate(setting.key, raw)
|
|
62
|
+
.then((msg) => setError(msg))
|
|
63
|
+
.catch((e: unknown) =>
|
|
64
|
+
setError(e instanceof Error ? e.message : String(e)),
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
[onUpdate, setting.key],
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
const scheduleSave = useCallback(
|
|
71
|
+
(raw: string) => {
|
|
72
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
73
|
+
timerRef.current = setTimeout(() => submit(raw), 500);
|
|
74
|
+
},
|
|
75
|
+
[submit],
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
const inputDisabled = saving || locked;
|
|
79
|
+
|
|
80
|
+
return (
|
|
81
|
+
<div className="py-2.5">
|
|
82
|
+
<div className="flex items-start justify-between gap-3">
|
|
83
|
+
<div>
|
|
84
|
+
<div className="flex items-center text-sm font-semibold text-foreground">
|
|
85
|
+
<label htmlFor={`${id}-input`} className="cursor-pointer">
|
|
86
|
+
{setting.label}
|
|
87
|
+
</label>
|
|
88
|
+
{setting.requiresLlm && !llmActive && <LlmBadge />}
|
|
89
|
+
</div>
|
|
90
|
+
<div className="mt-0.5 text-xs text-muted-foreground">
|
|
91
|
+
{setting.description}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
<div className="flex shrink-0 items-center gap-2">
|
|
95
|
+
{setting.type === "boolean" ? (
|
|
96
|
+
<Switch
|
|
97
|
+
id={`${id}-input`}
|
|
98
|
+
checked={Boolean(setting.value)}
|
|
99
|
+
disabled={inputDisabled || locked}
|
|
100
|
+
onCheckedChange={(checked) => submit(String(checked))}
|
|
101
|
+
aria-label={setting.label}
|
|
102
|
+
/>
|
|
103
|
+
) : (
|
|
104
|
+
<>
|
|
105
|
+
<input
|
|
106
|
+
id={`${id}-input`}
|
|
107
|
+
type={setting.type === "number" ? "number" : "text"}
|
|
108
|
+
defaultValue={String(setting.value ?? "")}
|
|
109
|
+
min={setting.min}
|
|
110
|
+
max={setting.max}
|
|
111
|
+
disabled={inputDisabled}
|
|
112
|
+
onChange={(e) => scheduleSave(e.target.value)}
|
|
113
|
+
className={`${INPUT_CLASS} ${setting.type === "number" ? "w-24" : "w-56"}`}
|
|
114
|
+
/>
|
|
115
|
+
{setting.unit && (
|
|
116
|
+
<span className="text-xs text-muted-foreground">{setting.unit}</span>
|
|
117
|
+
)}
|
|
118
|
+
</>
|
|
119
|
+
)}
|
|
120
|
+
</div>
|
|
121
|
+
</div>
|
|
122
|
+
{error && <p className="mt-1 text-xs text-danger">Error: {error}</p>}
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default function SettingsPanel(): React.ReactElement {
|
|
128
|
+
const [settings, setSettings] = useState<SettingsResponse | null>(null);
|
|
129
|
+
const [error, setError] = useState<string | null>(null);
|
|
130
|
+
const [saving, setSaving] = useState(false);
|
|
131
|
+
const [toast, setToast] = useState<string | null>(null);
|
|
132
|
+
|
|
133
|
+
const load = useCallback(() => {
|
|
134
|
+
fetchSettings()
|
|
135
|
+
.then(setSettings)
|
|
136
|
+
.catch((e: unknown) =>
|
|
137
|
+
setError(e instanceof Error ? e.message : String(e)),
|
|
138
|
+
);
|
|
139
|
+
}, []);
|
|
140
|
+
|
|
141
|
+
useEffect(() => {
|
|
142
|
+
load();
|
|
143
|
+
}, [load]);
|
|
144
|
+
|
|
145
|
+
const handleUpdate = useCallback(
|
|
146
|
+
async (key: string, raw: string): Promise<string | null> => {
|
|
147
|
+
setSaving(true);
|
|
148
|
+
try {
|
|
149
|
+
const res = await postSetting({ key, value: raw });
|
|
150
|
+
setToast(
|
|
151
|
+
res.restartRequired
|
|
152
|
+
? "Saved — restart pi to apply changes."
|
|
153
|
+
: "Saved.",
|
|
154
|
+
);
|
|
155
|
+
// Refresh to pick up the server's normalized value (and to keep the
|
|
156
|
+
// controlled Switch in sync with the persisted state).
|
|
157
|
+
load();
|
|
158
|
+
return null;
|
|
159
|
+
} catch (e) {
|
|
160
|
+
return e instanceof Error ? e.message : String(e);
|
|
161
|
+
} finally {
|
|
162
|
+
setSaving(false);
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
[load],
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
return (
|
|
169
|
+
<div className="flex flex-col gap-3">
|
|
170
|
+
{error && <p className="text-sm text-danger">Error: {error}</p>}
|
|
171
|
+
{!settings && !error && (
|
|
172
|
+
<p className="text-sm text-muted-foreground">Loading settings...</p>
|
|
173
|
+
)}
|
|
174
|
+
{settings?.categories.map((cat) => (
|
|
175
|
+
<SettingsSection key={cat.name} title={cat.name}>
|
|
176
|
+
{cat.settings.map((setting) => (
|
|
177
|
+
<SettingRow
|
|
178
|
+
key={setting.key}
|
|
179
|
+
setting={setting}
|
|
180
|
+
id={`${cat.name.replace(/[^a-z0-9]+/gi, "-")}-${setting.key}`}
|
|
181
|
+
llmActive={settings.llmActive}
|
|
182
|
+
saving={saving}
|
|
183
|
+
onUpdate={handleUpdate}
|
|
184
|
+
/>
|
|
185
|
+
))}
|
|
186
|
+
</SettingsSection>
|
|
187
|
+
))}
|
|
188
|
+
{toast && (
|
|
189
|
+
<div
|
|
190
|
+
className="mt-1 rounded-md border border-warning/40 bg-warning/10 p-2 text-xs text-warning"
|
|
191
|
+
role="status"
|
|
192
|
+
>
|
|
193
|
+
{toast}
|
|
194
|
+
</div>
|
|
195
|
+
)}
|
|
196
|
+
</div>
|
|
197
|
+
);
|
|
198
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SetupTab/SettingsSection.tsx — collapsible settings category section.
|
|
3
|
+
*
|
|
4
|
+
* Each category from /api/rag-settings renders as a <section> with a toggle
|
|
5
|
+
* button (aria-expanded + aria-controls) that shows/hides its setting rows.
|
|
6
|
+
* Matches the Sidebar collapsible-accessibility pattern.
|
|
7
|
+
*/
|
|
8
|
+
import type React from "react";
|
|
9
|
+
import { useState } from "react";
|
|
10
|
+
import { ChevronDown } from "lucide-react";
|
|
11
|
+
import { cn } from "../../utils/cn";
|
|
12
|
+
|
|
13
|
+
interface SettingsSectionProps {
|
|
14
|
+
readonly title: string;
|
|
15
|
+
readonly children: React.ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default function SettingsSection({
|
|
19
|
+
title,
|
|
20
|
+
children,
|
|
21
|
+
}: SettingsSectionProps): React.ReactElement {
|
|
22
|
+
const [open, setOpen] = useState<boolean>(true);
|
|
23
|
+
const panelId = `settings-${title.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`;
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<section className="overflow-hidden rounded-xl border border-border bg-bg-elevated/40">
|
|
27
|
+
<button
|
|
28
|
+
type="button"
|
|
29
|
+
onClick={() => setOpen((o) => !o)}
|
|
30
|
+
className="flex w-full items-center justify-between rounded-t-xl bg-bg-elevated/60 px-4 py-3 text-left text-sm font-semibold text-foreground transition-colors hover:bg-bg-elevated"
|
|
31
|
+
aria-expanded={open}
|
|
32
|
+
aria-controls={panelId}
|
|
33
|
+
>
|
|
34
|
+
<span>{title}</span>
|
|
35
|
+
<ChevronDown
|
|
36
|
+
className={cn(
|
|
37
|
+
"h-4 w-4 text-muted-foreground transition-transform",
|
|
38
|
+
open && "rotate-180",
|
|
39
|
+
)}
|
|
40
|
+
aria-hidden="true"
|
|
41
|
+
/>
|
|
42
|
+
</button>
|
|
43
|
+
{open && (
|
|
44
|
+
<div id={panelId} className="divide-y divide-border px-4 py-1">
|
|
45
|
+
{children}
|
|
46
|
+
</div>
|
|
47
|
+
)}
|
|
48
|
+
</section>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
@@ -13,73 +13,35 @@ import GameTab from "./GameTab";
|
|
|
13
13
|
import AchievementsTab from "./AchievementsTab";
|
|
14
14
|
import ConfigTab from "./ConfigTab";
|
|
15
15
|
import EmbedderSetup from "./SetupTab/EmbedderSetup";
|
|
16
|
-
|
|
17
|
-
const containerStyle: React.CSSProperties = {
|
|
18
|
-
padding: "1rem",
|
|
19
|
-
maxWidth: "720px",
|
|
20
|
-
margin: "0 auto",
|
|
21
|
-
fontFamily: "system-ui, sans-serif",
|
|
22
|
-
color: "#e0e0e0",
|
|
23
|
-
};
|
|
16
|
+
import { Toggle } from "../components/ui/toggle";
|
|
24
17
|
|
|
25
18
|
type SetupSubTab = "embedder" | "config" | "game" | "achievements";
|
|
26
19
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
function subTabBtnStyle(active: boolean): React.CSSProperties {
|
|
36
|
-
return {
|
|
37
|
-
background: active ? "#3a5a9f" : "transparent",
|
|
38
|
-
color: active ? "#fff" : "#a0a0c0",
|
|
39
|
-
border: "1px solid",
|
|
40
|
-
borderColor: active ? "#3a5a9f" : "#2a2a4e",
|
|
41
|
-
borderRadius: "6px",
|
|
42
|
-
padding: "0.4rem 0.8rem",
|
|
43
|
-
cursor: "pointer",
|
|
44
|
-
fontSize: "0.9rem",
|
|
45
|
-
fontWeight: active ? 600 : 400,
|
|
46
|
-
};
|
|
47
|
-
}
|
|
20
|
+
const SUB_TABS: ReadonlyArray<{ id: SetupSubTab; label: string }> = [
|
|
21
|
+
{ id: "embedder", label: "Embedder" },
|
|
22
|
+
{ id: "config", label: "Config" },
|
|
23
|
+
{ id: "game", label: "Game Mode" },
|
|
24
|
+
{ id: "achievements", label: "Achievements" },
|
|
25
|
+
];
|
|
48
26
|
|
|
49
27
|
export default function SetupTab(): React.ReactElement {
|
|
50
28
|
const [subTab, setSubTab] = useState<SetupSubTab>("embedder");
|
|
51
29
|
|
|
52
30
|
return (
|
|
53
|
-
<div
|
|
54
|
-
<nav
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Config
|
|
68
|
-
</button>
|
|
69
|
-
<button
|
|
70
|
-
type="button"
|
|
71
|
-
style={subTabBtnStyle(subTab === "game")}
|
|
72
|
-
onClick={() => setSubTab("game")}
|
|
73
|
-
>
|
|
74
|
-
Game Mode
|
|
75
|
-
</button>
|
|
76
|
-
<button
|
|
77
|
-
type="button"
|
|
78
|
-
style={subTabBtnStyle(subTab === "achievements")}
|
|
79
|
-
onClick={() => setSubTab("achievements")}
|
|
80
|
-
>
|
|
81
|
-
Achievements
|
|
82
|
-
</button>
|
|
31
|
+
<div className="mx-auto flex max-w-3xl flex-col gap-4 p-4">
|
|
32
|
+
<nav
|
|
33
|
+
className="flex gap-2 border-b border-border pb-2"
|
|
34
|
+
aria-label="Setup sections"
|
|
35
|
+
>
|
|
36
|
+
{SUB_TABS.map((t) => (
|
|
37
|
+
<Toggle
|
|
38
|
+
key={t.id}
|
|
39
|
+
pressed={subTab === t.id}
|
|
40
|
+
onClick={() => setSubTab(t.id)}
|
|
41
|
+
>
|
|
42
|
+
{t.label}
|
|
43
|
+
</Toggle>
|
|
44
|
+
))}
|
|
83
45
|
</nav>
|
|
84
46
|
|
|
85
47
|
{subTab === "embedder" && <EmbedderSetup />}
|
|
@@ -12,6 +12,8 @@ import { useCallback, useMemo, useState } from "react";
|
|
|
12
12
|
import { useApi } from "../hooks/useApi";
|
|
13
13
|
import { fetchTopics, fetchTopicMemories } from "../api/client";
|
|
14
14
|
import type { TopicsResponse, TopicMemoriesResponse } from "@contracts";
|
|
15
|
+
import { Badge } from "../components/ui/badge";
|
|
16
|
+
import { Card } from "../components/ui/card";
|
|
15
17
|
|
|
16
18
|
function fmtTs(ms: number | null): string {
|
|
17
19
|
if (!ms) return "—";
|
|
@@ -48,33 +50,45 @@ export default function TopicsTab(): React.ReactElement {
|
|
|
48
50
|
|
|
49
51
|
if (error && !data) {
|
|
50
52
|
return (
|
|
51
|
-
<div className="
|
|
53
|
+
<div className="rounded-lg border border-border bg-bg-card p-4 text-sm text-foreground">
|
|
54
|
+
Error loading topics: {error.message}
|
|
55
|
+
</div>
|
|
52
56
|
);
|
|
53
57
|
}
|
|
54
58
|
if (loading && !data) {
|
|
55
|
-
return
|
|
59
|
+
return (
|
|
60
|
+
<div className="rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground">
|
|
61
|
+
Loading topics…
|
|
62
|
+
</div>
|
|
63
|
+
);
|
|
56
64
|
}
|
|
57
65
|
if (!data) {
|
|
58
|
-
return
|
|
66
|
+
return (
|
|
67
|
+
<div className="rounded-lg border border-border bg-bg-card p-4 text-sm text-muted-foreground">
|
|
68
|
+
No topic data available.
|
|
69
|
+
</div>
|
|
70
|
+
);
|
|
59
71
|
}
|
|
60
72
|
|
|
61
73
|
if (data.totalTopics === 0) {
|
|
62
74
|
return (
|
|
63
|
-
<
|
|
64
|
-
<h3>Wiki</h3>
|
|
65
|
-
<p>
|
|
75
|
+
<Card className="p-4">
|
|
76
|
+
<h3 className="font-heading text-lg font-semibold">Wiki</h3>
|
|
77
|
+
<p className="mt-2 text-sm">
|
|
66
78
|
No topics yet. Topics are auto-generated after every 3rd compaction
|
|
67
79
|
from real memory embeddings (k-means + TF-IDF).
|
|
68
80
|
</p>
|
|
69
|
-
<p
|
|
70
|
-
|
|
81
|
+
<p className="mt-2 text-sm text-muted-foreground">
|
|
82
|
+
Check back after a few more compaction cycles.
|
|
83
|
+
</p>
|
|
84
|
+
</Card>
|
|
71
85
|
);
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
return (
|
|
75
|
-
<div className="
|
|
76
|
-
<h3>Wiki</h3>
|
|
77
|
-
<p className="
|
|
89
|
+
<div className="flex flex-col gap-4">
|
|
90
|
+
<h3 className="font-heading text-lg font-semibold">Wiki</h3>
|
|
91
|
+
<p className="text-sm text-muted-foreground">
|
|
78
92
|
{data.totalTopics} topic{data.totalTopics !== 1 ? "s" : ""} ·{" "}
|
|
79
93
|
{data.totalAssigned} assigned memori
|
|
80
94
|
{data.totalAssigned !== 1 ? "es" : "y"}
|
|
@@ -85,87 +99,105 @@ export default function TopicsTab(): React.ReactElement {
|
|
|
85
99
|
|
|
86
100
|
<input
|
|
87
101
|
type="search"
|
|
88
|
-
className="
|
|
102
|
+
className="mb-1 w-full max-w-sm rounded-md border border-border bg-bg-elevated/50 px-3 py-2 text-sm outline-none transition-colors focus:border-primary"
|
|
89
103
|
placeholder="Filter topics by label or term…"
|
|
90
104
|
value={query}
|
|
91
105
|
onChange={(e) => setQuery(e.target.value)}
|
|
92
106
|
/>
|
|
93
107
|
|
|
94
108
|
{drillTopicId && (
|
|
95
|
-
<
|
|
96
|
-
<h4>
|
|
109
|
+
<Card>
|
|
110
|
+
<h4 className="flex items-center gap-2 font-heading text-base font-semibold">
|
|
97
111
|
<button
|
|
98
112
|
type="button"
|
|
99
|
-
className="
|
|
113
|
+
className="text-sm text-muted-foreground transition-colors hover:text-foreground"
|
|
100
114
|
onClick={() => setDrillTopicId(null)}
|
|
101
115
|
>
|
|
102
116
|
← back
|
|
103
|
-
</button>
|
|
117
|
+
</button>
|
|
104
118
|
Topic <code>{drillTopicId}</code>
|
|
105
119
|
{drill.data && <> · {drill.data.label}</>}
|
|
106
120
|
{drill.data && <> · {drill.data.assignments.length} memories</>}
|
|
107
121
|
</h4>
|
|
108
122
|
{drill.error ? (
|
|
109
|
-
<div className="
|
|
123
|
+
<div className="mt-2 text-sm text-foreground">
|
|
110
124
|
Error: {(drill.error as Error).message}
|
|
111
125
|
</div>
|
|
112
126
|
) : drill.loading && !drill.data ? (
|
|
113
|
-
<div className="
|
|
127
|
+
<div className="mt-2 text-sm text-muted-foreground">
|
|
128
|
+
Loading memories…
|
|
129
|
+
</div>
|
|
114
130
|
) : drill.data ? (
|
|
115
|
-
<table className="
|
|
131
|
+
<table className="mt-2 w-full border-collapse text-sm">
|
|
116
132
|
<thead>
|
|
117
133
|
<tr>
|
|
118
|
-
<th
|
|
119
|
-
|
|
120
|
-
|
|
134
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
135
|
+
Memory id
|
|
136
|
+
</th>
|
|
137
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
138
|
+
Confidence
|
|
139
|
+
</th>
|
|
140
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
141
|
+
Assigned
|
|
142
|
+
</th>
|
|
121
143
|
</tr>
|
|
122
144
|
</thead>
|
|
123
145
|
<tbody>
|
|
124
146
|
{drill.data.assignments.map((a) => (
|
|
125
|
-
<tr key={a.memoryId}>
|
|
126
|
-
<td>
|
|
147
|
+
<tr key={a.memoryId} className="border-b border-border/50">
|
|
148
|
+
<td className="px-3 py-2">
|
|
127
149
|
<code>{a.memoryId}</code>
|
|
128
150
|
</td>
|
|
129
|
-
<td>
|
|
151
|
+
<td className="px-3 py-2">
|
|
130
152
|
{a.confidence != null ? a.confidence.toFixed(2) : "—"}
|
|
131
153
|
</td>
|
|
132
|
-
<td>{fmtTs(a.assignedAt)}</td>
|
|
154
|
+
<td className="px-3 py-2">{fmtTs(a.assignedAt)}</td>
|
|
133
155
|
</tr>
|
|
134
156
|
))}
|
|
135
157
|
</tbody>
|
|
136
158
|
</table>
|
|
137
159
|
) : null}
|
|
138
|
-
</
|
|
160
|
+
</Card>
|
|
139
161
|
)}
|
|
140
162
|
|
|
141
163
|
{!drillTopicId && (
|
|
142
|
-
<table className="
|
|
164
|
+
<table className="w-full border-collapse text-sm">
|
|
143
165
|
<thead>
|
|
144
166
|
<tr>
|
|
145
|
-
<th>
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
<th
|
|
167
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
168
|
+
Label
|
|
169
|
+
</th>
|
|
170
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
171
|
+
Memories
|
|
172
|
+
</th>
|
|
173
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">
|
|
174
|
+
Top Terms
|
|
175
|
+
</th>
|
|
176
|
+
<th className="border-b border-border px-3 py-2 text-right font-medium text-muted-foreground"></th>
|
|
149
177
|
</tr>
|
|
150
178
|
</thead>
|
|
151
179
|
<tbody>
|
|
152
180
|
{filtered.map((t) => (
|
|
153
181
|
<tr
|
|
154
182
|
key={t.id}
|
|
155
|
-
className="
|
|
183
|
+
className="cursor-pointer border-b border-border/50 transition-colors hover:bg-bg-elevated/40"
|
|
156
184
|
onClick={() => setDrillTopicId(t.id)}
|
|
157
|
-
style={{ cursor: "pointer" }}
|
|
158
185
|
>
|
|
159
|
-
<td className="
|
|
160
|
-
<td className="
|
|
161
|
-
|
|
186
|
+
<td className="px-3 py-2 font-semibold">{t.label}</td>
|
|
187
|
+
<td className="px-3 py-2">
|
|
188
|
+
<Badge variant="accent">{t.memoryCount}</Badge>
|
|
189
|
+
</td>
|
|
190
|
+
<td className="px-3 py-2 text-muted-foreground">
|
|
162
191
|
{t.termScore
|
|
163
192
|
.slice(0, 8)
|
|
164
193
|
.map((s) => s.term)
|
|
165
194
|
.join(", ")}
|
|
166
195
|
</td>
|
|
167
|
-
<td>
|
|
168
|
-
<button
|
|
196
|
+
<td className="px-3 py-2 text-right">
|
|
197
|
+
<button
|
|
198
|
+
type="button"
|
|
199
|
+
className="rounded-md border border-border px-2 py-1 text-xs text-muted-foreground transition-colors hover:bg-bg-elevated/40 hover:text-foreground"
|
|
200
|
+
>
|
|
169
201
|
drill
|
|
170
202
|
</button>
|
|
171
203
|
</td>
|
|
@@ -173,7 +205,10 @@ export default function TopicsTab(): React.ReactElement {
|
|
|
173
205
|
))}
|
|
174
206
|
{filtered.length === 0 && (
|
|
175
207
|
<tr>
|
|
176
|
-
<td
|
|
208
|
+
<td
|
|
209
|
+
colSpan={4}
|
|
210
|
+
className="px-3 py-2 text-sm text-muted-foreground"
|
|
211
|
+
>
|
|
177
212
|
No topics match “{query}”.
|
|
178
213
|
</td>
|
|
179
214
|
</tr>
|