pi-mega-compact 0.13.0 → 0.13.2

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 (212) hide show
  1. package/dist/extensions/dashboard-server/api-contracts/embedder-health.js +11 -0
  2. package/dist/extensions/dashboard-server/api-contracts/endpoints/registry.js +225 -0
  3. package/dist/extensions/dashboard-server/api-contracts/endpoints/types.js +1 -0
  4. package/dist/extensions/dashboard-server/api-contracts/endpoints.js +5 -224
  5. package/dist/extensions/dashboard-server/api-contracts/raptor.js +8 -0
  6. package/dist/extensions/dashboard-server/api-contracts.test/_helpers.js +32 -0
  7. package/dist/extensions/dashboard-server/routes-cache.test/_helpers.js +48 -0
  8. package/dist/extensions/dashboard-server/routes-embedder-health.js +67 -0
  9. package/dist/extensions/dashboard-server/routes-raptor.js +88 -0
  10. package/dist/extensions/dashboard-server/routes-setup.js +1 -1
  11. package/dist/extensions/dashboard-server/routes.js +2 -0
  12. package/dist/extensions/dashboard-server/server.js +5 -1
  13. package/dist/extensions/mega-cache-replay.test/_helpers.js +175 -0
  14. package/dist/extensions/mega-commands/dataCommands.js +151 -0
  15. package/dist/extensions/mega-commands/helpers.js +61 -0
  16. package/dist/extensions/mega-commands/historyCommands.js +97 -0
  17. package/dist/extensions/mega-commands/setupCommand.js +200 -0
  18. package/dist/extensions/mega-commands.js +14 -499
  19. package/dist/extensions/mega-compact-s38.test/_helpers.js +194 -0
  20. package/dist/extensions/mega-compact.js +12 -2
  21. package/dist/extensions/mega-compact.test/_helpers.js +225 -0
  22. package/dist/extensions/mega-events/agent-handlers/agentEndHandler.js +211 -0
  23. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.js +49 -0
  24. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.js +33 -0
  25. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.js +387 -0
  26. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/event.js +7 -0
  27. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.js +55 -0
  28. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.js +12 -0
  29. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.js +22 -0
  30. package/dist/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.js +38 -0
  31. package/dist/extensions/mega-events/agent-handlers/turnEndHandler.js +36 -0
  32. package/dist/extensions/mega-events/agent-handlers.js +4 -799
  33. package/dist/extensions/mega-events/context-handler/afterCompact.js +163 -0
  34. package/dist/extensions/mega-events/context-handler/messageText.js +12 -0
  35. package/dist/extensions/mega-events/context-handler/tailResult.js +46 -0
  36. package/dist/extensions/mega-events/context-handler.js +11 -198
  37. package/dist/extensions/mega-events/separated-prompt.test/_helpers.js +25 -0
  38. package/dist/src/config.js +2 -0
  39. package/dist/src/dedup-engine.test/_helpers.js +55 -0
  40. package/dist/src/e2e.test/_helpers.js +52 -0
  41. package/dist/src/embedder.js +1 -0
  42. package/dist/src/httpEmbedder.js +6 -0
  43. package/dist/src/hyde.js +146 -0
  44. package/dist/src/importance.test/_helpers.js +5 -0
  45. package/dist/src/memoryGraph/sources/checkpoints.js +78 -0
  46. package/dist/src/memoryGraph/sources/edges.js +17 -0
  47. package/dist/src/memoryGraph/sources/flags.js +22 -0
  48. package/dist/src/memoryGraph/sources/helpers.js +14 -0
  49. package/dist/src/memoryGraph/sources/memories.js +88 -0
  50. package/dist/src/memoryGraph/sources/raptor.js +26 -0
  51. package/dist/src/memoryGraph/sources/turns.js +176 -0
  52. package/dist/src/memoryGraph/sources.js +15 -441
  53. package/dist/src/memoryGraph-gates.test/_helpers.js +120 -0
  54. package/dist/src/ratio.bench.test/_helpers.js +198 -0
  55. package/dist/src/recall/async.js +112 -0
  56. package/dist/src/recall/format.js +149 -0
  57. package/dist/src/recall/memory.js +62 -0
  58. package/dist/src/recall/reformulate.js +82 -0
  59. package/dist/src/recall/sync.js +169 -0
  60. package/dist/src/recall/types.js +1 -0
  61. package/dist/src/recall.js +13 -530
  62. package/dist/src/store/sqlite/schema/core.js +232 -0
  63. package/dist/src/store/sqlite/schema/game.js +65 -0
  64. package/dist/src/store/sqlite/schema/plan-v2.js +107 -0
  65. package/dist/src/store/sqlite/schema/turns.js +59 -0
  66. package/dist/src/store/sqlite/schema.js +8 -441
  67. package/dist/src/store/turns/contract-compliance.test/_helpers.js +21 -0
  68. package/dist/src/store/turns/sqlite-store/admin.js +171 -0
  69. package/dist/src/store/turns/sqlite-store/ctx.js +1 -0
  70. package/dist/src/store/turns/sqlite-store/read.js +111 -0
  71. package/dist/src/store/turns/sqlite-store/rows.js +42 -0
  72. package/dist/src/store/turns/sqlite-store/write.js +102 -0
  73. package/dist/src/store/turns/sqlite-store.js +31 -367
  74. package/dist/src/vectorStore/class.js +356 -0
  75. package/dist/src/vectorStore/hash.js +10 -0
  76. package/dist/src/vectorStore/types.js +2 -0
  77. package/dist/src/vectorStore.js +8 -359
  78. package/dist/src/vectorStore.test/_helpers.js +17 -0
  79. package/extensions/dashboard-client/dist/assets/{CacheTab-BZNnKhh5.js → CacheTab-DPRHjYZ0.js} +2 -2
  80. package/extensions/dashboard-client/dist/assets/{CacheTab-BZNnKhh5.js.map → CacheTab-DPRHjYZ0.js.map} +1 -1
  81. package/extensions/dashboard-client/dist/assets/{EventsTab-CzF5L42U.js → EventsTab-CgwYq-Qf.js} +2 -2
  82. package/extensions/dashboard-client/dist/assets/{EventsTab-CzF5L42U.js.map → EventsTab-CgwYq-Qf.js.map} +1 -1
  83. package/extensions/dashboard-client/dist/assets/{HealthTab-BLpidMrX.js → HealthTab-BgOCjVzR.js} +2 -2
  84. package/extensions/dashboard-client/dist/assets/{HealthTab-BLpidMrX.js.map → HealthTab-BgOCjVzR.js.map} +1 -1
  85. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Yw1yFpsy.js +2 -0
  86. package/extensions/dashboard-client/dist/assets/MaintenanceTab-Yw1yFpsy.js.map +1 -0
  87. package/extensions/dashboard-client/dist/assets/MemoryMapTab-yHUX7Yzi.js +2 -0
  88. package/extensions/dashboard-client/dist/assets/MemoryMapTab-yHUX7Yzi.js.map +1 -0
  89. package/extensions/dashboard-client/dist/assets/{MetricsTab-B0PCysqs.js → MetricsTab-CcH9fP8P.js} +2 -2
  90. package/extensions/dashboard-client/dist/assets/{MetricsTab-B0PCysqs.js.map → MetricsTab-CcH9fP8P.js.map} +1 -1
  91. package/extensions/dashboard-client/dist/assets/{OverviewTab-DsOhqFu4.js → OverviewTab-BOs8ZNev.js} +2 -2
  92. package/extensions/dashboard-client/dist/assets/{OverviewTab-DsOhqFu4.js.map → OverviewTab-BOs8ZNev.js.map} +1 -1
  93. package/extensions/dashboard-client/dist/assets/{ReposTab-B3YKYuOf.js → ReposTab-B-MfSPvg.js} +2 -2
  94. package/extensions/dashboard-client/dist/assets/{ReposTab-B3YKYuOf.js.map → ReposTab-B-MfSPvg.js.map} +1 -1
  95. package/extensions/dashboard-client/dist/assets/{SessionsTab-B96FWcrC.js → SessionsTab-BmeN649Q.js} +2 -2
  96. package/extensions/dashboard-client/dist/assets/{SessionsTab-B96FWcrC.js.map → SessionsTab-BmeN649Q.js.map} +1 -1
  97. package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js +2 -0
  98. package/extensions/dashboard-client/dist/assets/SetupTab-nOknoph5.js.map +1 -0
  99. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BfkUVTvA.js → TimeSavedCard-DnPg0L0z.js} +2 -2
  100. package/extensions/dashboard-client/dist/assets/{TimeSavedCard-BfkUVTvA.js.map → TimeSavedCard-DnPg0L0z.js.map} +1 -1
  101. package/extensions/dashboard-client/dist/assets/{TopicsTab-DLRsZmXJ.js → TopicsTab-BODHOg_b.js} +2 -2
  102. package/extensions/dashboard-client/dist/assets/{TopicsTab-DLRsZmXJ.js.map → TopicsTab-BODHOg_b.js.map} +1 -1
  103. package/extensions/dashboard-client/dist/assets/{TurnsTab-DKGU2Bf6.js → TurnsTab-BK0I7hKr.js} +2 -2
  104. package/extensions/dashboard-client/dist/assets/{TurnsTab-DKGU2Bf6.js.map → TurnsTab-BK0I7hKr.js.map} +1 -1
  105. package/extensions/dashboard-client/dist/assets/{index-D-lPLRWB.js → index-mOlljTFI.js} +10 -10
  106. package/extensions/dashboard-client/dist/assets/index-mOlljTFI.js.map +1 -0
  107. package/extensions/dashboard-client/dist/assets/{useSSE-ClbbcgIp.js → useSSE-BYOtv1-3.js} +2 -2
  108. package/extensions/dashboard-client/dist/assets/{useSSE-ClbbcgIp.js.map → useSSE-BYOtv1-3.js.map} +1 -1
  109. package/extensions/dashboard-client/dist/index.html +1 -1
  110. package/extensions/dashboard-client/src/App.tsx +0 -4
  111. package/extensions/dashboard-client/src/api/client.ts +16 -0
  112. package/extensions/dashboard-client/src/tabs/MaintenanceTab/ActionsCard.tsx +178 -0
  113. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DbStatsCard.tsx +140 -0
  114. package/extensions/dashboard-client/src/tabs/MaintenanceTab/DebugBundleCard.tsx +109 -0
  115. package/extensions/dashboard-client/src/tabs/MaintenanceTab/HealthMitigationCard.tsx +98 -0
  116. package/extensions/dashboard-client/src/tabs/MaintenanceTab/SchemaHealthCard.tsx +108 -0
  117. package/extensions/dashboard-client/src/tabs/MaintenanceTab.tsx +12 -598
  118. package/extensions/dashboard-client/src/tabs/MemoryMapTab/MemoryMapView.tsx +476 -0
  119. package/extensions/dashboard-client/src/tabs/MemoryMapTab/RaptorTreeView.tsx +163 -0
  120. package/extensions/dashboard-client/src/tabs/MemoryMapTab.tsx +56 -466
  121. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderHealthCard.tsx +109 -0
  122. package/extensions/dashboard-client/src/tabs/SetupTab/EmbedderSetup.tsx +468 -0
  123. package/extensions/dashboard-client/src/tabs/SetupTab.tsx +23 -484
  124. package/extensions/dashboard-server/api-contracts/embedder-health.ts +32 -0
  125. package/extensions/dashboard-server/api-contracts/endpoints/registry.ts +360 -0
  126. package/extensions/dashboard-server/api-contracts/endpoints/types.ts +350 -0
  127. package/extensions/dashboard-server/api-contracts/endpoints.ts +27 -648
  128. package/extensions/dashboard-server/api-contracts/index.ts +6 -0
  129. package/extensions/dashboard-server/api-contracts/raptor.ts +49 -0
  130. package/extensions/dashboard-server/api-contracts.test/_helpers.ts +47 -0
  131. package/extensions/dashboard-server/routes-cache.test/_helpers.ts +94 -0
  132. package/extensions/dashboard-server/routes-embedder-health.ts +77 -0
  133. package/extensions/dashboard-server/routes-raptor.ts +128 -0
  134. package/extensions/dashboard-server/routes-setup.ts +1 -1
  135. package/extensions/dashboard-server/routes.ts +2 -0
  136. package/extensions/dashboard-server/server.ts +4 -0
  137. package/extensions/mega-cache-replay.test/_helpers.ts +188 -0
  138. package/extensions/mega-commands/dataCommands.ts +169 -0
  139. package/extensions/mega-commands/helpers.ts +62 -0
  140. package/extensions/mega-commands/historyCommands.ts +117 -0
  141. package/extensions/mega-commands/setupCommand.ts +235 -0
  142. package/extensions/mega-commands.ts +25 -538
  143. package/extensions/mega-compact-s38.test/_helpers.ts +201 -0
  144. package/extensions/mega-compact.test/_helpers.ts +237 -0
  145. package/extensions/mega-compact.ts +12 -2
  146. package/extensions/mega-events/agent-handlers/agentEndHandler.ts +238 -0
  147. package/extensions/mega-events/agent-handlers/turnEndHandler/cacheStripe.ts +74 -0
  148. package/extensions/mega-events/agent-handlers/turnEndHandler/contextHealth.ts +50 -0
  149. package/extensions/mega-events/agent-handlers/turnEndHandler/errorRetry.ts +421 -0
  150. package/extensions/mega-events/agent-handlers/turnEndHandler/event.ts +16 -0
  151. package/extensions/mega-events/agent-handlers/turnEndHandler/gameScoring.ts +73 -0
  152. package/extensions/mega-events/agent-handlers/turnEndHandler/lengthStop.ts +29 -0
  153. package/extensions/mega-events/agent-handlers/turnEndHandler/memoryReview.ts +42 -0
  154. package/extensions/mega-events/agent-handlers/turnEndHandler/recordTurnRow.ts +61 -0
  155. package/extensions/mega-events/agent-handlers/turnEndHandler.ts +64 -0
  156. package/extensions/mega-events/agent-handlers.ts +15 -861
  157. package/extensions/mega-events/context-handler/afterCompact.ts +213 -0
  158. package/extensions/mega-events/context-handler/messageText.ts +20 -0
  159. package/extensions/mega-events/context-handler/tailResult.ts +63 -0
  160. package/extensions/mega-events/context-handler.ts +17 -235
  161. package/extensions/mega-events/separated-prompt.test/_helpers.ts +35 -0
  162. package/package.json +1 -1
  163. package/src/config.ts +4 -0
  164. package/src/dedup-engine.test/_helpers.ts +79 -0
  165. package/src/e2e.test/_helpers.ts +59 -0
  166. package/src/embedder.ts +4 -0
  167. package/src/httpEmbedder.ts +7 -0
  168. package/src/hyde.ts +162 -0
  169. package/src/importance.test/_helpers.ts +5 -0
  170. package/src/memoryGraph/sources/checkpoints.ts +99 -0
  171. package/src/memoryGraph/sources/edges.ts +23 -0
  172. package/src/memoryGraph/sources/flags.ts +26 -0
  173. package/src/memoryGraph/sources/helpers.ts +13 -0
  174. package/src/memoryGraph/sources/memories.ts +108 -0
  175. package/src/memoryGraph/sources/raptor.ts +37 -0
  176. package/src/memoryGraph/sources/turns.ts +226 -0
  177. package/src/memoryGraph/sources.ts +19 -544
  178. package/src/memoryGraph-gates.test/_helpers.ts +164 -0
  179. package/src/ratio.bench.test/_helpers.ts +268 -0
  180. package/src/recall/async.ts +142 -0
  181. package/src/recall/format.ts +173 -0
  182. package/src/recall/memory.ts +90 -0
  183. package/src/recall/reformulate.ts +111 -0
  184. package/src/recall/sync.ts +196 -0
  185. package/src/recall/types.ts +63 -0
  186. package/src/recall.ts +25 -712
  187. package/src/store/sqlite/schema/core.ts +233 -0
  188. package/src/store/sqlite/schema/game.ts +66 -0
  189. package/src/store/sqlite/schema/plan-v2.ts +108 -0
  190. package/src/store/sqlite/schema/turns.ts +60 -0
  191. package/src/store/sqlite/schema.ts +13 -441
  192. package/src/store/turns/contract-compliance.test/_helpers.ts +38 -0
  193. package/src/store/turns/sqlite-store/admin.ts +249 -0
  194. package/src/store/turns/sqlite-store/ctx.ts +14 -0
  195. package/src/store/turns/sqlite-store/read.ts +174 -0
  196. package/src/store/turns/sqlite-store/rows.ts +55 -0
  197. package/src/store/turns/sqlite-store/write.ts +193 -0
  198. package/src/store/turns/sqlite-store.ts +33 -514
  199. package/src/vectorStore/class.ts +433 -0
  200. package/src/vectorStore/hash.ts +11 -0
  201. package/src/vectorStore/types.ts +58 -0
  202. package/src/vectorStore.test/_helpers.ts +20 -0
  203. package/src/vectorStore.ts +13 -489
  204. package/extensions/dashboard-client/dist/assets/ConfigTab-DG0WkuuG.js +0 -2
  205. package/extensions/dashboard-client/dist/assets/ConfigTab-DG0WkuuG.js.map +0 -1
  206. package/extensions/dashboard-client/dist/assets/MaintenanceTab-BQF7W7xX.js +0 -2
  207. package/extensions/dashboard-client/dist/assets/MaintenanceTab-BQF7W7xX.js.map +0 -1
  208. package/extensions/dashboard-client/dist/assets/MemoryMapTab-CPtHLv0A.js +0 -2
  209. package/extensions/dashboard-client/dist/assets/MemoryMapTab-CPtHLv0A.js.map +0 -1
  210. package/extensions/dashboard-client/dist/assets/SetupTab-hbzQ_NZv.js +0 -2
  211. package/extensions/dashboard-client/dist/assets/SetupTab-hbzQ_NZv.js.map +0 -1
  212. package/extensions/dashboard-client/dist/assets/index-D-lPLRWB.js.map +0 -1
@@ -1,476 +1,66 @@
1
1
  /**
2
- * MemoryMapTab.tsx — D3 memory map with force-directed graph.
3
- * Node shape encodes nodeType: checkpoint=filled circle, turn=hollow circle,
4
- * turn-content=hollow+ring, memory=diamond.
5
- * Fetches from /api/memory-map, renders SVG force layout.
2
+ * MemoryMapTab.tsx — Sub-tab shell under Memory Map (Part B).
3
+ *
4
+ * Hosts two sub-tabs: the D3 force-directed Memory Map (MemoryMapView) and
5
+ * the hierarchical RAPTOR tree (RaptorTreeView). The heavy rendering logic
6
+ * lives in ./MemoryMapTab/* to keep every file under the extensions limit.
6
7
  */
7
8
  import type React from "react";
8
- import { useEffect, useRef, useState, useCallback, useMemo } from "react";
9
- import { renderNodeShape, NODE_COLORS, NODE_TYPE_LABELS } from "../memory-map-shapes.js";
10
- import type { NodeType } from "../memory-map-shapes.js";
11
- import { buildLayout, applyForces } from "../memory-map-layout.js";
12
- import type { LayoutNode, LayoutEdge } from "../memory-map-layout.js";
13
-
14
- // Types (mirror of api-contracts/memory-map.ts client-side only)
15
-
16
- interface GraphNode {
17
- id: string;
18
- sessionId: string;
19
- label: string;
20
- summaryTruncated: string;
21
- tokenEstimate: number;
22
- timestamp: number;
23
- dedupStatus: string | undefined;
24
- raptorLevel: number;
25
- topicSummary: string | undefined;
26
- decisionCount: number;
27
- textSnippet: string;
28
- /** Source type discriminator for UI node-shape encoding. */
29
- nodeType: "checkpoint" | "turn" | "turn-content" | "memory";
30
- }
31
-
32
- interface GraphEdge {
33
- source: string;
34
- target: string;
35
- weight: number;
36
- type: "temporal" | "semantic" | "raptor_parent";
37
- }
38
-
39
- interface GraphValidationReport {
40
- readonly gatesRun: number;
41
- readonly gatesPassed: number;
42
- readonly dropped: { nodes: number; edges: number };
43
- readonly warnings: Array<{ gate: string; code: string; count: number }>;
44
- readonly sources: {
45
- checkpoint: number;
46
- turn: number;
47
- turnContent: number;
48
- memory: number;
49
- };
50
- readonly builtAt: number;
51
- }
52
-
53
- interface GraphMetadata {
54
- totalNodes: number;
55
- totalEdges: number;
56
- avgWeight: number;
57
- nodeTypeBreakdown: Record<string, number>;
58
- edgeTypeBreakdown: Record<string, number>;
59
- }
60
-
61
- interface MemoryMapResponse {
62
- nodes: GraphNode[];
63
- edges: GraphEdge[];
64
- metadata: GraphMetadata;
65
- /** Validation report from the 9-gate pipeline. Optional for backward compat. */
66
- validation?: GraphValidationReport;
67
- }
68
-
69
- // Simulation rendering constants (layout math is in memory-map-layout.ts)
70
-
71
- const MAX_ITERATIONS = 300;
72
- const EDGE_ALPHA = 0.3;
73
- const SVG_WIDTH = 900;
74
- const SVG_HEIGHT = 600;
75
- const PADDING = 40;
76
-
77
- // Helpers
9
+ import { useState } from "react";
10
+ import MemoryMapView from "./MemoryMapTab/MemoryMapView.js";
11
+ import RaptorTreeView from "./MemoryMapTab/RaptorTreeView.js";
12
+
13
+ type MemoryMapSubTab = "map" | "raptor";
14
+
15
+ const subTabNavStyle: React.CSSProperties = {
16
+ display: "flex",
17
+ gap: "0.5rem",
18
+ marginBottom: "1rem",
19
+ borderBottom: "1px solid #2a2a4e",
20
+ paddingBottom: "0.5rem",
21
+ paddingTop: "0.5rem",
22
+ width: "100%",
23
+ };
78
24
 
79
- function edgeColor(type: GraphEdge["type"]): string {
80
- switch (type) {
81
- case "temporal":
82
- return "#6366f1"; // indigo
83
- case "semantic":
84
- return "#22c55e"; // green
85
- case "raptor_parent":
86
- return "#f59e0b"; // amber
87
- }
25
+ function subTabBtnStyle(active: boolean): React.CSSProperties {
26
+ return {
27
+ background: active ? "#3a5a9f" : "transparent",
28
+ color: active ? "#fff" : "#a0a0c0",
29
+ border: "1px solid",
30
+ borderColor: active ? "#3a5a9f" : "#2a2a4e",
31
+ borderRadius: "6px",
32
+ padding: "0.4rem 0.8rem",
33
+ cursor: "pointer",
34
+ fontSize: "0.9rem",
35
+ fontWeight: active ? 600 : 400,
36
+ };
88
37
  }
89
38
 
90
- // Minimal legend swatch component
91
- interface SwatchProps {
92
- type: "node" | "edge";
93
- color: string;
94
- shape: "filled-circle" | "hollow-circle" | "hollow-ring" | "diamond" | "line";
95
- label: string;
96
- }
97
- const Swatch: React.FC<SwatchProps> = ({ color, shape, label }) => {
98
- const base: React.CSSProperties = {
99
- display: "inline-block",
100
- width: "10px",
101
- height: "10px",
102
- verticalAlign: "middle",
103
- marginRight: "3px",
104
- borderRadius: shape.startsWith("hollow") || shape === "filled-circle" ? "50%" : undefined,
105
- };
106
- let swatch: JSX.Element;
107
- if (shape === "line") {
108
- return <span style={{ color, marginRight: "6px" }}>{label}</span>;
109
- } else if (shape === "filled-circle") {
110
- swatch = <span style={{ ...base, backgroundColor: color }} />;
111
- } else if (shape === "hollow-circle") {
112
- swatch = <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: "transparent" }} />;
113
- } else if (shape === "hollow-ring") {
114
- swatch = (
115
- <span style={{ ...base, border: `2px solid ${color}`, backgroundColor: "transparent", position: "relative" }}>
116
- <span style={{ display: "block", width: "4px", height: "4px", borderRadius: "50%", backgroundColor: color, margin: "2px auto" }} />
117
- </span>
118
- );
119
- } else {
120
- swatch = <span style={{ ...base, clipPath: "polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)", backgroundColor: color }} />;
121
- }
122
- return <><span className="memory-map-legend-item">{swatch}{label}</span> </>;
123
- };
124
-
125
- // Force simulation engine (delegated to memory-map-layout.ts)
126
39
  const MemoryMapTab: React.FC = () => {
127
- const [data, setData] = useState<MemoryMapResponse | null>(null);
128
- const [loading, setLoading] = useState<boolean>(true);
129
- const [error, setError] = useState<string | null>(null);
130
- const [selectedNode, setSelectedNode] = useState<GraphNode | null>(null);
131
- const [searchQuery, setSearchQuery] = useState<string>("");
132
- const [filterSession] = useState<string>("");
133
- const [frame, setFrame] = useState<number>(0);
134
-
135
- const layoutRef = useRef<{ nodes: LayoutNode[]; edges: LayoutEdge[] } | null>(null);
136
- const animRef = useRef<number>(0);
137
-
138
- // Fetch graph data when filterSession changes
139
- useEffect(() => {
140
- let cancelled = false;
141
- const params = new URLSearchParams();
142
- if (filterSession) params.set("sessionId", filterSession);
143
- params.set("threshold", "0.7");
144
- params.set("maxEdgesPerNode", "4");
145
-
146
- setLoading(true);
147
- setError(null);
148
-
149
- fetch(`/api/memory-map?${params.toString()}`)
150
- .then((r) => {
151
- if (!r.ok) throw new Error(`HTTP ${r.status}`);
152
- return r.json() as Promise<MemoryMapResponse>;
153
- })
154
- .then((d) => {
155
- if (!cancelled) {
156
- setData(d);
157
- layoutRef.current = buildLayout(d);
158
- setFrame(1);
159
- setLoading(false);
160
- }
161
- })
162
- .catch((e: unknown) => {
163
- if (!cancelled) {
164
- setError(e instanceof Error ? e.message : "Unknown error");
165
- setLoading(false);
166
- }
167
- });
168
-
169
- return () => {
170
- cancelled = true;
171
- cancelAnimationFrame(animRef.current);
172
- };
173
- }, [filterSession]);
174
-
175
- // Run force simulation via requestAnimationFrame
176
- useEffect(() => {
177
- if (!layoutRef.current || frame === 0) return;
178
-
179
- const layout = layoutRef.current;
180
- let iter = 0;
181
-
182
- const tick = () => {
183
- if (iter >= MAX_ITERATIONS) return;
184
- applyForces(layout);
185
- iter++;
186
- setFrame(iter);
187
- animRef.current = requestAnimationFrame(tick);
188
- };
189
-
190
- animRef.current = requestAnimationFrame(tick);
191
- return () => cancelAnimationFrame(animRef.current);
192
- }, [frame]);
193
-
194
- // Toggle pin / select a node
195
- const handleNodeClick = useCallback((node: LayoutNode, index: number) => {
196
- const layout = layoutRef.current;
197
- if (!layout) return;
198
- layout.nodes[index].pinned = !layout.nodes[index].pinned;
199
- if (!layout.nodes[index].pinned) {
200
- layout.nodes[index].vx = 0;
201
- layout.nodes[index].vy = 0;
202
- }
203
- setSelectedNode((prev) => (prev?.id === node.id ? null : (node as unknown as GraphNode)));
204
- setFrame((s) => s + 1);
205
- }, []);
206
-
207
- // Filtered node indices for search
208
- const filteredSet = useMemo<Set<number> | null>(() => {
209
- const layout = layoutRef.current;
210
- if (!layout || !searchQuery) return null;
211
- const q = searchQuery.toLowerCase();
212
- return new Set(
213
- layout.nodes
214
- .map((n, i) =>
215
- n.summaryTruncated.toLowerCase().includes(q) || n.label.toLowerCase().includes(q) ? i : -1,
216
- )
217
- .filter((i) => i >= 0),
218
- );
219
- }, [searchQuery]);
220
-
221
- // Health indicator helpers (D3)
222
-
223
- /**
224
- * Derive graph health from validation report:
225
- * green = all gates passed + no warnings
226
- * yellow = warnings present but no critical gate failed
227
- * red = a critical gate (gatesRun > gatesPassed) failed
228
- */
229
- const graphHealth = useMemo<{ level: "green" | "yellow" | "red"; label: string }>(() => {
230
- const v = data?.validation;
231
- if (!v) return { level: "yellow", label: "No validation" };
232
- if (v.gatesPassed < v.gatesRun) return { level: "red", label: "Gate failure" };
233
- if (v.warnings.length > 0) return { level: "yellow", label: `${v.warnings.length} warning(s)` };
234
- return { level: "green", label: "Healthy" };
235
- }, [data?.validation]);
236
-
237
- const healthColor: Record<string, string> = {
238
- green: "#22c55e",
239
- yellow: "#eab308",
240
- red: "#ef4444",
241
- };
242
-
243
- // Source availability indicators (D3)
244
-
245
- /** Count badge fragments from validation.sources. */
246
- const countBadge = useMemo<string>(() => {
247
- const v = data?.validation;
248
- if (!v) {
249
- const totalNodes = data?.metadata.totalNodes ?? 0;
250
- return `${totalNodes} nodes`;
251
- }
252
- const parts: string[] = [];
253
- if (v.sources.checkpoint > 0) parts.push(`${v.sources.checkpoint} checkpoints`);
254
- if (v.sources.turn > 0) parts.push(`${v.sources.turn} turns`);
255
- if (v.sources.turnContent > 0) parts.push(`${v.sources.turnContent} turn-content`);
256
- if (v.sources.memory > 0) parts.push(`${v.sources.memory} memories`);
257
- if (parts.length === 0) {
258
- parts.push(`${data?.metadata.totalNodes ?? 0} nodes`);
259
- }
260
- return parts.join(" · ");
261
- }, [data?.validation, data?.metadata.totalNodes]);
262
-
263
- /** Per-source availability: ✓ for available sources, ✗ for empty ones. */
264
- const sourceAvail = useMemo<string>(() => {
265
- const v = data?.validation;
266
- if (!v) return "";
267
- const parts: string[] = [];
268
- parts.push(v.sources.checkpoint > 0 ? "✓ checkpoints" : "✗ checkpoints");
269
- parts.push(v.sources.turn > 0 ? "✓ turns" : "✗ turns");
270
- parts.push(v.sources.turnContent > 0 ? "✓ turn-content" : "✗ turn-content");
271
- parts.push(v.sources.memory > 0 ? "✓ memories" : "✗ memories");
272
- return parts.join(" | ");
273
- }, [data?.validation]);
274
-
275
- /** Whether all four sources are empty (true empty state). */
276
- const allSourcesEmpty = useMemo<boolean>(() => {
277
- const v = data?.validation;
278
- if (!v) return data?.metadata.totalNodes === 0;
279
- return (
280
- v.sources.checkpoint === 0 &&
281
- v.sources.turn === 0 &&
282
- v.sources.turnContent === 0 &&
283
- v.sources.memory === 0
284
- );
285
- }, [data?.validation, data?.metadata.totalNodes]);
286
-
287
- // Loading state
288
-
289
- if (loading) {
290
- return <div className="memory-map-loading">Loading memory graph...</div>;
291
- }
292
-
293
- // Error state
294
-
295
- if (error) {
296
- return (
297
- <div className="memory-map-error">
298
- <p>Failed to load memory map: {error}</p>
299
- <button
300
- className="memory-map-retry-btn"
301
- onClick={() => setFrame((s) => s + 1)}
302
- >
303
- Retry
304
- </button>
305
- </div>
306
- );
307
- }
308
-
309
- // Empty state (D2)
310
-
311
- if (!data || !layoutRef.current || allSourcesEmpty) {
312
- return (
313
- <div className="memory-map-empty">
314
- <p>Memories appear after your first compaction. The graph shows checkpoints (compaction summaries) linked by semantic similarity and time. Run a longer session or lower the compaction tier to see it sooner.</p>
315
- </div>
316
- );
317
- }
318
-
319
- const layout = layoutRef.current;
320
-
321
- // Render
322
-
323
- return (
324
- <div className="memory-map-container">
325
- {/* Toolbar */}
326
- <div className="memory-map-toolbar">
327
- <input
328
- type="text"
329
- placeholder="Search memories..."
330
- value={searchQuery}
331
- onInput={(e: React.FormEvent<HTMLInputElement>) =>
332
- setSearchQuery((e.target as HTMLInputElement).value)
333
- }
334
- className="memory-map-search"
335
- />
336
- <span className="memory-map-stats">
337
- {/* Count badge */}
338
- <span className="memory-map-count-badge">{countBadge}</span>
339
- <br />
340
- <span className="memory-map-edges">{data.edges.length} edges</span>
341
- </span>
342
- {/* Graph-health indicator */}
343
- <span
344
- className="memory-map-health-badge"
345
- style={{
346
- backgroundColor: healthColor[graphHealth.level] ?? "#6b7280",
347
- color: "#fff",
348
- padding: "2px 8px",
349
- borderRadius: "10px",
350
- fontSize: "11px",
351
- fontWeight: 600,
352
- marginLeft: "8px",
353
- }}
354
- title={`Validation: ${graphHealth.label}`}
355
- >
356
- {graphHealth.level === "green" ? "Healthy" : graphHealth.level === "yellow" ? "Warnings" : "Critical"}
357
- </span>
358
- </div>
359
-
360
- {/* Source availability indicators */}
361
- {sourceAvail ? (
362
- <div className="memory-map-source-avail" style={{ fontSize: "11px", padding: "2px 12px", color: "#6b7280" }}>
363
- {sourceAvail}
364
- </div>
365
- ) : null}
366
-
367
- {/* Legend — node types + edge types */}
368
- <div className="memory-map-legend">
369
- <span className="memory-map-legend-section">Nodes:</span>
370
- <Swatch type="node" color={NODE_COLORS.checkpoint} shape="filled-circle" label="Checkpoint" />
371
- <Swatch type="node" color={NODE_COLORS.turn} shape="hollow-circle" label="Turn" />
372
- <Swatch type="node" color={NODE_COLORS["turn-content"]} shape="hollow-ring" label="Turn Content" />
373
- <Swatch type="node" color={NODE_COLORS.memory} shape="diamond" label="Memory" />
374
- <span className="memory-map-legend-sep">|</span>
375
- <span className="memory-map-legend-section">Edges:</span>
376
- <Swatch type="edge" color={edgeColor("semantic")} shape="line" label="Semantic" />
377
- <Swatch type="edge" color={edgeColor("temporal")} shape="line" label="Temporal" />
378
- <Swatch type="edge" color={edgeColor("raptor_parent")} shape="line" label="Raptor" />
379
- </div>
380
-
381
- {/* SVG graph */}
382
- <svg
383
- width={SVG_WIDTH}
384
- height={SVG_HEIGHT}
385
- viewBox={`0 0 ${SVG_WIDTH} ${SVG_HEIGHT}`}
386
- className="memory-map-svg"
387
- >
388
- {/* Edges */}
389
- {layout.edges.map((e, i) => {
390
- const src = layout.nodes[e.source];
391
- const tgt = layout.nodes[e.target];
392
- const color = edgeColor(e.type);
393
- const strokeW = Math.max(1, e.weight * 2.5);
394
- return (
395
- <line
396
- key={`edge-${i}`}
397
- x1={PADDING + (src.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}
398
- y1={PADDING + (src.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}
399
- x2={PADDING + (tgt.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING)}
400
- y2={PADDING + (tgt.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING)}
401
- stroke={color}
402
- strokeWidth={strokeW}
403
- opacity={EDGE_ALPHA}
404
- />
405
- );
406
- })}
407
-
408
- {/* Nodes — shape encodes nodeType */}
409
- {layout.nodes.map((n, i) => {
410
- const cx =
411
- PADDING + (n.pos.x / (layout.nodes.length || 1)) * (SVG_WIDTH - 2 * PADDING);
412
- const cy =
413
- PADDING + (n.pos.y / (layout.nodes.length || 1)) * (SVG_HEIGHT - 2 * PADDING);
414
- const radius = Math.min(20, 8 + n.tokenEstimate / 500);
415
- const isFiltered = filteredSet ? filteredSet.has(i) : true;
416
- const isSelected = selectedNode?.id === n.id;
417
- const nodeLabel = n.label.length > 20 ? n.label.slice(0, 18) + "..." : n.label;
418
-
419
- return (
420
- <g
421
- key={`node-${i}`}
422
- className="memory-map-node-group"
423
- onClick={() => handleNodeClick(n, i)}
424
- style={{ cursor: "pointer" }}
425
- >
426
- {renderNodeShape(cx, cy, radius, n.nodeType as NodeType, isSelected, isFiltered, n.dedupStatus)}
427
- <text
428
- x={cx}
429
- y={cy + radius + 12}
430
- textAnchor="middle"
431
- fontSize="9px"
432
- fill="#374151"
433
- className="memory-map-label"
434
- >
435
- {nodeLabel}
436
- </text>
437
- </g>
438
- );
439
- })}
440
- </svg>
441
-
442
- {/* Node detail panel */}
443
- {selectedNode ? (
444
- <div className="memory-map-detail">
445
- <h3>
446
- <span
447
- className="memory-map-detail-type"
448
- style={{
449
- display: "inline-block",
450
- fontSize: "12px",
451
- fontWeight: 400,
452
- color: "#6b7280",
453
- marginRight: "6px",
454
- }}
455
- >
456
- {NODE_TYPE_LABELS[selectedNode.nodeType]}
457
- </span>
458
- {selectedNode.label}
459
- </h3>
460
- <p>{selectedNode.summaryTruncated}</p>
461
- {selectedNode.topicSummary ? (
462
- <p className="memory-map-topic">Topic: {selectedNode.topicSummary}</p>
463
- ) : null}
464
- <p>
465
- Tokens: {selectedNode.tokenEstimate} | Decisions: {selectedNode.decisionCount}
466
- </p>
467
- <p>Session: {selectedNode.sessionId}</p>
468
- <p>Raptor Level: {selectedNode.raptorLevel}</p>
469
- <p className="memory-map-snippet">{selectedNode.textSnippet}</p>
470
- </div>
471
- ) : null}
472
- </div>
473
- );
40
+ const [subTab, setSubTab] = useState<MemoryMapSubTab>("map");
41
+
42
+ return (
43
+ <div className="memory-map-tab">
44
+ <nav style={subTabNavStyle} aria-label="Memory map sections">
45
+ <button
46
+ type="button"
47
+ style={subTabBtnStyle(subTab === "map")}
48
+ onClick={() => setSubTab("map")}
49
+ >
50
+ Memory Map
51
+ </button>
52
+ <button
53
+ type="button"
54
+ style={subTabBtnStyle(subTab === "raptor")}
55
+ onClick={() => setSubTab("raptor")}
56
+ >
57
+ RAPTOR Tree
58
+ </button>
59
+ </nav>
60
+ {subTab === "map" && <MemoryMapView />}
61
+ {subTab === "raptor" && <RaptorTreeView />}
62
+ </div>
63
+ );
474
64
  };
475
65
 
476
66
  export default MemoryMapTab;
@@ -0,0 +1,109 @@
1
+ /**
2
+ * SetupTab/EmbedderHealthCard.tsx — embedder health probe card (Part A).
3
+ *
4
+ * Round-trips a test embed through the active embedder and shows ✓ working /
5
+ * ✗ unreachable + latency + dimensions. Polls every 30s.
6
+ */
7
+ import type React from "react";
8
+ import { useState, useEffect, useCallback } from "react";
9
+ import type { EmbedderHealthResponse } from "@contracts";
10
+ import { fetchEmbedderHealth } from "../../api/client";
11
+
12
+ const styles: Record<string, React.CSSProperties> = {
13
+ section: {
14
+ background: "#1a1a2e",
15
+ borderRadius: "8px",
16
+ padding: "1rem",
17
+ marginBottom: "1rem",
18
+ border: "1px solid #2a2a4e",
19
+ },
20
+ sectionTitle: {
21
+ fontSize: "1.1rem",
22
+ fontWeight: 700,
23
+ marginTop: 0,
24
+ marginBottom: "0.75rem",
25
+ color: "#e0e0e0",
26
+ borderBottom: "1px solid #333",
27
+ paddingBottom: "0.5rem",
28
+ },
29
+ label: { fontWeight: 600, color: "#a0a0c0", marginRight: "0.5rem" },
30
+ value: { color: "#e0e0e0" },
31
+ row: { marginBottom: "0.4rem", fontSize: "0.9rem" },
32
+ };
33
+
34
+ export default function EmbedderHealthCard(): React.ReactElement {
35
+ const [health, setHealth] = useState<EmbedderHealthResponse | null>(null);
36
+ const [error, setError] = useState<string | null>(null);
37
+
38
+ const loadHealth = useCallback(() => {
39
+ fetchEmbedderHealth()
40
+ .then(setHealth)
41
+ .catch((e: unknown) =>
42
+ setError(e instanceof Error ? e.message : String(e)),
43
+ );
44
+ }, []);
45
+
46
+ useEffect(() => {
47
+ loadHealth();
48
+ }, [loadHealth]);
49
+
50
+ // Poll health every 30s
51
+ useEffect(() => {
52
+ const id = setInterval(loadHealth, 30000);
53
+ return () => clearInterval(id);
54
+ }, [loadHealth]);
55
+
56
+ const ok = health?.status === "ok";
57
+ const statusText =
58
+ health?.status === "ok"
59
+ ? "Working"
60
+ : health?.status === "unreachable"
61
+ ? "Unreachable"
62
+ : "Error";
63
+ const color = ok ? "#4caf50" : "#f44336";
64
+ const icon = ok ? "✓" : "✗";
65
+
66
+ return (
67
+ <div style={styles.section}>
68
+ <h3 style={styles.sectionTitle}>Embedder Health</h3>
69
+ {error && (
70
+ <p style={{ color: "#f44336", fontSize: "0.85rem" }}>
71
+ Error: {error}
72
+ </p>
73
+ )}
74
+ {!health && !error && (
75
+ <p style={{ color: "#888", fontSize: "0.85rem" }}>
76
+ Probing embedder...
77
+ </p>
78
+ )}
79
+ {health && (
80
+ <>
81
+ <div style={styles.row}>
82
+ <span style={{ ...styles.label, color: `${color}` }}>
83
+ {icon} {statusText}:
84
+ </span>
85
+ <span style={styles.value}>{health.dim} dims</span>
86
+ {health.latencyMs !== undefined && (
87
+ <span style={{ color: "#a0a0c0", marginLeft: "0.5rem" }}>
88
+ ({health.latencyMs.toFixed(1)} ms)
89
+ </span>
90
+ )}
91
+ </div>
92
+ <div style={styles.row}>
93
+ <span style={styles.label}>Endpoint:</span>
94
+ <span style={styles.value}>
95
+ {health.url ?? (
96
+ <span style={{ color: "#888" }}>built-in (no URL)</span>
97
+ )}
98
+ </span>
99
+ </div>
100
+ {health.error && (
101
+ <p style={{ color: "#f44336", fontSize: "0.85rem" }}>
102
+ {health.error}
103
+ </p>
104
+ )}
105
+ </>
106
+ )}
107
+ </div>
108
+ );
109
+ }