@sparkleideas/agentdb-onnx 1.0.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.
- package/ARCHITECTURE.md +331 -0
- package/IMPLEMENTATION-SUMMARY.md +456 -0
- package/README.md +418 -0
- package/examples/complete-workflow.ts +281 -0
- package/package.json +41 -0
- package/src/benchmarks/benchmark-runner.ts +301 -0
- package/src/cli.ts +245 -0
- package/src/index.ts +128 -0
- package/src/services/ONNXEmbeddingService.ts +459 -0
- package/src/tests/integration.test.ts +302 -0
- package/src/tests/onnx-embedding.test.ts +317 -0
- package/tsconfig.json +19 -0
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sparkleideas/agentdb-onnx",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "AgentDB with optimized ONNX embeddings - 100% local, GPU-accelerated AI agent memory",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"dev": "tsx src/cli.ts",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest",
|
|
13
|
+
"benchmark": "tsx src/benchmarks/benchmark-runner.ts",
|
|
14
|
+
"example": "tsx examples/complete-workflow.ts"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"agentdb",
|
|
18
|
+
"onnx",
|
|
19
|
+
"embeddings",
|
|
20
|
+
"vector-database",
|
|
21
|
+
"ai-agents",
|
|
22
|
+
"local-inference",
|
|
23
|
+
"gpu-acceleration"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"onnxruntime-node": "^1.20.1",
|
|
27
|
+
"@xenova/transformers": "^2.17.2",
|
|
28
|
+
"commander": "^12.1.0",
|
|
29
|
+
"chalk": "^5.3.0",
|
|
30
|
+
"@sparkleideas/agentdb": "*"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.10.2",
|
|
34
|
+
"tsx": "^4.19.2",
|
|
35
|
+
"typescript": "^5.7.2",
|
|
36
|
+
"vitest": "^2.1.8"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
/**
|
|
3
|
+
* Comprehensive Performance Benchmarks for AgentDB + ONNX
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { createONNXAgentDB } from '../index.js';
|
|
7
|
+
import { unlink } from 'fs/promises';
|
|
8
|
+
import chalk from 'chalk';
|
|
9
|
+
|
|
10
|
+
interface BenchmarkResult {
|
|
11
|
+
name: string;
|
|
12
|
+
operations: number;
|
|
13
|
+
totalTime: number;
|
|
14
|
+
opsPerSec: number;
|
|
15
|
+
avgLatency: number;
|
|
16
|
+
p50: number;
|
|
17
|
+
p95: number;
|
|
18
|
+
p99: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Run a benchmark and collect statistics
|
|
23
|
+
*/
|
|
24
|
+
async function benchmark(
|
|
25
|
+
name: string,
|
|
26
|
+
operations: number,
|
|
27
|
+
fn: () => Promise<void>
|
|
28
|
+
): Promise<BenchmarkResult> {
|
|
29
|
+
const latencies: number[] = [];
|
|
30
|
+
|
|
31
|
+
console.log(chalk.blue(`\nš Running: ${name}`));
|
|
32
|
+
console.log(chalk.gray(` Operations: ${operations}`));
|
|
33
|
+
|
|
34
|
+
const startTime = Date.now();
|
|
35
|
+
|
|
36
|
+
for (let i = 0; i < operations; i++) {
|
|
37
|
+
const opStart = Date.now();
|
|
38
|
+
await fn();
|
|
39
|
+
const opLatency = Date.now() - opStart;
|
|
40
|
+
latencies.push(opLatency);
|
|
41
|
+
|
|
42
|
+
if ((i + 1) % Math.max(1, Math.floor(operations / 10)) === 0) {
|
|
43
|
+
process.stdout.write(chalk.gray(`.`));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const totalTime = Date.now() - startTime;
|
|
48
|
+
const opsPerSec = (operations / totalTime) * 1000;
|
|
49
|
+
|
|
50
|
+
// Calculate percentiles
|
|
51
|
+
latencies.sort((a, b) => a - b);
|
|
52
|
+
const p50 = latencies[Math.floor(latencies.length * 0.5)];
|
|
53
|
+
const p95 = latencies[Math.floor(latencies.length * 0.95)];
|
|
54
|
+
const p99 = latencies[Math.floor(latencies.length * 0.99)];
|
|
55
|
+
const avgLatency = latencies.reduce((a, b) => a + b, 0) / latencies.length;
|
|
56
|
+
|
|
57
|
+
console.log(); // Newline after dots
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
name,
|
|
61
|
+
operations,
|
|
62
|
+
totalTime,
|
|
63
|
+
opsPerSec,
|
|
64
|
+
avgLatency,
|
|
65
|
+
p50,
|
|
66
|
+
p95,
|
|
67
|
+
p99
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Print benchmark results
|
|
73
|
+
*/
|
|
74
|
+
function printResult(result: BenchmarkResult) {
|
|
75
|
+
console.log(chalk.green(`\nā
${result.name}`));
|
|
76
|
+
console.log(chalk.white(` Total time: ${result.totalTime.toFixed(2)}ms`));
|
|
77
|
+
console.log(chalk.white(` Throughput: ${result.opsPerSec.toFixed(2)} ops/sec`));
|
|
78
|
+
console.log(chalk.white(` Avg latency: ${result.avgLatency.toFixed(2)}ms`));
|
|
79
|
+
console.log(chalk.white(` P50 latency: ${result.p50.toFixed(2)}ms`));
|
|
80
|
+
console.log(chalk.white(` P95 latency: ${result.p95.toFixed(2)}ms`));
|
|
81
|
+
console.log(chalk.white(` P99 latency: ${result.p99.toFixed(2)}ms`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Main benchmark suite
|
|
86
|
+
*/
|
|
87
|
+
async function main() {
|
|
88
|
+
console.log(chalk.bold.cyan('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
89
|
+
console.log(chalk.bold.cyan('ā AgentDB + ONNX Performance Benchmark ā'));
|
|
90
|
+
console.log(chalk.bold.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
91
|
+
|
|
92
|
+
const dbPath = './benchmark-agentdb-onnx.db';
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
// Initialize AgentDB
|
|
96
|
+
console.log(chalk.yellow('š¦ Initializing AgentDB + ONNX...'));
|
|
97
|
+
const agentdb = await createONNXAgentDB({
|
|
98
|
+
dbPath,
|
|
99
|
+
modelName: 'Xenova/all-MiniLM-L6-v2',
|
|
100
|
+
useGPU: false,
|
|
101
|
+
batchSize: 32,
|
|
102
|
+
cacheSize: 10000
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
console.log(chalk.green('ā
Initialization complete\n'));
|
|
106
|
+
|
|
107
|
+
const results: BenchmarkResult[] = [];
|
|
108
|
+
|
|
109
|
+
// Benchmark 1: Single embedding generation
|
|
110
|
+
results.push(await benchmark(
|
|
111
|
+
'Single Embedding Generation',
|
|
112
|
+
100,
|
|
113
|
+
async () => {
|
|
114
|
+
await agentdb.embedder.embed(`Test embedding ${Math.random()}`);
|
|
115
|
+
}
|
|
116
|
+
));
|
|
117
|
+
|
|
118
|
+
// Benchmark 2: Cached embedding access
|
|
119
|
+
const cachedText = 'This text will be cached';
|
|
120
|
+
await agentdb.embedder.embed(cachedText); // Warm up cache
|
|
121
|
+
|
|
122
|
+
results.push(await benchmark(
|
|
123
|
+
'Cached Embedding Access',
|
|
124
|
+
1000,
|
|
125
|
+
async () => {
|
|
126
|
+
await agentdb.embedder.embed(cachedText);
|
|
127
|
+
}
|
|
128
|
+
));
|
|
129
|
+
|
|
130
|
+
// Benchmark 3: Batch embedding (10 items)
|
|
131
|
+
results.push(await benchmark(
|
|
132
|
+
'Batch Embedding (10 items)',
|
|
133
|
+
50,
|
|
134
|
+
async () => {
|
|
135
|
+
const texts = Array.from({ length: 10 }, (_, i) =>
|
|
136
|
+
`Batch text ${i} ${Math.random()}`
|
|
137
|
+
);
|
|
138
|
+
await agentdb.embedder.embedBatch(texts);
|
|
139
|
+
}
|
|
140
|
+
));
|
|
141
|
+
|
|
142
|
+
// Benchmark 4: Batch embedding (100 items)
|
|
143
|
+
results.push(await benchmark(
|
|
144
|
+
'Batch Embedding (100 items)',
|
|
145
|
+
10,
|
|
146
|
+
async () => {
|
|
147
|
+
const texts = Array.from({ length: 100 }, (_, i) =>
|
|
148
|
+
`Large batch text ${i} ${Math.random()}`
|
|
149
|
+
);
|
|
150
|
+
await agentdb.embedder.embedBatch(texts);
|
|
151
|
+
}
|
|
152
|
+
));
|
|
153
|
+
|
|
154
|
+
// Benchmark 5: Pattern storage
|
|
155
|
+
results.push(await benchmark(
|
|
156
|
+
'Pattern Storage (Single)',
|
|
157
|
+
100,
|
|
158
|
+
async () => {
|
|
159
|
+
await agentdb.reasoningBank.storePattern({
|
|
160
|
+
taskType: 'benchmark',
|
|
161
|
+
approach: `Approach ${Math.random()}`,
|
|
162
|
+
successRate: Math.random()
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
));
|
|
166
|
+
|
|
167
|
+
// Benchmark 6: Pattern batch storage (using loops)
|
|
168
|
+
results.push(await benchmark(
|
|
169
|
+
'Pattern Storage (Batch of 10)',
|
|
170
|
+
20,
|
|
171
|
+
async () => {
|
|
172
|
+
const patterns = Array.from({ length: 10 }, (_, i) => ({
|
|
173
|
+
taskType: 'batch-benchmark',
|
|
174
|
+
approach: `Batch approach ${i} ${Math.random()}`,
|
|
175
|
+
successRate: Math.random()
|
|
176
|
+
}));
|
|
177
|
+
for (const pattern of patterns) {
|
|
178
|
+
await agentdb.reasoningBank.storePattern(pattern);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
));
|
|
182
|
+
|
|
183
|
+
// Benchmark 7: Pattern search - pre-populate database
|
|
184
|
+
for (let i = 0; i < 100; i++) {
|
|
185
|
+
await agentdb.reasoningBank.storePattern({
|
|
186
|
+
taskType: 'search-test',
|
|
187
|
+
approach: `Search approach ${i}`,
|
|
188
|
+
successRate: Math.random()
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
results.push(await benchmark(
|
|
193
|
+
'Pattern Search (k=10)',
|
|
194
|
+
100,
|
|
195
|
+
async () => {
|
|
196
|
+
await agentdb.reasoningBank.searchPatterns({
|
|
197
|
+
task: 'search approach',
|
|
198
|
+
k: 10
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
));
|
|
202
|
+
|
|
203
|
+
// Benchmark 8: Episode storage
|
|
204
|
+
results.push(await benchmark(
|
|
205
|
+
'Episode Storage (Single)',
|
|
206
|
+
100,
|
|
207
|
+
async () => {
|
|
208
|
+
await agentdb.reflexionMemory.storeEpisode({
|
|
209
|
+
sessionId: 'benchmark',
|
|
210
|
+
task: `Task ${Math.random()}`,
|
|
211
|
+
reward: Math.random(),
|
|
212
|
+
success: Math.random() > 0.5,
|
|
213
|
+
critique: 'Benchmark critique'
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
));
|
|
217
|
+
|
|
218
|
+
// Benchmark 9: Episode batch storage (using loops)
|
|
219
|
+
results.push(await benchmark(
|
|
220
|
+
'Episode Storage (Batch of 10)',
|
|
221
|
+
20,
|
|
222
|
+
async () => {
|
|
223
|
+
const episodes = Array.from({ length: 10 }, (_, i) => ({
|
|
224
|
+
sessionId: 'batch-benchmark',
|
|
225
|
+
task: `Batch task ${i} ${Math.random()}`,
|
|
226
|
+
reward: Math.random(),
|
|
227
|
+
success: Math.random() > 0.5,
|
|
228
|
+
critique: `Batch critique ${i}`
|
|
229
|
+
}));
|
|
230
|
+
for (const episode of episodes) {
|
|
231
|
+
await agentdb.reflexionMemory.storeEpisode(episode);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
));
|
|
235
|
+
|
|
236
|
+
// Benchmark 10: Episode retrieval - pre-populate database
|
|
237
|
+
for (let i = 0; i < 100; i++) {
|
|
238
|
+
await agentdb.reflexionMemory.storeEpisode({
|
|
239
|
+
sessionId: 'retrieval-test',
|
|
240
|
+
task: `Retrieval task ${i}`,
|
|
241
|
+
reward: Math.random(),
|
|
242
|
+
success: Math.random() > 0.5
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
results.push(await benchmark(
|
|
247
|
+
'Episode Retrieval (k=10)',
|
|
248
|
+
100,
|
|
249
|
+
async () => {
|
|
250
|
+
await agentdb.reflexionMemory.retrieveRelevant({
|
|
251
|
+
task: 'retrieval task',
|
|
252
|
+
k: 10
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
));
|
|
256
|
+
|
|
257
|
+
// Print all results
|
|
258
|
+
console.log(chalk.bold.cyan('\n\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
259
|
+
console.log(chalk.bold.cyan('ā Benchmark Results ā'));
|
|
260
|
+
console.log(chalk.bold.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
261
|
+
|
|
262
|
+
results.forEach(printResult);
|
|
263
|
+
|
|
264
|
+
// Print summary
|
|
265
|
+
console.log(chalk.bold.cyan('\n\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā'));
|
|
266
|
+
console.log(chalk.bold.cyan('ā Summary ā'));
|
|
267
|
+
console.log(chalk.bold.cyan('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n'));
|
|
268
|
+
|
|
269
|
+
const stats = agentdb.getStats();
|
|
270
|
+
|
|
271
|
+
console.log(chalk.white('š Overall Statistics:'));
|
|
272
|
+
console.log(chalk.white(` Total embeddings: ${stats.embedder.totalEmbeddings}`));
|
|
273
|
+
console.log(chalk.white(` Avg embedding time: ${stats.embedder.avgLatency.toFixed(2)}ms`));
|
|
274
|
+
console.log(chalk.white(` Cache hit rate: ${(stats.embedder.cache.hitRate * 100).toFixed(1)}%`));
|
|
275
|
+
console.log(chalk.white(` Cache size: ${stats.embedder.cache.size}/${stats.embedder.cache.maxSize}`));
|
|
276
|
+
|
|
277
|
+
// Calculate speedup from batching
|
|
278
|
+
const singlePattern = results.find(r => r.name === 'Pattern Storage (Single)');
|
|
279
|
+
const batchPattern = results.find(r => r.name === 'Pattern Storage (Batch of 10)');
|
|
280
|
+
|
|
281
|
+
if (singlePattern && batchPattern) {
|
|
282
|
+
const speedup = (singlePattern.opsPerSec * 10) / batchPattern.opsPerSec;
|
|
283
|
+
console.log(chalk.white(`\nš Batch speedup: ${speedup.toFixed(2)}x faster`));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Cleanup
|
|
287
|
+
await agentdb.close();
|
|
288
|
+
|
|
289
|
+
console.log(chalk.green('\nā
Benchmark complete!\n'));
|
|
290
|
+
} catch (error) {
|
|
291
|
+
console.error(chalk.red('\nā Benchmark failed:'), error);
|
|
292
|
+
process.exit(1);
|
|
293
|
+
} finally {
|
|
294
|
+
try {
|
|
295
|
+
await unlink(dbPath);
|
|
296
|
+
} catch {}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Run benchmarks
|
|
301
|
+
main().catch(console.error);
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for AgentDB + ONNX
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { createONNXAgentDB } from './index.js';
|
|
9
|
+
import { unlink } from 'fs/promises';
|
|
10
|
+
|
|
11
|
+
const program = new Command();
|
|
12
|
+
|
|
13
|
+
program
|
|
14
|
+
.name('agentdb-onnx')
|
|
15
|
+
.description('AgentDB with optimized ONNX embeddings')
|
|
16
|
+
.version('1.0.0');
|
|
17
|
+
|
|
18
|
+
// Init command
|
|
19
|
+
program
|
|
20
|
+
.command('init')
|
|
21
|
+
.description('Initialize a new AgentDB with ONNX embeddings')
|
|
22
|
+
.argument('<db-path>', 'Path to database file')
|
|
23
|
+
.option('-m, --model <name>', 'Model name', 'Xenova/all-MiniLM-L6-v2')
|
|
24
|
+
.option('--gpu', 'Enable GPU acceleration')
|
|
25
|
+
.option('-b, --batch-size <size>', 'Batch size', '32')
|
|
26
|
+
.option('-c, --cache-size <size>', 'Cache size', '10000')
|
|
27
|
+
.action(async (dbPath, options) => {
|
|
28
|
+
try {
|
|
29
|
+
console.log(chalk.blue('Initializing AgentDB + ONNX...'));
|
|
30
|
+
console.log(chalk.gray(` Database: ${dbPath}`));
|
|
31
|
+
console.log(chalk.gray(` Model: ${options.model}`));
|
|
32
|
+
console.log(chalk.gray(` GPU: ${options.gpu ? 'enabled' : 'disabled'}`));
|
|
33
|
+
|
|
34
|
+
const agentdb = await createONNXAgentDB({
|
|
35
|
+
dbPath,
|
|
36
|
+
modelName: options.model,
|
|
37
|
+
useGPU: options.gpu,
|
|
38
|
+
batchSize: parseInt(options.batchSize),
|
|
39
|
+
cacheSize: parseInt(options.cacheSize)
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
console.log(chalk.green('ā
Initialized successfully'));
|
|
43
|
+
|
|
44
|
+
await agentdb.close();
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error(chalk.red('ā Error:'), error);
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Store pattern command
|
|
52
|
+
program
|
|
53
|
+
.command('store-pattern')
|
|
54
|
+
.description('Store a reasoning pattern')
|
|
55
|
+
.argument('<db-path>', 'Database path')
|
|
56
|
+
.requiredOption('-t, --task-type <type>', 'Task type')
|
|
57
|
+
.requiredOption('-a, --approach <approach>', 'Approach description')
|
|
58
|
+
.requiredOption('-s, --success-rate <rate>', 'Success rate (0-1)')
|
|
59
|
+
.option('--tags <tags>', 'Comma-separated tags')
|
|
60
|
+
.action(async (dbPath, options) => {
|
|
61
|
+
try {
|
|
62
|
+
const agentdb = await createONNXAgentDB({ dbPath, useGPU: false });
|
|
63
|
+
|
|
64
|
+
const id = await agentdb.reasoningBank.storePattern({
|
|
65
|
+
taskType: options.taskType,
|
|
66
|
+
approach: options.approach,
|
|
67
|
+
successRate: parseFloat(options.successRate),
|
|
68
|
+
tags: options.tags?.split(',')
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
console.log(chalk.green(`ā
Pattern stored with ID: ${id}`));
|
|
72
|
+
|
|
73
|
+
await agentdb.close();
|
|
74
|
+
} catch (error) {
|
|
75
|
+
console.error(chalk.red('ā Error:'), error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Search patterns command
|
|
81
|
+
program
|
|
82
|
+
.command('search-patterns')
|
|
83
|
+
.description('Search for similar patterns')
|
|
84
|
+
.argument('<db-path>', 'Database path')
|
|
85
|
+
.argument('<query>', 'Search query')
|
|
86
|
+
.option('-k, --top-k <k>', 'Number of results', '10')
|
|
87
|
+
.option('--threshold <threshold>', 'Similarity threshold', '0.7')
|
|
88
|
+
.option('--task-type <type>', 'Filter by task type')
|
|
89
|
+
.action(async (dbPath, query, options) => {
|
|
90
|
+
try {
|
|
91
|
+
const agentdb = await createONNXAgentDB({ dbPath, useGPU: false });
|
|
92
|
+
|
|
93
|
+
const results = await agentdb.reasoningBank.searchPatterns({
|
|
94
|
+
task: query,
|
|
95
|
+
k: parseInt(options.topK),
|
|
96
|
+
threshold: parseFloat(options.threshold),
|
|
97
|
+
filters: options.taskType ? { taskType: options.taskType } : undefined
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
console.log(chalk.blue(`\nFound ${results.length} patterns:\n`));
|
|
101
|
+
|
|
102
|
+
results.forEach((r, i) => {
|
|
103
|
+
console.log(chalk.white(`${i + 1}. ${r.approach}`));
|
|
104
|
+
console.log(chalk.gray(` Type: ${r.taskType}`));
|
|
105
|
+
console.log(chalk.gray(` Success: ${(r.successRate * 100).toFixed(1)}%`));
|
|
106
|
+
console.log(chalk.gray(` Similarity: ${(r.similarity * 100).toFixed(1)}%`));
|
|
107
|
+
if (r.tags && r.tags.length > 0) {
|
|
108
|
+
console.log(chalk.gray(` Tags: ${r.tags.join(', ')}`));
|
|
109
|
+
}
|
|
110
|
+
console.log();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await agentdb.close();
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error(chalk.red('ā Error:'), error);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Store episode command
|
|
121
|
+
program
|
|
122
|
+
.command('store-episode')
|
|
123
|
+
.description('Store a reflexion episode')
|
|
124
|
+
.argument('<db-path>', 'Database path')
|
|
125
|
+
.requiredOption('-s, --session <id>', 'Session ID')
|
|
126
|
+
.requiredOption('-t, --task <task>', 'Task description')
|
|
127
|
+
.requiredOption('-r, --reward <reward>', 'Reward (0-1)')
|
|
128
|
+
.requiredOption('--success', 'Task succeeded')
|
|
129
|
+
.option('--critique <critique>', 'Self-critique')
|
|
130
|
+
.action(async (dbPath, options) => {
|
|
131
|
+
try {
|
|
132
|
+
const agentdb = await createONNXAgentDB({ dbPath, useGPU: false });
|
|
133
|
+
|
|
134
|
+
const id = await agentdb.reflexionMemory.storeEpisode({
|
|
135
|
+
sessionId: options.session,
|
|
136
|
+
task: options.task,
|
|
137
|
+
reward: parseFloat(options.reward),
|
|
138
|
+
success: true,
|
|
139
|
+
critique: options.critique
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
console.log(chalk.green(`ā
Episode stored with ID: ${id}`));
|
|
143
|
+
|
|
144
|
+
await agentdb.close();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
console.error(chalk.red('ā Error:'), error);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// Search episodes command
|
|
152
|
+
program
|
|
153
|
+
.command('search-episodes')
|
|
154
|
+
.description('Search for similar episodes')
|
|
155
|
+
.argument('<db-path>', 'Database path')
|
|
156
|
+
.argument('<query>', 'Search query')
|
|
157
|
+
.option('-k, --top-k <k>', 'Number of results', '10')
|
|
158
|
+
.option('--only-successes', 'Only successful episodes')
|
|
159
|
+
.option('--min-reward <reward>', 'Minimum reward threshold')
|
|
160
|
+
.action(async (dbPath, query, options) => {
|
|
161
|
+
try {
|
|
162
|
+
const agentdb = await createONNXAgentDB({ dbPath, useGPU: false });
|
|
163
|
+
|
|
164
|
+
const results = await agentdb.reflexionMemory.retrieveRelevant({
|
|
165
|
+
task: query,
|
|
166
|
+
k: parseInt(options.topK),
|
|
167
|
+
onlySuccesses: options.onlySuccesses,
|
|
168
|
+
minReward: options.minReward ? parseFloat(options.minReward) : undefined
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
console.log(chalk.blue(`\nFound ${results.length} episodes:\n`));
|
|
172
|
+
|
|
173
|
+
results.forEach((r, i) => {
|
|
174
|
+
console.log(chalk.white(`${i + 1}. ${r.task}`));
|
|
175
|
+
console.log(chalk.gray(` Session: ${r.sessionId}`));
|
|
176
|
+
console.log(chalk.gray(` Reward: ${(r.reward * 100).toFixed(1)}%`));
|
|
177
|
+
console.log(chalk.gray(` Success: ${r.success ? 'Yes' : 'No'}`));
|
|
178
|
+
console.log(chalk.gray(` Similarity: ${(r.similarity * 100).toFixed(1)}%`));
|
|
179
|
+
if (r.critique) {
|
|
180
|
+
console.log(chalk.gray(` Critique: ${r.critique.substring(0, 80)}${r.critique.length > 80 ? '...' : ''}`));
|
|
181
|
+
}
|
|
182
|
+
console.log();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await agentdb.close();
|
|
186
|
+
} catch (error) {
|
|
187
|
+
console.error(chalk.red('ā Error:'), error);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
// Stats command
|
|
193
|
+
program
|
|
194
|
+
.command('stats')
|
|
195
|
+
.description('Show database statistics')
|
|
196
|
+
.argument('<db-path>', 'Database path')
|
|
197
|
+
.action(async (dbPath) => {
|
|
198
|
+
try {
|
|
199
|
+
const agentdb = await createONNXAgentDB({ dbPath, useGPU: false });
|
|
200
|
+
|
|
201
|
+
const stats = agentdb.getStats();
|
|
202
|
+
|
|
203
|
+
console.log(chalk.blue('\nš AgentDB + ONNX Statistics\n'));
|
|
204
|
+
|
|
205
|
+
console.log(chalk.white('Embeddings:'));
|
|
206
|
+
console.log(chalk.gray(` Model: ${stats.embedder.model}`));
|
|
207
|
+
console.log(chalk.gray(` Total: ${stats.embedder.totalEmbeddings}`));
|
|
208
|
+
console.log(chalk.gray(` Avg latency: ${stats.embedder.avgLatency.toFixed(2)}ms`));
|
|
209
|
+
console.log(chalk.gray(` Cache hit rate: ${(stats.embedder.cache.hitRate * 100).toFixed(1)}%`));
|
|
210
|
+
console.log(chalk.gray(` Cache size: ${stats.embedder.cache.size}/${stats.embedder.cache.maxSize}`));
|
|
211
|
+
|
|
212
|
+
console.log(chalk.white('\nDatabase:'));
|
|
213
|
+
if (stats.database) {
|
|
214
|
+
Object.entries(stats.database).forEach(([key, value]) => {
|
|
215
|
+
console.log(chalk.gray(` ${key}: ${value}`));
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
console.log();
|
|
220
|
+
|
|
221
|
+
await agentdb.close();
|
|
222
|
+
} catch (error) {
|
|
223
|
+
console.error(chalk.red('ā Error:'), error);
|
|
224
|
+
process.exit(1);
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Benchmark command
|
|
229
|
+
program
|
|
230
|
+
.command('benchmark')
|
|
231
|
+
.description('Run performance benchmarks')
|
|
232
|
+
.option('--operations <n>', 'Number of operations per test', '100')
|
|
233
|
+
.action(async (options) => {
|
|
234
|
+
console.log(chalk.blue('Running benchmarks...\n'));
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
// Import and run benchmark dynamically
|
|
238
|
+
await import('./benchmarks/benchmark-runner.js');
|
|
239
|
+
} catch (error) {
|
|
240
|
+
console.error(chalk.red('ā Benchmark failed:'), error);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
program.parse();
|