adaptive-memory-multi-model-router 2.15.3 → 2.15.5

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.
Files changed (101) hide show
  1. package/.github/workflows/adapters-ci.yml +142 -0
  2. package/.github/workflows/ci.yml +2 -5
  3. package/.github/workflows/pypi-publish.yml +102 -0
  4. package/CHANGELOG.md +7 -1
  5. package/README.md +260 -137
  6. package/README_ja.md +2 -2
  7. package/README_zh.md +1 -1
  8. package/adapters/README.md +36 -0
  9. package/adapters/__init__.py +25 -0
  10. package/adapters/a3m_adapter/__init__.py +51 -0
  11. package/adapters/a3m_adapter/adapter/__init__.py +22 -0
  12. package/adapters/a3m_adapter/adapter/autogen.py +169 -0
  13. package/adapters/a3m_adapter/adapter/config.py +100 -0
  14. package/adapters/a3m_adapter/adapter/haystack.py +197 -0
  15. package/adapters/a3m_adapter/adapter/langchain.py +155 -0
  16. package/adapters/a3m_adapter/adapter/langgraph.py +196 -0
  17. package/adapters/a3m_adapter/adapter/llamaindex.py +162 -0
  18. package/adapters/a3m_adapter/adapter/pinecone.py +217 -0
  19. package/adapters/a3m_adapter/adapter/vercel.py +188 -0
  20. package/adapters/a3m_adapter/tests/__init__.py +1 -0
  21. package/adapters/a3m_adapter/tests/test_adapters.py +118 -0
  22. package/adapters/a3m_adapter/tests/test_integration.py +80 -0
  23. package/adapters/requirements-dev.txt +6 -0
  24. package/adapters/requirements.txt +4 -0
  25. package/adapters/setup.py +23 -0
  26. package/apps/cost-calculator/README.md +72 -0
  27. package/apps/cost-calculator/calculator.css +280 -0
  28. package/apps/cost-calculator/calculator.js +150 -0
  29. package/apps/cost-calculator/index.html +321 -0
  30. package/apps/cost-calculator/package.json +13 -0
  31. package/articles/ANNOUNCEMENT_reddit_ml.md +76 -0
  32. package/articles/ANNOUNCEMENT_vc/347/244/276/345/214/272.md +71 -0
  33. package/articles/ANNOUNCEMENT_vercel.md +85 -0
  34. package/demo.py +251 -0
  35. package/dist/providers/providerConfig.d.ts +5 -1
  36. package/dist/providers/providerConfig.js +1006 -1
  37. package/dist/providers/providerConfig.js.map +1 -1
  38. package/docker-compose.yml +84 -60
  39. package/docs/comparison.md +2 -2
  40. package/docs/llms-full.txt +360 -138
  41. package/docs/llms.txt +70 -71
  42. package/docs-site/index.html +9 -9
  43. package/llms.txt +70 -62
  44. package/package.json +41 -91
  45. package/packages/a3m-vercel-ai/README.md +161 -0
  46. package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts +12 -0
  47. package/packages/a3m-vercel-ai/dist/a3m-language-model.d.ts.map +1 -0
  48. package/packages/a3m-vercel-ai/dist/a3m-language-model.js +289 -0
  49. package/packages/a3m-vercel-ai/dist/a3m-language-model.js.map +1 -0
  50. package/packages/a3m-vercel-ai/dist/index.d.ts +82 -0
  51. package/packages/a3m-vercel-ai/dist/index.d.ts.map +1 -0
  52. package/packages/a3m-vercel-ai/dist/index.js +79 -0
  53. package/packages/a3m-vercel-ai/dist/index.js.map +1 -0
  54. package/packages/a3m-vercel-ai/dist/types.d.ts +97 -0
  55. package/packages/a3m-vercel-ai/dist/types.d.ts.map +1 -0
  56. package/packages/a3m-vercel-ai/dist/types.js +5 -0
  57. package/packages/a3m-vercel-ai/dist/types.js.map +1 -0
  58. package/packages/a3m-vercel-ai/package-lock.json +969 -0
  59. package/packages/a3m-vercel-ai/package.json +46 -0
  60. package/packages/a3m-vercel-ai/src/a3m-language-model.ts +381 -0
  61. package/packages/a3m-vercel-ai/src/index.ts +104 -0
  62. package/packages/a3m-vercel-ai/src/types.ts +116 -0
  63. package/packages/a3m-vercel-ai/tsconfig.json +20 -0
  64. package/packages/agentkit-adapter/LICENSE +21 -0
  65. package/packages/agentkit-adapter/README.md +126 -0
  66. package/packages/agentkit-adapter/examples/agentkit-example.ts +139 -0
  67. package/packages/agentkit-adapter/package.json +57 -0
  68. package/packages/agentkit-adapter/src/adapter.ts +381 -0
  69. package/packages/agentkit-adapter/src/index.ts +36 -0
  70. package/packages/agentkit-adapter/src/types.ts +105 -0
  71. package/packages/agentkit-adapter/src/util.ts +13 -0
  72. package/packages/agentkit-adapter/tsconfig.json +22 -0
  73. package/prometheus.yml +8 -0
  74. package/python/README.md +92 -65
  75. package/python/a3m/__init__.py +32 -3
  76. package/python/a3m/adapters/__init__.py +21 -0
  77. package/python/a3m/adapters/langchain.py +190 -0
  78. package/python/a3m/adapters/llamaindex.py +249 -0
  79. package/python/a3m/adapters/qdrant.py +240 -0
  80. package/python/a3m/adapters/weaviate.py +263 -0
  81. package/python/a3m/client.py +5 -0
  82. package/python/a3m_router.egg-info/PKG-INFO +172 -0
  83. package/python/a3m_router.egg-info/SOURCES.txt +17 -0
  84. package/python/a3m_router.egg-info/dependency_links.txt +1 -0
  85. package/python/a3m_router.egg-info/requires.txt +24 -0
  86. package/python/a3m_router.egg-info/top_level.txt +1 -0
  87. package/python/build_verify.sh +32 -0
  88. package/python/dist/a3m_router-2.2.1-py3-none-any.whl +0 -0
  89. package/python/dist/a3m_router-2.2.1.tar.gz +0 -0
  90. package/python/dist/a3m_router-2.2.2-py3-none-any.whl +0 -0
  91. package/python/dist/a3m_router-2.2.2.tar.gz +0 -0
  92. package/python/mcp-server/README.md +172 -0
  93. package/python/mcp-server/a3m_mcp/__init__.py +15 -0
  94. package/python/mcp-server/a3m_mcp/__main__.py +15 -0
  95. package/python/mcp-server/a3m_mcp/server.py +339 -0
  96. package/python/mcp-server/pyproject.toml +24 -0
  97. package/python/pyproject.toml +56 -5
  98. package/python/setup.py +3 -28
  99. package/src/providers/providerConfig.ts +1053 -1
  100. package/summary.txt +38 -0
  101. package/tsconfig.build.json +1 -2
@@ -0,0 +1,280 @@
1
+ /* A3M Router Cost Calculator Styles */
2
+
3
+ :root {
4
+ --a3m-primary: #6366f1;
5
+ --a3m-accent: #818cf8;
6
+ --a3m-bg: #0f0f1a;
7
+ --a3m-surface: #1a1a2e;
8
+ --a3m-border: #2d2d4a;
9
+ --a3m-text: #e2e8f0;
10
+ --a3m-muted: #94a3b8;
11
+ --a3m-green: #22c55e;
12
+ --a3m-red: #ef4444;
13
+ }
14
+
15
+ * { box-sizing: border-box; margin: 0; padding: 0; }
16
+
17
+ body {
18
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
19
+ background: var(--a3m-bg);
20
+ color: var(--a3m-text);
21
+ min-height: 100vh;
22
+ padding: 2rem 1rem;
23
+ }
24
+
25
+ .container {
26
+ max-width: 900px;
27
+ margin: 0 auto;
28
+ }
29
+
30
+ h1 {
31
+ font-size: 1.75rem;
32
+ font-weight: 700;
33
+ text-align: center;
34
+ margin-bottom: 0.5rem;
35
+ }
36
+
37
+ .subtitle {
38
+ text-align: center;
39
+ color: var(--a3m-muted);
40
+ margin-bottom: 2rem;
41
+ }
42
+
43
+ .card {
44
+ background: var(--a3m-surface);
45
+ border: 1px solid var(--a3m-border);
46
+ border-radius: 12px;
47
+ padding: 1.5rem;
48
+ margin-bottom: 1.5rem;
49
+ }
50
+
51
+ .card-title {
52
+ font-size: 0.875rem;
53
+ font-weight: 600;
54
+ text-transform: uppercase;
55
+ letter-spacing: 0.05em;
56
+ color: var(--a3m-muted);
57
+ margin-bottom: 1rem;
58
+ }
59
+
60
+ /* Input grid */
61
+ .input-grid {
62
+ display: grid;
63
+ grid-template-columns: 1fr 1fr;
64
+ gap: 1rem;
65
+ }
66
+
67
+ @media (max-width: 600px) {
68
+ .input-grid { grid-template-columns: 1fr; }
69
+ }
70
+
71
+ .input-group {
72
+ display: flex;
73
+ flex-direction: column;
74
+ gap: 0.5rem;
75
+ }
76
+
77
+ .input-group label {
78
+ font-size: 0.875rem;
79
+ font-weight: 500;
80
+ color: var(--a3m-muted);
81
+ }
82
+
83
+ .input-group input,
84
+ .input-group select {
85
+ padding: 0.625rem 0.875rem;
86
+ background: var(--a3m-bg);
87
+ border: 1px solid var(--a3m-border);
88
+ border-radius: 8px;
89
+ color: var(--a3m-text);
90
+ font-size: 1rem;
91
+ width: 100%;
92
+ }
93
+
94
+ .input-group input:focus,
95
+ .input-group select:focus {
96
+ outline: none;
97
+ border-color: var(--a3m-primary);
98
+ }
99
+
100
+ /* Model mix rows */
101
+ .model-mix {
102
+ display: flex;
103
+ flex-direction: column;
104
+ gap: 0.75rem;
105
+ margin-top: 1rem;
106
+ }
107
+
108
+ .model-row {
109
+ display: grid;
110
+ grid-template-columns: 1fr 100px auto;
111
+ gap: 0.5rem;
112
+ align-items: center;
113
+ }
114
+
115
+ .model-row select,
116
+ .model-row input {
117
+ padding: 0.5rem;
118
+ background: var(--a3m-bg);
119
+ border: 1px solid var(--a3m-border);
120
+ border-radius: 6px;
121
+ color: var(--a3m-text);
122
+ font-size: 0.875rem;
123
+ }
124
+
125
+ .model-row span {
126
+ color: var(--a3m-muted);
127
+ font-size: 0.875rem;
128
+ white-space: nowrap;
129
+ }
130
+
131
+ .btn {
132
+ display: inline-flex;
133
+ align-items: center;
134
+ gap: 0.5rem;
135
+ padding: 0.625rem 1.25rem;
136
+ background: var(--a3m-primary);
137
+ color: white;
138
+ border: none;
139
+ border-radius: 8px;
140
+ font-size: 0.875rem;
141
+ font-weight: 600;
142
+ cursor: pointer;
143
+ transition: background 0.2s;
144
+ }
145
+
146
+ .btn:hover { background: var(--a3m-accent); }
147
+ .btn-secondary {
148
+ background: var(--a3m-border);
149
+ color: var(--a3m-text);
150
+ }
151
+ .btn-secondary:hover { background: #3d3d5a; }
152
+
153
+ .btn-row {
154
+ display: flex;
155
+ gap: 0.75rem;
156
+ margin-top: 1.25rem;
157
+ flex-wrap: wrap;
158
+ }
159
+
160
+ /* Results */
161
+ .results-grid {
162
+ display: grid;
163
+ grid-template-columns: repeat(3, 1fr);
164
+ gap: 1rem;
165
+ margin-bottom: 1.5rem;
166
+ }
167
+
168
+ @media (max-width: 600px) {
169
+ .results-grid { grid-template-columns: 1fr; }
170
+ }
171
+
172
+ .result-card {
173
+ background: var(--a3m-bg);
174
+ border: 1px solid var(--a3m-border);
175
+ border-radius: 10px;
176
+ padding: 1.25rem;
177
+ text-align: center;
178
+ }
179
+
180
+ .result-label {
181
+ font-size: 0.75rem;
182
+ font-weight: 600;
183
+ text-transform: uppercase;
184
+ letter-spacing: 0.05em;
185
+ color: var(--a3m-muted);
186
+ margin-bottom: 0.5rem;
187
+ }
188
+
189
+ .result-value {
190
+ font-size: 1.75rem;
191
+ font-weight: 700;
192
+ }
193
+
194
+ .result-value.savings { color: var(--a3m-green); }
195
+ .result-value.baseline { color: var(--a3m-muted); text-decoration: line-through; }
196
+
197
+ /* Breakdown table */
198
+ .breakdown-table {
199
+ width: 100%;
200
+ border-collapse: collapse;
201
+ font-size: 0.875rem;
202
+ margin-top: 1rem;
203
+ }
204
+
205
+ .breakdown-table th {
206
+ text-align: left;
207
+ padding: 0.625rem 0.75rem;
208
+ color: var(--a3m-muted);
209
+ font-weight: 600;
210
+ font-size: 0.75rem;
211
+ text-transform: uppercase;
212
+ border-bottom: 1px solid var(--a3m-border);
213
+ }
214
+
215
+ .breakdown-table td {
216
+ padding: 0.625rem 0.75rem;
217
+ border-bottom: 1px solid var(--a3m-border);
218
+ }
219
+
220
+ .breakdown-table tr:last-child td { border-bottom: none; }
221
+ .breakdown-table .num { text-align: right; font-variant-numeric: tabular-nums; }
222
+ .breakdown-table .savings-cell { color: var(--a3m-green); }
223
+
224
+ /* Share bar */
225
+ .share-bar {
226
+ display: flex;
227
+ gap: 0.5rem;
228
+ align-items: center;
229
+ margin-top: 1rem;
230
+ }
231
+
232
+ .share-bar input {
233
+ flex: 1;
234
+ padding: 0.5rem 0.75rem;
235
+ background: var(--a3m-bg);
236
+ border: 1px solid var(--a3m-border);
237
+ border-radius: 6px;
238
+ color: var(--a3m-text);
239
+ font-size: 0.8rem;
240
+ font-family: monospace;
241
+ }
242
+
243
+ /* Chart */
244
+ .chart-container {
245
+ position: relative;
246
+ height: 250px;
247
+ margin: 1.5rem 0;
248
+ }
249
+
250
+ .chart-bar {
251
+ position: absolute;
252
+ bottom: 0;
253
+ width: 40%;
254
+ border-radius: 6px 6px 0 0;
255
+ transition: height 0.5s ease;
256
+ }
257
+
258
+ .chart-bar.baseline {
259
+ left: 15%;
260
+ background: var(--a3m-muted);
261
+ opacity: 0.5;
262
+ }
263
+
264
+ .chart-bar.a3m {
265
+ right: 15%;
266
+ background: var(--a3m-primary);
267
+ }
268
+
269
+ /* Hidden until calculated */
270
+ .hidden { display: none; }
271
+
272
+ /* Footer */
273
+ .footer {
274
+ text-align: center;
275
+ color: var(--a3m-muted);
276
+ font-size: 0.75rem;
277
+ margin-top: 2rem;
278
+ }
279
+
280
+ .footer a { color: var(--a3m-accent); text-decoration: none; }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * A3M Router Cost Calculator
3
+ * Pure JS, no dependencies.
4
+ */
5
+
6
+ // --- Pricing constants (per 1M tokens) ---
7
+ const PRICING = {
8
+ 'gpt-4o': { input: 5.0, output: 15.0 },
9
+ 'gpt-4o-mini': { input: 0.15, output: 0.60 },
10
+ 'claude-3.5-sonnet': { input: 3.0, output: 15.0 },
11
+ 'claude-3-haiku': { input: 0.25, output: 1.25 },
12
+ 'gemini-1.5-pro': { input: 3.5, output: 10.5 },
13
+ 'gemini-1.5-flash': { input: 0.075, output: 0.30 },
14
+ 'groq-llama-3.3-70b': { input: 0.59, output: 0.79 },
15
+ 'groq-mixtral-8x7b': { input: 0.24, output: 0.24 },
16
+ };
17
+
18
+ const ROUTING_SAVINGS = {
19
+ // % of requests A3M routes to cheaper model
20
+ 'gpt-4o': 0.35, // 35% routed to 4o-mini
21
+ 'claude-3.5-sonnet': 0.40, // 40% routed to Haiku
22
+ 'gemini-1.5-pro': 0.45, // 45% routed to Flash
23
+ };
24
+
25
+ const AVG_TOKENS = {
26
+ input: 500, // avg input tokens
27
+ output: 800, // avg output tokens
28
+ };
29
+
30
+ /**
31
+ * @param {{ requestsPerMonth: number, modelMix: Array<{model: string, percent: number}> }} cfg
32
+ * @returns {{ totalCost: number, breakdown: Array<{model, requests, cost}> }}
33
+ */
34
+ function calculateBaselineCost({ requestsPerMonth, modelMix }) {
35
+ const breakdown = modelMix.map(({ model, percent }) => {
36
+ const reqCount = Math.round(requestsPerMonth * (percent / 100));
37
+ const pricing = PRICING[model] || { input: 3.0, output: 15.0 };
38
+ const cost = reqCount * (
39
+ (pricing.input * AVG_TOKENS.input / 1_000_000) +
40
+ (pricing.output * AVG_TOKENS.output / 1_000_000)
41
+ );
42
+ return { model, requests: reqCount, cost };
43
+ });
44
+
45
+ const totalCost = breakdown.reduce((sum, b) => sum + b.cost, 0);
46
+ return { totalCost, breakdown };
47
+ }
48
+
49
+ /**
50
+ * @param {{ requestsPerMonth: number, modelMix: Array<{model: string, percent: number}> }} cfg
51
+ * @returns {{ totalCost: number, breakdown: Array<{model, requests, cost, routedTo?, savings?}> }}
52
+ */
53
+ function calculateA3mCost({ requestsPerMonth, modelMix }) {
54
+ const breakdown = modelMix.map(({ model, percent }) => {
55
+ const reqCount = Math.round(requestsPerMonth * (percent / 100));
56
+ const routingSavings = ROUTING_SAVINGS[model] || 0;
57
+ const routedRequests = Math.round(reqCount * routingSavings);
58
+
59
+ // Baseline: all requests on premium model
60
+ const pricing = PRICING[model] || { input: 3.0, output: 15.0 };
61
+ const baselineCost = reqCount * (
62
+ (pricing.input * AVG_TOKENS.input / 1_000_000) +
63
+ (pricing.output * AVG_TOKENS.output / 1_000_000)
64
+ );
65
+
66
+ // A3M: some routed to cheaper model
67
+ // Find a cheaper alternative (heuristic: -mini, -flash, -haiku, or groq)
68
+ const cheaper = findCheaperModel(model);
69
+ const cheaperPricing = cheaper ? PRICING[cheaper] : pricing;
70
+
71
+ const a3mCost = (reqCount - routedRequests) * (
72
+ (pricing.input * AVG_TOKENS.input / 1_000_000) +
73
+ (pricing.output * AVG_TOKENS.output / 1_000_000)
74
+ ) + routedRequests * (
75
+ (cheaperPricing.input * AVG_TOKENS.input / 1_000_000) +
76
+ (cheaperPricing.output * AVG_TOKENS.output / 1_000_000)
77
+ );
78
+
79
+ return {
80
+ model,
81
+ requests: reqCount,
82
+ cost: a3mCost,
83
+ routedTo: routedRequests > 0 ? cheaper : null,
84
+ savings: baselineCost - a3mCost,
85
+ };
86
+ });
87
+
88
+ const totalCost = breakdown.reduce((sum, b) => sum + b.cost, 0);
89
+ const totalSavings = breakdown.reduce((sum, b) => sum + (b.savings || 0), 0);
90
+ return { totalCost, breakdown, totalSavings };
91
+ }
92
+
93
+ function findCheaperModel(model) {
94
+ const cheaperMap = {
95
+ 'gpt-4o': 'gpt-4o-mini',
96
+ 'claude-3.5-sonnet': 'claude-3-haiku',
97
+ 'gemini-1.5-pro': 'gemini-1.5-flash',
98
+ 'groq-llama-3.3-70b': 'groq-mixtral-8x7b',
99
+ };
100
+ return cheaperMap[model] || null;
101
+ }
102
+
103
+ /**
104
+ * @param {number} baseline
105
+ * @param {number} a3m
106
+ * @returns {{ savingsPercent: number, savingsAmount: number }}
107
+ */
108
+ function computeSavings(baseline, a3m) {
109
+ return {
110
+ savingsPercent: baseline > 0 ? ((baseline - a3m) / baseline) * 100 : 0,
111
+ savingsAmount: baseline - a3m,
112
+ };
113
+ }
114
+
115
+ /**
116
+ * Encodes calculator config into a URL-safe string
117
+ * @param {{ requestsPerMonth: number, modelMix: Array }} cfg
118
+ * @returns {string} base64url encoded config
119
+ */
120
+ function encodeConfig({ requestsPerMonth, modelMix }) {
121
+ const json = JSON.stringify({ requestsPerMonth, modelMix });
122
+ // btoa but URL-safe
123
+ return btoa(json).replace(/\+/g, '-').replace(/\//g, '_').replace(/=/g, '');
124
+ }
125
+
126
+ /**
127
+ * Decodes a URL-safe base64 string back to config
128
+ * @param {string} encoded
129
+ * @returns {{ requestsPerMonth: number, modelMix: Array }}
130
+ */
131
+ function decodeConfig(encoded) {
132
+ const base64 = encoded.replace(/-/g, '+').replace(/_/g, '/');
133
+ const json = atob(base64);
134
+ return JSON.parse(json);
135
+ }
136
+
137
+ /**
138
+ * Generates a full shareable URL
139
+ * @param {{ requestsPerMonth: number, modelMix: Array }} cfg
140
+ * @returns {string}
141
+ */
142
+ function generateShareableLink(cfg) {
143
+ const encoded = encodeConfig(cfg);
144
+ return `${window.location.origin}${window.location.pathname}?cfg=${encoded}`;
145
+ }
146
+
147
+ // --- Exports for testing ---
148
+ if (typeof module !== 'undefined' && module.exports) {
149
+ module.exports = { calculateBaselineCost, calculateA3mCost, computeSavings, encodeConfig, decodeConfig, PRICING };
150
+ }