adaptive-memory-multi-model-router 2.2.5 → 2.2.6

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 (63) hide show
  1. package/README.md +17 -22
  2. package/README.md.bak +836 -0
  3. package/dist/analytics/costAnalytics.d.ts +1 -0
  4. package/dist/cache/cacheKeyGenerator.d.ts +67 -0
  5. package/dist/cache/cacheKeyGenerator.d.ts.map +1 -0
  6. package/dist/cache/cacheKeyGenerator.js +211 -0
  7. package/dist/cache/cacheKeyGenerator.js.map +1 -0
  8. package/dist/cache/semanticCache.d.ts +41 -0
  9. package/dist/cache/semanticCache.d.ts.map +1 -1
  10. package/dist/cache/semanticCache.js +142 -0
  11. package/dist/cache/semanticCache.js.map +1 -1
  12. package/dist/cli.js +35 -478
  13. package/dist/cost/costTracker.js +0 -3
  14. package/dist/cost/preCallCostEstimator.d.ts +114 -0
  15. package/dist/cost/preCallCostEstimator.d.ts.map +1 -0
  16. package/dist/cost/preCallCostEstimator.js +256 -0
  17. package/dist/cost/preCallCostEstimator.js.map +1 -0
  18. package/dist/index.d.ts +16 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +264 -64
  21. package/dist/index.js.map +1 -1
  22. package/dist/inference/speculativeDecoding.d.ts +133 -0
  23. package/dist/inference/speculativeDecoding.d.ts.map +1 -0
  24. package/dist/inference/speculativeDecoding.js +276 -0
  25. package/dist/inference/speculativeDecoding.js.map +1 -0
  26. package/dist/integrations/langchainAdapter.d.ts +1 -0
  27. package/dist/integrations/oauth.d.ts +1 -0
  28. package/dist/memory/autoFetch.d.ts +1 -0
  29. package/dist/memory/memoryTree.d.ts +1 -0
  30. package/dist/memory/obsidianVault.d.ts +1 -0
  31. package/dist/providers/providerConfig.d.ts +1 -0
  32. package/dist/providers/providerConfig.js +2 -0
  33. package/dist/providers/providerHealth.d.ts +117 -0
  34. package/dist/providers/providerHealth.d.ts.map +1 -0
  35. package/dist/providers/providerHealth.js +309 -0
  36. package/dist/providers/providerHealth.js.map +1 -0
  37. package/dist/providers/registry.js +126 -128
  38. package/dist/routing/advancedRouter.js +310 -427
  39. package/dist/routing/difficultyClassifier.d.ts +79 -0
  40. package/dist/routing/difficultyClassifier.d.ts.map +1 -0
  41. package/dist/routing/difficultyClassifier.js +329 -0
  42. package/dist/routing/difficultyClassifier.js.map +1 -0
  43. package/dist/sdk.d.ts +125 -0
  44. package/dist/sdk.d.ts.map +1 -0
  45. package/dist/sdk.js +109 -100
  46. package/dist/sdk.js.map +1 -0
  47. package/dist/security/guardrails.d.ts +1 -0
  48. package/dist/server/dashboard.d.ts +1 -0
  49. package/dist/server/modelMapper.d.ts +1 -0
  50. package/dist/server/proxyServer.d.ts +1 -0
  51. package/package.json +4 -2
  52. package/src/cache/cacheKeyGenerator.ts +242 -0
  53. package/src/cache/semanticCache.ts +148 -0
  54. package/src/cost/preCallCostEstimator.ts +345 -0
  55. package/src/inference/speculativeDecoding.ts +373 -0
  56. package/src/providers/providerHealth.ts +397 -0
  57. package/src/routing/difficultyClassifier.ts +420 -0
  58. package/test/provider-test.js +2 -2
  59. package/test.js +7 -7
  60. package/test.js.bak +376 -0
  61. package/tsconfig.json +15 -5
  62. package/src/index.ts +0 -99
  63. package/src/skills/__tests__/skill_manager.test.ts +0 -328
package/dist/cli.js CHANGED
@@ -1,502 +1,59 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * A3M Router CLI - Adaptive Memory Multi-Model Router
4
- *
5
- * Commands:
6
- * npx a3m-router serve [--port 8787] Start OpenAI-compatible proxy server
7
- * npx a3m-router route <query> Route query to best provider
8
- * npx a3m-router batch <q1> <q2>.. Route multiple queries
9
- * npx a3m-router providers List all configured providers
10
- * npx a3m-router test Test all providers
11
- * npx a3m-router compare <query> Compare providers side by side
12
- * npx a3m-router benchmark Benchmark all providers
13
- * npx a3m-router recommend <task> Get model recommendation
14
- * npx a3m-router cost <text> Estimate token cost
15
- * npx a3m-router token <text> Count tokens
16
- * npx a3m-router models List known models
17
- * npx a3m-router memory add/search/stats Memory operations
18
- * npx a3m-router status Show router status
3
+ * TMLPD PI CLI
19
4
  */
20
5
 
21
- const { execSync } = require('child_process');
22
- const {
23
- createA3MRouter, routeQuery, routeBatch, recommendForTask,
24
- countTokens, estimateCost, MODEL_COSTS, CostTracker, MemoryTree,
25
- getAvailableProviders, providerConfig, registerProvider, loadProviders,
26
- } = require('./index.js');
27
-
28
- let createProxyServer;
29
- try {
30
- createProxyServer = require('./server/proxyServer.js').createProxyServer;
31
- } catch (e) {
32
- // Server module not yet compiled
33
- }
6
+ const { createTMLPD } = require("./dist/index.js");
34
7
 
35
8
  const args = process.argv.slice(2);
36
9
  const command = args[0];
37
10
 
38
- // ============================================================
39
- // HELPER FUNCTIONS
40
- // ============================================================
41
-
42
- function formatRoute(result) {
43
- console.log('\n🔀 A3M Router — Route Result');
44
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
45
- console.log(' Primary: ' + result.primary_model);
46
- if (result.fallback_models) {
47
- console.log(' Fallbacks: ' + result.fallback_models.join(', '));
48
- }
49
- if (result.estimated_cost) {
50
- console.log(' Est. Cost: $' + result.estimated_cost.toFixed(6));
51
- }
52
- if (result.provider_type) {
53
- console.log(' Type: ' + result.provider_type);
54
- }
55
- if (result.reasoning) {
56
- console.log(' Reason: ' + result.reasoning);
57
- showStarPrompt();
58
- }
59
- console.log('');
60
- }
61
-
62
-
63
- // ============================================================
64
- // STAR PROMPT (shown once per user)
65
- // ============================================================
66
- function showStarPrompt() {
67
- const fs = require('fs');
68
- const path = require('path');
69
- const home = process.env.HOME || process.env.USERPROFILE || '/tmp';
70
- const marker = path.join(home, '.a3m-router', '.star-prompt-shown');
71
-
72
- try {
73
- // Only show once
74
- if (fs.existsSync(marker)) return;
75
-
76
- // Create directory if needed
77
- const dir = path.dirname(marker);
78
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
79
-
80
- console.log('');
81
- console.log(' \x1b[2m── ────────────────────────────────────────\x1b[0m');
82
- console.log(' \x1b[2m⭐ Found this useful? Star us on GitHub:\x1b[0m');
83
- console.log(' \x1b[1m\x1b[36m https://github.com/Das-rebel/adaptive-memory-multi-model-router\x1b[0m');
84
- console.log(' \x1b[2m── ────────────────────────────────────────\x1b[0m');
85
- console.log('');
86
-
87
- // Mark as shown
88
- fs.writeFileSync(marker, new Date().toISOString());
89
- } catch (e) {
90
- // Silently fail - don't break CLI for this
91
- }
92
- }
93
-
94
- async function callProvider(providerId, model, prompt, maxTokens) {
95
- providerId = providerId || 'groq';
96
- model = model || 'llama-3.3-70b-versatile';
97
- maxTokens = maxTokens || 50;
98
-
99
- const providers = providerConfig.getAvailableProviders();
100
- const provider = providers[providerId];
101
-
102
- if (!provider) {
103
- console.error(' ❌ Provider "' + providerId + '" not found or not configured.');
104
- console.error(' Run: npx a3m-router providers');
105
- return null;
106
- }
107
-
108
- const startTime = Date.now();
109
-
110
- if (provider.type === 'cli') {
111
- try {
112
- if (providerId === 'commandcode') {
113
- const raw = execSync('commandcode -p "' + prompt.replace(/"/g, '\\"') + '" --skip-onboarding 2>&1', { timeout: 60000, encoding: 'utf-8' });
114
- const content = raw.replace(/\x1b\[[0-9;]*m/g, '').trim();
115
- return { content: content.substring(0, 200), totalTokens: Math.ceil(content.length / 4), cost: 0, latency: Date.now() - startTime };
116
- } else {
117
- const raw = execSync(provider.cliCommand + ' run "' + prompt.replace(/"/g, '\\"') + '" 2>&1', { timeout: 60000, encoding: 'utf-8' });
118
- const lines = raw.replace(/\x1b\[[0-9;]*m/g, '').split('\n').filter(l => l.trim() && !l.startsWith('>') && !l.includes('build'));
119
- const content = lines.join(' ').trim();
120
- return { content: content.substring(0, 200), totalTokens: Math.ceil(content.length / 4), cost: 0, latency: Date.now() - startTime };
121
- }
122
- } catch (e) {
123
- console.error(' ❌ ' + provider.name + ' error: ' + e.message.substring(0, 80));
124
- return null;
125
- }
126
- }
127
-
128
- // API provider
129
- try {
130
- const resp = await fetch(provider.baseUrl, {
131
- method: 'POST',
132
- headers: { 'Authorization': 'Bearer ' + provider.apiKey, 'Content-Type': 'application/json' },
133
- body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }], max_tokens: maxTokens }),
134
- });
135
- const data = await resp.json();
136
- const latency = Date.now() - startTime;
137
- if (data.error) {
138
- console.error(' ❌ ' + provider.name + ' error: ' + data.error.message.substring(0, 80));
139
- return null;
140
- }
141
- const tokens = data.usage || {};
142
- const cost = (tokens.prompt_tokens || 0) / 1000 * provider.costPerK.input + (tokens.completion_tokens || 0) / 1000 * provider.costPerK.output;
143
- return { content: data.choices[0].message.content.trim(), totalTokens: tokens.total_tokens || 0, cost, latency, model: data.model || model };
144
- } catch (e) {
145
- console.error(' ❌ ' + provider.name + ' error: ' + e.message.substring(0, 80));
146
- return null;
147
- }
148
- }
149
-
150
- // ============================================================
151
- // COMMANDS
152
- // ============================================================
153
-
154
11
  async function main() {
155
- const router = createA3MRouter({ memory: { maxSize: 1000 } });
156
-
157
12
  switch (command) {
158
- case 'providers': {
159
- const providers = providerConfig.getAvailableProviders();
160
- const allProviders = providerConfig._providers;
161
-
162
- console.log('\n📡 A3M Router — Provider Configuration');
163
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
164
- console.log(' Config: ~/.config/a3m-router/providers.json');
165
- console.log(' Add your own: npx a3m-router register <id> <config>');
166
- console.log('');
167
- console.log(' Provider Type Models Priority Key');
168
- console.log(' ───────────────────── ─────── ────── ──────── ─────────');
169
-
170
- for (const [id, provider] of Object.entries(allProviders)) {
171
- const available = providers[id];
172
- const status = available ? '✅' : '❌';
173
- const keyStatus = provider.apiKey ? '✅' : (provider.type === 'cli' ? 'N/A' : '❌');
174
- const modelCount = provider.models ? provider.models.length : 0;
175
- console.log(' ' + status + ' ' + (provider.name || id).padEnd(20) + ' ' + (provider.type || 'api').padEnd(7) + ' ' + String(modelCount).padEnd(6) + ' ' + String(provider.priority).padEnd(9) + ' ' + keyStatus);
176
- }
177
- console.log('');
178
- console.log(' Available: ' + Object.keys(providers).length + ' providers');
179
- console.log(' Configured: ' + Object.keys(allProviders).length + ' providers');
180
- console.log('');
181
- break;
182
- }
183
-
184
- case 'test': {
185
- const providers = providerConfig.getAvailableProviders();
186
- console.log('\n🧪 A3M Router — Provider Health Check');
187
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
188
-
189
- for (const [id, provider] of Object.entries(providers)) {
190
- const model = provider.models[0];
191
- console.log(' Testing ' + (provider.name || id) + ' (' + model + ')...');
192
- const result = await callProvider(id, model, 'Say OK', 5);
193
- if (result) {
194
- console.log(' ✅ Response: "' + result.content.substring(0, 30) + '" (' + result.totalTokens + ' tok, ' + result.latency + 'ms, $' + result.cost.toFixed(6) + ')');
195
- }
196
- console.log('');
197
- }
198
- break;
199
- }
200
-
201
- case 'compare': {
202
- const query = args.slice(1).join(' ');
203
- if (!query) {
204
- console.error('Usage: npx a3m-router compare "your query here"');
205
- process.exit(1);
206
- }
207
-
208
- const providers = providerConfig.getAvailableProviders();
209
- console.log('\n🔄 A3M Router — Provider Comparison');
210
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
211
- console.log(' Query: "' + query + '"');
212
- console.log('');
213
-
214
- const results = [];
215
- for (const [id, provider] of Object.entries(providers)) {
216
- const model = provider.models[0];
217
- console.log(' Testing ' + (provider.name || id) + '...');
218
- const result = await callProvider(id, model, query, 100);
219
- if (result) {
220
- results.push({ id: provider.name || id, model, ...result });
221
- }
222
- }
223
-
224
- console.log('\n Comparison:');
225
- console.log(' ──────────────────────────────────────────────────────────────');
226
- console.log(' Provider'.padEnd(18) + 'Response'.padEnd(40) + 'Time'.padEnd(12) + 'Cost');
227
- console.log(' ──────────────────────────────────────────────────────────────');
228
- for (const r of results) {
229
- console.log(' ' + r.id.padEnd(16) + r.content.substring(0, 38).padEnd(40) + (r.latency + 'ms').padEnd(12) + '$' + r.cost.toFixed(6));
230
- }
231
- console.log('');
232
- break;
233
- }
234
-
235
- case 'benchmark': {
236
- const queries = [
237
- 'What is 2+2?',
238
- 'Write a Python function to reverse a string.',
239
- 'Translate "Hello" to French.',
240
- 'Write a haiku about programming.',
241
- 'What is SQL injection?',
242
- ];
243
-
244
- const providers = providerConfig.getAvailableProviders();
245
- console.log('\n📊 A3M Router — Provider Benchmark');
246
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
247
-
248
- for (const [id, provider] of Object.entries(providers)) {
249
- const model = provider.models[0];
250
- console.log(' ' + (provider.name || id).padEnd(15) + '(' + model + ')');
251
-
252
- let totalTime = 0;
253
- let totalCost = 0;
254
-
255
- for (const q of queries) {
256
- const r = await callProvider(id, model, q, 50);
257
- if (r) {
258
- totalTime += r.latency;
259
- totalCost += r.cost;
260
- }
261
- }
262
-
263
- console.log(' Total: ' + totalTime + 'ms, Cost: $' + totalCost.toFixed(6) + ', Avg: ' + (totalTime / queries.length).toFixed(0) + 'ms/query');
264
- }
265
- console.log('');
266
- break;
267
- }
268
-
269
- case 'route': {
270
- const query = args.slice(1).join(' ');
271
- if (!query) {
272
- console.error('Usage: npx a3m-router route "your query here"');
273
- process.exit(1);
274
- }
275
- const result = router.route(query);
276
- formatRoute(result);
277
- break;
278
- }
279
-
280
- case 'batch': {
281
- const queries = args.slice(1);
282
- if (queries.length === 0) {
283
- console.error('Usage: npx a3m-router batch "query1" "query2" ...');
284
- process.exit(1);
285
- }
286
- const results = router.routeBatch(queries);
287
- console.log('\n🔀 A3M Router — Batch Results');
288
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
289
- results.forEach(function(r, i) {
290
- console.log(' ' + (i + 1) + '. "' + queries[i].substring(0, 40) + '..." → ' + r.primary_model);
291
- });
292
- console.log('');
293
- break;
294
- }
295
-
296
- case 'recommend': {
297
- const task = args.slice(1).join(' ');
298
- if (!task) {
299
- console.error('Usage: npx a3m-router recommend "coding"');
300
- process.exit(1);
301
- }
302
- const rec = router.recommend(task);
303
- console.log('\n🎯 A3M Router — Recommendation');
304
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
305
- console.log(JSON.stringify(rec, null, 2));
306
- console.log('');
307
- break;
308
- }
309
-
310
- case 'status': {
311
- const providers = providerConfig.getAvailableProviders();
312
- console.log('\n📊 A3M Router — Status');
313
- console.log('━━━━━━━━━━━━━━━━━━━━━━');
314
- console.log(' Version: 1.9.0');
315
- console.log(' Exports: 74');
316
- console.log(' Providers: ' + Object.keys(providers).length + ' configured');
317
- console.log(' Integrations: 116');
318
- console.log(' Keywords: 139');
319
- console.log(' Subpaths: 11');
320
- console.log(' Memory: ✅ MemoryTree + AutoFetch + ObsidianVault');
321
- console.log(' Compression: ✅ Enhanced + ISON');
322
- console.log(' Auth: ✅ OAuth 2.0 + PKCE');
323
- console.log(' Cost: ✅ Tracking + Budgets');
324
- console.log(' Cache: ✅ Prefix + Response');
325
- console.log(' Routing: ✅ RouteLLM + Adaptive');
326
- console.log(' Models known: ' + Object.keys(providerConfig._providers).length);
327
- console.log('');
328
- console.log(' Available Providers:');
329
- for (const [id, p] of Object.entries(providers)) {
330
- console.log(' ✅ ' + (p.name || id).padEnd(15) + '(' + p.models.length + ' models, type: ' + p.type + ')');
331
- }
332
- console.log('');
333
- break;
334
- }
335
-
336
- case 'cost': {
337
- const text = args.slice(1).join(' ') || 'Hello world this is a test';
338
- const tokens = countTokens(text);
339
- var completionTokens = Math.ceil(tokens * 1.5);
340
- var gpt4oCost = estimateCost(tokens, completionTokens, 'gpt-4o');
341
- var miniCost = estimateCost(tokens, completionTokens, 'gpt-4o-mini');
342
- var haikuCost = estimateCost(tokens, completionTokens, 'claude-3-haiku');
343
- var geminiCost = estimateCost(tokens, completionTokens, 'gemini-2.0-flash');
344
- console.log('\n💰 A3M Router — Cost Estimate');
345
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
346
- console.log(' Text: "' + text.substring(0, 50) + '"');
347
- console.log(' Tokens: ' + tokens);
348
- console.log(' GPT-4o: $' + gpt4oCost.toFixed(6));
349
- console.log(' GPT-4o-mini: $' + miniCost.toFixed(6));
350
- console.log(' Claude Haiku: $' + haikuCost.toFixed(6));
351
- console.log(' Gemini Flash: $' + geminiCost.toFixed(6));
352
- if (gpt4oCost > 0) {
353
- var savings = ((1 - miniCost / gpt4oCost) * 100).toFixed(1);
354
- console.log(' Savings: ' + savings + '% (mini vs GPT-4o)');
355
- }
356
- console.log('');
357
- break;
358
- }
359
-
360
- case 'models': {
361
- const allProviders = providerConfig._providers;
362
- console.log('\n📋 A3M Router — All Known Models');
363
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
364
-
365
- for (const [id, provider] of Object.entries(allProviders)) {
366
- if (!provider.models || provider.models.length === 0) continue;
367
- console.log(' ' + (provider.name || id).padEnd(15) + '(Priority: ' + provider.priority + ', Type: ' + provider.type + ')');
368
- for (const m of provider.models) {
369
- const cost = provider.costPerK;
370
- console.log(' ' + m.padEnd(40) + 'in:$' + (cost ? cost.input : 0) + ' out:$' + (cost ? cost.output : 0));
371
- }
372
- console.log('');
373
- }
13
+ case "execute": {
14
+ const tmlpd = createTMLPD();
15
+ const prompt = args.slice(1).join(" ");
16
+ const result = await tmlpd.execute(prompt);
17
+ console.log(JSON.stringify(result, null, 2));
374
18
  break;
375
19
  }
376
-
377
- case 'token': {
378
- const text = args.slice(1).join(' ');
379
- if (!text) {
380
- console.error('Usage: npx a3m-router token "your text here"');
381
- process.exit(1);
382
- }
383
- const tokens = countTokens(text);
384
- console.log(' "' + text + '" → ' + tokens + ' tokens');
20
+ case "parallel": {
21
+ const tmlpd = createTMLPD();
22
+ const models = args.slice(1).join(" ").split(",").map(m => m.trim());
23
+ const prompt = "Compare these models";
24
+ const result = await tmlpd.executeParallel(prompt, models);
25
+ console.log(JSON.stringify(result, null, 2));
385
26
  break;
386
27
  }
387
-
388
- case 'register': {
389
- const id = args[1];
390
- const config = JSON.parse(args.slice(2).join(' '));
391
- registerProvider(id, config);
392
- providerConfig.saveConfig();
393
- console.log('✅ Registered provider: ' + id);
394
- console.log(' Config saved to: ~/.config/a3m-router/providers.json');
28
+ case "cost": {
29
+ const tmlpd = createTMLPD();
30
+ const summary = tmlpd.getCostSummary();
31
+ console.log(JSON.stringify(summary, null, 2));
395
32
  break;
396
33
  }
397
-
398
- case 'memory': {
399
- const subcmd = args[1];
400
- if (subcmd === 'add') {
401
- const text = args.slice(2).join(' ');
402
- router.memory.add(text, { metadata: { cli: true } });
403
- console.log(' ✅ Added to memory: "' + text.substring(0, 50) + '"');
404
- } else if (subcmd === 'search') {
405
- const query = args.slice(2).join(' ');
406
- const results = router.memory.search(query);
407
- console.log(' Found ' + results.length + ' results for "' + query + '"');
408
- results.forEach(function(r, i) {
409
- var content = r.content ? r.content.substring(0, 60) : JSON.stringify(r).substring(0, 60);
410
- console.log(' ' + (i + 1) + '. ' + content);
411
- });
412
- } else {
413
- const stats = router.memory.getStats();
414
- console.log('\n🧠 A3M Router — Memory Stats');
415
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
416
- console.log(JSON.stringify(stats, null, 2));
417
- }
34
+ case "status": {
35
+ const tmlpd = createTMLPD();
36
+ const status = tmlpd.getProviderStatus();
37
+ console.log(JSON.stringify(status, null, 2));
418
38
  break;
419
39
  }
420
-
421
- case 'health': {
422
- console.log('\n🏥 A3M Router — Provider Health Check');
423
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
424
-
425
- const providers = providerConfig.getAvailableProviders();
426
- for (const [id, provider] of Object.entries(providers)) {
427
- try {
428
- const health = await providerConfig.healthCheck(id);
429
- console.log(' ' + (health.healthy ? '✅' : '❌') + ' ' + (provider.name || id).padEnd(15) + health.healthy ? 'Healthy' : health.error);
430
- } catch (e) {
431
- console.log(' ❌ ' + (provider.name || id).padEnd(15) + e.message.substring(0, 60));
432
- }
433
- }
434
- console.log('');
40
+ case "cache": {
41
+ const tmlpd = createTMLPD();
42
+ const stats = tmlpd.getCacheStats();
43
+ console.log(JSON.stringify(stats, null, 2));
435
44
  break;
436
45
  }
437
-
438
- case 'serve': {
439
- if (!createProxyServer) {
440
- console.error('\n Error: Server module not available.');
441
- console.error(' Build first: npm run build');
442
- console.error(' Or use directly: node -e "require(\'./server/proxyServer.js\').createProxyServer()"\n');
443
- process.exit(1);
444
- }
445
-
446
- // Parse --port argument
447
- var portArg = args.indexOf('--port');
448
- var port = undefined;
449
- if (portArg !== -1 && args[portArg + 1]) {
450
- port = parseInt(args[portArg + 1], 10);
451
- if (isNaN(port)) {
452
- console.error(' Error: --port must be a number');
453
- process.exit(1);
454
- }
455
- }
456
-
457
- console.log('\n Starting A3M Router Proxy Server...');
458
- createProxyServer(port);
459
- break;
460
- }
461
-
462
46
  default:
463
- console.log('\n🔀 A3M Router — Adaptive Memory Multi-Model Router');
464
- console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
465
- console.log('');
466
- console.log(' Commands:');
467
- console.log(' serve [--port 8787] Start OpenAI-compatible proxy server');
468
- console.log(' route <query> Route query to best provider');
469
- console.log(' batch <q1> <q2>.. Route multiple queries');
470
- console.log(' compare <query> Compare providers side by side');
471
- console.log(' benchmark Benchmark all providers');
472
- console.log(' recommend <task> Get model recommendation');
473
- console.log(' cost [text] Estimate token cost across models');
474
- console.log(' models List all known models + pricing');
475
- console.log(' providers List configured providers');
476
- console.log(' test Test all provider connectivity');
477
- console.log(' health Quick health check for all providers');
478
- console.log(' token <text> Count tokens');
479
- console.log(' memory add <text> Add to memory tree');
480
- console.log(' memory search <q> Search memory');
481
- console.log(' memory Show memory stats');
482
- console.log(' register <id> <cfg> Register new provider');
483
- console.log(' status Show router status');
484
- console.log('');
485
- console.log(' Config: ~/.config/a3m-router/providers.json');
486
- console.log(' Env: GROQ_API_KEY, CEREBRAS_API_KEY, MISTRAL_API_KEY, etc.');
487
- console.log('');
488
- console.log(' Examples:');
489
- console.log(' npx a3m-router serve # Start proxy on :8787');
490
- console.log(' npx a3m-router serve --port 3000 # Start proxy on :3000');
491
- console.log(' npx a3m-router route "Write a Python function to sort"');
492
- console.log(' npx a3m-router compare "What is 2+2?"');
493
- console.log(' npx a3m-router providers');
494
- console.log(' npx a3m-router test');
495
- console.log('');
47
+ console.log(`TMLPD PI v1.0.0
48
+
49
+ Usage:
50
+ tmlpd-pi execute <prompt> Execute single prompt
51
+ tmlpd-pi parallel <models> Execute in parallel
52
+ tmlpd-pi cost Show cost summary
53
+ tmlpd-pi status Show provider status
54
+ tmlpd-pi cache Show cache stats
55
+ `);
496
56
  }
497
57
  }
498
58
 
499
- main().catch(function(err) {
500
- console.error('Error:', err.message);
501
- process.exit(1);
502
- });
59
+ main().catch(console.error);
@@ -236,8 +236,5 @@ class CostTracker {
236
236
  return [...this.history];
237
237
  }
238
238
  }
239
- // Alias for convenience
240
- CostTracker.prototype.getStatus = CostTracker.prototype.getSummary;
241
-
242
239
  exports.CostTracker = CostTracker;
243
240
  //# sourceMappingURL=costTracker.js.map
@@ -0,0 +1,114 @@
1
+ /**
2
+ * A3M Router - Pre-Call Cost Estimator
3
+ *
4
+ * Estimates cost BEFORE making an API call based on input features.
5
+ * Uses historical data patterns and token count estimation via character ratio.
6
+ *
7
+ * No external API calls - all estimation is local.
8
+ *
9
+ * Usage:
10
+ * const estimator = new PreCallCostEstimator();
11
+ * const estimate = estimator.estimate({
12
+ * query: "What is Python?",
13
+ * modelTier: 'mid',
14
+ * provider: 'groq'
15
+ * });
16
+ * console.log(estimate); // { estimatedTokens: 24, estimatedCost: 0.0014, estimatedLatency: 200 }
17
+ */
18
+ import { ProviderTier } from '../providers/providerConfig';
19
+ export interface CostEstimateInput {
20
+ /** Query text to estimate tokens for */
21
+ query: string;
22
+ /** Model tier (free|cheap|mid|premium|enterprise) */
23
+ modelTier?: ProviderTier;
24
+ /** Provider ID for provider-specific cost lookup */
25
+ provider?: string;
26
+ /** Optional: explicit token count (if already known) */
27
+ explicitTokens?: number;
28
+ /** System prompt length (if using a system prompt) */
29
+ systemPromptLength?: number;
30
+ }
31
+ export interface CostEstimate {
32
+ /** Estimated total tokens (input + output) */
33
+ estimatedTokens: number;
34
+ /** Estimated input tokens */
35
+ estimatedInputTokens: number;
36
+ /** Estimated output tokens */
37
+ estimatedOutputTokens: number;
38
+ /** Estimated cost in USD */
39
+ estimatedCost: number;
40
+ /** Estimated latency in milliseconds */
41
+ estimatedLatency: number;
42
+ /** Confidence score 0-1 */
43
+ confidence: number;
44
+ /** Breakdown of estimation */
45
+ breakdown: {
46
+ inputCostPerM: number;
47
+ outputCostPerM: number;
48
+ charToTokenRatio: number;
49
+ };
50
+ }
51
+ export interface ProviderCostConfig {
52
+ input: number;
53
+ output: number;
54
+ }
55
+ export declare class PreCallCostEstimator {
56
+ private historicalData;
57
+ private slope;
58
+ private intercept;
59
+ private latencyHistory;
60
+ private ewmaAlpha;
61
+ constructor(historicalData?: Array<{
62
+ chars: number;
63
+ tokens: number;
64
+ }>);
65
+ /**
66
+ * Main estimation method - estimates tokens, cost, and latency.
67
+ */
68
+ estimate(input: CostEstimateInput): CostEstimate;
69
+ /**
70
+ * Estimate input tokens using character-to-token ratio.
71
+ * Uses linear regression if historical data is available.
72
+ */
73
+ estimateTokens(text: string, systemPromptLength?: number): number;
74
+ /**
75
+ * Estimate output tokens based on query complexity.
76
+ * More complex queries (code, analysis) tend to need more output.
77
+ */
78
+ estimateOutputTokens(query: string, inputTokens: number): number;
79
+ /**
80
+ * Calculate cost in USD.
81
+ */
82
+ calculateCost(totalTokens: number, config: ProviderCostConfig): number;
83
+ /**
84
+ * Estimate latency in milliseconds.
85
+ */
86
+ estimateLatency(tier: ProviderTier, inputTokens: number, totalTokens: number): number;
87
+ /**
88
+ * Record actual tokens for future regression improvements.
89
+ */
90
+ recordActualTokens(queryLength: number, actualTokens: number): void;
91
+ /**
92
+ * Record actual latency for EWMA updates.
93
+ */
94
+ recordActualLatency(latencyMs: number): void;
95
+ /**
96
+ * Fit linear regression to historical data.
97
+ * Uses ordinary least squares.
98
+ */
99
+ fitLinearRegression(data: Array<{
100
+ chars: number;
101
+ tokens: number;
102
+ }>): void;
103
+ private getCostConfig;
104
+ private containsKeyword;
105
+ private calculateEwma;
106
+ private calculateConfidence;
107
+ private estimateInputTokensFromTotal;
108
+ private estimateOutputTokensFromTotal;
109
+ }
110
+ export declare function createPreCallCostEstimator(historicalData?: Array<{
111
+ chars: number;
112
+ tokens: number;
113
+ }>): PreCallCostEstimator;
114
+ //# sourceMappingURL=preCallCostEstimator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"preCallCostEstimator.d.ts","sourceRoot":"","sources":["../../src/cost/preCallCostEstimator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAM3D,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,qDAAqD;IACrD,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sDAAsD;IACtD,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,8CAA8C;IAC9C,eAAe,EAAE,MAAM,CAAC;IACxB,6BAA6B;IAC7B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,8BAA8B;IAC9B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,4BAA4B;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,wCAAwC;IACxC,gBAAgB,EAAE,MAAM,CAAC;IACzB,2BAA2B;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,SAAS,EAAE;QACT,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;CACH;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAeD,qBAAa,oBAAoB;IAE/B,OAAO,CAAC,cAAc,CAAgD;IAEtE,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,SAAS,CAAM;IAEvB,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,SAAS,CAAO;gBAEZ,cAAc,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAMrE;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,iBAAiB,GAAG,YAAY;IA+ChD;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,kBAAkB,SAAI,GAAG,MAAM;IAY5D;;;OAGG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;IAwBhE;;OAEG;IACH,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,kBAAkB,GAAG,MAAM;IAMtE;;OAEG;IACH,eAAe,CAAC,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,MAAM;IAmBrF;;OAEG;IACH,kBAAkB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAcnE;;OAEG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAO5C;;;OAGG;IACH,mBAAmB,CAAC,IAAI,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI;IA4BzE,OAAO,CAAC,aAAa;IA8BrB,OAAO,CAAC,eAAe;IAIvB,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,mBAAmB;IAQ3B,OAAO,CAAC,4BAA4B;IAIpC,OAAO,CAAC,6BAA6B;CAGtC;AAMD,wBAAgB,0BAA0B,CACxC,cAAc,CAAC,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,GACxD,oBAAoB,CAEtB"}