agentic-flow 1.6.6 → 1.7.1

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 (44) hide show
  1. package/.claude/skills/.claude-flow/metrics/agent-metrics.json +1 -0
  2. package/.claude/skills/.claude-flow/metrics/performance.json +87 -0
  3. package/.claude/skills/.claude-flow/metrics/task-metrics.json +10 -0
  4. package/.claude/skills/skill-builder/.claude-flow/metrics/agent-metrics.json +1 -0
  5. package/.claude/skills/skill-builder/.claude-flow/metrics/performance.json +87 -0
  6. package/.claude/skills/skill-builder/.claude-flow/metrics/task-metrics.json +10 -0
  7. package/CHANGELOG.md +0 -30
  8. package/README.md +16 -2
  9. package/dist/agentdb/benchmarks/comprehensive-benchmark.js +664 -0
  10. package/dist/agentdb/benchmarks/frontier-benchmark.js +419 -0
  11. package/dist/agentdb/benchmarks/reflexion-benchmark.js +370 -0
  12. package/dist/agentdb/cli/agentdb-cli.js +717 -0
  13. package/dist/agentdb/controllers/CausalMemoryGraph.js +322 -0
  14. package/dist/agentdb/controllers/CausalRecall.js +281 -0
  15. package/dist/agentdb/controllers/EmbeddingService.js +118 -0
  16. package/dist/agentdb/controllers/ExplainableRecall.js +387 -0
  17. package/dist/agentdb/controllers/NightlyLearner.js +382 -0
  18. package/dist/agentdb/controllers/ReflexionMemory.js +239 -0
  19. package/dist/agentdb/controllers/SkillLibrary.js +276 -0
  20. package/dist/agentdb/controllers/frontier-index.js +9 -0
  21. package/dist/agentdb/controllers/index.js +8 -0
  22. package/dist/agentdb/index.js +32 -0
  23. package/dist/agentdb/optimizations/BatchOperations.js +198 -0
  24. package/dist/agentdb/optimizations/QueryOptimizer.js +225 -0
  25. package/dist/agentdb/optimizations/index.js +7 -0
  26. package/dist/agentdb/tests/frontier-features.test.js +665 -0
  27. package/dist/cli/skills-manager.js +1297 -0
  28. package/dist/cli/update-message.js +175 -0
  29. package/dist/cli-proxy.js +2 -26
  30. package/dist/mcp/standalone-stdio.js +200 -4
  31. package/dist/memory/SharedMemoryPool.js +211 -0
  32. package/dist/memory/index.js +6 -0
  33. package/dist/reasoningbank/AdvancedMemory.js +239 -0
  34. package/dist/reasoningbank/HybridBackend.js +305 -0
  35. package/dist/reasoningbank/index-new.js +87 -0
  36. package/dist/reasoningbank/index.js +0 -4
  37. package/dist/utils/cli.js +0 -5
  38. package/docs/AGENTDB_TESTING.md +411 -0
  39. package/package.json +4 -4
  40. package/scripts/run-validation.sh +165 -0
  41. package/scripts/test-agentdb.sh +153 -0
  42. package/wasm/reasoningbank/reasoningbank_wasm_bg.js +2 -2
  43. package/wasm/reasoningbank/reasoningbank_wasm_bg.wasm +0 -0
  44. package/docs/AGENTDB_INTEGRATION.md +0 -379
@@ -0,0 +1,118 @@
1
+ /**
2
+ * EmbeddingService - Text Embedding Generation
3
+ *
4
+ * Handles text-to-vector embedding generation using various models.
5
+ * Supports both local (transformers.js) and remote (OpenAI, etc.) embeddings.
6
+ */
7
+ export class EmbeddingService {
8
+ config;
9
+ pipeline; // transformers.js pipeline
10
+ cache;
11
+ constructor(config) {
12
+ this.config = config;
13
+ this.cache = new Map();
14
+ }
15
+ /**
16
+ * Initialize the embedding service
17
+ */
18
+ async initialize() {
19
+ if (this.config.provider === 'transformers') {
20
+ // Use transformers.js for local embeddings
21
+ try {
22
+ const { pipeline } = await import('@xenova/transformers');
23
+ this.pipeline = await pipeline('feature-extraction', this.config.model);
24
+ }
25
+ catch (error) {
26
+ console.warn('Transformers.js not available, falling back to mock embeddings');
27
+ this.pipeline = null;
28
+ }
29
+ }
30
+ }
31
+ /**
32
+ * Generate embedding for text
33
+ */
34
+ async embed(text) {
35
+ // Check cache
36
+ const cacheKey = `${this.config.model}:${text}`;
37
+ if (this.cache.has(cacheKey)) {
38
+ return this.cache.get(cacheKey);
39
+ }
40
+ let embedding;
41
+ if (this.config.provider === 'transformers' && this.pipeline) {
42
+ // Use transformers.js
43
+ const output = await this.pipeline(text, { pooling: 'mean', normalize: true });
44
+ embedding = new Float32Array(output.data);
45
+ }
46
+ else if (this.config.provider === 'openai' && this.config.apiKey) {
47
+ // Use OpenAI API
48
+ embedding = await this.embedOpenAI(text);
49
+ }
50
+ else {
51
+ // Mock embedding for testing
52
+ embedding = this.mockEmbedding(text);
53
+ }
54
+ // Cache result
55
+ if (this.cache.size > 10000) {
56
+ // Simple LRU: clear half the cache
57
+ const keysToDelete = Array.from(this.cache.keys()).slice(0, 5000);
58
+ keysToDelete.forEach(k => this.cache.delete(k));
59
+ }
60
+ this.cache.set(cacheKey, embedding);
61
+ return embedding;
62
+ }
63
+ /**
64
+ * Batch embed multiple texts
65
+ */
66
+ async embedBatch(texts) {
67
+ return Promise.all(texts.map(text => this.embed(text)));
68
+ }
69
+ /**
70
+ * Clear embedding cache
71
+ */
72
+ clearCache() {
73
+ this.cache.clear();
74
+ }
75
+ // ========================================================================
76
+ // Private Methods
77
+ // ========================================================================
78
+ async embedOpenAI(text) {
79
+ const response = await fetch('https://api.openai.com/v1/embeddings', {
80
+ method: 'POST',
81
+ headers: {
82
+ 'Authorization': `Bearer ${this.config.apiKey}`,
83
+ 'Content-Type': 'application/json'
84
+ },
85
+ body: JSON.stringify({
86
+ model: this.config.model,
87
+ input: text
88
+ })
89
+ });
90
+ const data = await response.json();
91
+ return new Float32Array(data.data[0].embedding);
92
+ }
93
+ mockEmbedding(text) {
94
+ // Simple deterministic mock embedding for testing
95
+ const embedding = new Float32Array(this.config.dimension);
96
+ // Use simple hash-based generation
97
+ let hash = 0;
98
+ for (let i = 0; i < text.length; i++) {
99
+ hash = ((hash << 5) - hash) + text.charCodeAt(i);
100
+ hash = hash & hash; // Convert to 32bit integer
101
+ }
102
+ // Fill embedding with pseudo-random values based on hash
103
+ for (let i = 0; i < this.config.dimension; i++) {
104
+ const seed = hash + i * 31;
105
+ embedding[i] = Math.sin(seed) * Math.cos(seed * 0.5);
106
+ }
107
+ // Normalize
108
+ let norm = 0;
109
+ for (let i = 0; i < embedding.length; i++) {
110
+ norm += embedding[i] * embedding[i];
111
+ }
112
+ norm = Math.sqrt(norm);
113
+ for (let i = 0; i < embedding.length; i++) {
114
+ embedding[i] /= norm;
115
+ }
116
+ return embedding;
117
+ }
118
+ }
@@ -0,0 +1,387 @@
1
+ /**
2
+ * ExplainableRecall - Provenance and Justification for Memory Retrieval
3
+ *
4
+ * Every retrieval returns:
5
+ * - Minimal hitting set of facts that justify the answer
6
+ * - Merkle proof chain for provenance
7
+ * - Policy compliance certificates
8
+ *
9
+ * Based on:
10
+ * - Minimal hitting set algorithms
11
+ * - Merkle tree provenance
12
+ * - Explainable AI techniques
13
+ */
14
+ import * as crypto from 'crypto';
15
+ export class ExplainableRecall {
16
+ db;
17
+ constructor(db) {
18
+ this.db = db;
19
+ }
20
+ /**
21
+ * Create a recall certificate for a retrieval operation
22
+ */
23
+ createCertificate(params) {
24
+ const { queryId, queryText, chunks, requirements, accessLevel = 'internal' } = params;
25
+ const startTime = Date.now();
26
+ // 1. Compute minimal hitting set
27
+ const minimalWhy = this.computeMinimalHittingSet(chunks, requirements);
28
+ // 2. Calculate metrics
29
+ const redundancyRatio = chunks.length / minimalWhy.length;
30
+ const completenessScore = this.calculateCompleteness(minimalWhy, requirements);
31
+ // 3. Build provenance chain
32
+ const sourceHashes = chunks.map(chunk => this.getOrCreateProvenance(chunk.type, parseInt(chunk.id)));
33
+ const merkleTree = this.buildMerkleTree(sourceHashes);
34
+ const merkleRoot = merkleTree.root;
35
+ // 4. Generate chunk metadata first (needed for certificate ID)
36
+ const chunkIds = chunks.map(c => c.id);
37
+ const chunkTypes = chunks.map(c => c.type);
38
+ // 5. Create certificate ID
39
+ const certificateId = this.generateCertificateId(queryId, chunkIds);
40
+ // 6. Generate proof chain for each chunk
41
+ const proofChain = chunks.map((chunk, idx) => this.getMerkleProof(merkleTree, idx)).flat();
42
+ // 7. Store certificate
43
+ this.db.prepare(`
44
+ INSERT INTO recall_certificates (
45
+ id, query_id, query_text, chunk_ids, chunk_types,
46
+ minimal_why, redundancy_ratio, completeness_score,
47
+ merkle_root, source_hashes, proof_chain,
48
+ access_level, latency_ms
49
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
50
+ `).run(certificateId, queryId, queryText, JSON.stringify(chunkIds), JSON.stringify(chunkTypes), JSON.stringify(minimalWhy), redundancyRatio, completenessScore, merkleRoot, JSON.stringify(sourceHashes), JSON.stringify(proofChain), accessLevel, Date.now() - startTime);
51
+ // 7. Store justification paths
52
+ this.storeJustificationPaths(certificateId, chunks, minimalWhy, requirements);
53
+ const certificate = {
54
+ id: certificateId,
55
+ queryId,
56
+ queryText,
57
+ chunkIds,
58
+ chunkTypes,
59
+ minimalWhy,
60
+ redundancyRatio,
61
+ completenessScore,
62
+ merkleRoot,
63
+ sourceHashes,
64
+ proofChain,
65
+ accessLevel: accessLevel,
66
+ latencyMs: Date.now() - startTime
67
+ };
68
+ return certificate;
69
+ }
70
+ /**
71
+ * Verify a recall certificate
72
+ */
73
+ verifyCertificate(certificateId) {
74
+ const cert = this.db.prepare('SELECT * FROM recall_certificates WHERE id = ?').get(certificateId);
75
+ if (!cert) {
76
+ return { valid: false, issues: ['Certificate not found'] };
77
+ }
78
+ const issues = [];
79
+ // 1. Verify Merkle root
80
+ const sourceHashes = JSON.parse(cert.source_hashes);
81
+ const merkleTree = this.buildMerkleTree(sourceHashes);
82
+ if (merkleTree.root !== cert.merkle_root) {
83
+ issues.push('Merkle root mismatch');
84
+ }
85
+ // 2. Verify chunk hashes still match
86
+ const chunkIds = JSON.parse(cert.chunk_ids);
87
+ const chunkTypes = JSON.parse(cert.chunk_types);
88
+ for (let i = 0; i < chunkIds.length; i++) {
89
+ const currentHash = this.getContentHash(chunkTypes[i], parseInt(chunkIds[i]));
90
+ if (currentHash !== sourceHashes[i]) {
91
+ issues.push(`Chunk ${chunkIds[i]} hash changed`);
92
+ }
93
+ }
94
+ // 3. Verify completeness
95
+ const minimalWhy = JSON.parse(cert.minimal_why);
96
+ if (minimalWhy.length === 0) {
97
+ issues.push('Empty justification set');
98
+ }
99
+ // 4. Verify redundancy ratio
100
+ if (cert.redundancy_ratio < 1.0) {
101
+ issues.push('Invalid redundancy ratio');
102
+ }
103
+ return {
104
+ valid: issues.length === 0,
105
+ issues
106
+ };
107
+ }
108
+ /**
109
+ * Get justification for why a chunk was included
110
+ */
111
+ getJustification(certificateId, chunkId) {
112
+ const row = this.db.prepare(`
113
+ SELECT * FROM justification_paths
114
+ WHERE certificate_id = ? AND chunk_id = ?
115
+ `).get(certificateId, chunkId);
116
+ if (!row)
117
+ return null;
118
+ return {
119
+ chunkId: row.chunk_id,
120
+ chunkType: row.chunk_type,
121
+ reason: row.reason,
122
+ necessityScore: row.necessity_score,
123
+ pathElements: JSON.parse(row.path_elements)
124
+ };
125
+ }
126
+ /**
127
+ * Get provenance lineage for a source
128
+ */
129
+ getProvenanceLineage(contentHash) {
130
+ const lineage = [];
131
+ let currentHash = contentHash;
132
+ while (currentHash) {
133
+ const source = this.db.prepare(`
134
+ SELECT * FROM provenance_sources WHERE content_hash = ?
135
+ `).get(currentHash);
136
+ if (!source)
137
+ break;
138
+ lineage.push({
139
+ id: source.id,
140
+ sourceType: source.source_type,
141
+ sourceId: source.source_id,
142
+ contentHash: source.content_hash,
143
+ parentHash: source.parent_hash,
144
+ derivedFrom: source.derived_from ? JSON.parse(source.derived_from) : undefined,
145
+ creator: source.creator,
146
+ metadata: source.metadata ? JSON.parse(source.metadata) : undefined
147
+ });
148
+ currentHash = source.parent_hash;
149
+ }
150
+ return lineage;
151
+ }
152
+ /**
153
+ * Audit certificate access
154
+ */
155
+ auditCertificate(certificateId) {
156
+ const certRow = this.db.prepare('SELECT * FROM recall_certificates WHERE id = ?').get(certificateId);
157
+ if (!certRow) {
158
+ throw new Error(`Certificate ${certificateId} not found`);
159
+ }
160
+ const certificate = {
161
+ id: certRow.id,
162
+ queryId: certRow.query_id,
163
+ queryText: certRow.query_text,
164
+ chunkIds: JSON.parse(certRow.chunk_ids),
165
+ chunkTypes: JSON.parse(certRow.chunk_types),
166
+ minimalWhy: JSON.parse(certRow.minimal_why),
167
+ redundancyRatio: certRow.redundancy_ratio,
168
+ completenessScore: certRow.completeness_score,
169
+ merkleRoot: certRow.merkle_root,
170
+ sourceHashes: JSON.parse(certRow.source_hashes),
171
+ proofChain: JSON.parse(certRow.proof_chain),
172
+ policyProof: certRow.policy_proof,
173
+ policyVersion: certRow.policy_version,
174
+ accessLevel: certRow.access_level,
175
+ latencyMs: certRow.latency_ms
176
+ };
177
+ // Get justifications
178
+ const justRows = this.db.prepare(`
179
+ SELECT * FROM justification_paths WHERE certificate_id = ?
180
+ `).all(certificateId);
181
+ const justifications = justRows.map(row => ({
182
+ chunkId: row.chunk_id,
183
+ chunkType: row.chunk_type,
184
+ reason: row.reason,
185
+ necessityScore: row.necessity_score,
186
+ pathElements: JSON.parse(row.path_elements)
187
+ }));
188
+ // Get provenance for each source
189
+ const provenance = new Map();
190
+ for (const hash of certificate.sourceHashes) {
191
+ provenance.set(hash, this.getProvenanceLineage(hash));
192
+ }
193
+ // Calculate quality metrics
194
+ const avgNecessity = justifications.reduce((sum, j) => sum + j.necessityScore, 0) / justifications.length;
195
+ return {
196
+ certificate,
197
+ justifications,
198
+ provenance,
199
+ quality: {
200
+ completeness: certificate.completenessScore,
201
+ redundancy: certificate.redundancyRatio,
202
+ avgNecessity
203
+ }
204
+ };
205
+ }
206
+ // ========================================================================
207
+ // Private Helper Methods
208
+ // ========================================================================
209
+ /**
210
+ * Compute minimal hitting set using greedy algorithm
211
+ * A hitting set contains at least one element from each requirement
212
+ */
213
+ computeMinimalHittingSet(chunks, requirements) {
214
+ if (requirements.length === 0) {
215
+ return chunks.slice(0, Math.min(3, chunks.length)).map(c => c.id);
216
+ }
217
+ const uncovered = new Set(requirements);
218
+ const selected = [];
219
+ // Greedy: select chunk that covers most uncovered requirements
220
+ while (uncovered.size > 0 && chunks.length > 0) {
221
+ let bestChunk = null;
222
+ let bestCoverage = 0;
223
+ for (const chunk of chunks) {
224
+ const coverage = Array.from(uncovered).filter(req => chunk.content.toLowerCase().includes(req.toLowerCase())).length;
225
+ if (coverage > bestCoverage) {
226
+ bestCoverage = coverage;
227
+ bestChunk = chunk;
228
+ }
229
+ }
230
+ if (!bestChunk)
231
+ break;
232
+ selected.push(bestChunk.id);
233
+ // Remove covered requirements
234
+ for (const req of Array.from(uncovered)) {
235
+ if (bestChunk.content.toLowerCase().includes(req.toLowerCase())) {
236
+ uncovered.delete(req);
237
+ }
238
+ }
239
+ // Remove selected chunk
240
+ chunks = chunks.filter(c => c.id !== bestChunk.id);
241
+ }
242
+ return selected;
243
+ }
244
+ /**
245
+ * Calculate completeness score
246
+ */
247
+ calculateCompleteness(minimalWhy, requirements) {
248
+ if (requirements.length === 0)
249
+ return 1.0;
250
+ const chunks = minimalWhy.map(id => {
251
+ // Get chunk content
252
+ const episode = this.db.prepare('SELECT output FROM episodes WHERE id = ?').get(parseInt(id));
253
+ return episode ? episode.output : '';
254
+ });
255
+ const satisfied = requirements.filter(req => chunks.some(content => content && content.toLowerCase().includes(req.toLowerCase())));
256
+ return satisfied.length / requirements.length;
257
+ }
258
+ /**
259
+ * Get or create provenance record
260
+ */
261
+ getOrCreateProvenance(sourceType, sourceId) {
262
+ // Check if provenance exists
263
+ const existing = this.db.prepare(`
264
+ SELECT content_hash FROM provenance_sources
265
+ WHERE source_type = ? AND source_id = ?
266
+ `).get(sourceType, sourceId);
267
+ if (existing) {
268
+ return existing.content_hash;
269
+ }
270
+ // Create new provenance
271
+ const contentHash = this.getContentHash(sourceType, sourceId);
272
+ this.db.prepare(`
273
+ INSERT INTO provenance_sources (source_type, source_id, content_hash, creator)
274
+ VALUES (?, ?, ?, ?)
275
+ `).run(sourceType, sourceId, contentHash, 'system');
276
+ return contentHash;
277
+ }
278
+ /**
279
+ * Get content hash for a memory
280
+ */
281
+ getContentHash(sourceType, sourceId) {
282
+ let content = '';
283
+ switch (sourceType) {
284
+ case 'episode':
285
+ const episode = this.db.prepare('SELECT task, output FROM episodes WHERE id = ?').get(sourceId);
286
+ content = episode ? `${episode.task}:${episode.output}` : '';
287
+ break;
288
+ case 'skill':
289
+ const skill = this.db.prepare('SELECT name, code FROM skills WHERE id = ?').get(sourceId);
290
+ content = skill ? `${skill.name}:${skill.code}` : '';
291
+ break;
292
+ case 'note':
293
+ const note = this.db.prepare('SELECT text FROM notes WHERE id = ?').get(sourceId);
294
+ content = note ? note.text : '';
295
+ break;
296
+ case 'fact':
297
+ const fact = this.db.prepare('SELECT subject, predicate, object FROM facts WHERE id = ?').get(sourceId);
298
+ content = fact ? `${fact.subject}:${fact.predicate}:${fact.object}` : '';
299
+ break;
300
+ }
301
+ return crypto.createHash('sha256').update(content).digest('hex');
302
+ }
303
+ /**
304
+ * Build Merkle tree from hashes
305
+ */
306
+ buildMerkleTree(hashes) {
307
+ if (hashes.length === 0) {
308
+ return { root: '', tree: [[]] };
309
+ }
310
+ const tree = [hashes];
311
+ while (tree[tree.length - 1].length > 1) {
312
+ const level = tree[tree.length - 1];
313
+ const nextLevel = [];
314
+ for (let i = 0; i < level.length; i += 2) {
315
+ if (i + 1 < level.length) {
316
+ const combined = level[i] + level[i + 1];
317
+ nextLevel.push(crypto.createHash('sha256').update(combined).digest('hex'));
318
+ }
319
+ else {
320
+ nextLevel.push(level[i]);
321
+ }
322
+ }
323
+ tree.push(nextLevel);
324
+ }
325
+ return { root: tree[tree.length - 1][0], tree };
326
+ }
327
+ /**
328
+ * Get Merkle proof for a leaf
329
+ */
330
+ getMerkleProof(merkleTree, leafIndex) {
331
+ const proof = [];
332
+ let index = leafIndex;
333
+ for (let level = 0; level < merkleTree.tree.length - 1; level++) {
334
+ const currentLevel = merkleTree.tree[level];
335
+ const isLeftNode = index % 2 === 0;
336
+ const siblingIndex = isLeftNode ? index + 1 : index - 1;
337
+ if (siblingIndex < currentLevel.length) {
338
+ proof.push({
339
+ hash: currentLevel[siblingIndex],
340
+ position: isLeftNode ? 'right' : 'left'
341
+ });
342
+ }
343
+ index = Math.floor(index / 2);
344
+ }
345
+ return proof;
346
+ }
347
+ /**
348
+ * Generate certificate ID
349
+ */
350
+ generateCertificateId(queryId, chunkIds) {
351
+ const data = `${queryId}:${chunkIds.join(',')}:${Date.now()}`;
352
+ return crypto.createHash('sha256').update(data).digest('hex');
353
+ }
354
+ /**
355
+ * Store justification paths
356
+ */
357
+ storeJustificationPaths(certificateId, chunks, minimalWhy, requirements) {
358
+ const stmt = this.db.prepare(`
359
+ INSERT INTO justification_paths (
360
+ certificate_id, chunk_id, chunk_type, reason, necessity_score, path_elements
361
+ ) VALUES (?, ?, ?, ?, ?, ?)
362
+ `);
363
+ for (const chunk of chunks) {
364
+ const isNecessary = minimalWhy.includes(chunk.id);
365
+ const reason = this.determineReason(chunk, requirements);
366
+ const necessityScore = isNecessary ? chunk.relevance : chunk.relevance * 0.5;
367
+ const pathElements = [
368
+ `Retrieved for query`,
369
+ isNecessary ? `Essential for justification` : `Supporting evidence`,
370
+ `Relevance: ${(chunk.relevance * 100).toFixed(1)}%`
371
+ ];
372
+ stmt.run(certificateId, chunk.id, chunk.type, reason, necessityScore, JSON.stringify(pathElements));
373
+ }
374
+ }
375
+ /**
376
+ * Determine reason for inclusion
377
+ */
378
+ determineReason(chunk, requirements) {
379
+ if (chunk.relevance > 0.9)
380
+ return 'semantic_match';
381
+ if (chunk.relevance > 0.7)
382
+ return 'causal_link';
383
+ if (chunk.relevance > 0.5)
384
+ return 'prerequisite';
385
+ return 'constraint';
386
+ }
387
+ }