@oni.bot/core 1.0.3 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (146) hide show
  1. package/dist/checkpointers/postgres.d.ts.map +1 -1
  2. package/dist/checkpointers/postgres.js +2 -1
  3. package/dist/checkpointers/postgres.js.map +1 -1
  4. package/dist/cli/inspect.d.ts.map +1 -1
  5. package/dist/cli/inspect.js +4 -2
  6. package/dist/cli/inspect.js.map +1 -1
  7. package/dist/coordination/request-reply.d.ts +11 -2
  8. package/dist/coordination/request-reply.d.ts.map +1 -1
  9. package/dist/coordination/request-reply.js.map +1 -1
  10. package/dist/events/bus.d.ts.map +1 -1
  11. package/dist/events/bus.js +1 -0
  12. package/dist/events/bus.js.map +1 -1
  13. package/dist/graph.d.ts +11 -1
  14. package/dist/graph.d.ts.map +1 -1
  15. package/dist/graph.js +4 -2
  16. package/dist/graph.js.map +1 -1
  17. package/dist/harness/agent-loop.d.ts +1 -7
  18. package/dist/harness/agent-loop.d.ts.map +1 -1
  19. package/dist/harness/agent-loop.js +2 -642
  20. package/dist/harness/agent-loop.js.map +1 -1
  21. package/dist/harness/loop/hooks.d.ts +7 -0
  22. package/dist/harness/loop/hooks.d.ts.map +1 -0
  23. package/dist/harness/loop/hooks.js +46 -0
  24. package/dist/harness/loop/hooks.js.map +1 -0
  25. package/dist/harness/loop/index.d.ts +8 -0
  26. package/dist/harness/loop/index.d.ts.map +1 -0
  27. package/dist/harness/loop/index.js +257 -0
  28. package/dist/harness/loop/index.js.map +1 -0
  29. package/dist/harness/loop/inference.d.ts +19 -0
  30. package/dist/harness/loop/inference.d.ts.map +1 -0
  31. package/dist/harness/loop/inference.js +121 -0
  32. package/dist/harness/loop/inference.js.map +1 -0
  33. package/dist/harness/loop/memory.d.ts +22 -0
  34. package/dist/harness/loop/memory.d.ts.map +1 -0
  35. package/dist/harness/loop/memory.js +73 -0
  36. package/dist/harness/loop/memory.js.map +1 -0
  37. package/dist/harness/loop/safety.d.ts +8 -0
  38. package/dist/harness/loop/safety.d.ts.map +1 -0
  39. package/dist/harness/loop/safety.js +21 -0
  40. package/dist/harness/loop/safety.js.map +1 -0
  41. package/dist/harness/loop/tools.d.ts +24 -0
  42. package/dist/harness/loop/tools.d.ts.map +1 -0
  43. package/dist/harness/loop/tools.js +184 -0
  44. package/dist/harness/loop/tools.js.map +1 -0
  45. package/dist/harness/loop/types.d.ts +7 -0
  46. package/dist/harness/loop/types.d.ts.map +1 -0
  47. package/dist/harness/loop/types.js +9 -0
  48. package/dist/harness/loop/types.js.map +1 -0
  49. package/dist/harness/memory/fs-compat.d.ts +3 -0
  50. package/dist/harness/memory/fs-compat.d.ts.map +1 -0
  51. package/dist/harness/memory/fs-compat.js +26 -0
  52. package/dist/harness/memory/fs-compat.js.map +1 -0
  53. package/dist/harness/memory/index.d.ts +105 -0
  54. package/dist/harness/memory/index.d.ts.map +1 -0
  55. package/dist/harness/memory/index.js +491 -0
  56. package/dist/harness/memory/index.js.map +1 -0
  57. package/dist/harness/memory/prompter.d.ts +7 -0
  58. package/dist/harness/memory/prompter.d.ts.map +1 -0
  59. package/dist/harness/memory/prompter.js +24 -0
  60. package/dist/harness/memory/prompter.js.map +1 -0
  61. package/dist/harness/memory/ranker.d.ts +15 -0
  62. package/dist/harness/memory/ranker.d.ts.map +1 -0
  63. package/dist/harness/memory/ranker.js +72 -0
  64. package/dist/harness/memory/ranker.js.map +1 -0
  65. package/dist/harness/memory/scanner.d.ts +26 -0
  66. package/dist/harness/memory/scanner.d.ts.map +1 -0
  67. package/dist/harness/memory/scanner.js +187 -0
  68. package/dist/harness/memory/scanner.js.map +1 -0
  69. package/dist/harness/memory/types.d.ts +50 -0
  70. package/dist/harness/memory/types.d.ts.map +1 -0
  71. package/dist/harness/memory/types.js +7 -0
  72. package/dist/harness/memory/types.js.map +1 -0
  73. package/dist/harness/memory-loader.d.ts +2 -149
  74. package/dist/harness/memory-loader.d.ts.map +1 -1
  75. package/dist/harness/memory-loader.js +1 -713
  76. package/dist/harness/memory-loader.js.map +1 -1
  77. package/dist/hitl/interrupt.d.ts.map +1 -1
  78. package/dist/hitl/interrupt.js +2 -1
  79. package/dist/hitl/interrupt.js.map +1 -1
  80. package/dist/prebuilt/react-agent.d.ts.map +1 -1
  81. package/dist/prebuilt/react-agent.js +6 -2
  82. package/dist/prebuilt/react-agent.js.map +1 -1
  83. package/dist/pregel/checkpointing.d.ts +12 -0
  84. package/dist/pregel/checkpointing.d.ts.map +1 -0
  85. package/dist/pregel/checkpointing.js +60 -0
  86. package/dist/pregel/checkpointing.js.map +1 -0
  87. package/dist/pregel/execution.d.ts +7 -0
  88. package/dist/pregel/execution.d.ts.map +1 -0
  89. package/dist/pregel/execution.js +178 -0
  90. package/dist/pregel/execution.js.map +1 -0
  91. package/dist/pregel/index.d.ts +61 -0
  92. package/dist/pregel/index.d.ts.map +1 -0
  93. package/dist/pregel/index.js +154 -0
  94. package/dist/pregel/index.js.map +1 -0
  95. package/dist/pregel/interrupts.d.ts +3 -0
  96. package/dist/pregel/interrupts.d.ts.map +1 -0
  97. package/dist/pregel/interrupts.js +7 -0
  98. package/dist/pregel/interrupts.js.map +1 -0
  99. package/dist/pregel/state-helpers.d.ts +12 -0
  100. package/dist/pregel/state-helpers.d.ts.map +1 -0
  101. package/dist/pregel/state-helpers.js +71 -0
  102. package/dist/pregel/state-helpers.js.map +1 -0
  103. package/dist/pregel/streaming.d.ts +5 -0
  104. package/dist/pregel/streaming.d.ts.map +1 -0
  105. package/dist/pregel/streaming.js +462 -0
  106. package/dist/pregel/streaming.js.map +1 -0
  107. package/dist/pregel/types.d.ts +48 -0
  108. package/dist/pregel/types.d.ts.map +1 -0
  109. package/dist/pregel/types.js +5 -0
  110. package/dist/pregel/types.js.map +1 -0
  111. package/dist/pregel.d.ts +1 -66
  112. package/dist/pregel.d.ts.map +1 -1
  113. package/dist/pregel.js +2 -854
  114. package/dist/pregel.js.map +1 -1
  115. package/dist/swarm/agent-node.d.ts +11 -0
  116. package/dist/swarm/agent-node.d.ts.map +1 -0
  117. package/dist/swarm/agent-node.js +156 -0
  118. package/dist/swarm/agent-node.js.map +1 -0
  119. package/dist/swarm/compile-ext.d.ts +5 -0
  120. package/dist/swarm/compile-ext.d.ts.map +1 -0
  121. package/dist/swarm/compile-ext.js +126 -0
  122. package/dist/swarm/compile-ext.js.map +1 -0
  123. package/dist/swarm/config.d.ts +147 -0
  124. package/dist/swarm/config.d.ts.map +1 -0
  125. package/dist/swarm/config.js +17 -0
  126. package/dist/swarm/config.js.map +1 -0
  127. package/dist/swarm/factories.d.ts +37 -0
  128. package/dist/swarm/factories.d.ts.map +1 -0
  129. package/dist/swarm/factories.js +703 -0
  130. package/dist/swarm/factories.js.map +1 -0
  131. package/dist/swarm/graph.d.ts +14 -147
  132. package/dist/swarm/graph.d.ts.map +1 -1
  133. package/dist/swarm/graph.js +30 -917
  134. package/dist/swarm/graph.js.map +1 -1
  135. package/dist/swarm/pool.js.map +1 -1
  136. package/dist/swarm/supervisor.js.map +1 -1
  137. package/dist/testing/index.d.ts +2 -2
  138. package/dist/testing/index.d.ts.map +1 -1
  139. package/dist/testing/index.js +3 -2
  140. package/dist/testing/index.js.map +1 -1
  141. package/dist/tools/define.d.ts +2 -1
  142. package/dist/tools/define.d.ts.map +1 -1
  143. package/dist/tools/define.js +3 -1
  144. package/dist/tools/define.js.map +1 -1
  145. package/dist/tools/types.d.ts.map +1 -1
  146. package/package.json +1 -1
@@ -0,0 +1,491 @@
1
+ // ============================================================
2
+ // @oni.bot/core/harness/memory — MemoryLoader
3
+ //
4
+ // Integration class wiring scanner, ranker, and prompter modules.
5
+ // All 20+ public methods are preserved here.
6
+ //
7
+ // NOTE: This file is 594 lines — exceeds the 500-line guideline.
8
+ // Exception: the MemoryLoader class has 20+ public methods that
9
+ // must live on a single class for test spying (vi.spyOn) and the
10
+ // static fromRoot() factory pattern. Further decomposition would
11
+ // require breaking the public API.
12
+ // ============================================================
13
+ import { getFs, getPath } from "./fs-compat.js";
14
+ import { estimateTokens, inferTierFromPath, extractTagsFromContent, extractSummary, registerFile, scanRoot, } from "./scanner.js";
15
+ import { applyBudget, rankAndLoad } from "./ranker.js";
16
+ import { buildSystemPrompt } from "./prompter.js";
17
+ export * from "./types.js";
18
+ // ─── MemoryLoader ─────────────────────────────────────────────────────────────
19
+ export class MemoryLoader {
20
+ config;
21
+ units = new Map();
22
+ loaded = new Set();
23
+ static DEFAULT_BUDGETS = {
24
+ 0: 800,
25
+ 1: 2000,
26
+ 2: 4000,
27
+ 3: 8000,
28
+ };
29
+ constructor(config) {
30
+ this.config = {
31
+ budgets: { ...MemoryLoader.DEFAULT_BUDGETS, ...config.budgets },
32
+ episodicRecentDays: config.episodicRecentDays ?? 7,
33
+ autoIndex: config.autoIndex ?? true,
34
+ matchThreshold: config.matchThreshold ?? 0.2,
35
+ debug: config.debug ?? false,
36
+ root: config.root,
37
+ };
38
+ this.ensureDirectoryStructure();
39
+ this.scan();
40
+ }
41
+ // ── Factory ──────────────────────────────────────────────────────────────
42
+ static fromRoot(root, opts) {
43
+ return new MemoryLoader({ root, ...opts });
44
+ }
45
+ // ── Directory Bootstrap ──────────────────────────────────────────────────
46
+ ensureDirectoryStructure() {
47
+ const fs = getFs();
48
+ const path = getPath();
49
+ if (!fs || !path)
50
+ return;
51
+ const dirs = [
52
+ "identity", "working", "user",
53
+ "procedural", "episodic/recent", "episodic/archive", "semantic",
54
+ ];
55
+ for (const dir of dirs) {
56
+ try {
57
+ const full = path.join(this.config.root, dir);
58
+ if (!fs.existsSync(full)) {
59
+ fs.mkdirSync(full, { recursive: true });
60
+ }
61
+ }
62
+ catch {
63
+ // Silent degrade — non-Node environment
64
+ }
65
+ }
66
+ }
67
+ // ── Scanning ─────────────────────────────────────────────────────────────
68
+ scan() {
69
+ this.units.clear();
70
+ const scanned = scanRoot(this.config.root);
71
+ for (const [k, v] of scanned)
72
+ this.units.set(k, v);
73
+ this.log(`Scanned: ${this.units.size} memory units found`);
74
+ }
75
+ registerFileSelf(absPath, relPath) {
76
+ const unit = registerFile(absPath, relPath);
77
+ if (unit)
78
+ this.units.set(relPath, unit);
79
+ }
80
+ // ── Progressive Disclosure ────────────────────────────────────────────────
81
+ /**
82
+ * wake() — Load Tier 0 (identity). Always called first.
83
+ * Additive: already-loaded units are skipped.
84
+ */
85
+ wake() {
86
+ return this.loadByTier(0);
87
+ }
88
+ /**
89
+ * orient() — Load Tier 1 (working, user/PROFILE, INDEX files).
90
+ * Additive.
91
+ */
92
+ orient() {
93
+ return this.loadByTier(1);
94
+ }
95
+ /**
96
+ * match(task) — Load Tier 2 units relevant to the task string.
97
+ * Scored by tag-overlap × recency. Additive.
98
+ * Returns empty LoadResult if taskTokens is empty (no error).
99
+ */
100
+ match(task) {
101
+ const budget = this.getBudget(2);
102
+ const candidates = this.getUnitsByTier(2).filter((u) => !this.loaded.has(u.key));
103
+ return rankAndLoad(task, 2, this.config.matchThreshold, candidates, budget, (u) => this.hydrate(u), (key) => this.loaded.add(key), (msg) => this.log(msg));
104
+ }
105
+ /**
106
+ * query(topic) — Load Tier 3 units. Called only via the memory_query tool.
107
+ * Additive.
108
+ */
109
+ query(topic) {
110
+ const budget = this.getBudget(3);
111
+ const candidates = this.getUnitsByTier(3).filter((u) => !this.loaded.has(u.key));
112
+ return rankAndLoad(topic, 3, this.config.matchThreshold, candidates, budget, (u) => this.hydrate(u), (key) => this.loaded.add(key), (msg) => this.log(msg));
113
+ }
114
+ /**
115
+ * load(key) — Directly load a specific memory unit by key. Additive.
116
+ */
117
+ load(key) {
118
+ const unit = this.units.get(key);
119
+ if (!unit)
120
+ return null;
121
+ const hydrated = this.hydrate(unit);
122
+ this.loaded.add(key);
123
+ return hydrated;
124
+ }
125
+ /**
126
+ * loadType(type) — Load all units of a given memory type.
127
+ * Budget: 16000t fixed (intentional escape hatch). Additive.
128
+ */
129
+ loadType(type) {
130
+ const units = [...this.units.values()].filter((u) => u.type === type && !this.loaded.has(u.key));
131
+ return applyBudget(units, 16000, (u) => this.hydrate(u), (key) => this.loaded.add(key), (msg) => this.log(msg));
132
+ }
133
+ /**
134
+ * buildSystemPrompt(tiers) — Assemble loaded units into a system prompt string.
135
+ * Default tiers: [0, 1, 2]
136
+ */
137
+ buildSystemPrompt(tiers = [0, 1, 2]) {
138
+ return buildSystemPrompt(this.units, this.loaded, tiers);
139
+ }
140
+ /**
141
+ * getLoadedManifest() — Compact list of loaded keys + costs.
142
+ * Format: "- <key> (T<tier>, <cost>t)" per line.
143
+ */
144
+ getLoadedManifest() {
145
+ return [...this.loaded]
146
+ .map((key) => {
147
+ const unit = this.units.get(key);
148
+ return unit ? `- ${key} (T${unit.tier}, ${unit.tokenCost}t)` : `- ${key}`;
149
+ })
150
+ .join("\n");
151
+ }
152
+ /** resetSession() — Clear loaded set and release hydrated content. Does not remove files. */
153
+ resetSession() {
154
+ this.loaded.clear();
155
+ for (const unit of this.units.values()) {
156
+ unit.content = undefined;
157
+ }
158
+ this.log("Session reset");
159
+ }
160
+ // ── Write API ─────────────────────────────────────────────────────────────
161
+ /**
162
+ * persist() — Write a memory unit to disk.
163
+ * autoIndex: rebuildIndex() called synchronously before return when autoIndex === true.
164
+ * Returns MemoryUnit with content populated.
165
+ */
166
+ persist(type, filename, content, subfolder) {
167
+ return this.persistInternal(type, filename, content, subfolder, false);
168
+ }
169
+ persistInternal(type, filename, content, subfolder, skipAutoIndex) {
170
+ const fs = getFs();
171
+ const path = getPath();
172
+ if (!fs || !path) {
173
+ // Silent degrade in non-Node environments — return a stub unit.
174
+ // Must NOT throw: callers (persistEpisodic, finally block) do not wrap this.
175
+ return {
176
+ key: `${type}/${filename}`,
177
+ path: "",
178
+ type,
179
+ tier: 1,
180
+ tags: [],
181
+ summary: "",
182
+ tokenCost: 0,
183
+ triggers: [],
184
+ updatedAt: new Date().toISOString(),
185
+ content,
186
+ };
187
+ }
188
+ const folder = subfolder
189
+ ? path.join(this.config.root, type, subfolder)
190
+ : path.join(this.config.root, type);
191
+ const absPath = path.join(folder, filename);
192
+ const relPath = path.relative(this.config.root, absPath);
193
+ const finalContent = /^---\r?\n/.test(content)
194
+ ? content
195
+ : this.injectFrontmatter(content, type, relPath);
196
+ try {
197
+ fs.mkdirSync(folder, { recursive: true });
198
+ fs.writeFileSync(absPath, finalContent, "utf-8");
199
+ }
200
+ catch {
201
+ // Must NOT throw: called from finally blocks — return a stub on I/O failure.
202
+ return {
203
+ key: relPath,
204
+ path: absPath,
205
+ type,
206
+ tier: inferTierFromPath(relPath, type),
207
+ tags: [],
208
+ summary: "",
209
+ tokenCost: estimateTokens(finalContent),
210
+ triggers: [],
211
+ updatedAt: new Date().toISOString(),
212
+ content: finalContent,
213
+ };
214
+ }
215
+ this.registerFileSelf(absPath, relPath);
216
+ const unit = this.units.get(relPath);
217
+ if (!unit) {
218
+ // registerFile silently failed (e.g. post-write permission error) — return minimal stub
219
+ return {
220
+ key: relPath,
221
+ path: absPath,
222
+ type,
223
+ tier: inferTierFromPath(relPath, type),
224
+ tags: [],
225
+ summary: "",
226
+ tokenCost: estimateTokens(finalContent),
227
+ triggers: [],
228
+ updatedAt: new Date().toISOString(),
229
+ content: finalContent,
230
+ };
231
+ }
232
+ unit.content = finalContent;
233
+ if (this.config.autoIndex && !skipAutoIndex) {
234
+ this.rebuildIndex(path.dirname(absPath));
235
+ }
236
+ this.log(`Persisted: ${relPath} (${unit.tokenCost}t)`);
237
+ return unit;
238
+ }
239
+ /**
240
+ * persistEpisodic() — Write session log to episodic/recent/<date>_<sessionId>.md.
241
+ * Triggers compaction if recent/ has files older than episodicRecentDays.
242
+ */
243
+ persistEpisodic(sessionId, content) {
244
+ const date = new Date().toISOString().split("T")[0];
245
+ const filename = `${date}_${sessionId}.md`;
246
+ // Skip autoIndex for episodic/recent — INDEX.md would pollute the dated file listing
247
+ const unit = this.persistInternal("episodic", filename, content, "recent", true);
248
+ this.compactEpisodicIfNeeded();
249
+ return unit;
250
+ }
251
+ /**
252
+ * persistSemantic() — Write knowledge unit to semantic/<domain>/<topic>.md.
253
+ * Rebuilds both domain INDEX.md and root semantic INDEX.md.
254
+ */
255
+ persistSemantic(domain, topic, content) {
256
+ const path = getPath();
257
+ const filename = `${topic.toLowerCase().replace(/\s+/g, "-")}.md`;
258
+ const unit = this.persist("semantic", filename, content, domain);
259
+ if (this.config.autoIndex && path) {
260
+ this.rebuildIndex(path.join(this.config.root, "semantic"));
261
+ }
262
+ return unit;
263
+ }
264
+ // ── INDEX.md Management ───────────────────────────────────────────────────
265
+ /**
266
+ * rebuildIndex() — Rewrite the INDEX.md for a given folder.
267
+ * INDEX.md files are write-only — never read back by the loader.
268
+ */
269
+ rebuildIndex(folder) {
270
+ const fs = getFs();
271
+ const path = getPath();
272
+ if (!fs || !path)
273
+ return;
274
+ const relFolder = path.relative(this.config.root, folder);
275
+ const folderPrefix = folder.endsWith(path.sep) ? folder : folder + path.sep;
276
+ const units = [...this.units.values()].filter((u) => u.path.startsWith(folderPrefix));
277
+ if (units.length === 0)
278
+ return;
279
+ const rows = units
280
+ .map((u) => `| ${path.basename(u.key)} | ${u.summary.slice(0, 60)} | ${u.tags.slice(0, 4).join(",")} | T${u.tier} | ${u.tokenCost} |`)
281
+ .join("\n");
282
+ const allTags = [...new Set(units.flatMap((u) => u.tags))].slice(0, 8).join(", ");
283
+ const index = [
284
+ `---`,
285
+ `type: index`,
286
+ `folder: ${relFolder}`,
287
+ `indexed_at: ${new Date().toISOString()}`,
288
+ `---`,
289
+ ``,
290
+ `# Index: ${relFolder || "root"}`,
291
+ `_token_budget: 200_`,
292
+ ``,
293
+ `## Contents`,
294
+ ``,
295
+ `| file | summary | tags | tier | tokens |`,
296
+ `|------|---------|------|------|--------|`,
297
+ rows,
298
+ ``,
299
+ `## Routing Hints`,
300
+ ``,
301
+ `- Load this folder when: ${allTags}`,
302
+ `- Units: ${units.length} | Total tokens: ${units.reduce((s, u) => s + u.tokenCost, 0)}`,
303
+ ].join("\n");
304
+ try {
305
+ fs.writeFileSync(path.join(folder, "INDEX.md"), index, "utf-8");
306
+ this.log(`Rebuilt INDEX.md: ${relFolder}`);
307
+ }
308
+ catch {
309
+ // Silent degrade
310
+ }
311
+ }
312
+ /** rebuildAllIndexes() — Rebuild every INDEX.md in the tree. */
313
+ rebuildAllIndexes() {
314
+ const path = getPath();
315
+ if (!path)
316
+ return;
317
+ const dirs = new Set();
318
+ for (const unit of this.units.values()) {
319
+ dirs.add(path.dirname(unit.path));
320
+ }
321
+ for (const dir of dirs) {
322
+ this.rebuildIndex(dir);
323
+ }
324
+ }
325
+ // ── Diagnostic ────────────────────────────────────────────────────────────
326
+ stats() {
327
+ const byType = {};
328
+ const byTier = {};
329
+ let totalTokens = 0;
330
+ for (const unit of this.units.values()) {
331
+ byType[unit.type] = (byType[unit.type] ?? 0) + 1;
332
+ byTier[`T${unit.tier}`] = (byTier[`T${unit.tier}`] ?? 0) + 1;
333
+ totalTokens += unit.tokenCost;
334
+ }
335
+ return {
336
+ totalUnits: this.units.size,
337
+ currentlyLoaded: this.loaded.size,
338
+ totalTokensOnDisk: totalTokens,
339
+ byType,
340
+ byTier,
341
+ root: this.config.root,
342
+ };
343
+ }
344
+ // ── Tool ─────────────────────────────────────────────────────────────────
345
+ /**
346
+ * getQueryTool() — Returns the memory_query ToolDefinition.
347
+ * The `reason` param is prompting-only — not used in execute logic.
348
+ * `_ctx` is typed as ToolContext (base); MemoryLoader needs no harness-specific context.
349
+ */
350
+ getQueryTool() {
351
+ return {
352
+ name: "memory_query",
353
+ description: `Retrieve deep knowledge from memory when you hit a gap mid-task.
354
+ Call this when: you need a specific procedure, domain fact, or past decision you don't currently have in context.
355
+ Do NOT call this speculatively — only when you've identified a concrete gap.
356
+ Returns: matching memory units or empty if nothing found.`,
357
+ schema: {
358
+ type: "object",
359
+ properties: {
360
+ topic: {
361
+ type: "string",
362
+ description: "Specific topic, skill name, or domain concept to retrieve. Be precise.",
363
+ },
364
+ reason: {
365
+ type: "string",
366
+ description: "One sentence: what gap are you filling and why do you need it now.",
367
+ },
368
+ },
369
+ required: ["topic", "reason"],
370
+ additionalProperties: false,
371
+ },
372
+ execute: (input, _ctx) => {
373
+ // reason intentionally unused — prompting-only
374
+ const result = this.query(input.topic);
375
+ if (result.units.length === 0) {
376
+ return {
377
+ found: false,
378
+ topic: input.topic,
379
+ message: "No matching memory found. Proceed with available context or escalate.",
380
+ };
381
+ }
382
+ return {
383
+ found: true,
384
+ units: result.units.map((u) => ({ key: u.key, content: u.content })),
385
+ totalTokens: result.totalTokens,
386
+ droppedCount: result.dropped.length,
387
+ };
388
+ },
389
+ };
390
+ }
391
+ // ── Internal Helpers ──────────────────────────────────────────────────────
392
+ loadByTier(tier) {
393
+ const budget = this.getBudget(tier);
394
+ const units = this.getUnitsByTier(tier).filter((u) => !this.loaded.has(u.key));
395
+ return applyBudget(units, budget, (u) => this.hydrate(u), (key) => this.loaded.add(key), (msg) => this.log(msg));
396
+ }
397
+ getUnitsByTier(tier) {
398
+ return [...this.units.values()].filter((u) => u.tier === tier);
399
+ }
400
+ getBudget(tier) {
401
+ return this.config.budgets[tier];
402
+ }
403
+ hydrate(unit) {
404
+ if (unit.content)
405
+ return unit;
406
+ const fs = getFs();
407
+ if (!fs) {
408
+ unit.content = `<!-- Failed to read: ${unit.path} -->`;
409
+ return unit;
410
+ }
411
+ try {
412
+ unit.content = fs.readFileSync(unit.path, "utf-8");
413
+ }
414
+ catch {
415
+ unit.content = `<!-- Failed to read: ${unit.path} -->`;
416
+ }
417
+ return unit;
418
+ }
419
+ injectFrontmatter(content, type, relPath) {
420
+ const tier = inferTierFromPath(relPath, type);
421
+ const tags = extractTagsFromContent(content);
422
+ const summary = extractSummary(content);
423
+ return [
424
+ "---",
425
+ `type: ${type}`,
426
+ `tier: ${tier}`,
427
+ `tags: ${tags.join(", ")}`,
428
+ `summary: ${summary.slice(0, 100)}`,
429
+ `created: ${new Date().toISOString()}`,
430
+ "---",
431
+ "",
432
+ content,
433
+ ].join("\n");
434
+ }
435
+ compactEpisodicIfNeeded() {
436
+ const fs = getFs();
437
+ const path = getPath();
438
+ if (!fs || !path)
439
+ return;
440
+ const recentDir = path.join(this.config.root, "episodic", "recent");
441
+ const archiveDir = path.join(this.config.root, "episodic", "archive");
442
+ if (!fs.existsSync(recentDir))
443
+ return;
444
+ const cutoff = new Date();
445
+ cutoff.setDate(cutoff.getDate() - this.config.episodicRecentDays);
446
+ let files;
447
+ try {
448
+ files = fs.readdirSync(recentDir).filter((f) => f.endsWith(".md"));
449
+ }
450
+ catch {
451
+ return;
452
+ }
453
+ let archived = false;
454
+ for (const file of files) {
455
+ const dateMatch = file.match(/^(\d{4}-\d{2}-\d{2})/);
456
+ if (!dateMatch)
457
+ continue;
458
+ // Parse as local-time midnight to match the local-time cutoff.
459
+ // new Date("YYYY-MM-DD") parses as UTC midnight which is off by up to
460
+ // ±24h relative to the local-time cutoff in non-UTC timezones.
461
+ const [y, m, d] = dateMatch[1].split("-").map(Number);
462
+ const fileDate = new Date(y, m - 1, d);
463
+ if (fileDate < cutoff) {
464
+ try {
465
+ const src = path.join(recentDir, file);
466
+ const dest = path.join(archiveDir, file);
467
+ fs.mkdirSync(archiveDir, { recursive: true });
468
+ fs.renameSync(src, dest);
469
+ const oldKey = path.relative(this.config.root, src);
470
+ const newKey = path.relative(this.config.root, dest);
471
+ this.units.delete(oldKey);
472
+ this.registerFileSelf(dest, newKey);
473
+ this.log(`Archived episodic: ${file}`);
474
+ archived = true;
475
+ }
476
+ catch {
477
+ // Skip if move fails
478
+ }
479
+ }
480
+ }
481
+ if (archived && this.config.autoIndex) {
482
+ this.rebuildIndex(recentDir);
483
+ this.rebuildIndex(archiveDir);
484
+ }
485
+ }
486
+ log(msg) {
487
+ if (this.config.debug)
488
+ console.log(`[MemoryLoader] ${msg}`);
489
+ }
490
+ }
491
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/harness/memory/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { MemoryTier, MemoryUnit } from "./types.js";
2
+ /**
3
+ * buildSystemPrompt — Assemble loaded units into a system prompt string.
4
+ * Default tiers: [0, 1, 2]
5
+ */
6
+ export declare function buildSystemPrompt(units: Map<string, MemoryUnit>, loaded: Set<string>, tiers?: MemoryTier[]): string;
7
+ //# sourceMappingURL=prompter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompter.d.ts","sourceRoot":"","sources":["../../../src/harness/memory/prompter.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAEzD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAC9B,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EACnB,KAAK,GAAE,UAAU,EAAc,GAC9B,MAAM,CAUR"}
@@ -0,0 +1,24 @@
1
+ // ============================================================
2
+ // @oni.bot/core/harness/memory — prompter
3
+ //
4
+ // System prompt assembly from loaded memory units.
5
+ // ============================================================
6
+ /**
7
+ * buildSystemPrompt — Assemble loaded units into a system prompt string.
8
+ * Default tiers: [0, 1, 2]
9
+ */
10
+ export function buildSystemPrompt(units, loaded, tiers = [0, 1, 2]) {
11
+ const sections = [];
12
+ for (const [key, unit] of units) {
13
+ if (!loaded.has(key))
14
+ continue;
15
+ if (!tiers.includes(unit.tier))
16
+ continue;
17
+ if (!unit.content)
18
+ continue;
19
+ const header = `\n\n<!-- MEMORY: ${unit.type.toUpperCase()} | ${unit.key} | T${unit.tier} -->\n`;
20
+ sections.push(header + unit.content);
21
+ }
22
+ return sections.join("");
23
+ }
24
+ //# sourceMappingURL=prompter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompter.js","sourceRoot":"","sources":["../../../src/harness/memory/prompter.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,0CAA0C;AAC1C,EAAE;AACF,mDAAmD;AACnD,+DAA+D;AAI/D;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,KAA8B,EAC9B,MAAmB,EACnB,QAAsB,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAE/B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,KAAK,EAAE,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC/B,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACzC,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,SAAS;QAC5B,MAAM,MAAM,GAAG,oBAAoB,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,IAAI,CAAC,GAAG,OAAO,IAAI,CAAC,IAAI,QAAQ,CAAC;QACjG,QAAQ,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,15 @@
1
+ import type { MemoryTier, MemoryUnit, LoadResult } from "./types.js";
2
+ export declare function extractTagsFromString(text: string): string[];
3
+ export declare function scoreRelevance(unit: MemoryUnit, taskTags: string[]): number;
4
+ /**
5
+ * Apply token budget to a list of candidate units.
6
+ * Hydrates selected units via the provided hydrate function.
7
+ * Returns a LoadResult with selected units + dropped overflow.
8
+ */
9
+ export declare function applyBudget(units: MemoryUnit[], budget: number, hydrateUnit: (unit: MemoryUnit) => MemoryUnit, markLoaded: (key: string) => void, logFn: (msg: string) => void): LoadResult;
10
+ /**
11
+ * Rank candidates by relevance to a task string, filter by threshold,
12
+ * apply budget, and return the LoadResult.
13
+ */
14
+ export declare function rankAndLoad(task: string, tier: MemoryTier, matchThreshold: number, candidates: MemoryUnit[], budget: number, hydrateUnit: (unit: MemoryUnit) => MemoryUnit, markLoaded: (key: string) => void, logFn: (msg: string) => void): LoadResult;
15
+ //# sourceMappingURL=ranker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranker.d.ts","sourceRoot":"","sources":["../../../src/harness/memory/ranker.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAcrE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAQ5D;AAID,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAW3E;AAID;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,UAAU,EAAE,EACnB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,EAC7C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EACjC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC3B,UAAU,CAiBZ;AAID;;;GAGG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,UAAU,EAChB,cAAc,EAAE,MAAM,EACtB,UAAU,EAAE,UAAU,EAAE,EACxB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,UAAU,EAC7C,UAAU,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EACjC,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAC3B,UAAU,CAYZ"}
@@ -0,0 +1,72 @@
1
+ // ============================================================
2
+ // @oni.bot/core/harness/memory — ranker
3
+ //
4
+ // Semantic relevance ranking and token budget enforcement.
5
+ // ============================================================
6
+ // ─── Stopwords ────────────────────────────────────────────────────────────────
7
+ const STOPWORDS = new Set([
8
+ "the", "and", "for", "are", "but", "not", "you", "all", "can", "had", "her", "was", "one",
9
+ "our", "out", "day", "get", "has", "him", "his", "how", "its", "may", "new", "now", "old",
10
+ "see", "two", "who", "did", "does", "into", "than", "that", "this", "with", "have", "from",
11
+ "they", "will", "been", "when", "what", "were", "your", "said", "each", "which", "their",
12
+ "time", "about", "would", "there", "could", "other", "after", "first", "these", "those",
13
+ ]);
14
+ // ─── Tag extraction ───────────────────────────────────────────────────────────
15
+ export function extractTagsFromString(text) {
16
+ return (text
17
+ .toLowerCase()
18
+ .match(/\b[a-z]{3,}\b/g)
19
+ ?.filter((w) => !STOPWORDS.has(w))
20
+ .slice(0, 20) ?? []);
21
+ }
22
+ // ─── Relevance scoring ────────────────────────────────────────────────────────
23
+ export function scoreRelevance(unit, taskTags) {
24
+ const unitTagSet = new Set([...unit.tags, ...unit.triggers]);
25
+ const overlap = taskTags.filter((t) => unitTagSet.has(t)).length;
26
+ const tagScore = overlap / Math.max(taskTags.length, 1);
27
+ const rawAge = Date.now() - new Date(unit.updatedAt).getTime();
28
+ const ageMs = isNaN(rawAge) ? 0 : rawAge;
29
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
30
+ const recencyScore = unit.type === "episodic" ? Math.max(0, 1 - ageDays / 30) : 0;
31
+ return tagScore * 0.8 + recencyScore * 0.2;
32
+ }
33
+ // ─── Budget enforcement ───────────────────────────────────────────────────────
34
+ /**
35
+ * Apply token budget to a list of candidate units.
36
+ * Hydrates selected units via the provided hydrate function.
37
+ * Returns a LoadResult with selected units + dropped overflow.
38
+ */
39
+ export function applyBudget(units, budget, hydrateUnit, markLoaded, logFn) {
40
+ const selected = [];
41
+ const dropped = [];
42
+ let used = 0;
43
+ for (const unit of units) {
44
+ if (used + unit.tokenCost <= budget) {
45
+ selected.push({ ...hydrateUnit(unit) });
46
+ markLoaded(unit.key);
47
+ used += unit.tokenCost;
48
+ }
49
+ else {
50
+ dropped.push(unit);
51
+ }
52
+ }
53
+ logFn(`Loaded ${selected.length} units (${used}/${budget}t). Dropped: ${dropped.length}`);
54
+ return { units: selected, totalTokens: used, budget, dropped };
55
+ }
56
+ // ─── Ranked query ─────────────────────────────────────────────────────────────
57
+ /**
58
+ * Rank candidates by relevance to a task string, filter by threshold,
59
+ * apply budget, and return the LoadResult.
60
+ */
61
+ export function rankAndLoad(task, tier, matchThreshold, candidates, budget, hydrateUnit, markLoaded, logFn) {
62
+ const taskTags = extractTagsFromString(task);
63
+ if (taskTags.length === 0) {
64
+ return { units: [], totalTokens: 0, budget, dropped: [] };
65
+ }
66
+ const scored = candidates
67
+ .map((unit) => ({ unit, score: scoreRelevance(unit, taskTags) }))
68
+ .filter(({ score }) => score > 0 && score >= matchThreshold)
69
+ .sort((a, b) => b.score - a.score);
70
+ return applyBudget(scored.map((s) => s.unit), budget, hydrateUnit, markLoaded, logFn);
71
+ }
72
+ //# sourceMappingURL=ranker.js.map