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,163 @@
1
+ /**
2
+ * context-handler/afterCompact.ts — post-compaction DB persistence + maintenance.
3
+ *
4
+ * Extracted from context-handler.ts (delegate-shell split). Runs after a live
5
+ * compaction: writes the checkpoint_epoch row (deterministic nonce), stamps turn
6
+ * epochs, rebuilds the auto-categorizing wiki, seeds the topic model from
7
+ * raw_transcript, and fire-and-forgets the dedup pipeline. All best-effort +
8
+ * non-fatal — a failure never breaks the agent loop.
9
+ */
10
+ import { openStore, writeCheckpointEpoch, } from "../../../src/store/sqlite.js";
11
+ import { epochIdFor } from "../../../src/mirror/epoch.js";
12
+ import { stampTurnsEpochFor } from "../../mega-turn-store.js";
13
+ import { TurnsConfig } from "../../../src/config/turns.js";
14
+ import { openTurnStore } from "../../../src/store/turns/connection.js";
15
+ import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, } from "../../../src/topics/index.js";
16
+ import { TrigramEmbedder } from "../../../src/embedder.js";
17
+ /**
18
+ * Persist the checkpoint_epoch, stamp turns, rebuild the auto-wiki, seed the
19
+ * topic model, and dedup — gated on dbMirror. Non-fatal end-to-end.
20
+ */
21
+ export async function persistEpochAndMaintain(runtime, config, ran) {
22
+ // S27 DB-mirror: write checkpoint_epoch with deterministic nonce.
23
+ // This makes the cache key stable across identical compactions.
24
+ if (config.dbMirror) {
25
+ try {
26
+ const db = openStore(runtime.currentStateDir);
27
+ const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
28
+ const epoch = {
29
+ epochId: epochIdFor(cpId),
30
+ sessionId: runtime.rt.sessionId,
31
+ startedSeq: 0,
32
+ committedSeq: ran.result.compactedFrom,
33
+ checkpointId: cpId,
34
+ cutIndex: ran.result.compactedFrom,
35
+ summaryMessageText: ran.result.summary,
36
+ createdAt: Date.now(),
37
+ };
38
+ writeCheckpointEpoch(db, epoch);
39
+ // S50B: link this session's turns to the epoch that just compacted
40
+ // them (compression-by-conversation-epoch metrics). Isolated-store
41
+ // only; best-effort + non-fatal.
42
+ try {
43
+ stampTurnsEpochFor(config, runtime.rt.sessionId, epoch.epochId, runtime.currentStateDir);
44
+ }
45
+ catch {
46
+ /* non-fatal: epoch stamping never breaks compaction */
47
+ }
48
+ // S51B: auto-categorizing wiki rebuild — every Nth compaction, derived
49
+ // from real context_chunks embeddings. Isolated-store only, gated on
50
+ // AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
51
+ // Fire regardless of dbMirror — context_chunks is the isolated store.
52
+ // Uses the already-open db when inside the dbMirror block; opens its own
53
+ // connection otherwise.
54
+ // from real context_chunks embeddings. Isolated-store only, gated on
55
+ // AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
56
+ try {
57
+ if (config.autoWikiEnabled && config.turnsDbEnabled) {
58
+ const every = Math.max(1, TurnsConfig.WIKI_REBUILD_EVERY_N_COMPACTS);
59
+ const tdb = openTurnStore(runtime.currentStateDir);
60
+ const n = bumpWikiCompactCounter(tdb);
61
+ if (n % every === 0) {
62
+ const model = buildTopicModel(db, {
63
+ kRange: [TurnsConfig.WIKI_K_MIN, TurnsConfig.WIKI_K_MAX],
64
+ labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
65
+ restarts: 5,
66
+ seed: 0x9e3779b9,
67
+ });
68
+ createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
69
+ runtime.logger.info("wiki_rebuild", {
70
+ clusterCount: model.k,
71
+ totalChunks: model.totalChunks,
72
+ method: "kmeans+tfidf",
73
+ criterion: model.criterion,
74
+ silhouetteScore: model.silhouetteScore,
75
+ uncalibrated: false,
76
+ });
77
+ }
78
+ }
79
+ }
80
+ catch (wikiErr) {
81
+ runtime.logger.warn("wiki_rebuild_failed", {
82
+ error: String(wikiErr),
83
+ });
84
+ }
85
+ // D1: seed the topic model from raw_transcript when context_chunks is
86
+ // thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
87
+ // Seeds buildTopicModel with on-the-fly trigram embeddings from
88
+ // recent raw_transcript rows for the current session.
89
+ try {
90
+ if (config.autoWikiEnabled &&
91
+ config.turnsDbEnabled &&
92
+ TurnsConfig.WIKI_SEED_FROM_TURNS) {
93
+ const floor = 50;
94
+ const countRow = db
95
+ .prepare(`SELECT COUNT(*) AS cnt FROM context_chunks WHERE session_id = ?`)
96
+ .get(runtime.rt.sessionId);
97
+ const chunkCount = countRow?.cnt ?? 0;
98
+ if (chunkCount < floor) {
99
+ const transcriptRows = db
100
+ .prepare(`SELECT DISTINCT content_bytes
101
+ FROM raw_transcript
102
+ WHERE session_id = ?
103
+ AND length(content_bytes) > 10
104
+ ORDER BY seq ASC
105
+ LIMIT 200`)
106
+ .all(runtime.rt.sessionId);
107
+ if (transcriptRows.length > 0) {
108
+ const embedder = new TrigramEmbedder();
109
+ const seedChunks = [];
110
+ for (let i = 0; i < transcriptRows.length; i++) {
111
+ const text = transcriptRows[i].content_bytes.trim();
112
+ if (text.length === 0)
113
+ continue;
114
+ const vec = embedder.embed(text);
115
+ seedChunks.push({
116
+ chunkId: `seed_transcript_${i}`,
117
+ sessionId: runtime.rt.sessionId,
118
+ vec,
119
+ text,
120
+ });
121
+ }
122
+ if (seedChunks.length > 0) {
123
+ const model = buildTopicModel(db, {
124
+ kRange: [
125
+ TurnsConfig.WIKI_K_MIN,
126
+ TurnsConfig.WIKI_K_MAX,
127
+ ],
128
+ labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
129
+ restarts: 5,
130
+ seed: 0x9e3779b9,
131
+ }, seedChunks);
132
+ createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
133
+ runtime.logger.info("wiki_seed", {
134
+ clusterCount: model.k,
135
+ sourceChunks: seedChunks.length,
136
+ totalChunks: model.totalChunks,
137
+ method: "kmeans+tfidf",
138
+ });
139
+ }
140
+ }
141
+ }
142
+ }
143
+ }
144
+ catch (seedErr) {
145
+ runtime.logger.warn("wiki_seed_failed", {
146
+ error: String(seedErr),
147
+ });
148
+ }
149
+ // S27 Task 6: Fire-and-forget dedup pipeline.
150
+ // Deduplicates raw_transcript rows for the compacted range.
151
+ try {
152
+ const { dedupTranscript } = await import("../../../src/mirror/dedup.js");
153
+ dedupTranscript(db, runtime.rt.sessionId, 0, ran.result.compactedFrom);
154
+ }
155
+ catch (_dedupErr) {
156
+ // Fire-and-forget: dedup failure is non-fatal
157
+ }
158
+ }
159
+ catch (e) {
160
+ runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
161
+ }
162
+ }
163
+ }
@@ -0,0 +1,12 @@
1
+ /** Best-effort text extraction from an AgentMessage for analytics/logging. */
2
+ export function messageContentText(m) {
3
+ const c = m.content;
4
+ if (typeof c === "string")
5
+ return c;
6
+ if (Array.isArray(c)) {
7
+ return c
8
+ .map((b) => (b && typeof b === "object" && "text" in b ? String(b.text ?? "") : ""))
9
+ .join(" ");
10
+ }
11
+ return "";
12
+ }
@@ -0,0 +1,46 @@
1
+ import { stagedForTail, withRecallTail } from "../recall-tail.js";
2
+ import { buildSeparatedPrompt, buildCacheOptimizedPrompt } from "../separated-prompt.js";
3
+ import { messageContentText } from "./messageText.js";
4
+ /**
5
+ * Build the tail injection closure. Returns undefined when nothing is staged
6
+ * (or the flags are OFF) so the caller falls through to its normal return.
7
+ */
8
+ export function buildTailResult(runtime, config, messages) {
9
+ // S53: helper to inject the staged recall/memory block as a user-role
10
+ // tail message at any view-return point. Returns undefined when nothing
11
+ // is staged (or the flag is OFF) so the caller falls through to its
12
+ // normal return. The F3 mirror append (above the gates) runs on the
13
+ // REAL transcript before any view is built, so the injected tail never
14
+ // reaches raw_transcript (PREVENT-PI: append-only, view-only).
15
+ const tailResult = (msgs) => {
16
+ const base = msgs ?? messages;
17
+ if (!stagedForTail(runtime, config) && !config.messageSeparation && !config.cacheStriping)
18
+ return undefined;
19
+ let result = stagedForTail(runtime, config)
20
+ ? withRecallTail(base, runtime, config)
21
+ : base;
22
+ if (config.cacheStriping) {
23
+ result = buildCacheOptimizedPrompt(result);
24
+ }
25
+ else if (config.messageSeparation) {
26
+ result = buildSeparatedPrompt(result);
27
+ }
28
+ // P2.5: log prefix stability (fire-and-forget, non-fatal).
29
+ // tailResult is sync, so use .then().catch() on the dynamic import.
30
+ if (result.length > 1) {
31
+ import("../../../src/cache-stripe-impl.js").then(({ computeStabilityScore }) => {
32
+ const stableScore = computeStabilityScore({ content: messageContentText(result[0] ?? result[0]), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 }, result.slice(0, 2).map((m) => ({ content: messageContentText(m), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 })));
33
+ runtime.logger.info("prefix_stability", {
34
+ stableScore: Number.isFinite(stableScore) ? stableScore : 0,
35
+ prefixMessages: result.length,
36
+ separation: config.messageSeparation ? "v2" : "off",
37
+ striping: config.cacheStriping ? "v3" : "off",
38
+ });
39
+ }).catch(() => {
40
+ // Non-fatal: stability logging is best-effort.
41
+ });
42
+ }
43
+ return { messages: result };
44
+ };
45
+ return tailResult;
46
+ }
@@ -1,32 +1,14 @@
1
- import { openStore, writeCheckpointEpoch, } from "../../src/store/sqlite.js";
2
- import { epochIdFor } from "../../src/mirror/epoch.js";
1
+ import { openStore, } from "../../src/store/sqlite.js";
3
2
  import { autoCompactCheck } from "../../src/compact.js";
4
3
  import { estimateSessionTokens } from "../../src/tokens.js";
5
4
  import { runCompact, piCompactWouldNoop } from "../mega-pipeline.js";
6
- import { stampTurnsEpochFor } from "../mega-turn-store.js";
7
- import { TurnsConfig } from "../../src/config/turns.js";
8
- import { openTurnStore } from "../../src/store/turns/connection.js";
9
- import { buildTopicModel, createTopicStore, bumpWikiCompactCounter, } from "../../src/topics/index.js";
10
- import { TrigramEmbedder } from "../../src/embedder.js";
11
- import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
12
5
  import { pressureFromPct, pressureRatio, } from "../mega-config.js";
13
6
  import { appendMirrorMessages } from "./mirror-append.js";
14
- import { stagedForTail, withRecallTail } from "./recall-tail.js";
15
- import { buildSeparatedPrompt, buildCacheOptimizedPrompt } from "./separated-prompt.js";
16
- /** Best-effort text extraction from an AgentMessage for analytics/logging.
17
- * AgentMessage is a discriminated union; .content exists only on some
18
- * variants (user/assistant/toolResult/custom). Narrow by role, never assume. */
19
- function messageContentText(m) {
20
- const c = m.content;
21
- if (typeof c === "string")
22
- return c;
23
- if (Array.isArray(c)) {
24
- return c
25
- .map((b) => (b && typeof b === "object" && "text" in b ? String(b.text ?? "") : ""))
26
- .join(" ");
27
- }
28
- return "";
29
- }
7
+ import { epochIdFor } from "../../src/mirror/epoch.js";
8
+ import { computeLiveTrimCut, liveTrimSummaryMessage } from "../mega-trim.js";
9
+ import { messageContentText } from "./context-handler/messageText.js";
10
+ import { buildTailResult } from "./context-handler/tailResult.js";
11
+ import { persistEpochAndMaintain } from "./context-handler/afterCompact.js";
30
12
  /** Register the context event handler (live-trim auto-trigger). */
31
13
  export function registerContextHandler(pi, runtime, config) {
32
14
  // ---- Auto-trigger: live trim (compact and continue) + native durable ----
@@ -50,39 +32,8 @@ export function registerContextHandler(pi, runtime, config) {
50
32
  // S53: helper to inject the staged recall/memory block as a user-role
51
33
  // tail message at any view-return point. Returns undefined when nothing
52
34
  // is staged (or the flag is OFF) so the caller falls through to its
53
- // normal return. The F3 mirror append (above the gates) runs on the
54
- // REAL transcript before any view is built, so the injected tail never
55
- // reaches raw_transcript (PREVENT-PI: append-only, view-only).
56
- const tailResult = (msgs) => {
57
- const base = msgs ?? messages;
58
- if (!stagedForTail(runtime, config) && !config.messageSeparation && !config.cacheStriping)
59
- return undefined;
60
- let result = stagedForTail(runtime, config)
61
- ? withRecallTail(base, runtime, config)
62
- : base;
63
- if (config.cacheStriping) {
64
- result = buildCacheOptimizedPrompt(result);
65
- }
66
- else if (config.messageSeparation) {
67
- result = buildSeparatedPrompt(result);
68
- }
69
- // P2.5: log prefix stability (fire-and-forget, non-fatal).
70
- // tailResult is sync, so use .then().catch() on the dynamic import.
71
- if (result.length > 1) {
72
- import("../../src/cache-stripe-impl.js").then(({ computeStabilityScore }) => {
73
- const stableScore = computeStabilityScore({ content: messageContentText(result[0] ?? result[0]), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 }, result.slice(0, 2).map((m) => ({ content: messageContentText(m), chunkId: "prefix", accessCount: 0, lastAccessedAt: 0 })));
74
- runtime.logger.info("prefix_stability", {
75
- stableScore: Number.isFinite(stableScore) ? stableScore : 0,
76
- prefixMessages: result.length,
77
- separation: config.messageSeparation ? "v2" : "off",
78
- striping: config.cacheStriping ? "v3" : "off",
79
- });
80
- }).catch(() => {
81
- // Non-fatal: stability logging is best-effort.
82
- });
83
- }
84
- return { messages: result };
85
- };
35
+ // normal return.
36
+ const tailResult = buildTailResult(runtime, config, messages);
86
37
  // Always track context for the dashboard/widget, even when auto is off.
87
38
  // (v0.8 regression: !config.auto gate sat above this, leaving ctx stats
88
39
  // null -> widget '?% / ?/?' when auto disabled. Track first, THEN gate.)
@@ -249,147 +200,9 @@ export function registerContextHandler(pi, runtime, config) {
249
200
  }
250
201
  return tailResult() ?? undefined;
251
202
  }
252
- // S27 DB-mirror: write checkpoint_epoch with deterministic nonce.
253
- // This makes the cache key stable across identical compactions.
254
- if (config.dbMirror) {
255
- try {
256
- const db = openStore(runtime.currentStateDir);
257
- const cpId = ran.result.checkpointId ?? `epoch-${Date.now()}`;
258
- const epoch = {
259
- epochId: epochIdFor(cpId),
260
- sessionId: runtime.rt.sessionId,
261
- startedSeq: 0,
262
- committedSeq: ran.result.compactedFrom,
263
- checkpointId: cpId,
264
- cutIndex: ran.result.compactedFrom,
265
- summaryMessageText: ran.result.summary,
266
- createdAt: Date.now(),
267
- };
268
- writeCheckpointEpoch(db, epoch);
269
- // S50B: link this session's turns to the epoch that just compacted
270
- // them (compression-by-conversation-epoch metrics). Isolated-store
271
- // only; best-effort + non-fatal.
272
- try {
273
- stampTurnsEpochFor(config, runtime.rt.sessionId, epoch.epochId, runtime.currentStateDir);
274
- }
275
- catch {
276
- /* non-fatal: epoch stamping never breaks compaction */
277
- }
278
- // S51B: auto-categorizing wiki rebuild — every Nth compaction, derived
279
- // from real context_chunks embeddings. Isolated-store only, gated on
280
- // AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
281
- // Fire regardless of dbMirror — context_chunks is the isolated store.
282
- // Uses the already-open db when inside the dbMirror block; opens its own
283
- // connection otherwise.
284
- // from real context_chunks embeddings. Isolated-store only, gated on
285
- // AUTO_WIKI_ENABLED; best-effort + non-fatal (never breaks compaction).
286
- try {
287
- if (config.autoWikiEnabled && config.turnsDbEnabled) {
288
- const every = Math.max(1, TurnsConfig.WIKI_REBUILD_EVERY_N_COMPACTS);
289
- const tdb = openTurnStore(runtime.currentStateDir);
290
- const n = bumpWikiCompactCounter(tdb);
291
- if (n % every === 0) {
292
- const model = buildTopicModel(db, {
293
- kRange: [TurnsConfig.WIKI_K_MIN, TurnsConfig.WIKI_K_MAX],
294
- labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
295
- restarts: 5,
296
- seed: 0x9e3779b9,
297
- });
298
- createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
299
- runtime.logger.info("wiki_rebuild", {
300
- clusterCount: model.k,
301
- totalChunks: model.totalChunks,
302
- method: "kmeans+tfidf",
303
- criterion: model.criterion,
304
- silhouetteScore: model.silhouetteScore,
305
- uncalibrated: false,
306
- });
307
- }
308
- }
309
- }
310
- catch (wikiErr) {
311
- runtime.logger.warn("wiki_rebuild_failed", {
312
- error: String(wikiErr),
313
- });
314
- }
315
- // D1: seed the topic model from raw_transcript when context_chunks is
316
- // thin (pre-compaction). Gated on WIKI_SEED_FROM_TURNS; non-fatal.
317
- // Seeds buildTopicModel with on-the-fly trigram embeddings from
318
- // recent raw_transcript rows for the current session.
319
- try {
320
- if (config.autoWikiEnabled &&
321
- config.turnsDbEnabled &&
322
- TurnsConfig.WIKI_SEED_FROM_TURNS) {
323
- const floor = 50;
324
- const countRow = db
325
- .prepare(`SELECT COUNT(*) AS cnt FROM context_chunks WHERE session_id = ?`)
326
- .get(runtime.rt.sessionId);
327
- const chunkCount = countRow?.cnt ?? 0;
328
- if (chunkCount < floor) {
329
- const transcriptRows = db
330
- .prepare(`SELECT DISTINCT content_bytes
331
- FROM raw_transcript
332
- WHERE session_id = ?
333
- AND length(content_bytes) > 10
334
- ORDER BY seq ASC
335
- LIMIT 200`)
336
- .all(runtime.rt.sessionId);
337
- if (transcriptRows.length > 0) {
338
- const embedder = new TrigramEmbedder();
339
- const seedChunks = [];
340
- for (let i = 0; i < transcriptRows.length; i++) {
341
- const text = transcriptRows[i].content_bytes.trim();
342
- if (text.length === 0)
343
- continue;
344
- const vec = embedder.embed(text);
345
- seedChunks.push({
346
- chunkId: `seed_transcript_${i}`,
347
- sessionId: runtime.rt.sessionId,
348
- vec,
349
- text,
350
- });
351
- }
352
- if (seedChunks.length > 0) {
353
- const model = buildTopicModel(db, {
354
- kRange: [
355
- TurnsConfig.WIKI_K_MIN,
356
- TurnsConfig.WIKI_K_MAX,
357
- ],
358
- labelTopTerms: TurnsConfig.WIKI_LABEL_TOP_TERMS,
359
- restarts: 5,
360
- seed: 0x9e3779b9,
361
- }, seedChunks);
362
- createTopicStore(runtime.currentStateDir).replaceTopicModel(model);
363
- runtime.logger.info("wiki_seed", {
364
- clusterCount: model.k,
365
- sourceChunks: seedChunks.length,
366
- totalChunks: model.totalChunks,
367
- method: "kmeans+tfidf",
368
- });
369
- }
370
- }
371
- }
372
- }
373
- }
374
- catch (seedErr) {
375
- runtime.logger.warn("wiki_seed_failed", {
376
- error: String(seedErr),
377
- });
378
- }
379
- // S27 Task 6: Fire-and-forget dedup pipeline.
380
- // Deduplicates raw_transcript rows for the compacted range.
381
- try {
382
- const { dedupTranscript } = await import("../../src/mirror/dedup.js");
383
- dedupTranscript(db, runtime.rt.sessionId, 0, ran.result.compactedFrom);
384
- }
385
- catch (_dedupErr) {
386
- // Fire-and-forget: dedup failure is non-fatal
387
- }
388
- }
389
- catch (e) {
390
- runtime.logger.warn("db-mirror-epoch-fail", { error: String(e) });
391
- }
392
- }
203
+ // S27 DB-mirror: write checkpoint_epoch + stamp turn epochs + auto-wiki +
204
+ // topic seed + fire-and-forget dedup. Best-effort + non-fatal.
205
+ await persistEpochAndMaintain(runtime, config, ran);
393
206
  // LEGACY path (rollback): v0.4.28 ctx.compact() + the no-op gate. The
394
207
  // manual compact path aborts the in-flight turn — only used behind the flag.
395
208
  // Read live from env (in addition to the load-time config) so the flag can be
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared helpers for the separated-prompt.test split files.
3
+ * Extracted from extensions/mega-events/separated-prompt.test.ts.
4
+ */
5
+ import { mkdtempSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { tmpdir } from "node:os";
8
+ import { DatabaseSync } from "node:sqlite";
9
+ import { initSchema } from "../../../src/store/sqlite/schema.js";
10
+ export function asR(arr) {
11
+ return arr;
12
+ }
13
+ /** Create a temp DB with schema initialized, returns db + dir. */
14
+ export function createTestDb() {
15
+ const dir = mkdtempSync(join(tmpdir(), "separated-prompt-test-"));
16
+ const db = new DatabaseSync(join(dir, "sqlite.db"));
17
+ db.exec("PRAGMA journal_mode=WAL");
18
+ db.exec("PRAGMA foreign_keys=ON");
19
+ initSchema(db);
20
+ return { db, dir };
21
+ }
22
+ /** Helper: create an AgentMessage-like object. */
23
+ export function msg(role, content, extra) {
24
+ return { role, content, ...extra };
25
+ }
@@ -98,3 +98,5 @@ export const RAG_TIERED_ROUTER = () => ragFlag("MEGACOMPACT_TIERED_ROUTER");
98
98
  export const RAG_RECALL_METRICS = () => ragFlag("MEGACOMPACT_RECALL_METRICS");
99
99
  /** B4: Memory graph traversal (dashboard-oriented). */
100
100
  export const RAG_MEMORY_GRAPH = () => ragFlag("MEGACOMPACT_MEMORY_GRAPH");
101
+ /** B5: HyDE — generate a hypothetical answer doc via LLM (HttpEmbedder only). Default OFF. */
102
+ export const RAG_HYDE_ENABLED = () => ragFlag("MEGACOMPACT_HYDE_ENABLED");
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Shared test fixtures/harness for the dedup-engine split test files.
3
+ *
4
+ * Extracted from dedup-engine.test.ts: tmp-dir lifecycle (beforeEach/afterEach),
5
+ * store construction, message builders, and the compact + okReason helpers.
6
+ * `currentTmpDir` is module-scoped per test-file subprocess (the runner isolates
7
+ * each file in its own node --test process), so tests never collide.
8
+ */
9
+ import { beforeEach, afterEach } from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import os from "os";
14
+ import { compactSession } from "../engine.js";
15
+ import { VectorStore } from "../vectorStore.js";
16
+ import { loadDedupConfig } from "../config/dedup.js";
17
+ function mkTmpDir() {
18
+ return fs.mkdtempSync(path.join(os.tmpdir(), "mc-dedup-"));
19
+ }
20
+ let currentTmpDir;
21
+ beforeEach(() => {
22
+ currentTmpDir = mkTmpDir();
23
+ });
24
+ afterEach(() => {
25
+ if (currentTmpDir && fs.existsSync(currentTmpDir)) {
26
+ fs.rmSync(currentTmpDir, { recursive: true, force: true });
27
+ }
28
+ currentTmpDir = undefined;
29
+ });
30
+ function baseConfig() {
31
+ return loadDedupConfig();
32
+ }
33
+ export function makeStore(over = {}) {
34
+ return new VectorStore({
35
+ stateDir: currentTmpDir,
36
+ config: { ...baseConfig(), ...over },
37
+ });
38
+ }
39
+ export function makeMsg(role, text) {
40
+ return { role, text };
41
+ }
42
+ export function buildConversation(n, prefix = "turn") {
43
+ const out = [];
44
+ for (let i = 0; i < n; i++) {
45
+ const role = i % 2 === 0 ? "user" : "assistant";
46
+ out.push(makeMsg(role, `${prefix} ${i + 1}: ${role} discusses implementation of feature ${i + 1} in src/module${i + 1}.ts and considers tradeoffs.`));
47
+ }
48
+ return out;
49
+ }
50
+ export function compactFull(store, sessionId, messages, keepFrom) {
51
+ return compactSession({ sessionId, messages, keepFrom: keepFrom ?? messages.length }, store);
52
+ }
53
+ export function okReason(reason, expected) {
54
+ assert.ok(reason !== undefined && expected.includes(reason), `expected dedupReason one of ${expected.join(", ")}, got ${reason}`);
55
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Shared helpers for the src/e2e.test split files.
3
+ *
4
+ * Extracted from the top of src/e2e.test.ts: isolated temp-store management,
5
+ * the config-overridable VectorStore factory (store), the message builder
6
+ * (msg), and the direct SQLite seeder (seedDirect) that bypasses online dedup.
7
+ *
8
+ * Relative paths are one directory deeper than the original file, hence
9
+ * `../vectorStore.js` etc.
10
+ */
11
+ import { mkdtempSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { VectorStore, computeRegionHash } from "../vectorStore.js";
15
+ import { loadDedupConfig } from "../config/dedup.js";
16
+ import { defaultEmbedder } from "../embedder.js";
17
+ import { upsertCheckpoint } from "../store/sqlite.js";
18
+ export const baseTmp = mkdtempSync(join(tmpdir(), "mc-e2e-"));
19
+ let counter = 0;
20
+ export function storeDir() {
21
+ return join(baseTmp, `run-${counter++}`);
22
+ }
23
+ /** Build an isolated VectorStore with a fresh state dir + optional config overrides. */
24
+ export function store(over = {}) {
25
+ const dir = storeDir();
26
+ const config = { ...loadDedupConfig(), ...over };
27
+ return new VectorStore({ stateDir: dir, config });
28
+ }
29
+ export function msg(role, text, toolName, input, output) {
30
+ return toolName
31
+ ? { role, text, toolName, input: input ?? text, output: output ?? text }
32
+ : { role, text };
33
+ }
34
+ /** Seed a checkpoint directly into SQLite (bypasses online dedup tiers). */
35
+ export function seedDirect(dir, sessionId, rows) {
36
+ const e = defaultEmbedder();
37
+ for (const r of rows) {
38
+ const cp = {
39
+ checkpointId: r.id,
40
+ sessionId,
41
+ summary: r.text,
42
+ keyDecisions: [],
43
+ nextSteps: [],
44
+ filesModified: [],
45
+ tokenEstimate: r.tok,
46
+ regionHash: computeRegionHash(r.text),
47
+ embedding: e.embed(r.text),
48
+ timestamp: r.ts ?? 1,
49
+ };
50
+ upsertCheckpoint(cp, dir);
51
+ }
52
+ }
@@ -55,6 +55,7 @@ function fnv1a(str) {
55
55
  * from corrupting stored vectors. Set MEGACOMPACT_EMBED_CACHE=0 to disable.
56
56
  */
57
57
  export class TrigramEmbedder {
58
+ kind = "trigram";
58
59
  dim;
59
60
  seed;
60
61
  /** @type {Map<string, Vector>} */
@@ -190,6 +190,7 @@ try {
190
190
  }
191
191
  `;
192
192
  export class HttpEmbedder {
193
+ kind = "http";
193
194
  url;
194
195
  apiKey;
195
196
  headers;
@@ -203,6 +204,11 @@ export class HttpEmbedder {
203
204
  get dim() {
204
205
  return this.resolvedDim;
205
206
  }
207
+ /** Derive the Ollama /api/chat endpoint from the embedding endpoint's origin
208
+ * (same host:port as the BYO embedding server). Used by HyDE (src/hyde.ts). */
209
+ get chatUrl() {
210
+ return new URL("/api/chat", this.url).href;
211
+ }
206
212
  embed(text) {
207
213
  const body = JSON.stringify({ input: [text] });
208
214
  const headers = {