adaptive-memory-multi-model-router 2.2.6 → 2.2.8
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 +146 -105
- package/assets/benchmark-results.png +0 -0
- package/assets/complexity-scoring-v2.png +0 -0
- package/assets/complexity-scoring.png +0 -0
- package/assets/cost-comparison-chart.png +0 -0
- package/assets/cost-comparison-v2.png +0 -0
- package/assets/feature-comparison-v2.png +0 -0
- package/assets/feature-comparison-v3.png +0 -0
- package/assets/provider-health-chart.png +0 -0
- package/assets/provider-health-v2.png +0 -0
- package/assets/routing-flow-v2.png +0 -0
- package/assets/routing-flow-v3.png +0 -0
- package/assets/routing-flow.png +0 -0
- package/assets/tier-distribution.png +0 -0
- package/benchmark-results.json +620 -46
- package/dist/analytics/costAnalytics.d.ts +0 -1
- package/dist/cache/semanticCache.d.ts +0 -41
- package/dist/cache/semanticCache.d.ts.map +1 -1
- package/dist/cache/semanticCache.js +0 -142
- package/dist/cache/semanticCache.js.map +1 -1
- package/dist/cli.js +478 -35
- package/dist/cost/costTracker.js +3 -0
- package/dist/index.d.ts +0 -16
- package/dist/index.js +64 -264
- package/dist/integrations/langchainAdapter.d.ts +0 -1
- package/dist/integrations/oauth.d.ts +0 -1
- package/dist/memory/autoFetch.d.ts +0 -1
- package/dist/memory/memoryTree.d.ts +0 -1
- package/dist/memory/obsidianVault.d.ts +0 -1
- package/dist/providers/providerConfig.d.ts +0 -1
- package/dist/providers/providerConfig.js +0 -2
- package/dist/providers/registry.js +128 -126
- package/dist/routing/advancedRouter.js +427 -310
- package/dist/sdk.js +100 -109
- package/dist/security/guardrails.d.ts +0 -1
- package/dist/server/dashboard.d.ts +0 -1
- package/dist/server/modelMapper.d.ts +0 -1
- package/dist/server/proxyServer.d.ts +0 -1
- package/package.json +96 -389
- package/scripts/run-mmlu-benchmark.js +176 -0
- package/scripts/run-provider-benchmark.js +244 -0
- package/src/cache/semanticCache.ts +0 -148
- package/src/index.ts +99 -0
- package/test/provider-test.js +70 -91
- package/test.js +41 -67
- package/tsconfig.json +5 -15
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/sdk.d.ts.map +0 -1
- package/dist/sdk.js.map +0 -1
- package/test.js.bak +0 -376
|
@@ -1,138 +1,140 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
3
|
+
* A3M Router - Generic Provider Registry
|
|
4
|
+
*
|
|
5
|
+
* Dynamically discovers and manages available LLM providers.
|
|
6
|
+
* Users configure providers via:
|
|
7
|
+
* - Environment variables (*_API_KEY patterns)
|
|
8
|
+
* - ~/.config/a3m-router/providers.json
|
|
9
|
+
* - Runtime registration via registerProvider()
|
|
10
|
+
*
|
|
11
|
+
* No hardcoded provider references - all loaded from providerConfig.
|
|
6
12
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
modelPriority: ["openai/gpt-4o", "groq/llama-3.3-70b-versatile", "cerebras/llama-3.3-70b"],
|
|
12
|
-
useOpenclawFallback: false,
|
|
13
|
-
maxTokens: 4096,
|
|
14
|
-
};
|
|
13
|
+
|
|
14
|
+
const { getAvailableProviders, loadConfig, healthCheck, registerProvider, deregisterProvider } = require("./providerConfig");
|
|
15
|
+
const { routeQuery, routeBatch, recommendForTask, extractQueryFeatures, MODEL_PROFILES } = require("../routing/advancedRouter");
|
|
16
|
+
|
|
15
17
|
class ProviderRegistry {
|
|
16
|
-
|
|
17
|
-
config;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
baseUrl,
|
|
44
|
-
mode: env.mode,
|
|
45
|
-
priority: this.modelPriority.findIndex((m) => m.startsWith(name + "/")),
|
|
46
|
-
enabled: Boolean(apiKey),
|
|
47
|
-
cooldownUntil: 0,
|
|
48
|
-
failureCount: 0,
|
|
49
|
-
lastError: null,
|
|
50
|
-
lastStatus: null,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
18
|
+
constructor(config = {}) {
|
|
19
|
+
this.config = config;
|
|
20
|
+
this.providers = new Map();
|
|
21
|
+
this.readyCache = [];
|
|
22
|
+
this.cacheTime = 0;
|
|
23
|
+
this.cacheDuration = 60000; // 1 minute
|
|
24
|
+
|
|
25
|
+
// Load configuration from env vars and config files
|
|
26
|
+
loadConfig();
|
|
27
|
+
this.initializeProviders();
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
initializeProviders() {
|
|
31
|
+
const available = getAvailableProviders();
|
|
32
|
+
|
|
33
|
+
for (const [name, provider] of Object.entries(available)) {
|
|
34
|
+
this.providers.set(name, {
|
|
35
|
+
name,
|
|
36
|
+
apiKey: provider.apiKey || null,
|
|
37
|
+
baseUrl: provider.baseUrl || null,
|
|
38
|
+
models: provider.models,
|
|
39
|
+
type: provider.type,
|
|
40
|
+
priority: provider.priority,
|
|
41
|
+
enabled: true,
|
|
42
|
+
cooldownUntil: 0,
|
|
43
|
+
failureCount: 0,
|
|
44
|
+
});
|
|
53
45
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
isProviderReady(name) {
|
|
49
|
+
const provider = this.providers.get(name);
|
|
50
|
+
if (!provider || !provider.enabled) return false;
|
|
51
|
+
if (Date.now() < provider.cooldownUntil) return false;
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getReadyProviders() {
|
|
56
|
+
const now = Date.now();
|
|
57
|
+
if (now - this.cacheTime < this.cacheDuration && this.readyCache.length > 0) {
|
|
58
|
+
return this.readyCache;
|
|
64
59
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
|
|
61
|
+
this.readyCache = Array.from(this.providers.entries())
|
|
62
|
+
.filter(([_, p]) => this.isProviderReady(p.name))
|
|
63
|
+
.map(([name]) => name);
|
|
64
|
+
this.cacheTime = now;
|
|
65
|
+
return this.readyCache;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
selectModel() {
|
|
69
|
+
const available = getAvailableProviders();
|
|
70
|
+
const sorted = Object.entries(available).sort(([, a], [, b]) => a.priority - b.priority);
|
|
71
|
+
|
|
72
|
+
for (const [name, provider] of sorted) {
|
|
73
|
+
for (const model of provider.models) {
|
|
74
|
+
const modelKey = model.includes('/') ? model : name + '/' + model;
|
|
75
|
+
if (this.isProviderReady(name)) {
|
|
76
|
+
return modelKey;
|
|
74
77
|
}
|
|
75
|
-
|
|
78
|
+
}
|
|
76
79
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
recordSuccess(name) {
|
|
84
|
+
const provider = this.providers.get(name);
|
|
85
|
+
if (provider) {
|
|
86
|
+
provider.failureCount = 0;
|
|
87
|
+
provider.cooldownUntil = 0;
|
|
85
88
|
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
provider.lastStatus = null;
|
|
96
|
-
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
recordFailure(name) {
|
|
92
|
+
const provider = this.providers.get(name);
|
|
93
|
+
if (provider) {
|
|
94
|
+
provider.failureCount++;
|
|
95
|
+
if (provider.failureCount >= 3) {
|
|
96
|
+
provider.cooldownUntil = Date.now() + 60000;
|
|
97
|
+
}
|
|
97
98
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
lastStatus: provider.lastStatus,
|
|
126
|
-
failureCount: provider.failureCount,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
return {
|
|
130
|
-
modelPriority: this.modelPriority,
|
|
131
|
-
readyProviders: this.getReadyProviders(),
|
|
132
|
-
providers: status,
|
|
133
|
-
timestamp: new Date().toISOString(),
|
|
134
|
-
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
getStatus() {
|
|
102
|
+
const available = getAvailableProviders();
|
|
103
|
+
return {
|
|
104
|
+
providers: Array.from(this.providers.keys()),
|
|
105
|
+
available: Object.keys(available),
|
|
106
|
+
ready: this.getReadyProviders(),
|
|
107
|
+
modelPriority: this.selectModel(),
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Dynamic provider management
|
|
112
|
+
addProvider(id, config) {
|
|
113
|
+
registerProvider(id, config);
|
|
114
|
+
this.initializeProviders();
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
removeProvider(id) {
|
|
118
|
+
deregisterProvider(id);
|
|
119
|
+
this.initializeProviders();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async checkHealth() {
|
|
123
|
+
const results = {};
|
|
124
|
+
for (const [name] of this.providers) {
|
|
125
|
+
results[name] = await healthCheck(name);
|
|
135
126
|
}
|
|
127
|
+
return results;
|
|
128
|
+
}
|
|
136
129
|
}
|
|
137
|
-
|
|
138
|
-
|
|
130
|
+
|
|
131
|
+
const _routing = require("../routing/advancedRouter");
|
|
132
|
+
|
|
133
|
+
module.exports = {
|
|
134
|
+
ProviderRegistry,
|
|
135
|
+
routeQuery: _routing.routeQuery,
|
|
136
|
+
routeBatch: _routing.routeBatch,
|
|
137
|
+
recommendForTask: _routing.recommendForTask,
|
|
138
|
+
extractQueryFeatures: _routing.extractQueryFeatures,
|
|
139
|
+
MODEL_PROFILES: _routing.MODEL_PROFILES,
|
|
140
|
+
};
|