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,267 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import {
3
+ createEvaluationResult,
4
+ scoreToQuality,
5
+ isQualityAcceptable,
6
+ type EvaluationResult,
7
+ type QualityLevel,
8
+ } from '../../src/search/refinement-types.js';
9
+ import {
10
+ SolutionEvaluator,
11
+ createSolutionEvaluator,
12
+ type VerificationResult,
13
+ } from '../../src/search/evaluator.js';
14
+ import type { Trajectory } from '../../src/types/trajectory.js';
15
+ import type { Task } from '../../src/types/task.js';
16
+
17
+ describe('Refinement Types', () => {
18
+ describe('scoreToQuality', () => {
19
+ it('should return excellent for scores >= 0.85', () => {
20
+ expect(scoreToQuality(0.85)).toBe('excellent');
21
+ expect(scoreToQuality(0.9)).toBe('excellent');
22
+ expect(scoreToQuality(1.0)).toBe('excellent');
23
+ });
24
+
25
+ it('should return good for scores >= 0.7 and < 0.85', () => {
26
+ expect(scoreToQuality(0.7)).toBe('good');
27
+ expect(scoreToQuality(0.8)).toBe('good');
28
+ expect(scoreToQuality(0.84)).toBe('good');
29
+ });
30
+
31
+ it('should return needs_work for scores >= 0.4 and < 0.7', () => {
32
+ expect(scoreToQuality(0.4)).toBe('needs_work');
33
+ expect(scoreToQuality(0.5)).toBe('needs_work');
34
+ expect(scoreToQuality(0.69)).toBe('needs_work');
35
+ });
36
+
37
+ it('should return poor for scores < 0.4', () => {
38
+ expect(scoreToQuality(0)).toBe('poor');
39
+ expect(scoreToQuality(0.2)).toBe('poor');
40
+ expect(scoreToQuality(0.39)).toBe('poor');
41
+ });
42
+ });
43
+
44
+ describe('isQualityAcceptable', () => {
45
+ it('should accept quality >= minAcceptable', () => {
46
+ expect(isQualityAcceptable('excellent', 'good')).toBe(true);
47
+ expect(isQualityAcceptable('good', 'good')).toBe(true);
48
+ expect(isQualityAcceptable('excellent', 'excellent')).toBe(true);
49
+ });
50
+
51
+ it('should reject quality < minAcceptable', () => {
52
+ expect(isQualityAcceptable('needs_work', 'good')).toBe(false);
53
+ expect(isQualityAcceptable('poor', 'good')).toBe(false);
54
+ expect(isQualityAcceptable('good', 'excellent')).toBe(false);
55
+ });
56
+
57
+ it('should use good as default minAcceptable', () => {
58
+ expect(isQualityAcceptable('good')).toBe(true);
59
+ expect(isQualityAcceptable('excellent')).toBe(true);
60
+ expect(isQualityAcceptable('needs_work')).toBe(false);
61
+ });
62
+ });
63
+
64
+ describe('createEvaluationResult', () => {
65
+ it('should create a valid evaluation result', () => {
66
+ const result = createEvaluationResult({
67
+ quality: 'good',
68
+ score: 0.75,
69
+ acceptable: true,
70
+ issues: [],
71
+ method: 'verification',
72
+ });
73
+
74
+ expect(result.quality).toBe('good');
75
+ expect(result.score).toBe(0.75);
76
+ expect(result.acceptable).toBe(true);
77
+ expect(result.issues).toEqual([]);
78
+ expect(result.method).toBe('verification');
79
+ });
80
+
81
+ it('should validate score bounds', () => {
82
+ expect(() => createEvaluationResult({
83
+ quality: 'good',
84
+ score: 1.5,
85
+ acceptable: true,
86
+ method: 'verification',
87
+ })).toThrow();
88
+
89
+ expect(() => createEvaluationResult({
90
+ quality: 'good',
91
+ score: -0.1,
92
+ acceptable: true,
93
+ method: 'verification',
94
+ })).toThrow();
95
+ });
96
+
97
+ it('should include issues when provided', () => {
98
+ const result = createEvaluationResult({
99
+ quality: 'needs_work',
100
+ score: 0.5,
101
+ acceptable: false,
102
+ issues: [
103
+ { type: 'incomplete', description: 'Missing tests', severity: 'major' },
104
+ ],
105
+ method: 'agent',
106
+ });
107
+
108
+ expect(result.issues.length).toBe(1);
109
+ expect(result.issues[0].type).toBe('incomplete');
110
+ expect(result.issues[0].description).toBe('Missing tests');
111
+ });
112
+ });
113
+ });
114
+
115
+ describe('SolutionEvaluator', () => {
116
+ const createMockTrajectory = (success: boolean): Trajectory => ({
117
+ id: 'test-trajectory',
118
+ task: {
119
+ id: 'test-task',
120
+ description: 'Test task',
121
+ domain: 'test',
122
+ context: {},
123
+ metadata: {},
124
+ createdAt: new Date(),
125
+ },
126
+ steps: [
127
+ {
128
+ action: 'test action',
129
+ observation: 'test observation',
130
+ metadata: {},
131
+ },
132
+ ],
133
+ outcome: {
134
+ success,
135
+ partialScore: success ? 1.0 : 0.0,
136
+ errorInfo: success ? undefined : 'Test error',
137
+ verificationDetails: {},
138
+ solution: success ? 'Test solution' : undefined,
139
+ },
140
+ agentId: 'test-agent',
141
+ timestamp: new Date(),
142
+ llmCalls: 1,
143
+ totalTokens: 100,
144
+ wallTimeSeconds: 1,
145
+ metadata: {},
146
+ });
147
+
148
+ const createMockTask = (): Task => ({
149
+ id: 'test-task',
150
+ description: 'Test task description',
151
+ domain: 'test',
152
+ context: {},
153
+ metadata: {},
154
+ createdAt: new Date(),
155
+ });
156
+
157
+ describe('heuristic evaluation', () => {
158
+ let evaluator: SolutionEvaluator;
159
+
160
+ beforeEach(() => {
161
+ evaluator = createSolutionEvaluator(null);
162
+ });
163
+
164
+ it('should evaluate successful trajectory positively', async () => {
165
+ const trajectory = createMockTrajectory(true);
166
+ const task = createMockTask();
167
+
168
+ const result = await evaluator.evaluate(trajectory, task);
169
+
170
+ expect(result.score).toBeGreaterThan(0.5);
171
+ expect(result.method).toBe('heuristic');
172
+ });
173
+
174
+ it('should evaluate failed trajectory negatively', async () => {
175
+ const trajectory = createMockTrajectory(false);
176
+ const task = createMockTask();
177
+
178
+ const result = await evaluator.evaluate(trajectory, task);
179
+
180
+ expect(result.score).toBeLessThanOrEqual(0.5);
181
+ expect(result.acceptable).toBe(false);
182
+ expect(result.issues.length).toBeGreaterThan(0);
183
+ });
184
+
185
+ it('should penalize trajectories with no steps', async () => {
186
+ const trajectory = createMockTrajectory(false);
187
+ trajectory.steps = [];
188
+ const task = createMockTask();
189
+
190
+ const result = await evaluator.evaluate(trajectory, task);
191
+
192
+ expect(result.score).toBeLessThan(0.5);
193
+ const incompleteIssue = result.issues.find(i => i.type === 'incomplete');
194
+ expect(incompleteIssue).toBeDefined();
195
+ });
196
+
197
+ it('should penalize long trajectories', async () => {
198
+ const trajectory = createMockTrajectory(true);
199
+ trajectory.steps = Array(25).fill({
200
+ action: 'action',
201
+ observation: 'observation',
202
+ metadata: {},
203
+ });
204
+ const task = createMockTask();
205
+
206
+ const result = await evaluator.evaluate(trajectory, task);
207
+
208
+ const inefficientIssue = result.issues.find(i => i.type === 'inefficient');
209
+ expect(inefficientIssue).toBeDefined();
210
+ });
211
+ });
212
+
213
+ describe('verification', () => {
214
+ it('should use registered verifier for domain', async () => {
215
+ const evaluator = createSolutionEvaluator(null);
216
+
217
+ const mockVerifier = vi.fn().mockResolvedValue({
218
+ passed: true,
219
+ confidence: 0.9,
220
+ } as VerificationResult);
221
+
222
+ evaluator.registerVerifier('test', mockVerifier);
223
+
224
+ const trajectory = createMockTrajectory(true);
225
+ const task = createMockTask();
226
+
227
+ const result = await evaluator.evaluate(trajectory, task);
228
+
229
+ expect(mockVerifier).toHaveBeenCalled();
230
+ expect(result.method).toBe('verification');
231
+ expect(result.acceptable).toBe(true);
232
+ });
233
+
234
+ it('should fall back to heuristic if verifier fails', async () => {
235
+ const evaluator = createSolutionEvaluator(null);
236
+
237
+ const mockVerifier = vi.fn().mockRejectedValue(new Error('Verification error'));
238
+ evaluator.registerVerifier('test', mockVerifier);
239
+
240
+ const trajectory = createMockTrajectory(true);
241
+ const task = createMockTask();
242
+
243
+ const result = await evaluator.evaluate(trajectory, task);
244
+
245
+ expect(result.method).toBe('heuristic');
246
+ });
247
+
248
+ it('should not use verifier for unknown domain', async () => {
249
+ const evaluator = createSolutionEvaluator(null);
250
+
251
+ const mockVerifier = vi.fn().mockResolvedValue({
252
+ passed: true,
253
+ confidence: 0.9,
254
+ } as VerificationResult);
255
+
256
+ evaluator.registerVerifier('other', mockVerifier);
257
+
258
+ const trajectory = createMockTrajectory(true);
259
+ const task = createMockTask();
260
+
261
+ const result = await evaluator.evaluate(trajectory, task);
262
+
263
+ expect(mockVerifier).not.toHaveBeenCalled();
264
+ expect(result.method).toBe('heuristic');
265
+ });
266
+ });
267
+ });
@@ -0,0 +1,427 @@
1
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
2
+ import { TaskRouter, createRouter, type RoutingDecision } from '../../src/search/router.js';
3
+ import { createMemorySystem } from '../../src/memory/system.js';
4
+ import { createTask } from '../../src/types/task.js';
5
+ import type { MemorySystem } from '../../src/memory/system.js';
6
+ import type { MetaLearner } from '../../src/learning/meta-learner.js';
7
+ import { mkdtemp, rm } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ import { tmpdir } from 'node:os';
10
+
11
+ describe('TaskRouter', () => {
12
+ let tempDir: string;
13
+ let memory: MemorySystem;
14
+ let router: TaskRouter;
15
+
16
+ beforeEach(async () => {
17
+ tempDir = await mkdtemp(join(tmpdir(), 'router-test-'));
18
+ memory = createMemorySystem(tempDir);
19
+ await memory.init();
20
+ router = createRouter(memory);
21
+ });
22
+
23
+ afterEach(async () => {
24
+ await memory.close();
25
+ await rm(tempDir, { recursive: true, force: true });
26
+ });
27
+
28
+ describe('basic routing', () => {
29
+ it('should return fallback strategy when no memory exists', async () => {
30
+ const task = createTask({
31
+ domain: 'test',
32
+ description: 'A completely new task with no similar experiences',
33
+ });
34
+
35
+ const decision = await router.route(task);
36
+
37
+ expect(decision.strategy).toBe('fallback');
38
+ expect(decision.confidence).toBeLessThan(0.5);
39
+ expect(decision.memoryContext).toBeDefined();
40
+ expect(decision.reasoning).toContain('No relevant memory');
41
+ });
42
+
43
+ it('should return direct strategy when high-confidence playbook exists', async () => {
44
+ // Add a high-confidence playbook with very matching situations
45
+ await memory.playbooks.add({
46
+ id: 'playbook-1',
47
+ name: 'Fix TypeScript errors',
48
+ applicability: {
49
+ situations: ['Fix TypeScript type error in user module', 'TypeScript compilation error', 'Type mismatch in code'],
50
+ triggers: ['tsc error', 'type error', 'TypeScript type error'],
51
+ antiPatterns: [],
52
+ domains: ['typescript', 'code'],
53
+ },
54
+ guidance: {
55
+ strategy: 'Read error message, identify type mismatch, fix types',
56
+ tactics: ['Check variable types', 'Add type annotations'],
57
+ steps: ['Read error', 'Find source', 'Fix type'],
58
+ },
59
+ verification: {
60
+ successIndicators: ['No compilation errors'],
61
+ failureIndicators: ['Still has errors'],
62
+ },
63
+ evolution: {
64
+ version: '1.0.0',
65
+ createdFrom: [],
66
+ failures: [],
67
+ refinements: [],
68
+ successCount: 10,
69
+ failureCount: 1,
70
+ },
71
+ confidence: 0.9,
72
+ complexity: 'simple',
73
+ estimatedEffort: 1,
74
+ createdAt: new Date(),
75
+ updatedAt: new Date(),
76
+ });
77
+
78
+ const task = createTask({
79
+ domain: 'typescript',
80
+ description: 'Fix TypeScript type error in user module',
81
+ });
82
+
83
+ const decision = await router.route(task);
84
+
85
+ // With matching playbook, should get direct strategy or at least find playbooks
86
+ expect(decision.memoryContext).toBeDefined();
87
+ // Strategy depends on similarity matching - may be direct or explore
88
+ expect(['direct', 'explore', 'fallback']).toContain(decision.strategy);
89
+ });
90
+
91
+ it('should return adapt strategy when similar successful experience exists', async () => {
92
+ // Add a successful experience
93
+ await memory.experiences.add({
94
+ id: 'exp-1',
95
+ taskInput: 'Fix authentication bug in login flow',
96
+ solutionOutput: 'Added proper token validation and error handling',
97
+ feedback: 'Successfully fixed the auth bug',
98
+ success: true,
99
+ domain: 'auth',
100
+ trajectoryId: 'traj-1',
101
+ usageCount: 0,
102
+ createdAt: new Date(),
103
+ metadata: {},
104
+ });
105
+
106
+ const task = createTask({
107
+ domain: 'auth',
108
+ description: 'Fix authentication bug in login flow for mobile',
109
+ });
110
+
111
+ const decision = await router.route(task);
112
+
113
+ // Should find the similar experience
114
+ expect(decision.memoryContext.experiences.length).toBeGreaterThan(0);
115
+ // Strategy depends on similarity score
116
+ expect(['adapt', 'explore', 'direct']).toContain(decision.strategy);
117
+ });
118
+
119
+ it('should return explore strategy when low similarity experiences exist', async () => {
120
+ // Add an experience with somewhat related content
121
+ await memory.experiences.add({
122
+ id: 'exp-partial',
123
+ taskInput: 'Implement user profile page',
124
+ solutionOutput: 'Created React component with user data',
125
+ feedback: 'Profile page works',
126
+ success: true,
127
+ domain: 'frontend',
128
+ trajectoryId: 'traj-partial',
129
+ usageCount: 0,
130
+ createdAt: new Date(),
131
+ metadata: {},
132
+ });
133
+
134
+ const task = createTask({
135
+ domain: 'frontend',
136
+ description: 'Add settings page with dark mode toggle',
137
+ });
138
+
139
+ const decision = await router.route(task);
140
+
141
+ expect(decision.memoryContext).toBeDefined();
142
+ // With partial similarity, should get explore or fallback
143
+ expect(['explore', 'fallback', 'direct']).toContain(decision.strategy);
144
+ });
145
+ });
146
+
147
+ describe('domain routing', () => {
148
+ it('should filter by domain when useDomainRouting is enabled', async () => {
149
+ // Add experiences in different domains
150
+ await memory.experiences.add({
151
+ id: 'exp-frontend',
152
+ taskInput: 'Build React component',
153
+ solutionOutput: 'Created component',
154
+ feedback: 'Works',
155
+ success: true,
156
+ domain: 'frontend',
157
+ trajectoryId: 'traj-fe',
158
+ usageCount: 0,
159
+ createdAt: new Date(),
160
+ metadata: {},
161
+ });
162
+
163
+ await memory.experiences.add({
164
+ id: 'exp-backend',
165
+ taskInput: 'Build API endpoint',
166
+ solutionOutput: 'Created endpoint',
167
+ feedback: 'Works',
168
+ success: true,
169
+ domain: 'backend',
170
+ trajectoryId: 'traj-be',
171
+ usageCount: 0,
172
+ createdAt: new Date(),
173
+ metadata: {},
174
+ });
175
+
176
+ const frontendRouter = createRouter(memory, { useDomainRouting: true });
177
+ const task = createTask({
178
+ domain: 'frontend',
179
+ description: 'Build React component for dashboard',
180
+ });
181
+
182
+ const decision = await frontendRouter.route(task);
183
+
184
+ // Should prioritize frontend experiences
185
+ expect(decision.memoryContext).toBeDefined();
186
+ });
187
+ });
188
+
189
+ describe('configuration', () => {
190
+ it('should respect similarityThreshold config', async () => {
191
+ const strictRouter = createRouter(memory, { similarityThreshold: 0.95 });
192
+
193
+ await memory.experiences.add({
194
+ id: 'exp-strict',
195
+ taskInput: 'Test task',
196
+ solutionOutput: 'Test solution',
197
+ feedback: 'Good',
198
+ success: true,
199
+ domain: 'test',
200
+ trajectoryId: 'traj-strict',
201
+ usageCount: 0,
202
+ createdAt: new Date(),
203
+ metadata: {},
204
+ });
205
+
206
+ const task = createTask({
207
+ domain: 'test',
208
+ description: 'Slightly different test task',
209
+ });
210
+
211
+ const decision = await strictRouter.route(task);
212
+
213
+ // With strict threshold, should fall back more often
214
+ expect(decision.confidence).toBeDefined();
215
+ });
216
+
217
+ it('should use defaultStrategy from config', async () => {
218
+ const exploreRouter = createRouter(memory, { defaultStrategy: 'explore' });
219
+
220
+ const task = createTask({
221
+ domain: 'unknown',
222
+ description: 'Completely novel task',
223
+ });
224
+
225
+ const decision = await exploreRouter.route(task);
226
+
227
+ // When no memory, should use default strategy reasoning
228
+ expect(decision).toBeDefined();
229
+ });
230
+
231
+ it('should update config dynamically', () => {
232
+ router.updateConfig({ similarityThreshold: 0.5 });
233
+ // Config is updated internally
234
+ });
235
+ });
236
+
237
+ describe('routing decision structure', () => {
238
+ it('should include all required fields in routing decision', async () => {
239
+ const task = createTask({
240
+ domain: 'test',
241
+ description: 'Test task',
242
+ });
243
+
244
+ const decision = await router.route(task);
245
+
246
+ expect(decision.strategy).toBeDefined();
247
+ expect(['direct', 'adapt', 'explore', 'fallback']).toContain(decision.strategy);
248
+ expect(decision.confidence).toBeGreaterThanOrEqual(0);
249
+ expect(decision.confidence).toBeLessThanOrEqual(1);
250
+ expect(decision.memoryContext).toBeDefined();
251
+ expect(decision.estimatedBudget).toBeGreaterThan(0);
252
+ expect(decision.reasoning).toBeDefined();
253
+ expect(typeof decision.reasoning).toBe('string');
254
+ });
255
+
256
+ it('should provide estimated budget based on strategy', async () => {
257
+ // Add high-quality playbook for low budget
258
+ await memory.playbooks.add({
259
+ id: 'pb-budget',
260
+ name: 'Quick fix',
261
+ applicability: {
262
+ situations: ['Quick budget test'],
263
+ triggers: ['budget test'],
264
+ antiPatterns: [],
265
+ domains: ['test'],
266
+ },
267
+ guidance: {
268
+ strategy: 'Simple fix',
269
+ tactics: [],
270
+ },
271
+ verification: {
272
+ successIndicators: ['Done'],
273
+ failureIndicators: [],
274
+ },
275
+ evolution: {
276
+ version: '1.0.0',
277
+ createdFrom: [],
278
+ failures: [],
279
+ refinements: [],
280
+ successCount: 5,
281
+ failureCount: 0,
282
+ },
283
+ confidence: 0.9,
284
+ complexity: 'simple',
285
+ estimatedEffort: 1,
286
+ createdAt: new Date(),
287
+ updatedAt: new Date(),
288
+ });
289
+
290
+ const task = createTask({
291
+ domain: 'test',
292
+ description: 'Quick budget test task',
293
+ });
294
+
295
+ const decision = await router.route(task);
296
+
297
+ // Direct strategy with high confidence should have low budget
298
+ if (decision.strategy === 'direct' && decision.confidence > 0.7) {
299
+ expect(decision.estimatedBudget).toBeLessThanOrEqual(4);
300
+ }
301
+ });
302
+ });
303
+
304
+ describe('meta-learning integration', () => {
305
+ it('should apply meta-learning adjustments when metaLearner is set', async () => {
306
+ const mockMetaLearner: MetaLearner = {
307
+ adjustRouting: vi.fn().mockResolvedValue({
308
+ strategy: 'explore',
309
+ confidence: 0.7,
310
+ reasoning: 'Meta-adjusted reasoning',
311
+ }),
312
+ recordOutcome: vi.fn(),
313
+ getActiveGuidance: vi.fn().mockResolvedValue([]),
314
+ generateObservation: vi.fn(),
315
+ } as unknown as MetaLearner;
316
+
317
+ router.setMetaLearner(mockMetaLearner);
318
+
319
+ const task = createTask({
320
+ domain: 'test',
321
+ description: 'Meta-learning test task',
322
+ });
323
+
324
+ const decision = await router.route(task);
325
+
326
+ expect(mockMetaLearner.adjustRouting).toHaveBeenCalled();
327
+ // The decision should reflect meta-learning adjustment
328
+ expect(decision.strategy).toBe('explore');
329
+ expect(decision.appliedMetaStrategies).toContain('meta-learning adjustment');
330
+ });
331
+
332
+ it('should continue with base routing if meta-learning fails', async () => {
333
+ const failingMetaLearner: MetaLearner = {
334
+ adjustRouting: vi.fn().mockRejectedValue(new Error('Meta-learning failed')),
335
+ recordOutcome: vi.fn(),
336
+ getActiveGuidance: vi.fn().mockResolvedValue([]),
337
+ generateObservation: vi.fn(),
338
+ } as unknown as MetaLearner;
339
+
340
+ router.setMetaLearner(failingMetaLearner);
341
+
342
+ const task = createTask({
343
+ domain: 'test',
344
+ description: 'Failing meta test',
345
+ });
346
+
347
+ // Should not throw, should fall back to base routing
348
+ const decision = await router.route(task);
349
+ expect(decision).toBeDefined();
350
+ expect(decision.strategy).toBeDefined();
351
+ });
352
+ });
353
+
354
+ describe('task characteristics extraction', () => {
355
+ it('should identify bug fix tasks', async () => {
356
+ const task = createTask({
357
+ domain: 'code',
358
+ description: 'Fix the bug in user authentication',
359
+ });
360
+
361
+ const decision = await router.route(task);
362
+ expect(decision).toBeDefined();
363
+ });
364
+
365
+ it('should identify testing tasks', async () => {
366
+ const task = createTask({
367
+ domain: 'code',
368
+ description: 'Write unit tests for the payment service',
369
+ });
370
+
371
+ const decision = await router.route(task);
372
+ expect(decision).toBeDefined();
373
+ });
374
+
375
+ it('should identify complex multi-file tasks', async () => {
376
+ const task = createTask({
377
+ domain: 'code',
378
+ description: 'Refactor authentication across multiple files in the codebase',
379
+ });
380
+
381
+ const decision = await router.route(task);
382
+ expect(decision).toBeDefined();
383
+ });
384
+ });
385
+ });
386
+
387
+ describe('createRouter', () => {
388
+ let tempDir: string;
389
+ let memory: MemorySystem;
390
+
391
+ beforeEach(async () => {
392
+ tempDir = await mkdtemp(join(tmpdir(), 'create-router-test-'));
393
+ memory = createMemorySystem(tempDir);
394
+ await memory.init();
395
+ });
396
+
397
+ afterEach(async () => {
398
+ await memory.close();
399
+ await rm(tempDir, { recursive: true, force: true });
400
+ });
401
+
402
+ it('should create a router with default config', () => {
403
+ const router = createRouter(memory);
404
+ expect(router).toBeInstanceOf(TaskRouter);
405
+ });
406
+
407
+ it('should create a router with custom config', () => {
408
+ const router = createRouter(memory, {
409
+ similarityThreshold: 0.7,
410
+ useDomainRouting: false,
411
+ defaultStrategy: 'explore',
412
+ });
413
+ expect(router).toBeInstanceOf(TaskRouter);
414
+ });
415
+
416
+ it('should create a router with meta learner', () => {
417
+ const mockMetaLearner = {
418
+ adjustRouting: vi.fn(),
419
+ recordOutcome: vi.fn(),
420
+ getActiveGuidance: vi.fn(),
421
+ generateObservation: vi.fn(),
422
+ } as unknown as MetaLearner;
423
+
424
+ const router = createRouter(memory, {}, mockMetaLearner);
425
+ expect(router).toBeInstanceOf(TaskRouter);
426
+ });
427
+ });