@devflow-tools/memory-engine 0.13.3 → 0.14.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 (56) hide show
  1. package/dist/consolidator.d.ts +13 -0
  2. package/dist/consolidator.d.ts.map +1 -0
  3. package/dist/consolidator.js +184 -0
  4. package/dist/consolidator.js.map +1 -0
  5. package/dist/event-grouper.d.ts +13 -0
  6. package/dist/event-grouper.d.ts.map +1 -0
  7. package/dist/event-grouper.js +178 -0
  8. package/dist/event-grouper.js.map +1 -0
  9. package/dist/graph-store.d.ts.map +1 -1
  10. package/dist/graph-store.js +2 -4
  11. package/dist/graph-store.js.map +1 -1
  12. package/dist/hybrid-search.d.ts +7 -4
  13. package/dist/hybrid-search.d.ts.map +1 -1
  14. package/dist/hybrid-search.js +69 -8
  15. package/dist/hybrid-search.js.map +1 -1
  16. package/dist/index.d.ts +14 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +7 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/l2-evaluator.d.ts +31 -0
  21. package/dist/l2-evaluator.d.ts.map +1 -0
  22. package/dist/l2-evaluator.js +103 -0
  23. package/dist/l2-evaluator.js.map +1 -0
  24. package/dist/llm-provider.d.ts +9 -0
  25. package/dist/llm-provider.d.ts.map +1 -0
  26. package/dist/llm-provider.js +37 -0
  27. package/dist/llm-provider.js.map +1 -0
  28. package/dist/memory-engine.d.ts +27 -4
  29. package/dist/memory-engine.d.ts.map +1 -1
  30. package/dist/memory-engine.js +275 -182
  31. package/dist/memory-engine.js.map +1 -1
  32. package/dist/memory-gate.d.ts +116 -0
  33. package/dist/memory-gate.d.ts.map +1 -0
  34. package/dist/memory-gate.js +385 -0
  35. package/dist/memory-gate.js.map +1 -0
  36. package/dist/memory-store.d.ts +234 -32
  37. package/dist/memory-store.d.ts.map +1 -1
  38. package/dist/memory-store.js +729 -142
  39. package/dist/memory-store.js.map +1 -1
  40. package/dist/project-validator.d.ts +10 -0
  41. package/dist/project-validator.d.ts.map +1 -0
  42. package/dist/project-validator.js +36 -0
  43. package/dist/project-validator.js.map +1 -0
  44. package/dist/session-summarizer.d.ts +10 -0
  45. package/dist/session-summarizer.d.ts.map +1 -0
  46. package/dist/session-summarizer.js +197 -0
  47. package/dist/session-summarizer.js.map +1 -0
  48. package/dist/signal-buffer.d.ts +42 -0
  49. package/dist/signal-buffer.d.ts.map +1 -0
  50. package/dist/signal-buffer.js +104 -0
  51. package/dist/signal-buffer.js.map +1 -0
  52. package/dist/signal-detector.d.ts +39 -0
  53. package/dist/signal-detector.d.ts.map +1 -0
  54. package/dist/signal-detector.js +239 -0
  55. package/dist/signal-detector.js.map +1 -0
  56. package/package.json +5 -5
@@ -0,0 +1,13 @@
1
+ import type { MemoryStore } from './memory-store.js';
2
+ export interface ConsolidatorResult {
3
+ consolidated: number;
4
+ skipped: number;
5
+ provider: string;
6
+ latencyMs: number;
7
+ }
8
+ export declare function consolidate(store: MemoryStore, projectRoot: string, options?: {
9
+ minObservations?: number;
10
+ minSessions?: number;
11
+ maxClusters?: number;
12
+ }): Promise<ConsolidatorResult>;
13
+ //# sourceMappingURL=consolidator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidator.d.ts","sourceRoot":"","sources":["../src/consolidator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA0BrD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID,wBAAsB,WAAW,CAC/B,KAAK,EAAE,WAAW,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IACR,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,GACA,OAAO,CAAC,kBAAkB,CAAC,CAuK7B"}
@@ -0,0 +1,184 @@
1
+ import { callLLM } from './llm-provider.js';
2
+ // ── Prompt ──────────────────────────────────────────────
3
+ const CONSOLIDATOR_SYSTEM = `You are a knowledge consolidator for DevFlow.
4
+ Given multiple observations about the same concept from different coding sessions,
5
+ produce ONE consolidated memory entry.
6
+
7
+ Output JSON:
8
+ {
9
+ "type": "semantic" | "pattern" | "constraint" | "preference" | "lesson",
10
+ "title": "≤80 chars",
11
+ "content": "1-2 sentence consolidated knowledge",
12
+ "confidence": 0.0-1.0,
13
+ "supersedes_observation_ids": ["obs:...", ...]
14
+ }
15
+
16
+ Rules:
17
+ - Merge complementary facts; discard contradictory outliers
18
+ - Higher confidence when observations are consistent across sessions
19
+ - If observations disagree, pick the majority view and note uncertainty in content
20
+ - Return ONLY the JSON object`;
21
+ // ── Consolidator ────────────────────────────────────────
22
+ export async function consolidate(store, projectRoot, options) {
23
+ const start = Date.now();
24
+ const minObs = options?.minObservations ?? 3;
25
+ const minSess = options?.minSessions ?? 2;
26
+ // 1. Get concept clusters from unconsolidated observations
27
+ const clusters = store.getClusterCandidates(projectRoot, minObs, minSess);
28
+ if (clusters.length === 0) {
29
+ console.log('[Consolidator] No clusters found (no concept meets cross-session threshold)');
30
+ return { consolidated: 0, skipped: 0, provider: 'none', latencyMs: Date.now() - start };
31
+ }
32
+ console.log('[Consolidator] Clusters formed', {
33
+ count: clusters.length,
34
+ clusters: clusters.map(c => ({
35
+ concept: c.concept,
36
+ observationCount: c.observationCount,
37
+ sessionCount: c.sessionCount,
38
+ })),
39
+ });
40
+ // 2. Fetch full observation data for each cluster
41
+ const clusterData = clusters.map(c => ({
42
+ concept: c.concept,
43
+ observationCount: c.observationCount,
44
+ sessionCount: c.sessionCount,
45
+ observations: c.observationIds
46
+ .map(id => store.getObservation(id))
47
+ .filter(Boolean),
48
+ }));
49
+ // 3. LLM aggregation (1 call for all clusters)
50
+ let provider = 'rules';
51
+ let consolidated = 0;
52
+ try {
53
+ const userPrompt = buildConsolidationPrompt(clusterData);
54
+ const response = await callLLM(CONSOLIDATOR_SYSTEM, userPrompt);
55
+ provider = response.provider;
56
+ if (response.provider !== 'rules') {
57
+ const results = JSON.parse(response.content);
58
+ const entries = Array.isArray(results) ? results : [results];
59
+ for (const entry of entries) {
60
+ if (!entry.type || !entry.content)
61
+ continue;
62
+ // 4. Write memory
63
+ const memId = `mem:${Date.now()}:${Math.random().toString(36).slice(2, 10)}`;
64
+ store.add({
65
+ id: memId,
66
+ type: entry.type,
67
+ content: entry.content,
68
+ title: entry.title,
69
+ source: 'consolidation',
70
+ status: 'active',
71
+ confidence: entry.confidence ?? 0.7,
72
+ });
73
+ // 5. Link observations to memory
74
+ const obsIds = entry.supersedes_observation_ids ?? [];
75
+ for (const obsId of obsIds) {
76
+ store.linkObservationToMemory(obsId, memId);
77
+ }
78
+ // 6. Add evidence
79
+ store.addEvidence({
80
+ memoryId: memId,
81
+ type: 'consolidation',
82
+ weight: entry.confidence ?? 0.7,
83
+ sourceObservationIds: obsIds,
84
+ summary: `Consolidated from ${obsIds.length} observations about "${entry.title ?? entry.type}"`,
85
+ });
86
+ // 7. Audit
87
+ store.recordHistory({
88
+ memoryId: memId,
89
+ event: 'ADD',
90
+ newContent: entry.content,
91
+ reason: 'consolidation',
92
+ });
93
+ consolidated++;
94
+ }
95
+ }
96
+ else {
97
+ // Rule fallback: pick highest-importance observation per cluster as representative
98
+ for (const cluster of clusterData) {
99
+ const best = cluster.observations.reduce((a, b) => (a?.importance ?? 0) >= (b?.importance ?? 0) ? a : b);
100
+ if (!best)
101
+ continue;
102
+ const memId = `mem:${Date.now()}:${Math.random().toString(36).slice(2, 10)}`;
103
+ store.add({
104
+ id: memId,
105
+ type: 'semantic',
106
+ content: best.narrative || best.title,
107
+ title: best.title,
108
+ source: 'consolidation',
109
+ status: 'active',
110
+ confidence: best.confidence,
111
+ });
112
+ store.linkObservationToMemory(best.id, memId);
113
+ store.addEvidence({
114
+ memoryId: memId,
115
+ type: 'consolidation',
116
+ weight: best.confidence,
117
+ sourceObservationIds: [best.id],
118
+ summary: `Rule-based consolidation from observation about "${cluster.concept}"`,
119
+ });
120
+ store.recordHistory({
121
+ memoryId: memId,
122
+ event: 'ADD',
123
+ newContent: best.narrative ?? best.title,
124
+ reason: 'consolidation_rule_fallback',
125
+ });
126
+ consolidated++;
127
+ }
128
+ }
129
+ }
130
+ catch (err) {
131
+ console.warn('[Consolidator] Consolidation failed', { error: err.message });
132
+ // Rule fallback on error
133
+ for (const cluster of clusterData) {
134
+ const best = cluster.observations.reduce((a, b) => (a?.importance ?? 0) >= (b?.importance ?? 0) ? a : b);
135
+ if (!best)
136
+ continue;
137
+ const memId = `mem:${Date.now()}:${Math.random().toString(36).slice(2, 10)}`;
138
+ store.add({
139
+ id: memId,
140
+ type: 'semantic',
141
+ content: best.narrative || best.title,
142
+ title: best.title,
143
+ source: 'consolidation',
144
+ status: 'active',
145
+ confidence: best.confidence,
146
+ });
147
+ store.linkObservationToMemory(best.id, memId);
148
+ store.addEvidence({
149
+ memoryId: memId,
150
+ type: 'consolidation',
151
+ weight: best.confidence,
152
+ sourceObservationIds: [best.id],
153
+ summary: `Error-fallback consolidation from observation about "${cluster.concept}"`,
154
+ });
155
+ store.recordHistory({
156
+ memoryId: memId,
157
+ event: 'ADD',
158
+ newContent: best.narrative ?? best.title,
159
+ reason: 'consolidation_error_fallback',
160
+ });
161
+ consolidated++;
162
+ }
163
+ }
164
+ const latencyMs = Date.now() - start;
165
+ console.log('[Consolidator] Consolidation complete', {
166
+ consolidated,
167
+ skipped: clusters.length - consolidated,
168
+ provider,
169
+ latencyMs,
170
+ });
171
+ return { consolidated, skipped: clusters.length - consolidated, provider, latencyMs };
172
+ }
173
+ // ── Helpers ─────────────────────────────────────────────
174
+ function buildConsolidationPrompt(clusters) {
175
+ const parts = clusters.map((c, i) => {
176
+ const obsText = c.observations
177
+ .filter(Boolean)
178
+ .map(o => ` - [${o.type}] ${o.title}: ${o.narrative || 'no narrative'} (importance: ${o.importance}, session: ${o.session_id}, id: ${o.id})`)
179
+ .join('\n');
180
+ return `Cluster ${i + 1}: Concept "${c.concept}" (${c.observationCount} observations across ${c.sessionCount} sessions)\n${obsText}`;
181
+ });
182
+ return `Consolidate the following observation clusters into memory entries. Return a JSON array with one entry per cluster.\n\n${parts.join('\n\n')}`;
183
+ }
184
+ //# sourceMappingURL=consolidator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consolidator.js","sourceRoot":"","sources":["../src/consolidator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { EventRow } from './memory-store.js';
2
+ export interface EventGroup {
3
+ id: string;
4
+ events: EventRow[];
5
+ primaryTool: string;
6
+ hasError: boolean;
7
+ hasFix: boolean;
8
+ signalTypes: string[];
9
+ summary: string;
10
+ }
11
+ export declare function groupEvents(events: EventRow[]): EventGroup[];
12
+ export declare function triageGroups(groups: EventGroup[], maxGroups?: number): EventGroup[];
13
+ //# sourceMappingURL=event-grouper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-grouper.d.ts","sourceRoot":"","sources":["../src/event-grouper.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAKlD,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CA4D5D;AAID,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE,SAAS,SAAI,GAAG,UAAU,EAAE,CAqC9E"}
@@ -0,0 +1,178 @@
1
+ // ── Constants ──────────────────────────────────────────
2
+ const LOW_VALUE_TOOLS = new Set([
3
+ 'Glob', 'Grep',
4
+ ]);
5
+ const LOW_VALUE_FIRST_WORDS = new Set([
6
+ 'ls', 'cat', 'grep', 'echo', 'cd', 'pwd', 'which',
7
+ 'head', 'tail', 'wc', 'date',
8
+ ]);
9
+ // ── Event Grouper ──────────────────────────────────────
10
+ export function groupEvents(events) {
11
+ const groups = [];
12
+ let currentGroup = [];
13
+ let groupIdx = 0;
14
+ for (let i = 0; i < events.length; i++) {
15
+ const e = events[i];
16
+ // Start new group on context boundaries
17
+ if (currentGroup.length > 0) {
18
+ const prev = currentGroup[currentGroup.length - 1];
19
+ const timeGap = e.created_at - prev.created_at;
20
+ const isNewGroup = timeGap > 120_000 || // >2 min gap
21
+ isContextSwitch(prev, e) ||
22
+ currentGroup.length >= 10; // max 10 events per group
23
+ if (isNewGroup) {
24
+ const group = buildGroup(currentGroup, groupIdx++);
25
+ if (group)
26
+ groups.push(group);
27
+ currentGroup = [];
28
+ }
29
+ }
30
+ currentGroup.push(e);
31
+ // Error events create their own micro-group (error + follow-up fix)
32
+ if (isErrorEvent(e) && currentGroup.length > 1) {
33
+ // Take error + next few events as a fix attempt group
34
+ const fixGroup = [e];
35
+ let j = i + 1;
36
+ while (j < events.length && j <= i + 5) {
37
+ const next = events[j];
38
+ if (isRelatedFix(e, next) || j - i <= 1) {
39
+ fixGroup.push(next);
40
+ j++;
41
+ }
42
+ else {
43
+ break;
44
+ }
45
+ }
46
+ if (fixGroup.length > 1) {
47
+ const group = buildGroup(fixGroup, groupIdx++);
48
+ if (group)
49
+ groups.push(group);
50
+ currentGroup = []; // reset current
51
+ i = j - 1; // skip consumed events
52
+ }
53
+ }
54
+ }
55
+ // Flush remaining
56
+ if (currentGroup.length > 0) {
57
+ const group = buildGroup(currentGroup, groupIdx++);
58
+ if (group)
59
+ groups.push(group);
60
+ }
61
+ console.log('[EventGrouper] Groups formed', {
62
+ eventCount: events.length,
63
+ groupCount: groups.length,
64
+ });
65
+ return groups;
66
+ }
67
+ // ── Triage ─────────────────────────────────────────────
68
+ export function triageGroups(groups, maxGroups = 8) {
69
+ const before = groups.length;
70
+ // Filter: remove pure-query groups
71
+ const filtered = groups.filter(g => {
72
+ // Keep groups with errors
73
+ if (g.hasError)
74
+ return true;
75
+ // Keep groups with fixes
76
+ if (g.hasFix)
77
+ return true;
78
+ // Remove groups that are only low-value tools
79
+ const onlyLowValue = g.events.every(e => {
80
+ if (LOW_VALUE_TOOLS.has(e.tool))
81
+ return true;
82
+ if (e.tool === 'Bash' && e.command) {
83
+ const firstWord = e.command.split(' ')[0] ?? '';
84
+ return LOW_VALUE_FIRST_WORDS.has(firstWord);
85
+ }
86
+ return false;
87
+ });
88
+ return !onlyLowValue;
89
+ });
90
+ // Sort: groups with errors/signals first, then by size desc
91
+ filtered.sort((a, b) => {
92
+ const aPriority = (a.hasError ? 2 : 0) + (a.hasFix ? 1 : 0) + a.signalTypes.length;
93
+ const bPriority = (b.hasError ? 2 : 0) + (b.hasFix ? 1 : 0) + b.signalTypes.length;
94
+ if (bPriority !== aPriority)
95
+ return bPriority - aPriority;
96
+ return b.events.length - a.events.length;
97
+ });
98
+ const result = filtered.slice(0, maxGroups);
99
+ console.log('[EventGrouper] Groups triaged', {
100
+ inputCount: before,
101
+ outputCount: result.length,
102
+ discardedCount: before - result.length,
103
+ });
104
+ return result;
105
+ }
106
+ // ── Helpers ────────────────────────────────────────────
107
+ function buildGroup(events, idx) {
108
+ if (events.length === 0)
109
+ return null;
110
+ const tools = events.map(e => e.tool);
111
+ const primaryTool = mostFrequent(tools);
112
+ const hasError = events.some(e => e.exit_code !== null && e.exit_code !== undefined && e.exit_code !== 0);
113
+ const hasFix = events.some(e => e.exit_code === 0) && hasError;
114
+ // Generate short summary from the events
115
+ const summaryEvents = events
116
+ .filter(e => e.tool !== 'Grep' && e.tool !== 'Glob')
117
+ .slice(0, 3);
118
+ const summary = summaryEvents
119
+ .map(e => {
120
+ const tool = e.tool === 'Bash' ? (e.command?.split(' ')[0] ?? 'bash') : e.tool;
121
+ return e.exit_code !== 0 ? `${tool}(error)` : tool;
122
+ })
123
+ .join(' → ');
124
+ return {
125
+ id: `group:${idx}`,
126
+ events,
127
+ primaryTool,
128
+ hasError,
129
+ hasFix,
130
+ signalTypes: [],
131
+ summary: summary || `${events.length} tool calls with ${primaryTool}`,
132
+ };
133
+ }
134
+ function isErrorEvent(e) {
135
+ return e.exit_code !== null && e.exit_code !== undefined && e.exit_code !== 0;
136
+ }
137
+ function isContextSwitch(prev, next) {
138
+ const BASH = 'Bash';
139
+ const FILE_TOOLS = new Set(['Read', 'Edit', 'Write']);
140
+ // Bash → File read is continuation
141
+ if (prev.tool === BASH && FILE_TOOLS.has(next.tool))
142
+ return false;
143
+ // File read → Edit is continuation
144
+ if (FILE_TOOLS.has(prev.tool) && FILE_TOOLS.has(next.tool))
145
+ return false;
146
+ // Agent spawn → anything is new context
147
+ if (prev.tool === 'Agent')
148
+ return true;
149
+ return false;
150
+ }
151
+ function isRelatedFix(errorEvent, nextEvent) {
152
+ // Same tool/command base
153
+ if (errorEvent.tool === nextEvent.tool)
154
+ return true;
155
+ if (errorEvent.command && nextEvent.command) {
156
+ const errBase = errorEvent.command.split(' ')[0];
157
+ const nextBase = nextEvent.command.split(' ')[0];
158
+ if (errBase === nextBase)
159
+ return true;
160
+ }
161
+ return false;
162
+ }
163
+ function mostFrequent(arr) {
164
+ const counts = new Map();
165
+ for (const item of arr) {
166
+ counts.set(item, (counts.get(item) ?? 0) + 1);
167
+ }
168
+ let best = arr[0] ?? 'unknown';
169
+ let bestCount = 0;
170
+ for (const [item, count] of counts) {
171
+ if (count > bestCount) {
172
+ best = item;
173
+ bestCount = count;
174
+ }
175
+ }
176
+ return best;
177
+ }
178
+ //# sourceMappingURL=event-grouper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-grouper.js","sourceRoot":"","sources":["../src/event-grouper.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"graph-store.d.ts","sourceRoot":"","sources":["../src/graph-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAkBrD,qBAAa,UAAU;IACT,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEhC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBjD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAI,GAAG,MAAM,EAAE;CA8B/D"}
1
+ {"version":3,"file":"graph-store.d.ts","sourceRoot":"","sources":["../src/graph-store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAgBrD,qBAAa,UAAU;IACT,OAAO,CAAC,KAAK;gBAAL,KAAK,EAAE,WAAW;IAEhC,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBjD,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,QAAQ,SAAI,GAAG,MAAM,EAAE;CA8B/D"}
@@ -11,7 +11,6 @@ function extractEntities(text) {
11
11
  entities.push(...compounds);
12
12
  return [...new Set(entities)];
13
13
  }
14
- const RELATED_RELATIONS = ['related_to', 'similar_to', 'same_category', 'same_scope'];
15
14
  export class GraphStore {
16
15
  store;
17
16
  constructor(store) {
@@ -28,9 +27,8 @@ export class GraphStore {
28
27
  for (const match of matches) {
29
28
  if (match.id === memoryId)
30
29
  continue;
31
- const relation = RELATED_RELATIONS[matches.indexOf(match) % RELATED_RELATIONS.length];
32
- this.store.addEdge(memoryId, match.id, relation, 0.7);
33
- this.store.addEdge(match.id, memoryId, relation, 0.7);
30
+ this.store.addEdge(memoryId, match.id, 'related_to', 0.7);
31
+ this.store.addEdge(match.id, memoryId, 'related_to', 0.7);
34
32
  }
35
33
  }
36
34
  catch { /* non-fatal */ }
@@ -1 +1 @@
1
- {"version":3,"file":"graph-store.js","sourceRoot":"","sources":["../src/graph-store.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph-store.js","sourceRoot":"","sources":["../src/graph-store.ts"],"names":[],"mappings":"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"}
@@ -8,16 +8,18 @@ export interface SearchOptions {
8
8
  }
9
9
  export interface SearchResultEntry {
10
10
  id: string;
11
- category: 'procedural' | 'semantic' | 'episodic' | 'failure_lesson';
11
+ type: string;
12
+ category: string;
13
+ title: string;
12
14
  content: string;
13
15
  originalText?: string;
14
- source: 'auto' | 'manual';
15
- status: 'pending' | 'approved' | 'rejected';
16
+ source: string;
17
+ status: string;
16
18
  confidence: number;
19
+ strength: number;
17
20
  scope: string;
18
21
  sessionId?: string;
19
22
  createdAt: number;
20
- approvedAt?: number;
21
23
  }
22
24
  export interface SearchResult {
23
25
  entry: SearchResultEntry;
@@ -28,6 +30,7 @@ export declare class HybridSearch {
28
30
  private embedder;
29
31
  private engine;
30
32
  constructor(store: MemoryStore, embedder: EmbeddingProvider, engine?: MemoryEngine);
33
+ private rerankWithLLM;
31
34
  search(query: string, options?: SearchOptions): Promise<SearchResult[]>;
32
35
  }
33
36
  //# sourceMappingURL=hybrid-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../src/hybrid-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,QAAQ,CAAC;IAC1B,MAAM,EAAE,SAAS,GAAG,UAAU,GAAG,UAAU,CAAC;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAqDD,qBAAa,YAAY;IAIrB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,MAAM,CAAsB;gBAG1B,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,iBAAiB,EACnC,MAAM,CAAC,EAAE,YAAY;IAKjB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CAmGlF"}
1
+ {"version":3,"file":"hybrid-search.d.ts","sourceRoot":"","sources":["../src/hybrid-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGvD,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;CACf;AAwDD,qBAAa,YAAY;IAIrB,OAAO,CAAC,KAAK;IACb,OAAO,CAAC,QAAQ;IAJlB,OAAO,CAAC,MAAM,CAAsB;gBAG1B,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,iBAAiB,EACnC,MAAM,CAAC,EAAE,YAAY;YAKT,aAAa;IA0CrB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;CA4HlF"}
@@ -1,4 +1,5 @@
1
- const DEFAULT_WEIGHTS = { bm25: 0.4, vector: 0.6, graph: 0.3 };
1
+ import { callLLM } from './llm-provider.js';
2
+ const DEFAULT_WEIGHTS = { bm25: 0.3, vector: 0.4, graph: 0.2, retention: 0.1 };
2
3
  const RRF_K = 60;
3
4
  function rrfFusion(results, k) {
4
5
  const scored = [];
@@ -22,18 +23,21 @@ function rrfFusion(results, k) {
22
23
  return scored;
23
24
  }
24
25
  function rowToEntry(row) {
26
+ const mappedStatus = row.status === 'active' ? 'approved' : row.status;
25
27
  return {
26
28
  id: row.id,
27
- category: row.category,
29
+ type: row.type,
30
+ category: row.type,
31
+ title: row.title,
28
32
  content: row.content,
29
33
  originalText: row.original_text ?? undefined,
30
34
  source: row.source,
31
- status: row.status,
35
+ status: mappedStatus,
32
36
  confidence: row.confidence,
37
+ strength: row.strength,
33
38
  scope: row.scope,
34
39
  sessionId: row.session_id ?? undefined,
35
40
  createdAt: row.created_at,
36
- approvedAt: row.approved_at ?? undefined,
37
41
  };
38
42
  }
39
43
  const MIN_EFFECTIVE_CONFIDENCE = 0.3;
@@ -46,6 +50,40 @@ export class HybridSearch {
46
50
  this.embedder = embedder;
47
51
  this.engine = engine ?? null;
48
52
  }
53
+ async rerankWithLLM(query, fused, docs) {
54
+ const candidates = fused.slice(0, Math.min(fused.length, 20));
55
+ if (candidates.length <= 1)
56
+ return fused;
57
+ const candidateList = candidates.map((c, i) => {
58
+ const doc = docs.get(c.id);
59
+ return `${i + 1}. [${c.id}] ${doc?.entry.title ?? 'Untitled'}\n ${(doc?.entry.content ?? '').slice(0, 200)}`;
60
+ }).join('\n\n');
61
+ const systemPrompt = 'You are a search relevance ranker. Return only the memory IDs in ranked order, one per line.';
62
+ const userMessage = `Query: "${query}"\n\nCandidates:\n${candidateList}\n\nRank these candidates by relevance to the query. Return only IDs, one per line:`;
63
+ try {
64
+ const response = await callLLM(systemPrompt, userMessage);
65
+ if (response.provider === 'rules')
66
+ return fused;
67
+ const llmRanked = new Map();
68
+ for (const line of response.content.split('\n')) {
69
+ const idMatch = line.match(/(mem:[a-zA-Z0-9:_-]+)/);
70
+ if (idMatch) {
71
+ llmRanked.set(idMatch[1], llmRanked.size);
72
+ }
73
+ }
74
+ if (llmRanked.size === 0)
75
+ return fused;
76
+ const rest = fused.slice(candidates.length);
77
+ const ranked = candidates
78
+ .filter(c => llmRanked.has(c.id))
79
+ .sort((a, b) => llmRanked.get(a.id) - llmRanked.get(b.id));
80
+ const unranked = candidates.filter(c => !llmRanked.has(c.id));
81
+ return [...ranked, ...unranked, ...rest];
82
+ }
83
+ catch {
84
+ return fused;
85
+ }
86
+ }
49
87
  async search(query, options = {}) {
50
88
  const limit = options.limit ?? 10;
51
89
  const fetchLimit = limit * 3;
@@ -64,7 +102,8 @@ export class HybridSearch {
64
102
  try {
65
103
  const simpleEntities = query.split(/\s+/).filter(w => w.length > 3);
66
104
  for (const entity of simpleEntities.slice(0, 5)) {
67
- const entityMatches = this.store.searchBM25(entity, 3);
105
+ const entityEmbedding = await this.embedder.embed(entity);
106
+ const entityMatches = this.store.searchVector(entityEmbedding, 3);
68
107
  for (const { id } of entityMatches) {
69
108
  if (!graphIds.has(id)) {
70
109
  graphIds.add(id);
@@ -101,9 +140,26 @@ export class HybridSearch {
101
140
  docs.get(id)?.ranks.set('graph', graphRank++);
102
141
  }
103
142
  }
143
+ // Retention signal (4th RRF channel, weight 0.1)
144
+ try {
145
+ const retentionRanked = [];
146
+ for (const [id] of docs) {
147
+ const retention = this.store.getRetentionScore(id);
148
+ if (retention) {
149
+ retentionRanked.push({ id, score: retention.score });
150
+ }
151
+ }
152
+ retentionRanked.sort((a, b) => b.score - a.score);
153
+ for (let i = 0; i < retentionRanked.length; i++) {
154
+ docs.get(retentionRanked[i].id)?.ranks.set('retention', i + 1);
155
+ }
156
+ }
157
+ catch { /* retention lookup failure is non-fatal */ }
104
158
  const fused = rrfFusion(docs, RRF_K);
159
+ // LLM rerank (only when LLM is available)
160
+ const ranked = await this.rerankWithLLM(query, fused, docs);
105
161
  const sessionCount = new Map();
106
- const diverse = new Set(fused.map(r => {
162
+ const diverse = new Set(ranked.map(r => {
107
163
  const doc = docs.get(r.id);
108
164
  const sid = doc?.entry.sessionId;
109
165
  if (sid) {
@@ -115,13 +171,13 @@ export class HybridSearch {
115
171
  return r.id;
116
172
  }).filter(Boolean));
117
173
  const results = [];
118
- for (const { id, score } of fused) {
174
+ for (const { id, score } of ranked) {
119
175
  if (!diverse.has(id))
120
176
  continue;
121
177
  const doc = docs.get(id);
122
178
  if (!doc)
123
179
  continue;
124
- if (options.categories?.length && !options.categories.includes(doc.entry.category))
180
+ if (options.categories?.length && !options.categories.includes(doc.entry.type))
125
181
  continue;
126
182
  if (options.scope && doc.entry.scope !== options.scope)
127
183
  continue;
@@ -140,6 +196,11 @@ export class HybridSearch {
140
196
  }
141
197
  }
142
198
  results.push({ entry: doc.entry, score: Math.round(score * 10000) / 10000 });
199
+ // Record access so confidence decay slows with use
200
+ try {
201
+ this.store.incrementAccess(doc.entry.id);
202
+ }
203
+ catch { /* non-critical */ }
143
204
  if (results.length >= limit)
144
205
  break;
145
206
  }