@agentic-robotics/mcp 0.2.0 ā 0.2.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/package.json +2 -2
- package/dist/optimized-benchmark.d.ts +0 -74
- package/dist/optimized-benchmark.d.ts.map +0 -1
- package/dist/optimized-benchmark.js +0 -231
- package/dist/optimized-benchmark.js.map +0 -1
- package/src/benchmark.ts +0 -434
- package/src/cli.ts +0 -89
- package/src/enhanced-memory.ts +0 -437
- package/src/enhanced-server.ts +0 -523
- package/src/flow-orchestrator.ts +0 -475
- package/src/hybrid-benchmark.ts +0 -291
- package/src/hybrid-memory.ts +0 -401
- package/src/index.ts +0 -10
- package/src/interface.ts +0 -118
- package/src/memory.ts +0 -315
- package/src/server.ts +0 -213
- package/tsconfig.json +0 -20
package/src/hybrid-benchmark.ts
DELETED
|
@@ -1,291 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hybrid Benchmark Suite
|
|
3
|
-
*
|
|
4
|
-
* Demonstrates performance improvements with direct SQL storage
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { HybridAgentDBMemory } from './hybrid-memory.js';
|
|
8
|
-
import type { Episode } from './memory.js';
|
|
9
|
-
|
|
10
|
-
interface BenchmarkResult {
|
|
11
|
-
name: string;
|
|
12
|
-
iterations: number;
|
|
13
|
-
totalTime: number;
|
|
14
|
-
avgTime: number;
|
|
15
|
-
minTime: number;
|
|
16
|
-
maxTime: number;
|
|
17
|
-
opsPerSec: number;
|
|
18
|
-
p50: number;
|
|
19
|
-
p95: number;
|
|
20
|
-
p99: number;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class HybridBenchmark {
|
|
24
|
-
private memory: HybridAgentDBMemory;
|
|
25
|
-
|
|
26
|
-
constructor() {
|
|
27
|
-
this.memory = new HybridAgentDBMemory('./hybrid-benchmark.db');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async initialize(): Promise<void> {
|
|
31
|
-
console.log('š Initializing hybrid benchmark suite...\n');
|
|
32
|
-
await this.memory.initialize();
|
|
33
|
-
console.log('ā
Benchmark suite ready\n');
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Run complete benchmark suite
|
|
38
|
-
*/
|
|
39
|
-
async runAll(): Promise<void> {
|
|
40
|
-
const suiteStartTime = Date.now();
|
|
41
|
-
|
|
42
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
43
|
-
console.log('ā Hybrid Integration Benchmark Suite ā');
|
|
44
|
-
console.log('ā Direct SQL + CLI Vector Search Performance Test ā');
|
|
45
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
46
|
-
|
|
47
|
-
// Hybrid Benchmarks
|
|
48
|
-
console.log('š HYBRID BENCHMARKS (SQL Storage + CLI Search)\n');
|
|
49
|
-
|
|
50
|
-
const storeEpisode = await this.benchmarkStoreEpisode(1000);
|
|
51
|
-
this.printResult('Store Episode (SQL)', storeEpisode);
|
|
52
|
-
|
|
53
|
-
const bulkStore = await this.benchmarkBulkStore(1000, 100);
|
|
54
|
-
this.printResult('Bulk Store (SQL Transaction)', bulkStore);
|
|
55
|
-
|
|
56
|
-
const retrieveMemories = await this.benchmarkRetrieveMemories(100);
|
|
57
|
-
this.printResult('Retrieve Memories (SQL Fallback)', retrieveMemories);
|
|
58
|
-
|
|
59
|
-
const queryWithContext = await this.benchmarkQueryWithContext(100);
|
|
60
|
-
this.printResult('Query with Context (Hybrid)', queryWithContext);
|
|
61
|
-
|
|
62
|
-
const searchSkills = await this.benchmarkSearchSkills(200);
|
|
63
|
-
this.printResult('Search Skills (SQL)', searchSkills);
|
|
64
|
-
|
|
65
|
-
const totalTime = Date.now() - suiteStartTime;
|
|
66
|
-
|
|
67
|
-
console.log('\nāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
68
|
-
console.log('ā BENCHMARK COMPLETE ā');
|
|
69
|
-
console.log(`ā Total Time: ${(totalTime / 1000).toFixed(2)}s ā`);
|
|
70
|
-
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
71
|
-
|
|
72
|
-
// Print performance metrics
|
|
73
|
-
const metrics = this.memory.getMetrics();
|
|
74
|
-
console.log('š PERFORMANCE METRICS\n');
|
|
75
|
-
console.log(` Store Operations: ${metrics.storeCount}`);
|
|
76
|
-
console.log(` Avg Store Time: ${metrics.avgStoreTime.toFixed(3)}ms`);
|
|
77
|
-
console.log(` Retrieve Operations: ${metrics.retrieveCount}`);
|
|
78
|
-
console.log(` Avg Retrieve Time: ${metrics.avgRetrieveTime.toFixed(3)}ms\n`);
|
|
79
|
-
|
|
80
|
-
// Print database stats
|
|
81
|
-
const stats = await this.memory.getStats();
|
|
82
|
-
console.log('š¾ DATABASE STATISTICS\n');
|
|
83
|
-
console.log(` Total Episodes: ${stats.total_episodes}`);
|
|
84
|
-
console.log(` Successful: ${stats.successful_episodes}`);
|
|
85
|
-
console.log(` Failed: ${stats.failed_episodes}`);
|
|
86
|
-
console.log(` Unique Tasks: ${stats.unique_tasks}`);
|
|
87
|
-
console.log(` Avg Confidence: ${stats.avg_confidence?.toFixed(3)}\n`);
|
|
88
|
-
|
|
89
|
-
// Optimization test
|
|
90
|
-
console.log('š§ Running database optimization...');
|
|
91
|
-
await this.memory.optimize();
|
|
92
|
-
console.log('');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Benchmark: Store Episode (Direct SQL)
|
|
97
|
-
*/
|
|
98
|
-
private async benchmarkStoreEpisode(iterations: number): Promise<BenchmarkResult> {
|
|
99
|
-
const times: number[] = [];
|
|
100
|
-
|
|
101
|
-
for (let i = 0; i < iterations; i++) {
|
|
102
|
-
const episode: Episode = {
|
|
103
|
-
sessionId: `bench-${i}`,
|
|
104
|
-
taskName: 'navigation',
|
|
105
|
-
confidence: Math.random(),
|
|
106
|
-
success: Math.random() > 0.3,
|
|
107
|
-
outcome: 'Completed navigation task',
|
|
108
|
-
strategy: 'adaptive_planning',
|
|
109
|
-
metadata: { x: i, y: i * 2, latency: Math.random() * 100 },
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
const start = performance.now();
|
|
113
|
-
await this.memory.storeEpisode(episode);
|
|
114
|
-
times.push(performance.now() - start);
|
|
115
|
-
|
|
116
|
-
if (i % 100 === 0 && i > 0) {
|
|
117
|
-
process.stderr.write(` Progress: ${i}/${iterations}\r`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
return this.calculateStats('Store Episode', times);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* Benchmark: Bulk Store (SQL Transaction)
|
|
126
|
-
*/
|
|
127
|
-
private async benchmarkBulkStore(totalEpisodes: number, batchSize: number): Promise<BenchmarkResult> {
|
|
128
|
-
const times: number[] = [];
|
|
129
|
-
const numBatches = Math.ceil(totalEpisodes / batchSize);
|
|
130
|
-
|
|
131
|
-
for (let i = 0; i < numBatches; i++) {
|
|
132
|
-
const batch: Episode[] = [];
|
|
133
|
-
for (let j = 0; j < batchSize; j++) {
|
|
134
|
-
const idx = i * batchSize + j;
|
|
135
|
-
batch.push({
|
|
136
|
-
sessionId: `bulk-${idx}`,
|
|
137
|
-
taskName: 'navigation',
|
|
138
|
-
confidence: Math.random(),
|
|
139
|
-
success: Math.random() > 0.3,
|
|
140
|
-
outcome: 'Completed navigation task',
|
|
141
|
-
strategy: 'adaptive_planning',
|
|
142
|
-
metadata: { x: idx, y: idx * 2 },
|
|
143
|
-
});
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const start = performance.now();
|
|
147
|
-
await this.memory.bulkStoreEpisodes(batch);
|
|
148
|
-
times.push(performance.now() - start);
|
|
149
|
-
|
|
150
|
-
if (i % 5 === 0 && i > 0) {
|
|
151
|
-
process.stderr.write(` Progress: ${i * batchSize}/${totalEpisodes}\r`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Convert to per-episode times
|
|
156
|
-
const perEpisodeTimes = times.map(t => t / batchSize);
|
|
157
|
-
return this.calculateStats('Bulk Store', perEpisodeTimes);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* Benchmark: Retrieve Memories (SQL fallback)
|
|
162
|
-
*/
|
|
163
|
-
private async benchmarkRetrieveMemories(iterations: number): Promise<BenchmarkResult> {
|
|
164
|
-
const times: number[] = [];
|
|
165
|
-
|
|
166
|
-
const queries = [
|
|
167
|
-
'navigation task',
|
|
168
|
-
'object detection',
|
|
169
|
-
'path planning',
|
|
170
|
-
'sensor fusion',
|
|
171
|
-
'motor control',
|
|
172
|
-
];
|
|
173
|
-
|
|
174
|
-
for (let i = 0; i < iterations; i++) {
|
|
175
|
-
const query = queries[i % queries.length];
|
|
176
|
-
|
|
177
|
-
const start = performance.now();
|
|
178
|
-
await this.memory.retrieveMemories(query, 5, {
|
|
179
|
-
onlySuccesses: true,
|
|
180
|
-
});
|
|
181
|
-
times.push(performance.now() - start);
|
|
182
|
-
|
|
183
|
-
if (i % 20 === 0 && i > 0) {
|
|
184
|
-
process.stderr.write(` Progress: ${i}/${iterations}\r`);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
return this.calculateStats('Retrieve Memories', times);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Benchmark: Query with Context
|
|
193
|
-
*/
|
|
194
|
-
private async benchmarkQueryWithContext(iterations: number): Promise<BenchmarkResult> {
|
|
195
|
-
const times: number[] = [];
|
|
196
|
-
|
|
197
|
-
for (let i = 0; i < iterations; i++) {
|
|
198
|
-
const start = performance.now();
|
|
199
|
-
await this.memory.queryWithContext('warehouse navigation', {
|
|
200
|
-
k: 10,
|
|
201
|
-
minConfidence: 0.5,
|
|
202
|
-
});
|
|
203
|
-
times.push(performance.now() - start);
|
|
204
|
-
|
|
205
|
-
if (i % 20 === 0 && i > 0) {
|
|
206
|
-
process.stderr.write(` Progress: ${i}/${iterations}\r`);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
return this.calculateStats('Query with Context', times);
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Benchmark: Search Skills (Direct SQL)
|
|
215
|
-
*/
|
|
216
|
-
private async benchmarkSearchSkills(iterations: number): Promise<BenchmarkResult> {
|
|
217
|
-
const times: number[] = [];
|
|
218
|
-
|
|
219
|
-
for (let i = 0; i < iterations; i++) {
|
|
220
|
-
const start = performance.now();
|
|
221
|
-
await this.memory.searchSkills('navigation', {
|
|
222
|
-
k: 5,
|
|
223
|
-
minSuccessRate: 0.5,
|
|
224
|
-
sortBy: 'success_rate',
|
|
225
|
-
});
|
|
226
|
-
times.push(performance.now() - start);
|
|
227
|
-
|
|
228
|
-
if (i % 20 === 0 && i > 0) {
|
|
229
|
-
process.stderr.write(` Progress: ${i}/${iterations}\r`);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return this.calculateStats('Search Skills', times);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Calculate statistics from timing data
|
|
238
|
-
*/
|
|
239
|
-
private calculateStats(name: string, times: number[]): BenchmarkResult {
|
|
240
|
-
const sorted = [...times].sort((a, b) => a - b);
|
|
241
|
-
const total = times.reduce((a, b) => a + b, 0);
|
|
242
|
-
|
|
243
|
-
return {
|
|
244
|
-
name,
|
|
245
|
-
iterations: times.length,
|
|
246
|
-
totalTime: total,
|
|
247
|
-
avgTime: total / times.length,
|
|
248
|
-
minTime: sorted[0],
|
|
249
|
-
maxTime: sorted[sorted.length - 1],
|
|
250
|
-
opsPerSec: (times.length / total) * 1000,
|
|
251
|
-
p50: sorted[Math.floor(sorted.length * 0.50)],
|
|
252
|
-
p95: sorted[Math.floor(sorted.length * 0.95)],
|
|
253
|
-
p99: sorted[Math.floor(sorted.length * 0.99)],
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Print benchmark result
|
|
259
|
-
*/
|
|
260
|
-
private printResult(name: string, result: BenchmarkResult): void {
|
|
261
|
-
const speedup = 2300 / result.avgTime; // Compare to CLI baseline (2.3s)
|
|
262
|
-
|
|
263
|
-
console.log(`${name}:`);
|
|
264
|
-
console.log(` Iterations: ${result.iterations.toLocaleString()}`);
|
|
265
|
-
console.log(` Avg Time: ${result.avgTime.toFixed(3)}ms`);
|
|
266
|
-
console.log(` Min/Max: ${result.minTime.toFixed(3)}ms / ${result.maxTime.toFixed(3)}ms`);
|
|
267
|
-
console.log(` p50/p95/p99: ${result.p50.toFixed(3)}ms / ${result.p95.toFixed(3)}ms / ${result.p99.toFixed(3)}ms`);
|
|
268
|
-
console.log(` Ops/sec: ${result.opsPerSec.toFixed(0)}`);
|
|
269
|
-
console.log(` Speedup: ${speedup.toFixed(0)}x faster than CLI`);
|
|
270
|
-
console.log('');
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
async close(): Promise<void> {
|
|
274
|
-
await this.memory.close();
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// CLI entry point
|
|
279
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
280
|
-
const benchmark = new HybridBenchmark();
|
|
281
|
-
|
|
282
|
-
try {
|
|
283
|
-
await benchmark.initialize();
|
|
284
|
-
await benchmark.runAll();
|
|
285
|
-
} catch (error) {
|
|
286
|
-
console.error('ā Benchmark failed:', error);
|
|
287
|
-
process.exit(1);
|
|
288
|
-
} finally {
|
|
289
|
-
await benchmark.close();
|
|
290
|
-
}
|
|
291
|
-
}
|
package/src/hybrid-memory.ts
DELETED
|
@@ -1,401 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hybrid AgentDB Memory Implementation
|
|
3
|
-
*
|
|
4
|
-
* Strategy: Direct SQLite for storage (fast), CLI for vector search (until API ready)
|
|
5
|
-
* Expected: 50-100x faster than pure CLI approach
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import Database from 'better-sqlite3';
|
|
9
|
-
import { promisify } from 'util';
|
|
10
|
-
import { exec } from 'child_process';
|
|
11
|
-
import type { Episode, Memory } from './memory.js';
|
|
12
|
-
|
|
13
|
-
const execAsync = promisify(exec);
|
|
14
|
-
|
|
15
|
-
export class HybridAgentDBMemory {
|
|
16
|
-
private db!: Database.Database;
|
|
17
|
-
private dbPath: string;
|
|
18
|
-
private initialized: boolean = false;
|
|
19
|
-
private performanceMetrics: {
|
|
20
|
-
storeCount: number;
|
|
21
|
-
retrieveCount: number;
|
|
22
|
-
avgStoreTime: number;
|
|
23
|
-
avgRetrieveTime: number;
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
constructor(dbPath: string) {
|
|
27
|
-
this.dbPath = dbPath;
|
|
28
|
-
this.performanceMetrics = {
|
|
29
|
-
storeCount: 0,
|
|
30
|
-
retrieveCount: 0,
|
|
31
|
-
avgStoreTime: 0,
|
|
32
|
-
avgRetrieveTime: 0,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async initialize(): Promise<void> {
|
|
37
|
-
if (this.initialized) return;
|
|
38
|
-
|
|
39
|
-
const startTime = Date.now();
|
|
40
|
-
|
|
41
|
-
// Open SQLite database with optimizations
|
|
42
|
-
this.db = new Database(this.dbPath);
|
|
43
|
-
|
|
44
|
-
// Enable performance optimizations
|
|
45
|
-
this.db.pragma('journal_mode = WAL'); // Write-Ahead Logging
|
|
46
|
-
this.db.pragma('synchronous = NORMAL'); // Balance safety/speed
|
|
47
|
-
this.db.pragma('cache_size = 10000'); // 10MB cache
|
|
48
|
-
this.db.pragma('temp_store = MEMORY'); // Temp tables in memory
|
|
49
|
-
this.db.pragma('mmap_size = 30000000000'); // Memory-mapped I/O
|
|
50
|
-
|
|
51
|
-
// Create tables if they don't exist
|
|
52
|
-
this.db.exec(`
|
|
53
|
-
CREATE TABLE IF NOT EXISTS reflexion_episodes (
|
|
54
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
55
|
-
session_id TEXT NOT NULL,
|
|
56
|
-
task_name TEXT NOT NULL,
|
|
57
|
-
confidence REAL NOT NULL,
|
|
58
|
-
success INTEGER NOT NULL,
|
|
59
|
-
outcome TEXT,
|
|
60
|
-
strategy TEXT,
|
|
61
|
-
metadata TEXT,
|
|
62
|
-
timestamp INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))
|
|
63
|
-
);
|
|
64
|
-
|
|
65
|
-
CREATE INDEX IF NOT EXISTS idx_task_name ON reflexion_episodes(task_name);
|
|
66
|
-
CREATE INDEX IF NOT EXISTS idx_success ON reflexion_episodes(success);
|
|
67
|
-
CREATE INDEX IF NOT EXISTS idx_timestamp ON reflexion_episodes(timestamp);
|
|
68
|
-
`);
|
|
69
|
-
|
|
70
|
-
this.initialized = true;
|
|
71
|
-
const elapsed = Date.now() - startTime;
|
|
72
|
-
|
|
73
|
-
console.error(`ā
Hybrid AgentDB initialized: ${this.dbPath}`);
|
|
74
|
-
console.error(`ā” Initialization time: ${elapsed}ms`);
|
|
75
|
-
console.error(`š Mode: Direct SQL storage + CLI vector search`);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Store episode using direct SQL (100x faster than CLI)
|
|
80
|
-
*/
|
|
81
|
-
async storeEpisode(episode: Episode): Promise<void> {
|
|
82
|
-
const startTime = performance.now();
|
|
83
|
-
|
|
84
|
-
const stmt = this.db.prepare(`
|
|
85
|
-
INSERT INTO reflexion_episodes
|
|
86
|
-
(session_id, task_name, confidence, success, outcome, strategy, metadata)
|
|
87
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
88
|
-
`);
|
|
89
|
-
|
|
90
|
-
stmt.run(
|
|
91
|
-
episode.sessionId,
|
|
92
|
-
episode.taskName,
|
|
93
|
-
episode.confidence,
|
|
94
|
-
episode.success ? 1 : 0,
|
|
95
|
-
episode.outcome,
|
|
96
|
-
episode.strategy || null,
|
|
97
|
-
episode.metadata ? JSON.stringify(episode.metadata) : null
|
|
98
|
-
);
|
|
99
|
-
|
|
100
|
-
const elapsed = performance.now() - startTime;
|
|
101
|
-
this.updateStoreMetrics(elapsed);
|
|
102
|
-
|
|
103
|
-
if (this.performanceMetrics.storeCount % 100 === 0 && this.performanceMetrics.storeCount > 0) {
|
|
104
|
-
console.error(`š¾ Stored episode: ${episode.taskName} (${elapsed.toFixed(2)}ms)`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Bulk store episodes (even faster with transactions)
|
|
110
|
-
*/
|
|
111
|
-
async bulkStoreEpisodes(episodes: Episode[]): Promise<void> {
|
|
112
|
-
const startTime = performance.now();
|
|
113
|
-
|
|
114
|
-
const stmt = this.db.prepare(`
|
|
115
|
-
INSERT INTO reflexion_episodes
|
|
116
|
-
(session_id, task_name, confidence, success, outcome, strategy, metadata)
|
|
117
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
118
|
-
`);
|
|
119
|
-
|
|
120
|
-
const insertMany = this.db.transaction((episodes: Episode[]) => {
|
|
121
|
-
for (const episode of episodes) {
|
|
122
|
-
stmt.run(
|
|
123
|
-
episode.sessionId,
|
|
124
|
-
episode.taskName,
|
|
125
|
-
episode.confidence,
|
|
126
|
-
episode.success ? 1 : 0,
|
|
127
|
-
episode.outcome,
|
|
128
|
-
episode.strategy || null,
|
|
129
|
-
episode.metadata ? JSON.stringify(episode.metadata) : null
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
insertMany(episodes);
|
|
135
|
-
|
|
136
|
-
const elapsed = performance.now() - startTime;
|
|
137
|
-
console.error(`š¾ Bulk stored ${episodes.length} episodes (${elapsed.toFixed(2)}ms, ${(elapsed/episodes.length).toFixed(2)}ms avg)`);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Retrieve memories using CLI vector search (until API ready)
|
|
142
|
-
* Falls back to SQL if CLI fails
|
|
143
|
-
*/
|
|
144
|
-
async retrieveMemories(
|
|
145
|
-
query: string,
|
|
146
|
-
k: number = 5,
|
|
147
|
-
options: {
|
|
148
|
-
minReward?: number;
|
|
149
|
-
onlySuccesses?: boolean;
|
|
150
|
-
onlyFailures?: boolean;
|
|
151
|
-
synthesizeContext?: boolean;
|
|
152
|
-
} = {}
|
|
153
|
-
): Promise<Memory[]> {
|
|
154
|
-
const startTime = performance.now();
|
|
155
|
-
|
|
156
|
-
// Try CLI vector search first (semantic search)
|
|
157
|
-
try {
|
|
158
|
-
let cmd = `npx agentdb reflexion retrieve "${query}" --k ${k}`;
|
|
159
|
-
|
|
160
|
-
if (options.minReward !== undefined) {
|
|
161
|
-
cmd += ` --min-reward ${options.minReward}`;
|
|
162
|
-
}
|
|
163
|
-
if (options.onlySuccesses) {
|
|
164
|
-
cmd += ' --only-successes';
|
|
165
|
-
}
|
|
166
|
-
if (options.onlyFailures) {
|
|
167
|
-
cmd += ' --only-failures';
|
|
168
|
-
}
|
|
169
|
-
if (options.synthesizeContext) {
|
|
170
|
-
cmd += ' --synthesize-context';
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const { stdout } = await execAsync(`AGENTDB_PATH="${this.dbPath}" ${cmd}`, {
|
|
174
|
-
timeout: 10000,
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
const lines = stdout.trim().split('\n');
|
|
178
|
-
const jsonLine = lines.find(line => line.startsWith('[') || line.startsWith('{'));
|
|
179
|
-
|
|
180
|
-
if (jsonLine) {
|
|
181
|
-
const data = JSON.parse(jsonLine);
|
|
182
|
-
const results = Array.isArray(data) ? data : [data];
|
|
183
|
-
|
|
184
|
-
const elapsed = performance.now() - startTime;
|
|
185
|
-
this.updateRetrieveMetrics(elapsed);
|
|
186
|
-
|
|
187
|
-
return results;
|
|
188
|
-
}
|
|
189
|
-
} catch (error: any) {
|
|
190
|
-
console.error('Vector search failed, falling back to SQL:', error.message);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Fallback: Direct SQL query (keyword search)
|
|
194
|
-
const whereConditions = ['1=1'];
|
|
195
|
-
const params: any[] = [];
|
|
196
|
-
|
|
197
|
-
if (options.onlySuccesses) {
|
|
198
|
-
whereConditions.push('success = 1');
|
|
199
|
-
}
|
|
200
|
-
if (options.onlyFailures) {
|
|
201
|
-
whereConditions.push('success = 0');
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Simple keyword matching
|
|
205
|
-
whereConditions.push("task_name LIKE ? OR outcome LIKE ?");
|
|
206
|
-
params.push(`%${query}%`, `%${query}%`);
|
|
207
|
-
|
|
208
|
-
const stmt = this.db.prepare(`
|
|
209
|
-
SELECT
|
|
210
|
-
task_name as task,
|
|
211
|
-
confidence,
|
|
212
|
-
success,
|
|
213
|
-
outcome,
|
|
214
|
-
strategy,
|
|
215
|
-
timestamp
|
|
216
|
-
FROM reflexion_episodes
|
|
217
|
-
WHERE ${whereConditions.join(' AND ')}
|
|
218
|
-
ORDER BY timestamp DESC
|
|
219
|
-
LIMIT ?
|
|
220
|
-
`);
|
|
221
|
-
|
|
222
|
-
const results = stmt.all(...params, k);
|
|
223
|
-
|
|
224
|
-
const elapsed = performance.now() - startTime;
|
|
225
|
-
this.updateRetrieveMetrics(elapsed);
|
|
226
|
-
|
|
227
|
-
return results.map((row: any) => ({
|
|
228
|
-
task: row.task,
|
|
229
|
-
confidence: row.confidence,
|
|
230
|
-
success: row.success === 1,
|
|
231
|
-
outcome: row.outcome,
|
|
232
|
-
strategy: row.strategy,
|
|
233
|
-
timestamp: row.timestamp,
|
|
234
|
-
}));
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
/**
|
|
238
|
-
* Query with context (SQL + CLI hybrid)
|
|
239
|
-
*/
|
|
240
|
-
async queryWithContext(
|
|
241
|
-
query: string,
|
|
242
|
-
options: {
|
|
243
|
-
k?: number;
|
|
244
|
-
minConfidence?: number;
|
|
245
|
-
domain?: string;
|
|
246
|
-
} = {}
|
|
247
|
-
): Promise<{ memories: Memory[]; context?: string }> {
|
|
248
|
-
const { k = 5, minConfidence = 0.0 } = options;
|
|
249
|
-
|
|
250
|
-
const memories = await this.retrieveMemories(query, k, {
|
|
251
|
-
minReward: minConfidence,
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// Generate simple context from results
|
|
255
|
-
let context: string | undefined;
|
|
256
|
-
if (memories.length > 0) {
|
|
257
|
-
const successRate = memories.filter(m => m.success).length / memories.length;
|
|
258
|
-
context = `Found ${memories.length} similar experiences (${(successRate * 100).toFixed(0)}% success rate)`;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
return { memories, context };
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Consolidate skills (direct SQL analysis)
|
|
266
|
-
*/
|
|
267
|
-
async consolidateSkills(options: {
|
|
268
|
-
minAttempts?: number;
|
|
269
|
-
minReward?: number;
|
|
270
|
-
timeWindowDays?: number;
|
|
271
|
-
} = {}): Promise<void> {
|
|
272
|
-
const {
|
|
273
|
-
minAttempts = 3,
|
|
274
|
-
minReward = 0.7,
|
|
275
|
-
timeWindowDays = 7,
|
|
276
|
-
} = options;
|
|
277
|
-
|
|
278
|
-
const timeWindow = Math.floor(Date.now() / 1000) - (timeWindowDays * 24 * 60 * 60);
|
|
279
|
-
|
|
280
|
-
const stmt = this.db.prepare(`
|
|
281
|
-
SELECT
|
|
282
|
-
task_name,
|
|
283
|
-
COUNT(*) as attempts,
|
|
284
|
-
AVG(confidence) as avg_confidence,
|
|
285
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) as success_rate
|
|
286
|
-
FROM reflexion_episodes
|
|
287
|
-
WHERE timestamp >= ?
|
|
288
|
-
GROUP BY task_name
|
|
289
|
-
HAVING attempts >= ? AND avg_confidence >= ?
|
|
290
|
-
ORDER BY success_rate DESC, attempts DESC
|
|
291
|
-
`);
|
|
292
|
-
|
|
293
|
-
const skills = stmt.all(timeWindow, minAttempts, minReward);
|
|
294
|
-
console.error(`šÆ Consolidated ${skills.length} skills from successful episodes`);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
/**
|
|
298
|
-
* Search skills (direct SQL)
|
|
299
|
-
*/
|
|
300
|
-
async searchSkills(
|
|
301
|
-
query: string,
|
|
302
|
-
options: {
|
|
303
|
-
k?: number;
|
|
304
|
-
minSuccessRate?: number;
|
|
305
|
-
sortBy?: 'success_rate' | 'avg_reward' | 'attempts';
|
|
306
|
-
} = {}
|
|
307
|
-
): Promise<any[]> {
|
|
308
|
-
const { k = 5, minSuccessRate = 0.0, sortBy = 'success_rate' } = options;
|
|
309
|
-
|
|
310
|
-
const orderByMap = {
|
|
311
|
-
'success_rate': 'success_rate DESC',
|
|
312
|
-
'avg_reward': 'avg_confidence DESC',
|
|
313
|
-
'attempts': 'attempts DESC',
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
const stmt = this.db.prepare(`
|
|
317
|
-
SELECT
|
|
318
|
-
task_name as name,
|
|
319
|
-
outcome as description,
|
|
320
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) * 1.0 / COUNT(*) as success_rate,
|
|
321
|
-
AVG(confidence) as avg_reward,
|
|
322
|
-
COUNT(*) as attempts,
|
|
323
|
-
MAX(timestamp) as last_used
|
|
324
|
-
FROM reflexion_episodes
|
|
325
|
-
WHERE task_name LIKE ? OR outcome LIKE ?
|
|
326
|
-
GROUP BY task_name
|
|
327
|
-
HAVING success_rate >= ?
|
|
328
|
-
ORDER BY ${orderByMap[sortBy]}
|
|
329
|
-
LIMIT ?
|
|
330
|
-
`);
|
|
331
|
-
|
|
332
|
-
return stmt.all(`%${query}%`, `%${query}%`, minSuccessRate, k);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/**
|
|
336
|
-
* Optimize database
|
|
337
|
-
*/
|
|
338
|
-
async optimize(): Promise<void> {
|
|
339
|
-
console.error('š§ Optimizing database...');
|
|
340
|
-
this.db.pragma('optimize');
|
|
341
|
-
this.db.pragma('wal_checkpoint(TRUNCATE)');
|
|
342
|
-
this.db.exec('VACUUM');
|
|
343
|
-
this.db.exec('ANALYZE');
|
|
344
|
-
console.error('ā
Database optimized');
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
/**
|
|
348
|
-
* Get performance metrics
|
|
349
|
-
*/
|
|
350
|
-
getMetrics() {
|
|
351
|
-
return { ...this.performanceMetrics };
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
/**
|
|
355
|
-
* Get database statistics
|
|
356
|
-
*/
|
|
357
|
-
async getStats(): Promise<any> {
|
|
358
|
-
const stats = this.db.prepare(`
|
|
359
|
-
SELECT
|
|
360
|
-
COUNT(*) as total_episodes,
|
|
361
|
-
SUM(CASE WHEN success = 1 THEN 1 ELSE 0 END) as successful_episodes,
|
|
362
|
-
SUM(CASE WHEN success = 0 THEN 1 ELSE 0 END) as failed_episodes,
|
|
363
|
-
COUNT(DISTINCT task_name) as unique_tasks,
|
|
364
|
-
AVG(confidence) as avg_confidence
|
|
365
|
-
FROM reflexion_episodes
|
|
366
|
-
`).get() || {};
|
|
367
|
-
|
|
368
|
-
return {
|
|
369
|
-
...stats,
|
|
370
|
-
performance: this.performanceMetrics,
|
|
371
|
-
database: {
|
|
372
|
-
path: this.dbPath,
|
|
373
|
-
pageSize: this.db.pragma('page_size', { simple: true }),
|
|
374
|
-
pageCount: this.db.pragma('page_count', { simple: true }),
|
|
375
|
-
journalMode: this.db.pragma('journal_mode', { simple: true }),
|
|
376
|
-
},
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
async close(): Promise<void> {
|
|
381
|
-
if (this.db) {
|
|
382
|
-
this.db.close();
|
|
383
|
-
}
|
|
384
|
-
this.initialized = false;
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
// Private helper methods
|
|
388
|
-
private updateStoreMetrics(elapsed: number): void {
|
|
389
|
-
const { storeCount, avgStoreTime } = this.performanceMetrics;
|
|
390
|
-
this.performanceMetrics.storeCount = storeCount + 1;
|
|
391
|
-
this.performanceMetrics.avgStoreTime =
|
|
392
|
-
(avgStoreTime * storeCount + elapsed) / (storeCount + 1);
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
private updateRetrieveMetrics(elapsed: number): void {
|
|
396
|
-
const { retrieveCount, avgRetrieveTime } = this.performanceMetrics;
|
|
397
|
-
this.performanceMetrics.retrieveCount = retrieveCount + 1;
|
|
398
|
-
this.performanceMetrics.avgRetrieveTime =
|
|
399
|
-
(avgRetrieveTime * retrieveCount + elapsed) / (retrieveCount + 1);
|
|
400
|
-
}
|
|
401
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ROS3 MCP Server
|
|
3
|
-
*
|
|
4
|
-
* Exposes robotics operations as a simplified server
|
|
5
|
-
* with AgentDB reflexion memory integration.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export { ROS3McpServer } from './server.js';
|
|
9
|
-
export { ROS3Interface } from './interface.js';
|
|
10
|
-
export { AgentDBMemory } from './memory.js';
|