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.
Files changed (51) hide show
  1. package/README.md +146 -105
  2. package/assets/benchmark-results.png +0 -0
  3. package/assets/complexity-scoring-v2.png +0 -0
  4. package/assets/complexity-scoring.png +0 -0
  5. package/assets/cost-comparison-chart.png +0 -0
  6. package/assets/cost-comparison-v2.png +0 -0
  7. package/assets/feature-comparison-v2.png +0 -0
  8. package/assets/feature-comparison-v3.png +0 -0
  9. package/assets/provider-health-chart.png +0 -0
  10. package/assets/provider-health-v2.png +0 -0
  11. package/assets/routing-flow-v2.png +0 -0
  12. package/assets/routing-flow-v3.png +0 -0
  13. package/assets/routing-flow.png +0 -0
  14. package/assets/tier-distribution.png +0 -0
  15. package/benchmark-results.json +620 -46
  16. package/dist/analytics/costAnalytics.d.ts +0 -1
  17. package/dist/cache/semanticCache.d.ts +0 -41
  18. package/dist/cache/semanticCache.d.ts.map +1 -1
  19. package/dist/cache/semanticCache.js +0 -142
  20. package/dist/cache/semanticCache.js.map +1 -1
  21. package/dist/cli.js +478 -35
  22. package/dist/cost/costTracker.js +3 -0
  23. package/dist/index.d.ts +0 -16
  24. package/dist/index.js +64 -264
  25. package/dist/integrations/langchainAdapter.d.ts +0 -1
  26. package/dist/integrations/oauth.d.ts +0 -1
  27. package/dist/memory/autoFetch.d.ts +0 -1
  28. package/dist/memory/memoryTree.d.ts +0 -1
  29. package/dist/memory/obsidianVault.d.ts +0 -1
  30. package/dist/providers/providerConfig.d.ts +0 -1
  31. package/dist/providers/providerConfig.js +0 -2
  32. package/dist/providers/registry.js +128 -126
  33. package/dist/routing/advancedRouter.js +427 -310
  34. package/dist/sdk.js +100 -109
  35. package/dist/security/guardrails.d.ts +0 -1
  36. package/dist/server/dashboard.d.ts +0 -1
  37. package/dist/server/modelMapper.d.ts +0 -1
  38. package/dist/server/proxyServer.d.ts +0 -1
  39. package/package.json +96 -389
  40. package/scripts/run-mmlu-benchmark.js +176 -0
  41. package/scripts/run-provider-benchmark.js +244 -0
  42. package/src/cache/semanticCache.ts +0 -148
  43. package/src/index.ts +99 -0
  44. package/test/provider-test.js +70 -91
  45. package/test.js +41 -67
  46. package/tsconfig.json +5 -15
  47. package/dist/index.d.ts.map +0 -1
  48. package/dist/index.js.map +0 -1
  49. package/dist/sdk.d.ts.map +0 -1
  50. package/dist/sdk.js.map +0 -1
  51. package/test.js.bak +0 -376
@@ -1,138 +1,140 @@
1
1
  "use strict";
2
2
  /**
3
- * TMLPD Provider Registry
4
- *
5
- * Manages provider configurations, API keys, and base URLs.
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
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.ProviderRegistry = void 0;
9
- const DEFAULT_PROVIDER_CONFIG = {
10
- providers: ["openai", "openrouter", "groq", "cerebras", "mistral", "xai", "zai", "anthropic", "google"],
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
- providers = new Map();
17
- config;
18
- modelPriority;
19
- constructor(config = {}) {
20
- this.config = { ...DEFAULT_PROVIDER_CONFIG, ...config };
21
- this.modelPriority = this.config.modelPriority;
22
- this.initializeProviders();
23
- }
24
- initializeProviders() {
25
- // Initialize from environment
26
- const envVars = {
27
- openai: { key: "OPENAI_API_KEY", url: "OPENAI_OPENAI_BASE_URL", mode: "openai" },
28
- openrouter: { key: "OPENROUTER_API_KEY", url: "OPENROUTER_OPENAI_BASE_URL", mode: "openai" },
29
- groq: { key: "GROQ_API_KEY", url: "GROQ_OPENAI_BASE_URL", mode: "openai" },
30
- cerebras: { key: "CEREBRAS_API_KEY", url: "CEREBRAS_OPENAI_BASE_URL", mode: "openai" },
31
- mistral: { key: "MISTRAL_API_KEY", url: "MISTRAL_OPENAI_BASE_URL", mode: "openai" },
32
- xai: { key: "XAI_API_KEY", url: "XAI_OPENAI_BASE_URL", mode: "openai" },
33
- zai: { key: "ZAI_API_KEY", url: "ZAI_OPENAI_BASE_URL", mode: "anthropic" },
34
- anthropic: { key: "ANTHROPIC_API_KEY", url: "ANTHROPIC_BASE_URL", mode: "anthropic" },
35
- google: { key: "GOOGLE_API_KEY", url: "GOOGLE_GEMINI_BASE_URL", mode: "gemini" },
36
- };
37
- for (const [name, env] of Object.entries(envVars)) {
38
- const apiKey = process.env[env.key] || "";
39
- const baseUrl = process.env[env.url] || "";
40
- this.providers.set(name, {
41
- name,
42
- apiKey,
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
- * Check if provider is ready (has API key, not in cooldown)
56
- */
57
- isProviderReady(name) {
58
- const provider = this.providers.get(name);
59
- if (!provider || !provider.enabled)
60
- return false;
61
- if (Date.now() < provider.cooldownUntil)
62
- return false;
63
- return true;
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
- * Get best available model from priority list
67
- */
68
- selectModel() {
69
- for (const model of this.modelPriority) {
70
- const providerName = model.split("/")[0];
71
- if (this.isProviderReady(providerName)) {
72
- return model;
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
- return null;
78
+ }
76
79
  }
77
- /**
78
- * Get all providers sorted by priority
79
- */
80
- getReadyProviders() {
81
- return Array.from(this.providers.entries())
82
- .filter(([_, p]) => this.isProviderReady(p.name))
83
- .sort((a, b) => a[1].priority - b[1].priority)
84
- .map(([name]) => name);
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
- * Record provider success
88
- */
89
- recordSuccess(name) {
90
- const provider = this.providers.get(name);
91
- if (provider) {
92
- provider.cooldownUntil = 0;
93
- provider.failureCount = 0;
94
- provider.lastError = null;
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
- * Record provider failure
100
- */
101
- recordFailure(name, statusCode, error) {
102
- const provider = this.providers.get(name);
103
- if (!provider)
104
- return;
105
- provider.failureCount++;
106
- provider.lastError = error;
107
- provider.lastStatus = statusCode;
108
- // Apply exponential backoff cooldown
109
- const baseDelay = statusCode === 429 ? 60000 : statusCode === 403 ? 300000 : 30000;
110
- const multiplier = Math.min(4, Math.pow(2, Math.max(0, provider.failureCount - 1)));
111
- provider.cooldownUntil = Date.now() + baseDelay * multiplier;
112
- }
113
- /**
114
- * Get provider status summary
115
- */
116
- getStatus() {
117
- const status = {};
118
- for (const [name, provider] of this.providers.entries()) {
119
- status[name] = {
120
- enabled: provider.enabled,
121
- mode: provider.mode,
122
- ready: this.isProviderReady(name),
123
- cooldownUntil: provider.cooldownUntil ? new Date(provider.cooldownUntil).toISOString() : null,
124
- lastError: provider.lastError,
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
- exports.ProviderRegistry = ProviderRegistry;
138
- //# sourceMappingURL=registry.js.map
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
+ };