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
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Shared helpers for the ratio benchmark split test files.
3
+ *
4
+ * Extracted from ratio.bench.test.ts: message builders, tmp-dir lifecycle,
5
+ * and the generateMessages / generateRealisticConversation / generateNearDuplicates
6
+ * fixtures used across all benchmark describe blocks.
7
+ */
8
+ import * as fs from "node:fs";
9
+ import * as path from "node:path";
10
+ import * as os from "node:os";
11
+ export function makeMsg(role, text) {
12
+ return { role, text };
13
+ }
14
+ export function makeDir() {
15
+ return fs.mkdtempSync(path.join(os.tmpdir(), "ratio-bench-"));
16
+ }
17
+ /** Generate N messages with controlled repetition. */
18
+ export function generateMessages(n, opts) {
19
+ const msgs = [];
20
+ const templates = [
21
+ "I'm looking at the {file} module. The {component} needs refactoring because {reason}.",
22
+ "Found a bug in {file}: the {component} doesn't handle {case} correctly. Here's the fix: {fix}",
23
+ "Let me check the {file} implementation. The {component} uses {pattern} pattern which is fine for now.",
24
+ "Updated {file} to fix the {component} issue. The {reason} was causing {case}.",
25
+ "Running tests on {file}. The {component} test covers {case} and {fix}. Looks good.",
26
+ "The {component} in {file} needs to handle {case}. Currently it just {fix}.",
27
+ "Reviewed the {file} changes. The {component} refactor looks solid. {reason}.",
28
+ "Deployed the {component} fix to staging. {file} is now handling {case} correctly.",
29
+ ];
30
+ const files = [
31
+ "src/engine.ts",
32
+ "src/store.ts",
33
+ "src/vectorStore.ts",
34
+ "src/compact.ts",
35
+ "src/recall.ts",
36
+ ];
37
+ const components = [
38
+ "compression",
39
+ "dedup",
40
+ "embedding",
41
+ "search",
42
+ "checkpoint",
43
+ "supersede",
44
+ "recall",
45
+ ];
46
+ const reasons = [
47
+ "performance",
48
+ "correctness",
49
+ "maintainability",
50
+ "edge case handling",
51
+ "type safety",
52
+ ];
53
+ const cases = [
54
+ "empty input",
55
+ "large payloads",
56
+ "concurrent access",
57
+ "unicode content",
58
+ "timeout",
59
+ ];
60
+ const fixes = [
61
+ "added bounds checking",
62
+ "refactored the loop",
63
+ "added error handling",
64
+ "simplified the logic",
65
+ "added unit tests",
66
+ ];
67
+ const patterns = ["singleton", "observer", "strategy", "factory", "builder"];
68
+ for (let i = 0; i < n; i++) {
69
+ const template = templates[i % templates.length];
70
+ const fill = (s) => s
71
+ .replace("{file}", files[i % files.length])
72
+ .replace("{component}", components[i % components.length])
73
+ .replace("{reason}", reasons[i % reasons.length])
74
+ .replace("{case}", cases[i % cases.length])
75
+ .replace("{fix}", fixes[i % fixes.length])
76
+ .replace("{pattern}", patterns[i % patterns.length]);
77
+ let text;
78
+ switch (opts.pattern) {
79
+ case "unique":
80
+ text = fill(template) + ` [turn ${i}]`;
81
+ break;
82
+ case "repetitive":
83
+ text = fill(templates[i % 5]);
84
+ break;
85
+ case "mixed":
86
+ text =
87
+ i % 5 < 3
88
+ ? fill(template) + ` [turn ${i}]`
89
+ : fill(templates[i % 3]);
90
+ break;
91
+ case "code-review":
92
+ if (i % 4 === 0) {
93
+ text = `Reviewing PR #${i}: ${fill(template)}`;
94
+ }
95
+ else if (i % 4 === 1) {
96
+ text = "```typescript\nfunction handle" + components[i % components.length] + "() {\n // " + fill(template) + "\n return result;\n}\n```";
97
+ }
98
+ else if (i % 4 === 2) {
99
+ text = `LGTM. ${fill(template)} The test coverage looks good.`;
100
+ }
101
+ else {
102
+ text = `@user requested changes: ${fill(template)}`;
103
+ }
104
+ break;
105
+ case "debug-session":
106
+ if (i % 6 === 0) {
107
+ text = `Error in ${files[i % files.length]}: TypeError: Cannot read property '${components[i % components.length]}' of undefined`;
108
+ }
109
+ else if (i % 6 === 1) {
110
+ text = `Stack trace:\n at ${components[i % components.length]} (${files[i % files.length]}:${100 + i}:15)\n at process (${files[(i + 1) % files.length]}:${50 + i}:3)`;
111
+ }
112
+ else if (i % 6 === 2) {
113
+ text = `The issue is that ${cases[i % cases.length]} isn't being handled. ${fixes[i % fixes.length]}.`;
114
+ }
115
+ else if (i % 6 === 3) {
116
+ text = `Applied fix: ${fill(template)}`;
117
+ }
118
+ else if (i % 6 === 4) {
119
+ text = `Tests passing now. ${reasons[i % reasons.length]}.`;
120
+ }
121
+ else {
122
+ text = `Committed fix for ${components[i % components.length]}. ${fill(template)}`;
123
+ }
124
+ break;
125
+ default:
126
+ text = fill(template);
127
+ }
128
+ const role = i % 2 === 0 ? "user" : "assistant";
129
+ msgs.push(makeMsg(role, text));
130
+ }
131
+ return msgs;
132
+ }
133
+ /** Generate a large realistic conversation with tool reads, code blocks, discussion. */
134
+ export function generateRealisticConversation(turns) {
135
+ const msgs = [];
136
+ for (let i = 0; i < turns; i++) {
137
+ const phase = i % 8;
138
+ const mods = ["compression", "dedup", "embedding", "search"];
139
+ const fns = ["vectorStore.ts", "engine.ts", "compact.ts", "recall.ts"];
140
+ const issues = ["error handling", "type safety", "performance", "logging"];
141
+ const bugs = ["null pointer", "type mismatch", "race condition", "memory leak"];
142
+ switch (phase) {
143
+ case 0:
144
+ msgs.push(makeMsg("user", `I need help with the ${mods[i % 4]} module. It's not working correctly.`));
145
+ break;
146
+ case 1:
147
+ msgs.push(makeMsg("assistant", `Let me look at the code. I'll check the ${fns[i % 4]} file.`));
148
+ break;
149
+ case 2:
150
+ msgs.push(makeMsg("tool", `File content of src/${["vectorStore", "engine", "compact", "recall"][i % 4]}.ts:\n${"x".repeat(800 + (i % 5) * 200)}\n// Line ${i * 10}: function ${["search", "compact", "embed", "dedup"][i % 4]}() { ... }`));
151
+ break;
152
+ case 3:
153
+ msgs.push(makeMsg("assistant", `I found the issue. The ${mods[i % 4]} function doesn't handle edge cases properly. Here's what I suggest:\n\n\`\`\`typescript\nfunction fixed${["Search", "Compact", "Embed", "Dedup"][i % 4]}() {\n if (!input) return null;\n return process(input);\n}\n\`\`\``));
154
+ break;
155
+ case 4:
156
+ msgs.push(makeMsg("user", `That looks good. Can you also fix the ${issues[i % 4]} while you're at it?`));
157
+ break;
158
+ case 5:
159
+ msgs.push(makeMsg("assistant", `Sure. I've updated the ${issues[i % 4]} as well. The changes affect:\n- src/engine.ts\n- src/store.ts`));
160
+ break;
161
+ case 6:
162
+ msgs.push(makeMsg("user", "Run the tests to make sure nothing is broken."));
163
+ break;
164
+ case 7:
165
+ msgs.push(makeMsg("assistant", `All ${150 + i * 3} tests pass. The fix resolved the ${bugs[i % 4]} issue.`));
166
+ break;
167
+ }
168
+ }
169
+ return msgs;
170
+ }
171
+ /** Generate near-duplicate messages with controlled edit distance. */
172
+ export function generateNearDuplicates(base, count, editLevel) {
173
+ const results = [];
174
+ for (let i = 0; i < count; i++) {
175
+ switch (editLevel) {
176
+ case "none":
177
+ results.push(base);
178
+ break;
179
+ case "one-word":
180
+ results.push(base.replace("bug", ["issue", "defect", "error", "problem"][i % 4]));
181
+ break;
182
+ case "minor-rephrase":
183
+ results.push(base
184
+ .replace("Found a bug", [
185
+ "Discovered an issue",
186
+ "Spotted a defect",
187
+ "Located an error",
188
+ "Identified a problem",
189
+ ][i % 4])
190
+ .replace("in the", ["in the", "within the", "inside the", "in our"][i % 4]));
191
+ break;
192
+ case "major-change":
193
+ results.push(`Turn ${i}: ${base.split(" ").reverse().join(" ")}. Additional context: ${"y".repeat(200)}`);
194
+ break;
195
+ }
196
+ }
197
+ return results;
198
+ }
@@ -0,0 +1,112 @@
1
+ /**
2
+ * recall/async.ts — Slice 2 async cross-repo recall.
3
+ *
4
+ * Same dedup/bound/inline contract as `recallAndInline`, but backed by
5
+ * `VectorStore.searchAsync` so it can recall across repos (HNSW NN over the
6
+ * global PGlite index) when `opts.crossRepo` is set. The synchronous
7
+ * `recallAndInline` is unchanged and remains the default per-session path.
8
+ * Inline-window dedupe + token cap (Fix C) apply here too.
9
+ */
10
+ import { vectorSearchAsync, vectorWasInjected, vectorMarkInjected, } from "../vectorStore.js";
11
+ import { estimateBlockTokens } from "../tokens.js";
12
+ import { defaultEmbedder, cosineSimilarity } from "../embedder.js";
13
+ import { formatRecallBlock } from "./format.js";
14
+ /**
15
+ * `store` must provide `searchAsync` (the live VectorStore does). Errors fall
16
+ * back to an empty result — recall is a bonus, never a hard dependency.
17
+ */
18
+ export async function recallAndInlineAsync(opts, store) {
19
+ const limit = opts.limit ?? 3;
20
+ const skip = opts.skipInjected ?? true;
21
+ const maxTokens = opts.recallMaxTokens ?? 0;
22
+ const doWindowDedupe = opts.windowDedupe ?? false;
23
+ const dedupSim = opts.dedupSim ?? 0.9;
24
+ let hits = [];
25
+ try {
26
+ hits = await vectorSearchAsync(store, opts.sessionId, opts.query, limit, {
27
+ crossRepo: opts.crossRepo,
28
+ repoId: opts.repoId,
29
+ });
30
+ }
31
+ catch {
32
+ hits = [];
33
+ }
34
+ // F1: hoist one embedder instance for inline dedupe. defaultEmbedder() is
35
+ // deterministic but creating it per call wastes allocations on large hit sets.
36
+ // (recallAndInline already hoisted this; applying the same fix here.)
37
+ const embedder = defaultEmbedder();
38
+ let liveEmbeddings = [];
39
+ if (doWindowDedupe && opts.liveWindow && opts.liveWindow.length > 0) {
40
+ liveEmbeddings = opts.liveWindow.map((m) => embedder.embed(m));
41
+ }
42
+ const toInject = [];
43
+ let blockTokens = 0;
44
+ // F2: when cross-repo is on but no global index dir could be resolved, skip
45
+ // foreign hits rather than injecting them undeduped — otherwise a foreign
46
+ // checkpoint with no machine-wide injected-set to consult would re-inject in
47
+ // every new session. Same-repo hits (no repoId) are unaffected. Warn once so
48
+ // the silent degradation is observable. (The extension resolver normally
49
+ // supplies a default globalIndexDir, so this is belt-and-braces.)
50
+ const skipCrossRepoHits = !!opts.crossRepo && !opts.globalIndexDir;
51
+ if (skipCrossRepoHits) {
52
+ try {
53
+ console.warn("[mega-compact:recall] cross-repo recall enabled but globalIndexDir is unset — " +
54
+ "skipping cross-repo injection to avoid re-injecting undeduped foreign checkpoints");
55
+ }
56
+ catch {
57
+ /* ignore */
58
+ }
59
+ }
60
+ for (const h of hits) {
61
+ // F2: skip foreign hits when we can't dedup them machine-wide.
62
+ if (skipCrossRepoHits && h.repoId)
63
+ continue;
64
+ if (skip &&
65
+ vectorWasInjected(store, opts.sessionId, h.checkpoint.checkpointId))
66
+ continue;
67
+ // S18: machine-wide injected-set — a foreign checkpoint already injected
68
+ // (in any session) is never re-injected. Only applies to cross-repo hits
69
+ // (same-repo hits have no repoId and are handled by the per-session set).
70
+ if (opts.globalIndexDir && h.repoId) {
71
+ try {
72
+ const { wasInjectedGlobal } = await import("./../store/sqlite.js");
73
+ if (wasInjectedGlobal(h.checkpoint.checkpointId, opts.sessionId, opts.globalIndexDir))
74
+ continue;
75
+ }
76
+ catch {
77
+ /* non-fatal: degrade to per-session injected-set only */
78
+ }
79
+ }
80
+ // Inline dedupe: skip a hit already resident in the live window (F1: hoisted embedder).
81
+ if (doWindowDedupe && liveEmbeddings.length > 0) {
82
+ const hitVec = embedder.embed(h.checkpoint.summary);
83
+ if (liveEmbeddings.some((v) => cosineSimilarity(v, hitVec) >= dedupSim))
84
+ continue;
85
+ }
86
+ // F3: build the hit list first; format ONCE at the end so the block carries
87
+ // exactly one preamble and numbering [1..n] rather than one per hit.
88
+ const partTokens = estimateBlockTokens(h.checkpoint.summary);
89
+ if (maxTokens > 0 && blockTokens + partTokens > maxTokens)
90
+ break;
91
+ toInject.push(h);
92
+ blockTokens += partTokens;
93
+ vectorMarkInjected(store, opts.sessionId, h.checkpoint.checkpointId);
94
+ // S18: record the cross-repo injection machine-wide so it's not re-injected
95
+ // by a later recall (same or different session).
96
+ if (opts.globalIndexDir && h.repoId) {
97
+ try {
98
+ const { markInjectedGlobal } = await import("./../store/sqlite.js");
99
+ markInjectedGlobal(h.checkpoint.checkpointId, h.repoId, opts.sessionId, opts.globalIndexDir);
100
+ }
101
+ catch {
102
+ /* non-fatal */
103
+ }
104
+ }
105
+ }
106
+ // F3: format once — one preamble, correct [1..n] numbering, token cap counted
107
+ // against one preamble (not N). Pass the full toInject array so formatRecallBlock
108
+ // has repoId + score for proper labeling.
109
+ const block = toInject.length > 0 ? formatRecallBlock(toInject) : "";
110
+ const report = toInject.map((h) => ` • ${h.checkpoint.checkpointId} (${h.checkpoint.summary.slice(0, 60).replace(/\n/g, " ")}…)`);
111
+ return { toInject, report, block, empty: toInject.length === 0 };
112
+ }
@@ -0,0 +1,149 @@
1
+ import { rehydrateRaptorTree, isShadowMode } from "../dedup/raptor/index.js";
2
+ import { maxCheckpointTimestamp } from "../store/sqlite.js";
3
+ import { normalizeSessionId } from "../store.js";
4
+ import { cosineSimilarity } from "../embedder.js";
5
+ import { computeRecallMetrics } from "../recallMetrics.js";
6
+ import { Logger } from "../log.js";
7
+ /** Wrap a recall block so the model reads it as restored compacted context. */
8
+ export function formatRecallBlock(hits) {
9
+ if (hits.length === 0)
10
+ return "";
11
+ const parts = hits.map((h, i) => {
12
+ const score = (h.score * 100).toFixed(0);
13
+ // S17: label a cross-repo hit with its source repo (the repoId doubles as
14
+ // that repo's stateDir, so the last path segment is the repo's display
15
+ // name). Same-repo hits (no repoId) stay unlabeled.
16
+ const repoName = h.repoId
17
+ ? ` (from repo ${h.repoId.split("/").filter(Boolean).pop() ?? h.repoId})`
18
+ : "";
19
+ // S42B: a RAPTOR cluster node hit (not a stored checkpoint) is labeled as a
20
+ // hierarchical summary and uses raptorSummary as its body. No Key files line
21
+ // (cluster nodes carry no file list).
22
+ if (h.raptorLevel !== undefined) {
23
+ return (`### Recalled cluster summary [${i + 1}] (level ${h.raptorLevel}, relevance ${score}%)${repoName}\n` +
24
+ `${(h.raptorSummary ?? h.checkpoint.summary).trim()}\n`);
25
+ }
26
+ return (`### Recalled context [${i + 1}] (relevance ${score}%)${repoName}\n` +
27
+ `${h.checkpoint.summary.trim()}\n` +
28
+ (h.checkpoint.filesModified.length
29
+ ? `Key files: ${h.checkpoint.filesModified.join(", ")}.\n`
30
+ : ""));
31
+ });
32
+ return ("The following compacted context was recalled from earlier in this session " +
33
+ "and is relevant to the current request. Treat it as background you already know:\n\n" +
34
+ parts.join("\n"));
35
+ }
36
+ /**
37
+ * S25 Phase-2: format the RAPTOR tree's top-level summary nodes (root + level-1
38
+ * clusters) as a hierarchical overview HEADER. Surfacing the high-level topical
39
+ * structure before the detailed checkpoint hits gives the model a map of what
40
+ * the session has covered. `nodes` are the RAPTOR summary nodes to surface,
41
+ * highest level first (root → level-1 clusters). Returns "" when empty.
42
+ */
43
+ export function formatRaptorBlock(nodes) {
44
+ if (nodes.length === 0)
45
+ return "";
46
+ const parts = nodes.map((n, i) => {
47
+ const score = n.score !== undefined
48
+ ? ` (relevance ${(n.score * 100).toFixed(0)}%)`
49
+ : "";
50
+ const label = n.level === 0
51
+ ? `Session overview [${i + 1}]${score}`
52
+ : `Cluster summary [${i + 1}] (level ${n.level})${score}`;
53
+ return `### ${label}\n${n.summary.trim()}\n`;
54
+ });
55
+ return ("The following hierarchical overview summarizes the structure of this " +
56
+ "session so far. Use it as a map of what has been covered:\n\n" +
57
+ parts.join("\n"));
58
+ }
59
+ /** Format one memory hit for the recall block. Category + score for traceability. */
60
+ export function formatMemoryRecallBlock(hits) {
61
+ if (hits.length === 0)
62
+ return "";
63
+ const parts = hits.map((h, i) => {
64
+ const pct = (h.score * 100).toFixed(0);
65
+ const cat = h.category ? `[${h.category}] ` : "";
66
+ const src = h.label ? ` ${h.label}` : "";
67
+ return `### Recalled memory [${i + 1}] (relevance ${pct}%${src})\n${cat}${h.content.trim()}`;
68
+ });
69
+ return ("The following facts about this project were saved from earlier turns " +
70
+ "and are relevant to the current request. Treat them as established:\n\n" +
71
+ parts.join("\n"));
72
+ }
73
+ /**
74
+ * S25 Phase-2: build the hierarchical overview header for a session. Rehydrates
75
+ * the persisted RAPTOR tree, picks the root + top level-1 cluster nodes by
76
+ * cosine similarity to the query, and formats them via formatRaptorBlock.
77
+ * Returns "" when no tree, stale tree, timedOut tree, or shadow mode. Non-fatal
78
+ * (wrapped in try/catch) — the overview is a bonus; a failure must never block
79
+ * the detailed recall block.
80
+ */
81
+ export function raptorOverviewBlock(store, sessionId, query) {
82
+ try {
83
+ const sid = normalizeSessionId(sessionId);
84
+ // S25 gate: the overview header is part of the RAPTOR serve surface, so it
85
+ // must honor the same contract as raptorSearchHits — shadow mode is
86
+ // logging-only building, not injection.
87
+ if (isShadowMode())
88
+ return "";
89
+ const tree = rehydrateRaptorTree(sid, store.stateDir);
90
+ if (!tree || !tree.rootId || tree.timedOut)
91
+ return "";
92
+ // Freshness: a tree built before the session's latest checkpoint is stale.
93
+ const maxTs = maxCheckpointTimestamp(sid, store.stateDir);
94
+ if (tree.builtAt && tree.builtAt < maxTs)
95
+ return "";
96
+ const root = tree.nodes.get(tree.rootId);
97
+ if (!root)
98
+ return "";
99
+ const qv = store.embedder.embed(query);
100
+ // Root (level 0) first, then the top level-1 clusters by cosine to the query.
101
+ const nodes = [
102
+ {
103
+ summary: root.summary,
104
+ level: root.level,
105
+ score: cosineSimilarity(qv, root.embedding),
106
+ },
107
+ ];
108
+ const level1 = [...tree.nodes.values()]
109
+ .filter((n) => n.level === 1 && n.summary)
110
+ .map((n) => ({
111
+ summary: n.summary,
112
+ level: n.level,
113
+ score: cosineSimilarity(qv, n.embedding),
114
+ }))
115
+ .sort((a, b) => b.score - a.score)
116
+ .slice(0, 3);
117
+ nodes.push(...level1);
118
+ return formatRaptorBlock(nodes);
119
+ }
120
+ catch {
121
+ return ""; // non-fatal: overview is a bonus
122
+ }
123
+ }
124
+ /**
125
+ * B3: Compute recall-quality metrics on the injected hits and log them.
126
+ * Only called when RAG_RECALL_METRICS() is ON. Non-fatal.
127
+ */
128
+ export function scoreAndLogRecallMetrics(query, toInject) {
129
+ try {
130
+ const logger = new Logger();
131
+ const metrics = computeRecallMetrics(query, toInject);
132
+ logger.info("recall_metrics", {
133
+ hitCount: toInject.length,
134
+ score: metrics.score,
135
+ pass: metrics.pass,
136
+ });
137
+ if (!metrics.pass && toInject.length > 0) {
138
+ logger.info("recall_metrics_low_quality", {
139
+ score: metrics.score,
140
+ relevance: metrics.breakdown.relevance,
141
+ coverage: metrics.breakdown.coverage,
142
+ diversity: metrics.breakdown.diversity,
143
+ });
144
+ }
145
+ }
146
+ catch {
147
+ /* non-fatal: metrics never break recall */
148
+ }
149
+ }
@@ -0,0 +1,62 @@
1
+ /**
2
+ * recall/memory.ts — S21 memory recall: durables (decisions, rules,
3
+ * user-saved facts) live in the `memories` table. We mirror the checkpoint
4
+ * recall path: rank by cosine, format a block, respect a token cap so it can
5
+ * never net-inflate the system prompt.
6
+ */
7
+ import { estimateBlockTokens } from "../tokens.js";
8
+ import { formatMemoryRecallBlock } from "./format.js";
9
+ /** Recall top-k durable memories, format into a token-capped block. */
10
+ export async function recallMemoriesAndInline(opts) {
11
+ const limit = opts.limit ?? 5;
12
+ const maxTokens = opts.recallMaxTokens ?? 0;
13
+ const { recallMemories, recallMemoriesCrossRepo } = await import("../memoryRecall.js");
14
+ const hits = await recallMemories(opts.query, opts.stateDir, {
15
+ topK: limit,
16
+ minSimilarity: opts.minSimilarity ?? 0.2,
17
+ });
18
+ // S24 cross-repo augmentation: if same-repo recall is thin, pull additional
19
+ // memories from OTHER repos via the PGlite HNSW index. Non-fatal: a failure
20
+ // degrades to the same-repo hits only.
21
+ const crossHits = [];
22
+ if (opts.crossRepo && hits.length < limit) {
23
+ try {
24
+ const x = await recallMemoriesCrossRepo(opts.query, opts.stateDir, {
25
+ repo: null,
26
+ limit: limit - hits.length,
27
+ crossRepoCosine: opts.crossRepoCosine ?? 0.3,
28
+ });
29
+ for (const h of x)
30
+ crossHits.push(h);
31
+ }
32
+ catch {
33
+ /* non-fatal — cross-repo failure → same-repo only */
34
+ }
35
+ }
36
+ if (hits.length === 0 && crossHits.length === 0)
37
+ return { empty: true, block: "", report: [] };
38
+ // Same incremental token cap pattern as checkpoint recall.
39
+ const parts = [];
40
+ const report = [];
41
+ let blockTokens = 0;
42
+ const pushHit = (content, category, score, label, blockSuffix) => {
43
+ const part = formatMemoryRecallBlock([{ content, category, score, label: blockSuffix }]);
44
+ const partTokens = estimateBlockTokens(part);
45
+ if (maxTokens > 0 && blockTokens + partTokens > maxTokens)
46
+ return false;
47
+ parts.push(part);
48
+ report.push(` • ${label} (${(score * 100).toFixed(0)}%): ${content.slice(0, 60).replace(/\n/g, " ")}…`);
49
+ blockTokens += partTokens;
50
+ return true;
51
+ };
52
+ for (const h of hits) {
53
+ if (!pushHit(h.memory.content, h.memory.category, h.score, `memory#${h.memory.id}`))
54
+ break;
55
+ }
56
+ for (const h of crossHits) {
57
+ const repoLabel = h.repoId.split(/[\\/]/).filter(Boolean).pop() ?? h.repoId;
58
+ if (!pushHit(h.memory.content, h.memory.category, h.score, `memory#${h.memory.id} (from ${repoLabel})`, `from ${repoLabel}`))
59
+ break;
60
+ }
61
+ return { empty: parts.length === 0, block: parts.join("\n"), report };
62
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * recall/reformulate.ts — S57 RAG suite helpers (B1/B2).
3
+ *
4
+ * Each helper is only called when its feature flag (RAG_QUERY_REFORMULATION /
5
+ * RAG_TIERED_ROUTER) is ON; flag-OFF never reaches them. All degrade
6
+ * non-fatally to the standard path on any error.
7
+ */
8
+ import { recall as searchRecall } from "../engine.js";
9
+ import { defaultEmbedder } from "../embedder.js";
10
+ import { reformulateQuery, isVagueQuery } from "../queryReformulation.js";
11
+ import { VAGUE_MIN_WORDS, VAGUE_VERY_SHORT_WORDS } from "../queryReformulation/cache.js";
12
+ import { getTieredRouter } from "../tieredRouter.js";
13
+ /**
14
+ * B1: If the query is vague, reformulate it via embedding-neighbor TF-IDF
15
+ * expansion. Returns the original query when reformulation is not supported
16
+ * or the query is already specific. Non-fatal: any error → original query.
17
+ */
18
+ export function reformulateRecallQuery(query, store, sessionId) {
19
+ try {
20
+ if (!isVagueQuery(query, {
21
+ vagueMinWords: VAGUE_MIN_WORDS,
22
+ vagueVeryShortWords: VAGUE_VERY_SHORT_WORDS,
23
+ }))
24
+ return query;
25
+ // Pre-compute neighbor candidates once. reformulateQuery embeds the query
26
+ // and calls `scan` internally; we return these pre-computed neighbors (same
27
+ // query) so the store needs no by-embedding lookup.
28
+ const { hits } = searchRecall({ sessionId, query, limit: 10, skipInjected: false }, store);
29
+ if (hits.length < 2)
30
+ return query; // too few neighbors for TF-IDF
31
+ const neighbors = hits.map((h) => ({
32
+ id: h.checkpoint.checkpointId,
33
+ score: h.score,
34
+ }));
35
+ const textById = new Map();
36
+ for (const h of hits)
37
+ textById.set(h.checkpoint.checkpointId, h.checkpoint.summary);
38
+ const scan = () => neighbors;
39
+ const corpus = {
40
+ totalDocs: neighbors.length,
41
+ docFreq: (term) => {
42
+ let df = 0;
43
+ for (const text of textById.values()) {
44
+ if (text.toLowerCase().includes(term.toLowerCase()))
45
+ df++;
46
+ }
47
+ return Math.max(df, 1);
48
+ },
49
+ };
50
+ const neighborTexts = (ids) => ids.map((id) => ({ id, text: textById.get(id) ?? "" }));
51
+ const { result } = reformulateQuery(query, defaultEmbedder(), scan, corpus, neighborTexts);
52
+ return result.expanded.length > query.length ? result.expanded : query;
53
+ }
54
+ catch {
55
+ return query; // non-fatal: fall back to original query
56
+ }
57
+ }
58
+ /**
59
+ * B2: Synchronous tiered recall. The TieredRouter.route() is async, so the
60
+ * sync path can only peek the L0 in-memory cache; on miss it falls through to
61
+ * the standard sync vector scan. The router's L1/L2 value is realized on the
62
+ * async path (recallAndInlineAsync). Non-fatal.
63
+ */
64
+ export function runTieredRecall(query, sessionId, limit, skip, store) {
65
+ try {
66
+ const router = getTieredRouter();
67
+ if (!router) {
68
+ const result = searchRecall({ sessionId, query, limit, skipInjected: skip }, store);
69
+ return { newHits: result.newHits, tier: "off" };
70
+ }
71
+ // Peek the L0 in-memory cache synchronously; fall through on miss.
72
+ const cached = router.peekCache(sessionId, query, limit);
73
+ if (cached && cached.length > 0)
74
+ return { newHits: cached, tier: "L0-cache" };
75
+ const result = searchRecall({ sessionId, query, limit, skipInjected: skip }, store);
76
+ return { newHits: result.newHits, tier: "sync-fallback" };
77
+ }
78
+ catch {
79
+ const result = searchRecall({ sessionId, query, limit, skipInjected: skip }, store);
80
+ return { newHits: result.newHits, tier: "fallback-error" };
81
+ }
82
+ }