cognitive-core 0.0.1 → 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 +363 -2
  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 +43 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +84 -0
  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 +61 -9
  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/index.d.ts +0 -4
  329. package/index.js +0 -4
@@ -0,0 +1,702 @@
1
+ /**
2
+ * Playbook Extractor
3
+ * Extracts playbooks from successful trajectories
4
+ * Replaces the old TextPatternExtractor with more intelligent extraction
5
+ */
6
+
7
+ import type {
8
+ Playbook,
9
+ Trajectory,
10
+ Refinement,
11
+ } from '../types/index.js';
12
+ import { createPlaybook } from '../types/index.js';
13
+ import type { AnalysisResult } from './analyzer.js';
14
+ import { textSimilarity } from '../utils/similarity.js';
15
+
16
+ /**
17
+ * Result of playbook extraction
18
+ */
19
+ export interface ExtractedPlaybooks {
20
+ /** Entirely new playbooks */
21
+ new: Playbook[];
22
+ /** Updates to existing playbooks */
23
+ updates: PlaybookUpdate[];
24
+ }
25
+
26
+ /**
27
+ * Update to an existing playbook
28
+ */
29
+ export interface PlaybookUpdate {
30
+ id: string;
31
+ refinement?: Refinement;
32
+ newTrigger?: string;
33
+ newAntiPattern?: string;
34
+ }
35
+
36
+ /**
37
+ * Configuration for playbook extraction
38
+ */
39
+ export interface PlaybookExtractorConfig {
40
+ /** Minimum trajectories needed to create a playbook */
41
+ minTrajectories: number;
42
+ /** Similarity threshold for merging playbooks */
43
+ mergeThreshold: number;
44
+ /** Minimum success rate for extraction */
45
+ minSuccessRate: number;
46
+ }
47
+
48
+ const DEFAULT_CONFIG: PlaybookExtractorConfig = {
49
+ minTrajectories: 2,
50
+ mergeThreshold: 0.85,
51
+ minSuccessRate: 0.6,
52
+ };
53
+
54
+ /**
55
+ * Playbook Extractor
56
+ * Intelligent extraction of playbooks from trajectories
57
+ */
58
+ export class PlaybookExtractor {
59
+ private config: PlaybookExtractorConfig;
60
+
61
+ constructor(config?: Partial<PlaybookExtractorConfig>) {
62
+ this.config = { ...DEFAULT_CONFIG, ...config };
63
+ }
64
+
65
+ /**
66
+ * Extract playbooks from successful trajectories
67
+ */
68
+ async extract(
69
+ trajectories: Trajectory[],
70
+ analyses: AnalysisResult[],
71
+ existingPlaybooks: Playbook[] = []
72
+ ): Promise<ExtractedPlaybooks> {
73
+ const result: ExtractedPlaybooks = {
74
+ new: [],
75
+ updates: [],
76
+ };
77
+
78
+ // Filter to successful, abstractable trajectories
79
+ const candidates = trajectories.filter((_t, i) => {
80
+ const analysis = analyses[i];
81
+ return analysis?.success && analysis.abstractable;
82
+ });
83
+
84
+ if (candidates.length < this.config.minTrajectories) {
85
+ return result;
86
+ }
87
+
88
+ // Group by domain
89
+ const byDomain = this.groupByDomain(candidates);
90
+
91
+ for (const [domain, domainTrajectories] of byDomain) {
92
+ // Extract playbooks from this domain
93
+ const extracted = await this.extractFromDomain(
94
+ domain,
95
+ domainTrajectories,
96
+ analyses,
97
+ existingPlaybooks
98
+ );
99
+
100
+ result.new.push(...extracted.new);
101
+ result.updates.push(...extracted.updates);
102
+ }
103
+
104
+ // Consolidate similar playbooks
105
+ result.new = await this.consolidate(result.new);
106
+
107
+ return result;
108
+ }
109
+
110
+ /**
111
+ * Extract playbooks from a single domain's trajectories
112
+ */
113
+ private async extractFromDomain(
114
+ domain: string,
115
+ trajectories: Trajectory[],
116
+ analyses: AnalysisResult[],
117
+ existingPlaybooks: Playbook[]
118
+ ): Promise<ExtractedPlaybooks> {
119
+ const result: ExtractedPlaybooks = {
120
+ new: [],
121
+ updates: [],
122
+ };
123
+
124
+ // Find common patterns across trajectories
125
+ const patterns = this.findCommonPatterns(trajectories, analyses);
126
+
127
+ for (const pattern of patterns) {
128
+ // Check if similar playbook exists
129
+ const existing = this.findSimilarPlaybook(pattern, existingPlaybooks);
130
+
131
+ if (existing) {
132
+ // Generate update
133
+ const update = this.generateUpdate(existing, pattern, trajectories);
134
+ if (update) {
135
+ result.updates.push(update);
136
+ }
137
+ } else {
138
+ // Create new playbook
139
+ const playbook = this.createPlaybookFromPattern(pattern, domain);
140
+ result.new.push(playbook);
141
+ }
142
+ }
143
+
144
+ return result;
145
+ }
146
+
147
+ /**
148
+ * Find common patterns across trajectories
149
+ */
150
+ private findCommonPatterns(
151
+ trajectories: Trajectory[],
152
+ analyses: AnalysisResult[]
153
+ ): ExtractedPattern[] {
154
+ const patterns: ExtractedPattern[] = [];
155
+
156
+ // Extract action sequences from key steps
157
+ const actionSequences: Array<{
158
+ actions: string[];
159
+ thought: string;
160
+ trajectoryId: string;
161
+ }> = [];
162
+
163
+ for (let i = 0; i < trajectories.length; i++) {
164
+ const trajectory = trajectories[i];
165
+ // Use index-based matching since TrainingExample doesn't have trajectoryId
166
+ const analysis = analyses[i];
167
+
168
+ if (!analysis) continue;
169
+
170
+ // Get key steps
171
+ const keySteps = analysis.keySteps
172
+ .map((idx) => trajectory.steps[idx])
173
+ .filter(Boolean);
174
+
175
+ if (keySteps.length > 0) {
176
+ actionSequences.push({
177
+ actions: keySteps.map((s) => s.action),
178
+ thought: keySteps[0]?.thought ?? trajectory.task.description,
179
+ trajectoryId: trajectory.id,
180
+ });
181
+ }
182
+ }
183
+
184
+ // Find repeated patterns
185
+ const patternCounts = new Map<string, ExtractedPattern>();
186
+
187
+ for (const seq of actionSequences) {
188
+ // Normalize actions
189
+ const normalized = seq.actions.map((a) => this.normalizeAction(a));
190
+ const key = normalized.join('|');
191
+
192
+ if (patternCounts.has(key)) {
193
+ const existing = patternCounts.get(key)!;
194
+ existing.frequency++;
195
+ existing.trajectoryIds.push(seq.trajectoryId);
196
+ } else {
197
+ patternCounts.set(key, {
198
+ actions: seq.actions,
199
+ normalizedActions: normalized,
200
+ thought: seq.thought,
201
+ frequency: 1,
202
+ trajectoryIds: [seq.trajectoryId],
203
+ });
204
+ }
205
+ }
206
+
207
+ // Filter to patterns that occur multiple times
208
+ for (const pattern of patternCounts.values()) {
209
+ if (pattern.frequency >= this.config.minTrajectories) {
210
+ patterns.push(pattern);
211
+ }
212
+ }
213
+
214
+ // Also extract error-recovery patterns
215
+ const errorPatterns = this.extractErrorPatterns(trajectories, analyses);
216
+ patterns.push(...errorPatterns);
217
+
218
+ return patterns;
219
+ }
220
+
221
+ /**
222
+ * Extract error-recovery patterns
223
+ */
224
+ private extractErrorPatterns(
225
+ trajectories: Trajectory[],
226
+ analyses: AnalysisResult[]
227
+ ): ExtractedPattern[] {
228
+ const patterns: ExtractedPattern[] = [];
229
+ const errorRecoveries = new Map<string, ExtractedPattern>();
230
+
231
+ for (let i = 0; i < trajectories.length; i++) {
232
+ const trajectory = trajectories[i];
233
+ const analysis = analyses[i];
234
+
235
+ if (!analysis?.errorPatterns) continue;
236
+
237
+ for (const errorPattern of analysis.errorPatterns) {
238
+ const key = errorPattern.signature;
239
+
240
+ // Find recovery actions (steps after the error)
241
+ const errorStepIdx = trajectory.steps.findIndex((s: { observation?: string }) =>
242
+ s.observation?.includes(errorPattern.signature)
243
+ );
244
+
245
+ if (errorStepIdx >= 0 && errorStepIdx < trajectory.steps.length - 1) {
246
+ const recoverySteps = trajectory.steps.slice(
247
+ errorStepIdx + 1,
248
+ errorStepIdx + 4
249
+ );
250
+
251
+ if (errorRecoveries.has(key)) {
252
+ const existing = errorRecoveries.get(key)!;
253
+ existing.frequency++;
254
+ existing.trajectoryIds.push(trajectory.id);
255
+ } else {
256
+ errorRecoveries.set(key, {
257
+ actions: recoverySteps.map((s: { action: string }) => s.action),
258
+ normalizedActions: recoverySteps.map((s: { action: string }) =>
259
+ this.normalizeAction(s.action)
260
+ ),
261
+ thought: `When encountering: ${errorPattern.signature}`,
262
+ frequency: 1,
263
+ trajectoryIds: [trajectory.id],
264
+ errorTrigger: errorPattern.signature,
265
+ });
266
+ }
267
+ }
268
+ }
269
+ }
270
+
271
+ for (const pattern of errorRecoveries.values()) {
272
+ if (pattern.frequency >= this.config.minTrajectories) {
273
+ patterns.push(pattern);
274
+ }
275
+ }
276
+
277
+ return patterns;
278
+ }
279
+
280
+ /**
281
+ * Normalize an action for pattern matching
282
+ */
283
+ private normalizeAction(action: string): string {
284
+ const lower = action.toLowerCase();
285
+
286
+ // Map to action categories
287
+ const categories: Record<string, string[]> = {
288
+ read: ['read', 'view', 'show', 'display', 'cat', 'less', 'get'],
289
+ write: ['write', 'create', 'add', 'insert', 'save'],
290
+ edit: ['edit', 'modify', 'change', 'update', 'replace'],
291
+ delete: ['delete', 'remove', 'drop', 'clear'],
292
+ search: ['search', 'find', 'grep', 'locate', 'query'],
293
+ run: ['run', 'execute', 'call', 'invoke', 'start'],
294
+ test: ['test', 'verify', 'check', 'validate', 'assert'],
295
+ build: ['build', 'compile', 'bundle', 'package'],
296
+ install: ['install', 'add', 'npm', 'yarn', 'pip'],
297
+ debug: ['debug', 'trace', 'log', 'inspect', 'breakpoint'],
298
+ };
299
+
300
+ for (const [category, keywords] of Object.entries(categories)) {
301
+ if (keywords.some((kw) => lower.includes(kw))) {
302
+ return category;
303
+ }
304
+ }
305
+
306
+ // Return first word as fallback
307
+ return lower.split(/\s+/)[0] ?? 'action';
308
+ }
309
+
310
+ /**
311
+ * Find similar existing playbook
312
+ */
313
+ private findSimilarPlaybook(
314
+ pattern: ExtractedPattern,
315
+ playbooks: Playbook[]
316
+ ): Playbook | undefined {
317
+ for (const playbook of playbooks) {
318
+ // Check situation similarity
319
+ const situationMatch = playbook.applicability.situations.some(
320
+ (s) => textSimilarity(pattern.thought, s) > this.config.mergeThreshold
321
+ );
322
+
323
+ if (situationMatch) return playbook;
324
+
325
+ // Check trigger match for error patterns
326
+ if (pattern.errorTrigger) {
327
+ const triggerMatch = playbook.applicability.triggers.some(
328
+ (t) =>
329
+ textSimilarity(pattern.errorTrigger!, t) > this.config.mergeThreshold
330
+ );
331
+ if (triggerMatch) return playbook;
332
+ }
333
+ }
334
+
335
+ return undefined;
336
+ }
337
+
338
+ /**
339
+ * Generate update for existing playbook
340
+ */
341
+ private generateUpdate(
342
+ playbook: Playbook,
343
+ pattern: ExtractedPattern,
344
+ trajectories: Trajectory[]
345
+ ): PlaybookUpdate | undefined {
346
+ const update: PlaybookUpdate = { id: playbook.id };
347
+ let hasUpdate = false;
348
+
349
+ // Check for new trigger
350
+ if (
351
+ pattern.errorTrigger &&
352
+ !playbook.applicability.triggers.includes(pattern.errorTrigger)
353
+ ) {
354
+ update.newTrigger = pattern.errorTrigger;
355
+ hasUpdate = true;
356
+ }
357
+
358
+ // Check for context-specific refinement
359
+ const contexts = trajectories
360
+ .filter((t) => pattern.trajectoryIds.includes(t.id))
361
+ .map((t) => this.extractContext(t));
362
+
363
+ const uniqueContext = contexts.find(
364
+ (c) =>
365
+ !playbook.evolution.refinements.some(
366
+ (r) => textSimilarity(r.context, c) > 0.8
367
+ )
368
+ );
369
+
370
+ if (uniqueContext && pattern.actions.length > 0) {
371
+ update.refinement = {
372
+ context: uniqueContext,
373
+ addition: `Also: ${pattern.actions.slice(0, 2).join(', ')}`,
374
+ source: 'success',
375
+ addedAt: new Date(),
376
+ };
377
+ hasUpdate = true;
378
+ }
379
+
380
+ return hasUpdate ? update : undefined;
381
+ }
382
+
383
+ /**
384
+ * Create a playbook from an extracted pattern
385
+ */
386
+ private createPlaybookFromPattern(
387
+ pattern: ExtractedPattern,
388
+ domain: string
389
+ ): Playbook {
390
+ const name = this.generatePlaybookName(pattern);
391
+
392
+ return createPlaybook({
393
+ name,
394
+ applicability: {
395
+ situations: [pattern.thought],
396
+ triggers: pattern.errorTrigger ? [pattern.errorTrigger] : [],
397
+ antiPatterns: [],
398
+ domains: [domain],
399
+ },
400
+ guidance: {
401
+ strategy: pattern.thought,
402
+ tactics: pattern.actions.slice(0, 5),
403
+ steps: pattern.actions,
404
+ },
405
+ verification: {
406
+ successIndicators: ['Task completes successfully'],
407
+ failureIndicators: ['Same error persists', 'New errors introduced'],
408
+ },
409
+ evolution: {
410
+ version: '1.0.0',
411
+ createdFrom: pattern.trajectoryIds,
412
+ failures: [],
413
+ refinements: [],
414
+ successCount: pattern.frequency,
415
+ failureCount: 0,
416
+ },
417
+ provenance: {
418
+ origin: 'extracted',
419
+ recordedAt: new Date(),
420
+ },
421
+ confidence: Math.min(0.5, 0.2 + pattern.frequency * 0.1),
422
+ complexity:
423
+ pattern.actions.length <= 3
424
+ ? 'simple'
425
+ : pattern.actions.length <= 6
426
+ ? 'moderate'
427
+ : 'complex',
428
+ estimatedEffort: Math.ceil(pattern.actions.length * 0.5),
429
+ });
430
+ }
431
+
432
+ /**
433
+ * Generate a kebab-case playbook name
434
+ */
435
+ private generatePlaybookName(pattern: ExtractedPattern): string {
436
+ const words = pattern.thought
437
+ .toLowerCase()
438
+ .replace(/[^\w\s]/g, '')
439
+ .split(/\s+/)
440
+ .filter((w) => w.length > 2 && !this.isStopWord(w))
441
+ .slice(0, 4);
442
+
443
+ if (words.length === 0) {
444
+ return `playbook-${Date.now()}`;
445
+ }
446
+
447
+ return words.join('-');
448
+ }
449
+
450
+ /**
451
+ * Check if word is a stop word
452
+ */
453
+ private isStopWord(word: string): boolean {
454
+ const stopWords = new Set([
455
+ 'the',
456
+ 'a',
457
+ 'an',
458
+ 'and',
459
+ 'or',
460
+ 'but',
461
+ 'is',
462
+ 'are',
463
+ 'was',
464
+ 'were',
465
+ 'be',
466
+ 'been',
467
+ 'being',
468
+ 'have',
469
+ 'has',
470
+ 'had',
471
+ 'do',
472
+ 'does',
473
+ 'did',
474
+ 'will',
475
+ 'would',
476
+ 'could',
477
+ 'should',
478
+ 'may',
479
+ 'might',
480
+ 'must',
481
+ 'shall',
482
+ 'can',
483
+ 'to',
484
+ 'of',
485
+ 'in',
486
+ 'for',
487
+ 'on',
488
+ 'with',
489
+ 'at',
490
+ 'by',
491
+ 'from',
492
+ 'as',
493
+ 'into',
494
+ 'through',
495
+ 'during',
496
+ 'before',
497
+ 'after',
498
+ 'above',
499
+ 'below',
500
+ 'between',
501
+ 'under',
502
+ 'again',
503
+ 'further',
504
+ 'then',
505
+ 'once',
506
+ 'here',
507
+ 'there',
508
+ 'when',
509
+ 'where',
510
+ 'why',
511
+ 'how',
512
+ 'all',
513
+ 'each',
514
+ 'few',
515
+ 'more',
516
+ 'most',
517
+ 'other',
518
+ 'some',
519
+ 'such',
520
+ 'no',
521
+ 'not',
522
+ 'only',
523
+ 'own',
524
+ 'same',
525
+ 'so',
526
+ 'than',
527
+ 'too',
528
+ 'very',
529
+ 'just',
530
+ ]);
531
+ return stopWords.has(word);
532
+ }
533
+
534
+ /**
535
+ * Extract context from a trajectory
536
+ */
537
+ private extractContext(trajectory: Trajectory): string {
538
+ // Try to extract meaningful context
539
+ const metadata = trajectory.task.metadata ?? {};
540
+
541
+ if (metadata.fileType) return `${metadata.fileType} files`;
542
+ if (metadata.framework) return `${metadata.framework} projects`;
543
+ if (metadata.language) return `${metadata.language} code`;
544
+
545
+ // Fall back to domain
546
+ return trajectory.task.domain;
547
+ }
548
+
549
+ /**
550
+ * Group trajectories by domain
551
+ */
552
+ private groupByDomain(
553
+ trajectories: Trajectory[]
554
+ ): Map<string, Trajectory[]> {
555
+ const groups = new Map<string, Trajectory[]>();
556
+
557
+ for (const trajectory of trajectories) {
558
+ const domain = trajectory.task.domain;
559
+ const existing = groups.get(domain) ?? [];
560
+ existing.push(trajectory);
561
+ groups.set(domain, existing);
562
+ }
563
+
564
+ return groups;
565
+ }
566
+
567
+ /**
568
+ * Consolidate similar playbooks
569
+ */
570
+ async consolidate(playbooks: Playbook[]): Promise<Playbook[]> {
571
+ if (playbooks.length <= 1) return playbooks;
572
+
573
+ const consolidated: Playbook[] = [];
574
+ const merged = new Set<string>();
575
+
576
+ for (let i = 0; i < playbooks.length; i++) {
577
+ if (merged.has(playbooks[i].id)) continue;
578
+
579
+ let current = playbooks[i];
580
+
581
+ for (let j = i + 1; j < playbooks.length; j++) {
582
+ if (merged.has(playbooks[j].id)) continue;
583
+
584
+ const other = playbooks[j];
585
+ const similarity = this.calculatePlaybookSimilarity(current, other);
586
+
587
+ if (similarity > this.config.mergeThreshold) {
588
+ current = this.mergePlaybooks(current, other);
589
+ merged.add(other.id);
590
+ }
591
+ }
592
+
593
+ consolidated.push(current);
594
+ }
595
+
596
+ return consolidated;
597
+ }
598
+
599
+ /**
600
+ * Calculate similarity between two playbooks
601
+ */
602
+ private calculatePlaybookSimilarity(a: Playbook, b: Playbook): number {
603
+ // Compare situations
604
+ let maxSituationSim = 0;
605
+ for (const sA of a.applicability.situations) {
606
+ for (const sB of b.applicability.situations) {
607
+ maxSituationSim = Math.max(maxSituationSim, textSimilarity(sA, sB));
608
+ }
609
+ }
610
+
611
+ // Compare guidance
612
+ const strategySim = textSimilarity(a.guidance.strategy, b.guidance.strategy);
613
+
614
+ // Combined score
615
+ return maxSituationSim * 0.6 + strategySim * 0.4;
616
+ }
617
+
618
+ /**
619
+ * Merge two similar playbooks
620
+ */
621
+ private mergePlaybooks(a: Playbook, b: Playbook): Playbook {
622
+ return createPlaybook({
623
+ id: a.id,
624
+ name: a.name,
625
+ applicability: {
626
+ situations: [...new Set([...a.applicability.situations, ...b.applicability.situations])],
627
+ triggers: [...new Set([...a.applicability.triggers, ...b.applicability.triggers])],
628
+ antiPatterns: [...new Set([...a.applicability.antiPatterns, ...b.applicability.antiPatterns])],
629
+ domains: [...new Set([...a.applicability.domains, ...b.applicability.domains])],
630
+ },
631
+ guidance: {
632
+ strategy: a.guidance.strategy, // Keep first
633
+ tactics: [...new Set([...a.guidance.tactics, ...b.guidance.tactics])],
634
+ steps: a.guidance.steps ?? b.guidance.steps,
635
+ codeExample: a.guidance.codeExample ?? b.guidance.codeExample,
636
+ },
637
+ verification: {
638
+ successIndicators: [...new Set([...a.verification.successIndicators, ...b.verification.successIndicators])],
639
+ failureIndicators: [...new Set([...a.verification.failureIndicators, ...b.verification.failureIndicators])],
640
+ rollbackStrategy: a.verification.rollbackStrategy ?? b.verification.rollbackStrategy,
641
+ },
642
+ evolution: {
643
+ version: a.evolution.version,
644
+ createdFrom: [...new Set([...a.evolution.createdFrom, ...b.evolution.createdFrom])],
645
+ failures: [...a.evolution.failures, ...b.evolution.failures],
646
+ refinements: [...a.evolution.refinements, ...b.evolution.refinements],
647
+ successCount: a.evolution.successCount + b.evolution.successCount,
648
+ failureCount: a.evolution.failureCount + b.evolution.failureCount,
649
+ },
650
+ provenance: a.provenance, // Preserve provenance from primary playbook
651
+ confidence: Math.max(a.confidence, b.confidence),
652
+ complexity: a.complexity,
653
+ estimatedEffort: Math.min(a.estimatedEffort, b.estimatedEffort),
654
+ });
655
+ }
656
+
657
+ /**
658
+ * Generate refinement from a failure
659
+ */
660
+ async generateRefinement(
661
+ _playbook: Playbook,
662
+ failedTrajectory: Trajectory,
663
+ failureContext: string
664
+ ): Promise<Refinement> {
665
+ // Analyze what was different in this failure
666
+ const context = this.extractContext(failedTrajectory);
667
+
668
+ // Try to identify what additional steps might help
669
+ const lastSteps = failedTrajectory.steps.slice(-3);
670
+ const suggestion = lastSteps.length > 0
671
+ ? `Consider checking: ${lastSteps.map((s: { action: string }) => s.action).join(', ')}`
672
+ : `Review the approach for ${failureContext}`;
673
+
674
+ return {
675
+ context,
676
+ addition: suggestion,
677
+ source: 'failure',
678
+ addedAt: new Date(),
679
+ };
680
+ }
681
+ }
682
+
683
+ /**
684
+ * Internal type for extracted patterns
685
+ */
686
+ interface ExtractedPattern {
687
+ actions: string[];
688
+ normalizedActions: string[];
689
+ thought: string;
690
+ frequency: number;
691
+ trajectoryIds: string[];
692
+ errorTrigger?: string;
693
+ }
694
+
695
+ /**
696
+ * Create a playbook extractor
697
+ */
698
+ export function createPlaybookExtractor(
699
+ config?: Partial<PlaybookExtractorConfig>
700
+ ): PlaybookExtractor {
701
+ return new PlaybookExtractor(config);
702
+ }