pi-mega-compact 0.20.57 → 0.20.59
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/dist/config/vector-cortex-dash-0a.js +22 -0
- package/dist/config/vector-cortex-dash-0b.js +21 -0
- package/dist/config/vector-cortex.js +4 -0
- package/dist/config.js +1 -1
- package/dist/extensions/dashboard-server/routes-rag-settings-vector-cortex.js +2 -0
- package/dist/src/config/vector-cortex-dash-0a.js +22 -0
- package/dist/src/config/vector-cortex-dash-0b.js +21 -0
- package/dist/src/config/vector-cortex.js +4 -0
- package/dist/src/config.js +1 -1
- package/extensions/dashboard-client/dist/assets/{AreaChart-CtJ6dSMT.js → AreaChart-GTwQxOAm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{AreaChart-CtJ6dSMT.js.map → AreaChart-GTwQxOAm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{BarChart-DJ3j3xDz.js → BarChart-BFqUD5L4.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{BarChart-DJ3j3xDz.js.map → BarChart-BFqUD5L4.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{CacheTab-CXU1_9lR.js → CacheTab-BLM6_PQQ.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{CacheTab-CXU1_9lR.js.map → CacheTab-BLM6_PQQ.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{EventsTab-DF-Q3o7x.js → EventsTab-BYLh6cud.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{EventsTab-DF-Q3o7x.js.map → EventsTab-BYLh6cud.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{HealthTab-Dr1HGOkl.js → HealthTab-CkJXEbjn.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{HealthTab-Dr1HGOkl.js.map → HealthTab-CkJXEbjn.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js +5 -0
- package/extensions/dashboard-client/dist/assets/HydeDetailPanel-Dt9T7kc5.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-zKhR18_s.js → MaintenanceTab-Lm3v0nJO.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MaintenanceTab-zKhR18_s.js.map → MaintenanceTab-Lm3v0nJO.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DekIzfn2.js → MemoryMapTab-C8AeBIQi.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MemoryMapTab-DekIzfn2.js.map → MemoryMapTab-C8AeBIQi.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CEKajY38.js → MetricsTab-m410T4vk.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{MetricsTab-CEKajY38.js.map → MetricsTab-m410T4vk.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{OverviewTab-24sG8xiE.js → OverviewTab-BfDfMFXx.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{OverviewTab-24sG8xiE.js.map → OverviewTab-BfDfMFXx.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{ReposTab-70gkV8l9.js → ReposTab-CsFxxqJ6.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{ReposTab-70gkV8l9.js.map → ReposTab-CsFxxqJ6.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-DstDOzwu.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{SetupTab-tbPrrfYx.js → SetupTab-DVT4PrH0.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{SetupTab-tbPrrfYx.js.map → SetupTab-DVT4PrH0.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B6mdtCWE.js → TimeSavedCard-BkRzjyRm.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{TimeSavedCard-B6mdtCWE.js.map → TimeSavedCard-BkRzjyRm.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js +2 -0
- package/extensions/dashboard-client/dist/assets/TurnsTab-D5QTnv52.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-SDThp0R0.js → VcStatusBadge-B8B8RStV.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{VcStatusBadge-SDThp0R0.js.map → VcStatusBadge-B8B8RStV.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-CrGANNd_.js +2 -0
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-CrGANNd_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/{WikiTab-Cki48_8N.js → WikiTab-DyD0yGzI.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{WikiTab-Cki48_8N.js.map → WikiTab-DyD0yGzI.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{button-CojFYd7q.js → button-Bynl3ONj.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{button-CojFYd7q.js.map → button-Bynl3ONj.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{card-Cxeeje9o.js → card-Daf3pQIu.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{card-Cxeeje9o.js.map → card-Daf3pQIu.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{client-extra-DLxyGxW8.js → client-extra-DqAYZBW1.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{client-extra-DLxyGxW8.js.map → client-extra-DqAYZBW1.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DRlqBks2.js → generateCategoricalChart-B-fe5jjr.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{generateCategoricalChart-DRlqBks2.js.map → generateCategoricalChart-B-fe5jjr.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{index-CkbdlPBm.js → index-Bjvv23bp.js} +3 -3
- package/extensions/dashboard-client/dist/assets/{index-CkbdlPBm.js.map → index-Bjvv23bp.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{switch-Cx_nl-Ba.js → switch-CivyERPS.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{switch-Cx_nl-Ba.js.map → switch-CivyERPS.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{toggle-CfIFzp6P.js → toggle-qmdkrAgF.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{toggle-CfIFzp6P.js.map → toggle-qmdkrAgF.js.map} +1 -1
- package/extensions/dashboard-client/dist/assets/{useSSE-B9_N7ccG.js → useSSE-uNuduyGe.js} +2 -2
- package/extensions/dashboard-client/dist/assets/{useSSE-B9_N7ccG.js.map → useSSE-uNuduyGe.js.map} +1 -1
- package/extensions/dashboard-client/dist/index.html +1 -1
- package/extensions/dashboard-client/src/dash-consolidation/plan.ts +200 -0
- package/extensions/dashboard-client/src/tabs/SessionsTab/TurnMemoryView.tsx +383 -0
- package/extensions/dashboard-client/src/tabs/SessionsTab.tsx +77 -6
- package/extensions/dashboard-client/src/tabs/VectorCortexTab/sections.tsx +201 -0
- package/extensions/dashboard-client/src/tabs/VectorCortexTab.tsx +168 -122
- package/extensions/dashboard-client/src/tabs/index.ts +30 -0
- package/extensions/dashboard-client/src/tabs/registry.ts +17 -0
- package/extensions/dashboard-server/routes-rag-settings-vector-cortex.ts +12 -0
- package/extensions/mega-runtime/widget-types.ts +2 -1
- package/package.json +1 -1
- package/src/config/vector-cortex-dash-0a.ts +24 -0
- package/src/config/vector-cortex-dash-0b.ts +23 -0
- package/src/config/vector-cortex.ts +4 -0
- package/src/config.ts +2 -0
- package/extensions/dashboard-client/dist/assets/SessionsTab-B3quvYPZ.js +0 -2
- package/extensions/dashboard-client/dist/assets/SessionsTab-B3quvYPZ.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/TurnsTab-CmhRJJqr.js +0 -5
- package/extensions/dashboard-client/dist/assets/TurnsTab-CmhRJJqr.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DDjCkTjk.js +0 -2
- package/extensions/dashboard-client/dist/assets/VectorCortexTab-DDjCkTjk.js.map +0 -1
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dash-consolidation/plan.ts — DASH-0a typed merge plan for the dashboard.
|
|
3
|
+
*
|
|
4
|
+
* Contract-planning only: this module records, as concrete data structures, the
|
|
5
|
+
* collapse of the 13 current dashboard TabIds onto the fixed 7 navigational
|
|
6
|
+
* surfaces (Overview, Sessions, Cache+Performance, Memory Graph, Diagnostics,
|
|
7
|
+
* Setup, Admin). The shell (App.tsx), the lazy list, and every tab/section
|
|
8
|
+
* component are untouched by this sprint — DASH-0b/0c consume this plan to
|
|
9
|
+
* move components, DASH-0d wires deep links + a11y hooks against it.
|
|
10
|
+
*
|
|
11
|
+
* All constants are `readonly`; no `any`. Imports only the TabId union (never
|
|
12
|
+
* redefined locally) so the plan can never drift from the live registry.
|
|
13
|
+
*/
|
|
14
|
+
import type { TabId } from "../tabs/registry";
|
|
15
|
+
|
|
16
|
+
/** The fixed 7 dashboard navigation surfaces. */
|
|
17
|
+
export type DASHSurface =
|
|
18
|
+
| "overview"
|
|
19
|
+
| "sessions"
|
|
20
|
+
| "cache-perf"
|
|
21
|
+
| "memory-graph"
|
|
22
|
+
| "diagnostics"
|
|
23
|
+
| "setup"
|
|
24
|
+
| "admin";
|
|
25
|
+
|
|
26
|
+
/** A source TabId the plan records as kept-but-not-a-surface (legacy section). */
|
|
27
|
+
export interface LegacySection {
|
|
28
|
+
id: TabId | "topics" | "achievements" | "game";
|
|
29
|
+
disposition: "keep_but_listed_under";
|
|
30
|
+
keep_but_listed_under: DASHSurface;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** One row of the per-surface merge plan. */
|
|
34
|
+
export interface DashSurfacePlan {
|
|
35
|
+
surface: DASHSurface;
|
|
36
|
+
label: string;
|
|
37
|
+
/** Current top-level TabIds folded into this surface. */
|
|
38
|
+
sources: readonly TabId[];
|
|
39
|
+
/** Delegate component/card ids that land on this surface. */
|
|
40
|
+
mergedCardIds: readonly string[];
|
|
41
|
+
/** Setup-only: the existent SetupTab SUB_TABS member ids (under setup, NOT admin). */
|
|
42
|
+
setup_subtabs?: readonly string[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The 7-surface merge plan keyed by surface id. */
|
|
46
|
+
export const DASH_TAB_PLAN: readonly DashSurfacePlan[] = [
|
|
47
|
+
{
|
|
48
|
+
surface: "overview",
|
|
49
|
+
label: "Overview",
|
|
50
|
+
sources: ["overview"],
|
|
51
|
+
mergedCardIds: [],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
surface: "sessions",
|
|
55
|
+
label: "Sessions",
|
|
56
|
+
sources: ["sessions", "turns"],
|
|
57
|
+
mergedCardIds: [],
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
surface: "cache-perf",
|
|
61
|
+
label: "Cache + Performance",
|
|
62
|
+
sources: ["cache", "metrics"],
|
|
63
|
+
mergedCardIds: [],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
surface: "memory-graph",
|
|
67
|
+
label: "Memory Graph",
|
|
68
|
+
sources: ["memory-map", "repos", "wiki"],
|
|
69
|
+
mergedCardIds: [
|
|
70
|
+
"MemoryMapView",
|
|
71
|
+
"RaptorTreeView",
|
|
72
|
+
"WikiPage",
|
|
73
|
+
"WikiPageControls",
|
|
74
|
+
"TopicTimeline",
|
|
75
|
+
"TopicEvolutionView",
|
|
76
|
+
"TopicEvolutionGraph",
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
surface: "diagnostics",
|
|
81
|
+
label: "Diagnostics",
|
|
82
|
+
sources: ["vector-cortex", "events", "health"],
|
|
83
|
+
mergedCardIds: [
|
|
84
|
+
"VectorCortexDiagnosticsCard",
|
|
85
|
+
"VectorCortexClosureCard",
|
|
86
|
+
"VectorCortexCrystalsCard",
|
|
87
|
+
"VectorCortexEconomicsCard",
|
|
88
|
+
"VectorCortexLedgerCard",
|
|
89
|
+
"VectorCortexOutcomesCard",
|
|
90
|
+
"VectorCortexPlansCard",
|
|
91
|
+
"VectorCortexPlatformCard",
|
|
92
|
+
"VectorCortexPolicyCard",
|
|
93
|
+
"VectorCortexRenderCard",
|
|
94
|
+
"VectorCortexRepairCard",
|
|
95
|
+
"VectorCortexRestoreCard",
|
|
96
|
+
"VectorCortexRolloutCard",
|
|
97
|
+
"VectorCortexShardsCard",
|
|
98
|
+
"VectorCortexTopologyCard",
|
|
99
|
+
],
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
surface: "setup",
|
|
103
|
+
label: "Setup",
|
|
104
|
+
sources: ["setup"],
|
|
105
|
+
mergedCardIds: [
|
|
106
|
+
"SettingsPanel",
|
|
107
|
+
"SettingsSection",
|
|
108
|
+
"ThresholdsPanel",
|
|
109
|
+
"CortexSetup",
|
|
110
|
+
"EmbedderSetup",
|
|
111
|
+
"CortexActionsCard",
|
|
112
|
+
"CortexBlockersCard",
|
|
113
|
+
"CortexEncoderCard",
|
|
114
|
+
"CortexRuntimeCard",
|
|
115
|
+
"EmbedderHealthCard",
|
|
116
|
+
"RagHealthCard",
|
|
117
|
+
"CustomEndpointSection",
|
|
118
|
+
"VectorCortexCosineFpCard",
|
|
119
|
+
"VectorCortexRepoCorpusCard",
|
|
120
|
+
],
|
|
121
|
+
// The existent SetupTab SUB_TABS member — recorded under Setup, NOT admin.
|
|
122
|
+
setup_subtabs: ["config"],
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
surface: "admin",
|
|
126
|
+
label: "Admin",
|
|
127
|
+
sources: ["maintenance"],
|
|
128
|
+
mergedCardIds: [
|
|
129
|
+
"ActionsCard",
|
|
130
|
+
"DbStatsCard",
|
|
131
|
+
"DebugBundleCard",
|
|
132
|
+
"HealthMitigationCard",
|
|
133
|
+
"SchemaHealthCard",
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
|
|
138
|
+
/** Exactly 7 fixed surfaces. */
|
|
139
|
+
export const DASH_TAB_COUNT = 7;
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Legacy sections rendered today that are kept-but-folded under a surface.
|
|
143
|
+
* One explicit bucket per non-surface tab/section so the audit stays total.
|
|
144
|
+
*/
|
|
145
|
+
export const DASH_LEGACY_SECTIONS: readonly LegacySection[] = [
|
|
146
|
+
{ id: "topics", disposition: "keep_but_listed_under", keep_but_listed_under: "admin" },
|
|
147
|
+
{ id: "achievements", disposition: "keep_but_listed_under", keep_but_listed_under: "admin" },
|
|
148
|
+
{ id: "game", disposition: "keep_but_listed_under", keep_but_listed_under: "admin" },
|
|
149
|
+
];
|
|
150
|
+
|
|
151
|
+
/** Old route -> new { surface, sub-tab hint } map, one entry per current TabId.
|
|
152
|
+
* Feeds the DASH-0d hash router; does not change App.tsx routing this sprint. */
|
|
153
|
+
export const DEEP_LINK_TARGETS: Readonly<Record<TabId, { surface: DASHSurface; subTabHint: string }>> = {
|
|
154
|
+
overview: { surface: "overview", subTabHint: "overview" },
|
|
155
|
+
sessions: { surface: "sessions", subTabHint: "session-list" },
|
|
156
|
+
turns: { surface: "sessions", subTabHint: "turn-list" },
|
|
157
|
+
cache: { surface: "cache-perf", subTabHint: "cache-cards" },
|
|
158
|
+
metrics: { surface: "cache-perf", subTabHint: "perf-cards" },
|
|
159
|
+
"memory-map": { surface: "memory-graph", subTabHint: "memory-map" },
|
|
160
|
+
repos: { surface: "memory-graph", subTabHint: "repo-list" },
|
|
161
|
+
wiki: { surface: "memory-graph", subTabHint: "wiki" },
|
|
162
|
+
"vector-cortex": { surface: "diagnostics", subTabHint: "cortex" },
|
|
163
|
+
events: { surface: "diagnostics", subTabHint: "event-log" },
|
|
164
|
+
health: { surface: "diagnostics", subTabHint: "health" },
|
|
165
|
+
setup: { surface: "setup", subTabHint: "settings" },
|
|
166
|
+
maintenance: { surface: "admin", subTabHint: "maintenance" },
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/** One a11y landmark row per fixed surface (DASH-0d axe-hook contract).
|
|
170
|
+
* No ARIA markup is emitted this sprint — this constant IS the contract. */
|
|
171
|
+
export interface NavMapRow {
|
|
172
|
+
surface: DASHSurface;
|
|
173
|
+
navLabel: string;
|
|
174
|
+
subNavLabel: string | null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export const DASH_NAV_MAP: readonly NavMapRow[] = [
|
|
178
|
+
{ surface: "overview", navLabel: "Overview", subNavLabel: null },
|
|
179
|
+
{ surface: "sessions", navLabel: "Session windows", subNavLabel: "Session turns" },
|
|
180
|
+
{ surface: "cache-perf", navLabel: "Performance cards", subNavLabel: "Cache status" },
|
|
181
|
+
{ surface: "memory-graph", navLabel: "Memory graph", subNavLabel: "Wiki + repos" },
|
|
182
|
+
{ surface: "diagnostics", navLabel: "Diagnostics groups", subNavLabel: "Event + health" },
|
|
183
|
+
{ surface: "setup", navLabel: "Setup", subNavLabel: "Sub-tabs" },
|
|
184
|
+
{ surface: "admin", navLabel: "Admin", subNavLabel: "Maintenance" },
|
|
185
|
+
];
|
|
186
|
+
|
|
187
|
+
/** Per-surface responsive plan: column strategy + sub-tab toggle collapse.
|
|
188
|
+
* All grids stay `grid-cols-1 md:grid-cols-3`, matching existent card grids;
|
|
189
|
+
* below `sm` sub-tab toggles collapse to a horizontal scroll region. */
|
|
190
|
+
export interface ResponsivePlan {
|
|
191
|
+
surface: DASHSurface;
|
|
192
|
+
grid: "grid-cols-1 md:grid-cols-3";
|
|
193
|
+
subTabCollapseBelow: "sm";
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export const DASH_RESPONSIVE: readonly ResponsivePlan[] = DASH_TAB_PLAN.map((p) => ({
|
|
197
|
+
surface: p.surface,
|
|
198
|
+
grid: "grid-cols-1 md:grid-cols-3",
|
|
199
|
+
subTabCollapseBelow: "sm",
|
|
200
|
+
}));
|
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-client/src/tabs/SessionsTab/TurnMemoryView.tsx — Turn-by-turn memory
|
|
3
|
+
* tracking + recall (S52), moved VERBATIM from the top-level TurnsTab.tsx.
|
|
4
|
+
*
|
|
5
|
+
* DASH-0b: the Sessions surface absorbs the existent TurnsTab as a drill-down.
|
|
6
|
+
* This file holds the byte-preserved turns body (the `TurnMemoryView`
|
|
7
|
+
* component). The standalone `tabs/TurnsTab.tsx` is LEFT UNTOUCHED this sprint —
|
|
8
|
+
* its copy stays live for flag-off / pre-DASH parity. A DASH-0d cleanup deletes
|
|
9
|
+
* the standalone copy after a deep-link audit proves no live consumer points
|
|
10
|
+
* at it. Only the export name changed (TurnsTab → TurnMemoryView); the render
|
|
11
|
+
* body is otherwise identical.
|
|
12
|
+
*
|
|
13
|
+
* Fetches /api/turns (conversation list), expands the active conversation into
|
|
14
|
+
* per-turn detail (/api/turns/conversation/:id), and renders:
|
|
15
|
+
* - Conversation summary list (turn count, recall total, epochs, last turn).
|
|
16
|
+
* - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,
|
|
17
|
+
* epoch id, and the injected-checkpoint recall set (the memory recalled
|
|
18
|
+
* at each turn, with score + source).
|
|
19
|
+
* - Pending rewind intents (S52A) + Fork action (S50C primitive).
|
|
20
|
+
*
|
|
21
|
+
* Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs
|
|
22
|
+
* (PREVENT-PI-004: loopback-only, same-origin static bundle).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import type React from "react";
|
|
26
|
+
import { useCallback, useState } from "react";
|
|
27
|
+
import { useApi } from "../../hooks/useApi";
|
|
28
|
+
import {
|
|
29
|
+
fetchTurns,
|
|
30
|
+
fetchConversationTurns,
|
|
31
|
+
fetchTurnIntents,
|
|
32
|
+
postFork,
|
|
33
|
+
postTurnIntent,
|
|
34
|
+
} from "../../api/client";
|
|
35
|
+
import type {
|
|
36
|
+
TurnsResponse,
|
|
37
|
+
ConversationTurnsResponse,
|
|
38
|
+
RewindIntentsResponse,
|
|
39
|
+
TurnRow,
|
|
40
|
+
ConversationSummary,
|
|
41
|
+
} from "@contracts";
|
|
42
|
+
import { Card, CardContent, CardHeader, CardTitle } from "../../components/ui/card";
|
|
43
|
+
import { Badge } from "../../components/ui/badge";
|
|
44
|
+
import { Button } from "../../components/ui/button";
|
|
45
|
+
import { HydeDetailPanel } from "../../components/HydeDetailPanel";
|
|
46
|
+
|
|
47
|
+
function fmtTs(ms: number): string {
|
|
48
|
+
if (!ms) return "—";
|
|
49
|
+
return new Date(ms).toLocaleString();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function bandVariant(band: TurnRow["pressureBand"]): "success" | "warning" | "danger" | "default" {
|
|
53
|
+
if (band === "green") return "success";
|
|
54
|
+
if (band === "yellow") return "warning";
|
|
55
|
+
if (band === "red") return "danger";
|
|
56
|
+
return "default";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function sourceLabel(s: TurnRow["recall"][number]["source"]): string {
|
|
60
|
+
if (s === "checkpoint") return "ckpt";
|
|
61
|
+
if (s === "cluster_summary") return "raptor";
|
|
62
|
+
return "mem";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function TurnMemoryView(): React.ReactElement {
|
|
66
|
+
const {
|
|
67
|
+
data: turns,
|
|
68
|
+
loading,
|
|
69
|
+
error,
|
|
70
|
+
} = useApi<TurnsResponse>(
|
|
71
|
+
useCallback(() => fetchTurns(), []),
|
|
72
|
+
{
|
|
73
|
+
pollInterval: 10_000,
|
|
74
|
+
},
|
|
75
|
+
);
|
|
76
|
+
const { data: intents } = useApi<RewindIntentsResponse>(
|
|
77
|
+
useCallback(() => fetchTurnIntents(), []),
|
|
78
|
+
{ pollInterval: 5_000 },
|
|
79
|
+
);
|
|
80
|
+
const [expanded, setExpanded] = useState<string | null>(null);
|
|
81
|
+
const [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);
|
|
82
|
+
const [detailLoading, setDetailLoading] = useState(false);
|
|
83
|
+
const [busy, setBusy] = useState<string | null>(null);
|
|
84
|
+
const [notice, setNotice] = useState<string | null>(null);
|
|
85
|
+
|
|
86
|
+
const expand = useCallback(
|
|
87
|
+
async (conversationId: string) => {
|
|
88
|
+
if (expanded === conversationId) {
|
|
89
|
+
setExpanded(null);
|
|
90
|
+
setDetail(null);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
setExpanded(conversationId);
|
|
94
|
+
setDetailLoading(true);
|
|
95
|
+
setDetail(null);
|
|
96
|
+
try {
|
|
97
|
+
const d = await fetchConversationTurns(conversationId);
|
|
98
|
+
setDetail(d);
|
|
99
|
+
} finally {
|
|
100
|
+
setDetailLoading(false);
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
[expanded],
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
const onFork = useCallback(
|
|
107
|
+
async (conversationId: string, turnIndex: number) => {
|
|
108
|
+
setBusy(`fork:${conversationId}:${turnIndex}`);
|
|
109
|
+
setNotice(null);
|
|
110
|
+
try {
|
|
111
|
+
const out = await postFork(conversationId, turnIndex);
|
|
112
|
+
setNotice(
|
|
113
|
+
`Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,
|
|
114
|
+
);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
setNotice(`Fork failed: ${(e as Error).message}`);
|
|
117
|
+
} finally {
|
|
118
|
+
setBusy(null);
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
[],
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
const onRewind = useCallback(
|
|
125
|
+
async (conversationId: string, turnIndex: number) => {
|
|
126
|
+
setBusy(`rewind:${conversationId}:${turnIndex}`);
|
|
127
|
+
setNotice(null);
|
|
128
|
+
try {
|
|
129
|
+
await postTurnIntent(conversationId, turnIndex);
|
|
130
|
+
setNotice(`Rewind intent queued for turn ${turnIndex}`);
|
|
131
|
+
} catch (e) {
|
|
132
|
+
setNotice(`Rewind failed: ${(e as Error).message}`);
|
|
133
|
+
} finally {
|
|
134
|
+
setBusy(null);
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
[],
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
if (error && !turns) {
|
|
141
|
+
return <div className="tab-stub">Error loading turns: {error.message}</div>;
|
|
142
|
+
}
|
|
143
|
+
if (loading && !turns) {
|
|
144
|
+
return <div className="tab-stub">Loading turns…</div>;
|
|
145
|
+
}
|
|
146
|
+
if (!turns || turns.conversations.length === 0) {
|
|
147
|
+
return (
|
|
148
|
+
<div className="tab-stub">
|
|
149
|
+
<h3>Turn-by-turn memory</h3>
|
|
150
|
+
<p>
|
|
151
|
+
No turns recorded yet. Per-turn tracking starts when{" "}
|
|
152
|
+
<code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a
|
|
153
|
+
compaction. Each turn records its context metrics + the checkpoints
|
|
154
|
+
recalled into it.
|
|
155
|
+
</p>
|
|
156
|
+
</div>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div className="flex flex-col gap-4">
|
|
162
|
+
<h3 className="font-heading text-lg font-semibold">
|
|
163
|
+
Turn-by-turn memory tracking + recall
|
|
164
|
+
</h3>
|
|
165
|
+
{notice && <Badge variant="warning">{notice}</Badge>}
|
|
166
|
+
|
|
167
|
+
{intents && intents.intents.length > 0 && (
|
|
168
|
+
<Card>
|
|
169
|
+
<CardHeader>
|
|
170
|
+
<CardTitle>
|
|
171
|
+
Pending rewind intents ({intents.intents.length})
|
|
172
|
+
</CardTitle>
|
|
173
|
+
</CardHeader>
|
|
174
|
+
<CardContent>
|
|
175
|
+
<ul className="list-disc space-y-1 pl-5">
|
|
176
|
+
{intents.intents.map((i) => (
|
|
177
|
+
<li key={i.id}>
|
|
178
|
+
{fmtTs(i.createdAt)} — rewind{" "}
|
|
179
|
+
<code>{i.conversationId}</code> to turn {i.targetTurnIndex}
|
|
180
|
+
</li>
|
|
181
|
+
))}
|
|
182
|
+
</ul>
|
|
183
|
+
</CardContent>
|
|
184
|
+
</Card>
|
|
185
|
+
)}
|
|
186
|
+
|
|
187
|
+
<Card>
|
|
188
|
+
<CardHeader>
|
|
189
|
+
<CardTitle>
|
|
190
|
+
Conversations ({turns.conversations.length})
|
|
191
|
+
</CardTitle>
|
|
192
|
+
</CardHeader>
|
|
193
|
+
<CardContent>
|
|
194
|
+
<table className="w-full border-collapse text-sm">
|
|
195
|
+
<thead>
|
|
196
|
+
<tr>
|
|
197
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Conversation</th>
|
|
198
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Turns</th>
|
|
199
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recall</th>
|
|
200
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epochs</th>
|
|
201
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Avg ctx%</th>
|
|
202
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Last turn</th>
|
|
203
|
+
<th className="border-b border-border px-3 py-2"></th>
|
|
204
|
+
</tr>
|
|
205
|
+
</thead>
|
|
206
|
+
<tbody>
|
|
207
|
+
{turns.conversations.map((c: ConversationSummary) => (
|
|
208
|
+
<ConversationRow
|
|
209
|
+
key={c.conversationId}
|
|
210
|
+
c={c}
|
|
211
|
+
active={turns.activeConversationId === c.conversationId}
|
|
212
|
+
expanded={expanded === c.conversationId}
|
|
213
|
+
onExpand={() => expand(c.conversationId)}
|
|
214
|
+
/>
|
|
215
|
+
))}
|
|
216
|
+
</tbody>
|
|
217
|
+
</table>
|
|
218
|
+
</CardContent>
|
|
219
|
+
</Card>
|
|
220
|
+
|
|
221
|
+
{expanded && (
|
|
222
|
+
<Card>
|
|
223
|
+
<CardHeader>
|
|
224
|
+
<CardTitle>
|
|
225
|
+
Turns in <code>{expanded}</code>
|
|
226
|
+
</CardTitle>
|
|
227
|
+
</CardHeader>
|
|
228
|
+
<CardContent>
|
|
229
|
+
{detailLoading ? (
|
|
230
|
+
<div className="text-sm text-muted-foreground">Loading turns…</div>
|
|
231
|
+
) : detail ? (
|
|
232
|
+
<TurnDetail
|
|
233
|
+
detail={detail}
|
|
234
|
+
busy={busy}
|
|
235
|
+
onFork={onFork}
|
|
236
|
+
onRewind={onRewind}
|
|
237
|
+
/>
|
|
238
|
+
) : (
|
|
239
|
+
<div className="text-sm text-muted-foreground">No detail.</div>
|
|
240
|
+
)}
|
|
241
|
+
</CardContent>
|
|
242
|
+
</Card>
|
|
243
|
+
)}
|
|
244
|
+
</div>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function ConversationRow({
|
|
249
|
+
c,
|
|
250
|
+
active,
|
|
251
|
+
expanded,
|
|
252
|
+
onExpand,
|
|
253
|
+
}: {
|
|
254
|
+
c: ConversationSummary;
|
|
255
|
+
active: boolean;
|
|
256
|
+
expanded: boolean;
|
|
257
|
+
onExpand: () => void;
|
|
258
|
+
}): React.ReactElement {
|
|
259
|
+
return (
|
|
260
|
+
<>
|
|
261
|
+
<tr
|
|
262
|
+
className={`border-b border-border/50 hover:bg-bg-elevated/40 ${
|
|
263
|
+
active ? "bg-primary/10" : ""
|
|
264
|
+
}`}
|
|
265
|
+
onClick={onExpand}
|
|
266
|
+
style={{ cursor: "pointer" }}
|
|
267
|
+
>
|
|
268
|
+
<td className="px-3 py-2">
|
|
269
|
+
{expanded ? "▾" : "▸"} <code>{c.conversationId}</code>
|
|
270
|
+
{active && <Badge variant="accent" className="ml-2">active</Badge>}
|
|
271
|
+
</td>
|
|
272
|
+
<td className="px-3 py-2 text-right">{c.turnCount}</td>
|
|
273
|
+
<td className="px-3 py-2 text-right">{c.totalRecall}</td>
|
|
274
|
+
<td className="px-3 py-2 text-right">{c.epochCount}</td>
|
|
275
|
+
<td className="px-3 py-2 text-right">{c.avgCtxPercent.toFixed(0)}%</td>
|
|
276
|
+
<td className="px-3 py-2">{fmtTs(c.lastTurnAt)}</td>
|
|
277
|
+
<td className="px-3 py-2" />
|
|
278
|
+
</tr>
|
|
279
|
+
</>
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function TurnDetail({
|
|
284
|
+
detail,
|
|
285
|
+
busy,
|
|
286
|
+
onFork,
|
|
287
|
+
onRewind,
|
|
288
|
+
}: {
|
|
289
|
+
detail: ConversationTurnsResponse;
|
|
290
|
+
busy: string | null;
|
|
291
|
+
onFork: (conversationId: string, turnIndex: number) => void;
|
|
292
|
+
onRewind: (conversationId: string, turnIndex: number) => void;
|
|
293
|
+
}): React.ReactElement {
|
|
294
|
+
return (
|
|
295
|
+
<table className="w-full border-collapse text-sm">
|
|
296
|
+
<thead>
|
|
297
|
+
<tr>
|
|
298
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">#</th>
|
|
299
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Role</th>
|
|
300
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ctx</th>
|
|
301
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Band</th>
|
|
302
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Epoch</th>
|
|
303
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Recalled checkpoints (memory recall)</th>
|
|
304
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">HyDE</th>
|
|
305
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Ended</th>
|
|
306
|
+
<th className="border-b border-border px-3 py-2 text-left font-medium text-muted-foreground">Actions</th>
|
|
307
|
+
</tr>
|
|
308
|
+
</thead>
|
|
309
|
+
<tbody>
|
|
310
|
+
{detail.turns.map((t) => (
|
|
311
|
+
<tr
|
|
312
|
+
key={`${t.conversationId}:${t.turnIndex}`}
|
|
313
|
+
className="border-b border-border/50 hover:bg-bg-elevated/40"
|
|
314
|
+
>
|
|
315
|
+
<td className="px-3 py-2 text-right">{t.turnIndex}</td>
|
|
316
|
+
<td className="px-3 py-2">{t.role}</td>
|
|
317
|
+
<td className="px-3 py-2">
|
|
318
|
+
{t.ctxTokens ?? "—"}
|
|
319
|
+
{t.ctxPercent != null && (
|
|
320
|
+
<span className="text-muted-foreground">
|
|
321
|
+
{" "}
|
|
322
|
+
· {t.ctxPercent.toFixed(0)}%
|
|
323
|
+
</span>
|
|
324
|
+
)}
|
|
325
|
+
</td>
|
|
326
|
+
<td className="px-3 py-2">
|
|
327
|
+
<Badge variant={bandVariant(t.pressureBand)}>
|
|
328
|
+
{t.pressureBand ?? "—"}
|
|
329
|
+
</Badge>
|
|
330
|
+
</td>
|
|
331
|
+
<td className="px-3 py-2">{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : "—"}</td>
|
|
332
|
+
<td className="px-3 py-2">
|
|
333
|
+
{t.recall.length === 0 ? (
|
|
334
|
+
<span className="text-muted-foreground">—</span>
|
|
335
|
+
) : (
|
|
336
|
+
<ul className="space-y-1">
|
|
337
|
+
{t.recall.map((r) => (
|
|
338
|
+
<li key={r.checkpointId}>
|
|
339
|
+
<code>{r.checkpointId.slice(0, 12)}</code>{" "}
|
|
340
|
+
<span className="text-muted-foreground">
|
|
341
|
+
{sourceLabel(r.source)} · {r.score.toFixed(2)}
|
|
342
|
+
{r.raptorLevel != null ? ` · L${r.raptorLevel}` : ""}
|
|
343
|
+
</span>
|
|
344
|
+
</li>
|
|
345
|
+
))}
|
|
346
|
+
</ul>
|
|
347
|
+
)}
|
|
348
|
+
</td>
|
|
349
|
+
<td className="px-3 py-2 align-top">
|
|
350
|
+
<HydeDetailPanel
|
|
351
|
+
conversationId={t.conversationId}
|
|
352
|
+
turnIndex={t.turnIndex}
|
|
353
|
+
/>
|
|
354
|
+
</td>
|
|
355
|
+
<td className="px-3 py-2">{fmtTs(t.endedAt)}</td>
|
|
356
|
+
<td className="px-3 py-2">
|
|
357
|
+
<div className="flex gap-2">
|
|
358
|
+
<Button
|
|
359
|
+
type="button"
|
|
360
|
+
variant="outline"
|
|
361
|
+
size="sm"
|
|
362
|
+
disabled={busy !== null}
|
|
363
|
+
onClick={() => onFork(t.conversationId, t.turnIndex)}
|
|
364
|
+
>
|
|
365
|
+
fork
|
|
366
|
+
</Button>
|
|
367
|
+
<Button
|
|
368
|
+
type="button"
|
|
369
|
+
variant="outline"
|
|
370
|
+
size="sm"
|
|
371
|
+
disabled={busy !== null}
|
|
372
|
+
onClick={() => onRewind(t.conversationId, t.turnIndex)}
|
|
373
|
+
>
|
|
374
|
+
rewind
|
|
375
|
+
</Button>
|
|
376
|
+
</div>
|
|
377
|
+
</td>
|
|
378
|
+
</tr>
|
|
379
|
+
))}
|
|
380
|
+
</tbody>
|
|
381
|
+
</table>
|
|
382
|
+
);
|
|
383
|
+
}
|