agentic-flow 1.7.2 → 1.7.4

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 (55) hide show
  1. package/.claude/agents/test-neural.md +0 -5
  2. package/.claude/answer.md +1 -0
  3. package/.claude/settings.json +19 -20
  4. package/CHANGELOG.md +0 -91
  5. package/README.md +17 -81
  6. package/dist/agentdb/benchmarks/comprehensive-benchmark.js +664 -0
  7. package/dist/agentdb/benchmarks/frontier-benchmark.js +419 -0
  8. package/dist/agentdb/benchmarks/reflexion-benchmark.js +370 -0
  9. package/dist/agentdb/cli/agentdb-cli.js +717 -0
  10. package/dist/agentdb/controllers/CausalMemoryGraph.js +322 -0
  11. package/dist/agentdb/controllers/CausalRecall.js +281 -0
  12. package/dist/agentdb/controllers/EmbeddingService.js +118 -0
  13. package/dist/agentdb/controllers/ExplainableRecall.js +387 -0
  14. package/dist/agentdb/controllers/NightlyLearner.js +382 -0
  15. package/dist/agentdb/controllers/ReflexionMemory.js +239 -0
  16. package/dist/agentdb/controllers/SkillLibrary.js +276 -0
  17. package/dist/agentdb/controllers/frontier-index.js +9 -0
  18. package/dist/agentdb/controllers/index.js +8 -0
  19. package/dist/agentdb/index.js +32 -0
  20. package/dist/agentdb/optimizations/BatchOperations.js +198 -0
  21. package/dist/agentdb/optimizations/QueryOptimizer.js +225 -0
  22. package/dist/agentdb/optimizations/index.js +7 -0
  23. package/dist/agentdb/tests/frontier-features.test.js +665 -0
  24. package/dist/cli/skills-manager.js +3 -1
  25. package/dist/cli-proxy.js +2 -33
  26. package/dist/mcp/standalone-stdio.js +200 -4
  27. package/dist/memory/SharedMemoryPool.js +211 -0
  28. package/dist/memory/index.js +6 -0
  29. package/dist/reasoningbank/AdvancedMemory.js +239 -0
  30. package/dist/reasoningbank/HybridBackend.js +305 -0
  31. package/dist/reasoningbank/index-new.js +87 -0
  32. package/dist/reasoningbank/index.js +23 -44
  33. package/dist/utils/cli.js +0 -22
  34. package/docs/AGENTDB_TESTING.md +411 -0
  35. package/docs/v1.7.1-QUICK-START.md +399 -0
  36. package/package.json +4 -4
  37. package/scripts/run-validation.sh +165 -0
  38. package/scripts/test-agentdb.sh +153 -0
  39. package/.claude/skills/agentdb-memory-patterns/SKILL.md +0 -166
  40. package/.claude/skills/agentdb-vector-search/SKILL.md +0 -126
  41. package/.claude/skills/agentic-flow/agentdb-memory-patterns/SKILL.md +0 -166
  42. package/.claude/skills/agentic-flow/agentdb-vector-search/SKILL.md +0 -126
  43. package/.claude/skills/agentic-flow/reasoningbank-intelligence/SKILL.md +0 -201
  44. package/.claude/skills/agentic-flow/swarm-orchestration/SKILL.md +0 -179
  45. package/.claude/skills/reasoningbank-intelligence/SKILL.md +0 -201
  46. package/.claude/skills/skill-builder/README.md +0 -308
  47. package/.claude/skills/skill-builder/SKILL.md +0 -910
  48. package/.claude/skills/skill-builder/docs/SPECIFICATION.md +0 -358
  49. package/.claude/skills/skill-builder/resources/schemas/skill-frontmatter.schema.json +0 -41
  50. package/.claude/skills/skill-builder/resources/templates/full-skill.template +0 -118
  51. package/.claude/skills/skill-builder/resources/templates/minimal-skill.template +0 -38
  52. package/.claude/skills/skill-builder/scripts/generate-skill.sh +0 -334
  53. package/.claude/skills/skill-builder/scripts/validate-skill.sh +0 -198
  54. package/.claude/skills/swarm-orchestration/SKILL.md +0 -179
  55. package/docs/AGENTDB_INTEGRATION.md +0 -379
@@ -0,0 +1,322 @@
1
+ /**
2
+ * CausalMemoryGraph - Causal Reasoning over Agent Memories
3
+ *
4
+ * Implements intervention-based reasoning rather than correlation.
5
+ * Stores p(y|do(x)) estimates and tracks causal uplift across episodes.
6
+ *
7
+ * Based on:
8
+ * - Pearl's do-calculus and causal inference
9
+ * - Uplift modeling from A/B testing
10
+ * - Instrumental variable methods
11
+ */
12
+ export class CausalMemoryGraph {
13
+ db;
14
+ constructor(db) {
15
+ this.db = db;
16
+ }
17
+ /**
18
+ * Add a causal edge between memories
19
+ */
20
+ addCausalEdge(edge) {
21
+ const stmt = this.db.prepare(`
22
+ INSERT INTO causal_edges (
23
+ from_memory_id, from_memory_type, to_memory_id, to_memory_type,
24
+ similarity, uplift, confidence, sample_size,
25
+ evidence_ids, experiment_ids, confounder_score,
26
+ mechanism, metadata
27
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
28
+ `);
29
+ const result = stmt.run(edge.fromMemoryId, edge.fromMemoryType, edge.toMemoryId, edge.toMemoryType, edge.similarity, edge.uplift || null, edge.confidence, edge.sampleSize || null, edge.evidenceIds ? JSON.stringify(edge.evidenceIds) : null, edge.experimentIds ? JSON.stringify(edge.experimentIds) : null, edge.confounderScore || null, edge.mechanism || null, edge.metadata ? JSON.stringify(edge.metadata) : null);
30
+ return result.lastInsertRowid;
31
+ }
32
+ /**
33
+ * Create a causal experiment (A/B test)
34
+ */
35
+ createExperiment(experiment) {
36
+ const stmt = this.db.prepare(`
37
+ INSERT INTO causal_experiments (
38
+ name, hypothesis, treatment_id, treatment_type, control_id,
39
+ start_time, sample_size, status, metadata
40
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
41
+ `);
42
+ const result = stmt.run(experiment.name, experiment.hypothesis, experiment.treatmentId, experiment.treatmentType, experiment.controlId || null, experiment.startTime, experiment.sampleSize, experiment.status, experiment.metadata ? JSON.stringify(experiment.metadata) : null);
43
+ return result.lastInsertRowid;
44
+ }
45
+ /**
46
+ * Record an observation in an experiment
47
+ */
48
+ recordObservation(observation) {
49
+ const stmt = this.db.prepare(`
50
+ INSERT INTO causal_observations (
51
+ experiment_id, episode_id, is_treatment, outcome_value, outcome_type, context
52
+ ) VALUES (?, ?, ?, ?, ?, ?)
53
+ `);
54
+ stmt.run(observation.experimentId, observation.episodeId, observation.isTreatment ? 1 : 0, observation.outcomeValue, observation.outcomeType, observation.context ? JSON.stringify(observation.context) : null);
55
+ // Update sample size
56
+ this.db.prepare(`
57
+ UPDATE causal_experiments
58
+ SET sample_size = sample_size + 1
59
+ WHERE id = ?
60
+ `).run(observation.experimentId);
61
+ }
62
+ /**
63
+ * Calculate uplift for an experiment
64
+ */
65
+ calculateUplift(experimentId) {
66
+ // Get treatment and control observations
67
+ const observations = this.db.prepare(`
68
+ SELECT is_treatment, outcome_value
69
+ FROM causal_observations
70
+ WHERE experiment_id = ?
71
+ `).all(experimentId);
72
+ const treatmentValues = observations
73
+ .filter(o => o.is_treatment === 1)
74
+ .map(o => o.outcome_value);
75
+ const controlValues = observations
76
+ .filter(o => o.is_treatment === 0)
77
+ .map(o => o.outcome_value);
78
+ if (treatmentValues.length === 0 || controlValues.length === 0) {
79
+ return { uplift: 0, pValue: 1.0, confidenceInterval: [0, 0] };
80
+ }
81
+ // Calculate means
82
+ const treatmentMean = this.mean(treatmentValues);
83
+ const controlMean = this.mean(controlValues);
84
+ const uplift = treatmentMean - controlMean;
85
+ // Calculate standard errors
86
+ const treatmentSE = this.standardError(treatmentValues);
87
+ const controlSE = this.standardError(controlValues);
88
+ const pooledSE = Math.sqrt(treatmentSE ** 2 + controlSE ** 2);
89
+ // t-statistic and p-value (two-tailed)
90
+ const tStat = uplift / pooledSE;
91
+ const df = treatmentValues.length + controlValues.length - 2;
92
+ const pValue = 2 * (1 - this.tCDF(Math.abs(tStat), df));
93
+ // 95% confidence interval
94
+ const tCritical = this.tInverse(0.025, df);
95
+ const marginOfError = tCritical * pooledSE;
96
+ const confidenceInterval = [
97
+ uplift - marginOfError,
98
+ uplift + marginOfError
99
+ ];
100
+ // Update experiment with results
101
+ this.db.prepare(`
102
+ UPDATE causal_experiments
103
+ SET treatment_mean = ?,
104
+ control_mean = ?,
105
+ uplift = ?,
106
+ p_value = ?,
107
+ confidence_interval_low = ?,
108
+ confidence_interval_high = ?,
109
+ status = 'completed'
110
+ WHERE id = ?
111
+ `).run(treatmentMean, controlMean, uplift, pValue, confidenceInterval[0], confidenceInterval[1], experimentId);
112
+ return { uplift, pValue, confidenceInterval };
113
+ }
114
+ /**
115
+ * Query causal effects
116
+ */
117
+ queryCausalEffects(query) {
118
+ const { interventionMemoryId, interventionMemoryType, outcomeMemoryId, minConfidence = 0.5, minUplift = 0.0 } = query;
119
+ let sql = `
120
+ SELECT * FROM causal_edges
121
+ WHERE from_memory_id = ?
122
+ AND from_memory_type = ?
123
+ AND confidence >= ?
124
+ AND ABS(uplift) >= ?
125
+ `;
126
+ const params = [
127
+ interventionMemoryId,
128
+ interventionMemoryType,
129
+ minConfidence,
130
+ minUplift
131
+ ];
132
+ if (outcomeMemoryId) {
133
+ sql += ' AND to_memory_id = ?';
134
+ params.push(outcomeMemoryId);
135
+ }
136
+ sql += ' ORDER BY ABS(uplift) * confidence DESC';
137
+ const rows = this.db.prepare(sql).all(...params);
138
+ return rows.map(row => this.rowToCausalEdge(row));
139
+ }
140
+ /**
141
+ * Get causal chain (multi-hop reasoning)
142
+ */
143
+ getCausalChain(fromMemoryId, toMemoryId, maxDepth = 5) {
144
+ // Use recursive CTE from view
145
+ const chains = this.db.prepare(`
146
+ WITH RECURSIVE chain(from_id, to_id, depth, path, total_uplift, min_confidence) AS (
147
+ SELECT
148
+ from_memory_id,
149
+ to_memory_id,
150
+ 1,
151
+ from_memory_id || '->' || to_memory_id,
152
+ uplift,
153
+ confidence
154
+ FROM causal_edges
155
+ WHERE from_memory_id = ? AND confidence >= 0.5
156
+
157
+ UNION ALL
158
+
159
+ SELECT
160
+ chain.from_id,
161
+ ce.to_memory_id,
162
+ chain.depth + 1,
163
+ chain.path || '->' || ce.to_memory_id,
164
+ chain.total_uplift + ce.uplift,
165
+ MIN(chain.min_confidence, ce.confidence)
166
+ FROM chain
167
+ JOIN causal_edges ce ON chain.to_id = ce.from_memory_id
168
+ WHERE chain.depth < ?
169
+ AND ce.confidence >= 0.5
170
+ AND chain.path NOT LIKE '%' || ce.to_memory_id || '%'
171
+ )
172
+ SELECT path, total_uplift, min_confidence
173
+ FROM chain
174
+ WHERE to_id = ?
175
+ ORDER BY total_uplift DESC
176
+ LIMIT 10
177
+ `).all(fromMemoryId, maxDepth, toMemoryId);
178
+ return chains.map(row => ({
179
+ path: row.path.split('->').map(Number),
180
+ totalUplift: row.total_uplift,
181
+ confidence: row.min_confidence
182
+ }));
183
+ }
184
+ /**
185
+ * Calculate causal gain: E[outcome|do(treatment)] - E[outcome]
186
+ */
187
+ calculateCausalGain(treatmentId, outcomeType) {
188
+ // Get episodes where treatment was applied
189
+ const withTreatment = this.db.prepare(`
190
+ SELECT AVG(CASE WHEN ? = 'reward' THEN reward
191
+ WHEN ? = 'success' THEN success
192
+ WHEN ? = 'latency' THEN latency_ms
193
+ END) as avg_outcome
194
+ FROM episodes
195
+ WHERE id IN (
196
+ SELECT to_memory_id FROM causal_edges
197
+ WHERE from_memory_id = ? AND confidence >= 0.6
198
+ )
199
+ `).get(outcomeType, outcomeType, outcomeType, treatmentId);
200
+ // Get baseline (no treatment)
201
+ const baseline = this.db.prepare(`
202
+ SELECT AVG(CASE WHEN ? = 'reward' THEN reward
203
+ WHEN ? = 'success' THEN success
204
+ WHEN ? = 'latency' THEN latency_ms
205
+ END) as avg_outcome
206
+ FROM episodes
207
+ WHERE id NOT IN (
208
+ SELECT to_memory_id FROM causal_edges
209
+ WHERE from_memory_id = ?
210
+ )
211
+ `).get(outcomeType, outcomeType, outcomeType, treatmentId);
212
+ const causalGain = (withTreatment?.avg_outcome || 0) - (baseline?.avg_outcome || 0);
213
+ // Get most confident edge for mechanism
214
+ const edge = this.db.prepare(`
215
+ SELECT mechanism, confidence
216
+ FROM causal_edges
217
+ WHERE from_memory_id = ?
218
+ ORDER BY confidence DESC
219
+ LIMIT 1
220
+ `).get(treatmentId);
221
+ return {
222
+ causalGain,
223
+ confidence: edge?.confidence || 0,
224
+ mechanism: edge?.mechanism || 'unknown'
225
+ };
226
+ }
227
+ /**
228
+ * Detect confounders using correlation analysis
229
+ */
230
+ detectConfounders(edgeId) {
231
+ const edge = this.db.prepare('SELECT * FROM causal_edges WHERE id = ?').get(edgeId);
232
+ if (!edge) {
233
+ return { confounders: [] };
234
+ }
235
+ // Find memories correlated with both treatment and outcome
236
+ // This is a simplified version - production would use proper statistical tests
237
+ const potentialConfounders = this.db.prepare(`
238
+ SELECT DISTINCT e.id, e.task
239
+ FROM episodes e
240
+ WHERE e.id != ? AND e.id != ?
241
+ AND e.session_id IN (
242
+ SELECT session_id FROM episodes WHERE id = ?
243
+ UNION
244
+ SELECT session_id FROM episodes WHERE id = ?
245
+ )
246
+ `).all(edge.from_memory_id, edge.to_memory_id, edge.from_memory_id, edge.to_memory_id);
247
+ const confounders = potentialConfounders.map((conf) => {
248
+ // Calculate correlation scores (simplified)
249
+ const treatmentCorr = this.calculateCorrelation(conf.id, edge.from_memory_id);
250
+ const outcomeCorr = this.calculateCorrelation(conf.id, edge.to_memory_id);
251
+ const confounderScore = Math.sqrt(treatmentCorr ** 2 * outcomeCorr ** 2);
252
+ return {
253
+ memoryId: conf.id,
254
+ correlationWithTreatment: treatmentCorr,
255
+ correlationWithOutcome: outcomeCorr,
256
+ confounderScore
257
+ };
258
+ }).filter(c => c.confounderScore > 0.3);
259
+ // Update edge with confounder score
260
+ if (confounders.length > 0) {
261
+ const maxConfounderScore = Math.max(...confounders.map(c => c.confounderScore));
262
+ this.db.prepare(`
263
+ UPDATE causal_edges
264
+ SET confounder_score = ?
265
+ WHERE id = ?
266
+ `).run(maxConfounderScore, edgeId);
267
+ }
268
+ return { confounders };
269
+ }
270
+ // ========================================================================
271
+ // Private Helper Methods
272
+ // ========================================================================
273
+ rowToCausalEdge(row) {
274
+ return {
275
+ id: row.id,
276
+ fromMemoryId: row.from_memory_id,
277
+ fromMemoryType: row.from_memory_type,
278
+ toMemoryId: row.to_memory_id,
279
+ toMemoryType: row.to_memory_type,
280
+ similarity: row.similarity,
281
+ uplift: row.uplift,
282
+ confidence: row.confidence,
283
+ sampleSize: row.sample_size,
284
+ evidenceIds: row.evidence_ids ? JSON.parse(row.evidence_ids) : undefined,
285
+ experimentIds: row.experiment_ids ? JSON.parse(row.experiment_ids) : undefined,
286
+ confounderScore: row.confounder_score,
287
+ mechanism: row.mechanism,
288
+ metadata: row.metadata ? JSON.parse(row.metadata) : undefined
289
+ };
290
+ }
291
+ mean(values) {
292
+ return values.reduce((a, b) => a + b, 0) / values.length;
293
+ }
294
+ variance(values) {
295
+ const avg = this.mean(values);
296
+ return values.reduce((sum, val) => sum + (val - avg) ** 2, 0) / values.length;
297
+ }
298
+ standardError(values) {
299
+ return Math.sqrt(this.variance(values) / values.length);
300
+ }
301
+ tCDF(t, df) {
302
+ // Simplified t-distribution CDF (use proper stats library in production)
303
+ // This is an approximation
304
+ return 0.5 + 0.5 * Math.sign(t) * (1 - Math.pow(1 + t * t / df, -df / 2));
305
+ }
306
+ tInverse(p, df) {
307
+ // Simplified inverse t-distribution (use proper stats library)
308
+ // Approximation for 95% CI
309
+ return 1.96; // Standard normal approximation
310
+ }
311
+ calculateCorrelation(id1, id2) {
312
+ // Simplified correlation calculation
313
+ // In production, use proper correlation metrics
314
+ const sharedSessions = this.db.prepare(`
315
+ SELECT COUNT(DISTINCT e1.session_id) as shared
316
+ FROM episodes e1
317
+ JOIN episodes e2 ON e1.session_id = e2.session_id
318
+ WHERE e1.id = ? AND e2.id = ?
319
+ `).get(id1, id2);
320
+ return Math.min(sharedSessions?.shared || 0, 1.0);
321
+ }
322
+ }
@@ -0,0 +1,281 @@
1
+ /**
2
+ * CausalRecall - Utility-Based Reranking + Certificate Issuer
3
+ *
4
+ * Combines:
5
+ * 1. Vector similarity search
6
+ * 2. Causal uplift from CausalMemoryGraph
7
+ * 3. Utility-based reranking: U = α*similarity + β*uplift − γ*latencyCost
8
+ * 4. Automatic certificate issuance via ExplainableRecall
9
+ *
10
+ * This is the main entry point for production retrieval with:
11
+ * - Causal-aware ranking
12
+ * - Explainable provenance
13
+ * - Policy compliance
14
+ */
15
+ import { CausalMemoryGraph } from './CausalMemoryGraph.js';
16
+ import { ExplainableRecall } from './ExplainableRecall.js';
17
+ export class CausalRecall {
18
+ config;
19
+ db;
20
+ causalGraph;
21
+ explainableRecall;
22
+ embedder;
23
+ constructor(db, embedder, config = {
24
+ alpha: 0.7,
25
+ beta: 0.2,
26
+ gamma: 0.1,
27
+ minConfidence: 0.6
28
+ }) {
29
+ this.config = config;
30
+ this.db = db;
31
+ this.embedder = embedder;
32
+ this.causalGraph = new CausalMemoryGraph(db);
33
+ this.explainableRecall = new ExplainableRecall(db);
34
+ }
35
+ /**
36
+ * Main recall function with utility-based reranking and certificate issuance
37
+ *
38
+ * @param queryId Unique query identifier
39
+ * @param queryText Natural language query
40
+ * @param k Number of results to return (default: 12)
41
+ * @param requirements Optional list of requirements for completeness checking
42
+ * @param accessLevel Security access level for certificate
43
+ * @returns Reranked results with certificate
44
+ */
45
+ async recall(queryId, queryText, k = 12, requirements, accessLevel = 'internal') {
46
+ const startTime = Date.now();
47
+ const metrics = {
48
+ vectorSearchMs: 0,
49
+ causalLookupMs: 0,
50
+ rerankMs: 0,
51
+ certificateMs: 0
52
+ };
53
+ // Step 1: Vector similarity search
54
+ const vectorStart = Date.now();
55
+ const queryEmbedding = await this.embedder.embed(queryText);
56
+ const candidates = await this.vectorSearch(queryEmbedding, k * 2); // Fetch 2k for reranking
57
+ metrics.vectorSearchMs = Date.now() - vectorStart;
58
+ // Step 2: Load causal edges for candidates
59
+ const causalStart = Date.now();
60
+ const causalEdges = await this.loadCausalEdges(candidates.map(c => c.id));
61
+ metrics.causalLookupMs = Date.now() - causalStart;
62
+ // Step 3: Rerank by utility
63
+ const rerankStart = Date.now();
64
+ const reranked = this.rerankByUtility(candidates, causalEdges);
65
+ const topK = reranked.slice(0, k);
66
+ metrics.rerankMs = Date.now() - rerankStart;
67
+ // Step 4: Issue certificate
68
+ const certStart = Date.now();
69
+ const certificate = this.issueCertificate({
70
+ queryId,
71
+ queryText,
72
+ candidates: topK,
73
+ requirements: requirements || this.extractRequirements(queryText),
74
+ accessLevel
75
+ });
76
+ metrics.certificateMs = Date.now() - certStart;
77
+ const totalLatencyMs = Date.now() - startTime;
78
+ return {
79
+ candidates: topK,
80
+ certificate,
81
+ queryId,
82
+ totalLatencyMs,
83
+ metrics
84
+ };
85
+ }
86
+ /**
87
+ * Vector similarity search using cosine similarity
88
+ */
89
+ async vectorSearch(queryEmbedding, k) {
90
+ const results = [];
91
+ // Search episode embeddings
92
+ const episodes = this.db.prepare(`
93
+ SELECT
94
+ e.id,
95
+ 'episode' as type,
96
+ e.task || ' ' || COALESCE(e.output, '') as content,
97
+ ee.embedding,
98
+ e.latency_ms
99
+ FROM episodes e
100
+ JOIN episode_embeddings ee ON e.id = ee.episode_id
101
+ ORDER BY e.ts DESC
102
+ LIMIT ?
103
+ `).all(k * 2);
104
+ for (const ep of episodes) {
105
+ const episodeRow = ep;
106
+ const embedding = new Float32Array(JSON.parse(episodeRow.embedding));
107
+ const similarity = this.cosineSimilarity(queryEmbedding, embedding);
108
+ results.push({
109
+ id: episodeRow.id.toString(),
110
+ type: episodeRow.type,
111
+ content: episodeRow.content,
112
+ similarity,
113
+ latencyMs: episodeRow.latency_ms || 0
114
+ });
115
+ }
116
+ // Sort by similarity and return top k
117
+ return results
118
+ .sort((a, b) => b.similarity - a.similarity)
119
+ .slice(0, k);
120
+ }
121
+ /**
122
+ * Load causal edges for candidates
123
+ */
124
+ async loadCausalEdges(candidateIds) {
125
+ const edgeMap = new Map();
126
+ if (candidateIds.length === 0) {
127
+ return edgeMap;
128
+ }
129
+ const placeholders = candidateIds.map(() => '?').join(',');
130
+ const edges = this.db.prepare(`
131
+ SELECT * FROM causal_edges
132
+ WHERE from_memory_id IN (${placeholders})
133
+ AND confidence >= ?
134
+ `).all(...candidateIds.map(id => parseInt(id)), this.config.minConfidence || 0.6);
135
+ for (const edge of edges) {
136
+ const fromId = edge.from_memory_id.toString();
137
+ if (!edgeMap.has(fromId)) {
138
+ edgeMap.set(fromId, []);
139
+ }
140
+ edgeMap.get(fromId).push({
141
+ id: edge.id,
142
+ fromMemoryId: edge.from_memory_id,
143
+ fromMemoryType: edge.from_memory_type,
144
+ toMemoryId: edge.to_memory_id,
145
+ toMemoryType: edge.to_memory_type,
146
+ similarity: edge.similarity,
147
+ uplift: edge.uplift,
148
+ confidence: edge.confidence,
149
+ sampleSize: edge.sample_size,
150
+ evidenceIds: edge.evidence_ids ? JSON.parse(edge.evidence_ids) : undefined,
151
+ mechanism: edge.mechanism
152
+ });
153
+ }
154
+ return edgeMap;
155
+ }
156
+ /**
157
+ * Rerank by utility: U = α*similarity + β*uplift − γ*latencyCost
158
+ */
159
+ rerankByUtility(candidates, causalEdges) {
160
+ const { alpha, beta, gamma } = this.config;
161
+ const reranked = candidates.map(candidate => {
162
+ // Get causal uplift (average if multiple edges)
163
+ const edges = causalEdges.get(candidate.id) || [];
164
+ const avgUplift = edges.length > 0
165
+ ? edges.reduce((sum, e) => sum + (e.uplift || 0), 0) / edges.length
166
+ : 0;
167
+ const avgConfidence = edges.length > 0
168
+ ? edges.reduce((sum, e) => sum + e.confidence, 0) / edges.length
169
+ : 0;
170
+ // Normalize latency (assume max 1000ms)
171
+ const latencyCost = Math.min(candidate.latencyMs / 1000, 1.0);
172
+ // Calculate utility
173
+ const utilityScore = alpha * candidate.similarity + beta * avgUplift - gamma * latencyCost;
174
+ return {
175
+ id: candidate.id,
176
+ type: candidate.type,
177
+ content: candidate.content,
178
+ similarity: candidate.similarity,
179
+ uplift: avgUplift,
180
+ causalConfidence: avgConfidence,
181
+ latencyMs: candidate.latencyMs,
182
+ utilityScore,
183
+ rank: 0 // Will be set after sorting
184
+ };
185
+ });
186
+ // Sort by utility score descending
187
+ reranked.sort((a, b) => b.utilityScore - a.utilityScore);
188
+ // Assign ranks
189
+ reranked.forEach((candidate, idx) => {
190
+ candidate.rank = idx + 1;
191
+ });
192
+ return reranked;
193
+ }
194
+ /**
195
+ * Issue certificate for the retrieval
196
+ */
197
+ issueCertificate(params) {
198
+ const { queryId, queryText, candidates, requirements, accessLevel } = params;
199
+ const chunks = candidates.map(c => ({
200
+ id: c.id,
201
+ type: c.type,
202
+ content: c.content,
203
+ relevance: c.similarity
204
+ }));
205
+ return this.explainableRecall.createCertificate({
206
+ queryId,
207
+ queryText,
208
+ chunks,
209
+ requirements,
210
+ accessLevel
211
+ });
212
+ }
213
+ /**
214
+ * Extract requirements from query text (simple keyword extraction)
215
+ */
216
+ extractRequirements(queryText) {
217
+ // Simple extraction: split on common words and filter
218
+ const stopWords = new Set(['a', 'an', 'the', 'is', 'are', 'was', 'were', 'to', 'from', 'for', 'with', 'how', 'what', 'where', 'when', 'why', 'who']);
219
+ const words = queryText
220
+ .toLowerCase()
221
+ .replace(/[^a-z0-9\s]/g, '')
222
+ .split(/\s+/)
223
+ .filter(w => w.length > 3 && !stopWords.has(w));
224
+ // Return unique words
225
+ return [...new Set(words)];
226
+ }
227
+ /**
228
+ * Cosine similarity between two vectors
229
+ */
230
+ cosineSimilarity(a, b) {
231
+ if (a.length !== b.length) {
232
+ throw new Error('Vector dimensions must match');
233
+ }
234
+ let dotProduct = 0;
235
+ let magnitudeA = 0;
236
+ let magnitudeB = 0;
237
+ for (let i = 0; i < a.length; i++) {
238
+ dotProduct += a[i] * b[i];
239
+ magnitudeA += a[i] * a[i];
240
+ magnitudeB += b[i] * b[i];
241
+ }
242
+ const magnitude = Math.sqrt(magnitudeA) * Math.sqrt(magnitudeB);
243
+ return magnitude === 0 ? 0 : dotProduct / magnitude;
244
+ }
245
+ /**
246
+ * Batch recall for multiple queries
247
+ */
248
+ async batchRecall(queries, requirements, accessLevel = 'internal') {
249
+ const results = [];
250
+ for (const query of queries) {
251
+ const result = await this.recall(query.queryId, query.queryText, query.k || 12, requirements, accessLevel);
252
+ results.push(result);
253
+ }
254
+ return results;
255
+ }
256
+ /**
257
+ * Get recall statistics
258
+ */
259
+ getStats() {
260
+ const causalEdges = this.db.prepare('SELECT COUNT(*) as count FROM causal_edges').get();
261
+ const certificates = this.db.prepare('SELECT COUNT(*) as count FROM recall_certificates').get();
262
+ const avgStats = this.db.prepare(`
263
+ SELECT
264
+ AVG(redundancy_ratio) as avg_redundancy,
265
+ AVG(completeness_score) as avg_completeness
266
+ FROM recall_certificates
267
+ `).get();
268
+ return {
269
+ totalCausalEdges: causalEdges.count,
270
+ totalCertificates: certificates.count,
271
+ avgRedundancyRatio: avgStats?.avg_redundancy || 0,
272
+ avgCompletenessScore: avgStats?.avg_completeness || 0
273
+ };
274
+ }
275
+ /**
276
+ * Update rerank configuration
277
+ */
278
+ updateConfig(config) {
279
+ this.config = { ...this.config, ...config };
280
+ }
281
+ }