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,124 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Completions Handler
4
+ *
5
+ * Handles POST /v1/completions
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ exports.handleCompletions = handleCompletions;
42
+ const modelMapper_1 = require("../modelMapper");
43
+ const metrics_1 = require("../metrics");
44
+ function readBody(req) {
45
+ return new Promise((resolve, reject) => {
46
+ const chunks = [];
47
+ req.on('data', (chunk) => chunks.push(chunk));
48
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
49
+ req.on('error', reject);
50
+ });
51
+ }
52
+ function jsonResponse(res, statusCode, body) {
53
+ res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
54
+ res.end(JSON.stringify(body));
55
+ }
56
+ function errorResponse(res, statusCode, message, errorType = 'server_error') {
57
+ jsonResponse(res, statusCode, { error: { message, type: errorType, code: statusCode } });
58
+ }
59
+ async function handleCompletions(req, res, ctx) {
60
+ (0, metrics_1.recordActiveRequest)(1);
61
+ const body = await readBody(req);
62
+ let request;
63
+ try {
64
+ request = JSON.parse(body);
65
+ }
66
+ catch {
67
+ (0, metrics_1.recordActiveRequest)(-1);
68
+ errorResponse(res, 400, 'Invalid JSON in request body', 'invalid_request_error');
69
+ return;
70
+ }
71
+ const prompts = Array.isArray(request.prompt) ? request.prompt : [request.prompt || ''];
72
+ const messages = prompts.map((p) => ({ role: 'user', content: p }));
73
+ const model = request.model || 'auto';
74
+ const stream = request.stream || false;
75
+ const requestId = ctx.requestId;
76
+ const promptForRouting = prompts.join(' ');
77
+ const mapping = (0, modelMapper_1.resolveModel)(model, promptForRouting);
78
+ if (!mapping) {
79
+ (0, metrics_1.recordActiveRequest)(-1);
80
+ errorResponse(res, 503, `No provider available for model "${model}".`, 'server_error');
81
+ return;
82
+ }
83
+ const startTime = Date.now();
84
+ if (stream) {
85
+ try {
86
+ const { streamProviderResponse } = await Promise.resolve().then(() => __importStar(require('../proxyServer')));
87
+ await streamProviderResponse(res, mapping, messages, { temperature: request.temperature, max_tokens: request.max_tokens, stop: request.stop }, requestId);
88
+ const latencyMs = Date.now() - startTime;
89
+ (0, metrics_1.recordRequest)({ endpoint: '/v1/completions', provider: mapping.providerId, status: 'success', durationMs: latencyMs, model });
90
+ (0, metrics_1.recordActiveRequest)(-1);
91
+ }
92
+ catch (err) {
93
+ const message = err instanceof Error ? err.message : String(err);
94
+ if (!res.headersSent)
95
+ errorResponse(res, 500, message);
96
+ (0, metrics_1.recordActiveRequest)(-1);
97
+ }
98
+ return;
99
+ }
100
+ try {
101
+ const { callWithFallback } = await Promise.resolve().then(() => __importStar(require('../proxyServer')));
102
+ const { result, mapping: usedMapping } = await callWithFallback(model, messages, { temperature: request.temperature, max_tokens: request.max_tokens, stop: request.stop }, promptForRouting);
103
+ const latencyMs = Date.now() - startTime;
104
+ const response = {
105
+ id: requestId,
106
+ object: 'text_completion',
107
+ created: Math.floor(Date.now() / 1000),
108
+ model: result.model,
109
+ choices: [{ text: result.content, index: 0, finish_reason: result.finish_reason }],
110
+ usage: result.usage,
111
+ };
112
+ jsonResponse(res, 200, response);
113
+ (0, metrics_1.recordRequest)({ endpoint: '/v1/completions', provider: usedMapping.providerId, status: 'success', durationMs: latencyMs, tokensIn: result.usage.prompt_tokens, tokensOut: result.usage.completion_tokens, model });
114
+ console.log(`[a3m-router] ${requestId} completion model=${model}→${usedMapping.providerId}/${usedMapping.model} latency=${latencyMs}ms`);
115
+ }
116
+ catch (err) {
117
+ const message = err instanceof Error ? err.message : String(err);
118
+ if (!res.headersSent)
119
+ errorResponse(res, 502, message, 'upstream_error');
120
+ }
121
+ (0, metrics_1.recordActiveRequest)(-1);
122
+ }
123
+ exports.default = handleCompletions;
124
+ //# sourceMappingURL=completionsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completionsHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/completionsHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * A3M Router - Embeddings Handler
3
+ *
4
+ * Handles POST /v1/embeddings
5
+ * OpenAI-compatible embeddings endpoint.
6
+ *
7
+ * Routes embedding requests to the best available provider:
8
+ * - OpenAI (text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002)
9
+ * - Cohere (embed-english-v3.0, embed-multilingual-v3.0)
10
+ * - Google (text-embedding-004)
11
+ * - Local Ollama (nomic-embed-text, etc.)
12
+ */
13
+ import * as http from 'http';
14
+ import { RouteContext } from '../router';
15
+ export declare function handleEmbeddings(req: http.IncomingMessage, res: http.ServerResponse, ctx: RouteContext): Promise<void>;
16
+ export default handleEmbeddings;
17
+ //# sourceMappingURL=embeddingsHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddingsHandler.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/embeddingsHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAoLzC,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAsEf;AAED,eAAe,gBAAgB,CAAC"}
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Embeddings Handler
4
+ *
5
+ * Handles POST /v1/embeddings
6
+ * OpenAI-compatible embeddings endpoint.
7
+ *
8
+ * Routes embedding requests to the best available provider:
9
+ * - OpenAI (text-embedding-3-small, text-embedding-3-large, text-embedding-ada-002)
10
+ * - Cohere (embed-english-v3.0, embed-multilingual-v3.0)
11
+ * - Google (text-embedding-004)
12
+ * - Local Ollama (nomic-embed-text, etc.)
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.handleEmbeddings = handleEmbeddings;
16
+ const providerConfig_1 = require("../../providers/providerConfig");
17
+ const metrics_1 = require("../metrics");
18
+ function readBody(req) {
19
+ return new Promise((resolve, reject) => {
20
+ const chunks = [];
21
+ req.on('data', (chunk) => chunks.push(chunk));
22
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
23
+ req.on('error', reject);
24
+ });
25
+ }
26
+ function jsonResponse(res, statusCode, body) {
27
+ res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
28
+ res.end(JSON.stringify(body));
29
+ }
30
+ function errorResponse(res, statusCode, message, errorType = 'server_error') {
31
+ jsonResponse(res, statusCode, { error: { message, type: errorType, code: statusCode } });
32
+ }
33
+ /**
34
+ * Get the best available embeddings provider.
35
+ */
36
+ function getEmbeddingsProvider() {
37
+ const providers = (0, providerConfig_1.getAvailableProviders)();
38
+ // Priority: OpenAI > Cohere > Google > Ollama
39
+ const priority = ['openai', 'cohere', 'google', 'ollama'];
40
+ for (const id of priority) {
41
+ const provider = providers[id];
42
+ if (!provider || !provider.apiKey)
43
+ continue;
44
+ if (id === 'openai') {
45
+ return {
46
+ providerId: 'openai',
47
+ model: 'text-embedding-3-small',
48
+ adapter: openAIAdapter,
49
+ };
50
+ }
51
+ if (id === 'cohere') {
52
+ return {
53
+ providerId: 'cohere',
54
+ model: 'embed-english-v3.0',
55
+ adapter: cohereAdapter,
56
+ };
57
+ }
58
+ if (id === 'google') {
59
+ return {
60
+ providerId: 'google',
61
+ model: 'text-embedding-004',
62
+ adapter: googleAdapter,
63
+ };
64
+ }
65
+ if (id === 'ollama' && provider.baseUrl) {
66
+ return {
67
+ providerId: 'ollama',
68
+ model: 'nomic-embed-text:latest',
69
+ adapter: ollamaAdapter,
70
+ };
71
+ }
72
+ }
73
+ return null;
74
+ }
75
+ // ============================================================
76
+ // PROVIDER ADAPTERS
77
+ // ============================================================
78
+ const openAIAdapter = {
79
+ modelMap(model) {
80
+ const valid = ['text-embedding-3-small', 'text-embedding-3-large', 'text-embedding-ada-002'];
81
+ return valid.includes(model) ? model : 'text-embedding-3-small';
82
+ },
83
+ urlFor(_apiKey, _model) {
84
+ return 'https://api.openai.com/v1/embeddings';
85
+ },
86
+ async call(url, apiKey, model, input, dimensions) {
87
+ const body = { model, input };
88
+ if (dimensions)
89
+ body.dimensions = dimensions;
90
+ const resp = await fetch(url, {
91
+ method: 'POST',
92
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
93
+ body: JSON.stringify(body),
94
+ });
95
+ const data = await resp.json();
96
+ if (data.error)
97
+ throw new Error(data.error.message || JSON.stringify(data.error));
98
+ return data.data.map((item) => item.embedding);
99
+ },
100
+ };
101
+ const cohereAdapter = {
102
+ modelMap(model) {
103
+ const valid = ['embed-english-v3.0', 'embed-multilingual-v3.0', 'embed-english-v2.0'];
104
+ return valid.includes(model) ? model : 'embed-english-v3.0';
105
+ },
106
+ urlFor(_apiKey, _model) {
107
+ return 'https://api.cohere.ai/v2/embed';
108
+ },
109
+ async call(url, apiKey, model, input, _dimensions) {
110
+ const resp = await fetch(url, {
111
+ method: 'POST',
112
+ headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
113
+ body: JSON.stringify({ model, texts: input }),
114
+ });
115
+ const data = await resp.json();
116
+ if (data.error)
117
+ throw new Error(data.error.message || JSON.stringify(data.error));
118
+ return data.embeddings;
119
+ },
120
+ };
121
+ const googleAdapter = {
122
+ modelMap(model) {
123
+ return 'text-embedding-004';
124
+ },
125
+ urlFor(apiKey, _model) {
126
+ return `https://generativelanguage.googleapis.com/v1beta2/models/text-embedding-004:predict?key=${apiKey}`;
127
+ },
128
+ async call(url, _apiKey, model, input, _dimensions) {
129
+ const resp = await fetch(url, {
130
+ method: 'POST',
131
+ headers: { 'Content-Type': 'application/json' },
132
+ body: JSON.stringify({
133
+ instances: input.map((text) => ({ content: text })),
134
+ parameters: { outputDimensionality: 768 },
135
+ }),
136
+ });
137
+ const data = await resp.json();
138
+ if (data.error)
139
+ throw new Error(data.error.message || JSON.stringify(data.error));
140
+ return data.predictions.map((p) => p.embeddings.values);
141
+ },
142
+ };
143
+ const ollamaAdapter = {
144
+ modelMap(model) {
145
+ return model || 'nomic-embed-text:latest';
146
+ },
147
+ urlFor(baseUrl) {
148
+ return `${baseUrl}/api/embeddings`;
149
+ },
150
+ async call(url, _apiKey, model, input) {
151
+ const results = [];
152
+ for (const text of input) {
153
+ const resp = await fetch(url, {
154
+ method: 'POST',
155
+ headers: { 'Content-Type': 'application/json' },
156
+ body: JSON.stringify({ model, prompt: text }),
157
+ });
158
+ const data = await resp.json();
159
+ if (data.error)
160
+ throw new Error(data.error);
161
+ results.push(data.embedding);
162
+ }
163
+ return results;
164
+ },
165
+ };
166
+ // ============================================================
167
+ // HANDLER
168
+ // ============================================================
169
+ async function handleEmbeddings(req, res, ctx) {
170
+ (0, metrics_1.recordActiveRequest)(1);
171
+ const body = await readBody(req);
172
+ let request;
173
+ try {
174
+ request = JSON.parse(body);
175
+ }
176
+ catch {
177
+ (0, metrics_1.recordActiveRequest)(-1);
178
+ errorResponse(res, 400, 'Invalid JSON in request body', 'invalid_request_error');
179
+ return;
180
+ }
181
+ const inputs = Array.isArray(request.input) ? request.input : [request.input];
182
+ if (inputs.length === 0) {
183
+ (0, metrics_1.recordActiveRequest)(-1);
184
+ errorResponse(res, 400, 'input is required', 'invalid_request_error');
185
+ return;
186
+ }
187
+ const provider = getEmbeddingsProvider();
188
+ if (!provider) {
189
+ (0, metrics_1.recordActiveRequest)(-1);
190
+ errorResponse(res, 503, 'No embeddings provider available. Configure API keys for OpenAI, Cohere, or Google.', 'server_error');
191
+ return;
192
+ }
193
+ const model = request.model || provider.model;
194
+ const adapter = provider.adapter;
195
+ const providers = (0, providerConfig_1.getAvailableProviders)();
196
+ const providerConfig = providers[provider.providerId];
197
+ const resolvedModel = adapter.modelMap(model) || provider.model;
198
+ const url = adapter.urlFor(providerConfig.apiKey || '', resolvedModel);
199
+ const startTime = Date.now();
200
+ try {
201
+ const embeddings = await adapter.call(url, providerConfig.apiKey || '', resolvedModel, inputs, request.dimensions);
202
+ const latencyMs = Date.now() - startTime;
203
+ const response = {
204
+ object: 'list',
205
+ data: embeddings.map((embedding, i) => ({
206
+ object: 'embedding',
207
+ embedding,
208
+ index: i,
209
+ })),
210
+ model: resolvedModel,
211
+ usage: {
212
+ prompt_tokens: 0, // Embedding APIs don't always return token counts
213
+ total_tokens: 0,
214
+ },
215
+ };
216
+ jsonResponse(res, 200, response);
217
+ (0, metrics_1.recordRequest)({
218
+ endpoint: '/v1/embeddings',
219
+ provider: provider.providerId,
220
+ status: 'success',
221
+ durationMs: latencyMs,
222
+ model: resolvedModel,
223
+ });
224
+ }
225
+ catch (err) {
226
+ const message = err instanceof Error ? err.message : String(err);
227
+ if (!res.headersSent)
228
+ errorResponse(res, 502, message, 'upstream_error');
229
+ (0, metrics_1.recordProviderError)(provider.providerId, 'embeddings_error');
230
+ console.error(`[a3m-router] ${ctx.requestId} embeddings ERROR ${provider.providerId}: ${message}`);
231
+ }
232
+ (0, metrics_1.recordActiveRequest)(-1);
233
+ }
234
+ exports.default = handleEmbeddings;
235
+ //# sourceMappingURL=embeddingsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embeddingsHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/embeddingsHandler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A3M Router - Health Handler
3
+ *
4
+ * Handles GET /health
5
+ */
6
+ import * as http from 'http';
7
+ import { RouteContext } from '../router';
8
+ export declare function handleHealth(_req: http.IncomingMessage, res: http.ServerResponse, _ctx: RouteContext): Promise<void>;
9
+ export default handleHealth;
10
+ //# sourceMappingURL=healthHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthHandler.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/healthHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AASzC,wBAAsB,YAAY,CAChC,IAAI,EAAE,IAAI,CAAC,eAAe,EAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,IAAI,CAAC,CAkCf;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Health Handler
4
+ *
5
+ * Handles GET /health
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.handleHealth = handleHealth;
9
+ const providerConfig_1 = require("../../providers/providerConfig");
10
+ const state_1 = require("../state");
11
+ function jsonResponse(res, statusCode, body) {
12
+ res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
13
+ res.end(JSON.stringify(body));
14
+ }
15
+ async function handleHealth(_req, res, _ctx) {
16
+ const available = (0, providerConfig_1.getAvailableProviders)();
17
+ const providerStatus = {};
18
+ let healthyCount = 0;
19
+ for (const [id, provider] of Object.entries(available)) {
20
+ const hasKey = !!provider.apiKey;
21
+ const isAvailable = provider.type !== 'api' || hasKey;
22
+ providerStatus[id] = {
23
+ name: provider.name || id,
24
+ type: provider.type,
25
+ models: provider.models?.length || 0,
26
+ available: isAvailable,
27
+ };
28
+ if (isAvailable)
29
+ healthyCount++;
30
+ }
31
+ const costSummary = state_1.costTracker.getSummary();
32
+ jsonResponse(res, 200, {
33
+ status: 'ok',
34
+ version: '2.14.60',
35
+ providers: {
36
+ total: Object.keys(available).length,
37
+ healthy: healthyCount,
38
+ details: providerStatus,
39
+ },
40
+ cost: {
41
+ total: costSummary.total_cost,
42
+ requests: costSummary.request_count,
43
+ },
44
+ uptime: process.uptime(),
45
+ recentRequests: state_1.requestLogs.slice(-20),
46
+ });
47
+ }
48
+ exports.default = handleHealth;
49
+ //# sourceMappingURL=healthHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"healthHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/healthHandler.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAYH,oCAsCC;AA9CD,mEAAuE;AACvE,oCAAoD;AAEpD,SAAS,YAAY,CAAC,GAAwB,EAAE,UAAkB,EAAE,IAAY;IAC9E,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,GAAG,EAAE,CAAC,CAAC;IACtG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAEM,KAAK,UAAU,YAAY,CAChC,IAA0B,EAC1B,GAAwB,EACxB,IAAkB;IAElB,MAAM,SAAS,GAAG,IAAA,sCAAqB,GAAE,CAAC;IAC1C,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,IAAI,YAAY,GAAG,CAAC,CAAC;IAErB,KAAK,MAAM,CAAC,EAAE,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACvD,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;QACjC,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,KAAK,KAAK,IAAI,MAAM,CAAC;QACtD,cAAc,CAAC,EAAE,CAAC,GAAG;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,EAAE;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;YACpC,SAAS,EAAE,WAAW;SACvB,CAAC;QACF,IAAI,WAAW;YAAE,YAAY,EAAE,CAAC;IAClC,CAAC;IAED,MAAM,WAAW,GAAG,mBAAW,CAAC,UAAU,EAAE,CAAC;IAE7C,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE;QACrB,MAAM,EAAE,IAAI;QACZ,OAAO,EAAE,SAAS;QAClB,SAAS,EAAE;YACT,KAAK,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM;YACpC,OAAO,EAAE,YAAY;YACrB,OAAO,EAAE,cAAc;SACxB;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,WAAW,CAAC,UAAU;YAC7B,QAAQ,EAAE,WAAW,CAAC,aAAa;SACpC;QACD,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;QACxB,cAAc,EAAE,mBAAW,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC,CAAC;AACL,CAAC;AAED,kBAAe,YAAY,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * A3M Router - Prometheus Metrics Handler
3
+ *
4
+ * Handles GET /metrics
5
+ * Returns Prometheus-compatible metrics output.
6
+ */
7
+ import * as http from 'http';
8
+ import { RouteContext } from '../router';
9
+ export declare function handleMetrics(_req: http.IncomingMessage, res: http.ServerResponse, _ctx: RouteContext): void;
10
+ export default handleMetrics;
11
+ //# sourceMappingURL=metricsHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsHandler.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/metricsHandler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAYzC,wBAAgB,aAAa,CAC3B,IAAI,EAAE,IAAI,CAAC,eAAe,EAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,IAAI,EAAE,YAAY,GACjB,IAAI,CAGN;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Prometheus Metrics Handler
4
+ *
5
+ * Handles GET /metrics
6
+ * Returns Prometheus-compatible metrics output.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.handleMetrics = handleMetrics;
10
+ const metrics_1 = require("../metrics");
11
+ function textResponse(res, statusCode, body) {
12
+ res.writeHead(statusCode, {
13
+ 'Content-Type': 'text/plain; version=0.0.4; charset=utf-8',
14
+ 'Access-Control-Allow-Origin': '*',
15
+ 'Cache-Control': 'no-cache',
16
+ });
17
+ res.end(body);
18
+ }
19
+ function handleMetrics(_req, res, _ctx) {
20
+ const output = (0, metrics_1.generatePrometheusMetrics)();
21
+ textResponse(res, 200, output);
22
+ }
23
+ exports.default = handleMetrics;
24
+ //# sourceMappingURL=metricsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metricsHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/metricsHandler.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;AAeH,sCAOC;AAlBD,wCAAuD;AAEvD,SAAS,YAAY,CAAC,GAAwB,EAAE,UAAkB,EAAE,IAAY;IAC9E,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE;QACxB,cAAc,EAAE,0CAA0C;QAC1D,6BAA6B,EAAE,GAAG;QAClC,eAAe,EAAE,UAAU;KAC5B,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,SAAgB,aAAa,CAC3B,IAA0B,EAC1B,GAAwB,EACxB,IAAkB;IAElB,MAAM,MAAM,GAAG,IAAA,mCAAyB,GAAE,CAAC;IAC3C,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,kBAAe,aAAa,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A3M Router - Models Handler
3
+ *
4
+ * Handles GET /v1/models
5
+ */
6
+ import * as http from 'http';
7
+ import { RouteContext } from '../router';
8
+ export declare function handleModels(_req: http.IncomingMessage, res: http.ServerResponse, _ctx: RouteContext): void;
9
+ export default handleModels;
10
+ //# sourceMappingURL=modelsHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelsHandler.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/modelsHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAQzC,wBAAgB,YAAY,CAC1B,IAAI,EAAE,IAAI,CAAC,eAAe,EAC1B,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,IAAI,EAAE,YAAY,GACjB,IAAI,CAGN;AAED,eAAe,YAAY,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Models Handler
4
+ *
5
+ * Handles GET /v1/models
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.handleModels = handleModels;
9
+ const modelMapper_1 = require("../modelMapper");
10
+ function jsonResponse(res, statusCode, body) {
11
+ res.writeHead(statusCode, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
12
+ res.end(JSON.stringify(body));
13
+ }
14
+ function handleModels(_req, res, _ctx) {
15
+ const models = (0, modelMapper_1.listAvailableModels)();
16
+ jsonResponse(res, 200, { object: 'list', data: models });
17
+ }
18
+ exports.default = handleModels;
19
+ //# sourceMappingURL=modelsHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelsHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/modelsHandler.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;AAWH,oCAOC;AAdD,gDAAqD;AAErD,SAAS,YAAY,CAAC,GAAwB,EAAE,UAAkB,EAAE,IAAY;IAC9E,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,6BAA6B,EAAE,GAAG,EAAE,CAAC,CAAC;IACtG,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAgB,YAAY,CAC1B,IAA0B,EAC1B,GAAwB,EACxB,IAAkB;IAElB,MAAM,MAAM,GAAG,IAAA,iCAAmB,GAAE,CAAC;IACrC,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;AAC3D,CAAC;AAED,kBAAe,YAAY,CAAC"}
@@ -0,0 +1,96 @@
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
+ export interface Counter {
19
+ value: number;
20
+ labels: Record<string, string>;
21
+ }
22
+ export interface Histogram {
23
+ values: number[];
24
+ count: number;
25
+ sum: number;
26
+ buckets: {
27
+ bound: number;
28
+ count: number;
29
+ }[];
30
+ }
31
+ export interface Gauge {
32
+ value: number;
33
+ }
34
+ /**
35
+ * Increment a counter by delta (default 1).
36
+ */
37
+ export declare function incrementCounter(name: string, labels?: Record<string, string>, delta?: number): void;
38
+ /**
39
+ * Record a histogram value (duration, size, etc.).
40
+ */
41
+ export declare function recordHistogram(name: string, labels: Record<string, string>, value: number): void;
42
+ /**
43
+ * Set a gauge value.
44
+ */
45
+ export declare function setGauge(name: string, labels: Record<string, string>, value: number): void;
46
+ /**
47
+ * Increment active requests gauge (call on start, decrement on end).
48
+ */
49
+ export declare function recordActiveRequest(delta: 1 | -1): void;
50
+ /**
51
+ * Get current active request count.
52
+ */
53
+ export declare function getActiveRequests(): number;
54
+ /**
55
+ * Generate Prometheus /metrics output.
56
+ */
57
+ export declare function generatePrometheusMetrics(): string;
58
+ /**
59
+ * Record a completed request with all metrics.
60
+ */
61
+ export declare function recordRequest(params: {
62
+ endpoint: string;
63
+ provider: string;
64
+ status: 'success' | 'error';
65
+ durationMs: number;
66
+ tokensIn?: number;
67
+ tokensOut?: number;
68
+ cost?: number;
69
+ model?: string;
70
+ }): void;
71
+ /**
72
+ * Record a provider error.
73
+ */
74
+ export declare function recordProviderError(provider: string, errorType: string): void;
75
+ /**
76
+ * Record a cache hit.
77
+ */
78
+ export declare function recordCacheHit(cacheType: 'semantic' | 'exact' | 'none'): void;
79
+ /**
80
+ * Record a fallback trigger.
81
+ */
82
+ export declare function recordFallback(provider: string): void;
83
+ declare const _default: {
84
+ incrementCounter: typeof incrementCounter;
85
+ recordHistogram: typeof recordHistogram;
86
+ setGauge: typeof setGauge;
87
+ recordActiveRequest: typeof recordActiveRequest;
88
+ getActiveRequests: typeof getActiveRequests;
89
+ generatePrometheusMetrics: typeof generatePrometheusMetrics;
90
+ recordRequest: typeof recordRequest;
91
+ recordProviderError: typeof recordProviderError;
92
+ recordCacheHit: typeof recordCacheHit;
93
+ recordFallback: typeof recordFallback;
94
+ };
95
+ export default _default;
96
+ //# sourceMappingURL=metrics.d.ts.map