adaptive-memory-multi-model-router 2.13.18 → 2.13.20
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/.dockerignore +82 -0
- package/.env.example +303 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +83 -12
- package/.github/ISSUE_TEMPLATE/config.yml +12 -6
- package/.github/ISSUE_TEMPLATE/feature_request.md +61 -10
- package/.github/PULL_REQUEST_TEMPLATE.md +53 -26
- package/.github/dependabot.yml +9 -0
- package/.github/workflows/codeql.yml +38 -0
- package/.github/workflows/npm-publish.yml +20 -0
- package/.github/workflows/stale.yml +56 -0
- package/ARCHITECTURE.md +346 -0
- package/AUDIT_REPORT.md +28 -0
- package/CHANGELOG.md +386 -22
- package/CONTRIBUTORS.md +20 -0
- package/Dockerfile +53 -0
- package/Dockerfile.proxy +33 -0
- package/PR_STATUS_REPORT.md +148 -0
- package/README.md +22 -0
- package/RUNKIT.md +83 -0
- package/_schema.html +61 -15
- package/articles/AI_AGENT_LLM_ROUTING.md +150 -0
- package/articles/FROM_ZERO_TO_10K.md +107 -0
- package/articles/LLM_BENCHMARK_DEEP_DIVE.md +153 -0
- package/articles/TWEETS_10K_DOWNLOADS.md +47 -0
- package/articles/TWEETS_BENCHMARK_FIRST.md +46 -0
- package/articles/TWEETS_MCP_PLAY.md +51 -0
- package/articles/TWEETS_SEQUENTIAL_BROKEN.md +49 -0
- package/articles/TWEETS_WHY_BUILD.md +54 -0
- package/benchmark-results.json +26 -45
- package/cli/a3m +840 -0
- package/demo/package.json +13 -0
- package/demo/public/index.html +762 -0
- package/demo/server.js +405 -0
- package/dist/cli.js +4 -0
- package/docker-compose.yml +74 -0
- package/docs/.nojekyll +0 -0
- package/docs/BENCHMARK.md +96 -22
- package/docs/_config.yml +49 -0
- package/docs/api.html +513 -0
- package/docs/benchmark.html +387 -0
- package/docs/cli-cheatsheet.md +339 -0
- package/docs/comparison.md +108 -0
- package/docs/curl-examples.md +247 -0
- package/docs/index.html +390 -99
- package/docs/openapi.yaml +1318 -0
- package/docs/quick-start.html +366 -0
- package/docs/robots.txt +1 -1
- package/docs/sitemap.xml +23 -5
- package/docs/styles.css +682 -0
- package/examples/README.md +61 -0
- package/examples/a3m-sdk.js +124 -0
- package/examples/basic-route.js +54 -0
- package/examples/chat-loop.js +202 -0
- package/examples/classify-then-route.js +102 -0
- package/examples/cost-compare.js +120 -0
- package/examples/ensemble.js +160 -0
- package/integrations/langchain/README.md +216 -0
- package/integrations/langchain/a3m_langchain.ts +1360 -0
- package/integrations/langchain/example.ts +287 -0
- package/integrations/vercel-ai-sdk/README.md +49 -0
- package/integrations/vercel-ai-sdk/a3m_provider.ts +78 -0
- package/integrations/vercel-ai-sdk/example.ts +25 -0
- package/llms-full.txt +43 -0
- package/llms.txt +9 -0
- package/mcp-server/README.md +188 -0
- package/mcp-server/package.json +29 -0
- package/mcp-server/src/index.ts +744 -0
- package/mcp-server/tsconfig.json +19 -0
- package/package.json +3 -3
- package/proxy/README.md +227 -0
- package/proxy/package-lock.json +831 -0
- package/proxy/package.json +17 -0
- package/proxy/rate-limit.js +145 -0
- package/proxy/rate-limit.test.js +311 -0
- package/proxy/server.js +970 -0
- package/scripts/banner.js +29 -0
- package/scripts/compare-providers.sh +230 -0
- package/scripts/cross_post.py +443 -0
- package/scripts/publish_fcc.py +106 -0
- package/scripts/push-to-gitee.sh +52 -0
- package/src/tui/dashboard.ts +13 -0
- package/tests/__mocks__/tokenUtils.ts +22 -0
- package/tests/memory/episodicMemory.test.ts +227 -0
- package/tests/package-lock.json +1628 -0
- package/tests/package.json +18 -0
- package/tests/routing/ensembleVoting.test.ts +236 -0
- package/tests/routing/providerRetry.test.ts +360 -0
- package/tests/routing/queryTypePresets.test.ts +206 -0
- package/tests/tsconfig.json +21 -0
- package/tests/vitest.config.ts +18 -0
- package/.env +0 -2
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A3M Router — LangChain Integration Example
|
|
3
|
+
*
|
|
4
|
+
* Run with: npx ts-node integrations/langchain/example.ts
|
|
5
|
+
* Or: npx tsx integrations/langchain/example.ts
|
|
6
|
+
*
|
|
7
|
+
* Prerequisites:
|
|
8
|
+
* npm install @langchain/core
|
|
9
|
+
* export GROQ_API_KEY=gsk_your_key_here
|
|
10
|
+
* export OPENAI_API_KEY=sk-your-key-here
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
// ============================================================
|
|
14
|
+
// Example 1: Basic Usage (Single Provider Routing)
|
|
15
|
+
// ============================================================
|
|
16
|
+
|
|
17
|
+
import { A3MLLM, A3M_DEFAULT_PROVIDERS } from './a3m_langchain';
|
|
18
|
+
|
|
19
|
+
async function exampleBasic() {
|
|
20
|
+
console.log('\n=== Example 1: Basic Routing ===\n');
|
|
21
|
+
|
|
22
|
+
const llm = new A3MLLM({
|
|
23
|
+
providers: {
|
|
24
|
+
groq: {
|
|
25
|
+
...A3M_DEFAULT_PROVIDERS.groq,
|
|
26
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
temperature: 0.7,
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const response = await llm.invoke('What is the capital of France?');
|
|
33
|
+
console.log('Response:', response);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// ============================================================
|
|
37
|
+
// Example 2: Multi-Provider with Cost-Based Routing
|
|
38
|
+
// ============================================================
|
|
39
|
+
|
|
40
|
+
async function exampleMultiProvider() {
|
|
41
|
+
console.log('\n=== Example 2: Multi-Provider Cost-Based Routing ===\n');
|
|
42
|
+
|
|
43
|
+
const llm = new A3MLLM({
|
|
44
|
+
providers: {
|
|
45
|
+
groq: {
|
|
46
|
+
...A3M_DEFAULT_PROVIDERS.groq,
|
|
47
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
48
|
+
},
|
|
49
|
+
openai: {
|
|
50
|
+
...A3M_DEFAULT_PROVIDERS.openai,
|
|
51
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
52
|
+
},
|
|
53
|
+
nvidia: {
|
|
54
|
+
...A3M_DEFAULT_PROVIDERS.nvidia,
|
|
55
|
+
apiKey: process.env.NVIDIA_API_KEY,
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
routingStrategy: 'cheapest', // Auto-pick the cheapest available provider
|
|
59
|
+
fallbackEnabled: true, // Fall back to next provider on failure
|
|
60
|
+
onRoute: (info) => {
|
|
61
|
+
console.log(`[Route] ${info.strategy} → ${info.provider}/${info.model}`);
|
|
62
|
+
},
|
|
63
|
+
onError: (info) => {
|
|
64
|
+
console.log(`[Error] ${info.provider}: ${info.error} (fallback: ${info.willFallback})`);
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const { text, metadata } = await llm.invokeWithMetadata(
|
|
69
|
+
'Explain quantum entanglement in simple terms.',
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
console.log('Response:', text.slice(0, 200), '...');
|
|
73
|
+
console.log('Routing Metadata:', JSON.stringify(metadata, null, 2));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ============================================================
|
|
77
|
+
// Example 3: Ensemble Mode (Parallel Execution)
|
|
78
|
+
// ============================================================
|
|
79
|
+
|
|
80
|
+
async function exampleEnsemble() {
|
|
81
|
+
console.log('\n=== Example 3: Ensemble Mode (Parallel Execution) ===\n');
|
|
82
|
+
|
|
83
|
+
const llm = new A3MLLM({
|
|
84
|
+
providers: {
|
|
85
|
+
groq: {
|
|
86
|
+
...A3M_DEFAULT_PROVIDERS.groq,
|
|
87
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
88
|
+
},
|
|
89
|
+
openai: {
|
|
90
|
+
...A3M_DEFAULT_PROVIDERS.openai,
|
|
91
|
+
apiKey: process.env.OPENAI_API_KEY,
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
routingStrategy: 'priority',
|
|
95
|
+
priorityOrder: ['groq', 'openai'],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Run both providers in parallel, return the longest response
|
|
99
|
+
const result = await llm.ensembleInvoke(
|
|
100
|
+
'Write a haiku about artificial intelligence.',
|
|
101
|
+
{
|
|
102
|
+
ensemble: 'longest',
|
|
103
|
+
},
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
console.log('Merged Response:', result.text);
|
|
107
|
+
console.log('Ensemble Metadata:', JSON.stringify(result.metadata, null, 2));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// ============================================================
|
|
111
|
+
// Example 4: LangChain Chain Integration
|
|
112
|
+
// ============================================================
|
|
113
|
+
|
|
114
|
+
import { PromptTemplate } from '@langchain/core/prompts';
|
|
115
|
+
import { StringOutputParser } from '@langchain/core/output_parsers';
|
|
116
|
+
|
|
117
|
+
async function exampleChain() {
|
|
118
|
+
console.log('\n=== Example 4: LangChain Chain Integration ===\n');
|
|
119
|
+
|
|
120
|
+
const llm = new A3MLLM({
|
|
121
|
+
providers: {
|
|
122
|
+
groq: {
|
|
123
|
+
...A3M_DEFAULT_PROVIDERS.groq,
|
|
124
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
temperature: 0.7,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// Create a chain with prompt template
|
|
131
|
+
const prompt = PromptTemplate.fromTemplate(
|
|
132
|
+
'You are a {role}. Answer the following question:\n{question}',
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
// Chain: prompt → LLM → string output parser
|
|
136
|
+
const chain = prompt.pipe(llm as any).pipe(new StringOutputParser());
|
|
137
|
+
|
|
138
|
+
const response = await chain.invoke({
|
|
139
|
+
role: 'physics professor',
|
|
140
|
+
question: 'Why is the sky blue?',
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
console.log('Chain Response:', response);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// ============================================================
|
|
147
|
+
// Example 5: Custom Provider Configuration
|
|
148
|
+
// ============================================================
|
|
149
|
+
|
|
150
|
+
async function exampleCustomProvider() {
|
|
151
|
+
console.log('\n=== Example 5: Custom Provider Configuration ===\n');
|
|
152
|
+
|
|
153
|
+
const llm = new A3MLLM({
|
|
154
|
+
providers: {
|
|
155
|
+
ollama: {
|
|
156
|
+
name: 'Ollama Local',
|
|
157
|
+
baseUrl: 'http://127.0.0.1:11434/v1/chat/completions',
|
|
158
|
+
models: ['llama3', 'mistral'],
|
|
159
|
+
tier: 'free',
|
|
160
|
+
cost: { input: 0, output: 0 },
|
|
161
|
+
},
|
|
162
|
+
lmstudio: {
|
|
163
|
+
name: 'LM Studio',
|
|
164
|
+
baseUrl: 'http://127.0.0.1:1234/v1/chat/completions',
|
|
165
|
+
models: ['local-model'],
|
|
166
|
+
tier: 'free',
|
|
167
|
+
cost: { input: 0, output: 0 },
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
routingStrategy: 'priority',
|
|
171
|
+
priorityOrder: ['ollama', 'lmstudio'],
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
console.log('Trying local provider...');
|
|
175
|
+
try {
|
|
176
|
+
const response = await llm.invoke('Hello, who are you?');
|
|
177
|
+
console.log('Response:', response);
|
|
178
|
+
} catch (error) {
|
|
179
|
+
console.log('Local provider unavailable (expected if Ollama is not running).');
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// ============================================================
|
|
184
|
+
// Example 6: Access Routing Metadata
|
|
185
|
+
// ============================================================
|
|
186
|
+
|
|
187
|
+
async function exampleMetadata() {
|
|
188
|
+
console.log('\n=== Example 6: Accessing Routing Metadata ===\n');
|
|
189
|
+
|
|
190
|
+
const llm = new A3MLLM({
|
|
191
|
+
providers: {
|
|
192
|
+
groq: {
|
|
193
|
+
...A3M_DEFAULT_PROVIDERS.groq,
|
|
194
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
onRoute: (info) => {
|
|
198
|
+
console.log(`Routing to: ${info.provider} → ${info.model}`);
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Use invokeWithMetadata to get full routing info
|
|
203
|
+
const { text, metadata } = await llm.invokeWithMetadata(
|
|
204
|
+
'What is 2 + 2?',
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
console.log('Response:', text);
|
|
208
|
+
console.log('--- Routing Metadata ---');
|
|
209
|
+
console.log(`Provider: ${metadata.provider}`);
|
|
210
|
+
console.log(`Model: ${metadata.model}`);
|
|
211
|
+
console.log(`Latency: ${metadata.latencyMs}ms`);
|
|
212
|
+
console.log(`Cost: $${metadata.costUsd}`);
|
|
213
|
+
console.log(`Tier: ${metadata.tier}`);
|
|
214
|
+
console.log(`Ensemble: ${metadata.ensemble}`);
|
|
215
|
+
if (metadata.tokensUsed) {
|
|
216
|
+
console.log(`Tokens Used: ${metadata.tokensUsed.total} (${metadata.tokensUsed.input} in / ${metadata.tokensUsed.output} out)`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// ============================================================
|
|
221
|
+
// Example 7: Factory Function (Quick Start)
|
|
222
|
+
// ============================================================
|
|
223
|
+
|
|
224
|
+
import { createA3MProvider, createA3MRouter } from './a3m_langchain';
|
|
225
|
+
|
|
226
|
+
async function exampleFactory() {
|
|
227
|
+
console.log('\n=== Example 7: Factory Functions ===\n');
|
|
228
|
+
|
|
229
|
+
// Quick single-provider LLM
|
|
230
|
+
const groq = createA3MProvider('groq', {
|
|
231
|
+
apiKey: process.env.GROQ_API_KEY,
|
|
232
|
+
});
|
|
233
|
+
const response1 = await groq.invoke('Say hello!');
|
|
234
|
+
console.log('Single provider:', response1);
|
|
235
|
+
|
|
236
|
+
// Auto-routing across multiple providers
|
|
237
|
+
const router = createA3MRouter({
|
|
238
|
+
groq: { apiKey: process.env.GROQ_API_KEY },
|
|
239
|
+
nvidia: { apiKey: process.env.NVIDIA_API_KEY },
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const { text, metadata } = await router.invokeWithMetadata(
|
|
243
|
+
'What is the speed of light?',
|
|
244
|
+
);
|
|
245
|
+
console.log('Auto-routed response:', text.slice(0, 100));
|
|
246
|
+
console.log('Selected provider:', metadata.provider);
|
|
247
|
+
console.log('Cost: $' + metadata.costUsd);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ============================================================
|
|
251
|
+
// Run All Examples
|
|
252
|
+
// ============================================================
|
|
253
|
+
|
|
254
|
+
async function main() {
|
|
255
|
+
console.log('A3M Router — LangChain Integration Examples');
|
|
256
|
+
console.log('==========================================');
|
|
257
|
+
console.log('Requires at least one API key (GROQ_API_KEY, OPENAI_API_KEY, etc.)');
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
// Run examples that don't require API keys first
|
|
261
|
+
// (they'll error gracefully if no provider is available)
|
|
262
|
+
|
|
263
|
+
// Example 5 (custom) runs even without external API keys
|
|
264
|
+
if (process.env.GROQ_API_KEY) {
|
|
265
|
+
await exampleBasic();
|
|
266
|
+
await exampleMultiProvider();
|
|
267
|
+
await exampleChain();
|
|
268
|
+
await exampleMetadata();
|
|
269
|
+
await exampleFactory();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (process.env.GROQ_API_KEY && process.env.OPENAI_API_KEY) {
|
|
273
|
+
await exampleEnsemble();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
await exampleCustomProvider();
|
|
277
|
+
} catch (error) {
|
|
278
|
+
console.error('Example failed:', error);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
console.log('\nDone!');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Run if executed directly
|
|
285
|
+
if (require.main === module) {
|
|
286
|
+
main().catch(console.error);
|
|
287
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# A3M Router x Vercel AI SDK
|
|
2
|
+
|
|
3
|
+
Use A3M Router's smart routing with Vercel AI SDK's `generateText` and `streamText`.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install ai adaptive-memory-multi-model-router
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { createA3M } from './a3m_provider';
|
|
15
|
+
import { generateText } from 'ai';
|
|
16
|
+
|
|
17
|
+
const a3m = createA3M({ strategy: 'cheapest' });
|
|
18
|
+
|
|
19
|
+
const result = await generateText({
|
|
20
|
+
model: a3m('auto'),
|
|
21
|
+
prompt: 'Hello!',
|
|
22
|
+
});
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Strategies
|
|
26
|
+
|
|
27
|
+
| Strategy | Behavior |
|
|
28
|
+
| --------- | --------------------------------- |
|
|
29
|
+
| `cheapest`| Routes to lowest-cost provider |
|
|
30
|
+
| `fastest` | Routes to lowest-latency provider |
|
|
31
|
+
| `auto` | Balances cost and quality |
|
|
32
|
+
|
|
33
|
+
## Configuration
|
|
34
|
+
|
|
35
|
+
- `A3M_API_KEY` env variable or pass in constructor
|
|
36
|
+
- Point to self-hosted proxy via `baseUrl`
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const a3m = createA3M({
|
|
40
|
+
strategy: 'fastest',
|
|
41
|
+
baseUrl: 'http://localhost:8787/v1',
|
|
42
|
+
apiKey: 'my-key',
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Files
|
|
47
|
+
|
|
48
|
+
- `a3m_provider.ts` -- the custom provider implementation
|
|
49
|
+
- `example.ts` -- usage example with `generateText` and `streamText`
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A3M Router — Vercel AI SDK Custom Provider
|
|
3
|
+
*
|
|
4
|
+
* A lightweight custom provider that routes through A3M's smart router
|
|
5
|
+
* using Vercel AI SDK's `generateText` and `streamText`.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* ```ts
|
|
9
|
+
* import { createA3M } from './a3m_provider';
|
|
10
|
+
* import { generateText } from 'ai';
|
|
11
|
+
*
|
|
12
|
+
* const a3m = createA3M({ strategy: 'cheapest' });
|
|
13
|
+
* const result = await generateText({
|
|
14
|
+
* model: a3m('auto'),
|
|
15
|
+
* prompt: 'Hello'
|
|
16
|
+
* });
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
interface A3MConfig {
|
|
21
|
+
strategy?: 'cheapest' | 'fastest' | 'auto';
|
|
22
|
+
apiKey?: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface A3MProvider {
|
|
27
|
+
(modelId: string): {
|
|
28
|
+
specVersion: 'v1';
|
|
29
|
+
provider: string;
|
|
30
|
+
modelId: string;
|
|
31
|
+
defaultObjectGenerationMode: 'object';
|
|
32
|
+
supportsStructuredOutputs: boolean;
|
|
33
|
+
doGenerate: (options: any) => Promise<any>;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function createA3M(config: A3MConfig = {}): A3MProvider {
|
|
38
|
+
const strategy = config.strategy || 'auto';
|
|
39
|
+
const baseUrl = config.baseUrl || 'http://localhost:8787/v1';
|
|
40
|
+
|
|
41
|
+
return (modelId: string) => ({
|
|
42
|
+
specVersion: 'v1' as const,
|
|
43
|
+
provider: 'a3m-router',
|
|
44
|
+
modelId,
|
|
45
|
+
defaultObjectGenerationMode: 'object' as const,
|
|
46
|
+
supportsStructuredOutputs: true,
|
|
47
|
+
|
|
48
|
+
async doGenerate(options: any) {
|
|
49
|
+
const response = await fetch(`${baseUrl}/chat/completions`, {
|
|
50
|
+
method: 'POST',
|
|
51
|
+
headers: {
|
|
52
|
+
'Content-Type': 'application/json',
|
|
53
|
+
Authorization: `Bearer ${config.apiKey || process.env.A3M_API_KEY || ''}`,
|
|
54
|
+
},
|
|
55
|
+
body: JSON.stringify({
|
|
56
|
+
model: modelId,
|
|
57
|
+
messages: options.prompt,
|
|
58
|
+
temperature: options.temperature ?? 0.7,
|
|
59
|
+
max_tokens: options.maxTokens ?? 2048,
|
|
60
|
+
}),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (!response.ok) {
|
|
64
|
+
throw new Error(`A3M: ${response.status} ${await response.text()}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const data = await response.json();
|
|
68
|
+
return {
|
|
69
|
+
text: data.choices?.[0]?.message?.content || '',
|
|
70
|
+
finishReason: data.choices?.[0]?.finish_reason || 'stop',
|
|
71
|
+
usage: {
|
|
72
|
+
promptTokens: data.usage?.prompt_tokens || 0,
|
|
73
|
+
completionTokens: data.usage?.completion_tokens || 0,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createA3M } from './a3m_provider';
|
|
2
|
+
import { generateText, streamText } from 'ai';
|
|
3
|
+
|
|
4
|
+
// Quick route (cheapest provider)
|
|
5
|
+
const a3m = createA3M({ strategy: 'cheapest' });
|
|
6
|
+
|
|
7
|
+
async function main() {
|
|
8
|
+
// Non-streaming
|
|
9
|
+
const result = await generateText({
|
|
10
|
+
model: a3m('auto'),
|
|
11
|
+
prompt: 'Explain quantum computing in one sentence',
|
|
12
|
+
});
|
|
13
|
+
console.log(result.text);
|
|
14
|
+
|
|
15
|
+
// Streaming
|
|
16
|
+
const stream = await streamText({
|
|
17
|
+
model: a3m('auto'),
|
|
18
|
+
prompt: 'Write a haiku about AI routing',
|
|
19
|
+
});
|
|
20
|
+
for await (const chunk of stream.textStream) {
|
|
21
|
+
process.stdout.write(chunk);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
main().catch(console.error);
|
package/llms-full.txt
CHANGED
|
@@ -182,3 +182,46 @@ npx adaptive-memory-multi-model-router
|
|
|
182
182
|
# Quick start: docs/QUICK_START.md
|
|
183
183
|
# Benchmarks: docs/BENCHMARK.md
|
|
184
184
|
```
|
|
185
|
+
|
|
186
|
+
## Additional Resources
|
|
187
|
+
|
|
188
|
+
### Docs
|
|
189
|
+
- [BENCHMARK.md](./docs/BENCHMARK.md) — Independent benchmark data
|
|
190
|
+
- [API.md](./docs/API.md) — API reference
|
|
191
|
+
- [CORE_VISION_PRD.md](./docs/CORE_VISION_PRD.md) — Product requirements
|
|
192
|
+
- [CONFIGURATION.md](./docs/CONFIGURATION.md) — Configuration reference
|
|
193
|
+
- [ENGINEERING_SPEC.md](./docs/ENGINEERING_SPEC.md) — Engineering specification
|
|
194
|
+
- [INTEGRATIONS.md](./docs/INTEGRATIONS.md) — Integration guide
|
|
195
|
+
- [QUICK_START.md](./docs/QUICK_START.md) — Quick start guide
|
|
196
|
+
- [ARCHITECTURAL-IMPROVEMENTS.md](./docs/ARCHITECTURAL-IMPROVEMENTS-2025.md) — Architecture docs
|
|
197
|
+
|
|
198
|
+
### Integrations
|
|
199
|
+
- [LangChain](./integrations/langchain/) — LangChain integration adapter
|
|
200
|
+
- [Vercel AI SDK](./integrations/vercel-ai-sdk/) — Vercel AI SDK integration (use with @ai-sdk packages)
|
|
201
|
+
|
|
202
|
+
### Servers & Tools
|
|
203
|
+
- [MCP Server](./mcp-server/) — Model Context Protocol server
|
|
204
|
+
- [Demo](./demo/) — Interactive demo application
|
|
205
|
+
- [Proxy](./proxy/) — OpenAI-compatible proxy server
|
|
206
|
+
|
|
207
|
+
### Community
|
|
208
|
+
- [GitHub Discussions](https://github.com/Das-rebel/a3m-router/discussions) — Community Q&A, ideas, and show-and-tell
|
|
209
|
+
|
|
210
|
+
### Documentation Site
|
|
211
|
+
- [GitHub Pages](https://das-rebel.github.io/A3M-Router-Parallel-multi-LLM-Gateway/) — Full documentation website
|
|
212
|
+
- [Benchmark Results](https://das-rebel.github.io/A3M-Router-Parallel-multi-LLM-Gateway/benchmark) — Independent benchmark data
|
|
213
|
+
- [Quick Start](https://das-rebel.github.io/A3M-Router-Parallel-multi-LLM-Gateway/quick-start) — Getting started guide
|
|
214
|
+
- [API Reference](https://das-rebel.github.io/A3M-Router-Parallel-multi-LLM-Gateway/api) — SDK and CLI reference
|
|
215
|
+
|
|
216
|
+
### Docs
|
|
217
|
+
- [ARCHITECTURE.md](./ARCHITECTURE.md) — Codebase architecture
|
|
218
|
+
- [CHANGELOG.md](./CHANGELOG.md) — Version history
|
|
219
|
+
- [docs/comparison.md](./docs/comparison.md) — Competitor comparison
|
|
220
|
+
- [docs/cli-cheatsheet.md](./docs/cli-cheatsheet.md) — CLI quick reference
|
|
221
|
+
- [docs/curl-examples.md](./docs/curl-examples.md) — One-liner curl examples
|
|
222
|
+
- [docs/openapi.yaml](./docs/openapi.yaml) — OpenAPI specification
|
|
223
|
+
- [docs/BENCHMARK.md](./docs/BENCHMARK.md) — Detailed benchmark data
|
|
224
|
+
|
|
225
|
+
### Deployments
|
|
226
|
+
- [Docker](https://github.com/Das-rebel/a3m-router) — Multi-stage Dockerfile and docker-compose
|
|
227
|
+
- [npm](https://www.npmjs.com/package/adaptive-memory-multi-model-router) — npm package (install: npm install -g adaptive-memory-multi-model-router)
|
package/llms.txt
CHANGED
|
@@ -52,3 +52,12 @@ Parallel ensemble execution: runs N providers simultaneously, scores results on
|
|
|
52
52
|
- 10,024 npm downloads in 14 days
|
|
53
53
|
- 72 versions published
|
|
54
54
|
- Zero marketing budget
|
|
55
|
+
|
|
56
|
+
## Links
|
|
57
|
+
- Docs: `docs/` ([BENCHMARK.md](./docs/BENCHMARK.md), [API.md](./docs/API.md), [ARCHITECTURAL-IMPROVEMENTS.md](./docs/ARCHITECTURAL-IMPROVEMENTS-2025.md), [CORE_VISION_PRD.md](./docs/CORE_VISION_PRD.md), [CONFIGURATION.md](./docs/CONFIGURATION.md), [ENGINEERING_SPEC.md](./docs/ENGINEERING_SPEC.md), [INTEGRATIONS.md](./docs/INTEGRATIONS.md), [QUICK_START.md](./docs/QUICK_START.md))
|
|
58
|
+
- Integration: LangChain (`integrations/langchain/`)
|
|
59
|
+
- Integration: Vercel AI SDK (`integrations/vercel-ai-sdk/`)
|
|
60
|
+
- MCP Server: `mcp-server/`
|
|
61
|
+
- Demo: `demo/`
|
|
62
|
+
- Proxy: `proxy/`
|
|
63
|
+
- Community: [GitHub Discussions](https://github.com/Das-rebel/a3m-router/discussions)
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
# A3M Router MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for [A3M Router](https://github.com/Das-rebel/a3m-router) — parallel multi-LLM execution for AI agents.
|
|
4
|
+
|
|
5
|
+
Allows any MCP-compatible AI agent (Claude Code, Cursor, Windsurf, etc.) to use A3M's routing and ensemble execution directly.
|
|
6
|
+
|
|
7
|
+
## Tools
|
|
8
|
+
|
|
9
|
+
| Tool | Description |
|
|
10
|
+
|------|-------------|
|
|
11
|
+
| `a3m_route` | Route a query to the optimal LLM provider (model selection + reasoning, no execution) |
|
|
12
|
+
| `a3m_ensemble` | Execute a query across multiple providers in parallel and merge results |
|
|
13
|
+
| `a3m_classify` | Classify a query by type (fast/creative/deep/code) and get provider recommendations |
|
|
14
|
+
| `a3m_providers` | List all configured providers with models, cost, and availability |
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
# Install globally
|
|
20
|
+
npm install -g @a3m/mcp-server
|
|
21
|
+
|
|
22
|
+
# Or from the repo
|
|
23
|
+
cd mcp-server
|
|
24
|
+
npm install
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Configuration
|
|
28
|
+
|
|
29
|
+
Set API keys as environment variables for the providers you want to use:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Required for at least one provider
|
|
33
|
+
export GROQ_API_KEY=gsk_...
|
|
34
|
+
export GOOGLE_API_KEY=AIza...
|
|
35
|
+
export CEREBRAS_API_KEY=csk-...
|
|
36
|
+
export MISTRAL_API_KEY=...
|
|
37
|
+
export MINIMAX_API_KEY=...
|
|
38
|
+
|
|
39
|
+
# Optional: Custom A3M config
|
|
40
|
+
export A3M_CONFIG_PATH=~/.config/a3m-router/providers.json
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Usage
|
|
44
|
+
|
|
45
|
+
### Claude Code
|
|
46
|
+
|
|
47
|
+
Add to your `~/.claude.json` or project `.claude.json`:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"mcpServers": {
|
|
52
|
+
"a3m-router": {
|
|
53
|
+
"command": "npx",
|
|
54
|
+
"args": ["@a3m/mcp-server"],
|
|
55
|
+
"env": {
|
|
56
|
+
"GROQ_API_KEY": "gsk_...",
|
|
57
|
+
"GOOGLE_API_KEY": "AIza..."
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Cursor
|
|
65
|
+
|
|
66
|
+
In Cursor Settings -> Features -> MCP Servers, add:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
Name: A3M Router
|
|
70
|
+
Type: command
|
|
71
|
+
Command: npx @a3m/mcp-server
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Direct MCP Client
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Start the server
|
|
78
|
+
npx @a3m/mcp-server
|
|
79
|
+
|
|
80
|
+
# Pipe stdin/stdout for MCP protocol
|
|
81
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | npx @a3m/mcp-server
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Testing the Server
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Clone and install
|
|
88
|
+
git clone https://github.com/Das-rebel/a3m-router.git
|
|
89
|
+
cd a3m-router/mcp-server
|
|
90
|
+
npm install
|
|
91
|
+
npx tsc
|
|
92
|
+
|
|
93
|
+
# Run directly (pipe test)
|
|
94
|
+
echo '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | node dist/index.js
|
|
95
|
+
|
|
96
|
+
# Or use the MCP inspector
|
|
97
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Examples
|
|
101
|
+
|
|
102
|
+
### Route a query
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
Tool: a3m_route
|
|
106
|
+
Input: { "query": "Write a Python function to sort a list" }
|
|
107
|
+
Output:
|
|
108
|
+
{
|
|
109
|
+
"model": "groq/llama-3.3-70b-versatile",
|
|
110
|
+
"tier": "cheap",
|
|
111
|
+
"provider": "groq",
|
|
112
|
+
"confidence": 0.85,
|
|
113
|
+
"reasoning": "Code query detected, routing to fast coding provider",
|
|
114
|
+
"estimated_cost": 0.000012,
|
|
115
|
+
"classification": "code"
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Ensemble execution
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
Tool: a3m_ensemble
|
|
123
|
+
Input: { "query": "Explain quantum computing in 3 sentences" }
|
|
124
|
+
Output:
|
|
125
|
+
{
|
|
126
|
+
"query": "Explain quantum computing in 3 sentences",
|
|
127
|
+
"parallel_responses": [
|
|
128
|
+
{ "provider": "groq", "confidence": 0.92, "content": "..." },
|
|
129
|
+
{ "provider": "google", "confidence": 0.88, "content": "..." },
|
|
130
|
+
{ "provider": "cerebras", "confidence": 0.85, "content": "..." }
|
|
131
|
+
],
|
|
132
|
+
"best_answer": "...",
|
|
133
|
+
"stats": {
|
|
134
|
+
"total_providers": 4,
|
|
135
|
+
"successful": 3,
|
|
136
|
+
"failed": 1,
|
|
137
|
+
"total_cost": 0.000031
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Protocol
|
|
143
|
+
|
|
144
|
+
The server uses standard MCP transport via stdio:
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
Client -> Server: JSON-RPC request (stdin)
|
|
148
|
+
Server -> Client: JSON-RPC response (stdout)
|
|
149
|
+
Server -> Stderr: Logs (for debugging)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Architecture
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
┌─────────────────────────────────────────────────┐
|
|
156
|
+
│ MCP Client (Claude Code, Cursor) │
|
|
157
|
+
└──────────────────┬──────────────────────────────┘
|
|
158
|
+
│ MCP Protocol (stdio)
|
|
159
|
+
┌──────────────────▼──────────────────────────────┐
|
|
160
|
+
│ A3M MCP Server (mcp-server) │
|
|
161
|
+
│ │
|
|
162
|
+
│ a3m_route a3m_ensemble a3m_classify providers│
|
|
163
|
+
└──────────────────┬──────────────────────────────┘
|
|
164
|
+
│ Internal API
|
|
165
|
+
┌──────────────────▼──────────────────────────────┐
|
|
166
|
+
│ A3M Router (adaptive-memory-multi- │
|
|
167
|
+
│ model-router) │
|
|
168
|
+
│ │
|
|
169
|
+
│ routeQuery() extractQueryFeatures() providers │
|
|
170
|
+
└───────┬────────────┬────────────┬────────────────┘
|
|
171
|
+
│ │ │
|
|
172
|
+
┌────▼───┐ ┌────▼───┐ ┌────▼───┐
|
|
173
|
+
│ Groq │ │ Google │ │Cerebras│ ...
|
|
174
|
+
└────────┘ └────────┘ └────────┘
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Development
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
cd mcp-server
|
|
181
|
+
npm install
|
|
182
|
+
npm run build # npx tsc
|
|
183
|
+
npm start # node dist/index.js
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## License
|
|
187
|
+
|
|
188
|
+
MIT
|