adaptive-memory-multi-model-router 1.8.1 ā 1.9.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/dist/cli.js +344 -109
- package/dist/index.js +14 -0
- package/dist/providers/providerConfig.js +452 -0
- package/dist/providers/registry.js +60 -41
- package/dist/routing/advancedRouter.js +368 -310
- package/package.json +2 -2
- package/test.js +376 -0
package/dist/cli.js
CHANGED
|
@@ -2,45 +2,233 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* A3M Router CLI - Adaptive Memory Multi-Model Router
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
* npx a3m-router route
|
|
7
|
-
* npx a3m-router
|
|
8
|
-
* npx a3m-router
|
|
9
|
-
* npx a3m-router
|
|
5
|
+
* Commands:
|
|
6
|
+
* npx a3m-router route <query> Route query to best provider
|
|
7
|
+
* npx a3m-router batch <q1> <q2>.. Route multiple queries
|
|
8
|
+
* npx a3m-router providers List all configured providers
|
|
9
|
+
* npx a3m-router test Test all providers
|
|
10
|
+
* npx a3m-router compare <query> Compare providers side by side
|
|
11
|
+
* npx a3m-router benchmark Benchmark all providers
|
|
12
|
+
* npx a3m-router recommend <task> Get model recommendation
|
|
13
|
+
* npx a3m-router cost <text> Estimate token cost
|
|
14
|
+
* npx a3m-router token <text> Count tokens
|
|
15
|
+
* npx a3m-router models List known models
|
|
16
|
+
* npx a3m-router memory add/search/stats Memory operations
|
|
17
|
+
* npx a3m-router status Show router status
|
|
10
18
|
*/
|
|
11
19
|
|
|
12
|
-
const {
|
|
20
|
+
const { execSync } = require('child_process');
|
|
21
|
+
const {
|
|
22
|
+
createA3MRouter, routeQuery, routeBatch, recommendForTask,
|
|
23
|
+
countTokens, estimateCost, MODEL_COSTS, CostTracker, MemoryTree,
|
|
24
|
+
getAvailableProviders, providerConfig, registerProvider, loadProviders,
|
|
25
|
+
} = require('./index.js');
|
|
13
26
|
|
|
14
27
|
const args = process.argv.slice(2);
|
|
15
28
|
const command = args[0];
|
|
16
29
|
|
|
30
|
+
// ============================================================
|
|
31
|
+
// HELPER FUNCTIONS
|
|
32
|
+
// ============================================================
|
|
33
|
+
|
|
17
34
|
function formatRoute(result) {
|
|
18
|
-
console.log(
|
|
19
|
-
console.log(
|
|
20
|
-
console.log(
|
|
35
|
+
console.log('\nš A3M Router ā Route Result');
|
|
36
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
37
|
+
console.log(' Primary: ' + result.primary_model);
|
|
21
38
|
if (result.fallback_models) {
|
|
22
|
-
console.log(
|
|
39
|
+
console.log(' Fallbacks: ' + result.fallback_models.join(', '));
|
|
23
40
|
}
|
|
24
41
|
if (result.estimated_cost) {
|
|
25
|
-
console.log(
|
|
42
|
+
console.log(' Est. Cost: $' + result.estimated_cost.toFixed(6));
|
|
26
43
|
}
|
|
27
|
-
if (result.
|
|
28
|
-
console.log(
|
|
44
|
+
if (result.provider_type) {
|
|
45
|
+
console.log(' Type: ' + result.provider_type);
|
|
29
46
|
}
|
|
30
|
-
if (result.
|
|
31
|
-
console.log(
|
|
47
|
+
if (result.reasoning) {
|
|
48
|
+
console.log(' Reason: ' + result.reasoning);
|
|
32
49
|
}
|
|
33
|
-
console.log(
|
|
50
|
+
console.log('');
|
|
34
51
|
}
|
|
35
52
|
|
|
53
|
+
async function callProvider(providerId, model, prompt, maxTokens) {
|
|
54
|
+
providerId = providerId || 'groq';
|
|
55
|
+
model = model || 'llama-3.3-70b-versatile';
|
|
56
|
+
maxTokens = maxTokens || 50;
|
|
57
|
+
|
|
58
|
+
const providers = providerConfig.getAvailableProviders();
|
|
59
|
+
const provider = providers[providerId];
|
|
60
|
+
|
|
61
|
+
if (!provider) {
|
|
62
|
+
console.error(' ā Provider "' + providerId + '" not found or not configured.');
|
|
63
|
+
console.error(' Run: npx a3m-router providers');
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const startTime = Date.now();
|
|
68
|
+
|
|
69
|
+
if (provider.type === 'cli') {
|
|
70
|
+
try {
|
|
71
|
+
if (providerId === 'commandcode') {
|
|
72
|
+
const raw = execSync('commandcode -p "' + prompt.replace(/"/g, '\\"') + '" --skip-onboarding 2>&1', { timeout: 60000, encoding: 'utf-8' });
|
|
73
|
+
const content = raw.replace(/\x1b\[[0-9;]*m/g, '').trim();
|
|
74
|
+
return { content: content.substring(0, 200), totalTokens: Math.ceil(content.length / 4), cost: 0, latency: Date.now() - startTime };
|
|
75
|
+
} else {
|
|
76
|
+
const raw = execSync(provider.cliCommand + ' run "' + prompt.replace(/"/g, '\\"') + '" 2>&1', { timeout: 60000, encoding: 'utf-8' });
|
|
77
|
+
const lines = raw.replace(/\x1b\[[0-9;]*m/g, '').split('\n').filter(l => l.trim() && !l.startsWith('>') && !l.includes('build'));
|
|
78
|
+
const content = lines.join(' ').trim();
|
|
79
|
+
return { content: content.substring(0, 200), totalTokens: Math.ceil(content.length / 4), cost: 0, latency: Date.now() - startTime };
|
|
80
|
+
}
|
|
81
|
+
} catch (e) {
|
|
82
|
+
console.error(' ā ' + provider.name + ' error: ' + e.message.substring(0, 80));
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// API provider
|
|
88
|
+
try {
|
|
89
|
+
const resp = await fetch(provider.baseUrl, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: { 'Authorization': 'Bearer ' + provider.apiKey, 'Content-Type': 'application/json' },
|
|
92
|
+
body: JSON.stringify({ model, messages: [{ role: 'user', content: prompt }], max_tokens: maxTokens }),
|
|
93
|
+
});
|
|
94
|
+
const data = await resp.json();
|
|
95
|
+
const latency = Date.now() - startTime;
|
|
96
|
+
if (data.error) {
|
|
97
|
+
console.error(' ā ' + provider.name + ' error: ' + data.error.message.substring(0, 80));
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const tokens = data.usage || {};
|
|
101
|
+
const cost = (tokens.prompt_tokens || 0) / 1000 * provider.costPerK.input + (tokens.completion_tokens || 0) / 1000 * provider.costPerK.output;
|
|
102
|
+
return { content: data.choices[0].message.content.trim(), totalTokens: tokens.total_tokens || 0, cost, latency, model: data.model || model };
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.error(' ā ' + provider.name + ' error: ' + e.message.substring(0, 80));
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// ============================================================
|
|
110
|
+
// COMMANDS
|
|
111
|
+
// ============================================================
|
|
112
|
+
|
|
36
113
|
async function main() {
|
|
37
114
|
const router = createA3MRouter({ memory: { maxSize: 1000 } });
|
|
38
115
|
|
|
39
116
|
switch (command) {
|
|
40
|
-
case
|
|
41
|
-
const
|
|
117
|
+
case 'providers': {
|
|
118
|
+
const providers = providerConfig.getAvailableProviders();
|
|
119
|
+
const allProviders = providerConfig._providers;
|
|
120
|
+
|
|
121
|
+
console.log('\nš” A3M Router ā Provider Configuration');
|
|
122
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
123
|
+
console.log(' Config: ~/.config/a3m-router/providers.json');
|
|
124
|
+
console.log(' Add your own: npx a3m-router register <id> <config>');
|
|
125
|
+
console.log('');
|
|
126
|
+
console.log(' Provider Type Models Priority Key');
|
|
127
|
+
console.log(' āāāāāāāāāāāāāāāāāāāāā āāāāāāā āāāāāā āāāāāāāā āāāāāāāāā');
|
|
128
|
+
|
|
129
|
+
for (const [id, provider] of Object.entries(allProviders)) {
|
|
130
|
+
const available = providers[id];
|
|
131
|
+
const status = available ? 'ā
' : 'ā';
|
|
132
|
+
const keyStatus = provider.apiKey ? 'ā
' : (provider.type === 'cli' ? 'N/A' : 'ā');
|
|
133
|
+
const modelCount = provider.models ? provider.models.length : 0;
|
|
134
|
+
console.log(' ' + status + ' ' + (provider.name || id).padEnd(20) + ' ' + (provider.type || 'api').padEnd(7) + ' ' + String(modelCount).padEnd(6) + ' ' + String(provider.priority).padEnd(9) + ' ' + keyStatus);
|
|
135
|
+
}
|
|
136
|
+
console.log('');
|
|
137
|
+
console.log(' Available: ' + Object.keys(providers).length + ' providers');
|
|
138
|
+
console.log(' Configured: ' + Object.keys(allProviders).length + ' providers');
|
|
139
|
+
console.log('');
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
case 'test': {
|
|
144
|
+
const providers = providerConfig.getAvailableProviders();
|
|
145
|
+
console.log('\nš§Ŗ A3M Router ā Provider Health Check');
|
|
146
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
147
|
+
|
|
148
|
+
for (const [id, provider] of Object.entries(providers)) {
|
|
149
|
+
const model = provider.models[0];
|
|
150
|
+
console.log(' Testing ' + (provider.name || id) + ' (' + model + ')...');
|
|
151
|
+
const result = await callProvider(id, model, 'Say OK', 5);
|
|
152
|
+
if (result) {
|
|
153
|
+
console.log(' ā
Response: "' + result.content.substring(0, 30) + '" (' + result.totalTokens + ' tok, ' + result.latency + 'ms, $' + result.cost.toFixed(6) + ')');
|
|
154
|
+
}
|
|
155
|
+
console.log('');
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
case 'compare': {
|
|
161
|
+
const query = args.slice(1).join(' ');
|
|
42
162
|
if (!query) {
|
|
43
|
-
console.error(
|
|
163
|
+
console.error('Usage: npx a3m-router compare "your query here"');
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const providers = providerConfig.getAvailableProviders();
|
|
168
|
+
console.log('\nš A3M Router ā Provider Comparison');
|
|
169
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
170
|
+
console.log(' Query: "' + query + '"');
|
|
171
|
+
console.log('');
|
|
172
|
+
|
|
173
|
+
const results = [];
|
|
174
|
+
for (const [id, provider] of Object.entries(providers)) {
|
|
175
|
+
const model = provider.models[0];
|
|
176
|
+
console.log(' Testing ' + (provider.name || id) + '...');
|
|
177
|
+
const result = await callProvider(id, model, query, 100);
|
|
178
|
+
if (result) {
|
|
179
|
+
results.push({ id: provider.name || id, model, ...result });
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
console.log('\n Comparison:');
|
|
184
|
+
console.log(' āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
185
|
+
console.log(' Provider'.padEnd(18) + 'Response'.padEnd(40) + 'Time'.padEnd(12) + 'Cost');
|
|
186
|
+
console.log(' āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
187
|
+
for (const r of results) {
|
|
188
|
+
console.log(' ' + r.id.padEnd(16) + r.content.substring(0, 38).padEnd(40) + (r.latency + 'ms').padEnd(12) + '$' + r.cost.toFixed(6));
|
|
189
|
+
}
|
|
190
|
+
console.log('');
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
case 'benchmark': {
|
|
195
|
+
const queries = [
|
|
196
|
+
'What is 2+2?',
|
|
197
|
+
'Write a Python function to reverse a string.',
|
|
198
|
+
'Translate "Hello" to French.',
|
|
199
|
+
'Write a haiku about programming.',
|
|
200
|
+
'What is SQL injection?',
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
const providers = providerConfig.getAvailableProviders();
|
|
204
|
+
console.log('\nš A3M Router ā Provider Benchmark');
|
|
205
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
206
|
+
|
|
207
|
+
for (const [id, provider] of Object.entries(providers)) {
|
|
208
|
+
const model = provider.models[0];
|
|
209
|
+
console.log(' ' + (provider.name || id).padEnd(15) + '(' + model + ')');
|
|
210
|
+
|
|
211
|
+
let totalTime = 0;
|
|
212
|
+
let totalCost = 0;
|
|
213
|
+
|
|
214
|
+
for (const q of queries) {
|
|
215
|
+
const r = await callProvider(id, model, q, 50);
|
|
216
|
+
if (r) {
|
|
217
|
+
totalTime += r.latency;
|
|
218
|
+
totalCost += r.cost;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
console.log(' Total: ' + totalTime + 'ms, Cost: $' + totalCost.toFixed(6) + ', Avg: ' + (totalTime / queries.length).toFixed(0) + 'ms/query');
|
|
223
|
+
}
|
|
224
|
+
console.log('');
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
case 'route': {
|
|
229
|
+
const query = args.slice(1).join(' ');
|
|
230
|
+
if (!query) {
|
|
231
|
+
console.error('Usage: npx a3m-router route "your query here"');
|
|
44
232
|
process.exit(1);
|
|
45
233
|
}
|
|
46
234
|
const result = router.route(query);
|
|
@@ -48,152 +236,199 @@ async function main() {
|
|
|
48
236
|
break;
|
|
49
237
|
}
|
|
50
238
|
|
|
51
|
-
case
|
|
239
|
+
case 'batch': {
|
|
52
240
|
const queries = args.slice(1);
|
|
53
241
|
if (queries.length === 0) {
|
|
54
|
-
console.error(
|
|
242
|
+
console.error('Usage: npx a3m-router batch "query1" "query2" ...');
|
|
55
243
|
process.exit(1);
|
|
56
244
|
}
|
|
57
245
|
const results = router.routeBatch(queries);
|
|
58
|
-
console.log(
|
|
59
|
-
console.log(
|
|
246
|
+
console.log('\nš A3M Router ā Batch Results');
|
|
247
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
60
248
|
results.forEach(function(r, i) {
|
|
61
|
-
console.log(
|
|
249
|
+
console.log(' ' + (i + 1) + '. "' + queries[i].substring(0, 40) + '..." ā ' + r.primary_model);
|
|
62
250
|
});
|
|
63
|
-
console.log(
|
|
251
|
+
console.log('');
|
|
64
252
|
break;
|
|
65
253
|
}
|
|
66
254
|
|
|
67
|
-
case
|
|
68
|
-
const task = args.slice(1).join(
|
|
255
|
+
case 'recommend': {
|
|
256
|
+
const task = args.slice(1).join(' ');
|
|
69
257
|
if (!task) {
|
|
70
|
-
console.error(
|
|
258
|
+
console.error('Usage: npx a3m-router recommend "coding"');
|
|
71
259
|
process.exit(1);
|
|
72
260
|
}
|
|
73
261
|
const rec = router.recommend(task);
|
|
74
|
-
console.log(
|
|
75
|
-
console.log(
|
|
262
|
+
console.log('\nšÆ A3M Router ā Recommendation');
|
|
263
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
76
264
|
console.log(JSON.stringify(rec, null, 2));
|
|
265
|
+
console.log('');
|
|
77
266
|
break;
|
|
78
267
|
}
|
|
79
268
|
|
|
80
|
-
case
|
|
81
|
-
|
|
82
|
-
console.log(
|
|
83
|
-
console.log(
|
|
84
|
-
console.log(
|
|
85
|
-
console.log(
|
|
86
|
-
console.log(
|
|
87
|
-
console.log(
|
|
88
|
-
console.log(
|
|
89
|
-
console.log(
|
|
90
|
-
console.log(
|
|
91
|
-
console.log(
|
|
92
|
-
console.log(
|
|
93
|
-
console.log(
|
|
94
|
-
console.log(
|
|
95
|
-
console.log(
|
|
96
|
-
console.log(
|
|
269
|
+
case 'status': {
|
|
270
|
+
const providers = providerConfig.getAvailableProviders();
|
|
271
|
+
console.log('\nš A3M Router ā Status');
|
|
272
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāā');
|
|
273
|
+
console.log(' Version: 1.9.0');
|
|
274
|
+
console.log(' Exports: 74');
|
|
275
|
+
console.log(' Providers: ' + Object.keys(providers).length + ' configured');
|
|
276
|
+
console.log(' Integrations: 116');
|
|
277
|
+
console.log(' Keywords: 139');
|
|
278
|
+
console.log(' Subpaths: 11');
|
|
279
|
+
console.log(' Memory: ā
MemoryTree + AutoFetch + ObsidianVault');
|
|
280
|
+
console.log(' Compression: ā
Enhanced + ISON');
|
|
281
|
+
console.log(' Auth: ā
OAuth 2.0 + PKCE');
|
|
282
|
+
console.log(' Cost: ā
Tracking + Budgets');
|
|
283
|
+
console.log(' Cache: ā
Prefix + Response');
|
|
284
|
+
console.log(' Routing: ā
RouteLLM + Adaptive');
|
|
285
|
+
console.log(' Models known: ' + Object.keys(providerConfig._providers).length);
|
|
286
|
+
console.log('');
|
|
287
|
+
console.log(' Available Providers:');
|
|
288
|
+
for (const [id, p] of Object.entries(providers)) {
|
|
289
|
+
console.log(' ā
' + (p.name || id).padEnd(15) + '(' + p.models.length + ' models, type: ' + p.type + ')');
|
|
290
|
+
}
|
|
291
|
+
console.log('');
|
|
97
292
|
break;
|
|
98
293
|
}
|
|
99
294
|
|
|
100
|
-
case
|
|
101
|
-
const text = args.slice(1).join(
|
|
295
|
+
case 'cost': {
|
|
296
|
+
const text = args.slice(1).join(' ') || 'Hello world this is a test';
|
|
102
297
|
const tokens = countTokens(text);
|
|
103
298
|
var completionTokens = Math.ceil(tokens * 1.5);
|
|
104
|
-
var gpt4oCost = estimateCost(tokens, completionTokens,
|
|
105
|
-
var miniCost = estimateCost(tokens, completionTokens,
|
|
106
|
-
var haikuCost = estimateCost(tokens, completionTokens,
|
|
107
|
-
var geminiCost = estimateCost(tokens, completionTokens,
|
|
108
|
-
console.log(
|
|
109
|
-
console.log(
|
|
110
|
-
console.log(
|
|
111
|
-
console.log(
|
|
112
|
-
console.log(
|
|
113
|
-
console.log(
|
|
114
|
-
console.log(
|
|
115
|
-
console.log(
|
|
299
|
+
var gpt4oCost = estimateCost(tokens, completionTokens, 'gpt-4o');
|
|
300
|
+
var miniCost = estimateCost(tokens, completionTokens, 'gpt-4o-mini');
|
|
301
|
+
var haikuCost = estimateCost(tokens, completionTokens, 'claude-3-haiku');
|
|
302
|
+
var geminiCost = estimateCost(tokens, completionTokens, 'gemini-2.0-flash');
|
|
303
|
+
console.log('\nš° A3M Router ā Cost Estimate');
|
|
304
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
305
|
+
console.log(' Text: "' + text.substring(0, 50) + '"');
|
|
306
|
+
console.log(' Tokens: ' + tokens);
|
|
307
|
+
console.log(' GPT-4o: $' + gpt4oCost.toFixed(6));
|
|
308
|
+
console.log(' GPT-4o-mini: $' + miniCost.toFixed(6));
|
|
309
|
+
console.log(' Claude Haiku: $' + haikuCost.toFixed(6));
|
|
310
|
+
console.log(' Gemini Flash: $' + geminiCost.toFixed(6));
|
|
116
311
|
if (gpt4oCost > 0) {
|
|
117
312
|
var savings = ((1 - miniCost / gpt4oCost) * 100).toFixed(1);
|
|
118
|
-
console.log(
|
|
313
|
+
console.log(' Savings: ' + savings + '% (mini vs GPT-4o)');
|
|
119
314
|
}
|
|
120
|
-
console.log(
|
|
315
|
+
console.log('');
|
|
121
316
|
break;
|
|
122
317
|
}
|
|
123
318
|
|
|
124
|
-
case
|
|
125
|
-
|
|
126
|
-
console.log(
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
console.log(
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
319
|
+
case 'models': {
|
|
320
|
+
const allProviders = providerConfig._providers;
|
|
321
|
+
console.log('\nš A3M Router ā All Known Models');
|
|
322
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
323
|
+
|
|
324
|
+
for (const [id, provider] of Object.entries(allProviders)) {
|
|
325
|
+
if (!provider.models || provider.models.length === 0) continue;
|
|
326
|
+
console.log(' ' + (provider.name || id).padEnd(15) + '(Priority: ' + provider.priority + ', Type: ' + provider.type + ')');
|
|
327
|
+
for (const m of provider.models) {
|
|
328
|
+
const cost = provider.costPerK;
|
|
329
|
+
console.log(' ' + m.padEnd(40) + 'in:$' + (cost ? cost.input : 0) + ' out:$' + (cost ? cost.output : 0));
|
|
330
|
+
}
|
|
331
|
+
console.log('');
|
|
332
|
+
}
|
|
135
333
|
break;
|
|
136
334
|
}
|
|
137
335
|
|
|
138
|
-
case
|
|
139
|
-
const text = args.slice(1).join(
|
|
336
|
+
case 'token': {
|
|
337
|
+
const text = args.slice(1).join(' ');
|
|
140
338
|
if (!text) {
|
|
141
|
-
console.error(
|
|
339
|
+
console.error('Usage: npx a3m-router token "your text here"');
|
|
142
340
|
process.exit(1);
|
|
143
341
|
}
|
|
144
342
|
const tokens = countTokens(text);
|
|
145
|
-
console.log(
|
|
343
|
+
console.log(' "' + text + '" ā ' + tokens + ' tokens');
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
case 'register': {
|
|
348
|
+
const id = args[1];
|
|
349
|
+
const config = JSON.parse(args.slice(2).join(' '));
|
|
350
|
+
registerProvider(id, config);
|
|
351
|
+
providerConfig.saveConfig();
|
|
352
|
+
console.log('ā
Registered provider: ' + id);
|
|
353
|
+
console.log(' Config saved to: ~/.config/a3m-router/providers.json');
|
|
146
354
|
break;
|
|
147
355
|
}
|
|
148
356
|
|
|
149
|
-
case
|
|
357
|
+
case 'memory': {
|
|
150
358
|
const subcmd = args[1];
|
|
151
|
-
if (subcmd ===
|
|
152
|
-
const text = args.slice(2).join(
|
|
359
|
+
if (subcmd === 'add') {
|
|
360
|
+
const text = args.slice(2).join(' ');
|
|
153
361
|
router.memory.add(text, { metadata: { cli: true } });
|
|
154
|
-
console.log(
|
|
155
|
-
} else if (subcmd ===
|
|
156
|
-
const query = args.slice(2).join(
|
|
362
|
+
console.log(' ā
Added to memory: "' + text.substring(0, 50) + '"');
|
|
363
|
+
} else if (subcmd === 'search') {
|
|
364
|
+
const query = args.slice(2).join(' ');
|
|
157
365
|
const results = router.memory.search(query);
|
|
158
|
-
console.log(
|
|
366
|
+
console.log(' Found ' + results.length + ' results for "' + query + '"');
|
|
159
367
|
results.forEach(function(r, i) {
|
|
160
368
|
var content = r.content ? r.content.substring(0, 60) : JSON.stringify(r).substring(0, 60);
|
|
161
|
-
console.log(
|
|
369
|
+
console.log(' ' + (i + 1) + '. ' + content);
|
|
162
370
|
});
|
|
163
371
|
} else {
|
|
164
372
|
const stats = router.memory.getStats();
|
|
165
|
-
console.log(
|
|
166
|
-
console.log(
|
|
373
|
+
console.log('\nš§ A3M Router ā Memory Stats');
|
|
374
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
167
375
|
console.log(JSON.stringify(stats, null, 2));
|
|
168
376
|
}
|
|
169
377
|
break;
|
|
170
378
|
}
|
|
171
379
|
|
|
380
|
+
case 'health': {
|
|
381
|
+
console.log('\nš„ A3M Router ā Provider Health Check');
|
|
382
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n');
|
|
383
|
+
|
|
384
|
+
const providers = providerConfig.getAvailableProviders();
|
|
385
|
+
for (const [id, provider] of Object.entries(providers)) {
|
|
386
|
+
try {
|
|
387
|
+
const health = await providerConfig.healthCheck(id);
|
|
388
|
+
console.log(' ' + (health.healthy ? 'ā
' : 'ā') + ' ' + (provider.name || id).padEnd(15) + health.healthy ? 'Healthy' : health.error);
|
|
389
|
+
} catch (e) {
|
|
390
|
+
console.log(' ā ' + (provider.name || id).padEnd(15) + e.message.substring(0, 60));
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
console.log('');
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
|
|
172
397
|
default:
|
|
173
|
-
console.log(
|
|
174
|
-
console.log(
|
|
175
|
-
console.log(
|
|
176
|
-
console.log(
|
|
177
|
-
console.log(
|
|
178
|
-
console.log(
|
|
179
|
-
console.log(
|
|
180
|
-
console.log(
|
|
181
|
-
console.log(
|
|
182
|
-
console.log(
|
|
183
|
-
console.log(
|
|
184
|
-
console.log(
|
|
185
|
-
console.log(
|
|
186
|
-
console.log(
|
|
187
|
-
console.log(
|
|
188
|
-
console.log(
|
|
189
|
-
console.log(
|
|
190
|
-
console.log(
|
|
191
|
-
console.log(
|
|
192
|
-
console.log(
|
|
398
|
+
console.log('\nš A3M Router ā Adaptive Memory Multi-Model Router');
|
|
399
|
+
console.log('āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā');
|
|
400
|
+
console.log('');
|
|
401
|
+
console.log(' Commands:');
|
|
402
|
+
console.log(' route <query> Route query to best provider');
|
|
403
|
+
console.log(' batch <q1> <q2>.. Route multiple queries');
|
|
404
|
+
console.log(' compare <query> Compare providers side by side');
|
|
405
|
+
console.log(' benchmark Benchmark all providers');
|
|
406
|
+
console.log(' recommend <task> Get model recommendation');
|
|
407
|
+
console.log(' cost [text] Estimate token cost across models');
|
|
408
|
+
console.log(' models List all known models + pricing');
|
|
409
|
+
console.log(' providers List configured providers');
|
|
410
|
+
console.log(' test Test all provider connectivity');
|
|
411
|
+
console.log(' health Quick health check for all providers');
|
|
412
|
+
console.log(' token <text> Count tokens');
|
|
413
|
+
console.log(' memory add <text> Add to memory tree');
|
|
414
|
+
console.log(' memory search <q> Search memory');
|
|
415
|
+
console.log(' memory Show memory stats');
|
|
416
|
+
console.log(' register <id> <cfg> Register new provider');
|
|
417
|
+
console.log(' status Show router status');
|
|
418
|
+
console.log('');
|
|
419
|
+
console.log(' Config: ~/.config/a3m-router/providers.json');
|
|
420
|
+
console.log(' Env: GROQ_API_KEY, CEREBRAS_API_KEY, MISTRAL_API_KEY, etc.');
|
|
421
|
+
console.log('');
|
|
422
|
+
console.log(' Examples:');
|
|
423
|
+
console.log(' npx a3m-router route "Write a Python function to sort"');
|
|
424
|
+
console.log(' npx a3m-router compare "What is 2+2?"');
|
|
425
|
+
console.log(' npx a3m-router providers');
|
|
426
|
+
console.log(' npx a3m-router test');
|
|
427
|
+
console.log('');
|
|
193
428
|
}
|
|
194
429
|
}
|
|
195
430
|
|
|
196
431
|
main().catch(function(err) {
|
|
197
|
-
console.error(
|
|
432
|
+
console.error('Error:', err.message);
|
|
198
433
|
process.exit(1);
|
|
199
434
|
});
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,15 @@ const costTracker_1 = require("./cost/costTracker");
|
|
|
34
34
|
Object.defineProperty(exports, "CostTracker", { enumerable: true, get: function () { return costTracker_1.CostTracker; } });
|
|
35
35
|
const registry_1 = require("./providers/registry");
|
|
36
36
|
Object.defineProperty(exports, "ProviderRegistry", { enumerable: true, get: function () { return registry_1.ProviderRegistry; } });
|
|
37
|
+
const providerConfig_1 = require("./providers/providerConfig");
|
|
38
|
+
Object.defineProperty(exports, "loadProviders", { enumerable: true, get: function () { return providerConfig_1.loadProviders; } });
|
|
39
|
+
Object.defineProperty(exports, "getAvailableProviders", { enumerable: true, get: function () { return providerConfig_1.getAvailableProviders; } });
|
|
40
|
+
Object.defineProperty(exports, "healthCheckProvider", { enumerable: true, get: function () { return providerConfig_1.healthCheck; } });
|
|
41
|
+
Object.defineProperty(exports, "registerProvider", { enumerable: true, get: function () { return providerConfig_1.registerProvider; } });
|
|
42
|
+
Object.defineProperty(exports, "deregisterProvider", { enumerable: true, get: function () { return providerConfig_1.deregisterProvider; } });
|
|
43
|
+
Object.defineProperty(exports, "findCheapestAvailableProvider", { enumerable: true, get: function () { return providerConfig_1.findCheapestAvailableProvider; } });
|
|
44
|
+
Object.defineProperty(exports, "findFastestAvailableProvider", { enumerable: true, get: function () { return providerConfig_1.findFastestAvailableProvider; } });
|
|
45
|
+
Object.defineProperty(exports, "DEFAULT_PROVIDERS", { enumerable: true, get: function () { return providerConfig_1.DEFAULT_PROVIDERS; } });
|
|
37
46
|
const reliability_1 = require("./utils/reliability");
|
|
38
47
|
Object.defineProperty(exports, "CircuitBreaker", { enumerable: true, get: function () { return reliability_1.CircuitBreaker; } });
|
|
39
48
|
Object.defineProperty(exports, "withRetry", { enumerable: true, get: function () { return reliability_1.withRetry; } });
|
|
@@ -330,3 +339,8 @@ function createA3MRouter(config = {}) {
|
|
|
330
339
|
};
|
|
331
340
|
}
|
|
332
341
|
exports.createA3MRouter = createA3MRouter;
|
|
342
|
+
|
|
343
|
+
// Provider Configuration (generic, user-configurable) - additional exports
|
|
344
|
+
const providerConfig = require("./providers/providerConfig");
|
|
345
|
+
Object.defineProperty(exports, "providerConfig", { enumerable: true, get: function () { return providerConfig; } });
|
|
346
|
+
Object.defineProperty(exports, "saveProviderConfig", { enumerable: true, get: function () { return providerConfig.saveConfig; } });
|