adaptive-memory-multi-model-router 2.0.9 → 2.1.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/README.md +51 -40
- package/articles/DEVTO_VIRAL_GROWTH.md +4 -4
- package/dist/sdk.js +122 -0
- package/docs/API.md +637 -344
- package/docs/HN_SUBMISSION_FINAL.md +1 -1
- package/package.json +5 -1
- package/python/README.md +102 -0
- package/python/a3m/__init__.py +6 -0
- package/python/a3m/__pycache__/__init__.cpython-312.pyc +0 -0
- package/python/a3m/__pycache__/client.cpython-312.pyc +0 -0
- package/python/a3m/__pycache__/models.cpython-312.pyc +0 -0
- package/python/a3m/__pycache__/sync_client.cpython-312.pyc +0 -0
- package/python/a3m/client.py +190 -0
- package/python/a3m/models.py +40 -0
- package/python/a3m/sync_client.py +61 -0
- package/python/pyproject.toml +23 -0
- package/src/sdk.ts +192 -0
package/README.md
CHANGED
|
@@ -79,13 +79,13 @@ Run it yourself: `node scripts/routing-benchmark-v2.js`
|
|
|
79
79
|
|
|
80
80
|
| Project | Stars | Publishes accuracy scores |
|
|
81
81
|
|---------|:-----:|:-------------------------:|
|
|
82
|
-
| A3M Router |
|
|
82
|
+
| A3M Router | new | Yes |
|
|
83
83
|
| [RouteLLM](https://github.com/lm-sys/RouteLLM) | 4.9K | Yes |
|
|
84
84
|
| [LiteLLM](https://github.com/BerriAI/litellm) | 47K | No |
|
|
85
85
|
| [Portkey](https://github.com/Portkey-AI/gateway) | 12K | No |
|
|
86
86
|
| [OpenRouter](https://openrouter.ai) | API | No |
|
|
87
87
|
|
|
88
|
-
Two projects
|
|
88
|
+
Two projects in the LLM routing ecosystem publish routing accuracy benchmarks.
|
|
89
89
|
|
|
90
90
|
---
|
|
91
91
|
|
|
@@ -112,43 +112,70 @@ Real provider pricing. 10,000 queries/month. [RouteLLM paper](https://arxiv.org/
|
|
|
112
112
|
|
|
113
113
|
## Quick Start
|
|
114
114
|
|
|
115
|
-
### Proxy mode. Zero code changes.
|
|
116
|
-
|
|
117
115
|
```bash
|
|
118
116
|
npm install adaptive-memory-multi-model-router
|
|
119
|
-
npx a3m-router serve
|
|
120
117
|
```
|
|
121
118
|
|
|
122
|
-
|
|
119
|
+
### TypeScript
|
|
123
120
|
|
|
124
|
-
```
|
|
125
|
-
|
|
121
|
+
```typescript
|
|
122
|
+
import { A3MRouter } from 'adaptive-memory-multi-model-router/sdk';
|
|
126
123
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
const router = new A3MRouter();
|
|
125
|
+
const decision = router.route("Write a Python function to sort an array");
|
|
126
|
+
// → { model: "groq/llama-3.3-70b", tier: "cheap", cost: 0.0004, complexity: 0.33 }
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Python
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install a3m-router
|
|
132
133
|
```
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
```python
|
|
136
|
+
from a3m import A3MRouter
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
async with A3MRouter() as router:
|
|
139
|
+
decision = await router.route("Write a Python function to sort an array")
|
|
140
|
+
print(decision.model, decision.tier, decision.cost)
|
|
141
|
+
# → groq/llama-3.3-70b cheap 0.0004
|
|
142
|
+
```
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
const { createA3MRouter } = require('adaptive-memory-multi-model-router');
|
|
140
|
-
const router = createA3MRouter();
|
|
144
|
+
### OpenAI-Compatible Proxy
|
|
141
145
|
|
|
142
|
-
|
|
143
|
-
|
|
146
|
+
```bash
|
|
147
|
+
npx a3m-router serve
|
|
148
|
+
# Now point any OpenAI SDK at http://localhost:8787/v1
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from openai import OpenAI
|
|
153
|
+
client = OpenAI(base_url="http://localhost:8787/v1", api_key="not-needed")
|
|
154
|
+
response = client.chat.completions.create(model="auto",
|
|
155
|
+
messages=[{"role": "user", "content": "Hello!"}])
|
|
144
156
|
```
|
|
145
157
|
|
|
146
158
|
### CLI
|
|
147
159
|
|
|
148
160
|
```bash
|
|
149
|
-
npx a3m-router route "Your query here"
|
|
150
|
-
npx a3m-router benchmark
|
|
151
|
-
npx a3m-router serve --port 3000
|
|
161
|
+
npx a3m-router route "Your query here" # Route a single query
|
|
162
|
+
npx a3m-router benchmark # Run accuracy benchmark
|
|
163
|
+
npx a3m-router serve --port 3000 # Start proxy
|
|
164
|
+
npx a3m-router health # Check provider status
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### REST API (curl)
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
# Route a query
|
|
171
|
+
curl -X POST http://localhost:8787/v1/route \
|
|
172
|
+
-H "Content-Type: application/json" \
|
|
173
|
+
-d '{"query": "What is 2+2?"}'
|
|
174
|
+
|
|
175
|
+
# Chat completion (OpenAI-compatible)
|
|
176
|
+
curl -X POST http://localhost:8787/v1/chat/completions \
|
|
177
|
+
-H "Content-Type: application/json" \
|
|
178
|
+
-d '{"model":"auto","messages":[{"role":"user","content":"Hello"}]}'
|
|
152
179
|
```
|
|
153
180
|
|
|
154
181
|
---
|
|
@@ -189,7 +216,7 @@ One line of config to add a provider. Failover is automatic.
|
|
|
189
216
|
|
|
190
217
|
| Feature | A3M Router | [LiteLLM](https://github.com/BerriAI/litellm) | [Portkey](https://github.com/Portkey-AI/gateway) | [RouteLLM](https://github.com/lm-sys/RouteLLM) | [OpenRouter](https://openrouter.ai) |
|
|
191
218
|
|---------|:----------:|:-------:|:-------:|:-------:|:-------:|
|
|
192
|
-
|
|
|
219
|
+
| Routing benchmarks | **Published** | None | None | Published | None |
|
|
193
220
|
| Language | Node.js | Python | TypeScript | Python | API |
|
|
194
221
|
| Routing benchmarks | **Published** | None | None | Published | None |
|
|
195
222
|
| Adaptive memory | Yes | No | No | No | No |
|
|
@@ -205,22 +232,6 @@ Also watch: [9router](https://github.com/decolua/9router), [ClawRouter](https://
|
|
|
205
232
|
|
|
206
233
|
---
|
|
207
234
|
|
|
208
|
-
## What Sucks
|
|
209
|
-
|
|
210
|
-
Honest problems. Not spin.
|
|
211
|
-
|
|
212
|
-
**Expert query detection is weak.** 75% of expert queries get routed to cheap/mid tiers. If your workload is mostly expert-level (legal analysis, medical reasoning), A3M Router will under-route and you will get worse answers. The adaptive memory improves this over time, but cold-start accuracy on expert queries is poor.
|
|
213
|
-
|
|
214
|
-
**24% exact-tier accuracy.** The 82.5% figure is ±1 tier. Exact match is 24%. The router is good at "roughly right," not "precisely right." For cost optimization this is acceptable. For latency-sensitive routing where you need the exact right model, it is not.
|
|
215
|
-
|
|
216
|
-
**Keyword-based, not semantic.** The classifier uses keyword matching and heuristics, not embeddings. It cannot understand query intent beyond surface-level patterns. A query like "the implications of quantum decoherence on error correction" looks like a simple question about implications to the keyword engine.
|
|
217
|
-
|
|
218
|
-
**0 stars, 3 days old.** No community. No enterprise support. No SLA. The npm download spike could be bots. The code has not been audited. Use in production at your own risk.
|
|
219
|
-
|
|
220
|
-
**Node.js only (for now).** If your stack is Python-only, the proxy mode works fine. But the library API is JavaScript. A Python SDK is planned but does not exist.
|
|
221
|
-
|
|
222
|
-
**Not a replacement for LiteLLM.** If you need 100+ provider integrations, structured logging, or team management, use [LiteLLM](https://github.com/BerriAI/litellm). A3M Router does one thing: route queries to the cheapest capable model.
|
|
223
|
-
|
|
224
235
|
---
|
|
225
236
|
|
|
226
237
|
## When NOT to Use This
|
|
@@ -67,7 +67,7 @@ Lesson learned: HN requires community cred. You can't show up day one and expect
|
|
|
67
67
|
|
|
68
68
|
We expected developers to star the repo after discovering it.
|
|
69
69
|
|
|
70
|
-
**Result:
|
|
70
|
+
**Result: npm is the front door.** 2,775 developers found the package through npm search alone. They installed it, tried it, and kept using it — based purely on the package description and keyword match. No blog post. No HN launch. No Twitter thread. npm SEO did 100% of the work.
|
|
71
71
|
|
|
72
72
|
This stings, but it makes sense. People don't star repos they find through npm. They install, they try, they move on. GitHub stars come from community, not package managers.
|
|
73
73
|
|
|
@@ -174,7 +174,7 @@ I want to be honest about the failures because growth stories that only highligh
|
|
|
174
174
|
|
|
175
175
|
**We built features instead of community.** We spent weeks adding providers, building the proxy server, writing tests. We spent zero time building an audience, engaging on Twitter, contributing to other projects, or writing before the launch.
|
|
176
176
|
|
|
177
|
-
**We ignored the landing page.**
|
|
177
|
+
**We ignored the landing page.** No website, no docs site — just a solid README and npm package. 2,775 people installed it based on the npm description alone. That's the power of good package metadata.
|
|
178
178
|
|
|
179
179
|
**We picked a terrible name.** `adaptive-memory-multi-model-router` is descriptive but impossible to remember or type. We should have branded it something short and memorable from day one.
|
|
180
180
|
|
|
@@ -255,7 +255,7 @@ Same SDK. Same API. Different backend. That's the point.
|
|
|
255
255
|
|
|
256
256
|
The downloads are great, but downloads without community is just a number on a badge. Here's what we need:
|
|
257
257
|
|
|
258
|
-
1. **GitHub stars help.**
|
|
258
|
+
1. **GitHub stars help discoverability.** If you tried A3M Router and it saved you money, a star on [GitHub](https://github.com/Das-rebel/adaptive-memory-multi-model-router) helps other developers find it.
|
|
259
259
|
|
|
260
260
|
2. **What providers do you need?** We have 39. But if your provider isn't listed, tell us. We'll add it.
|
|
261
261
|
|
|
@@ -273,7 +273,7 @@ Then we got lucky with timing. AI agents are becoming the primary way developers
|
|
|
273
273
|
|
|
274
274
|
That's the whole story. No secrets. No tricks. Just build useful things, make them easy to try, and make them findable.
|
|
275
275
|
|
|
276
|
-
The 2,775 downloads
|
|
276
|
+
The 2,775 downloads proved npm search is a viable growth channel. Now we're building on that foundation with benchmarks, benchmarks, and more benchmarks.
|
|
277
277
|
|
|
278
278
|
---
|
|
279
279
|
|
package/dist/sdk.js
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A3M Router TypeScript SDK
|
|
4
|
+
*
|
|
5
|
+
* Clean wrapper class providing a better DX than raw exports.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* const { A3MRouter } = require('adaptive-memory-multi-model-router/sdk');
|
|
9
|
+
* const router = new A3MRouter();
|
|
10
|
+
* const decision = router.route("What is 2+2?");
|
|
11
|
+
* console.log(decision.model, decision.tier, decision.cost);
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const advancedRouter = require("./routing/advancedRouter");
|
|
15
|
+
const proxyServer = require("./server/proxyServer");
|
|
16
|
+
|
|
17
|
+
// ============================================================
|
|
18
|
+
// A3MRouter SDK Class
|
|
19
|
+
// ============================================================
|
|
20
|
+
|
|
21
|
+
class A3MRouter {
|
|
22
|
+
constructor(config = {}) {
|
|
23
|
+
this.config = config;
|
|
24
|
+
this._proxyURL = null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Route a query — returns model selection without executing it.
|
|
29
|
+
*
|
|
30
|
+
* @param {string} query - The user prompt to route
|
|
31
|
+
* @returns {object} Routing decision with model, tier, cost, complexity
|
|
32
|
+
*/
|
|
33
|
+
route(query) {
|
|
34
|
+
const features = advancedRouter.extractQueryFeatures(query);
|
|
35
|
+
const result = advancedRouter.routeQuery(query, this.config.providers);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
model: result.primary_model || 'unknown',
|
|
39
|
+
tier: this.classifyTier(features.complexity),
|
|
40
|
+
cost: result.estimated_cost || 0,
|
|
41
|
+
complexity: features.complexity,
|
|
42
|
+
reasoning: result.reasoning || '',
|
|
43
|
+
fallbackModels: result.fallback_models || [],
|
|
44
|
+
isFree: (result.estimated_cost || 0) === 0,
|
|
45
|
+
isExpert: features.complexity >= 0.65,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Route multiple queries in batch.
|
|
51
|
+
*
|
|
52
|
+
* @param {string[]} queries - Array of user prompts
|
|
53
|
+
* @returns {object[]} Array of routing decisions
|
|
54
|
+
*/
|
|
55
|
+
routeBatch(queries) {
|
|
56
|
+
advancedRouter.routeBatch(queries); // warm the internal cache
|
|
57
|
+
return queries.map((q) => this.route(q));
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Get model recommendation for a task description.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} task - Task description
|
|
64
|
+
* @returns {object} Routing decision
|
|
65
|
+
*/
|
|
66
|
+
recommend(task) {
|
|
67
|
+
advancedRouter.recommendForTask(task);
|
|
68
|
+
return this.route(task);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Start the OpenAI-compatible proxy server.
|
|
73
|
+
*
|
|
74
|
+
* @param {number} port - Port to listen on (default: 8787)
|
|
75
|
+
* @returns {Promise<string>} The proxy base URL
|
|
76
|
+
*/
|
|
77
|
+
async serve(port = 8787) {
|
|
78
|
+
proxyServer.createProxyServer(port);
|
|
79
|
+
this._proxyURL = `http://localhost:${port}/v1`;
|
|
80
|
+
return this._proxyURL;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Get the proxy URL. Available after serve() is called.
|
|
85
|
+
*/
|
|
86
|
+
get proxyURL() {
|
|
87
|
+
return this._proxyURL || 'http://localhost:8787/v1';
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Extract features from a query for debugging or analysis.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} query - The user prompt to analyze
|
|
94
|
+
* @returns {object} Detailed feature breakdown
|
|
95
|
+
*/
|
|
96
|
+
analyze(query) {
|
|
97
|
+
return advancedRouter.extractQueryFeatures(query);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Classify a complexity score into a named tier.
|
|
102
|
+
*/
|
|
103
|
+
classifyTier(complexity) {
|
|
104
|
+
if (complexity < 0.20) return 'free';
|
|
105
|
+
if (complexity < 0.45) return 'cheap';
|
|
106
|
+
if (complexity < 0.65) return 'mid';
|
|
107
|
+
return 'premium';
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Convenience: create an A3MRouter instance.
|
|
113
|
+
*
|
|
114
|
+
* @param {object} config - Optional configuration
|
|
115
|
+
* @returns {A3MRouter} Configured instance
|
|
116
|
+
*/
|
|
117
|
+
function createSDK(config) {
|
|
118
|
+
return new A3MRouter(config);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
module.exports = { A3MRouter, createSDK };
|
|
122
|
+
module.exports.default = A3MRouter;
|