universal-agent-memory 0.6.2 → 0.7.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.
- package/dist/benchmarks/agents/naive-agent.d.ts +60 -0
- package/dist/benchmarks/agents/naive-agent.d.ts.map +1 -0
- package/dist/benchmarks/agents/naive-agent.js +144 -0
- package/dist/benchmarks/agents/naive-agent.js.map +1 -0
- package/dist/benchmarks/agents/uam-agent.d.ts +167 -0
- package/dist/benchmarks/agents/uam-agent.d.ts.map +1 -0
- package/dist/benchmarks/agents/uam-agent.js +386 -0
- package/dist/benchmarks/agents/uam-agent.js.map +1 -0
- package/dist/benchmarks/benchmark.d.ts +328 -0
- package/dist/benchmarks/benchmark.d.ts.map +1 -0
- package/dist/benchmarks/benchmark.js +104 -0
- package/dist/benchmarks/benchmark.js.map +1 -0
- package/dist/benchmarks/execution-verifier.d.ts +41 -0
- package/dist/benchmarks/execution-verifier.d.ts.map +1 -0
- package/dist/benchmarks/execution-verifier.js +342 -0
- package/dist/benchmarks/execution-verifier.js.map +1 -0
- package/dist/benchmarks/hierarchical-prompting.d.ts +37 -0
- package/dist/benchmarks/hierarchical-prompting.d.ts.map +1 -0
- package/dist/benchmarks/hierarchical-prompting.js +260 -0
- package/dist/benchmarks/hierarchical-prompting.js.map +1 -0
- package/dist/benchmarks/improved-benchmark.d.ts +88 -0
- package/dist/benchmarks/improved-benchmark.d.ts.map +1 -0
- package/dist/benchmarks/improved-benchmark.js +533 -0
- package/dist/benchmarks/improved-benchmark.js.map +1 -0
- package/dist/benchmarks/index.d.ts +10 -0
- package/dist/benchmarks/index.d.ts.map +1 -0
- package/dist/benchmarks/index.js +10 -0
- package/dist/benchmarks/index.js.map +1 -0
- package/dist/benchmarks/multi-turn-agent.d.ts +44 -0
- package/dist/benchmarks/multi-turn-agent.d.ts.map +1 -0
- package/dist/benchmarks/multi-turn-agent.js +235 -0
- package/dist/benchmarks/multi-turn-agent.js.map +1 -0
- package/dist/benchmarks/runner.d.ts +2 -0
- package/dist/benchmarks/runner.d.ts.map +1 -0
- package/dist/benchmarks/runner.js +2 -0
- package/dist/benchmarks/runner.js.map +1 -0
- package/dist/benchmarks/tasks.d.ts +19 -0
- package/dist/benchmarks/tasks.d.ts.map +1 -0
- package/dist/benchmarks/tasks.js +371 -0
- package/dist/benchmarks/tasks.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/backends/qdrant-cloud.d.ts +1 -1
- package/dist/memory/backends/qdrant-cloud.d.ts.map +1 -1
- package/dist/memory/backends/qdrant-cloud.js +6 -4
- package/dist/memory/backends/qdrant-cloud.js.map +1 -1
- package/dist/memory/context-compressor.d.ts +66 -0
- package/dist/memory/context-compressor.d.ts.map +1 -0
- package/dist/memory/context-compressor.js +250 -0
- package/dist/memory/context-compressor.js.map +1 -0
- package/dist/memory/dynamic-retrieval.d.ts +26 -0
- package/dist/memory/dynamic-retrieval.d.ts.map +1 -0
- package/dist/memory/dynamic-retrieval.js +378 -0
- package/dist/memory/dynamic-retrieval.js.map +1 -0
- package/dist/memory/embeddings.d.ts +93 -0
- package/dist/memory/embeddings.d.ts.map +1 -0
- package/dist/memory/embeddings.js +391 -0
- package/dist/memory/embeddings.js.map +1 -0
- package/dist/memory/hierarchical-memory.d.ts +116 -0
- package/dist/memory/hierarchical-memory.d.ts.map +1 -0
- package/dist/memory/hierarchical-memory.js +299 -0
- package/dist/memory/hierarchical-memory.js.map +1 -0
- package/dist/memory/memory-consolidator.d.ts +88 -0
- package/dist/memory/memory-consolidator.d.ts.map +1 -0
- package/dist/memory/memory-consolidator.js +348 -0
- package/dist/memory/memory-consolidator.js.map +1 -0
- package/dist/memory/speculative-cache.d.ts +89 -0
- package/dist/memory/speculative-cache.d.ts.map +1 -0
- package/dist/memory/speculative-cache.js +259 -0
- package/dist/memory/speculative-cache.js.map +1 -0
- package/dist/memory/task-classifier.d.ts +33 -0
- package/dist/memory/task-classifier.d.ts.map +1 -0
- package/dist/memory/task-classifier.js +277 -0
- package/dist/memory/task-classifier.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +62 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +150 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/validate-json.d.ts +52 -0
- package/dist/utils/validate-json.d.ts.map +1 -0
- package/dist/utils/validate-json.js +99 -0
- package/dist/utils/validate-json.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context Compression Module for UAM
|
|
3
|
+
*
|
|
4
|
+
* Implements semantic compression to reduce token usage while preserving meaning.
|
|
5
|
+
* Based on Acon (Agent Context Optimization) and AgentCompress research.
|
|
6
|
+
*/
|
|
7
|
+
const DEFAULT_CONFIG = {
|
|
8
|
+
maxTokens: 2000,
|
|
9
|
+
minSemanticPreservation: 0.85,
|
|
10
|
+
compressionLevel: 'medium',
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Estimate token count (rough approximation: ~4 chars per token)
|
|
14
|
+
*/
|
|
15
|
+
export function estimateTokens(text) {
|
|
16
|
+
return Math.ceil(text.length / 4);
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Compress a single memory entry
|
|
20
|
+
*/
|
|
21
|
+
export function compressMemoryEntry(content, config = {}) {
|
|
22
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
23
|
+
const originalTokens = estimateTokens(content);
|
|
24
|
+
if (originalTokens <= cfg.maxTokens / 4) {
|
|
25
|
+
return {
|
|
26
|
+
original: content,
|
|
27
|
+
compressed: content,
|
|
28
|
+
originalTokens,
|
|
29
|
+
compressedTokens: originalTokens,
|
|
30
|
+
tokenReduction: 0,
|
|
31
|
+
preservedSemantics: 1.0,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
let compressed = content;
|
|
35
|
+
// Level 1: Remove redundant whitespace and formatting
|
|
36
|
+
compressed = compressed.replace(/\s+/g, ' ').trim();
|
|
37
|
+
compressed = compressed.replace(/\n{3,}/g, '\n\n');
|
|
38
|
+
// Level 2: Remove common filler phrases
|
|
39
|
+
if (cfg.compressionLevel !== 'light') {
|
|
40
|
+
const fillerPatterns = [
|
|
41
|
+
/\b(basically|essentially|actually|really|very|quite|somewhat|rather)\b/gi,
|
|
42
|
+
/\b(in order to)\b/gi,
|
|
43
|
+
/\b(it is worth noting that|it should be noted that)\b/gi,
|
|
44
|
+
/\b(as a matter of fact|in fact)\b/gi,
|
|
45
|
+
/\b(at the end of the day)\b/gi,
|
|
46
|
+
/\b(the fact that)\b/gi,
|
|
47
|
+
/\b(in this case|in that case)\b/gi,
|
|
48
|
+
];
|
|
49
|
+
for (const pattern of fillerPatterns) {
|
|
50
|
+
compressed = compressed.replace(pattern, '');
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// Level 3: Aggressive - truncate to key sentences
|
|
54
|
+
if (cfg.compressionLevel === 'aggressive') {
|
|
55
|
+
const sentences = compressed.split(/(?<=[.!?])\s+/);
|
|
56
|
+
const maxSentences = Math.max(3, Math.ceil(sentences.length * 0.4));
|
|
57
|
+
// Keep first sentence (context), middle sentences (key info), last sentence (conclusion)
|
|
58
|
+
if (sentences.length > maxSentences) {
|
|
59
|
+
const first = sentences.slice(0, 1);
|
|
60
|
+
const middle = sentences.slice(1, -1).slice(0, maxSentences - 2);
|
|
61
|
+
const last = sentences.slice(-1);
|
|
62
|
+
compressed = [...first, ...middle, ...last].join(' ');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// Clean up artifacts
|
|
66
|
+
compressed = compressed.replace(/\s{2,}/g, ' ').trim();
|
|
67
|
+
const compressedTokens = estimateTokens(compressed);
|
|
68
|
+
const tokenReduction = 1 - (compressedTokens / originalTokens);
|
|
69
|
+
// Estimate semantic preservation (based on compression ratio - rough heuristic)
|
|
70
|
+
const preservedSemantics = Math.max(0.7, 1 - (tokenReduction * 0.3));
|
|
71
|
+
return {
|
|
72
|
+
original: content,
|
|
73
|
+
compressed,
|
|
74
|
+
originalTokens,
|
|
75
|
+
compressedTokens,
|
|
76
|
+
tokenReduction,
|
|
77
|
+
preservedSemantics,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Compress multiple memories into a consolidated context
|
|
82
|
+
*/
|
|
83
|
+
export function compressMemoryBatch(memories, config = {}) {
|
|
84
|
+
const cfg = { ...DEFAULT_CONFIG, ...config };
|
|
85
|
+
// Sort by importance (descending)
|
|
86
|
+
const sorted = [...memories].sort((a, b) => (b.importance || 5) - (a.importance || 5));
|
|
87
|
+
// Group by type for structured output
|
|
88
|
+
const grouped = {};
|
|
89
|
+
for (const mem of sorted) {
|
|
90
|
+
const type = mem.type || 'general';
|
|
91
|
+
if (!grouped[type])
|
|
92
|
+
grouped[type] = [];
|
|
93
|
+
grouped[type].push(mem.content);
|
|
94
|
+
}
|
|
95
|
+
// Build consolidated context
|
|
96
|
+
const sections = [];
|
|
97
|
+
const typeOrder = ['goal', 'action', 'observation', 'thought'];
|
|
98
|
+
for (const type of typeOrder) {
|
|
99
|
+
if (grouped[type] && grouped[type].length > 0) {
|
|
100
|
+
const compressed = grouped[type].map(c => compressMemoryEntry(c, cfg).compressed);
|
|
101
|
+
sections.push(`[${type.toUpperCase()}]\n${compressed.join('\n')}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
// Add remaining types
|
|
105
|
+
for (const type of Object.keys(grouped)) {
|
|
106
|
+
if (!typeOrder.includes(type)) {
|
|
107
|
+
const compressed = grouped[type].map(c => compressMemoryEntry(c, cfg).compressed);
|
|
108
|
+
sections.push(`[${type.toUpperCase()}]\n${compressed.join('\n')}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const original = memories.map(m => m.content).join('\n');
|
|
112
|
+
const compressed = sections.join('\n\n');
|
|
113
|
+
const originalTokens = estimateTokens(original);
|
|
114
|
+
const compressedTokens = estimateTokens(compressed);
|
|
115
|
+
return {
|
|
116
|
+
original,
|
|
117
|
+
compressed,
|
|
118
|
+
originalTokens,
|
|
119
|
+
compressedTokens,
|
|
120
|
+
tokenReduction: 1 - (compressedTokens / originalTokens),
|
|
121
|
+
preservedSemantics: 0.9, // Batch compression preserves structure
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Summarize old memories into a single compressed entry
|
|
126
|
+
*/
|
|
127
|
+
export function summarizeMemories(memories, maxOutputTokens = 500) {
|
|
128
|
+
if (memories.length === 0)
|
|
129
|
+
return '';
|
|
130
|
+
// Group by type
|
|
131
|
+
const byType = {};
|
|
132
|
+
for (const mem of memories) {
|
|
133
|
+
if (!byType[mem.type])
|
|
134
|
+
byType[mem.type] = [];
|
|
135
|
+
byType[mem.type].push(mem.content);
|
|
136
|
+
}
|
|
137
|
+
// Create summary sections
|
|
138
|
+
const summaryParts = [];
|
|
139
|
+
for (const [type, contents] of Object.entries(byType)) {
|
|
140
|
+
// Deduplicate similar content
|
|
141
|
+
const unique = deduplicateContent(contents);
|
|
142
|
+
// Compress each unique entry
|
|
143
|
+
const compressed = unique.map(c => {
|
|
144
|
+
const result = compressMemoryEntry(c, { compressionLevel: 'aggressive' });
|
|
145
|
+
return result.compressed;
|
|
146
|
+
});
|
|
147
|
+
// Limit to most important entries
|
|
148
|
+
const maxPerType = Math.max(2, Math.floor(maxOutputTokens / (Object.keys(byType).length * 50)));
|
|
149
|
+
const limited = compressed.slice(0, maxPerType);
|
|
150
|
+
if (limited.length > 0) {
|
|
151
|
+
summaryParts.push(`${type}: ${limited.join('; ')}`);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const dateRange = getDateRange(memories.map(m => m.timestamp));
|
|
155
|
+
const header = `[Summary ${dateRange}]`;
|
|
156
|
+
return `${header}\n${summaryParts.join('\n')}`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Deduplicate content using simple similarity check
|
|
160
|
+
*/
|
|
161
|
+
function deduplicateContent(contents, threshold = 0.8) {
|
|
162
|
+
const unique = [];
|
|
163
|
+
for (const content of contents) {
|
|
164
|
+
const normalizedNew = content.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
165
|
+
let isDuplicate = false;
|
|
166
|
+
for (const existing of unique) {
|
|
167
|
+
const normalizedExisting = existing.toLowerCase().replace(/\s+/g, ' ').trim();
|
|
168
|
+
const similarity = jaccardSimilarity(normalizedNew, normalizedExisting);
|
|
169
|
+
if (similarity > threshold) {
|
|
170
|
+
isDuplicate = true;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (!isDuplicate) {
|
|
175
|
+
unique.push(content);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return unique;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Calculate Jaccard similarity between two strings
|
|
182
|
+
*/
|
|
183
|
+
function jaccardSimilarity(a, b) {
|
|
184
|
+
const setA = new Set(a.split(/\s+/));
|
|
185
|
+
const setB = new Set(b.split(/\s+/));
|
|
186
|
+
const intersection = new Set([...setA].filter(x => setB.has(x)));
|
|
187
|
+
const union = new Set([...setA, ...setB]);
|
|
188
|
+
return intersection.size / union.size;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get date range string
|
|
192
|
+
*/
|
|
193
|
+
function getDateRange(timestamps) {
|
|
194
|
+
if (timestamps.length === 0)
|
|
195
|
+
return 'unknown';
|
|
196
|
+
const dates = timestamps.map(t => new Date(t)).filter(d => !isNaN(d.getTime()));
|
|
197
|
+
if (dates.length === 0)
|
|
198
|
+
return 'unknown';
|
|
199
|
+
const min = new Date(Math.min(...dates.map(d => d.getTime())));
|
|
200
|
+
const max = new Date(Math.max(...dates.map(d => d.getTime())));
|
|
201
|
+
const formatDate = (d) => d.toISOString().split('T')[0];
|
|
202
|
+
if (formatDate(min) === formatDate(max)) {
|
|
203
|
+
return formatDate(min);
|
|
204
|
+
}
|
|
205
|
+
return `${formatDate(min)} to ${formatDate(max)}`;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Context budget manager
|
|
209
|
+
*/
|
|
210
|
+
export class ContextBudget {
|
|
211
|
+
maxTokens;
|
|
212
|
+
usedTokens = 0;
|
|
213
|
+
sections = new Map();
|
|
214
|
+
constructor(maxTokens = 12000) {
|
|
215
|
+
this.maxTokens = maxTokens;
|
|
216
|
+
}
|
|
217
|
+
allocate(section, content) {
|
|
218
|
+
const tokens = estimateTokens(content);
|
|
219
|
+
const available = this.maxTokens - this.usedTokens;
|
|
220
|
+
if (tokens <= available) {
|
|
221
|
+
this.usedTokens += tokens;
|
|
222
|
+
this.sections.set(section, tokens);
|
|
223
|
+
return { content, tokens, truncated: false };
|
|
224
|
+
}
|
|
225
|
+
// Need to truncate
|
|
226
|
+
const targetTokens = Math.floor(available * 0.9);
|
|
227
|
+
const targetChars = targetTokens * 4;
|
|
228
|
+
const truncated = content.slice(0, targetChars) + '... [truncated]';
|
|
229
|
+
const actualTokens = estimateTokens(truncated);
|
|
230
|
+
this.usedTokens += actualTokens;
|
|
231
|
+
this.sections.set(section, actualTokens);
|
|
232
|
+
return { content: truncated, tokens: actualTokens, truncated: true };
|
|
233
|
+
}
|
|
234
|
+
remaining() {
|
|
235
|
+
return this.maxTokens - this.usedTokens;
|
|
236
|
+
}
|
|
237
|
+
usage() {
|
|
238
|
+
return {
|
|
239
|
+
total: this.maxTokens,
|
|
240
|
+
used: this.usedTokens,
|
|
241
|
+
remaining: this.remaining(),
|
|
242
|
+
sections: Object.fromEntries(this.sections),
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
reset() {
|
|
246
|
+
this.usedTokens = 0;
|
|
247
|
+
this.sections.clear();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=context-compressor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-compressor.js","sourceRoot":"","sources":["../../src/memory/context-compressor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Memory Retrieval System for UAM
|
|
3
|
+
*
|
|
4
|
+
* Retrieves relevant memories based on task content, not static context.
|
|
5
|
+
* Implements semantic search with fallback to keyword matching.
|
|
6
|
+
*/
|
|
7
|
+
import { type TaskClassification } from './task-classifier.js';
|
|
8
|
+
export interface RetrievedMemory {
|
|
9
|
+
content: string;
|
|
10
|
+
type: 'lesson' | 'gotcha' | 'pattern' | 'context' | 'example';
|
|
11
|
+
relevance: number;
|
|
12
|
+
source: string;
|
|
13
|
+
}
|
|
14
|
+
export interface DynamicMemoryContext {
|
|
15
|
+
classification: TaskClassification;
|
|
16
|
+
relevantMemories: RetrievedMemory[];
|
|
17
|
+
patterns: string[];
|
|
18
|
+
gotchas: string[];
|
|
19
|
+
projectContext: string;
|
|
20
|
+
formattedContext: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Main function to retrieve task-specific memory context
|
|
24
|
+
*/
|
|
25
|
+
export declare function retrieveDynamicMemoryContext(taskInstruction: string, projectRoot?: string): Promise<DynamicMemoryContext>;
|
|
26
|
+
//# sourceMappingURL=dynamic-retrieval.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-retrieval.d.ts","sourceRoot":"","sources":["../../src/memory/dynamic-retrieval.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAgE,KAAK,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE7H,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,kBAAkB,CAAC;IACnC,gBAAgB,EAAE,eAAe,EAAE,CAAC;IACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAsB,4BAA4B,CAChD,eAAe,EAAE,MAAM,EACvB,WAAW,GAAE,MAAsB,GAClC,OAAO,CAAC,oBAAoB,CAAC,CAgD/B"}
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamic Memory Retrieval System for UAM
|
|
3
|
+
*
|
|
4
|
+
* Retrieves relevant memories based on task content, not static context.
|
|
5
|
+
* Implements semantic search with fallback to keyword matching.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync, readFileSync } from 'fs';
|
|
8
|
+
import { join } from 'path';
|
|
9
|
+
import { execSync } from 'child_process';
|
|
10
|
+
import { classifyTask, extractTaskEntities, getSuggestedMemoryQueries } from './task-classifier.js';
|
|
11
|
+
/**
|
|
12
|
+
* Main function to retrieve task-specific memory context
|
|
13
|
+
*/
|
|
14
|
+
export async function retrieveDynamicMemoryContext(taskInstruction, projectRoot = process.cwd()) {
|
|
15
|
+
// Step 1: Classify the task
|
|
16
|
+
const classification = classifyTask(taskInstruction);
|
|
17
|
+
// Step 2: Extract entities from task
|
|
18
|
+
const entities = extractTaskEntities(taskInstruction);
|
|
19
|
+
// Step 3: Get suggested memory queries
|
|
20
|
+
const suggestedQueries = getSuggestedMemoryQueries(classification);
|
|
21
|
+
// Step 4: Query all memory sources
|
|
22
|
+
const memories = await queryAllMemorySources(taskInstruction, classification, entities, suggestedQueries, projectRoot);
|
|
23
|
+
// Step 5: Extract patterns and gotchas
|
|
24
|
+
const patterns = memories
|
|
25
|
+
.filter(m => m.type === 'pattern')
|
|
26
|
+
.map(m => m.content);
|
|
27
|
+
const gotchas = memories
|
|
28
|
+
.filter(m => m.type === 'gotcha')
|
|
29
|
+
.map(m => m.content);
|
|
30
|
+
// Step 6: Get project-specific context
|
|
31
|
+
const projectContext = await getProjectContext(classification, projectRoot);
|
|
32
|
+
// Step 7: Format the context with recency bias (critical at END)
|
|
33
|
+
const formattedContext = formatContextWithRecencyBias(classification, memories, patterns, gotchas, projectContext);
|
|
34
|
+
return {
|
|
35
|
+
classification,
|
|
36
|
+
relevantMemories: memories,
|
|
37
|
+
patterns,
|
|
38
|
+
gotchas,
|
|
39
|
+
projectContext,
|
|
40
|
+
formattedContext,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Query all memory sources for relevant information
|
|
45
|
+
*/
|
|
46
|
+
async function queryAllMemorySources(taskInstruction, classification, entities, suggestedQueries, projectRoot) {
|
|
47
|
+
const memories = [];
|
|
48
|
+
// Source 1: Short-term SQLite memory
|
|
49
|
+
const shortTermMemories = await queryShortTermMemory(classification, entities, projectRoot);
|
|
50
|
+
memories.push(...shortTermMemories);
|
|
51
|
+
// Source 2: Session memories (recent decisions)
|
|
52
|
+
const sessionMemories = await querySessionMemory(taskInstruction, projectRoot);
|
|
53
|
+
memories.push(...sessionMemories);
|
|
54
|
+
// Source 3: Long-term prepopulated memory
|
|
55
|
+
const longTermMemories = await queryLongTermMemory(suggestedQueries, projectRoot);
|
|
56
|
+
memories.push(...longTermMemories);
|
|
57
|
+
// Source 4: CLAUDE.md sections relevant to task
|
|
58
|
+
const claudeMdMemories = await queryCLAUDEMd(classification, projectRoot);
|
|
59
|
+
memories.push(...claudeMdMemories);
|
|
60
|
+
// Source 5: Category-specific patterns from droids
|
|
61
|
+
const droidPatterns = getCategoryPatterns(classification);
|
|
62
|
+
memories.push(...droidPatterns);
|
|
63
|
+
// Deduplicate and sort by relevance
|
|
64
|
+
const uniqueMemories = deduplicateMemories(memories);
|
|
65
|
+
return uniqueMemories.sort((a, b) => b.relevance - a.relevance).slice(0, 15);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Query short-term SQLite memory
|
|
69
|
+
*/
|
|
70
|
+
async function queryShortTermMemory(classification, entities, projectRoot) {
|
|
71
|
+
const dbPath = join(projectRoot, 'agents/data/memory/short_term.db');
|
|
72
|
+
if (!existsSync(dbPath))
|
|
73
|
+
return [];
|
|
74
|
+
const memories = [];
|
|
75
|
+
try {
|
|
76
|
+
// Query by category keywords
|
|
77
|
+
for (const keyword of classification.keywords.slice(0, 3)) {
|
|
78
|
+
const result = execSync(`sqlite3 "${dbPath}" "SELECT type, content FROM memories WHERE content LIKE '%${keyword}%' ORDER BY id DESC LIMIT 3;"`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
79
|
+
if (result) {
|
|
80
|
+
for (const line of result.split('\n')) {
|
|
81
|
+
const [type, content] = line.split('|');
|
|
82
|
+
if (content) {
|
|
83
|
+
memories.push({
|
|
84
|
+
content: content.slice(0, 500),
|
|
85
|
+
type: type === 'lesson' ? 'lesson' : 'context',
|
|
86
|
+
relevance: 0.7,
|
|
87
|
+
source: 'short-term-memory',
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Query by technology mentions
|
|
94
|
+
for (const tech of entities.technologies.slice(0, 2)) {
|
|
95
|
+
const result = execSync(`sqlite3 "${dbPath}" "SELECT type, content FROM memories WHERE content LIKE '%${tech}%' ORDER BY id DESC LIMIT 2;"`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
96
|
+
if (result) {
|
|
97
|
+
for (const line of result.split('\n')) {
|
|
98
|
+
const [type, content] = line.split('|');
|
|
99
|
+
if (content) {
|
|
100
|
+
memories.push({
|
|
101
|
+
content: content.slice(0, 500),
|
|
102
|
+
type: type === 'gotcha' ? 'gotcha' : 'context',
|
|
103
|
+
relevance: 0.6,
|
|
104
|
+
source: 'short-term-memory',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Ignore query errors
|
|
113
|
+
}
|
|
114
|
+
return memories;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Query session memories for recent decisions
|
|
118
|
+
*/
|
|
119
|
+
async function querySessionMemory(_taskInstruction, projectRoot) {
|
|
120
|
+
const dbPath = join(projectRoot, 'agents/data/memory/short_term.db');
|
|
121
|
+
if (!existsSync(dbPath))
|
|
122
|
+
return [];
|
|
123
|
+
const memories = [];
|
|
124
|
+
try {
|
|
125
|
+
// Get recent high-importance session memories
|
|
126
|
+
const result = execSync(`sqlite3 "${dbPath}" "SELECT type, content FROM session_memories WHERE importance >= 7 ORDER BY id DESC LIMIT 5;"`, { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
127
|
+
if (result) {
|
|
128
|
+
for (const line of result.split('\n')) {
|
|
129
|
+
const [type, content] = line.split('|');
|
|
130
|
+
if (content) {
|
|
131
|
+
memories.push({
|
|
132
|
+
content: content.slice(0, 500),
|
|
133
|
+
type: type === 'lesson' ? 'lesson' : type === 'decision' ? 'context' : 'pattern',
|
|
134
|
+
relevance: 0.8,
|
|
135
|
+
source: 'session-memory',
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// Ignore query errors
|
|
143
|
+
}
|
|
144
|
+
return memories;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Query long-term prepopulated memory
|
|
148
|
+
*/
|
|
149
|
+
async function queryLongTermMemory(queries, projectRoot) {
|
|
150
|
+
const memoryPath = join(projectRoot, 'agents/data/memory/long_term_prepopulated.json');
|
|
151
|
+
if (!existsSync(memoryPath))
|
|
152
|
+
return [];
|
|
153
|
+
const memories = [];
|
|
154
|
+
try {
|
|
155
|
+
const data = JSON.parse(readFileSync(memoryPath, 'utf-8'));
|
|
156
|
+
const allMemories = data.memories || data.lessons || data || [];
|
|
157
|
+
// Simple keyword matching for now (semantic search would be better)
|
|
158
|
+
for (const query of queries.slice(0, 5)) {
|
|
159
|
+
const queryLower = query.toLowerCase();
|
|
160
|
+
const queryWords = queryLower.split(/\s+/);
|
|
161
|
+
for (const mem of allMemories) {
|
|
162
|
+
const content = (mem.content || mem.text || JSON.stringify(mem)).toLowerCase();
|
|
163
|
+
const matchCount = queryWords.filter(w => content.includes(w)).length;
|
|
164
|
+
if (matchCount >= 2) {
|
|
165
|
+
memories.push({
|
|
166
|
+
content: (mem.content || mem.text || JSON.stringify(mem)).slice(0, 500),
|
|
167
|
+
type: mem.type || 'lesson',
|
|
168
|
+
relevance: matchCount / queryWords.length,
|
|
169
|
+
source: 'long-term-memory',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Ignore parse errors
|
|
177
|
+
}
|
|
178
|
+
return memories;
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Query CLAUDE.md for relevant sections
|
|
182
|
+
*/
|
|
183
|
+
async function queryCLAUDEMd(classification, projectRoot) {
|
|
184
|
+
const claudeMdPath = join(projectRoot, 'CLAUDE.md');
|
|
185
|
+
if (!existsSync(claudeMdPath))
|
|
186
|
+
return [];
|
|
187
|
+
const memories = [];
|
|
188
|
+
try {
|
|
189
|
+
const content = readFileSync(claudeMdPath, 'utf-8');
|
|
190
|
+
// Extract Code Field section (always relevant)
|
|
191
|
+
const codeFieldMatch = content.match(/## .*CODE FIELD.*?(?=\n## |\n---\n|$)/s);
|
|
192
|
+
if (codeFieldMatch) {
|
|
193
|
+
memories.push({
|
|
194
|
+
content: codeFieldMatch[0].slice(0, 800),
|
|
195
|
+
type: 'pattern',
|
|
196
|
+
relevance: 0.9,
|
|
197
|
+
source: 'CLAUDE.md',
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
// Extract category-specific sections
|
|
201
|
+
const categorySectionMap = {
|
|
202
|
+
'sysadmin': [/## .*System|Admin|Linux|Network.*?(?=\n## |\n---\n|$)/si],
|
|
203
|
+
'security': [/## .*Security|Auth.*?(?=\n## |\n---\n|$)/si],
|
|
204
|
+
'testing': [/## .*Test.*?(?=\n## |\n---\n|$)/si],
|
|
205
|
+
'coding': [/## .*Coding|Convention|Pattern.*?(?=\n## |\n---\n|$)/si],
|
|
206
|
+
};
|
|
207
|
+
const patterns = categorySectionMap[classification.category] || [];
|
|
208
|
+
for (const pattern of patterns) {
|
|
209
|
+
const match = content.match(pattern);
|
|
210
|
+
if (match) {
|
|
211
|
+
memories.push({
|
|
212
|
+
content: match[0].slice(0, 600),
|
|
213
|
+
type: 'context',
|
|
214
|
+
relevance: 0.75,
|
|
215
|
+
source: 'CLAUDE.md',
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
// Extract gotchas/troubleshooting sections
|
|
220
|
+
const gotchasMatch = content.match(/## .*Troubleshoot|Gotcha|Common.*?(?=\n## |\n---\n|$)/si);
|
|
221
|
+
if (gotchasMatch) {
|
|
222
|
+
memories.push({
|
|
223
|
+
content: gotchasMatch[0].slice(0, 500),
|
|
224
|
+
type: 'gotcha',
|
|
225
|
+
relevance: 0.7,
|
|
226
|
+
source: 'CLAUDE.md',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch {
|
|
231
|
+
// Ignore read errors
|
|
232
|
+
}
|
|
233
|
+
return memories;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Get category-specific patterns from droid knowledge
|
|
237
|
+
*/
|
|
238
|
+
function getCategoryPatterns(classification) {
|
|
239
|
+
const patterns = [];
|
|
240
|
+
const categoryPatterns = {
|
|
241
|
+
'sysadmin': [
|
|
242
|
+
'Use `ip addr` instead of deprecated `ifconfig` for network info',
|
|
243
|
+
'Use `ss -tlnp` instead of `netstat` for listening ports',
|
|
244
|
+
'Always check `journalctl -u <service>` for service logs',
|
|
245
|
+
'Use `make -j$(nproc)` for parallel kernel compilation',
|
|
246
|
+
],
|
|
247
|
+
'security': [
|
|
248
|
+
'Never log sensitive data (passwords, tokens, keys)',
|
|
249
|
+
'Use parameterized queries to prevent SQL injection',
|
|
250
|
+
'Validate and sanitize all user input',
|
|
251
|
+
'Check for CVE exploits before attempting complex attacks',
|
|
252
|
+
],
|
|
253
|
+
'ml-training': [
|
|
254
|
+
'Start with smaller models (distilbert vs bert-large) for speed',
|
|
255
|
+
'Use `CUDA_VISIBLE_DEVICES` to select specific GPUs',
|
|
256
|
+
'Cache datasets to avoid repeated downloads',
|
|
257
|
+
'Set `num_train_epochs=3` initially, increase if needed',
|
|
258
|
+
],
|
|
259
|
+
'debugging': [
|
|
260
|
+
'Use `pip check` to detect dependency conflicts',
|
|
261
|
+
'Use `git reflog` to recover lost commits',
|
|
262
|
+
'Check `conda env export` before modifying environments',
|
|
263
|
+
'Add verbose flags (-v, --debug) to diagnose issues',
|
|
264
|
+
],
|
|
265
|
+
'coding': [
|
|
266
|
+
'State assumptions before writing code',
|
|
267
|
+
'Handle edge cases explicitly (empty arrays, null values)',
|
|
268
|
+
'Use TypeScript strict mode for better type safety',
|
|
269
|
+
'Include try-catch for operations that can fail',
|
|
270
|
+
],
|
|
271
|
+
'testing': [
|
|
272
|
+
'Test edge cases: empty input, null, undefined',
|
|
273
|
+
'Use mocks for external dependencies',
|
|
274
|
+
'Aim for high coverage on critical paths',
|
|
275
|
+
'Run tests before committing: `npm test`',
|
|
276
|
+
],
|
|
277
|
+
};
|
|
278
|
+
const relevantPatterns = categoryPatterns[classification.category] || [];
|
|
279
|
+
for (const pattern of relevantPatterns) {
|
|
280
|
+
patterns.push({
|
|
281
|
+
content: pattern,
|
|
282
|
+
type: 'pattern',
|
|
283
|
+
relevance: 0.85,
|
|
284
|
+
source: 'droid-knowledge',
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
// Add common gotchas
|
|
288
|
+
const commonGotchas = [
|
|
289
|
+
'Array index: use `i < length`, not `i <= length`',
|
|
290
|
+
'JSON.parse throws on invalid input - wrap in try/catch',
|
|
291
|
+
'Empty array reduce needs initial value',
|
|
292
|
+
'Map.get() returns undefined for missing keys',
|
|
293
|
+
];
|
|
294
|
+
for (const gotcha of commonGotchas.slice(0, 2)) {
|
|
295
|
+
patterns.push({
|
|
296
|
+
content: gotcha,
|
|
297
|
+
type: 'gotcha',
|
|
298
|
+
relevance: 0.8,
|
|
299
|
+
source: 'droid-knowledge',
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return patterns;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Get project-specific context
|
|
306
|
+
*/
|
|
307
|
+
async function getProjectContext(classification, projectRoot) {
|
|
308
|
+
const sections = [];
|
|
309
|
+
// Add project structure if relevant
|
|
310
|
+
if (['coding', 'testing', 'debugging'].includes(classification.category)) {
|
|
311
|
+
try {
|
|
312
|
+
const pkgJsonPath = join(projectRoot, 'package.json');
|
|
313
|
+
if (existsSync(pkgJsonPath)) {
|
|
314
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'));
|
|
315
|
+
sections.push(`Project: ${pkg.name} v${pkg.version}`);
|
|
316
|
+
if (pkg.scripts) {
|
|
317
|
+
const scripts = Object.keys(pkg.scripts).slice(0, 5).join(', ');
|
|
318
|
+
sections.push(`Available scripts: ${scripts}`);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
// Ignore
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return sections.join('\n');
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Format context with recency bias (critical info at END)
|
|
330
|
+
* Based on Droid's hierarchical prompting strategy
|
|
331
|
+
*/
|
|
332
|
+
function formatContextWithRecencyBias(classification, memories, patterns, gotchas, projectContext) {
|
|
333
|
+
const sections = [];
|
|
334
|
+
// Section 1: Project context (less critical, at start)
|
|
335
|
+
if (projectContext) {
|
|
336
|
+
sections.push('## Project Context\n' + projectContext);
|
|
337
|
+
}
|
|
338
|
+
// Section 2: General patterns (medium priority)
|
|
339
|
+
if (patterns.length > 0) {
|
|
340
|
+
sections.push('## Relevant Patterns\n' + patterns.slice(0, 5).map(p => `- ${p}`).join('\n'));
|
|
341
|
+
}
|
|
342
|
+
// Section 3: Retrieved memories
|
|
343
|
+
const lessons = memories.filter(m => m.type === 'lesson').slice(0, 3);
|
|
344
|
+
if (lessons.length > 0) {
|
|
345
|
+
sections.push('## Lessons from Memory\n' + lessons.map(m => `- ${m.content}`).join('\n'));
|
|
346
|
+
}
|
|
347
|
+
// Section 4: Task classification info
|
|
348
|
+
sections.push(`## Task Classification
|
|
349
|
+
- Category: ${classification.category}
|
|
350
|
+
- Suggested approach: Use ${classification.suggestedDroid} patterns
|
|
351
|
+
- Key focus: ${classification.keywords.slice(0, 3).join(', ')}`);
|
|
352
|
+
// Section 5: CRITICAL - Gotchas at END (recency bias)
|
|
353
|
+
if (gotchas.length > 0) {
|
|
354
|
+
sections.push('## ⚠️ CRITICAL: Avoid These Mistakes\n' + gotchas.slice(0, 4).map(g => `- ${g}`).join('\n'));
|
|
355
|
+
}
|
|
356
|
+
// Section 6: Final reminders (most recent = highest attention)
|
|
357
|
+
sections.push(`## Final Reminders
|
|
358
|
+
- State assumptions before coding
|
|
359
|
+
- Handle edge cases explicitly
|
|
360
|
+
- Verify solution before reporting success`);
|
|
361
|
+
return sections.join('\n\n') + '\n\n---\n\n';
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Deduplicate memories by content similarity
|
|
365
|
+
*/
|
|
366
|
+
function deduplicateMemories(memories) {
|
|
367
|
+
const seen = new Set();
|
|
368
|
+
const unique = [];
|
|
369
|
+
for (const mem of memories) {
|
|
370
|
+
const key = mem.content.slice(0, 100).toLowerCase().replace(/\s+/g, ' ');
|
|
371
|
+
if (!seen.has(key)) {
|
|
372
|
+
seen.add(key);
|
|
373
|
+
unique.push(mem);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
return unique;
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=dynamic-retrieval.js.map
|