adaptive-memory-multi-model-router 2.1.0 → 2.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.
package/docs/API.md CHANGED
@@ -1,562 +1,855 @@
1
- # A3M Router API Documentation
1
+ # A3M Router API Reference
2
+
3
+ Complete reference for the A3M Router — TypeScript SDK, Python SDK, CLI, REST API, and integrations.
4
+
5
+ ---
2
6
 
3
7
  ## Table of Contents
4
8
 
5
- - [Core Functions](#core-functions)
6
- - [Memory Module](#memory-module)
7
- - [Compression Module](#compression-module)
8
- - [Auto-Fetch Module](#auto-fetch-module)
9
- - [OAuth Module](#oauth-module)
10
- - [Provider Registry](#provider-registry)
11
- - [Cost Tracker](#cost-tracker)
12
- - [Circuit Breaker](#circuit-breaker)
9
+ - [TypeScript SDK](#typescript-sdk)
10
+ - [Python SDK](#python-sdk)
11
+ - [CLI](#cli)
12
+ - [REST API](#rest-api)
13
+ - [OpenAI SDK Compatibility](#openai-sdk-compatibility)
14
+ - [LangChain Integration](#langchain-integration)
15
+ - [Configuration](#configuration)
16
+ - [Error Handling](#error-handling)
13
17
 
14
18
  ---
15
19
 
16
- ## Core Functions
20
+ ## TypeScript SDK
17
21
 
18
- ### createA3MRouter
22
+ ### Installation
19
23
 
20
- Creates an A3M Router instance with specified configuration.
21
-
22
- ```javascript
23
- import { createA3MRouter } from 'adaptive-memory-multi-model-router';
24
-
25
- const router = createA3MRouter({
26
- memory: true, // Enable memory tree
27
- costBudget: 0.05, // Max cost per request in USD
28
- providers: ['openai', 'groq', 'anthropic'], // Enabled providers
29
- maxLatency: 2000, // Max latency in ms
30
- cacheEnabled: true // Enable caching
31
- });
24
+ ```bash
25
+ npm install adaptive-memory-multi-model-router
32
26
  ```
33
27
 
34
- **Parameters:**
28
+ ### Import
35
29
 
36
- | Name | Type | Default | Description |
37
- |------|------|---------|-------------|
38
- | `memory` | boolean | `false` | Enable memory tree |
39
- | `costBudget` | number | `0.10` | Max cost per request |
40
- | `providers` | string[] | `['openai']` | Enabled providers |
41
- | `maxLatency` | number | `5000` | Max latency in ms |
42
- | `cacheEnabled` | boolean | `true` | Enable response cache |
30
+ ```typescript
31
+ import { A3MRouter } from 'adaptive-memory-multi-model-router/sdk';
32
+ ```
43
33
 
44
- **Returns:** `A3MRouter` instance
34
+ ### Constructor
45
35
 
46
- ---
36
+ ```typescript
37
+ const router = new A3MRouter(config?: A3MRouterConfig);
38
+ ```
47
39
 
48
- ### router.route()
40
+ **A3MRouterConfig:**
49
41
 
50
- Routes a request to the optimal provider.
42
+ | Option | Type | Default | Description |
43
+ |--------|------|---------|-------------|
44
+ | `defaultModel` | `string` | — | Fallback model when routing is ambiguous |
45
+ | `maxCostPerQuery` | `number` | — | Max cost per query in USD |
46
+ | `preferSpeedOverQuality` | `boolean` | `false` | Prefer fast models over higher quality |
47
+ | `providers` | `string[]` | all | Restrict routing to these provider IDs |
51
48
 
52
- ```javascript
53
- const result = await router.route({
54
- prompt: 'Your prompt here',
55
- context: {
56
- type: 'coding', // 'coding', 'analysis', 'creative'
57
- language: 'python', // Optional language hint
58
- domain: 'tech' // Optional domain hint
59
- },
60
- options: {
61
- maxCost: 0.02,
62
- maxLatency: 2000
63
- }
64
- });
65
- ```
49
+ ### Methods
66
50
 
67
- **Parameters:**
51
+ #### `route(query: string): RoutingResult`
68
52
 
69
- | Name | Type | Description |
70
- |------|------|-------------|
71
- | `prompt` | string | The input prompt |
72
- | `context` | object | Routing context |
73
- | `options.maxCost` | number | Max cost for this request |
74
- | `options.maxLatency` | number | Max latency in ms |
53
+ Route a query to the best available model. Returns the decision without executing the query.
75
54
 
76
- **Returns:**
55
+ ```typescript
56
+ const decision = router.route("Write a Python function to sort a list");
77
57
 
78
- ```javascript
79
- {
80
- output: 'Response text',
81
- provider: 'openai',
82
- model: 'gpt-4o',
83
- cost: 0.0015,
84
- latency: 850,
85
- tokens: { prompt: 150, completion: 200 }
86
- }
58
+ console.log(decision.model); // "groq/llama-3.3-70b-versatile"
59
+ console.log(decision.tier); // "cheap"
60
+ console.log(decision.cost); // 0.00035
61
+ console.log(decision.complexity); // 0.35
62
+ console.log(decision.reasoning); // "Selected Groq/llama-3.3-70b for code detected"
63
+ console.log(decision.fallbackModels); // ["cerebras/llama-3.3-70b", "mistral/mistral-small"]
64
+ console.log(decision.isFree); // false
65
+ console.log(decision.isExpert); // false
87
66
  ```
88
67
 
89
- ---
68
+ **RoutingResult:**
90
69
 
91
- ## Memory Module
70
+ | Field | Type | Description |
71
+ |-------|------|-------------|
72
+ | `model` | `string` | Selected model identifier |
73
+ | `tier` | `'free' \| 'cheap' \| 'mid' \| 'premium'` | Cost tier |
74
+ | `cost` | `number` | Estimated cost in USD |
75
+ | `complexity` | `number` | Query complexity score (0.0–1.0) |
76
+ | `reasoning` | `string` | Human-readable routing reason |
77
+ | `fallbackModels` | `string[]` | Alternative models in priority order |
78
+ | `isFree` | `boolean` | Whether the selected model is free |
79
+ | `isExpert` | `boolean` | Whether this is an expert-level query |
92
80
 
93
- ### MemoryTree
81
+ #### `routeBatch(queries: string[]): RoutingResult[]`
94
82
 
95
- Hierarchical memory with LRU cache and fast index.
83
+ Route multiple queries at once.
96
84
 
97
- ```javascript
98
- import { MemoryTree } from 'adaptive-memory-multi-model-router/memory';
99
-
100
- const tree = new MemoryTree(maxChunkSize = 3000);
85
+ ```typescript
86
+ const decisions = router.routeBatch([
87
+ "What is 2+2?",
88
+ "Design a distributed database",
89
+ "Translate to French"
90
+ ]);
91
+
92
+ decisions.forEach((d, i) => {
93
+ console.log(`Query ${i}: ${d.model} ($${d.cost.toFixed(6)})`);
94
+ });
101
95
  ```
102
96
 
103
- #### tree.add(data)
97
+ #### `recommend(task: string): RoutingResult`
104
98
 
105
- Adds data to memory tree.
99
+ Get model recommendation for a task category.
106
100
 
107
- ```javascript
108
- await tree.add('Your context content here');
109
- await tree.add('More content for the tree');
101
+ ```typescript
102
+ const rec = router.recommend("code generation");
103
+ console.log(rec.model); // "deepseek/deepseek-chat"
110
104
  ```
111
105
 
112
- #### tree.search(query)
106
+ #### `analyze(query: string): QueryFeatures`
113
107
 
114
- Fast indexed search.
108
+ Extract detailed features from a query for debugging.
115
109
 
116
- ```javascript
117
- const results = tree.search('keyword');
118
- // Returns: [{ id, content, score, accessCount, ... }]
110
+ ```typescript
111
+ const features = router.analyze("Design a secure authentication system for a healthcare app");
112
+
113
+ console.log(features.complexity); // 0.72
114
+ console.log(features.has_code); // false
115
+ console.log(features.requires_reasoning); // true
116
+ console.log(features.is_security); // true
117
+ console.log(features.detected_domain); // "security"
118
+ console.log(features.domain_score); // 0.30
119
+ ```
120
+
121
+ **QueryFeatures:**
122
+
123
+ | Field | Type | Description |
124
+ |-------|------|-------------|
125
+ | `complexity` | `number` | Overall complexity score (0.0–1.0) |
126
+ | `length` | `number` | Word count |
127
+ | `has_code` | `boolean` | Code-related keywords detected |
128
+ | `has_math` | `boolean` | Math-related keywords detected |
129
+ | `is_multilingual` | `boolean` | Non-ASCII characters detected |
130
+ | `is_translation` | `boolean` | Translation request detected |
131
+ | `is_creative` | `boolean` | Creative writing request |
132
+ | `requires_reasoning` | `boolean` | Analytical/reasoning verbs detected |
133
+ | `is_security` | `boolean` | Security domain keywords |
134
+ | `is_devops` | `boolean` | DevOps/infrastructure keywords |
135
+ | `is_data` | `boolean` | Data/ML keywords |
136
+ | `detected_domain` | `string` | Best matching domain (legal, medical, finance, security, architecture, ml_research) |
137
+ | `domain_score` | `number` | Domain match confidence |
138
+
139
+ #### `serve(port?: number): Promise<string>`
140
+
141
+ Start the OpenAI-compatible proxy server.
142
+
143
+ ```typescript
144
+ const proxyURL = await router.serve(8787);
145
+ console.log(proxyURL); // "http://localhost:8787/v1"
146
+
147
+ // Now use with any OpenAI SDK
148
+ import OpenAI from 'openai';
149
+ const client = new OpenAI({ baseURL: proxyURL, apiKey: 'not-needed' });
119
150
  ```
120
151
 
121
- #### tree.getContext(maxTokens)
152
+ #### `proxyURL` (getter)
122
153
 
123
- Gets context for routing.
154
+ Returns the proxy URL. Available after `serve()` is called, otherwise returns the default.
124
155
 
125
- ```javascript
126
- const context = tree.getContext(3000);
127
- // Returns: concatenated context string
156
+ ```typescript
157
+ router.serve(3000);
158
+ console.log(router.proxyURL); // "http://localhost:3000/v1"
128
159
  ```
129
160
 
130
- #### tree.toMarkdown()
161
+ ### Tier Classification
131
162
 
132
- Exports memory as Obsidian-compatible markdown.
163
+ Complexity scores map to tiers:
133
164
 
134
- ```javascript
135
- const md = tree.toMarkdown();
136
- fs.writeFileSync('./memory.md', md);
137
- ```
165
+ | Tier | Complexity Range | Typical Models | Cost/1M tokens |
166
+ |------|:----------------:|----------------|:--------------:|
167
+ | `free` | 0.00 – 0.19 | CommandCode, Ollama, LM Studio | $0.00 |
168
+ | `cheap` | 0.20 – 0.44 | Groq Llama, Cerebras, DeepSeek | ~$0.60 |
169
+ | `mid` | 0.45 – 0.64 | Mistral Small, GPT-4o-mini | ~$1.50 |
170
+ | `premium` | 0.65 – 1.00 | GPT-4o, Claude Sonnet, Gemini Pro | $2.50+ |
138
171
 
139
- #### tree.getStats()
172
+ ### Low-Level API
140
173
 
141
- Returns tree statistics.
174
+ The SDK wraps these lower-level exports, also available directly:
142
175
 
143
- ```javascript
144
- const stats = tree.getStats();
145
- // { totalChunks, maxDepth, indexSize, lruSize }
176
+ ```typescript
177
+ import {
178
+ routeQuery,
179
+ routeBatch,
180
+ recommendForTask,
181
+ extractQueryFeatures,
182
+ createA3MRouter,
183
+ getAvailableProviders,
184
+ registerProvider,
185
+ createProxyServer,
186
+ } from 'adaptive-memory-multi-model-router';
187
+
188
+ // Direct routing
189
+ const result = routeQuery("What is 2+2?");
190
+ // => { primary_model, fallback_models, confidence, reasoning, estimated_cost, ... }
191
+
192
+ // Router instance (v1 style)
193
+ const router = createA3MRouter();
194
+ const decision = router.route("Hello");
146
195
  ```
147
196
 
148
197
  ---
149
198
 
150
- ### EpisodicMemoryStore
199
+ ## Python SDK
151
200
 
152
- Episodic memory for routing decisions.
201
+ ### Installation
153
202
 
154
- ```javascript
155
- import { EpisodicMemoryStore } from 'adaptive-memory-multi-model-router';
156
-
157
- const memory = new EpisodicMemoryStore();
203
+ ```bash
204
+ pip install a3m-router
158
205
  ```
159
206
 
160
- #### memory.record(request, response, routing)
207
+ ### Usage
161
208
 
162
- Records a routing decision.
209
+ ```python
210
+ from a3m import A3MRouter
163
211
 
164
- ```javascript
165
- await memory.record(request, response, {
166
- provider: 'openai',
167
- model: 'gpt-4o',
168
- reasoning: 'Simple query, fast model sufficient'
169
- });
170
- ```
212
+ # Create router instance
213
+ router = A3MRouter()
171
214
 
172
- #### memory.getSimilar(request)
215
+ # Route a query
216
+ decision = router.route("Write a Python function")
217
+ print(decision.model) # "groq/llama-3.3-70b"
218
+ print(decision.tier) # "cheap"
219
+ print(decision.cost) # 0.0004
220
+ print(decision.complexity) # 0.35
173
221
 
174
- Gets similar past requests.
222
+ # Chat through the router (auto-selects model)
223
+ response = router.chat("What is 2+2?")
224
+ print(response.content) # "4"
225
+ print(response.model) # "groq/llama-3.3-70b"
175
226
 
176
- ```javascript
177
- const similar = await memory.getSimilar({ prompt: 'Debug Python' });
178
- // Returns routing decisions for similar prompts
227
+ # Analyze query features
228
+ features = router.analyze("Design a microservice architecture")
229
+ print(features.complexity) # 0.58
230
+ print(features.has_code) # False
231
+ print(features.detected_domain) # "architecture"
179
232
  ```
180
233
 
181
- ---
182
-
183
- ### ObsidianVault
234
+ ### Async Usage
184
235
 
185
- Exports routing decisions as markdown files.
236
+ ```python
237
+ import asyncio
238
+ from a3m import A3MRouter
186
239
 
187
- ```javascript
188
- import { ObsidianVault } from 'adaptive-memory-multi-model-router/vault';
240
+ async def main():
241
+ router = A3MRouter()
242
+
243
+ # Async chat
244
+ response = await router.achat("Explain quantum computing")
245
+ print(response.content)
246
+
247
+ # Batch routing
248
+ decisions = router.route_batch([
249
+ "What is 2+2?",
250
+ "Design a distributed system",
251
+ "Write a poem"
252
+ ])
253
+ for d in decisions:
254
+ print(f"{d.model} ({d.tier}) — ${d.cost:.6f}")
189
255
 
190
- const vault = new ObsidianVault({ path: './vault' });
256
+ asyncio.run(main())
191
257
  ```
192
258
 
193
- #### vault.saveDecision(decision)
259
+ ### With OpenAI Python SDK
194
260
 
195
- Saves a routing decision as markdown.
261
+ ```python
262
+ from openai import OpenAI
196
263
 
197
- ```javascript
198
- await vault.saveDecision({
199
- id: 'decision-001',
200
- timestamp: Date.now(),
201
- prompt: 'Explain quantum',
202
- selectedProvider: 'openai',
203
- selectedModel: 'gpt-4o',
204
- reasoning: 'Complex topic, use best model',
205
- cost: 0.003,
206
- latency: 1200
207
- });
208
- ```
209
-
210
- #### vault.getRecentDecisions(count)
211
-
212
- Gets recent decisions.
264
+ # Point OpenAI SDK at the A3M proxy
265
+ client = OpenAI(
266
+ base_url="http://localhost:8787/v1",
267
+ api_key="not-needed"
268
+ )
213
269
 
214
- ```javascript
215
- const recent = vault.getRecentDecisions(10);
270
+ response = client.chat.completions.create(
271
+ model="auto",
272
+ messages=[{"role": "user", "content": "Hello!"}]
273
+ )
274
+ print(response.choices[0].message.content)
216
275
  ```
217
276
 
218
277
  ---
219
278
 
220
- ## Compression Module
221
-
222
- ### EnhancedCompression
279
+ ## CLI
223
280
 
224
- TokenJuice-style compression with caching.
281
+ ### Installation
225
282
 
226
- ```javascript
227
- import { EnhancedCompression } from 'adaptive-memory-multi-model-router/compression';
228
-
229
- const compressor = new EnhancedCompression();
283
+ ```bash
284
+ npm install -g adaptive-memory-multi-model-router
285
+ # or use without installing:
286
+ npx a3m-router <command>
230
287
  ```
231
288
 
232
- #### compressor.compress(text)
289
+ ### Commands
233
290
 
234
- Compresses text (HTML→Markdown, URL shortening, etc).
291
+ #### `route` Route a query
235
292
 
236
- ```javascript
237
- const compressed = compressor.compress('<h1>Hello</h1><p>URL: https://very-long-url.com</p>');
238
- // Returns: '# Hello\n\nURL: very-long-url.com/...'
293
+ ```bash
294
+ npx a3m-router route "Your query here"
239
295
  ```
240
296
 
241
- #### compressor.getStats(original, compressed)
297
+ Output:
298
+ ```
299
+ Primary: groq/llama-3.3-70b-versatile
300
+ Fallbacks: cerebras/llama-3.3-70b, mistral/mistral-small
301
+ Est. Cost: $0.000350
302
+ Type: api
303
+ Reason: Selected Groq for code detected, fast tier
304
+ ```
242
305
 
243
- Gets compression statistics.
306
+ #### `serve` — Start proxy server
244
307
 
245
- ```javascript
246
- const stats = compressor.getStats(original, compressed);
247
- // { original: 200, compressed: 80, reduction: '60.0%', ratio: '0.40' }
308
+ ```bash
309
+ npx a3m-router serve --port 8787
248
310
  ```
249
311
 
250
- ---
312
+ Options:
313
+ - `--port` / `-p` — Port to listen on (default: 8787)
251
314
 
252
- ### isonEncode / isonDecode
315
+ #### `benchmark` Run routing accuracy benchmark
253
316
 
254
- ISON format compression.
317
+ ```bash
318
+ npx a3m-router benchmark
319
+ ```
255
320
 
256
- ```javascript
257
- import { isonEncode, isonDecode } from 'adaptive-memory-multi-model-router/utils/compression';
321
+ #### `providers` — List configured providers
258
322
 
259
- const encoded = isonEncode(messages);
260
- const decoded = isonDecode(encoded);
323
+ ```bash
324
+ npx a3m-router providers
261
325
  ```
262
326
 
263
- ---
327
+ #### `models` — List known models
264
328
 
265
- ## Auto-Fetch Module
329
+ ```bash
330
+ npx a3m-router models
331
+ ```
266
332
 
267
- ### AutoFetch
333
+ #### `recommend` — Get model recommendation for a task
268
334
 
269
- Periodically syncs data from connected tools.
335
+ ```bash
336
+ npx a3m-router recommend "code generation"
337
+ ```
270
338
 
271
- ```javascript
272
- import { AutoFetch } from 'adaptive-memory-multi-model-router/autofetch';
339
+ #### `cost` — Estimate token cost
273
340
 
274
- const fetcher = new AutoFetch({
275
- intervalMs: 20 * 60 * 1000, // 20 minutes
276
- targets: ['github', 'notion', 'slack', 'gmail', 'calendar']
277
- });
341
+ ```bash
342
+ npx a3m-router cost "Your text here"
278
343
  ```
279
344
 
280
- #### fetcher.start()
281
-
282
- Starts the sync loop.
345
+ #### `token` — Count tokens
283
346
 
284
- ```javascript
285
- fetcher.start();
347
+ ```bash
348
+ npx a3m-router token "Your text here"
286
349
  ```
287
350
 
288
- #### fetcher.syncAll()
351
+ #### `batch` — Route multiple queries
289
352
 
290
- Triggers immediate sync.
291
-
292
- ```javascript
293
- const results = await fetcher.syncAll();
294
- // Returns: Map<target, SyncResult>
353
+ ```bash
354
+ npx a3m-router batch "What is 2+2?" "Design a system" "Write a poem"
295
355
  ```
296
356
 
297
- #### fetcher.stop()
357
+ #### `compare` — Compare providers side by side
298
358
 
299
- Stops the sync loop.
359
+ ```bash
360
+ npx a3m-router compare "Your query"
361
+ ```
300
362
 
301
- ```javascript
302
- fetcher.stop();
363
+ #### `test` — Test all configured providers
364
+
365
+ ```bash
366
+ npx a3m-router test
303
367
  ```
304
368
 
305
- #### fetcher.getStats()
369
+ #### `memory` — Memory operations
306
370
 
307
- Gets sync statistics.
371
+ ```bash
372
+ npx a3m-router memory add "key" "value"
373
+ npx a3m-router memory search "query"
374
+ npx a3m-router memory stats
375
+ ```
308
376
 
309
- ```javascript
310
- const stats = fetcher.getStats();
311
- // { totalTargets: 5, failedTargets: 0 }
377
+ #### `status` — Show router status
378
+
379
+ ```bash
380
+ npx a3m-router status
312
381
  ```
313
382
 
314
383
  ---
315
384
 
316
- ## OAuth Module
385
+ ## REST API
317
386
 
318
- ### OAuthManager
387
+ Start the server:
319
388
 
320
- One-click OAuth for integrations.
389
+ ```bash
390
+ npx a3m-router serve --port 8787
391
+ ```
321
392
 
322
- ```javascript
323
- import { OAuthManager } from 'adaptive-memory-multi-model-router/oauth';
393
+ Base URL: `http://localhost:8787`
324
394
 
325
- const oauth = new OAuthManager();
326
- ```
395
+ ### POST /v1/chat/completions
327
396
 
328
- #### oauth.configure(provider, config)
397
+ OpenAI-compatible chat endpoint. Supports both streaming and non-streaming.
329
398
 
330
- Configures an OAuth provider.
399
+ **Request:**
331
400
 
332
- ```javascript
333
- oauth.configure('github', {
334
- clientId: 'your-client-id',
335
- clientSecret: 'your-secret',
336
- redirectUri: 'http://localhost:3000/callback'
337
- });
401
+ ```bash
402
+ curl http://localhost:8787/v1/chat/completions \
403
+ -H "Content-Type: application/json" \
404
+ -d '{
405
+ "model": "auto",
406
+ "messages": [
407
+ {"role": "system", "content": "You are a helpful assistant."},
408
+ {"role": "user", "content": "What is 2+2?"}
409
+ ],
410
+ "temperature": 0.7,
411
+ "max_tokens": 1024,
412
+ "stream": false
413
+ }'
338
414
  ```
339
415
 
340
- #### oauth.getAuthUrl(provider)
416
+ **Request Body:**
341
417
 
342
- Gets authorization URL.
418
+ | Field | Type | Default | Description |
419
+ |-------|------|---------|-------------|
420
+ | `model` | `string` | `"auto"` | Model to use. `"auto"` triggers routing. Accepts `provider/model` format. |
421
+ | `messages` | `array` | required | OpenAI-format message array |
422
+ | `temperature` | `number` | provider default | Sampling temperature (0–2) |
423
+ | `max_tokens` | `number` | `1024` | Maximum tokens to generate |
424
+ | `stream` | `boolean` | `false` | Enable SSE streaming |
425
+ | `stop` | `string \| string[]` | — | Stop sequences |
343
426
 
344
- ```javascript
345
- const url = oauth.getAuthUrl('github');
346
- // Opens OAuth flow
347
- ```
427
+ **Non-streaming response:**
348
428
 
349
- #### oauth.handleCallback(provider, code, state)
429
+ ```json
430
+ {
431
+ "id": "chatcmpl-a1b2c3d4",
432
+ "object": "chat.completion",
433
+ "created": 1716000000,
434
+ "model": "llama-3.3-70b-versatile",
435
+ "choices": [
436
+ {
437
+ "index": 0,
438
+ "message": {
439
+ "role": "assistant",
440
+ "content": "2 + 2 = 4"
441
+ },
442
+ "finish_reason": "stop"
443
+ }
444
+ ],
445
+ "usage": {
446
+ "prompt_tokens": 24,
447
+ "completion_tokens": 5,
448
+ "total_tokens": 29
449
+ }
450
+ }
451
+ ```
350
452
 
351
- Handles OAuth callback.
453
+ **Streaming response:**
352
454
 
353
- ```javascript
354
- const tokens = await oauth.handleCallback('github', code, state);
355
455
  ```
456
+ data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":...,"model":"...","choices":[{"index":0,"delta":{"content":"2"},"finish_reason":null}]}
356
457
 
357
- #### oauth.isConnected(provider)
458
+ data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":...,"model":"...","choices":[{"index":0,"delta":{"content":" +"},"finish_reason":null}]}
358
459
 
359
- Checks if provider is connected.
460
+ data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":...,"model":"...","choices":[{"index":0,"delta":{"content":" 2 = 4"},"finish_reason":null}]}
360
461
 
361
- ```javascript
362
- const connected = oauth.isConnected('github');
462
+ data: {"id":"chatcmpl-...","object":"chat.completion.chunk","created":...,"model":"...","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
463
+
464
+ data: [DONE]
363
465
  ```
364
466
 
365
- #### oauth.getAccessToken(provider)
467
+ **Model routing:**
366
468
 
367
- Gets valid access token (auto-refreshes).
469
+ | Model value | Behavior |
470
+ |-------------|----------|
471
+ | `"auto"` | Routes based on query complexity (recommended) |
472
+ | `"groq/llama-3.3-70b-versatile"` | Uses specific provider/model |
473
+ | `"gpt-4o"` | Maps to configured OpenAI provider |
474
+ | `"claude-sonnet"` | Maps to configured Anthropic provider |
368
475
 
369
- ```javascript
370
- const token = await oauth.getAccessToken('github');
476
+ ### POST /v1/completions
477
+
478
+ OpenAI-compatible text completions endpoint.
479
+
480
+ ```bash
481
+ curl http://localhost:8787/v1/completions \
482
+ -H "Content-Type: application/json" \
483
+ -d '{
484
+ "model": "auto",
485
+ "prompt": "The capital of France is",
486
+ "max_tokens": 50
487
+ }'
371
488
  ```
372
489
 
373
- ---
490
+ **Response:**
374
491
 
375
- ## Provider Registry
492
+ ```json
493
+ {
494
+ "id": "chatcmpl-...",
495
+ "object": "text_completion",
496
+ "created": 1716000000,
497
+ "model": "llama-3.3-70b-versatile",
498
+ "choices": [
499
+ {
500
+ "text": " Paris.",
501
+ "index": 0,
502
+ "finish_reason": "stop"
503
+ }
504
+ ],
505
+ "usage": {
506
+ "prompt_tokens": 5,
507
+ "completion_tokens": 2,
508
+ "total_tokens": 7
509
+ }
510
+ }
511
+ ```
376
512
 
377
- ### ProviderRegistry
513
+ ### POST /v1/route
378
514
 
379
- Manages 14 LLM providers.
515
+ Route a query without executing it. Returns the routing decision.
380
516
 
381
- ```javascript
382
- import { ProviderRegistry } from 'adaptive-memory-multi-model-router/providers';
517
+ ```bash
518
+ curl -X POST http://localhost:8787/v1/route \
519
+ -H "Content-Type: application/json" \
520
+ -d '{"query": "Write a Python function to sort a list"}'
521
+ ```
383
522
 
384
- const registry = new ProviderRegistry();
523
+ **Response:**
524
+
525
+ ```json
526
+ {
527
+ "primary_model": "groq/llama-3.3-70b-versatile",
528
+ "fallback_models": ["cerebras/llama-3.3-70b", "mistral/mistral-small"],
529
+ "confidence": 0.82,
530
+ "reasoning": "Selected Groq for code detected, fast tier",
531
+ "estimated_cost": 0.00035,
532
+ "estimated_latency_ms": 800,
533
+ "features": {
534
+ "complexity": 0.35,
535
+ "has_code": true,
536
+ "has_math": false,
537
+ "requires_reasoning": false,
538
+ "detected_domain": ""
539
+ }
540
+ }
385
541
  ```
386
542
 
387
- #### registry.getReadyProviders()
543
+ ### GET /v1/models
388
544
 
389
- Gets currently available providers.
545
+ List all available models.
390
546
 
391
- ```javascript
392
- const ready = registry.getReadyProviders();
393
- // ['openai', 'groq', 'anthropic']
547
+ ```bash
548
+ curl http://localhost:8787/v1/models
394
549
  ```
395
550
 
396
- #### registry.selectModel()
551
+ **Response:**
397
552
 
398
- Selects optimal model based on cost-latency tradeoff.
399
-
400
- ```javascript
401
- const model = registry.selectModel();
402
- // 'openai/gpt-4o'
553
+ ```json
554
+ {
555
+ "object": "list",
556
+ "data": [
557
+ {
558
+ "id": "groq/llama-3.3-70b-versatile",
559
+ "object": "model",
560
+ "owned_by": "groq"
561
+ }
562
+ ]
563
+ }
403
564
  ```
404
565
 
405
- #### registry.recordSuccess(provider)
566
+ ### GET /health
406
567
 
407
- Records successful request.
568
+ Health check with provider status and cost summary.
408
569
 
409
- ```javascript
410
- registry.recordSuccess('openai');
570
+ ```bash
571
+ curl http://localhost:8787/health
411
572
  ```
412
573
 
413
- #### registry.recordFailure(provider)
574
+ **Response:**
414
575
 
415
- Records failed request.
576
+ ```json
577
+ {
578
+ "status": "ok",
579
+ "version": "2.1.0",
580
+ "providers": {
581
+ "total": 12,
582
+ "healthy": 8,
583
+ "details": {
584
+ "groq": {
585
+ "name": "Groq",
586
+ "type": "api",
587
+ "models": 3,
588
+ "available": true
589
+ }
590
+ }
591
+ },
592
+ "cost": {
593
+ "total": 0.0042,
594
+ "requests": 127
595
+ },
596
+ "uptime": 86400.5,
597
+ "recentRequests": []
598
+ }
599
+ ```
416
600
 
417
- ```javascript
418
- registry.recordFailure('openai');
601
+ ### GET /dashboard
602
+
603
+ Interactive web dashboard (if `public/` directory is present).
604
+
605
+ ```
606
+ http://localhost:8787/
419
607
  ```
420
608
 
421
609
  ---
422
610
 
423
- ## Cost Tracker
611
+ ## OpenAI SDK Compatibility
424
612
 
425
- ### CostTracker
613
+ The A3M Router proxy is fully compatible with the OpenAI SDK. Point the `baseURL` at the proxy and use `model: "auto"` for routing.
426
614
 
427
- Tracks request costs and budgets.
615
+ ### JavaScript/TypeScript
428
616
 
429
617
  ```javascript
430
- import { CostTracker } from 'adaptive-memory-multi-model-router/cost';
618
+ import OpenAI from 'openai';
431
619
 
432
- const tracker = new CostTracker();
433
- ```
620
+ const client = new OpenAI({
621
+ baseURL: 'http://localhost:8787/v1',
622
+ apiKey: 'not-needed'
623
+ });
434
624
 
435
- #### tracker.record(requestInfo)
625
+ // Auto-routing
626
+ const response = await client.chat.completions.create({
627
+ model: 'auto',
628
+ messages: [{ role: 'user', content: 'Hello!' }]
629
+ });
436
630
 
437
- Records a request.
631
+ // Specific model
632
+ const response2 = await client.chat.completions.create({
633
+ model: 'groq/llama-3.3-70b-versatile',
634
+ messages: [{ role: 'user', content: 'Hello!' }]
635
+ });
438
636
 
439
- ```javascript
440
- tracker.record({
441
- provider: 'openai',
442
- model: 'gpt-4o',
443
- promptTokens: 150,
444
- completionTokens: 200,
445
- cost: 0.003
637
+ // Streaming
638
+ const stream = await client.chat.completions.create({
639
+ model: 'auto',
640
+ messages: [{ role: 'user', content: 'Tell me a story' }],
641
+ stream: true
446
642
  });
643
+ for await (const chunk of stream) {
644
+ process.stdout.write(chunk.choices[0]?.delta?.content || '');
645
+ }
447
646
  ```
448
647
 
449
- #### tracker.getSummary()
648
+ ### Python
450
649
 
451
- Gets cost summary.
650
+ ```python
651
+ from openai import OpenAI
452
652
 
453
- ```javascript
454
- const summary = tracker.getSummary();
455
- // { totalRequests, totalCost, byProvider, byModel }
456
- ```
653
+ client = OpenAI(
654
+ base_url="http://localhost:8787/v1",
655
+ api_key="not-needed"
656
+ )
457
657
 
458
- #### tracker.getRemainingBudget(provider)
658
+ response = client.chat.completions.create(
659
+ model="auto",
660
+ messages=[{"role": "user", "content": "Hello!"}]
661
+ )
662
+ print(response.choices[0].message.content)
663
+ ```
459
664
 
460
- Gets remaining budget.
665
+ ### cURL
461
666
 
462
- ```javascript
463
- const remaining = tracker.getRemainingBudget('openai');
667
+ ```bash
668
+ curl http://localhost:8787/v1/chat/completions \
669
+ -H "Content-Type: application/json" \
670
+ -d '{"model":"auto","messages":[{"role":"user","content":"Hello!"}]}'
464
671
  ```
465
672
 
466
673
  ---
467
674
 
468
- ## Circuit Breaker
675
+ ## LangChain Integration
469
676
 
470
- ### CircuitBreaker
677
+ ```typescript
678
+ import { A3MChatModel } from 'adaptive-memory-multi-model-router/langchain';
679
+ import { HumanMessage } from '@langchain/core/messages';
471
680
 
472
- Prevents cascading failures.
681
+ const model = new A3MChatModel({
682
+ modelName: 'auto', // or specific model
683
+ temperature: 0.7,
684
+ });
473
685
 
474
- ```javascript
475
- import { CircuitBreaker } from 'adaptive-memory-multi-model-router/utils/reliability';
686
+ // Invoke
687
+ const response = await model.invoke([
688
+ new HumanMessage("What is 2+2?")
689
+ ]);
690
+ console.log(response.content);
691
+
692
+ // Streaming
693
+ const stream = await model.stream([
694
+ new HumanMessage("Tell me a story")
695
+ ]);
696
+ for await (const chunk of stream) {
697
+ process.stdout.write(chunk.content);
698
+ }
699
+ ```
476
700
 
477
- const breaker = new CircuitBreaker({
478
- name: 'openai',
479
- failureThreshold: 3,
480
- resetTimeout: 60000
481
- });
701
+ **Prerequisites:**
702
+
703
+ ```bash
704
+ npm install @langchain/core @langchain/openai
482
705
  ```
483
706
 
484
- #### breaker.canExecute()
707
+ LangChain is a peer dependency — install it separately.
485
708
 
486
- Checks if request can proceed.
709
+ ---
487
710
 
488
- ```javascript
489
- if (breaker.canExecute()) {
490
- // Proceed with request
491
- }
492
- ```
711
+ ## Configuration
493
712
 
494
- #### breaker.recordSuccess()
713
+ ### Environment Variables
495
714
 
496
- Records success.
715
+ | Variable | Description | Default |
716
+ |----------|-------------|---------|
717
+ | `PORT` | Proxy server port | `8787` |
718
+ | `GROQ_API_KEY` | Groq provider API key | — |
719
+ | `CEREBRAS_API_KEY` | Cerebras provider API key | — |
720
+ | `OPENAI_API_KEY` | OpenAI provider API key | — |
721
+ | `ANTHROPIC_API_KEY` | Anthropic provider API key | — |
722
+ | `GOOGLE_API_KEY` | Google/Gemini provider API key | — |
723
+ | `MISTRAL_API_KEY` | Mistral provider API key | — |
724
+ | `DEEPSEEK_API_KEY` | DeepSeek provider API key | — |
725
+ | `OPENROUTER_API_KEY` | OpenRouter provider API key | — |
497
726
 
498
- ```javascript
499
- breaker.recordSuccess();
500
- ```
727
+ ### Config File
501
728
 
502
- #### breaker.recordFailure()
729
+ Provider configuration is stored at `~/.config/a3m-router/providers.json`:
503
730
 
504
- Records failure.
731
+ ```json
732
+ {
733
+ "providers": {
734
+ "groq": {
735
+ "apiKey": "gsk_...",
736
+ "models": ["llama-3.3-70b-versatile", "mixtral-8x7b"]
737
+ }
738
+ }
739
+ }
740
+ ```
505
741
 
506
- ```javascript
507
- breaker.recordFailure();
742
+ ### Programmatic Provider Registration
743
+
744
+ ```typescript
745
+ import { registerProvider } from 'adaptive-memory-multi-model-router';
746
+
747
+ registerProvider('my-provider', {
748
+ name: 'My Provider',
749
+ type: 'api',
750
+ apiKey: 'sk-...',
751
+ baseUrl: 'https://api.my-provider.com/v1/chat/completions',
752
+ models: ['my-model-v1'],
753
+ costPerK: { input: 0.50, output: 1.50 },
754
+ maxTokens: 8192,
755
+ priority: 5,
756
+ });
508
757
  ```
509
758
 
510
759
  ---
511
760
 
512
- ## CLI Commands
761
+ ## Error Handling
513
762
 
514
- | Command | Description |
515
- |---------|-------------|
516
- | `a3m-router route "prompt"` | Route to optimal model |
517
- | `a3m-router parallel "t1" "t2" "t3"` | Parallel execution |
518
- | `a3m-router compare "prompt"` | Compare models |
519
- | `a3m-router cost` | Show cost summary |
520
- | `a3m-router count "text"` | Count tokens |
521
- | `a3m-router compress "text"` | Compress text |
522
- | `a3m-router local "prompt"` | Local Ollama |
523
- | `a3m-router providers` | List providers |
763
+ ### HTTP Error Responses
524
764
 
525
- ---
765
+ All errors follow the OpenAI error format:
526
766
 
527
- ## Error Handling
767
+ ```json
768
+ {
769
+ "error": {
770
+ "message": "No provider available for model \"gpt-4o\". Configure API keys.",
771
+ "type": "server_error",
772
+ "code": 503
773
+ }
774
+ }
775
+ ```
528
776
 
529
- ```javascript
530
- import { CircuitBreaker, withRetry } from 'adaptive-memory-multi-model-router';
777
+ | Status | Type | Description |
778
+ |--------|------|-------------|
779
+ | 400 | `invalid_request_error` | Malformed request body or missing fields |
780
+ | 404 | `not_found` | Unknown endpoint |
781
+ | 502 | `upstream_error` | Provider returned an error |
782
+ | 503 | `server_error` | No providers available |
531
783
 
532
- const breaker = new CircuitBreaker({ name: 'test' });
784
+ ### Fallback Behavior
785
+
786
+ When the primary provider fails, the proxy automatically tries alternative providers in order:
787
+
788
+ 1. Primary provider (routed or specified)
789
+ 2. Other configured API providers
790
+ 3. Returns 502 if all providers fail
791
+
792
+ ### SDK Error Handling
793
+
794
+ ```typescript
795
+ const router = new A3MRouter();
533
796
 
534
797
  try {
535
- const result = await withRetry(
536
- () => router.route({ prompt: 'test' }),
537
- { maxRetries: 3, retryDelay: 1000 }
538
- );
539
- } catch (error) {
540
- if (breaker.getState().status === 'open') {
541
- console.log('Circuit open - using fallback');
798
+ const decision = router.route("Your query");
799
+ if (decision.model === 'unknown') {
800
+ // No providers available
542
801
  }
802
+ } catch (err) {
803
+ console.error('Routing failed:', err);
543
804
  }
544
805
  ```
545
806
 
546
807
  ---
547
808
 
548
- ## TypeScript Support
809
+ ## Provider Support
549
810
 
550
- A3M Router is written in TypeScript with full type definitions.
811
+ ### Supported Provider Types
812
+
813
+ | Type | Providers | Protocol |
814
+ |------|-----------|----------|
815
+ | **API** | Groq, Cerebras, OpenAI, Anthropic, Google, Mistral, DeepSeek, OpenRouter | REST API |
816
+ | **Local** | Ollama, vLLM, LM Studio | OpenAI-compatible local API |
817
+ | **CLI** | CommandCode, OpenCode | Local CLI tools |
818
+
819
+ ### Adding Custom Providers
551
820
 
552
821
  ```typescript
553
- import { createA3MRouter, type A3MRouterConfig } from 'adaptive-memory-multi-model-router';
822
+ import { registerProvider } from 'adaptive-memory-multi-model-router';
823
+
824
+ registerProvider('custom', {
825
+ name: 'Custom LLM',
826
+ type: 'api',
827
+ apiKey: process.env.CUSTOM_API_KEY,
828
+ baseUrl: 'https://api.custom.com/v1/chat/completions',
829
+ models: ['custom-v1'],
830
+ costPerK: { input: 1.0, output: 2.0 },
831
+ maxTokens: 4096,
832
+ priority: 5,
833
+ });
834
+ ```
554
835
 
555
- const config: A3MRouterConfig = {
556
- memory: true,
557
- costBudget: 0.05,
558
- providers: ['openai', 'groq']
559
- };
836
+ ---
560
837
 
561
- const router = createA3MRouter(config);
838
+ ## Architecture
839
+
840
+ ```
841
+ ┌──────────────┐ ┌──────────────────────────────────────────┐
842
+ │ Your Code │────>│ A3M Router │
843
+ │ │ │ │
844
+ │ OpenAI SDK │ │ ┌─────────┐ ┌──────────────────┐ │
845
+ │ LangChain │ │ │ Routing │───>│ Model Selection │ │
846
+ │ Python SDK │ │ │ Engine │ │ (cost/quality) │ │
847
+ │ CLI │ │ └─────────┘ └──────┬───────────┘ │
848
+ │ cURL │ │ │ │
849
+ └──────────────┘ │ ┌─────────────────────▼────────────┐ │
850
+ │ │ Provider Layer │ │
851
+ │ │ Groq | Cerebras | OpenAI | ... │ │
852
+ │ │ Ollama | vLLM | LM Studio │ │
853
+ │ └───────────────────────────────────┘ │
854
+ └──────────────────────────────────────────┘
562
855
  ```