pi-mega-compact 0.9.2 → 0.11.0

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.
Files changed (143) hide show
  1. package/README.md +3 -2
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +95 -47
  3. package/dist/extensions/dashboard-server/api-contracts/index.js +1 -1
  4. package/dist/extensions/dashboard-server/api-contracts/turns.js +10 -0
  5. package/dist/extensions/dashboard-server/api-contracts.test.js +3 -2
  6. package/dist/extensions/dashboard-server/routes-topics.js +87 -0
  7. package/dist/extensions/dashboard-server/routes-turns.js +264 -0
  8. package/dist/extensions/dashboard-server/routes.js +3 -1
  9. package/dist/extensions/dashboard-server/server.js +6 -2
  10. package/dist/extensions/mega-compact.js +10 -6
  11. package/dist/extensions/mega-config.js +4 -0
  12. package/dist/extensions/mega-events/agent-handlers.js +62 -49
  13. package/dist/extensions/mega-events/context-handler.js +48 -2
  14. package/dist/extensions/mega-events/session-handlers.js +25 -1
  15. package/dist/extensions/mega-metrics-cmds.js +90 -0
  16. package/dist/extensions/mega-pipeline/recall.js +47 -17
  17. package/dist/extensions/mega-topics-cmds.js +111 -0
  18. package/dist/extensions/mega-turn-store.js +110 -0
  19. package/dist/extensions/mega-turn-store.test.js +68 -0
  20. package/dist/src/config/turns.js +48 -0
  21. package/dist/src/fork.js +33 -0
  22. package/dist/src/fork.test.js +81 -0
  23. package/dist/src/intent.js +51 -0
  24. package/dist/src/intent.test.js +78 -0
  25. package/dist/src/metrics/index.js +4 -0
  26. package/dist/src/metrics/turns.js +118 -0
  27. package/dist/src/metrics/turns.test.js +152 -0
  28. package/dist/src/store/sqlite/raw-transcript.js +5 -3
  29. package/dist/src/store/sqlite.dbmirror.test.js +9 -0
  30. package/dist/src/store/turns/connection.js +123 -0
  31. package/dist/src/store/turns/contract-compliance.test.js +428 -0
  32. package/dist/src/store/turns/index.js +31 -0
  33. package/dist/src/store/turns/memory-store.js +357 -0
  34. package/dist/src/store/turns/memory-store.test.js +9 -0
  35. package/dist/src/store/turns/migrations.js +178 -0
  36. package/dist/src/store/turns/migrations.test.js +138 -0
  37. package/dist/src/store/turns/schema.js +115 -0
  38. package/dist/src/store/turns/sqlite-store.js +455 -0
  39. package/dist/src/store/turns/sqlite-store.test.js +144 -0
  40. package/dist/src/store/turns/types.js +16 -0
  41. package/dist/src/topics/cluster.js +141 -0
  42. package/dist/src/topics/cluster.test.js +150 -0
  43. package/dist/src/topics/index.js +6 -0
  44. package/dist/src/topics/kselection.js +142 -0
  45. package/dist/src/topics/labels.js +56 -0
  46. package/dist/src/topics/store.js +119 -0
  47. package/dist/src/topics/store.test.js +117 -0
  48. package/dist/src/topics/types.js +8 -0
  49. package/dist/src/wiki.js +133 -0
  50. package/dist/src/wiki.test.js +171 -0
  51. package/extensions/dashboard-client/dist/assets/{AchievementTiles-QPo46Pwg.js → AchievementTiles-DZp_xQOW.js} +2 -2
  52. package/extensions/dashboard-client/dist/assets/{AchievementTiles-QPo46Pwg.js.map → AchievementTiles-DZp_xQOW.js.map} +1 -1
  53. package/extensions/dashboard-client/dist/assets/{AchievementsTab-BDJxRXRY.js → AchievementsTab-BzFHpAHM.js} +2 -2
  54. package/extensions/dashboard-client/dist/assets/{AchievementsTab-BDJxRXRY.js.map → AchievementsTab-BzFHpAHM.js.map} +1 -1
  55. package/extensions/dashboard-client/dist/assets/{CacheTab-CUMqXQjd.js → CacheTab-DEQbTq2T.js} +2 -2
  56. package/extensions/dashboard-client/dist/assets/{CacheTab-CUMqXQjd.js.map → CacheTab-DEQbTq2T.js.map} +1 -1
  57. package/extensions/dashboard-client/dist/assets/{ConfigTab-j1dRzurG.js → ConfigTab-DQ4FG33J.js} +2 -2
  58. package/extensions/dashboard-client/dist/assets/{ConfigTab-j1dRzurG.js.map → ConfigTab-DQ4FG33J.js.map} +1 -1
  59. package/extensions/dashboard-client/dist/assets/{EventsTab-CMglXK4p.js → EventsTab-D5HoEVYo.js} +2 -2
  60. package/extensions/dashboard-client/dist/assets/{EventsTab-CMglXK4p.js.map → EventsTab-D5HoEVYo.js.map} +1 -1
  61. package/extensions/dashboard-client/dist/assets/{GameTab-fpaDoyxi.js → GameTab-Jzsc4yeY.js} +2 -2
  62. package/extensions/dashboard-client/dist/assets/{GameTab-fpaDoyxi.js.map → GameTab-Jzsc4yeY.js.map} +1 -1
  63. package/extensions/dashboard-client/dist/assets/{MetricsTab-CWG2crG_.js → MetricsTab-D_XnsEYX.js} +2 -2
  64. package/extensions/dashboard-client/dist/assets/{MetricsTab-CWG2crG_.js.map → MetricsTab-D_XnsEYX.js.map} +1 -1
  65. package/extensions/dashboard-client/dist/assets/{OverviewTab-BaV2D2nf.js → OverviewTab-BMREvAth.js} +2 -2
  66. package/extensions/dashboard-client/dist/assets/{OverviewTab-BaV2D2nf.js.map → OverviewTab-BMREvAth.js.map} +1 -1
  67. package/extensions/dashboard-client/dist/assets/{ReposTab-C-0kuZ_0.js → ReposTab-DuyhOktG.js} +2 -2
  68. package/extensions/dashboard-client/dist/assets/{ReposTab-C-0kuZ_0.js.map → ReposTab-DuyhOktG.js.map} +1 -1
  69. package/extensions/dashboard-client/dist/assets/{SessionsTab-CSYhddCA.js → SessionsTab-mz_vz8i2.js} +2 -2
  70. package/extensions/dashboard-client/dist/assets/{SessionsTab-CSYhddCA.js.map → SessionsTab-mz_vz8i2.js.map} +1 -1
  71. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Dy4KRjSM.js → TimeSavedCard-B8AIjNTY.js} +2 -2
  72. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-Dy4KRjSM.js.map → TimeSavedCard-B8AIjNTY.js.map} +1 -1
  73. package/extensions/dashboard-client/dist/assets/TopicsTab-DKuct4oD.js +2 -0
  74. package/extensions/dashboard-client/dist/assets/TopicsTab-DKuct4oD.js.map +1 -0
  75. package/extensions/dashboard-client/dist/assets/TurnsTab-11MGLxY8.js +2 -0
  76. package/extensions/dashboard-client/dist/assets/TurnsTab-11MGLxY8.js.map +1 -0
  77. package/extensions/dashboard-client/dist/assets/{index-D_WtU2TV.js → index-CqLN7STl.js} +10 -10
  78. package/extensions/dashboard-client/dist/assets/index-CqLN7STl.js.map +1 -0
  79. package/extensions/dashboard-client/dist/assets/{index-og3ghxyY.css → index-gn66lYD2.css} +1 -1
  80. package/extensions/dashboard-client/dist/assets/{useSSE-C9yVJlGP.js → useSSE-CXrQSbVY.js} +2 -2
  81. package/extensions/dashboard-client/dist/assets/{useSSE-C9yVJlGP.js.map → useSSE-CXrQSbVY.js.map} +1 -1
  82. package/extensions/dashboard-client/dist/index.html +2 -2
  83. package/extensions/dashboard-client/src/App.tsx +10 -2
  84. package/extensions/dashboard-client/src/api/client.ts +90 -1
  85. package/extensions/dashboard-client/src/main.tsx +1 -0
  86. package/extensions/dashboard-client/src/styles/turns.css +142 -0
  87. package/extensions/dashboard-client/src/tabs/TopicsTab.tsx +186 -0
  88. package/extensions/dashboard-client/src/tabs/TurnsTab.tsx +336 -0
  89. package/extensions/dashboard-server/api-contracts/endpoints.ts +394 -291
  90. package/extensions/dashboard-server/api-contracts/game-types.ts +141 -88
  91. package/extensions/dashboard-server/api-contracts/index.ts +153 -133
  92. package/extensions/dashboard-server/api-contracts/turns.ts +114 -0
  93. package/extensions/dashboard-server/api-contracts.test.ts +920 -919
  94. package/extensions/dashboard-server/routes-topics.ts +119 -0
  95. package/extensions/dashboard-server/routes-turns.ts +305 -0
  96. package/extensions/dashboard-server/routes.ts +8 -1
  97. package/extensions/dashboard-server/server.ts +6 -2
  98. package/extensions/mega-compact.ts +75 -59
  99. package/extensions/mega-config.ts +232 -220
  100. package/extensions/mega-events/agent-handlers.ts +194 -151
  101. package/extensions/mega-events/context-handler.ts +50 -1
  102. package/extensions/mega-events/session-handlers.ts +26 -5
  103. package/extensions/mega-metrics-cmds.ts +114 -0
  104. package/extensions/mega-pipeline/recall.ts +215 -152
  105. package/extensions/mega-topics-cmds.ts +151 -0
  106. package/extensions/mega-turn-store.test.ts +108 -0
  107. package/extensions/mega-turn-store.ts +169 -0
  108. package/package.json +3 -1
  109. package/src/config/turns.ts +69 -0
  110. package/src/fork.test.ts +94 -0
  111. package/src/fork.ts +78 -0
  112. package/src/intent.test.ts +87 -0
  113. package/src/intent.ts +115 -0
  114. package/src/metrics/index.ts +9 -0
  115. package/src/metrics/turns.test.ts +165 -0
  116. package/src/metrics/turns.ts +201 -0
  117. package/src/store/sqlite/raw-transcript.ts +9 -3
  118. package/src/store/sqlite.dbmirror.test.ts +10 -0
  119. package/src/store/turns/connection.ts +137 -0
  120. package/src/store/turns/contract-compliance.test.ts +562 -0
  121. package/src/store/turns/index.ts +65 -0
  122. package/src/store/turns/memory-store.test.ts +15 -0
  123. package/src/store/turns/memory-store.ts +469 -0
  124. package/src/store/turns/migrations.test.ts +161 -0
  125. package/src/store/turns/migrations.ts +203 -0
  126. package/src/store/turns/schema.ts +158 -0
  127. package/src/store/turns/sqlite-store.test.ts +161 -0
  128. package/src/store/turns/sqlite-store.ts +656 -0
  129. package/src/store/turns/types.ts +181 -0
  130. package/src/topics/cluster.test.ts +176 -0
  131. package/src/topics/cluster.ts +191 -0
  132. package/src/topics/index.ts +18 -0
  133. package/src/topics/kselection.ts +182 -0
  134. package/src/topics/labels.ts +67 -0
  135. package/src/topics/store.test.ts +132 -0
  136. package/src/topics/store.ts +208 -0
  137. package/src/topics/types.ts +64 -0
  138. package/src/wiki.test.ts +217 -0
  139. package/src/wiki.ts +198 -0
  140. package/dist/extensions/openclaw-mega-compact.js +0 -291
  141. package/dist/src/minilm.js +0 -92
  142. package/dist/src/wordpiece.js +0 -129
  143. package/extensions/dashboard-client/dist/assets/index-D_WtU2TV.js.map +0 -1
@@ -0,0 +1,336 @@
1
+ /**
2
+ * dashboard-client/src/tabs/TurnsTab.tsx — Turn-by-turn memory tracking + recall (S52).
3
+ *
4
+ * Fetches /api/turns (conversation list), expands the active conversation into
5
+ * per-turn detail (/api/turns/conversation/:id), and renders:
6
+ * - Conversation summary list (turn count, recall total, epochs, last turn).
7
+ * - Per-turn rows: turn index, role, ctx tokens/percent + pressure band,
8
+ * epoch id, and the injected-checkpoint recall set (the memory recalled
9
+ * at each turn, with score + source).
10
+ * - Pending rewind intents (S52A) + Fork action (S50C primitive).
11
+ *
12
+ * Read-mostly via /api/turns; fork/intent/prune via POST. No absolute URLs
13
+ * (PREVENT-PI-004: loopback-only, same-origin static bundle).
14
+ */
15
+
16
+ import type React from "react";
17
+ import { useCallback, useState } from "react";
18
+ import { useApi } from "../hooks/useApi";
19
+ import {
20
+ fetchTurns,
21
+ fetchConversationTurns,
22
+ fetchTurnIntents,
23
+ postFork,
24
+ postTurnIntent,
25
+ } from "../api/client";
26
+ import type {
27
+ TurnsResponse,
28
+ ConversationTurnsResponse,
29
+ RewindIntentsResponse,
30
+ TurnRow,
31
+ ConversationSummary,
32
+ } from "@contracts";
33
+
34
+ function fmtTs(ms: number): string {
35
+ if (!ms) return "—";
36
+ return new Date(ms).toLocaleString();
37
+ }
38
+
39
+ function bandClass(band: TurnRow["pressureBand"]): string {
40
+ if (band === "green") return "band band-green";
41
+ if (band === "yellow") return "band band-yellow";
42
+ if (band === "red") return "band band-red";
43
+ return "band";
44
+ }
45
+
46
+ function sourceLabel(s: TurnRow["recall"][number]["source"]): string {
47
+ if (s === "checkpoint") return "ckpt";
48
+ if (s === "cluster_summary") return "raptor";
49
+ return "mem";
50
+ }
51
+
52
+ export default function TurnsTab(): React.ReactElement {
53
+ const {
54
+ data: turns,
55
+ loading,
56
+ error,
57
+ } = useApi<TurnsResponse>(
58
+ useCallback(() => fetchTurns(), []),
59
+ {
60
+ pollInterval: 10_000,
61
+ },
62
+ );
63
+ const { data: intents } = useApi<RewindIntentsResponse>(
64
+ useCallback(() => fetchTurnIntents(), []),
65
+ { pollInterval: 5_000 },
66
+ );
67
+ const [expanded, setExpanded] = useState<string | null>(null);
68
+ const [detail, setDetail] = useState<ConversationTurnsResponse | null>(null);
69
+ const [detailLoading, setDetailLoading] = useState(false);
70
+ const [busy, setBusy] = useState<string | null>(null);
71
+ const [notice, setNotice] = useState<string | null>(null);
72
+
73
+ const expand = useCallback(
74
+ async (conversationId: string) => {
75
+ if (expanded === conversationId) {
76
+ setExpanded(null);
77
+ setDetail(null);
78
+ return;
79
+ }
80
+ setExpanded(conversationId);
81
+ setDetailLoading(true);
82
+ setDetail(null);
83
+ try {
84
+ const d = await fetchConversationTurns(conversationId);
85
+ setDetail(d);
86
+ } finally {
87
+ setDetailLoading(false);
88
+ }
89
+ },
90
+ [expanded],
91
+ );
92
+
93
+ const onFork = useCallback(
94
+ async (conversationId: string, turnIndex: number) => {
95
+ setBusy(`fork:${conversationId}:${turnIndex}`);
96
+ setNotice(null);
97
+ try {
98
+ const out = await postFork(conversationId, turnIndex);
99
+ setNotice(
100
+ `Forked → ${out.childConversationId} (${out.recalledCount} recalled)`,
101
+ );
102
+ } catch (e) {
103
+ setNotice(`Fork failed: ${(e as Error).message}`);
104
+ } finally {
105
+ setBusy(null);
106
+ }
107
+ },
108
+ [],
109
+ );
110
+
111
+ const onRewind = useCallback(
112
+ async (conversationId: string, turnIndex: number) => {
113
+ setBusy(`rewind:${conversationId}:${turnIndex}`);
114
+ setNotice(null);
115
+ try {
116
+ await postTurnIntent(conversationId, turnIndex);
117
+ setNotice(`Rewind intent queued for turn ${turnIndex}`);
118
+ } catch (e) {
119
+ setNotice(`Rewind failed: ${(e as Error).message}`);
120
+ } finally {
121
+ setBusy(null);
122
+ }
123
+ },
124
+ [],
125
+ );
126
+
127
+ if (error && !turns) {
128
+ return <div className="tab-stub">Error loading turns: {error.message}</div>;
129
+ }
130
+ if (loading && !turns) {
131
+ return <div className="tab-stub">Loading turns…</div>;
132
+ }
133
+ if (!turns || turns.conversations.length === 0) {
134
+ return (
135
+ <div className="tab-stub">
136
+ <h3>Turn-by-turn memory</h3>
137
+ <p>
138
+ No turns recorded yet. Per-turn tracking starts when{" "}
139
+ <code>MEGACOMPACT_TURNS_DB=1</code> and the session runs through a
140
+ compaction. Each turn records its context metrics + the checkpoints
141
+ recalled into it.
142
+ </p>
143
+ </div>
144
+ );
145
+ }
146
+
147
+ return (
148
+ <div className="turns-tab">
149
+ <h3>Turn-by-turn memory tracking + recall</h3>
150
+ {notice && <div className="turns-notice">{notice}</div>}
151
+
152
+ {intents && intents.intents.length > 0 && (
153
+ <section className="turns-intents">
154
+ <h4>Pending rewind intents ({intents.intents.length})</h4>
155
+ <ul>
156
+ {intents.intents.map((i) => (
157
+ <li key={i.id}>
158
+ {fmtTs(i.createdAt)} — rewind <code>{i.conversationId}</code> to
159
+ turn {i.targetTurnIndex}
160
+ </li>
161
+ ))}
162
+ </ul>
163
+ </section>
164
+ )}
165
+
166
+ <section className="turns-conv-list">
167
+ <h4>Conversations ({turns.conversations.length})</h4>
168
+ <table className="turns-table">
169
+ <thead>
170
+ <tr>
171
+ <th>Conversation</th>
172
+ <th>Turns</th>
173
+ <th>Recall</th>
174
+ <th>Epochs</th>
175
+ <th>Avg ctx%</th>
176
+ <th>Last turn</th>
177
+ <th></th>
178
+ </tr>
179
+ </thead>
180
+ <tbody>
181
+ {turns.conversations.map((c: ConversationSummary) => (
182
+ <ConversationRow
183
+ key={c.conversationId}
184
+ c={c}
185
+ active={turns.activeConversationId === c.conversationId}
186
+ expanded={expanded === c.conversationId}
187
+ onExpand={() => expand(c.conversationId)}
188
+ />
189
+ ))}
190
+ </tbody>
191
+ </table>
192
+ </section>
193
+
194
+ {expanded && (
195
+ <section className="turns-detail">
196
+ <h4>
197
+ Turns in <code>{expanded}</code>
198
+ </h4>
199
+ {detailLoading ? (
200
+ <div className="tab-stub">Loading turns…</div>
201
+ ) : detail ? (
202
+ <TurnDetail
203
+ detail={detail}
204
+ busy={busy}
205
+ onFork={onFork}
206
+ onRewind={onRewind}
207
+ />
208
+ ) : (
209
+ <div className="tab-stub">No detail.</div>
210
+ )}
211
+ </section>
212
+ )}
213
+ </div>
214
+ );
215
+ }
216
+
217
+ function ConversationRow({
218
+ c,
219
+ active,
220
+ expanded,
221
+ onExpand,
222
+ }: {
223
+ c: ConversationSummary;
224
+ active: boolean;
225
+ expanded: boolean;
226
+ onExpand: () => void;
227
+ }): React.ReactElement {
228
+ return (
229
+ <>
230
+ <tr
231
+ className={active ? "turns-row active" : "turns-row"}
232
+ onClick={onExpand}
233
+ style={{ cursor: "pointer" }}
234
+ >
235
+ <td>
236
+ {expanded ? "▾" : "▸"} <code>{c.conversationId}</code>
237
+ {active && <span className="pill">active</span>}
238
+ </td>
239
+ <td>{c.turnCount}</td>
240
+ <td>{c.totalRecall}</td>
241
+ <td>{c.epochCount}</td>
242
+ <td>{(c.avgCtxPercent * 100).toFixed(0)}%</td>
243
+ <td>{fmtTs(c.lastTurnAt)}</td>
244
+ <td />
245
+ </tr>
246
+ </>
247
+ );
248
+ }
249
+
250
+ function TurnDetail({
251
+ detail,
252
+ busy,
253
+ onFork,
254
+ onRewind,
255
+ }: {
256
+ detail: ConversationTurnsResponse;
257
+ busy: string | null;
258
+ onFork: (conversationId: string, turnIndex: number) => void;
259
+ onRewind: (conversationId: string, turnIndex: number) => void;
260
+ }): React.ReactElement {
261
+ return (
262
+ <table className="turns-detail-table">
263
+ <thead>
264
+ <tr>
265
+ <th>#</th>
266
+ <th>Role</th>
267
+ <th>Ctx</th>
268
+ <th>Band</th>
269
+ <th>Epoch</th>
270
+ <th>Recalled checkpoints (memory recall)</th>
271
+ <th>Ended</th>
272
+ <th>Actions</th>
273
+ </tr>
274
+ </thead>
275
+ <tbody>
276
+ {detail.turns.map((t) => (
277
+ <tr key={`${t.conversationId}:${t.turnIndex}`}>
278
+ <td>{t.turnIndex}</td>
279
+ <td>{t.role}</td>
280
+ <td>
281
+ {t.ctxTokens ?? "—"}
282
+ {t.ctxPercent != null && (
283
+ <span className="muted">
284
+ {" "}
285
+ · {(t.ctxPercent * 100).toFixed(0)}%
286
+ </span>
287
+ )}
288
+ </td>
289
+ <td>
290
+ <span className={bandClass(t.pressureBand)}>
291
+ {t.pressureBand ?? "—"}
292
+ </span>
293
+ </td>
294
+ <td>{t.epochId ? <code>{t.epochId.slice(0, 8)}</code> : "—"}</td>
295
+ <td className="recall-cell">
296
+ {t.recall.length === 0 ? (
297
+ <span className="muted">—</span>
298
+ ) : (
299
+ <ul className="recall-list">
300
+ {t.recall.map((r) => (
301
+ <li key={r.checkpointId}>
302
+ <code>{r.checkpointId.slice(0, 12)}</code>{" "}
303
+ <span className="muted">
304
+ {sourceLabel(r.source)} · {r.score.toFixed(2)}
305
+ {r.raptorLevel != null ? ` · L${r.raptorLevel}` : ""}
306
+ </span>
307
+ </li>
308
+ ))}
309
+ </ul>
310
+ )}
311
+ </td>
312
+ <td>{fmtTs(t.endedAt)}</td>
313
+ <td className="actions-cell">
314
+ <button
315
+ type="button"
316
+ className="mini-btn"
317
+ disabled={busy !== null}
318
+ onClick={() => onFork(t.conversationId, t.turnIndex)}
319
+ >
320
+ fork
321
+ </button>
322
+ <button
323
+ type="button"
324
+ className="mini-btn"
325
+ disabled={busy !== null}
326
+ onClick={() => onRewind(t.conversationId, t.turnIndex)}
327
+ >
328
+ rewind
329
+ </button>
330
+ </td>
331
+ </tr>
332
+ ))}
333
+ </tbody>
334
+ </table>
335
+ );
336
+ }