adaptive-memory-multi-model-router 2.14.59 → 2.15.0

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 (140) hide show
  1. package/.github/ISSUE_TEMPLATE/checklist.md +35 -0
  2. package/.github/workflows/ci.yml +9 -6
  3. package/POPULARITY_BOOSTERS.md +18 -0
  4. package/PR_STATUS_REPORT.md +55 -148
  5. package/README.md +222 -1035
  6. package/assets/chart-accuracy-by-tier.svg +63 -0
  7. package/assets/chart-confusion-matrix.svg +98 -0
  8. package/assets/chart-cost-comparison.svg +66 -0
  9. package/assets/chart-latency-overhead.svg +102 -0
  10. package/assets/chart-routerena-leaderboard.svg +76 -0
  11. package/dist/analytics/costAnalytics.d.ts +1 -0
  12. package/dist/benchmark/comprehensive.d.ts +4 -53
  13. package/dist/benchmark/comprehensive.d.ts.map +1 -0
  14. package/dist/benchmark/comprehensive.js +112 -214
  15. package/dist/benchmark/comprehensive.js.map +1 -1
  16. package/dist/benchmark/reproducible.d.ts +1 -0
  17. package/dist/cache/semanticCache.d.ts +1 -0
  18. package/dist/cli/setupWizard.d.ts +6 -1
  19. package/dist/cli/setupWizard.d.ts.map +1 -1
  20. package/dist/cli/setupWizard.js +6 -9
  21. package/dist/cli/setupWizard.js.map +1 -1
  22. package/dist/cost/budgetEnforcer.d.ts +1 -0
  23. package/dist/cost/costTracker.d.ts +1 -0
  24. package/dist/ensemble/multiRoundDialog.d.ts +1 -0
  25. package/dist/ensemble/multiRoundDialog.d.ts.map +1 -0
  26. package/dist/ensemble/shapleyValue.d.ts +1 -0
  27. package/dist/ensemble/shapleyValue.d.ts.map +1 -0
  28. package/dist/ensemble.d.ts +1 -0
  29. package/dist/index.d.ts +1 -0
  30. package/dist/integrations/langchainAdapter.d.ts +1 -0
  31. package/dist/integrations/oauth.d.ts +1 -0
  32. package/dist/integrations/scienceAdapter.d.ts +1 -0
  33. package/dist/integrations/scienceAdapter.d.ts.map +1 -0
  34. package/dist/memory/autoFetch.d.ts +1 -0
  35. package/dist/memory/hybridMemory.d.ts +1 -0
  36. package/dist/memory/hybridMemory.d.ts.map +1 -0
  37. package/dist/memory/memoryTree.d.ts +1 -0
  38. package/dist/memory/memoryTree.d.ts.map +1 -1
  39. package/dist/memory/obsidianVault.d.ts +1 -0
  40. package/dist/memory/obsidianVault.d.ts.map +1 -1
  41. package/dist/memory/reasoningBank.d.ts +1 -0
  42. package/dist/memory/reasoningBank.d.ts.map +1 -0
  43. package/dist/observability/changeWatch.d.ts +1 -0
  44. package/dist/observability/fatigueDetector.d.ts +1 -0
  45. package/dist/observability/index.d.ts +1 -0
  46. package/dist/observability/metrics.d.ts +1 -0
  47. package/dist/observability/metrics.d.ts.map +1 -1
  48. package/dist/observability/middleware.d.ts +1 -0
  49. package/dist/observability/tracer.d.ts +1 -0
  50. package/dist/observability/tracer.d.ts.map +1 -1
  51. package/dist/observability/types.d.ts +1 -0
  52. package/dist/providers/providerConfig.d.ts +1 -0
  53. package/dist/providers/providerConfig.d.ts.map +1 -1
  54. package/dist/routing/advancedRouter.d.ts +2 -1
  55. package/dist/routing/advancedRouter.d.ts.map +1 -1
  56. package/dist/routing/crossModelValidation.d.ts +1 -0
  57. package/dist/routing/providerHealth.d.ts +1 -0
  58. package/dist/routing/providerHealth.d.ts.map +1 -1
  59. package/dist/routing/providerRetry.d.ts +1 -0
  60. package/dist/sdk.d.ts +1 -0
  61. package/dist/security/guardrails.d.ts +1 -0
  62. package/dist/security/guardrails.d.ts.map +1 -1
  63. package/dist/server/dashboard.d.ts +1 -0
  64. package/dist/server/handlers/chatHandler.d.ts +11 -0
  65. package/dist/server/handlers/chatHandler.d.ts.map +1 -0
  66. package/dist/server/handlers/chatHandler.js +159 -0
  67. package/dist/server/handlers/chatHandler.js.map +1 -0
  68. package/dist/server/handlers/completionsHandler.d.ts +10 -0
  69. package/dist/server/handlers/completionsHandler.d.ts.map +1 -0
  70. package/dist/server/handlers/completionsHandler.js +124 -0
  71. package/dist/server/handlers/completionsHandler.js.map +1 -0
  72. package/dist/server/handlers/embeddingsHandler.d.ts +17 -0
  73. package/dist/server/handlers/embeddingsHandler.d.ts.map +1 -0
  74. package/dist/server/handlers/embeddingsHandler.js +235 -0
  75. package/dist/server/handlers/embeddingsHandler.js.map +1 -0
  76. package/dist/server/handlers/healthHandler.d.ts +10 -0
  77. package/dist/server/handlers/healthHandler.d.ts.map +1 -0
  78. package/dist/server/handlers/healthHandler.js +49 -0
  79. package/dist/server/handlers/healthHandler.js.map +1 -0
  80. package/dist/server/handlers/metricsHandler.d.ts +11 -0
  81. package/dist/server/handlers/metricsHandler.d.ts.map +1 -0
  82. package/dist/server/handlers/metricsHandler.js +24 -0
  83. package/dist/server/handlers/metricsHandler.js.map +1 -0
  84. package/dist/server/handlers/modelsHandler.d.ts +10 -0
  85. package/dist/server/handlers/modelsHandler.d.ts.map +1 -0
  86. package/dist/server/handlers/modelsHandler.js +19 -0
  87. package/dist/server/handlers/modelsHandler.js.map +1 -0
  88. package/dist/server/metrics.d.ts +96 -0
  89. package/dist/server/metrics.d.ts.map +1 -0
  90. package/dist/server/metrics.js +267 -0
  91. package/dist/server/metrics.js.map +1 -0
  92. package/dist/server/modelMapper.d.ts +1 -0
  93. package/dist/server/proxyServer.d.ts +53 -17
  94. package/dist/server/proxyServer.d.ts.map +1 -1
  95. package/dist/server/proxyServer.js +66 -303
  96. package/dist/server/proxyServer.js.map +1 -1
  97. package/dist/server/router.d.ts +49 -0
  98. package/dist/server/router.d.ts.map +1 -0
  99. package/dist/server/router.js +120 -0
  100. package/dist/server/router.js.map +1 -0
  101. package/dist/server/state.d.ts +30 -0
  102. package/dist/server/state.d.ts.map +1 -0
  103. package/dist/server/state.js +18 -0
  104. package/dist/server/state.js.map +1 -0
  105. package/dist/skills/__tests__/skill_manager.test.d.ts +3 -0
  106. package/dist/skills/__tests__/skill_manager.test.d.ts.map +1 -1
  107. package/dist/skills/__tests__/skill_manager.test.js +3 -6
  108. package/dist/skills/__tests__/skill_manager.test.js.map +1 -1
  109. package/dist/tui/dashboard.d.ts +1 -0
  110. package/dist/tui/index.d.ts +1 -0
  111. package/dist/utils/costUtils.d.ts +1 -0
  112. package/dist/utils/reliability.js +4 -18
  113. package/dist/utils/sorting.d.ts +1 -0
  114. package/dist/utils/tokenUtils.d.ts +1 -0
  115. package/docs/assets/chart-accuracy-by-tier.svg +63 -0
  116. package/docs/assets/chart-confusion-matrix.svg +98 -0
  117. package/docs/assets/chart-cost-comparison.svg +66 -0
  118. package/docs/assets/chart-latency-overhead.svg +102 -0
  119. package/docs/assets/chart-routerena-leaderboard.svg +76 -0
  120. package/docs/index.html +72 -80
  121. package/docs/llms-full.txt +156 -184
  122. package/docs/llms.txt +77 -42
  123. package/llms-full.txt +156 -184
  124. package/llms.txt +77 -42
  125. package/mcp-server/package.json +6 -0
  126. package/mcp-server/tsconfig.json +3 -2
  127. package/package.json +4 -3
  128. package/scripts/postinstall-nudge.js +3 -0
  129. package/src/server/handlers/chatHandler.ts +173 -0
  130. package/src/server/handlers/completionsHandler.ts +120 -0
  131. package/src/server/handlers/embeddingsHandler.ts +271 -0
  132. package/src/server/handlers/healthHandler.ts +57 -0
  133. package/src/server/handlers/metricsHandler.ts +30 -0
  134. package/src/server/handlers/modelsHandler.ts +25 -0
  135. package/src/server/metrics.ts +303 -0
  136. package/src/server/proxyServer.ts +71 -394
  137. package/src/server/router.ts +157 -0
  138. package/src/server/state.ts +34 -0
  139. package/src/skills/__tests__/skill_manager.test.ts +3 -3
  140. package/index.html +0 -667
@@ -0,0 +1,303 @@
1
+ /**
2
+ * A3M Router - Prometheus Metrics
3
+ *
4
+ * Lightweight metrics collector for observability.
5
+ * Exports Prometheus-compatible /metrics endpoint.
6
+ *
7
+ * Metrics:
8
+ * a3m_requests_total{endpoint, provider, status} — Counter
9
+ * a3m_request_duration_ms{endpoint, provider} — Histogram
10
+ * a3m_cost_usd_total{provider} — Counter
11
+ * a3m_tokens_total{provider, type} — Counter
12
+ * a3m_cache_hits_total{cache_type} — Counter
13
+ * a3m_fallback_triggered_total{provider} — Counter
14
+ * a3m_provider_errors_total{provider, error_type} — Counter
15
+ * a3m_routing_decisions_total{model} — Counter
16
+ * a3m_active_requests — Gauge
17
+ */
18
+
19
+ // ============================================================
20
+ // TYPES
21
+ // ============================================================
22
+
23
+ export interface Counter {
24
+ value: number;
25
+ labels: Record<string, string>;
26
+ }
27
+
28
+ export interface Histogram {
29
+ values: number[];
30
+ count: number;
31
+ sum: number;
32
+ buckets: { bound: number; count: number }[];
33
+ }
34
+
35
+ export interface Gauge {
36
+ value: number;
37
+ }
38
+
39
+ // ============================================================
40
+ // METRICS STORE
41
+ // ============================================================
42
+
43
+ // Counters: { name: { labels: value } }
44
+ const counters = new Map<string, Map<string, number>>();
45
+ // Histograms: { name: { labels: { values[], count, sum, buckets[] } } }
46
+ const histograms = new Map<string, Map<string, Histogram>>();
47
+ // Gauges: { name: { labels: value } }
48
+ const gauges = new Map<string, Map<string, number>>();
49
+
50
+ // Metric definitions
51
+ const METRIC_DEFINITIONS = {
52
+ a3m_requests_total: { type: 'counter', help: 'Total requests' },
53
+ a3m_request_duration_ms: {
54
+ type: 'histogram',
55
+ help: 'Request duration in milliseconds',
56
+ buckets: [5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000],
57
+ },
58
+ a3m_cost_usd_total: { type: 'counter', help: 'Total cost in USD' },
59
+ a3m_tokens_total: { type: 'counter', help: 'Total tokens' },
60
+ a3m_cache_hits_total: { type: 'counter', help: 'Cache hits' },
61
+ a3m_fallback_triggered_total: { type: 'counter', help: 'Fallback triggered count' },
62
+ a3m_provider_errors_total: { type: 'counter', help: 'Provider errors' },
63
+ a3m_routing_decisions_total: { type: 'counter', help: 'Routing decisions' },
64
+ a3m_active_requests: { type: 'gauge', help: 'Active requests' },
65
+ } as const;
66
+
67
+ const LABEL_NAMES = {
68
+ a3m_requests_total: ['endpoint', 'provider', 'status'] as const,
69
+ a3m_request_duration_ms: ['endpoint', 'provider'] as const,
70
+ a3m_cost_usd_total: ['provider'] as const,
71
+ a3m_tokens_total: ['provider', 'type'] as const,
72
+ a3m_cache_hits_total: ['cache_type'] as const,
73
+ a3m_fallback_triggered_total: ['provider'] as const,
74
+ a3m_provider_errors_total: ['provider', 'error_type'] as const,
75
+ a3m_routing_decisions_total: ['model'] as const,
76
+ a3m_active_requests: [] as const,
77
+ } as const;
78
+
79
+ // ============================================================
80
+ // HELPERS
81
+ // ============================================================
82
+
83
+ function labelsToKey(labels: Record<string, string>): string {
84
+ return Object.keys(labels)
85
+ .sort()
86
+ .map((k) => `${k}="${labels[k]}"`)
87
+ .join(',');
88
+ }
89
+
90
+ function getOrInitCounter(name: string, labels: Record<string, string>): Map<string, number> {
91
+ if (!counters.has(name)) counters.set(name, new Map());
92
+ const counterMap = counters.get(name)!;
93
+ const key = labelsToKey(labels);
94
+ if (!counterMap.has(key)) counterMap.set(key, 0);
95
+ return counterMap;
96
+ }
97
+
98
+ function getOrInitHistogram(name: string, labels: Record<string, string>): Histogram {
99
+ if (!histograms.has(name)) histograms.set(name, new Map());
100
+ const histMap = histograms.get(name)!;
101
+ const key = labelsToKey(labels);
102
+ if (!histMap.has(key)) {
103
+ const def = METRIC_DEFINITIONS[name as keyof typeof METRIC_DEFINITIONS];
104
+ if (def.type !== 'histogram') {
105
+ throw new Error(`Metric ${name} is not a histogram`);
106
+ }
107
+ const histDef = def as { type: 'histogram'; buckets: readonly number[] };
108
+ histMap.set(key, {
109
+ values: [],
110
+ count: 0,
111
+ sum: 0,
112
+ buckets: histDef.buckets.map((b) => ({ bound: b, count: 0 })),
113
+ });
114
+ }
115
+ return histMap.get(key)!;
116
+ }
117
+
118
+ function getOrInitGauge(name: string, labels: Record<string, string>): Map<string, number> {
119
+ if (!gauges.has(name)) gauges.set(name, new Map());
120
+ const gaugeMap = gauges.get(name)!;
121
+ const key = labelsToKey(labels);
122
+ if (!gaugeMap.has(key)) gaugeMap.set(key, 0);
123
+ return gaugeMap;
124
+ }
125
+
126
+ // ============================================================
127
+ // PUBLIC API
128
+ // ============================================================
129
+
130
+ /**
131
+ * Increment a counter by delta (default 1).
132
+ */
133
+ export function incrementCounter(name: string, labels: Record<string, string> = {}, delta = 1): void {
134
+ const counterMap = getOrInitCounter(name, labels);
135
+ const key = labelsToKey(labels);
136
+ counterMap.set(key, counterMap.get(key)! + delta);
137
+ }
138
+
139
+ /**
140
+ * Record a histogram value (duration, size, etc.).
141
+ */
142
+ export function recordHistogram(name: string, labels: Record<string, string>, value: number): void {
143
+ const hist = getOrInitHistogram(name, labels);
144
+ hist.values.push(value);
145
+ hist.count++;
146
+ hist.sum += value;
147
+ // Update bucket counts
148
+ for (const bucket of hist.buckets) {
149
+ if (value <= bucket.bound) bucket.count++;
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Set a gauge value.
155
+ */
156
+ export function setGauge(name: string, labels: Record<string, string>, value: number): void {
157
+ const gaugeMap = getOrInitGauge(name, labels);
158
+ const key = labelsToKey(labels);
159
+ gaugeMap.set(key, value);
160
+ }
161
+
162
+ /**
163
+ * Increment active requests gauge (call on start, decrement on end).
164
+ */
165
+ export function recordActiveRequest(delta: 1 | -1): void {
166
+ setGauge('a3m_active_requests', {}, Math.max(0, getActiveRequests() + delta));
167
+ }
168
+
169
+ /**
170
+ * Get current active request count.
171
+ */
172
+ export function getActiveRequests(): number {
173
+ const gaugeMap = gauges.get('a3m_active_requests');
174
+ if (!gaugeMap || gaugeMap.size === 0) return 0;
175
+ return Array.from(gaugeMap.values())[0] || 0;
176
+ }
177
+
178
+ // ============================================================
179
+ // PROMETHEUS EXPORT FORMAT
180
+ // ============================================================
181
+
182
+ /**
183
+ * Generate Prometheus /metrics output.
184
+ */
185
+ export function generatePrometheusMetrics(): string {
186
+ const lines: string[] = [];
187
+
188
+ // Helper to get metric help/type
189
+ function metricHeader(name: string): string {
190
+ const def = METRIC_DEFINITIONS[name as keyof typeof METRIC_DEFINITIONS];
191
+ if (!def) return '';
192
+ return `# HELP ${name} ${def.help}\n# TYPE ${name} ${def.type}`;
193
+ }
194
+
195
+ // Counters
196
+ for (const [name, counterMap] of counters) {
197
+ lines.push(metricHeader(name));
198
+ for (const [labelKey, value] of counterMap) {
199
+ lines.push(`${name}{${labelKey}} ${value}`);
200
+ }
201
+ lines.push('');
202
+ }
203
+
204
+ // Histograms
205
+ for (const [name, histMap] of histograms) {
206
+ lines.push(metricHeader(name));
207
+ for (const [labelKey, hist] of histMap) {
208
+ // Per-bucket cumulative counts
209
+ for (const bucket of hist.buckets) {
210
+ lines.push(`${name}_bucket{${labelKey},le="${bucket.bound}"} ${bucket.count}`);
211
+ }
212
+ // +Inf bucket = total count
213
+ lines.push(`${name}_bucket{${labelKey},le="+Inf"} ${hist.count}`);
214
+ // Summary
215
+ lines.push(`${name}_sum{${labelKey}} ${hist.sum}`);
216
+ lines.push(`${name}_count{${labelKey}} ${hist.count}`);
217
+ }
218
+ lines.push('');
219
+ }
220
+
221
+ // Gauges
222
+ for (const [name, gaugeMap] of gauges) {
223
+ lines.push(metricHeader(name));
224
+ for (const [labelKey, value] of gaugeMap) {
225
+ lines.push(`${name}{${labelKey}} ${value}`);
226
+ }
227
+ lines.push('');
228
+ }
229
+
230
+ return lines.join('\n');
231
+ }
232
+
233
+ // ============================================================
234
+ // SPECIALIZED RECORDERS (convenience wrappers)
235
+ // ============================================================
236
+
237
+ /**
238
+ * Record a completed request with all metrics.
239
+ */
240
+ export function recordRequest(params: {
241
+ endpoint: string;
242
+ provider: string;
243
+ status: 'success' | 'error';
244
+ durationMs: number;
245
+ tokensIn?: number;
246
+ tokensOut?: number;
247
+ cost?: number;
248
+ model?: string;
249
+ }): void {
250
+ incrementCounter('a3m_requests_total', {
251
+ endpoint: params.endpoint,
252
+ provider: params.provider,
253
+ status: params.status,
254
+ });
255
+ recordHistogram('a3m_request_duration_ms', {
256
+ endpoint: params.endpoint,
257
+ provider: params.provider,
258
+ }, params.durationMs);
259
+ if (params.tokensIn !== undefined && params.tokensOut !== undefined) {
260
+ incrementCounter('a3m_tokens_total', { provider: params.provider, type: 'input' }, params.tokensIn);
261
+ incrementCounter('a3m_tokens_total', { provider: params.provider, type: 'output' }, params.tokensOut);
262
+ }
263
+ if (params.cost !== undefined && params.cost > 0) {
264
+ incrementCounter('a3m_cost_usd_total', { provider: params.provider }, Math.round(params.cost * 1e6) / 1e6);
265
+ }
266
+ if (params.model) {
267
+ incrementCounter('a3m_routing_decisions_total', { model: params.model });
268
+ }
269
+ }
270
+
271
+ /**
272
+ * Record a provider error.
273
+ */
274
+ export function recordProviderError(provider: string, errorType: string): void {
275
+ incrementCounter('a3m_provider_errors_total', { provider, error_type: errorType });
276
+ }
277
+
278
+ /**
279
+ * Record a cache hit.
280
+ */
281
+ export function recordCacheHit(cacheType: 'semantic' | 'exact' | 'none'): void {
282
+ incrementCounter('a3m_cache_hits_total', { cache_type: cacheType });
283
+ }
284
+
285
+ /**
286
+ * Record a fallback trigger.
287
+ */
288
+ export function recordFallback(provider: string): void {
289
+ incrementCounter('a3m_fallback_triggered_total', { provider });
290
+ }
291
+
292
+ export default {
293
+ incrementCounter,
294
+ recordHistogram,
295
+ setGauge,
296
+ recordActiveRequest,
297
+ getActiveRequests,
298
+ generatePrometheusMetrics,
299
+ recordRequest,
300
+ recordProviderError,
301
+ recordCacheHit,
302
+ recordFallback,
303
+ };