adaptive-memory-multi-model-router 2.14.60 → 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 (146) 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/README.md +222 -1039
  5. package/assets/chart-accuracy-by-tier.svg +63 -0
  6. package/assets/chart-confusion-matrix.svg +98 -0
  7. package/assets/chart-cost-comparison.svg +66 -0
  8. package/assets/chart-latency-overhead.svg +102 -0
  9. package/assets/chart-routerena-leaderboard.svg +76 -0
  10. package/dist/analytics/costAnalytics.d.ts +1 -0
  11. package/dist/benchmark/comprehensive.d.ts +4 -53
  12. package/dist/benchmark/comprehensive.d.ts.map +1 -0
  13. package/dist/benchmark/comprehensive.js +112 -214
  14. package/dist/benchmark/comprehensive.js.map +1 -1
  15. package/dist/benchmark/reproducible.d.ts +1 -0
  16. package/dist/cache/semanticCache.d.ts +1 -0
  17. package/dist/cli/setupWizard.d.ts +6 -1
  18. package/dist/cli/setupWizard.d.ts.map +1 -1
  19. package/dist/cli/setupWizard.js +6 -9
  20. package/dist/cli/setupWizard.js.map +1 -1
  21. package/dist/cli.js +15 -14
  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/hf-space/app.py +3 -3
  124. package/llms-full.txt +156 -184
  125. package/llms.txt +77 -42
  126. package/mcp-server/package.json +6 -0
  127. package/mcp-server/tsconfig.json +3 -2
  128. package/package.json +2 -2
  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/NEW_OPPORTUNITIES.md +0 -163
  141. package/NEW_SUBMISSIONS.md +0 -80
  142. package/PRIORITY_REDDIT_TARGETS.md +0 -53
  143. package/VISIBILITY_PLAN.md +0 -146
  144. package/articles/TWITTER_THREAD_IMPLICATIONS.md +0 -182
  145. package/articles/TWITTER_THREAD_VAULT.md +0 -164
  146. package/index.html +0 -667
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Chat Completions Handler
4
+ *
5
+ * Handles POST /v1/chat/completions
6
+ * Plug-and-play: register with router.registerRoute('POST', /^\/v1\/chat\/completions$/, handleChatCompletions);
7
+ */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || (function () {
25
+ var ownKeys = function(o) {
26
+ ownKeys = Object.getOwnPropertyNames || function (o) {
27
+ var ar = [];
28
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
29
+ return ar;
30
+ };
31
+ return ownKeys(o);
32
+ };
33
+ return function (mod) {
34
+ if (mod && mod.__esModule) return mod;
35
+ var result = {};
36
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
37
+ __setModuleDefault(result, mod);
38
+ return result;
39
+ };
40
+ })();
41
+ Object.defineProperty(exports, "__esModule", { value: true });
42
+ exports.handleChatCompletions = handleChatCompletions;
43
+ const modelMapper_1 = require("../modelMapper");
44
+ const state_1 = require("../state");
45
+ const metrics_1 = require("../metrics");
46
+ // ============================================================
47
+ // HELPERS
48
+ // ============================================================
49
+ function readBody(req) {
50
+ return new Promise((resolve, reject) => {
51
+ const chunks = [];
52
+ req.on('data', (chunk) => chunks.push(chunk));
53
+ req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));
54
+ req.on('error', reject);
55
+ });
56
+ }
57
+ function jsonResponse(res, statusCode, body) {
58
+ res.writeHead(statusCode, {
59
+ 'Content-Type': 'application/json',
60
+ 'Access-Control-Allow-Origin': '*',
61
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
62
+ 'Access-Control-Allow-Headers': 'Content-Type, Authorization',
63
+ });
64
+ res.end(JSON.stringify(body));
65
+ }
66
+ function errorResponse(res, statusCode, message, errorType = 'server_error') {
67
+ jsonResponse(res, statusCode, { error: { message, type: errorType, code: statusCode } });
68
+ }
69
+ // ============================================================
70
+ // HANDLER
71
+ // ============================================================
72
+ async function handleChatCompletions(req, res, ctx) {
73
+ (0, metrics_1.recordActiveRequest)(1);
74
+ const body = await readBody(req);
75
+ let request;
76
+ try {
77
+ request = JSON.parse(body);
78
+ }
79
+ catch {
80
+ (0, metrics_1.recordActiveRequest)(-1);
81
+ errorResponse(res, 400, 'Invalid JSON in request body', 'invalid_request_error');
82
+ return;
83
+ }
84
+ if (!request.messages || !Array.isArray(request.messages) || request.messages.length === 0) {
85
+ (0, metrics_1.recordActiveRequest)(-1);
86
+ errorResponse(res, 400, 'messages is required and must be a non-empty array', 'invalid_request_error');
87
+ return;
88
+ }
89
+ const model = request.model || 'auto';
90
+ const stream = request.stream || false;
91
+ const requestId = ctx.requestId;
92
+ const promptForRouting = request.messages.map((m) => m.content).join(' ');
93
+ const mapping = (0, modelMapper_1.resolveModel)(model, promptForRouting);
94
+ if (!mapping) {
95
+ (0, metrics_1.recordActiveRequest)(-1);
96
+ errorResponse(res, 503, `No provider available for model "${model}". Configure API keys.`, 'server_error');
97
+ return;
98
+ }
99
+ const startTime = Date.now();
100
+ if (stream) {
101
+ try {
102
+ const { streamProviderResponse } = await Promise.resolve().then(() => __importStar(require('../proxyServer')));
103
+ await streamProviderResponse(res, mapping, request.messages, { temperature: request.temperature, max_tokens: request.max_tokens, stop: request.stop }, requestId);
104
+ const latencyMs = Date.now() - startTime;
105
+ (0, metrics_1.recordRequest)({ endpoint: '/v1/chat/completions', provider: mapping.providerId, status: 'success', durationMs: latencyMs, model });
106
+ (0, metrics_1.recordActiveRequest)(-1);
107
+ }
108
+ catch (err) {
109
+ const message = err instanceof Error ? err.message : String(err);
110
+ if (!res.headersSent)
111
+ errorResponse(res, 500, message);
112
+ (0, metrics_1.recordProviderError)(mapping.providerId, 'stream_error');
113
+ (0, metrics_1.recordActiveRequest)(-1);
114
+ }
115
+ return;
116
+ }
117
+ // Non-streaming path
118
+ try {
119
+ const { callWithFallback } = await Promise.resolve().then(() => __importStar(require('../proxyServer')));
120
+ const { result, mapping: usedMapping } = await callWithFallback(model, request.messages, { temperature: request.temperature, max_tokens: request.max_tokens, stop: request.stop }, promptForRouting);
121
+ const latencyMs = Date.now() - startTime;
122
+ const inputCost = (result.usage.prompt_tokens / 1000) * usedMapping.costPerK.input;
123
+ const outputCost = (result.usage.completion_tokens / 1000) * usedMapping.costPerK.output;
124
+ const totalCost = inputCost + outputCost;
125
+ state_1.costTracker.record(usedMapping.providerId, usedMapping.model, result.usage.prompt_tokens, result.usage.completion_tokens);
126
+ const response = {
127
+ id: requestId,
128
+ object: 'chat.completion',
129
+ created: Math.floor(Date.now() / 1000),
130
+ model: result.model,
131
+ choices: [{ index: 0, message: { role: 'assistant', content: result.content }, finish_reason: result.finish_reason }],
132
+ usage: result.usage,
133
+ };
134
+ jsonResponse(res, 200, response);
135
+ (0, metrics_1.recordRequest)({
136
+ endpoint: '/v1/chat/completions',
137
+ provider: usedMapping.providerId,
138
+ status: 'success',
139
+ durationMs: latencyMs,
140
+ tokensIn: result.usage.prompt_tokens,
141
+ tokensOut: result.usage.completion_tokens,
142
+ cost: totalCost,
143
+ model,
144
+ });
145
+ console.log(`[a3m-router] ${requestId} chat model=${model}→${usedMapping.providerId}/${usedMapping.model} latency=${latencyMs}ms tokens=${result.usage.total_tokens} cost=$${totalCost.toFixed(6)}`);
146
+ }
147
+ catch (err) {
148
+ const message = err instanceof Error ? err.message : String(err);
149
+ const latencyMs = Date.now() - startTime;
150
+ (0, metrics_1.recordRequest)({ endpoint: '/v1/chat/completions', provider: mapping.providerId, status: 'error', durationMs: latencyMs, model });
151
+ (0, metrics_1.recordProviderError)(mapping.providerId, message.slice(0, 50));
152
+ console.error(`[a3m-router] ${requestId} ERROR model=${model}→${mapping.providerId}/${mapping.model} latency=${latencyMs}ms error=${message}`);
153
+ if (!res.headersSent)
154
+ errorResponse(res, 502, message, 'upstream_error');
155
+ }
156
+ (0, metrics_1.recordActiveRequest)(-1);
157
+ }
158
+ exports.default = handleChatCompletions;
159
+ //# sourceMappingURL=chatHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatHandler.js","sourceRoot":"","sources":["../../../src/server/handlers/chatHandler.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6DH,sDAwGC;AAjKD,gDAA8C;AAC9C,oCAAuC;AACvC,wCAAqF;AAwBrF,+DAA+D;AAC/D,UAAU;AACV,+DAA+D;AAE/D,SAAS,QAAQ,CAAC,GAAyB;IACzC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACtD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACtE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAS,YAAY,CAAC,GAAwB,EAAE,UAAkB,EAAE,IAAY;IAC9E,GAAG,CAAC,SAAS,CAAC,UAAU,EAAE;QACxB,cAAc,EAAE,kBAAkB;QAClC,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,6BAA6B;KAC9D,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,GAAwB,EAAE,UAAkB,EAAE,OAAe,EAAE,SAAS,GAAG,cAAc;IAC9G,YAAY,CAAC,GAAG,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,+DAA+D;AAC/D,UAAU;AACV,+DAA+D;AAExD,KAAK,UAAU,qBAAqB,CACzC,GAAyB,EACzB,GAAwB,EACxB,GAAiB;IAEjB,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC;IAEvB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,GAAG,CAAC,CAAC;IACjC,IAAI,OAAoB,CAAC;IAEzB,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;QACxB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,8BAA8B,EAAE,uBAAuB,CAAC,CAAC;QACjF,OAAO;IACT,CAAC;IAED,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC3F,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;QACxB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,oDAAoD,EAAE,uBAAuB,CAAC,CAAC;QACvG,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;IAChC,MAAM,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE1E,MAAM,OAAO,GAAG,IAAA,0BAAY,EAAC,KAAK,EAAE,gBAAgB,CAAC,CAAC;IACtD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;QACxB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,oCAAoC,KAAK,wBAAwB,EAAE,cAAc,CAAC,CAAC;QAC3G,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAE7B,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,EAAE,sBAAsB,EAAE,GAAG,wDAAa,gBAAgB,GAAC,CAAC;YAClE,MAAM,sBAAsB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,EACzD,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EACxF,SAAS,CAAC,CAAC;YACb,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;YACzC,IAAA,uBAAa,EAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACnI,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,GAAG,CAAC,WAAW;gBAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;YACvD,IAAA,6BAAmB,EAAC,OAAO,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;YACxD,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;QAC1B,CAAC;QACD,OAAO;IACT,CAAC;IAED,qBAAqB;IACrB,IAAI,CAAC;QACH,MAAM,EAAE,gBAAgB,EAAE,GAAG,wDAAa,gBAAgB,GAAC,CAAC;QAC5D,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,MAAM,gBAAgB,CAC7D,KAAK,EAAE,OAAO,CAAC,QAAQ,EACvB,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,EACxF,gBAAgB,CACjB,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACzC,MAAM,SAAS,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC;QACnF,MAAM,UAAU,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC;QACzF,MAAM,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;QAEzC,mBAAW,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,EAAE,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAE1H,MAAM,QAAQ,GAAG;YACf,EAAE,EAAE,SAAS;YACb,MAAM,EAAE,iBAAiB;YACzB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;YACtC,KAAK,EAAE,MAAM,CAAC,KAAK;YACnB,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE,OAAO,EAAE,MAAM,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,MAAM,CAAC,aAAa,EAAE,CAAC;YAC9H,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;QAEF,YAAY,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QACjC,IAAA,uBAAa,EAAC;YACZ,QAAQ,EAAE,sBAAsB;YAChC,QAAQ,EAAE,WAAW,CAAC,UAAU;YAChC,MAAM,EAAE,SAAS;YACjB,UAAU,EAAE,SAAS;YACrB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa;YACpC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,iBAAiB;YACzC,IAAI,EAAE,SAAS;YACf,KAAK;SACN,CAAC,CAAC;QAEH,OAAO,CAAC,GAAG,CAAC,gBAAgB,SAAS,eAAe,KAAK,IAAI,WAAW,CAAC,UAAU,IAAI,WAAW,CAAC,KAAK,YAAY,SAAS,aAAa,MAAM,CAAC,KAAK,CAAC,YAAY,UAAU,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACvM,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACzC,IAAA,uBAAa,EAAC,EAAE,QAAQ,EAAE,sBAAsB,EAAE,QAAQ,EAAE,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;QACjI,IAAA,6BAAmB,EAAC,OAAO,CAAC,UAAU,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;QAC9D,OAAO,CAAC,KAAK,CAAC,gBAAgB,SAAS,gBAAgB,KAAK,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,KAAK,YAAY,SAAS,YAAY,OAAO,EAAE,CAAC,CAAC;QAC/I,IAAI,CAAC,GAAG,CAAC,WAAW;YAAE,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC;IAC3E,CAAC;IAED,IAAA,6BAAmB,EAAC,CAAC,CAAC,CAAC,CAAC;AAC1B,CAAC;AAED,kBAAe,qBAAqB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * A3M Router - Completions Handler
3
+ *
4
+ * Handles POST /v1/completions
5
+ */
6
+ import * as http from 'http';
7
+ import { RouteContext } from '../router';
8
+ export declare function handleCompletions(req: http.IncomingMessage, res: http.ServerResponse, ctx: RouteContext): Promise<void>;
9
+ export default handleCompletions;
10
+ //# sourceMappingURL=completionsHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"completionsHandler.d.ts","sourceRoot":"","sources":["../../../src/server/handlers/completionsHandler.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAiCzC,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,EACxB,GAAG,EAAE,YAAY,GAChB,OAAO,CAAC,IAAI,CAAC,CAyEf;AAED,eAAe,iBAAiB,CAAC"}
@@ -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