pi-mega-compact 0.8.12 → 0.8.15
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 +44 -21
- package/dist/extensions/mega-cache-replay.test.js +4 -2
- package/dist/extensions/mega-compact-s38.test.js +317 -0
- package/dist/extensions/mega-compact.js +14 -0
- package/dist/extensions/mega-compact.test.js +37 -8
- package/dist/extensions/mega-config.js +5 -0
- package/dist/extensions/mega-events/agent-handlers.js +184 -4
- package/dist/extensions/mega-events/context-handler.js +35 -2
- package/dist/extensions/mega-events/error-classifier.js +118 -0
- package/dist/extensions/mega-events.js +1 -0
- package/dist/extensions/mega-runtime/state.js +16 -0
- package/dist/extensions/mega-teamrun.test.js +14 -1
- package/extensions/dashboard-client/dist/assets/AchievementTiles-BH26e95w.js +2 -0
- package/extensions/dashboard-client/dist/assets/AchievementTiles-BH26e95w.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/AchievementsTab-B94wvRV_.js +2 -0
- package/extensions/dashboard-client/dist/assets/AchievementsTab-B94wvRV_.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-DPmw3NHR.js +2 -0
- package/extensions/dashboard-client/dist/assets/CacheTab-DPmw3NHR.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js +2 -0
- package/extensions/dashboard-client/dist/assets/ConfigTab-C3g3smRL.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-B5PicfFw.js +2 -0
- package/extensions/dashboard-client/dist/assets/EventsTab-B5PicfFw.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/GameTab-CsVwp78a.js +2 -0
- package/extensions/dashboard-client/dist/assets/GameTab-CsVwp78a.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-Cf72UewX.js +2 -0
- package/extensions/dashboard-client/dist/assets/MetricsTab-Cf72UewX.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-Dh6aG3gy.js +2 -0
- package/extensions/dashboard-client/dist/assets/OverviewTab-Dh6aG3gy.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-HXf2dorl.js +2 -0
- package/extensions/dashboard-client/dist/assets/ReposTab-HXf2dorl.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-kUnoospE.js +2 -0
- package/extensions/dashboard-client/dist/assets/TimeSavedCard-kUnoospE.js.map +1 -0
- package/extensions/dashboard-client/dist/assets/index-Cfxniu2R.css +1 -0
- package/extensions/dashboard-client/dist/assets/{index-XAIN8km6.js → index-DMntLu-8.js} +11 -10
- package/extensions/dashboard-client/dist/assets/index-DMntLu-8.js.map +1 -0
- package/extensions/dashboard-client/dist/index.html +2 -2
- package/extensions/dashboard-client/src/App.tsx +18 -4
- package/extensions/dashboard-client/src/components/AchievementTiles.tsx +105 -0
- package/extensions/dashboard-client/src/components/ActiveReposTable.tsx +116 -0
- package/extensions/dashboard-client/src/components/CacheHitsCard.tsx +73 -0
- package/extensions/dashboard-client/src/components/CacheStatusPerModel.tsx +78 -35
- package/extensions/dashboard-client/src/components/ConfigSummaryCard.tsx +101 -0
- package/extensions/dashboard-client/src/components/ContextGauge.tsx +11 -15
- package/extensions/dashboard-client/src/components/DataSafetyCard.tsx +42 -33
- package/extensions/dashboard-client/src/components/EventCategoryFilter.tsx +46 -9
- package/extensions/dashboard-client/src/components/LegendCard.tsx +49 -0
- package/extensions/dashboard-client/src/components/ModelBadge.tsx +42 -11
- package/extensions/dashboard-client/src/components/PerfCards.tsx +91 -0
- package/extensions/dashboard-client/src/components/RepoAllSessionsCard.tsx +102 -0
- package/extensions/dashboard-client/src/components/RepoDetailModal.tsx +9 -2
- package/extensions/dashboard-client/src/components/RepoTable.tsx +30 -22
- package/extensions/dashboard-client/src/components/SavingsByModelTable.tsx +226 -0
- package/extensions/dashboard-client/src/components/SessionInfo.tsx +25 -50
- package/extensions/dashboard-client/src/components/SummaryTiles.tsx +20 -11
- package/extensions/dashboard-client/src/components/TimeSavedCard.tsx +61 -0
- package/extensions/dashboard-client/src/components/TriggerStatus.tsx +31 -19
- package/extensions/dashboard-client/src/components/VectorStoreCard.tsx +134 -0
- package/extensions/dashboard-client/src/main.tsx +5 -0
- package/extensions/dashboard-client/src/styles/base.css +77 -9
- package/extensions/dashboard-client/src/styles/config.css +149 -0
- package/extensions/dashboard-client/src/styles/game-achievements.css +265 -0
- package/extensions/dashboard-client/src/styles/metrics-extra.css +69 -0
- package/extensions/dashboard-client/src/styles/overview-extra.css +170 -0
- package/extensions/dashboard-client/src/styles/repos-extra.css +99 -0
- package/extensions/dashboard-client/src/styles/repos-metrics.css +14 -23
- package/extensions/dashboard-client/src/tabs/AchievementsTab.tsx +55 -0
- package/extensions/dashboard-client/src/tabs/CacheTab.tsx +50 -0
- package/extensions/dashboard-client/src/tabs/ConfigTab.tsx +240 -5
- package/extensions/dashboard-client/src/tabs/EventsTab.tsx +55 -3
- package/extensions/dashboard-client/src/tabs/GameTab.tsx +287 -0
- package/extensions/dashboard-client/src/tabs/MetricsTab.tsx +7 -1
- package/extensions/dashboard-client/src/tabs/OverviewTab.tsx +103 -17
- package/extensions/dashboard-client/src/tabs/ReposTab.tsx +57 -22
- package/extensions/dashboard-client/src/utils/format.ts +85 -0
- package/extensions/dashboard-client/src/utils/types.ts +27 -0
- package/extensions/mega-cache-replay.test.ts +3 -3
- package/extensions/mega-compact-s38.test.ts +330 -0
- package/extensions/mega-compact.test.ts +41 -13
- package/extensions/mega-compact.ts +14 -0
- package/extensions/mega-config.ts +24 -0
- package/extensions/mega-dashboard.ts +7 -0
- package/extensions/mega-events/agent-handlers.ts +179 -5
- package/extensions/mega-events/context-handler.ts +31 -2
- package/extensions/mega-events/error-classifier.ts +109 -0
- package/extensions/mega-events.ts +1 -0
- package/extensions/mega-runtime/helpers.ts +5 -0
- package/extensions/mega-runtime/state.ts +17 -1
- package/extensions/mega-teamrun.test.ts +13 -1
- package/package.json +4 -1
- package/dist/extensions/dashboard-server/helpers.js +0 -37
- package/dist/extensions/dashboard-server/html/all-repos-tab.js +0 -26
- package/dist/extensions/dashboard-server/html/body-open.js +0 -23
- package/dist/extensions/dashboard-server/html/current-repo-tab.js +0 -130
- package/dist/extensions/dashboard-server/html/head-open.js +0 -16
- package/dist/extensions/dashboard-server/html/high-score-tab.js +0 -25
- package/dist/extensions/dashboard-server/html/repo-detail-modal.js +0 -26
- package/dist/extensions/dashboard-server/html/script.js +0 -259
- package/dist/extensions/dashboard-server/html/styles.js +0 -103
- package/dist/extensions/dashboard-server/html/summary-tab.js +0 -19
- package/dist/extensions/dashboard-server/html-template.js +0 -41
- package/dist/src/store/sqlite/connection.js +0 -35
- package/dist/src/store/sqlite/index-store.js +0 -167
- package/dist/src/store/sqlite/memory.js +0 -54
- package/dist/src/store/sqlite/minhash-lsh.js +0 -47
- package/dist/src/store/sqlite/sessions.js +0 -39
- package/dist/src/store/sqlite/transaction.js +0 -19
- package/dist/src/vectorStore/add.js +0 -260
- package/dist/src/vectorStore/dedup.js +0 -52
- package/dist/src/vectorStore/index.js +0 -10
- package/dist/src/vectorStore/queries.js +0 -83
- package/dist/src/vectorStore/search.js +0 -95
- package/dist/src/vectorStore/session.js +0 -19
- package/dist/src/vectorStore/store.js +0 -105
- package/dist/src/vectorStore/types.js +0 -6
- package/dist/src/vectorStore/utils.js +0 -23
- package/extensions/dashboard-client/dist/assets/ConfigTab-RrjXWfvr.js +0 -2
- package/extensions/dashboard-client/dist/assets/ConfigTab-RrjXWfvr.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/EventsTab-BH_FxJ08.js +0 -2
- package/extensions/dashboard-client/dist/assets/EventsTab-BH_FxJ08.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/MetricsTab-C-PoFV4p.js +0 -2
- package/extensions/dashboard-client/dist/assets/MetricsTab-C-PoFV4p.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/OverviewTab-Db-qBqFN.js +0 -2
- package/extensions/dashboard-client/dist/assets/OverviewTab-Db-qBqFN.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/ReposTab-DhCjJvuj.js +0 -2
- package/extensions/dashboard-client/dist/assets/ReposTab-DhCjJvuj.js.map +0 -1
- package/extensions/dashboard-client/dist/assets/index-Buer5yxB.css +0 -1
- package/extensions/dashboard-client/dist/assets/index-XAIN8km6.js.map +0 -1
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-client/src/components/SavingsByModelTable.tsx — Savings by Model.
|
|
3
|
+
*
|
|
4
|
+
* 14 columns aggregated client-side from /api/index repos by model.
|
|
5
|
+
* Replicates html.ts renderByModel logic: group by modelName, accumulate
|
|
6
|
+
* tokens/cost/sessions, collapse numeric ranges when repos disagree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type React from "react";
|
|
10
|
+
import { useMemo } from "react";
|
|
11
|
+
import type { IndexesIndexRow } from "@contracts";
|
|
12
|
+
|
|
13
|
+
export interface SavingsByModelTableProps {
|
|
14
|
+
repos: IndexesIndexRow[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ModelGroup {
|
|
18
|
+
model: string;
|
|
19
|
+
provider: string;
|
|
20
|
+
checkpoints: number;
|
|
21
|
+
tokensSaved: number;
|
|
22
|
+
tokensIn: number;
|
|
23
|
+
tokensOut: number;
|
|
24
|
+
sessions: number;
|
|
25
|
+
usd: number;
|
|
26
|
+
inRates: number[];
|
|
27
|
+
outRates: number[];
|
|
28
|
+
ctxWindows: number[];
|
|
29
|
+
maxTokens: number[];
|
|
30
|
+
reasoning: boolean | null;
|
|
31
|
+
lastAt: number;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Collapse numeric samples: "—" | single | "lo–hi" (matches html.ts). */
|
|
35
|
+
function collapseNum(samples: number[]): string {
|
|
36
|
+
if (!samples.length) return "\u2014";
|
|
37
|
+
const lo = Math.min(...samples);
|
|
38
|
+
const hi = Math.max(...samples);
|
|
39
|
+
return lo === hi
|
|
40
|
+
? lo.toLocaleString()
|
|
41
|
+
: `${lo.toLocaleString()}\u2013${hi.toLocaleString()}`;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Collapse rate samples: "—" | "$rate" | "$lo–$hi" (matches html.ts). */
|
|
45
|
+
function collapseRate(samples: number[]): string {
|
|
46
|
+
if (!samples.length) return "\u2014";
|
|
47
|
+
const lo = Math.min(...samples);
|
|
48
|
+
const hi = Math.max(...samples);
|
|
49
|
+
const fmt = (v: number): string => `$${v.toFixed(6)}`;
|
|
50
|
+
return lo === hi ? fmt(lo) : `${fmt(lo)}\u2013${fmt(hi)}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Group repos by model, accumulate totals, sort by tokensSaved desc. */
|
|
54
|
+
function aggregate(repos: IndexesIndexRow[]): ModelGroup[] {
|
|
55
|
+
const map: Record<string, ModelGroup> = {};
|
|
56
|
+
for (const r of repos) {
|
|
57
|
+
const key = (r.modelName && r.modelName.trim()) || "(unknown)";
|
|
58
|
+
if (!map[key]) {
|
|
59
|
+
map[key] = {
|
|
60
|
+
model: key,
|
|
61
|
+
provider: r.providerName ?? r.provider ?? "\u2014",
|
|
62
|
+
checkpoints: 0,
|
|
63
|
+
tokensSaved: 0,
|
|
64
|
+
tokensIn: 0,
|
|
65
|
+
tokensOut: 0,
|
|
66
|
+
sessions: 0,
|
|
67
|
+
usd: 0,
|
|
68
|
+
inRates: [],
|
|
69
|
+
outRates: [],
|
|
70
|
+
ctxWindows: [],
|
|
71
|
+
maxTokens: [],
|
|
72
|
+
reasoning: null,
|
|
73
|
+
lastAt: 0,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const g = map[key];
|
|
77
|
+
g.checkpoints += r.checkpointCount || 0;
|
|
78
|
+
g.tokensSaved += r.tokensSaved || 0;
|
|
79
|
+
g.tokensIn += r.tokensDropped || 0;
|
|
80
|
+
g.tokensOut += r.tokensKept || 0;
|
|
81
|
+
g.sessions += r.sessions || 0;
|
|
82
|
+
if (r.inputRate) {
|
|
83
|
+
g.usd += (r.tokensSaved || 0) * r.inputRate;
|
|
84
|
+
g.inRates.push(r.inputRate);
|
|
85
|
+
}
|
|
86
|
+
if (r.outputRate) g.outRates.push(r.outputRate);
|
|
87
|
+
if (r.contextWindow) g.ctxWindows.push(r.contextWindow);
|
|
88
|
+
if (r.maxTokens) g.maxTokens.push(r.maxTokens);
|
|
89
|
+
if (r.reasoning != null) g.reasoning = r.reasoning;
|
|
90
|
+
if (r.lastCompactedAt && r.lastCompactedAt > g.lastAt)
|
|
91
|
+
g.lastAt = r.lastCompactedAt;
|
|
92
|
+
}
|
|
93
|
+
return Object.values(map).sort((a, b) => b.tokensSaved - a.tokensSaved);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/** Tooltip text copied verbatim from html.ts title attributes. */
|
|
97
|
+
const TOOLTIPS = {
|
|
98
|
+
tokensIn: "Tokens dropped from context by compaction (the input reclaimed)",
|
|
99
|
+
tokensOut:
|
|
100
|
+
"Tokens kept as compacted summaries still in context (the output retained)",
|
|
101
|
+
ctxWindow: "Model context window (max input tokens the model accepts)",
|
|
102
|
+
maxOut: "Model max output tokens per turn",
|
|
103
|
+
reas: "Reasoning-capable model",
|
|
104
|
+
sessions: "Distinct sessions with at least one checkpoint",
|
|
105
|
+
inRate: "USD per input token",
|
|
106
|
+
outRate: "USD per output token",
|
|
107
|
+
} as const;
|
|
108
|
+
|
|
109
|
+
export function SavingsByModelTable({
|
|
110
|
+
repos,
|
|
111
|
+
}: SavingsByModelTableProps): React.ReactElement {
|
|
112
|
+
const groups = useMemo(() => aggregate(repos), [repos]);
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<div className="savings-by-model">
|
|
116
|
+
<p className="legend-note">
|
|
117
|
+
How much context & cost mega-compact has reclaimed, grouped by
|
|
118
|
+
the model you were running. Compression ratio reflects
|
|
119
|
+
workload/content, not model quality.
|
|
120
|
+
</p>
|
|
121
|
+
<div className="table-scroll">
|
|
122
|
+
<table className="savings-table">
|
|
123
|
+
<thead>
|
|
124
|
+
<tr>
|
|
125
|
+
<th>Model</th>
|
|
126
|
+
<th>Provider</th>
|
|
127
|
+
<th className="num" title={TOOLTIPS.tokensIn}>
|
|
128
|
+
Tokens In
|
|
129
|
+
</th>
|
|
130
|
+
<th className="num" title={TOOLTIPS.tokensOut}>
|
|
131
|
+
Tokens Out
|
|
132
|
+
</th>
|
|
133
|
+
<th className="num">Freed</th>
|
|
134
|
+
<th className="num" title={TOOLTIPS.ctxWindow}>
|
|
135
|
+
Ctx Window
|
|
136
|
+
</th>
|
|
137
|
+
<th className="num" title={TOOLTIPS.maxOut}>
|
|
138
|
+
Max Out
|
|
139
|
+
</th>
|
|
140
|
+
<th className="num" title={TOOLTIPS.reas}>
|
|
141
|
+
Reas.
|
|
142
|
+
</th>
|
|
143
|
+
<th className="num" title={TOOLTIPS.sessions}>
|
|
144
|
+
Sessions
|
|
145
|
+
</th>
|
|
146
|
+
<th className="num">Checkpoints</th>
|
|
147
|
+
<th className="num" title={TOOLTIPS.inRate}>
|
|
148
|
+
In $/tok
|
|
149
|
+
</th>
|
|
150
|
+
<th className="num" title={TOOLTIPS.outRate}>
|
|
151
|
+
Out $/tok
|
|
152
|
+
</th>
|
|
153
|
+
<th className="num">$ Saved</th>
|
|
154
|
+
<th className="num">Last Used</th>
|
|
155
|
+
</tr>
|
|
156
|
+
</thead>
|
|
157
|
+
<tbody>
|
|
158
|
+
{groups.length === 0 && (
|
|
159
|
+
<tr>
|
|
160
|
+
<td colSpan={14} className="repo-empty">
|
|
161
|
+
No repositories registered yet.
|
|
162
|
+
</td>
|
|
163
|
+
</tr>
|
|
164
|
+
)}
|
|
165
|
+
{groups.map((g) => {
|
|
166
|
+
const freed = (g.tokensIn || 0) - (g.tokensOut || 0);
|
|
167
|
+
const usd =
|
|
168
|
+
g.usd > 0 ? `$${g.usd.toFixed(4)}` : "\u2014";
|
|
169
|
+
const when = g.lastAt
|
|
170
|
+
? new Date(g.lastAt).toLocaleString()
|
|
171
|
+
: "\u2014";
|
|
172
|
+
const reas =
|
|
173
|
+
g.reasoning == null
|
|
174
|
+
? "\u2014"
|
|
175
|
+
: g.reasoning
|
|
176
|
+
? "yes"
|
|
177
|
+
: "no";
|
|
178
|
+
return (
|
|
179
|
+
<tr key={g.model}>
|
|
180
|
+
<td className="repo-model">{g.model}</td>
|
|
181
|
+
<td>{g.provider}</td>
|
|
182
|
+
<td className="num">
|
|
183
|
+
{g.tokensIn.toLocaleString()}
|
|
184
|
+
</td>
|
|
185
|
+
<td className="num">
|
|
186
|
+
{g.tokensOut.toLocaleString()}
|
|
187
|
+
</td>
|
|
188
|
+
<td className="num">
|
|
189
|
+
{freed.toLocaleString()}
|
|
190
|
+
</td>
|
|
191
|
+
<td className="num">
|
|
192
|
+
{collapseNum(g.ctxWindows)}
|
|
193
|
+
</td>
|
|
194
|
+
<td className="num">
|
|
195
|
+
{collapseNum(g.maxTokens)}
|
|
196
|
+
</td>
|
|
197
|
+
<td className="num">{reas}</td>
|
|
198
|
+
<td className="num">
|
|
199
|
+
{g.sessions.toLocaleString()}
|
|
200
|
+
</td>
|
|
201
|
+
<td className="num">
|
|
202
|
+
{g.checkpoints.toLocaleString()}
|
|
203
|
+
</td>
|
|
204
|
+
<td className="num">
|
|
205
|
+
{collapseRate(g.inRates)}
|
|
206
|
+
</td>
|
|
207
|
+
<td className="num">
|
|
208
|
+
{collapseRate(g.outRates)}
|
|
209
|
+
</td>
|
|
210
|
+
<td className="num">{usd}</td>
|
|
211
|
+
<td className="num">{when}</td>
|
|
212
|
+
</tr>
|
|
213
|
+
);
|
|
214
|
+
})}
|
|
215
|
+
</tbody>
|
|
216
|
+
</table>
|
|
217
|
+
</div>
|
|
218
|
+
<p className="legend-note">
|
|
219
|
+
Tokens In = Σ original region tokens dropped by compaction. Tokens
|
|
220
|
+
Out = Σ compacted summary tokens still retained in context. Freed =
|
|
221
|
+
Tokens In − Tokens Out (net context reclaimed). Ctx Window / Max Out
|
|
222
|
+
/ Reas. come from the latest captured model snapshot for each repo.
|
|
223
|
+
</p>
|
|
224
|
+
</div>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
@@ -1,64 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* dashboard-client/src/components/SessionInfo.tsx —
|
|
2
|
+
* dashboard-client/src/components/SessionInfo.tsx — Crew / Agents card.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Shows Active Agents, Current Turn, and Status.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type React from "react";
|
|
8
8
|
|
|
9
9
|
export interface SessionInfoProps {
|
|
10
|
-
/**
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
|
|
14
|
-
/** Total checkpoints across all sessions. */
|
|
15
|
-
checkpointCount: number;
|
|
16
|
-
/** Total tokens saved through compaction. */
|
|
17
|
-
tokensSaved: number;
|
|
18
|
-
/** Dedup hit rate (percent, 0–100). */
|
|
19
|
-
dedupHitRate: number;
|
|
10
|
+
/** Number of active crew agents. */
|
|
11
|
+
activeAgents: number;
|
|
12
|
+
/** Current turn index in the crew round-robin. */
|
|
13
|
+
currentTurn: number;
|
|
20
14
|
}
|
|
21
15
|
|
|
22
|
-
function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
16
|
+
export function SessionInfo(
|
|
17
|
+
props: SessionInfoProps,
|
|
18
|
+
): React.ReactElement {
|
|
19
|
+
const { activeAgents, currentTurn } = props;
|
|
20
|
+
const status =
|
|
21
|
+
activeAgents > 0 ? `▶ ${activeAgents} running` : "idle";
|
|
27
22
|
|
|
28
|
-
export function SessionInfo({
|
|
29
|
-
state,
|
|
30
|
-
persistedThisSession,
|
|
31
|
-
checkpointCount,
|
|
32
|
-
tokensSaved,
|
|
33
|
-
dedupHitRate,
|
|
34
|
-
}: SessionInfoProps): React.ReactElement {
|
|
35
|
-
const badge = state ?? "no session";
|
|
36
23
|
return (
|
|
37
|
-
<div className="card
|
|
38
|
-
<h3>
|
|
39
|
-
<
|
|
40
|
-
<span
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
</span>
|
|
45
|
-
{
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
<div className="stat">
|
|
51
|
-
<span className="stat-label">Checkpoints</span>
|
|
52
|
-
<span className="stat-value">{checkpointCount.toLocaleString()}</span>
|
|
53
|
-
</div>
|
|
54
|
-
<div className="stat stat-highlight">
|
|
55
|
-
<span className="stat-label">Saved</span>
|
|
56
|
-
<span className="stat-value">{fmt(tokensSaved)}</span>
|
|
57
|
-
</div>
|
|
58
|
-
<div className="stat">
|
|
59
|
-
<span className="stat-label">Dedup hit</span>
|
|
60
|
-
<span className="stat-value">{dedupHitRate.toFixed(1)}%</span>
|
|
61
|
-
</div>
|
|
24
|
+
<div className="card crew-card">
|
|
25
|
+
<h3>Crew / Agents</h3>
|
|
26
|
+
<div className="ov-stat-row">
|
|
27
|
+
<span className="ov-stat-label">Active Agents</span>
|
|
28
|
+
<span className="ov-stat-value">{activeAgents}</span>
|
|
29
|
+
</div>
|
|
30
|
+
<div className="ov-stat-row">
|
|
31
|
+
<span className="ov-stat-label">Current Turn</span>
|
|
32
|
+
<span className="ov-stat-value">{currentTurn}</span>
|
|
33
|
+
</div>
|
|
34
|
+
<div className="ov-stat-row">
|
|
35
|
+
<span className="ov-stat-label">Status</span>
|
|
36
|
+
<span className="ov-stat-value">{status}</span>
|
|
62
37
|
</div>
|
|
63
38
|
</div>
|
|
64
39
|
);
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dashboard-client/src/components/SummaryTiles.tsx — aggregate header tiles.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* 4 tiles: Repositories, Total Checkpoints, Total Tokens Saved,
|
|
5
|
+
* Compressed-Original. Matches old dashboard #panel-summary tiles.
|
|
5
6
|
*/
|
|
6
7
|
|
|
7
8
|
import type React from "react";
|
|
@@ -9,14 +10,22 @@ import type React from "react";
|
|
|
9
10
|
export interface SummaryTilesProps {
|
|
10
11
|
/** Total repos in the registry. */
|
|
11
12
|
totalRepos: number;
|
|
12
|
-
/** Repos active within the last 24 hours. */
|
|
13
|
-
activeRepos: number;
|
|
14
13
|
/** Total checkpoints across all repos. */
|
|
15
14
|
totalCheckpoints: number;
|
|
16
15
|
/** Total tokens saved across all repos. */
|
|
17
16
|
totalTokensSaved: number;
|
|
17
|
+
/** Total compressed-original bytes across all repos. */
|
|
18
|
+
compressedOriginalBytes: number;
|
|
18
19
|
}
|
|
19
20
|
|
|
21
|
+
/** Format bytes → MiB/KiB/B (matches html.ts fmtBytesTop). */
|
|
22
|
+
function fmtBytesTop(b: number): string {
|
|
23
|
+
if (b >= 1_048_576) return `${(b / 1_048_576).toFixed(1)} MiB`;
|
|
24
|
+
if (b >= 1024) return `${(b / 1024).toFixed(1)} KiB`;
|
|
25
|
+
return `${b} B`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Format large numbers with K/M suffix. */
|
|
20
29
|
function fmt(n: number): string {
|
|
21
30
|
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
22
31
|
if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;
|
|
@@ -25,28 +34,28 @@ function fmt(n: number): string {
|
|
|
25
34
|
|
|
26
35
|
export function SummaryTiles({
|
|
27
36
|
totalRepos,
|
|
28
|
-
activeRepos,
|
|
29
37
|
totalCheckpoints,
|
|
30
38
|
totalTokensSaved,
|
|
39
|
+
compressedOriginalBytes,
|
|
31
40
|
}: SummaryTilesProps): React.ReactElement {
|
|
32
41
|
return (
|
|
33
42
|
<div className="summary-tiles">
|
|
34
43
|
<div className="tile">
|
|
35
|
-
<span className="tile-label">
|
|
44
|
+
<span className="tile-label">Repositories</span>
|
|
36
45
|
<span className="tile-value">{totalRepos.toLocaleString()}</span>
|
|
37
46
|
</div>
|
|
38
47
|
<div className="tile">
|
|
39
|
-
<span className="tile-label">
|
|
40
|
-
<span className="tile-value">{activeRepos.toLocaleString()}</span>
|
|
41
|
-
</div>
|
|
42
|
-
<div className="tile">
|
|
43
|
-
<span className="tile-label">Checkpoints</span>
|
|
48
|
+
<span className="tile-label">Total Checkpoints</span>
|
|
44
49
|
<span className="tile-value">{totalCheckpoints.toLocaleString()}</span>
|
|
45
50
|
</div>
|
|
46
51
|
<div className="tile tile-highlight">
|
|
47
|
-
<span className="tile-label">Tokens
|
|
52
|
+
<span className="tile-label">Total Tokens Saved</span>
|
|
48
53
|
<span className="tile-value">{fmt(totalTokensSaved)}</span>
|
|
49
54
|
</div>
|
|
55
|
+
<div className="tile">
|
|
56
|
+
<span className="tile-label">Compressed-Original</span>
|
|
57
|
+
<span className="tile-value">{fmtBytesTop(compressedOriginalBytes)}</span>
|
|
58
|
+
</div>
|
|
50
59
|
</div>
|
|
51
60
|
);
|
|
52
61
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-client/src/components/TimeSavedCard.tsx — Time Saved (est.) card.
|
|
3
|
+
*
|
|
4
|
+
* 4 fields: Compact (session), Compact (total),
|
|
5
|
+
* Cache Hit (session), Cache Hit (total).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type React from "react";
|
|
9
|
+
import { fmtSec } from "../utils/format";
|
|
10
|
+
|
|
11
|
+
export interface TimeSavedCardProps {
|
|
12
|
+
/** Seconds saved by compaction this session. */
|
|
13
|
+
compactSessionSec: number;
|
|
14
|
+
/** Total seconds saved by compaction. */
|
|
15
|
+
compactTotalSec: number;
|
|
16
|
+
/** Seconds saved by cache hits this session. */
|
|
17
|
+
cacheHitSessionSec: number;
|
|
18
|
+
/** Total seconds saved by cache hits. */
|
|
19
|
+
cacheHitTotalSec: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function StatRow({
|
|
23
|
+
label,
|
|
24
|
+
value,
|
|
25
|
+
}: {
|
|
26
|
+
label: string;
|
|
27
|
+
value: string;
|
|
28
|
+
}): React.ReactElement {
|
|
29
|
+
return (
|
|
30
|
+
<div className="ov-stat-row">
|
|
31
|
+
<span className="ov-stat-label">{label}</span>
|
|
32
|
+
<span className="ov-stat-value">{value}</span>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function TimeSavedCard(
|
|
38
|
+
props: TimeSavedCardProps,
|
|
39
|
+
): React.ReactElement {
|
|
40
|
+
return (
|
|
41
|
+
<div className="card time-saved-card">
|
|
42
|
+
<h3>⏱ Time Saved (est.)</h3>
|
|
43
|
+
<StatRow
|
|
44
|
+
label="Compact (session)"
|
|
45
|
+
value={fmtSec(props.compactSessionSec)}
|
|
46
|
+
/>
|
|
47
|
+
<StatRow
|
|
48
|
+
label="Compact (total)"
|
|
49
|
+
value={fmtSec(props.compactTotalSec)}
|
|
50
|
+
/>
|
|
51
|
+
<StatRow
|
|
52
|
+
label="Cache Hit (session)"
|
|
53
|
+
value={fmtSec(props.cacheHitSessionSec)}
|
|
54
|
+
/>
|
|
55
|
+
<StatRow
|
|
56
|
+
label="Cache Hit (total)"
|
|
57
|
+
value={fmtSec(props.cacheHitTotalSec)}
|
|
58
|
+
/>
|
|
59
|
+
</div>
|
|
60
|
+
);
|
|
61
|
+
}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* dashboard-client/src/components/TriggerStatus.tsx — trigger armed/ready status.
|
|
3
3
|
*
|
|
4
|
-
* Two bullets (
|
|
4
|
+
* Two bullets (Armed, Ready) + state text.
|
|
5
|
+
* Ready bullet shows "na" (yellow) when not armed.
|
|
6
|
+
* State text: ready → "THRESHOLD EXCEEDED — compacting next event",
|
|
7
|
+
* armed → "past fast gate — monitoring token count",
|
|
8
|
+
* idle → "idle — below fast gate".
|
|
5
9
|
*/
|
|
6
10
|
|
|
7
11
|
import type React from "react";
|
|
@@ -19,15 +23,19 @@ export interface TriggerStatusProps {
|
|
|
19
23
|
fastGatePct: number;
|
|
20
24
|
}
|
|
21
25
|
|
|
26
|
+
type BulletState = "on" | "off" | "na";
|
|
27
|
+
|
|
22
28
|
function Bullet({
|
|
23
|
-
|
|
29
|
+
state,
|
|
24
30
|
label,
|
|
25
31
|
}: {
|
|
26
|
-
|
|
32
|
+
state: BulletState;
|
|
27
33
|
label: string;
|
|
28
34
|
}): React.ReactElement {
|
|
35
|
+
const cls =
|
|
36
|
+
state === "on" ? "bullet-on" : state === "na" ? "bullet-na" : "bullet-off";
|
|
29
37
|
return (
|
|
30
|
-
<div className={`bullet ${
|
|
38
|
+
<div className={`bullet ${cls}`}>
|
|
31
39
|
<span className="bullet-dot" aria-hidden="true" />
|
|
32
40
|
<span className="bullet-label">{label}</span>
|
|
33
41
|
</div>
|
|
@@ -37,26 +45,30 @@ function Bullet({
|
|
|
37
45
|
export function TriggerStatus({
|
|
38
46
|
armed,
|
|
39
47
|
ready,
|
|
40
|
-
currentTokens,
|
|
41
|
-
thresholdTokens,
|
|
42
|
-
fastGatePct,
|
|
43
48
|
}: TriggerStatusProps): React.ReactElement {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
// tr-armed: on if armed, off if not
|
|
50
|
+
// tr-ready: on if ready, na (yellow) if not armed, off if armed but not ready
|
|
51
|
+
const armedState: BulletState = armed ? "on" : "off";
|
|
52
|
+
const readyState: BulletState = ready
|
|
53
|
+
? "on"
|
|
54
|
+
: !armed
|
|
55
|
+
? "na"
|
|
56
|
+
: "off";
|
|
57
|
+
|
|
58
|
+
const stateText = ready
|
|
59
|
+
? "THRESHOLD EXCEEDED — compacting next event"
|
|
60
|
+
: armed
|
|
61
|
+
? "past fast gate — monitoring token count"
|
|
62
|
+
: "idle — below fast gate";
|
|
63
|
+
|
|
48
64
|
return (
|
|
49
65
|
<div className="card trigger-status">
|
|
50
|
-
<h3>Trigger</h3>
|
|
66
|
+
<h3>Trigger Status</h3>
|
|
51
67
|
<div className="bullet-row">
|
|
52
|
-
<Bullet
|
|
53
|
-
<Bullet
|
|
68
|
+
<Bullet state={armedState} label="Armed" />
|
|
69
|
+
<Bullet state={readyState} label="Ready" />
|
|
54
70
|
</div>
|
|
55
|
-
<p className="trigger-
|
|
56
|
-
Threshold: {thresholdTokens.toLocaleString()} tokens
|
|
57
|
-
</p>
|
|
58
|
-
<p className="trigger-detail">Current: {cur} tokens</p>
|
|
59
|
-
<p className="trigger-detail">Fast gate: {fastGatePct}%</p>
|
|
71
|
+
<p className="trigger-state-text">{stateText}</p>
|
|
60
72
|
</div>
|
|
61
73
|
);
|
|
62
74
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* dashboard-client/src/components/VectorStoreCard.tsx — Vector Store (session) card.
|
|
3
|
+
*
|
|
4
|
+
* 9 fields: Checkpoints, Original (dropped), Kept (summaries), Freed,
|
|
5
|
+
* Injected, Recall Relevance %, Storage Dedup %, Collapsed, Last ID.
|
|
6
|
+
* Plus a compression meter bar (green ≥90%, yellow ≥60%, red <60%).
|
|
7
|
+
*
|
|
8
|
+
* NOTE: dedupHitRate, storageDedupRate, compressionPct, dedupPct are
|
|
9
|
+
* 0–1 fractions at runtime (despite contract saying 0–100).
|
|
10
|
+
* Tooltips copied verbatim from html.ts.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type React from "react";
|
|
14
|
+
import { fmtPctFromFraction } from "../utils/format";
|
|
15
|
+
|
|
16
|
+
export interface VectorStoreCardProps {
|
|
17
|
+
checkpointCount: number;
|
|
18
|
+
/** Original tokens dropped into compaction (session). */
|
|
19
|
+
tokensIn: number;
|
|
20
|
+
/** Kept summary tokens (session). */
|
|
21
|
+
tokensOut: number;
|
|
22
|
+
/** Tokens freed = dropped − kept (session). */
|
|
23
|
+
tokensFreed: number;
|
|
24
|
+
/** Recall injection count. */
|
|
25
|
+
injectedCount: number;
|
|
26
|
+
/** Recall relevance — 0–1 fraction. */
|
|
27
|
+
dedupHitRate: number;
|
|
28
|
+
/** Storage dedup rate — 0–1 fraction. */
|
|
29
|
+
storageDedupRate: number;
|
|
30
|
+
/** Duplicate chunks collapsed. */
|
|
31
|
+
dedupCollapsed: number;
|
|
32
|
+
/** Last checkpoint ID or null. */
|
|
33
|
+
lastCheckpointId: string | null;
|
|
34
|
+
/** Session compression ratio — 0–1 fraction. */
|
|
35
|
+
compressionPct: number;
|
|
36
|
+
/** Session dedup contribution — 0–1 fraction. */
|
|
37
|
+
dedupPct: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** Compression meter colour class (inverse of context: high = good). */
|
|
41
|
+
function compressClass(sp: number): string {
|
|
42
|
+
if (sp >= 0.9) return "meter-green";
|
|
43
|
+
if (sp >= 0.6) return "meter-yellow";
|
|
44
|
+
return "meter-red";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Stat row with optional tooltip. */
|
|
48
|
+
function StatRow({
|
|
49
|
+
label,
|
|
50
|
+
value,
|
|
51
|
+
title,
|
|
52
|
+
}: {
|
|
53
|
+
label: string;
|
|
54
|
+
value: string | number;
|
|
55
|
+
title?: string;
|
|
56
|
+
}): React.ReactElement {
|
|
57
|
+
return (
|
|
58
|
+
<div className="ov-stat-row">
|
|
59
|
+
<span className="ov-stat-label" title={title}>
|
|
60
|
+
{label}
|
|
61
|
+
</span>
|
|
62
|
+
<span className="ov-stat-value">{value}</span>
|
|
63
|
+
</div>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function VectorStoreCard(
|
|
68
|
+
props: VectorStoreCardProps,
|
|
69
|
+
): React.ReactElement {
|
|
70
|
+
const sp = props.compressionPct;
|
|
71
|
+
const barCls = compressClass(sp);
|
|
72
|
+
const barWidth = Math.max(sp * 100, 0.5);
|
|
73
|
+
const compressSub = `${fmtPctFromFraction(sp)} tokens saved · dedup: ${fmtPctFromFraction(props.dedupPct)}`;
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div className="card vector-store-card">
|
|
77
|
+
<h3>Vector Store (session)</h3>
|
|
78
|
+
<StatRow
|
|
79
|
+
label="Checkpoints"
|
|
80
|
+
value={props.checkpointCount.toLocaleString()}
|
|
81
|
+
title="A saved summary of a chunk of your conversation that was compacted to free up space."
|
|
82
|
+
/>
|
|
83
|
+
<StatRow
|
|
84
|
+
label="Original (dropped)"
|
|
85
|
+
value={props.tokensIn.toLocaleString()}
|
|
86
|
+
title="Total size of the original conversation text dropped into compaction this session, including redundant regions skipped by dedup. This is the 'in'."
|
|
87
|
+
/>
|
|
88
|
+
<StatRow
|
|
89
|
+
label="Kept (summaries)"
|
|
90
|
+
value={props.tokensOut.toLocaleString()}
|
|
91
|
+
title="Compact summaries we are currently holding as 'memory' for this session (the 'out'). Smaller is better."
|
|
92
|
+
/>
|
|
93
|
+
<StatRow
|
|
94
|
+
label="Freed"
|
|
95
|
+
value={props.tokensFreed.toLocaleString()}
|
|
96
|
+
title="Conversation space freed = dropped − kept (the 'saved')."
|
|
97
|
+
/>
|
|
98
|
+
<StatRow
|
|
99
|
+
label="Injected"
|
|
100
|
+
value={props.injectedCount}
|
|
101
|
+
title="How many times old context was automatically brought back into the conversation because it was relevant to what you were doing."
|
|
102
|
+
/>
|
|
103
|
+
<StatRow
|
|
104
|
+
label="Recall Relevance"
|
|
105
|
+
value={fmtPctFromFraction(props.dedupHitRate)}
|
|
106
|
+
title="Of the times we recalled old context, how often it was actually on-topic."
|
|
107
|
+
/>
|
|
108
|
+
<StatRow
|
|
109
|
+
label="Storage Dedup"
|
|
110
|
+
value={fmtPctFromFraction(props.storageDedupRate)}
|
|
111
|
+
title="How often new content matched something we already had, so we skipped storing a duplicate copy. Higher = less wasted space."
|
|
112
|
+
/>
|
|
113
|
+
<StatRow
|
|
114
|
+
label="Collapsed"
|
|
115
|
+
value={props.dedupCollapsed}
|
|
116
|
+
title="How many duplicate chunks we collapsed into one instead of storing separately."
|
|
117
|
+
/>
|
|
118
|
+
<StatRow
|
|
119
|
+
label="Last ID"
|
|
120
|
+
value={props.lastCheckpointId ?? "—"}
|
|
121
|
+
title="The ID of the most recent saved checkpoint."
|
|
122
|
+
/>
|
|
123
|
+
<div className="ov-compression-meter">
|
|
124
|
+
<div className="meter-track">
|
|
125
|
+
<div
|
|
126
|
+
className={`meter-fill ${barCls}`}
|
|
127
|
+
style={{ width: `${barWidth}%` }}
|
|
128
|
+
/>
|
|
129
|
+
</div>
|
|
130
|
+
<span className="meter-sub">{compressSub}</span>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
@@ -10,6 +10,11 @@ import App from "./App";
|
|
|
10
10
|
import "./styles/base.css";
|
|
11
11
|
import "./styles/overview-events.css";
|
|
12
12
|
import "./styles/repos-metrics.css";
|
|
13
|
+
import "./styles/repos-extra.css";
|
|
14
|
+
import "./styles/overview-extra.css";
|
|
15
|
+
import "./styles/config.css";
|
|
16
|
+
import "./styles/metrics-extra.css";
|
|
17
|
+
import "./styles/game-achievements.css";
|
|
13
18
|
|
|
14
19
|
const rootEl = document.getElementById("root");
|
|
15
20
|
if (!rootEl) {
|