adaptive-memory-multi-model-router 2.2.6 ā 2.2.7
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/README.md +132 -94
- package/assets/benchmark-results.png +0 -0
- package/assets/complexity-scoring-v2.png +0 -0
- package/assets/complexity-scoring.png +0 -0
- package/assets/cost-comparison-chart.png +0 -0
- package/assets/cost-comparison-v2.png +0 -0
- package/assets/feature-comparison-v2.png +0 -0
- package/assets/feature-comparison-v3.png +0 -0
- package/assets/provider-health-chart.png +0 -0
- package/assets/provider-health-v2.png +0 -0
- package/assets/routing-flow-v2.png +0 -0
- package/assets/routing-flow-v3.png +0 -0
- package/assets/routing-flow.png +0 -0
- package/assets/tier-distribution.png +0 -0
- package/benchmark-results.json +620 -46
- package/dist/analytics/costAnalytics.d.ts +0 -1
- package/dist/cache/semanticCache.d.ts +0 -41
- package/dist/cache/semanticCache.d.ts.map +1 -1
- package/dist/cache/semanticCache.js +0 -142
- package/dist/cache/semanticCache.js.map +1 -1
- package/dist/cli.js +478 -35
- package/dist/cost/costTracker.js +3 -0
- package/dist/index.d.ts +0 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +64 -264
- package/dist/index.js.map +1 -1
- package/dist/integrations/langchainAdapter.d.ts +0 -1
- package/dist/integrations/oauth.d.ts +0 -1
- package/dist/memory/autoFetch.d.ts +0 -1
- package/dist/memory/memoryTree.d.ts +0 -1
- package/dist/memory/obsidianVault.d.ts +0 -1
- package/dist/providers/providerConfig.d.ts +0 -1
- package/dist/providers/providerConfig.js +0 -2
- package/dist/providers/registry.js +128 -126
- package/dist/routing/advancedRouter.js +427 -310
- package/dist/sdk.js +100 -109
- package/dist/security/guardrails.d.ts +0 -1
- package/dist/server/dashboard.d.ts +0 -1
- package/dist/server/modelMapper.d.ts +0 -1
- package/dist/server/proxyServer.d.ts +0 -1
- package/package.json +3 -325
- package/scripts/run-mmlu-benchmark.js +176 -0
- package/scripts/run-provider-benchmark.js +244 -0
- package/src/cache/semanticCache.ts +0 -148
- package/src/index.ts +99 -0
- package/test/provider-test.js +70 -91
- package/test.js +41 -67
- package/tsconfig.json +5 -15
package/dist/cli.js
CHANGED
|
@@ -1,59 +1,502 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
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
|
|
4
19
|
*/
|
|
5
20
|
|
|
6
|
-
const {
|
|
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
|
+
}
|
|
7
34
|
|
|
8
35
|
const args = process.argv.slice(2);
|
|
9
36
|
const command = args[0];
|
|
10
37
|
|
|
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
|
+
|
|
11
154
|
async function main() {
|
|
155
|
+
const router = createA3MRouter({ memory: { maxSize: 1000 } });
|
|
156
|
+
|
|
12
157
|
switch (command) {
|
|
13
|
-
case
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
console.log(
|
|
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('');
|
|
18
181
|
break;
|
|
19
182
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
+
}
|
|
26
198
|
break;
|
|
27
199
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
31
|
-
|
|
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('');
|
|
32
232
|
break;
|
|
33
233
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
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('');
|
|
38
266
|
break;
|
|
39
267
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
43
|
-
|
|
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('');
|
|
44
293
|
break;
|
|
45
294
|
}
|
|
46
|
-
default:
|
|
47
|
-
console.log(`TMLPD PI v1.0.0
|
|
48
295
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
+
}
|
|
374
|
+
break;
|
|
375
|
+
}
|
|
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');
|
|
385
|
+
break;
|
|
386
|
+
}
|
|
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');
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
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
|
+
}
|
|
418
|
+
break;
|
|
419
|
+
}
|
|
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('');
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
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
|
+
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('');
|
|
56
496
|
}
|
|
57
497
|
}
|
|
58
498
|
|
|
59
|
-
main().catch(
|
|
499
|
+
main().catch(function(err) {
|
|
500
|
+
console.error('Error:', err.message);
|
|
501
|
+
process.exit(1);
|
|
502
|
+
});
|
package/dist/cost/costTracker.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
export { routeQuery, routeBatch, recommendForTask, extractQueryFeatures, MODEL_PROFILES, updateModelProfile, getProviderHealth, } from './routing/advancedRouter';
|
|
2
2
|
export { DEFAULT_PROVIDERS, getAvailableProviders, registerProvider, deregisterProvider, updateProvider, healthCheck, checkAllProviders, findCheapestAvailableProvider, findFastestAvailableProvider, loadConfig, saveConfig, } from './providers/providerConfig';
|
|
3
|
-
export { ProviderRegistry } from './providers/registry';
|
|
4
|
-
export { providerConfig } from './providers/providerConfig';
|
|
5
|
-
export { estimateCost } from './routing/advancedRouter';
|
|
6
3
|
export type { ProviderTier, ProviderFormat, ProviderType, ProviderCost, ProviderDefinition, } from './providers/providerConfig';
|
|
7
4
|
export { CostTracker } from './cost/costTracker';
|
|
8
5
|
export { MemoryTree } from './memory/memoryTree';
|
|
@@ -29,19 +26,6 @@ export declare function createA3MRouter(options?: A3MRouterOptions): {
|
|
|
29
26
|
healthCheck: typeof healthCheck;
|
|
30
27
|
costTracker: any;
|
|
31
28
|
memoryTree: MemoryTree;
|
|
32
|
-
providers: any;
|
|
33
|
-
cache: any;
|
|
34
|
-
compression: {
|
|
35
|
-
compress: (input: string) => any;
|
|
36
|
-
decompress: (input: Buffer) => any;
|
|
37
|
-
};
|
|
38
|
-
vault: {
|
|
39
|
-
store: (key: string, value: any) => Promise<void>;
|
|
40
|
-
retrieve: (key: string) => Promise<null>;
|
|
41
|
-
};
|
|
42
|
-
autoFetch: boolean;
|
|
43
|
-
oauth: boolean;
|
|
44
29
|
options: A3MRouterOptions;
|
|
45
30
|
};
|
|
46
31
|
export default createA3MRouter;
|
|
47
|
-
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|