cognitive-core 0.0.2 → 0.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 (329) hide show
  1. package/README.md +302 -116
  2. package/SKILL.md +193 -0
  3. package/dist/agents/index.d.ts +3 -0
  4. package/dist/agents/index.d.ts.map +1 -0
  5. package/dist/agents/index.js +5 -0
  6. package/dist/agents/index.js.map +1 -0
  7. package/dist/agents/mock-provider.d.ts +23 -0
  8. package/dist/agents/mock-provider.d.ts.map +1 -0
  9. package/dist/agents/mock-provider.js +71 -0
  10. package/dist/agents/mock-provider.js.map +1 -0
  11. package/dist/agents/types.d.ts +98 -0
  12. package/dist/agents/types.d.ts.map +1 -0
  13. package/dist/agents/types.js +44 -0
  14. package/dist/agents/types.js.map +1 -0
  15. package/dist/atlas.d.ts +196 -0
  16. package/dist/atlas.d.ts.map +1 -0
  17. package/dist/atlas.js +373 -0
  18. package/dist/atlas.js.map +1 -0
  19. package/dist/bin/cognitive-core.d.ts +18 -0
  20. package/dist/bin/cognitive-core.d.ts.map +1 -0
  21. package/dist/bin/cognitive-core.js +419 -0
  22. package/dist/bin/cognitive-core.js.map +1 -0
  23. package/dist/embeddings/bm25.d.ts +104 -0
  24. package/dist/embeddings/bm25.d.ts.map +1 -0
  25. package/dist/embeddings/bm25.js +264 -0
  26. package/dist/embeddings/bm25.js.map +1 -0
  27. package/dist/embeddings/index.d.ts +12 -0
  28. package/dist/embeddings/index.d.ts.map +1 -0
  29. package/dist/embeddings/index.js +16 -0
  30. package/dist/embeddings/index.js.map +1 -0
  31. package/dist/embeddings/manager.d.ts +112 -0
  32. package/dist/embeddings/manager.d.ts.map +1 -0
  33. package/dist/embeddings/manager.js +215 -0
  34. package/dist/embeddings/manager.js.map +1 -0
  35. package/dist/embeddings/provider.d.ts +101 -0
  36. package/dist/embeddings/provider.d.ts.map +1 -0
  37. package/dist/embeddings/provider.js +232 -0
  38. package/dist/embeddings/provider.js.map +1 -0
  39. package/dist/embeddings/vector-store.d.ts +101 -0
  40. package/dist/embeddings/vector-store.d.ts.map +1 -0
  41. package/dist/embeddings/vector-store.js +256 -0
  42. package/dist/embeddings/vector-store.js.map +1 -0
  43. package/dist/factory.d.ts +193 -0
  44. package/dist/factory.d.ts.map +1 -0
  45. package/dist/factory.js +109 -0
  46. package/dist/factory.js.map +1 -0
  47. package/dist/index.d.ts +30 -453
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +84 -509
  50. package/dist/index.js.map +1 -0
  51. package/dist/learning/analyzer.d.ts +110 -0
  52. package/dist/learning/analyzer.d.ts.map +1 -0
  53. package/dist/learning/analyzer.js +213 -0
  54. package/dist/learning/analyzer.js.map +1 -0
  55. package/dist/learning/effectiveness.d.ts +158 -0
  56. package/dist/learning/effectiveness.d.ts.map +1 -0
  57. package/dist/learning/effectiveness.js +251 -0
  58. package/dist/learning/effectiveness.js.map +1 -0
  59. package/dist/learning/index.d.ts +8 -0
  60. package/dist/learning/index.d.ts.map +1 -0
  61. package/dist/learning/index.js +11 -0
  62. package/dist/learning/index.js.map +1 -0
  63. package/dist/learning/llm-extractor.d.ts +88 -0
  64. package/dist/learning/llm-extractor.d.ts.map +1 -0
  65. package/dist/learning/llm-extractor.js +372 -0
  66. package/dist/learning/llm-extractor.js.map +1 -0
  67. package/dist/learning/meta-learner.d.ts +80 -0
  68. package/dist/learning/meta-learner.d.ts.map +1 -0
  69. package/dist/learning/meta-learner.js +355 -0
  70. package/dist/learning/meta-learner.js.map +1 -0
  71. package/dist/learning/pipeline.d.ts +65 -0
  72. package/dist/learning/pipeline.d.ts.map +1 -0
  73. package/dist/learning/pipeline.js +170 -0
  74. package/dist/learning/pipeline.js.map +1 -0
  75. package/dist/learning/playbook-extractor.d.ts +113 -0
  76. package/dist/learning/playbook-extractor.d.ts.map +1 -0
  77. package/dist/learning/playbook-extractor.js +523 -0
  78. package/dist/learning/playbook-extractor.js.map +1 -0
  79. package/dist/learning/usage-inference.d.ts +82 -0
  80. package/dist/learning/usage-inference.d.ts.map +1 -0
  81. package/dist/learning/usage-inference.js +261 -0
  82. package/dist/learning/usage-inference.js.map +1 -0
  83. package/dist/mcp/index.d.ts +6 -0
  84. package/dist/mcp/index.d.ts.map +1 -0
  85. package/dist/mcp/index.js +6 -0
  86. package/dist/mcp/index.js.map +1 -0
  87. package/dist/mcp/playbook-server.d.ts +120 -0
  88. package/dist/mcp/playbook-server.d.ts.map +1 -0
  89. package/dist/mcp/playbook-server.js +427 -0
  90. package/dist/mcp/playbook-server.js.map +1 -0
  91. package/dist/memory/curated-loader.d.ts +62 -0
  92. package/dist/memory/curated-loader.d.ts.map +1 -0
  93. package/dist/memory/curated-loader.js +106 -0
  94. package/dist/memory/curated-loader.js.map +1 -0
  95. package/dist/memory/experience.d.ts +122 -0
  96. package/dist/memory/experience.d.ts.map +1 -0
  97. package/dist/memory/experience.js +392 -0
  98. package/dist/memory/experience.js.map +1 -0
  99. package/dist/memory/index.d.ts +6 -0
  100. package/dist/memory/index.d.ts.map +1 -0
  101. package/dist/memory/index.js +9 -0
  102. package/dist/memory/index.js.map +1 -0
  103. package/dist/memory/meta.d.ts +90 -0
  104. package/dist/memory/meta.d.ts.map +1 -0
  105. package/dist/memory/meta.js +362 -0
  106. package/dist/memory/meta.js.map +1 -0
  107. package/dist/memory/playbook.d.ts +133 -0
  108. package/dist/memory/playbook.d.ts.map +1 -0
  109. package/dist/memory/playbook.js +357 -0
  110. package/dist/memory/playbook.js.map +1 -0
  111. package/dist/memory/system.d.ts +167 -0
  112. package/dist/memory/system.d.ts.map +1 -0
  113. package/dist/memory/system.js +383 -0
  114. package/dist/memory/system.js.map +1 -0
  115. package/dist/runtime/backends/acp.d.ts +67 -0
  116. package/dist/runtime/backends/acp.d.ts.map +1 -0
  117. package/dist/runtime/backends/acp.js +290 -0
  118. package/dist/runtime/backends/acp.js.map +1 -0
  119. package/dist/runtime/backends/index.d.ts +5 -0
  120. package/dist/runtime/backends/index.d.ts.map +1 -0
  121. package/dist/runtime/backends/index.js +6 -0
  122. package/dist/runtime/backends/index.js.map +1 -0
  123. package/dist/runtime/backends/mock.d.ts +67 -0
  124. package/dist/runtime/backends/mock.d.ts.map +1 -0
  125. package/dist/runtime/backends/mock.js +153 -0
  126. package/dist/runtime/backends/mock.js.map +1 -0
  127. package/dist/runtime/backends/subprocess.d.ts +56 -0
  128. package/dist/runtime/backends/subprocess.d.ts.map +1 -0
  129. package/dist/runtime/backends/subprocess.js +260 -0
  130. package/dist/runtime/backends/subprocess.js.map +1 -0
  131. package/dist/runtime/flows/learning.d.ts +73 -0
  132. package/dist/runtime/flows/learning.d.ts.map +1 -0
  133. package/dist/runtime/flows/learning.js +116 -0
  134. package/dist/runtime/flows/learning.js.map +1 -0
  135. package/dist/runtime/flows/validation.d.ts +122 -0
  136. package/dist/runtime/flows/validation.d.ts.map +1 -0
  137. package/dist/runtime/flows/validation.js +223 -0
  138. package/dist/runtime/flows/validation.js.map +1 -0
  139. package/dist/runtime/index.d.ts +6 -0
  140. package/dist/runtime/index.d.ts.map +1 -0
  141. package/dist/runtime/index.js +8 -0
  142. package/dist/runtime/index.js.map +1 -0
  143. package/dist/runtime/manager.d.ts +116 -0
  144. package/dist/runtime/manager.d.ts.map +1 -0
  145. package/dist/runtime/manager.js +416 -0
  146. package/dist/runtime/manager.js.map +1 -0
  147. package/dist/runtime/types.d.ts +138 -0
  148. package/dist/runtime/types.d.ts.map +1 -0
  149. package/dist/runtime/types.js +2 -0
  150. package/dist/runtime/types.js.map +1 -0
  151. package/dist/search/evaluator.d.ts +102 -0
  152. package/dist/search/evaluator.d.ts.map +1 -0
  153. package/dist/search/evaluator.js +352 -0
  154. package/dist/search/evaluator.js.map +1 -0
  155. package/dist/search/index.d.ts +7 -0
  156. package/dist/search/index.d.ts.map +1 -0
  157. package/dist/search/index.js +11 -0
  158. package/dist/search/index.js.map +1 -0
  159. package/dist/search/refinement-loop.d.ts +73 -0
  160. package/dist/search/refinement-loop.d.ts.map +1 -0
  161. package/dist/search/refinement-loop.js +245 -0
  162. package/dist/search/refinement-loop.js.map +1 -0
  163. package/dist/search/refinement-types.d.ts +154 -0
  164. package/dist/search/refinement-types.d.ts.map +1 -0
  165. package/dist/search/refinement-types.js +99 -0
  166. package/dist/search/refinement-types.js.map +1 -0
  167. package/dist/search/router.d.ts +61 -0
  168. package/dist/search/router.d.ts.map +1 -0
  169. package/dist/search/router.js +197 -0
  170. package/dist/search/router.js.map +1 -0
  171. package/dist/search/solver.d.ts +75 -0
  172. package/dist/search/solver.d.ts.map +1 -0
  173. package/dist/search/solver.js +216 -0
  174. package/dist/search/solver.js.map +1 -0
  175. package/dist/search/verification-runner.d.ts +125 -0
  176. package/dist/search/verification-runner.d.ts.map +1 -0
  177. package/dist/search/verification-runner.js +440 -0
  178. package/dist/search/verification-runner.js.map +1 -0
  179. package/dist/surfacing/index.d.ts +2 -0
  180. package/dist/surfacing/index.d.ts.map +1 -0
  181. package/dist/surfacing/index.js +2 -0
  182. package/dist/surfacing/index.js.map +1 -0
  183. package/dist/surfacing/skill-library.d.ts +158 -0
  184. package/dist/surfacing/skill-library.d.ts.map +1 -0
  185. package/dist/surfacing/skill-library.js +429 -0
  186. package/dist/surfacing/skill-library.js.map +1 -0
  187. package/dist/types/config.d.ts +1113 -0
  188. package/dist/types/config.d.ts.map +1 -0
  189. package/dist/types/config.js +274 -0
  190. package/dist/types/config.js.map +1 -0
  191. package/dist/types/index.d.ts +9 -0
  192. package/dist/types/index.d.ts.map +1 -0
  193. package/dist/types/index.js +14 -0
  194. package/dist/types/index.js.map +1 -0
  195. package/dist/types/memory.d.ts +339 -0
  196. package/dist/types/memory.d.ts.map +1 -0
  197. package/dist/types/memory.js +207 -0
  198. package/dist/types/memory.js.map +1 -0
  199. package/dist/types/meta.d.ts +146 -0
  200. package/dist/types/meta.d.ts.map +1 -0
  201. package/dist/types/meta.js +51 -0
  202. package/dist/types/meta.js.map +1 -0
  203. package/dist/types/outcome.d.ts +42 -0
  204. package/dist/types/outcome.d.ts.map +1 -0
  205. package/dist/types/outcome.js +50 -0
  206. package/dist/types/outcome.js.map +1 -0
  207. package/dist/types/playbook.d.ts +119 -0
  208. package/dist/types/playbook.d.ts.map +1 -0
  209. package/dist/types/playbook.js +71 -0
  210. package/dist/types/playbook.js.map +1 -0
  211. package/dist/types/step.d.ts +44 -0
  212. package/dist/types/step.d.ts.map +1 -0
  213. package/dist/types/step.js +32 -0
  214. package/dist/types/step.js.map +1 -0
  215. package/dist/types/task.d.ts +91 -0
  216. package/dist/types/task.d.ts.map +1 -0
  217. package/dist/types/task.js +39 -0
  218. package/dist/types/task.js.map +1 -0
  219. package/dist/types/trajectory.d.ts +221 -0
  220. package/dist/types/trajectory.d.ts.map +1 -0
  221. package/dist/types/trajectory.js +60 -0
  222. package/dist/types/trajectory.js.map +1 -0
  223. package/dist/utils/index.d.ts +4 -0
  224. package/dist/utils/index.d.ts.map +1 -0
  225. package/dist/utils/index.js +4 -0
  226. package/dist/utils/index.js.map +1 -0
  227. package/dist/utils/similarity.d.ts +31 -0
  228. package/dist/utils/similarity.d.ts.map +1 -0
  229. package/dist/utils/similarity.js +107 -0
  230. package/dist/utils/similarity.js.map +1 -0
  231. package/dist/utils/storage.d.ts +106 -0
  232. package/dist/utils/storage.d.ts.map +1 -0
  233. package/dist/utils/storage.js +203 -0
  234. package/dist/utils/storage.js.map +1 -0
  235. package/dist/utils/validation.d.ts +129 -0
  236. package/dist/utils/validation.d.ts.map +1 -0
  237. package/dist/utils/validation.js +171 -0
  238. package/dist/utils/validation.js.map +1 -0
  239. package/package.json +50 -34
  240. package/scripts/migrate-to-playbooks.ts +307 -0
  241. package/src/agents/index.ts +14 -0
  242. package/src/agents/mock-provider.ts +93 -0
  243. package/src/agents/types.ts +137 -0
  244. package/src/atlas.ts +560 -0
  245. package/src/bin/cognitive-core.ts +470 -0
  246. package/src/embeddings/bm25.ts +337 -0
  247. package/src/embeddings/index.ts +39 -0
  248. package/src/embeddings/manager.ts +288 -0
  249. package/src/embeddings/provider.ts +311 -0
  250. package/src/embeddings/vector-store.ts +353 -0
  251. package/src/factory.ts +263 -0
  252. package/src/index.ts +246 -0
  253. package/src/learning/analyzer.ts +335 -0
  254. package/src/learning/effectiveness.ts +428 -0
  255. package/src/learning/index.ts +58 -0
  256. package/src/learning/llm-extractor.ts +542 -0
  257. package/src/learning/meta-learner.ts +516 -0
  258. package/src/learning/pipeline.ts +244 -0
  259. package/src/learning/playbook-extractor.ts +702 -0
  260. package/src/learning/usage-inference.ts +372 -0
  261. package/src/mcp/index.ts +12 -0
  262. package/src/mcp/playbook-server.ts +565 -0
  263. package/src/memory/curated-loader.ts +160 -0
  264. package/src/memory/experience.ts +515 -0
  265. package/src/memory/index.ts +27 -0
  266. package/src/memory/meta.ts +506 -0
  267. package/src/memory/playbook.ts +493 -0
  268. package/src/memory/system.ts +551 -0
  269. package/src/runtime/backends/acp.ts +378 -0
  270. package/src/runtime/backends/index.ts +24 -0
  271. package/src/runtime/backends/mock.ts +218 -0
  272. package/src/runtime/backends/subprocess.ts +356 -0
  273. package/src/runtime/flows/learning.ts +183 -0
  274. package/src/runtime/flows/validation.ts +381 -0
  275. package/src/runtime/index.ts +53 -0
  276. package/src/runtime/manager.ts +541 -0
  277. package/src/runtime/types.ts +157 -0
  278. package/src/search/evaluator.ts +474 -0
  279. package/src/search/index.ts +59 -0
  280. package/src/search/refinement-loop.ts +363 -0
  281. package/src/search/refinement-types.ts +159 -0
  282. package/src/search/router.ts +261 -0
  283. package/src/search/solver.ts +303 -0
  284. package/src/search/verification-runner.ts +570 -0
  285. package/src/surfacing/index.ts +6 -0
  286. package/src/surfacing/skill-library.ts +594 -0
  287. package/src/types/config.ts +333 -0
  288. package/src/types/index.ts +130 -0
  289. package/src/types/memory.ts +270 -0
  290. package/src/types/meta.ts +218 -0
  291. package/src/types/outcome.ts +66 -0
  292. package/src/types/playbook.ts +196 -0
  293. package/src/types/step.ts +40 -0
  294. package/src/types/task.ts +52 -0
  295. package/src/types/trajectory.ts +80 -0
  296. package/src/utils/index.ts +38 -0
  297. package/src/utils/similarity.ts +139 -0
  298. package/src/utils/storage.ts +249 -0
  299. package/src/utils/validation.ts +286 -0
  300. package/tests/embeddings/bm25.test.ts +130 -0
  301. package/tests/embeddings/manager.test.ts +205 -0
  302. package/tests/integration/atlas.test.ts +266 -0
  303. package/tests/integration/e2e.test.ts +929 -0
  304. package/tests/learning/analyzer.test.ts +426 -0
  305. package/tests/learning/effectiveness.test.ts +542 -0
  306. package/tests/learning/pipeline.test.ts +176 -0
  307. package/tests/learning/playbook-extractor-provenance.test.ts +114 -0
  308. package/tests/learning/usage-inference.test.ts +254 -0
  309. package/tests/mcp/playbook-server.test.ts +252 -0
  310. package/tests/memory/experience.test.ts +198 -0
  311. package/tests/memory/playbook.test.ts +338 -0
  312. package/tests/memory/provenance.test.ts +639 -0
  313. package/tests/memory/system.test.ts +325 -0
  314. package/tests/runtime/agent-manager.test.ts +512 -0
  315. package/tests/runtime/mock-backend.test.ts +248 -0
  316. package/tests/search/refinement-loop.test.ts +468 -0
  317. package/tests/search/refinement.test.ts +267 -0
  318. package/tests/search/router.test.ts +427 -0
  319. package/tests/surfacing/skill-library.test.ts +292 -0
  320. package/tests/types/outcome.test.ts +147 -0
  321. package/tests/types/step.test.ts +133 -0
  322. package/tests/types/task.test.ts +158 -0
  323. package/tests/types/trajectory.test.ts +253 -0
  324. package/tests/utils/similarity.test.ts +188 -0
  325. package/tests/utils/validation.test.ts +252 -0
  326. package/tsconfig.json +25 -0
  327. package/vitest.config.ts +22 -0
  328. package/dist/index.d.mts +0 -466
  329. package/dist/index.mjs +0 -478
@@ -0,0 +1,515 @@
1
+ import type { Experience } from '../types/index.js';
2
+ import { JsonStore } from '../utils/storage.js';
3
+ import { findTopK } from '../utils/similarity.js';
4
+
5
+ /**
6
+ * Result of pruning operation
7
+ */
8
+ export interface PruneResult {
9
+ /** IDs of pruned experiences */
10
+ prunedIds: string[];
11
+ /** IDs organized by pruning reason */
12
+ prunedByReason: {
13
+ age: string[];
14
+ usage: string[];
15
+ capacity: string[];
16
+ redundancy: string[];
17
+ failedOld: string[];
18
+ };
19
+ /** Total number pruned */
20
+ totalPruned: number;
21
+ /** Count remaining after pruning */
22
+ remainingCount: number;
23
+ }
24
+
25
+ /**
26
+ * Experience Memory - ReMem-style task-level retrieval
27
+ * Stores complete (task, solution, feedback) tuples
28
+ */
29
+ export class ExperienceMemory {
30
+ private _store: JsonStore<Experience>;
31
+ private initialized = false;
32
+
33
+ constructor(baseDir: string) {
34
+ this._store = new JsonStore<Experience>(baseDir, 'experiences', {
35
+ autoSaveInterval: 60000,
36
+ pretty: true,
37
+ });
38
+ }
39
+
40
+ async init(): Promise<void> {
41
+ if (this.initialized) return;
42
+ await this._store.init();
43
+ this.initialized = true;
44
+ }
45
+
46
+ /**
47
+ * Store a new experience
48
+ */
49
+ async add(experience: Experience): Promise<void> {
50
+ await this.init();
51
+ this._store.set(experience.id, experience);
52
+ await this._store.save(experience.id);
53
+ }
54
+
55
+ /**
56
+ * Retrieve an experience by ID
57
+ */
58
+ async get(id: string): Promise<Experience | undefined> {
59
+ await this.init();
60
+ return this._store.get(id);
61
+ }
62
+
63
+ /**
64
+ * Find similar experiences
65
+ * Uses embedding similarity if available, falls back to text similarity
66
+ */
67
+ async findSimilar(
68
+ query: string | number[],
69
+ options?: {
70
+ k?: number;
71
+ domain?: string;
72
+ minScore?: number;
73
+ successOnly?: boolean;
74
+ }
75
+ ): Promise<Array<{ experience: Experience; score: number }>> {
76
+ await this.init();
77
+
78
+ const k = options?.k ?? 4; // ReMem default
79
+ let experiences = this._store.values();
80
+
81
+ // Filter by domain if specified
82
+ if (options?.domain) {
83
+ experiences = experiences.filter((e) => e.domain === options.domain);
84
+ }
85
+
86
+ // Filter by success if specified
87
+ if (options?.successOnly) {
88
+ experiences = experiences.filter((e) => e.success);
89
+ }
90
+
91
+ // Find similar experiences
92
+ const results = findTopK(
93
+ query,
94
+ experiences,
95
+ (e) => (Array.isArray(query) ? e.embedding : e.taskInput),
96
+ k
97
+ ).map(({ item, score }) => ({
98
+ experience: item,
99
+ score,
100
+ }));
101
+
102
+ // Filter by minimum score
103
+ if (options?.minScore !== undefined) {
104
+ return results.filter((r) => r.score >= options.minScore!);
105
+ }
106
+
107
+ return results;
108
+ }
109
+
110
+ /**
111
+ * Update an experience (e.g., after refinement)
112
+ */
113
+ async update(
114
+ id: string,
115
+ updates: Partial<Experience>
116
+ ): Promise<Experience | undefined> {
117
+ await this.init();
118
+ const existing = this._store.get(id);
119
+ if (!existing) return undefined;
120
+
121
+ const updated = {
122
+ ...existing,
123
+ ...updates,
124
+ id: existing.id, // Preserve ID
125
+ };
126
+ this._store.set(id, updated);
127
+ await this._store.save(id);
128
+ return updated;
129
+ }
130
+
131
+ /**
132
+ * Increment usage count
133
+ */
134
+ async recordUsage(id: string): Promise<void> {
135
+ await this.init();
136
+ const existing = this._store.get(id);
137
+ if (existing) {
138
+ existing.usageCount++;
139
+ existing.lastAccessedAt = new Date();
140
+ this._store.set(id, existing);
141
+ }
142
+ }
143
+
144
+ /**
145
+ * Get all experiences
146
+ */
147
+ async getAll(): Promise<Experience[]> {
148
+ await this.init();
149
+ return this._store.values();
150
+ }
151
+
152
+ /**
153
+ * Get experiences by trajectory
154
+ */
155
+ async getByTrajectory(trajectoryId: string): Promise<Experience[]> {
156
+ await this.init();
157
+ return this._store.values().filter((e) => e.trajectoryId === trajectoryId);
158
+ }
159
+
160
+ /**
161
+ * Prune low-value experiences
162
+ */
163
+ async prune(options?: {
164
+ maxCount?: number;
165
+ minUsageCount?: number;
166
+ maxAgeDays?: number;
167
+ removeFailedOlderThanDays?: number;
168
+ similarityThreshold?: number;
169
+ preserveDomainCoverage?: boolean;
170
+ }): Promise<PruneResult> {
171
+ await this.init();
172
+ const pruned: string[] = [];
173
+ const prunedByReason: PruneResult['prunedByReason'] = {
174
+ age: [],
175
+ usage: [],
176
+ capacity: [],
177
+ redundancy: [],
178
+ failedOld: [],
179
+ };
180
+ let experiences = this._store.values();
181
+
182
+ // 1. Prune by age
183
+ if (options?.maxAgeDays) {
184
+ const cutoff = Date.now() - options.maxAgeDays * 24 * 60 * 60 * 1000;
185
+ const oldExperiences = experiences.filter(
186
+ (e) => e.createdAt.getTime() < cutoff
187
+ );
188
+ for (const exp of oldExperiences) {
189
+ this._store.delete(exp.id);
190
+ pruned.push(exp.id);
191
+ prunedByReason.age.push(exp.id);
192
+ }
193
+ experiences = experiences.filter((e) => e.createdAt.getTime() >= cutoff);
194
+ }
195
+
196
+ // 2. Prune failed experiences older than threshold
197
+ if (options?.removeFailedOlderThanDays) {
198
+ const cutoff =
199
+ Date.now() - options.removeFailedOlderThanDays * 24 * 60 * 60 * 1000;
200
+ const failedOld = experiences.filter(
201
+ (e) => !e.success && e.createdAt.getTime() < cutoff
202
+ );
203
+ for (const exp of failedOld) {
204
+ this._store.delete(exp.id);
205
+ pruned.push(exp.id);
206
+ prunedByReason.failedOld.push(exp.id);
207
+ }
208
+ experiences = experiences.filter(
209
+ (e) => e.success || e.createdAt.getTime() >= cutoff
210
+ );
211
+ }
212
+
213
+ // 3. Prune by minimum usage count
214
+ if (options?.minUsageCount !== undefined) {
215
+ const lowUsage = experiences.filter(
216
+ (e) => e.usageCount < options.minUsageCount!
217
+ );
218
+ // Only prune low-usage if they're also old (>7 days)
219
+ const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
220
+ for (const exp of lowUsage) {
221
+ if (exp.createdAt.getTime() < sevenDaysAgo) {
222
+ this._store.delete(exp.id);
223
+ pruned.push(exp.id);
224
+ prunedByReason.usage.push(exp.id);
225
+ }
226
+ }
227
+ experiences = this._store.values(); // Refresh
228
+ }
229
+
230
+ // 4. Prune redundant/similar experiences
231
+ if (options?.similarityThreshold) {
232
+ const redundant = await this.findRedundant(
233
+ experiences,
234
+ options.similarityThreshold,
235
+ options.preserveDomainCoverage
236
+ );
237
+ for (const exp of redundant) {
238
+ this._store.delete(exp.id);
239
+ pruned.push(exp.id);
240
+ prunedByReason.redundancy.push(exp.id);
241
+ }
242
+ experiences = this._store.values(); // Refresh
243
+ }
244
+
245
+ // 5. Prune by count (keep most valuable)
246
+ if (options?.maxCount && experiences.length > options.maxCount) {
247
+ // Sort by value
248
+ experiences.sort((a, b) => {
249
+ const scoreA = this.computeValue(a);
250
+ const scoreB = this.computeValue(b);
251
+ return scoreB - scoreA;
252
+ });
253
+
254
+ // If preserving domain coverage, ensure each domain keeps some
255
+ if (options.preserveDomainCoverage) {
256
+ const kept = this.selectWithDomainCoverage(
257
+ experiences,
258
+ options.maxCount
259
+ );
260
+ const keptIds = new Set(kept.map((e) => e.id));
261
+ for (const exp of experiences) {
262
+ if (!keptIds.has(exp.id)) {
263
+ this._store.delete(exp.id);
264
+ pruned.push(exp.id);
265
+ prunedByReason.capacity.push(exp.id);
266
+ }
267
+ }
268
+ } else {
269
+ const toRemove = experiences.slice(options.maxCount);
270
+ for (const exp of toRemove) {
271
+ this._store.delete(exp.id);
272
+ pruned.push(exp.id);
273
+ prunedByReason.capacity.push(exp.id);
274
+ }
275
+ }
276
+ }
277
+
278
+ // Save changes
279
+ if (pruned.length > 0) {
280
+ await this._store.flush();
281
+ }
282
+
283
+ return {
284
+ prunedIds: pruned,
285
+ prunedByReason,
286
+ totalPruned: pruned.length,
287
+ remainingCount: this._store.size(),
288
+ };
289
+ }
290
+
291
+ /**
292
+ * Find redundant experiences (similar to others, lower value)
293
+ */
294
+ private async findRedundant(
295
+ experiences: Experience[],
296
+ threshold: number,
297
+ preserveDomainCoverage = true
298
+ ): Promise<Experience[]> {
299
+ const redundant: Experience[] = [];
300
+ const kept = new Set<string>();
301
+ const domainCounts: Record<string, number> = {};
302
+
303
+ // Sort by value (highest first)
304
+ const sorted = [...experiences].sort((a, b) => {
305
+ return this.computeValue(b) - this.computeValue(a);
306
+ });
307
+
308
+ for (const exp of sorted) {
309
+ // Check if similar to any kept experience
310
+ let isDuplicate = false;
311
+ for (const keptId of kept) {
312
+ const keptExp = experiences.find((e) => e.id === keptId);
313
+ if (keptExp && this.computeSimilarity(exp, keptExp) > threshold) {
314
+ isDuplicate = true;
315
+ break;
316
+ }
317
+ }
318
+
319
+ if (isDuplicate) {
320
+ // Check domain coverage
321
+ if (preserveDomainCoverage) {
322
+ const domainCount = domainCounts[exp.domain] ?? 0;
323
+ if (domainCount < 3) {
324
+ // Keep at least 3 per domain
325
+ kept.add(exp.id);
326
+ domainCounts[exp.domain] = domainCount + 1;
327
+ continue;
328
+ }
329
+ }
330
+ redundant.push(exp);
331
+ } else {
332
+ kept.add(exp.id);
333
+ domainCounts[exp.domain] = (domainCounts[exp.domain] ?? 0) + 1;
334
+ }
335
+ }
336
+
337
+ return redundant;
338
+ }
339
+
340
+ /**
341
+ * Compute similarity between two experiences
342
+ */
343
+ private computeSimilarity(a: Experience, b: Experience): number {
344
+ // If both have embeddings, use cosine similarity
345
+ if (a.embedding && b.embedding) {
346
+ let dot = 0;
347
+ let normA = 0;
348
+ let normB = 0;
349
+ for (let i = 0; i < a.embedding.length; i++) {
350
+ dot += a.embedding[i] * b.embedding[i];
351
+ normA += a.embedding[i] * a.embedding[i];
352
+ normB += b.embedding[i] * b.embedding[i];
353
+ }
354
+ return dot / (Math.sqrt(normA) * Math.sqrt(normB) || 1);
355
+ }
356
+
357
+ // Fall back to Jaccard similarity on task input words
358
+ const wordsA = new Set(a.taskInput.toLowerCase().split(/\s+/));
359
+ const wordsB = new Set(b.taskInput.toLowerCase().split(/\s+/));
360
+ const intersection = new Set([...wordsA].filter((x) => wordsB.has(x)));
361
+ const union = new Set([...wordsA, ...wordsB]);
362
+ return intersection.size / union.size;
363
+ }
364
+
365
+ /**
366
+ * Select experiences while preserving domain coverage
367
+ */
368
+ private selectWithDomainCoverage(
369
+ experiences: Experience[],
370
+ maxCount: number
371
+ ): Experience[] {
372
+ const selected: Experience[] = [];
373
+ const domainCounts: Record<string, number> = {};
374
+ const domains = [...new Set(experiences.map((e) => e.domain))];
375
+ const minPerDomain = Math.max(1, Math.floor(maxCount / (domains.length * 2)));
376
+
377
+ // First pass: ensure minimum per domain
378
+ for (const domain of domains) {
379
+ const domainExps = experiences
380
+ .filter((e) => e.domain === domain)
381
+ .sort((a, b) => this.computeValue(b) - this.computeValue(a));
382
+
383
+ for (let i = 0; i < Math.min(minPerDomain, domainExps.length); i++) {
384
+ if (selected.length < maxCount) {
385
+ selected.push(domainExps[i]);
386
+ domainCounts[domain] = (domainCounts[domain] ?? 0) + 1;
387
+ }
388
+ }
389
+ }
390
+
391
+ // Second pass: fill remaining slots with highest value
392
+ const selectedIds = new Set(selected.map((e) => e.id));
393
+ const remaining = experiences
394
+ .filter((e) => !selectedIds.has(e.id))
395
+ .sort((a, b) => this.computeValue(b) - this.computeValue(a));
396
+
397
+ for (const exp of remaining) {
398
+ if (selected.length >= maxCount) break;
399
+ selected.push(exp);
400
+ }
401
+
402
+ return selected;
403
+ }
404
+
405
+ /**
406
+ * Compute value score for an experience
407
+ */
408
+ private computeValue(exp: Experience): number {
409
+ const ageMs = Date.now() - exp.createdAt.getTime();
410
+ const ageDays = ageMs / (1000 * 60 * 60 * 24);
411
+ const recencyScore = Math.exp(-ageDays / 30); // Decay over ~30 days
412
+
413
+ // Access recency bonus
414
+ const accessAgeMs = exp.lastAccessedAt
415
+ ? Date.now() - exp.lastAccessedAt.getTime()
416
+ : ageMs;
417
+ const accessAgeDays = accessAgeMs / (1000 * 60 * 60 * 24);
418
+ const accessRecencyScore = Math.exp(-accessAgeDays / 14); // Decay over ~14 days
419
+
420
+ return (
421
+ (exp.success ? 1 : 0.3) * // Success bonus
422
+ (1 + Math.log(exp.usageCount + 1)) * // Usage bonus (log scale)
423
+ (recencyScore * 0.5 + accessRecencyScore * 0.5) // Combined recency
424
+ );
425
+ }
426
+
427
+ /**
428
+ * Get pruning statistics
429
+ */
430
+ async getPruningStats(): Promise<{
431
+ total: number;
432
+ byDomain: Record<string, number>;
433
+ bySuccess: { success: number; failure: number };
434
+ oldestDate: Date | null;
435
+ newestDate: Date | null;
436
+ averageUsage: number;
437
+ suggestedPrunes: {
438
+ lowUsage: number;
439
+ old: number;
440
+ failedOld: number;
441
+ };
442
+ }> {
443
+ await this.init();
444
+ const experiences = this._store.values();
445
+
446
+ const byDomain: Record<string, number> = {};
447
+ let successCount = 0;
448
+ let totalUsage = 0;
449
+ let oldestDate: Date | null = null;
450
+ let newestDate: Date | null = null;
451
+
452
+ const sevenDaysAgo = Date.now() - 7 * 24 * 60 * 60 * 1000;
453
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;
454
+ let lowUsageCount = 0;
455
+ let oldCount = 0;
456
+ let failedOldCount = 0;
457
+
458
+ for (const exp of experiences) {
459
+ // Domain counts
460
+ byDomain[exp.domain] = (byDomain[exp.domain] ?? 0) + 1;
461
+
462
+ // Success counts
463
+ if (exp.success) successCount++;
464
+
465
+ // Usage sum
466
+ totalUsage += exp.usageCount;
467
+
468
+ // Date tracking
469
+ const createdAt = exp.createdAt;
470
+ if (!oldestDate || createdAt < oldestDate) oldestDate = createdAt;
471
+ if (!newestDate || createdAt > newestDate) newestDate = createdAt;
472
+
473
+ // Suggested prunes
474
+ if (exp.usageCount === 0 && createdAt.getTime() < sevenDaysAgo) {
475
+ lowUsageCount++;
476
+ }
477
+ if (createdAt.getTime() < thirtyDaysAgo) {
478
+ oldCount++;
479
+ if (!exp.success) failedOldCount++;
480
+ }
481
+ }
482
+
483
+ return {
484
+ total: experiences.length,
485
+ byDomain,
486
+ bySuccess: {
487
+ success: successCount,
488
+ failure: experiences.length - successCount,
489
+ },
490
+ oldestDate,
491
+ newestDate,
492
+ averageUsage: experiences.length > 0 ? totalUsage / experiences.length : 0,
493
+ suggestedPrunes: {
494
+ lowUsage: lowUsageCount,
495
+ old: oldCount,
496
+ failedOld: failedOldCount,
497
+ },
498
+ };
499
+ }
500
+
501
+ /**
502
+ * Get count
503
+ */
504
+ async count(): Promise<number> {
505
+ await this.init();
506
+ return this._store.size();
507
+ }
508
+
509
+ /**
510
+ * Close the store
511
+ */
512
+ async close(): Promise<void> {
513
+ await this._store.close();
514
+ }
515
+ }
@@ -0,0 +1,27 @@
1
+ export { ExperienceMemory, type PruneResult } from './experience.js';
2
+ export {
3
+ MemorySystem,
4
+ createMemorySystem,
5
+ type MemoryQueryResult,
6
+ type MemoryQueryResultV2,
7
+ } from './system.js';
8
+
9
+ // Playbook-based memory
10
+ export {
11
+ PlaybookLibrary,
12
+ createPlaybookLibrary,
13
+ type PlaybookMatch,
14
+ } from './playbook.js';
15
+
16
+ // Meta-learning memory
17
+ export {
18
+ MetaMemory,
19
+ createMetaMemory,
20
+ } from './meta.js';
21
+
22
+ // Curated playbook loading
23
+ export {
24
+ loadCuratedPlaybooks,
25
+ type CuratedPlaybookFile,
26
+ type CuratedLoadResult,
27
+ } from './curated-loader.js';