@agentic-robotics/mcp 0.1.3 โ†’ 0.2.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.
Files changed (55) hide show
  1. package/dist/benchmark.d.ts +97 -0
  2. package/dist/benchmark.d.ts.map +1 -0
  3. package/dist/benchmark.js +330 -0
  4. package/dist/benchmark.js.map +1 -0
  5. package/dist/cli.d.ts +6 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +79 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/enhanced-memory.d.ts +118 -0
  10. package/dist/enhanced-memory.d.ts.map +1 -0
  11. package/dist/enhanced-memory.js +296 -0
  12. package/dist/enhanced-memory.js.map +1 -0
  13. package/dist/enhanced-server.d.ts +122 -0
  14. package/dist/enhanced-server.d.ts.map +1 -0
  15. package/dist/enhanced-server.js +361 -0
  16. package/dist/enhanced-server.js.map +1 -0
  17. package/dist/flow-orchestrator.d.ts +75 -0
  18. package/dist/flow-orchestrator.d.ts.map +1 -0
  19. package/dist/flow-orchestrator.js +350 -0
  20. package/dist/flow-orchestrator.js.map +1 -0
  21. package/dist/hybrid-benchmark.d.ts +44 -0
  22. package/dist/hybrid-benchmark.d.ts.map +1 -0
  23. package/dist/hybrid-benchmark.js +232 -0
  24. package/dist/hybrid-benchmark.js.map +1 -0
  25. package/dist/hybrid-memory.d.ts +81 -0
  26. package/dist/hybrid-memory.d.ts.map +1 -0
  27. package/dist/hybrid-memory.js +296 -0
  28. package/dist/hybrid-memory.js.map +1 -0
  29. package/dist/index.d.ts +10 -0
  30. package/dist/index.d.ts.map +1 -0
  31. package/dist/index.js +10 -0
  32. package/dist/index.js.map +1 -0
  33. package/dist/interface.d.ts +38 -0
  34. package/dist/interface.d.ts.map +1 -0
  35. package/dist/interface.js +75 -0
  36. package/dist/interface.js.map +1 -0
  37. package/dist/memory.d.ts +52 -0
  38. package/dist/memory.d.ts.map +1 -0
  39. package/dist/memory.js +230 -0
  40. package/dist/memory.js.map +1 -0
  41. package/dist/optimized-benchmark.d.ts +74 -0
  42. package/dist/optimized-benchmark.d.ts.map +1 -0
  43. package/dist/optimized-benchmark.js +231 -0
  44. package/dist/optimized-benchmark.js.map +1 -0
  45. package/dist/server.d.ts +55 -0
  46. package/dist/server.d.ts.map +1 -0
  47. package/dist/server.js +147 -0
  48. package/dist/server.js.map +1 -0
  49. package/package.json +3 -2
  50. package/src/enhanced-server.ts +1 -1
  51. package/src/flow-orchestrator.ts +177 -117
  52. package/src/hybrid-memory.ts +2 -2
  53. package/src/memory.ts +171 -52
  54. package/src/optimized-benchmark.ts +0 -302
  55. package/src/optimized-memory.ts +0 -271
package/src/memory.ts CHANGED
@@ -1,14 +1,11 @@
1
1
  /**
2
2
  * AgentDB Reflexion Memory Integration
3
3
  *
4
- * Enables robot learning from past experiences with 100ยตs retrieval
4
+ * Enables robot learning from past experiences with secure command execution
5
+ * SECURITY: Uses spawn() with argument arrays to prevent command injection
5
6
  */
6
7
 
7
8
  import { spawn } from 'child_process';
8
- import { promisify } from 'util';
9
- import { exec } from 'child_process';
10
-
11
- const execAsync = promisify(exec);
12
9
 
13
10
  export interface Episode {
14
11
  sessionId: string;
@@ -29,11 +26,51 @@ export interface Memory {
29
26
  timestamp: number;
30
27
  }
31
28
 
29
+ /**
30
+ * Helper to safely spawn a command and capture output
31
+ * Prevents command injection by using spawn with argument array
32
+ */
33
+ function spawnAsync(
34
+ command: string,
35
+ args: string[],
36
+ env?: Record<string, string>
37
+ ): Promise<{ stdout: string; stderr: string; code: number }> {
38
+ return new Promise((resolve, reject) => {
39
+ const child = spawn(command, args, {
40
+ env: { ...process.env, ...env },
41
+ shell: false, // Critical: disable shell interpretation
42
+ });
43
+
44
+ let stdout = '';
45
+ let stderr = '';
46
+
47
+ child.stdout?.on('data', (data) => {
48
+ stdout += data.toString();
49
+ });
50
+
51
+ child.stderr?.on('data', (data) => {
52
+ stderr += data.toString();
53
+ });
54
+
55
+ child.on('close', (code) => {
56
+ resolve({ stdout, stderr, code: code || 0 });
57
+ });
58
+
59
+ child.on('error', (error) => {
60
+ reject(error);
61
+ });
62
+ });
63
+ }
64
+
32
65
  export class AgentDBMemory {
33
66
  private dbPath: string;
34
67
  private initialized: boolean = false;
35
68
 
36
69
  constructor(dbPath: string) {
70
+ // Validate dbPath to prevent path traversal
71
+ if (!dbPath || dbPath.includes('..') || dbPath.includes(';') || dbPath.includes('|')) {
72
+ throw new Error('Invalid database path');
73
+ }
37
74
  this.dbPath = dbPath;
38
75
  }
39
76
 
@@ -41,38 +78,64 @@ export class AgentDBMemory {
41
78
  if (this.initialized) return;
42
79
 
43
80
  try {
44
- // Initialize AgentDB database
45
- const { stdout, stderr } = await execAsync(
46
- `npx agentdb init "${this.dbPath}" --dimension 768 --preset medium`
47
- );
81
+ // Initialize AgentDB database - use spawn with argument array for security
82
+ const { stdout, stderr, code } = await spawnAsync('npx', [
83
+ 'agentdb',
84
+ 'init',
85
+ this.dbPath,
86
+ '--dimension',
87
+ '768',
88
+ '--preset',
89
+ 'medium',
90
+ ]);
48
91
 
49
- console.error('AgentDB initialized:', this.dbPath);
50
- this.initialized = true;
92
+ if (code === 0 || stderr.includes('already exists')) {
93
+ console.error('AgentDB initialized:', this.dbPath);
94
+ this.initialized = true;
95
+ } else {
96
+ throw new Error(`Initialization failed: ${stderr}`);
97
+ }
51
98
  } catch (error: any) {
52
99
  // Database might already exist
53
- if (!error.message.includes('already exists')) {
54
- console.error('AgentDB initialization warning:', error.message);
100
+ if (error.message?.includes('already exists')) {
101
+ this.initialized = true;
102
+ } else {
103
+ throw new Error(`Failed to initialize AgentDB: ${error.message}`);
55
104
  }
56
- this.initialized = true;
57
105
  }
58
106
  }
59
107
 
60
108
  async storeEpisode(episode: Episode): Promise<void> {
61
- const cmd = [
62
- 'npx agentdb reflexion store',
63
- `"${episode.sessionId}"`,
64
- `"${episode.taskName}"`,
65
- episode.confidence.toString(),
66
- episode.success.toString(),
67
- episode.outcome ? `"${episode.outcome}"` : '""',
68
- ].join(' ');
109
+ if (!this.initialized) {
110
+ throw new Error('AgentDB not initialized. Call initialize() first.');
111
+ }
69
112
 
70
113
  try {
71
- await execAsync(`AGENTDB_PATH="${this.dbPath}" ${cmd}`);
114
+ // Use spawn with argument array to prevent command injection
115
+ const { code, stderr } = await spawnAsync(
116
+ 'npx',
117
+ [
118
+ 'agentdb',
119
+ 'reflexion',
120
+ 'store',
121
+ episode.sessionId,
122
+ episode.taskName,
123
+ episode.confidence.toString(),
124
+ episode.success.toString(),
125
+ episode.outcome || '',
126
+ ],
127
+ { AGENTDB_PATH: this.dbPath }
128
+ );
129
+
130
+ if (code !== 0) {
131
+ throw new Error(`Command failed: ${stderr}`);
132
+ }
133
+
72
134
  console.error(`Stored episode: ${episode.taskName} (success: ${episode.success})`);
73
135
  } catch (error: any) {
74
- console.error('Error storing episode:', error.message);
75
- throw error;
136
+ const errorMsg = `Failed to store episode "${episode.taskName}": ${error.message}`;
137
+ console.error('Error storing episode:', errorMsg);
138
+ throw new Error(errorMsg); // Throw instead of silently failing
76
139
  }
77
140
  }
78
141
 
@@ -86,27 +149,38 @@ export class AgentDBMemory {
86
149
  synthesizeContext?: boolean;
87
150
  } = {}
88
151
  ): Promise<Memory[]> {
89
- let cmd = `npx agentdb reflexion retrieve "${query}" --k ${k}`;
152
+ if (!this.initialized) {
153
+ throw new Error('AgentDB not initialized. Call initialize() first.');
154
+ }
155
+
156
+ // Build safe argument array
157
+ const args = ['agentdb', 'reflexion', 'retrieve', query, '--k', k.toString()];
90
158
 
91
159
  if (options.minReward !== undefined) {
92
- cmd += ` --min-reward ${options.minReward}`;
160
+ args.push('--min-reward', options.minReward.toString());
93
161
  }
94
162
  if (options.onlySuccesses) {
95
- cmd += ' --only-successes';
163
+ args.push('--only-successes');
96
164
  }
97
165
  if (options.onlyFailures) {
98
- cmd += ' --only-failures';
166
+ args.push('--only-failures');
99
167
  }
100
168
  if (options.synthesizeContext) {
101
- cmd += ' --synthesize-context';
169
+ args.push('--synthesize-context');
102
170
  }
103
171
 
104
172
  try {
105
- const { stdout } = await execAsync(`AGENTDB_PATH="${this.dbPath}" ${cmd}`);
173
+ const { stdout, code, stderr } = await spawnAsync('npx', args, {
174
+ AGENTDB_PATH: this.dbPath,
175
+ });
176
+
177
+ if (code !== 0) {
178
+ throw new Error(`Command failed: ${stderr}`);
179
+ }
106
180
 
107
181
  // Parse JSON output
108
182
  const lines = stdout.trim().split('\n');
109
- const jsonLine = lines.find(line => line.startsWith('[') || line.startsWith('{'));
183
+ const jsonLine = lines.find((line) => line.startsWith('[') || line.startsWith('{'));
110
184
 
111
185
  if (jsonLine) {
112
186
  const data = JSON.parse(jsonLine);
@@ -115,8 +189,8 @@ export class AgentDBMemory {
115
189
 
116
190
  return [];
117
191
  } catch (error: any) {
118
- console.error('Error retrieving memories:', error.message);
119
- return [];
192
+ // Throw error instead of silently returning empty array
193
+ throw new Error(`Failed to retrieve memories for query "${query}": ${error.message}`);
120
194
  }
121
195
  }
122
196
 
@@ -128,21 +202,41 @@ export class AgentDBMemory {
128
202
  domain?: string;
129
203
  } = {}
130
204
  ): Promise<{ memories: Memory[]; context?: string }> {
205
+ if (!this.initialized) {
206
+ throw new Error('AgentDB not initialized. Call initialize() first.');
207
+ }
208
+
131
209
  const { k = 5, minConfidence = 0.0, domain } = options;
132
210
 
133
- let cmd = `npx agentdb query --query "${query}" --k ${k} --min-confidence ${minConfidence}`;
211
+ // Build safe argument array
212
+ const args = [
213
+ 'agentdb',
214
+ 'query',
215
+ '--query',
216
+ query,
217
+ '--k',
218
+ k.toString(),
219
+ '--min-confidence',
220
+ minConfidence.toString(),
221
+ ];
134
222
 
135
223
  if (domain) {
136
- cmd += ` --domain "${domain}"`;
224
+ args.push('--domain', domain);
137
225
  }
138
226
 
139
- cmd += ' --synthesize-context --format json';
227
+ args.push('--synthesize-context', '--format', 'json');
140
228
 
141
229
  try {
142
- const { stdout } = await execAsync(`AGENTDB_PATH="${this.dbPath}" ${cmd}`);
230
+ const { stdout, code, stderr } = await spawnAsync('npx', args, {
231
+ AGENTDB_PATH: this.dbPath,
232
+ });
233
+
234
+ if (code !== 0) {
235
+ throw new Error(`Command failed: ${stderr}`);
236
+ }
143
237
 
144
238
  const lines = stdout.trim().split('\n');
145
- const jsonLine = lines.find(line => line.startsWith('[') || line.startsWith('{'));
239
+ const jsonLine = lines.find((line) => line.startsWith('[') || line.startsWith('{'));
146
240
 
147
241
  if (jsonLine) {
148
242
  const data = JSON.parse(jsonLine);
@@ -154,8 +248,8 @@ export class AgentDBMemory {
154
248
 
155
249
  return { memories: [] };
156
250
  } catch (error: any) {
157
- console.error('Error querying with context:', error.message);
158
- return { memories: [] };
251
+ // Throw error instead of silently returning empty array
252
+ throw new Error(`Failed to query with context "${query}": ${error.message}`);
159
253
  }
160
254
  }
161
255
 
@@ -164,29 +258,54 @@ export class AgentDBMemory {
164
258
  minReward?: number;
165
259
  timeWindowDays?: number;
166
260
  } = {}): Promise<void> {
167
- const {
168
- minAttempts = 3,
169
- minReward = 0.7,
170
- timeWindowDays = 7,
171
- } = options;
261
+ if (!this.initialized) {
262
+ throw new Error('AgentDB not initialized. Call initialize() first.');
263
+ }
172
264
 
173
- const cmd = `npx agentdb skill consolidate ${minAttempts} ${minReward} ${timeWindowDays} true`;
265
+ const { minAttempts = 3, minReward = 0.7, timeWindowDays = 7 } = options;
174
266
 
175
267
  try {
176
- await execAsync(`AGENTDB_PATH="${this.dbPath}" ${cmd}`);
268
+ const { code, stderr } = await spawnAsync(
269
+ 'npx',
270
+ [
271
+ 'agentdb',
272
+ 'skill',
273
+ 'consolidate',
274
+ minAttempts.toString(),
275
+ minReward.toString(),
276
+ timeWindowDays.toString(),
277
+ 'true',
278
+ ],
279
+ { AGENTDB_PATH: this.dbPath }
280
+ );
281
+
282
+ if (code !== 0) {
283
+ throw new Error(`Command failed: ${stderr}`);
284
+ }
285
+
177
286
  console.error('Skills consolidated from successful episodes');
178
287
  } catch (error: any) {
179
- console.error('Error consolidating skills:', error.message);
288
+ throw new Error(`Failed to consolidate skills: ${error.message}`);
180
289
  }
181
290
  }
182
291
 
183
292
  async getStats(): Promise<any> {
293
+ if (!this.initialized) {
294
+ throw new Error('AgentDB not initialized. Call initialize() first.');
295
+ }
296
+
184
297
  try {
185
- const { stdout } = await execAsync(`AGENTDB_PATH="${this.dbPath}" npx agentdb db stats`);
298
+ const { stdout, code, stderr } = await spawnAsync('npx', ['agentdb', 'db', 'stats'], {
299
+ AGENTDB_PATH: this.dbPath,
300
+ });
301
+
302
+ if (code !== 0) {
303
+ throw new Error(`Command failed: ${stderr}`);
304
+ }
305
+
186
306
  return { stats: stdout.trim() };
187
307
  } catch (error: any) {
188
- console.error('Error getting stats:', error.message);
189
- return { stats: 'unavailable' };
308
+ throw new Error(`Failed to get stats: ${error.message}`);
190
309
  }
191
310
  }
192
311
 
@@ -1,302 +0,0 @@
1
- /**
2
- * Optimized Benchmark Suite
3
- *
4
- * Uses JavaScript APIs directly for accurate performance measurement
5
- */
6
-
7
- import { OptimizedAgentDBMemory } from './optimized-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
- interface BenchmarkSuite {
24
- agentdb: {
25
- storeEpisode: BenchmarkResult;
26
- retrieveMemories: BenchmarkResult;
27
- queryWithContext: BenchmarkResult;
28
- consolidateSkills: BenchmarkResult;
29
- searchSkills: BenchmarkResult;
30
- };
31
- overall: {
32
- totalTime: number;
33
- timestamp: string;
34
- };
35
- }
36
-
37
- export class OptimizedBenchmark {
38
- private memory: OptimizedAgentDBMemory;
39
-
40
- constructor() {
41
- this.memory = new OptimizedAgentDBMemory('./optimized-benchmark.db');
42
- }
43
-
44
- async initialize(): Promise<void> {
45
- console.log('๐Ÿ Initializing optimized benchmark suite...\n');
46
- await this.memory.initialize();
47
- console.log('โœ… Benchmark suite ready\n');
48
- }
49
-
50
- /**
51
- * Run complete benchmark suite
52
- */
53
- async runAll(): Promise<BenchmarkSuite> {
54
- const suiteStartTime = Date.now();
55
-
56
- console.log('โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”');
57
- console.log('โ”‚ Optimized Integration Benchmark Suite โ”‚');
58
- console.log('โ”‚ AgentDB JavaScript API Performance Test โ”‚');
59
- console.log('โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n');
60
-
61
- // AgentDB Benchmarks with JS API
62
- console.log('๐Ÿ“Š AGENTDB BENCHMARKS (JS API)\n');
63
-
64
- const storeEpisode = await this.benchmarkStoreEpisode(1000);
65
- this.printResult('Store Episode', storeEpisode);
66
-
67
- const retrieveMemories = await this.benchmarkRetrieveMemories(500);
68
- this.printResult('Retrieve Memories', retrieveMemories);
69
-
70
- const queryWithContext = await this.benchmarkQueryWithContext(300);
71
- this.printResult('Query with Context', queryWithContext);
72
-
73
- const consolidateSkills = await this.benchmarkConsolidateSkills(10);
74
- this.printResult('Consolidate Skills', consolidateSkills);
75
-
76
- const searchSkills = await this.benchmarkSearchSkills(200);
77
- this.printResult('Search Skills', searchSkills);
78
-
79
- const totalTime = Date.now() - suiteStartTime;
80
-
81
- console.log('\nโ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”');
82
- console.log('โ”‚ BENCHMARK COMPLETE โ”‚');
83
- console.log(`โ”‚ Total Time: ${(totalTime / 1000).toFixed(2)}s โ”‚`);
84
- console.log('โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜\n');
85
-
86
- // Print performance metrics
87
- const metrics = this.memory.getMetrics();
88
- console.log('๐Ÿ“ˆ PERFORMANCE METRICS\n');
89
- console.log(` Store Operations: ${metrics.storeCount}`);
90
- console.log(` Avg Store Time: ${metrics.avgStoreTime.toFixed(3)}ms`);
91
- console.log(` Retrieve Operations: ${metrics.retrieveCount}`);
92
- console.log(` Avg Retrieve Time: ${metrics.avgRetrieveTime.toFixed(3)}ms\n`);
93
-
94
- return {
95
- agentdb: {
96
- storeEpisode,
97
- retrieveMemories,
98
- queryWithContext,
99
- consolidateSkills,
100
- searchSkills,
101
- },
102
- overall: {
103
- totalTime,
104
- timestamp: new Date().toISOString(),
105
- },
106
- };
107
- }
108
-
109
- /**
110
- * Benchmark: Store Episode (JS API)
111
- */
112
- private async benchmarkStoreEpisode(iterations: number): Promise<BenchmarkResult> {
113
- const times: number[] = [];
114
-
115
- for (let i = 0; i < iterations; i++) {
116
- const episode: Episode = {
117
- sessionId: `bench-${i}`,
118
- taskName: 'navigation',
119
- confidence: Math.random(),
120
- success: Math.random() > 0.3,
121
- outcome: 'Completed navigation task',
122
- strategy: 'adaptive_planning',
123
- metadata: { x: i, y: i * 2, latency: Math.random() * 100 },
124
- };
125
-
126
- const start = performance.now();
127
- await this.memory.storeEpisode(episode);
128
- times.push(performance.now() - start);
129
-
130
- if (i % 100 === 0 && i > 0) {
131
- process.stderr.write(` Progress: ${i}/${iterations}\r`);
132
- }
133
- }
134
-
135
- return this.calculateStats('Store Episode', times);
136
- }
137
-
138
- /**
139
- * Benchmark: Retrieve Memories (JS API)
140
- */
141
- private async benchmarkRetrieveMemories(iterations: number): Promise<BenchmarkResult> {
142
- const times: number[] = [];
143
-
144
- const queries = [
145
- 'navigation task',
146
- 'object detection',
147
- 'path planning',
148
- 'sensor fusion',
149
- 'motor control',
150
- ];
151
-
152
- for (let i = 0; i < iterations; i++) {
153
- const query = queries[i % queries.length];
154
-
155
- const start = performance.now();
156
- await this.memory.retrieveMemories(query, 5, {
157
- onlySuccesses: true,
158
- synthesizeContext: true,
159
- });
160
- times.push(performance.now() - start);
161
-
162
- if (i % 50 === 0 && i > 0) {
163
- process.stderr.write(` Progress: ${i}/${iterations}\r`);
164
- }
165
- }
166
-
167
- return this.calculateStats('Retrieve Memories', times);
168
- }
169
-
170
- /**
171
- * Benchmark: Query with Context (JS API)
172
- */
173
- private async benchmarkQueryWithContext(iterations: number): Promise<BenchmarkResult> {
174
- const times: number[] = [];
175
-
176
- for (let i = 0; i < iterations; i++) {
177
- const start = performance.now();
178
- await this.memory.queryWithContext('warehouse navigation', {
179
- k: 10,
180
- minConfidence: 0.5,
181
- synthesizeReasoning: true,
182
- });
183
- times.push(performance.now() - start);
184
-
185
- if (i % 30 === 0 && i > 0) {
186
- process.stderr.write(` Progress: ${i}/${iterations}\r`);
187
- }
188
- }
189
-
190
- return this.calculateStats('Query with Context', times);
191
- }
192
-
193
- /**
194
- * Benchmark: Consolidate Skills (JS API)
195
- */
196
- private async benchmarkConsolidateSkills(iterations: number): Promise<BenchmarkResult> {
197
- const times: number[] = [];
198
-
199
- for (let i = 0; i < iterations; i++) {
200
- const start = performance.now();
201
- await this.memory.consolidateSkills({
202
- minAttempts: 3,
203
- minReward: 0.7,
204
- timeWindowDays: 7,
205
- enablePruning: true,
206
- });
207
- times.push(performance.now() - start);
208
-
209
- if (i % 2 === 0 && i > 0) {
210
- process.stderr.write(` Progress: ${i}/${iterations}\r`);
211
- }
212
- }
213
-
214
- return this.calculateStats('Consolidate Skills', times);
215
- }
216
-
217
- /**
218
- * Benchmark: Search Skills (JS API)
219
- */
220
- private async benchmarkSearchSkills(iterations: number): Promise<BenchmarkResult> {
221
- const times: number[] = [];
222
-
223
- for (let i = 0; i < iterations; i++) {
224
- const start = performance.now();
225
- await this.memory.searchSkills('navigation', {
226
- k: 5,
227
- minSuccessRate: 0.5,
228
- sortBy: 'success_rate',
229
- });
230
- times.push(performance.now() - start);
231
-
232
- if (i % 20 === 0 && i > 0) {
233
- process.stderr.write(` Progress: ${i}/${iterations}\r`);
234
- }
235
- }
236
-
237
- return this.calculateStats('Search Skills', times);
238
- }
239
-
240
- /**
241
- * Calculate statistics from timing data
242
- */
243
- private calculateStats(name: string, times: number[]): BenchmarkResult {
244
- const sorted = [...times].sort((a, b) => a - b);
245
- const total = times.reduce((a, b) => a + b, 0);
246
-
247
- return {
248
- name,
249
- iterations: times.length,
250
- totalTime: total,
251
- avgTime: total / times.length,
252
- minTime: sorted[0],
253
- maxTime: sorted[sorted.length - 1],
254
- opsPerSec: (times.length / total) * 1000,
255
- p50: sorted[Math.floor(sorted.length * 0.50)],
256
- p95: sorted[Math.floor(sorted.length * 0.95)],
257
- p99: sorted[Math.floor(sorted.length * 0.99)],
258
- };
259
- }
260
-
261
- /**
262
- * Print benchmark result
263
- */
264
- private printResult(name: string, result: BenchmarkResult): void {
265
- console.log(`${name}:`);
266
- console.log(` Iterations: ${result.iterations.toLocaleString()}`);
267
- console.log(` Avg Time: ${result.avgTime.toFixed(3)}ms`);
268
- console.log(` Min/Max: ${result.minTime.toFixed(3)}ms / ${result.maxTime.toFixed(3)}ms`);
269
- console.log(` p50/p95/p99: ${result.p50.toFixed(3)}ms / ${result.p95.toFixed(3)}ms / ${result.p99.toFixed(3)}ms`);
270
- console.log(` Ops/sec: ${result.opsPerSec.toFixed(0)}`);
271
- console.log('');
272
- }
273
-
274
- /**
275
- * Export results to JSON
276
- */
277
- async exportResults(suite: BenchmarkSuite, filename: string): Promise<void> {
278
- const fs = await import('fs/promises');
279
- await fs.writeFile(filename, JSON.stringify(suite, null, 2));
280
- console.log(`๐Ÿ“ Results exported to ${filename}`);
281
- }
282
-
283
- async close(): Promise<void> {
284
- await this.memory.close();
285
- }
286
- }
287
-
288
- // CLI entry point
289
- if (import.meta.url === `file://${process.argv[1]}`) {
290
- const benchmark = new OptimizedBenchmark();
291
-
292
- try {
293
- await benchmark.initialize();
294
- const results = await benchmark.runAll();
295
- await benchmark.exportResults(results, './optimized-benchmark-results.json');
296
- } catch (error) {
297
- console.error('โŒ Benchmark failed:', error);
298
- process.exit(1);
299
- } finally {
300
- await benchmark.close();
301
- }
302
- }