adaptive-memory-multi-model-router 1.9.5 → 2.0.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 (121) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
  2. package/.github/ISSUE_TEMPLATE/config.yml +11 -0
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +37 -0
  4. package/.github/PULL_REQUEST_TEMPLATE.md +44 -0
  5. package/.github/workflows/npm-stats-validation.yml +152 -0
  6. package/.github/workflows/pages.yml +37 -0
  7. package/CHANGELOG.md +122 -0
  8. package/CODE_OF_CONDUCT.md +128 -0
  9. package/CONTRIBUTING.md +110 -0
  10. package/LAUNCH-PAIN-DRIVEN.md +339 -0
  11. package/LAUNCH.md +575 -0
  12. package/POPULARITY_BOOSTERS.md +285 -0
  13. package/README.md +231 -300
  14. package/SECURITY.md +69 -0
  15. package/articles/CONTENT_STRUCTURE.md +292 -0
  16. package/articles/DEVTO_COST_GUIDE.md +473 -0
  17. package/articles/DEVTO_FINAL.md +416 -0
  18. package/articles/DEVTO_MULTI_PROVIDER.md +542 -0
  19. package/articles/HN_10X_BETTER.md +430 -0
  20. package/articles/HN_CHINESE_STYLE.md +308 -0
  21. package/articles/HN_FINAL.md +199 -0
  22. package/articles/HN_POSTED_VERSION.md +56 -0
  23. package/articles/HN_RESEARCH.md +364 -0
  24. package/articles/PAIN-DRIVEN-devto-v2.md +308 -0
  25. package/articles/PAIN-DRIVEN-devto-v3.md +268 -0
  26. package/articles/PAIN-DRIVEN-devto.md +242 -0
  27. package/articles/PAIN-DRIVEN-hackernews-v2.md +138 -0
  28. package/articles/PAIN-DRIVEN-hackernews-v3.md +151 -0
  29. package/articles/PAIN-DRIVEN-hackernews.md +131 -0
  30. package/articles/PAIN-DRIVEN-reddit-v2.md +301 -0
  31. package/articles/PAIN-DRIVEN-reddit-v3.md +236 -0
  32. package/articles/PAIN-DRIVEN-reddit.md +218 -0
  33. package/articles/PAIN-DRIVEN-twitter-v2.md +110 -0
  34. package/articles/PAIN-DRIVEN-twitter-v3.md +121 -0
  35. package/articles/PAIN-DRIVEN-twitter.md +120 -0
  36. package/articles/PORTKEY_VS_A3M.md +147 -0
  37. package/articles/REDDIT_FINAL.md +232 -0
  38. package/articles/TWITTER_FINAL.md +167 -0
  39. package/articles/WHY_10X_BETTER.md +261 -0
  40. package/articles/WHY_CHINESE_STYLE_BETTER.md +323 -0
  41. package/articles/hashnode-llm-cost-optimization.md +125 -0
  42. package/articles/medium-building-llm-router.md +205 -0
  43. package/articles/twitter-thread-cost-savings.md +98 -0
  44. package/articles/youtube-tutorial-script.md +262 -0
  45. package/assets/banner.svg +109 -0
  46. package/assets/logo.svg +68 -0
  47. package/assets/social-preview.svg +64 -0
  48. package/demo/demo-script.md +53 -0
  49. package/dist/analytics/costAnalytics.d.ts +77 -0
  50. package/dist/analytics/costAnalytics.d.ts.map +1 -0
  51. package/dist/analytics/costAnalytics.js +219 -0
  52. package/dist/analytics/costAnalytics.js.map +1 -0
  53. package/dist/cache/semanticCache.d.ts +62 -0
  54. package/dist/cache/semanticCache.d.ts.map +1 -0
  55. package/dist/cache/semanticCache.js +176 -0
  56. package/dist/cache/semanticCache.js.map +1 -0
  57. package/dist/cli.js +35 -0
  58. package/dist/index.d.ts +4 -723
  59. package/dist/index.js +11 -362
  60. package/dist/index.js.map +1 -1
  61. package/dist/integrations/langchainAdapter.d.ts +146 -0
  62. package/dist/integrations/langchainAdapter.d.ts.map +1 -0
  63. package/dist/integrations/langchainAdapter.js +731 -0
  64. package/dist/integrations/langchainAdapter.js.map +1 -0
  65. package/dist/integrations/oauth.d.ts +69 -0
  66. package/dist/integrations/oauth.d.ts.map +1 -0
  67. package/dist/integrations/oauth.js +225 -21
  68. package/dist/integrations/oauth.js.map +1 -0
  69. package/dist/memory/autoFetch.d.ts +39 -0
  70. package/dist/memory/autoFetch.d.ts.map +1 -0
  71. package/dist/memory/autoFetch.js +80 -88
  72. package/dist/memory/autoFetch.js.map +1 -0
  73. package/dist/memory/memoryTree.d.ts +76 -0
  74. package/dist/memory/memoryTree.d.ts.map +1 -0
  75. package/dist/memory/memoryTree.js +185 -130
  76. package/dist/memory/memoryTree.js.map +1 -0
  77. package/dist/memory/obsidianVault.d.ts +71 -0
  78. package/dist/memory/obsidianVault.d.ts.map +1 -0
  79. package/dist/memory/obsidianVault.js +207 -22
  80. package/dist/memory/obsidianVault.js.map +1 -0
  81. package/dist/providers/providerConfig.d.ts +49 -0
  82. package/dist/providers/providerConfig.d.ts.map +1 -0
  83. package/dist/providers/providerConfig.js +806 -401
  84. package/dist/providers/providerConfig.js.map +1 -0
  85. package/dist/security/guardrails.d.ts +76 -0
  86. package/dist/security/guardrails.d.ts.map +1 -0
  87. package/dist/security/guardrails.js +479 -0
  88. package/dist/security/guardrails.js.map +1 -0
  89. package/dist/server/dashboard.d.ts +58 -0
  90. package/dist/server/dashboard.d.ts.map +1 -0
  91. package/dist/server/dashboard.js +553 -0
  92. package/dist/server/dashboard.js.map +1 -0
  93. package/dist/server/modelMapper.d.ts +43 -0
  94. package/dist/server/modelMapper.d.ts.map +1 -0
  95. package/dist/server/modelMapper.js +154 -0
  96. package/dist/server/modelMapper.js.map +1 -0
  97. package/dist/server/proxyServer.d.ts +41 -0
  98. package/dist/server/proxyServer.d.ts.map +1 -0
  99. package/dist/server/proxyServer.js +932 -0
  100. package/dist/server/proxyServer.js.map +1 -0
  101. package/dist/skills/__tests__/skill_manager.test.d.ts +2 -0
  102. package/dist/skills/__tests__/skill_manager.test.d.ts.map +1 -0
  103. package/dist/skills/__tests__/skill_manager.test.js +268 -0
  104. package/dist/skills/__tests__/skill_manager.test.js.map +1 -0
  105. package/docs-site/index.html +347 -0
  106. package/package.json +53 -7
  107. package/playground/README.md +51 -0
  108. package/playground/codesandbox.json +12 -0
  109. package/playground/index.js +39 -0
  110. package/scripts/update-npm-badges.js +158 -0
  111. package/src/analytics/costAnalytics.ts +304 -0
  112. package/src/cache/semanticCache.ts +221 -0
  113. package/src/index.ts +6 -0
  114. package/src/integrations/langchainAdapter.ts +955 -0
  115. package/src/providers/providerConfig.ts +923 -0
  116. package/src/security/guardrails.ts +585 -0
  117. package/src/server/dashboard.ts +610 -0
  118. package/src/server/modelMapper.ts +182 -0
  119. package/src/server/proxyServer.ts +1105 -0
  120. package/src/types/langchain.d.ts +83 -0
  121. package/tsconfig.build.json +20 -0
@@ -0,0 +1,58 @@
1
+ /**
2
+ * A3M Router - Dashboard UI + API Endpoints
3
+ *
4
+ * Single HTML dashboard served at GET / when the proxy server runs.
5
+ * Dark theme, hacker/terminal aesthetic, auto-refreshes every 5s.
6
+ * API endpoints: /api/stats, /api/providers, /api/requests, /api/clear
7
+ *
8
+ * No React, no build step — vanilla HTML/CSS/JS served inline.
9
+ */
10
+ import * as http from "http";
11
+ export interface DashboardRequest {
12
+ timestamp: number;
13
+ query: string;
14
+ provider: string;
15
+ model: string;
16
+ latency: number;
17
+ cost: number;
18
+ status: "success" | "error";
19
+ error?: string;
20
+ tokens?: {
21
+ input: number;
22
+ output: number;
23
+ };
24
+ }
25
+ export interface DashboardProvider {
26
+ id: string;
27
+ name: string;
28
+ status: "online" | "offline";
29
+ requestsToday: number;
30
+ costToday: number;
31
+ avgLatency: number;
32
+ lastError: string | null;
33
+ lastErrorTime: number | null;
34
+ }
35
+ export interface DashboardStats {
36
+ totalRequestsToday: number;
37
+ totalCostToday: number;
38
+ avgLatency: number;
39
+ activeProviders: number;
40
+ totalProviders: number;
41
+ providers: DashboardProvider[];
42
+ recentRequests: DashboardRequest[];
43
+ costByProvider: Record<string, number>;
44
+ uptime: number;
45
+ }
46
+ /**
47
+ * Record a request for the dashboard.
48
+ */
49
+ export declare function recordRequest(req: Omit<DashboardRequest, "timestamp">): void;
50
+ /**
51
+ * Register a provider as available (called on startup / health check).
52
+ */
53
+ export declare function registerProvider(id: string, name: string): void;
54
+ /**
55
+ * Handle dashboard API requests. Returns true if the request was handled.
56
+ */
57
+ export declare function handleDashboardRequest(req: http.IncomingMessage, res: http.ServerResponse): boolean;
58
+ export declare function getDashboardHTML(): string;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../../src/server/dashboard.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAM7B,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC7B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,iBAAiB,EAAE,CAAC;IAC/B,cAAc,EAAE,gBAAgB,EAAE,CAAC;IACnC,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC;CAChB;AAWD;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,WAAW,CAAC,GAAG,IAAI,CAoC5E;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAa/D;AA4CD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,OAAO,CA0DT;AAMD,wBAAgB,gBAAgB,IAAI,MAAM,CA0XzC"}
@@ -0,0 +1,553 @@
1
+ "use strict";
2
+ /**
3
+ * A3M Router - Dashboard UI + API Endpoints
4
+ *
5
+ * Single HTML dashboard served at GET / when the proxy server runs.
6
+ * Dark theme, hacker/terminal aesthetic, auto-refreshes every 5s.
7
+ * API endpoints: /api/stats, /api/providers, /api/requests, /api/clear
8
+ *
9
+ * No React, no build step — vanilla HTML/CSS/JS served inline.
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.recordRequest = recordRequest;
13
+ exports.registerProvider = registerProvider;
14
+ exports.handleDashboardRequest = handleDashboardRequest;
15
+ exports.getDashboardHTML = getDashboardHTML;
16
+ // ============================================================
17
+ // Dashboard State (in-memory)
18
+ // ============================================================
19
+ const MAX_REQUESTS = 50;
20
+ const recentRequests = [];
21
+ const providerStats = new Map();
22
+ const startTime = Date.now();
23
+ /**
24
+ * Record a request for the dashboard.
25
+ */
26
+ function recordRequest(req) {
27
+ const entry = { ...req, timestamp: Date.now() };
28
+ recentRequests.unshift(entry);
29
+ if (recentRequests.length > MAX_REQUESTS)
30
+ recentRequests.pop();
31
+ // Update provider stats
32
+ const existing = providerStats.get(req.provider);
33
+ const today = startOfToday();
34
+ const isToday = true; // We track rolling
35
+ if (existing) {
36
+ existing.requestsToday++;
37
+ existing.costToday += req.cost;
38
+ // Running average latency
39
+ existing.avgLatency =
40
+ (existing.avgLatency * (existing.requestsToday - 1) + req.latency) /
41
+ existing.requestsToday;
42
+ if (req.status === "error") {
43
+ existing.lastError = req.error || "Unknown error";
44
+ existing.lastErrorTime = entry.timestamp;
45
+ existing.status = "offline";
46
+ }
47
+ else {
48
+ existing.status = "online";
49
+ }
50
+ }
51
+ else {
52
+ providerStats.set(req.provider, {
53
+ id: req.provider,
54
+ name: req.provider,
55
+ status: req.status === "success" ? "online" : "offline",
56
+ requestsToday: 1,
57
+ costToday: req.cost,
58
+ avgLatency: req.latency,
59
+ lastError: req.status === "error" ? req.error || "Unknown error" : null,
60
+ lastErrorTime: req.status === "error" ? entry.timestamp : null,
61
+ });
62
+ }
63
+ }
64
+ /**
65
+ * Register a provider as available (called on startup / health check).
66
+ */
67
+ function registerProvider(id, name) {
68
+ if (!providerStats.has(id)) {
69
+ providerStats.set(id, {
70
+ id,
71
+ name,
72
+ status: "online",
73
+ requestsToday: 0,
74
+ costToday: 0,
75
+ avgLatency: 0,
76
+ lastError: null,
77
+ lastErrorTime: null,
78
+ });
79
+ }
80
+ }
81
+ /**
82
+ * Build the full stats snapshot.
83
+ */
84
+ function buildStats() {
85
+ const providers = Array.from(providerStats.values());
86
+ const active = providers.filter((p) => p.status === "online").length;
87
+ const totalCost = providers.reduce((s, p) => s + p.costToday, 0);
88
+ const totalReqs = providers.reduce((s, p) => s + p.requestsToday, 0);
89
+ const latReqs = providers.filter((p) => p.avgLatency > 0);
90
+ const avgLat = latReqs.length > 0
91
+ ? latReqs.reduce((s, p) => s + p.avgLatency, 0) / latReqs.length
92
+ : 0;
93
+ const costByProvider = {};
94
+ for (const p of providers) {
95
+ costByProvider[p.id] = p.costToday;
96
+ }
97
+ return {
98
+ totalRequestsToday: totalReqs,
99
+ totalCostToday: totalCost,
100
+ avgLatency: avgLat,
101
+ activeProviders: active,
102
+ totalProviders: providers.length,
103
+ providers,
104
+ recentRequests,
105
+ costByProvider,
106
+ uptime: Date.now() - startTime,
107
+ };
108
+ }
109
+ function startOfToday() {
110
+ const d = new Date();
111
+ d.setHours(0, 0, 0, 0);
112
+ return d.getTime();
113
+ }
114
+ // ============================================================
115
+ // API Route Handler
116
+ // ============================================================
117
+ /**
118
+ * Handle dashboard API requests. Returns true if the request was handled.
119
+ */
120
+ function handleDashboardRequest(req, res) {
121
+ const url = req.url || "/";
122
+ // CORS headers
123
+ res.setHeader("Access-Control-Allow-Origin", "*");
124
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
125
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
126
+ if (req.method === "OPTIONS") {
127
+ res.writeHead(204);
128
+ res.end();
129
+ return true;
130
+ }
131
+ // GET / → Dashboard HTML
132
+ if (url === "/" && req.method === "GET") {
133
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
134
+ res.end(getDashboardHTML());
135
+ return true;
136
+ }
137
+ // GET /api/stats
138
+ if (url === "/api/stats" && req.method === "GET") {
139
+ res.writeHead(200, { "Content-Type": "application/json" });
140
+ res.end(JSON.stringify(buildStats()));
141
+ return true;
142
+ }
143
+ // GET /api/providers
144
+ if (url === "/api/providers" && req.method === "GET") {
145
+ res.writeHead(200, { "Content-Type": "application/json" });
146
+ res.end(JSON.stringify(Array.from(providerStats.values())));
147
+ return true;
148
+ }
149
+ // GET /api/requests
150
+ if (url === "/api/requests" && req.method === "GET") {
151
+ res.writeHead(200, { "Content-Type": "application/json" });
152
+ res.end(JSON.stringify(recentRequests));
153
+ return true;
154
+ }
155
+ // POST /api/clear
156
+ if (url === "/api/clear" && req.method === "POST") {
157
+ recentRequests.length = 0;
158
+ for (const p of providerStats.values()) {
159
+ p.requestsToday = 0;
160
+ p.costToday = 0;
161
+ p.avgLatency = 0;
162
+ p.lastError = null;
163
+ p.lastErrorTime = null;
164
+ }
165
+ res.writeHead(200, { "Content-Type": "application/json" });
166
+ res.end(JSON.stringify({ ok: true, message: "Dashboard cleared" }));
167
+ return true;
168
+ }
169
+ return false; // Not a dashboard route
170
+ }
171
+ // ============================================================
172
+ // Dashboard HTML
173
+ // ============================================================
174
+ function getDashboardHTML() {
175
+ return `<!DOCTYPE html>
176
+ <html lang="en">
177
+ <head>
178
+ <meta charset="UTF-8">
179
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
180
+ <title>A3M Router Dashboard</title>
181
+ <style>
182
+ * { margin:0; padding:0; box-sizing:border-box; }
183
+ :root {
184
+ --bg: #0a0a0f;
185
+ --surface: #111118;
186
+ --surface2: #1a1a24;
187
+ --border: #2a2a3a;
188
+ --text: #c8c8d8;
189
+ --text-dim: #6a6a80;
190
+ --green: #00ff88;
191
+ --green-dim: #00aa5a;
192
+ --red: #ff4444;
193
+ --yellow: #ffcc00;
194
+ --cyan: #00ccff;
195
+ --magenta: #ff44ff;
196
+ --orange: #ff8800;
197
+ --mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', 'Consolas', monospace;
198
+ }
199
+ body {
200
+ background: var(--bg);
201
+ color: var(--text);
202
+ font-family: var(--mono);
203
+ font-size: 13px;
204
+ line-height: 1.5;
205
+ padding: 20px;
206
+ min-height: 100vh;
207
+ }
208
+ a { color: var(--cyan); text-decoration: none; }
209
+
210
+ /* Header */
211
+ .header {
212
+ border-bottom: 1px solid var(--green-dim);
213
+ padding-bottom: 12px;
214
+ margin-bottom: 24px;
215
+ display: flex;
216
+ justify-content: space-between;
217
+ align-items: center;
218
+ }
219
+ .header h1 {
220
+ color: var(--green);
221
+ font-size: 18px;
222
+ font-weight: 600;
223
+ letter-spacing: 2px;
224
+ }
225
+ .header .uptime { color: var(--text-dim); font-size: 11px; }
226
+
227
+ /* Overview cards */
228
+ .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 28px; }
229
+ .card {
230
+ background: var(--surface);
231
+ border: 1px solid var(--border);
232
+ border-radius: 6px;
233
+ padding: 16px;
234
+ position: relative;
235
+ overflow: hidden;
236
+ }
237
+ .card::before {
238
+ content: '';
239
+ position: absolute;
240
+ top: 0; left: 0; right: 0;
241
+ height: 2px;
242
+ background: var(--green);
243
+ opacity: 0.6;
244
+ }
245
+ .card.error::before { background: var(--red); }
246
+ .card .label { color: var(--text-dim); font-size: 10px; text-transform: uppercase; letter-spacing: 1px; margin-bottom: 6px; }
247
+ .card .value { font-size: 22px; font-weight: 700; color: var(--green); }
248
+ .card .value.cost { color: var(--yellow); }
249
+ .card .value.latency { color: var(--cyan); }
250
+ .card .value.providers { color: var(--magenta); }
251
+
252
+ /* Section */
253
+ .section { margin-bottom: 28px; }
254
+ .section-title {
255
+ color: var(--green);
256
+ font-size: 13px;
257
+ font-weight: 600;
258
+ text-transform: uppercase;
259
+ letter-spacing: 1.5px;
260
+ margin-bottom: 12px;
261
+ padding-left: 10px;
262
+ border-left: 3px solid var(--green);
263
+ }
264
+
265
+ /* Provider table */
266
+ table { width: 100%; border-collapse: collapse; }
267
+ th {
268
+ text-align: left;
269
+ color: var(--text-dim);
270
+ font-size: 10px;
271
+ text-transform: uppercase;
272
+ letter-spacing: 1px;
273
+ padding: 8px 12px;
274
+ border-bottom: 1px solid var(--border);
275
+ }
276
+ td {
277
+ padding: 8px 12px;
278
+ border-bottom: 1px solid var(--border);
279
+ font-size: 12px;
280
+ }
281
+ tr:hover { background: var(--surface2); }
282
+ .status-dot { font-size: 14px; }
283
+ .error-text { color: var(--red); font-size: 11px; max-width: 200px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
284
+
285
+ /* Cost chart */
286
+ .chart-row { display: flex; align-items: center; margin-bottom: 8px; gap: 12px; }
287
+ .chart-label { width: 100px; text-align: right; color: var(--text-dim); font-size: 11px; flex-shrink:0; }
288
+ .chart-bar-wrap { flex: 1; background: var(--surface); border-radius: 3px; height: 20px; position: relative; }
289
+ .chart-bar {
290
+ height: 100%;
291
+ border-radius: 3px;
292
+ min-width: 2px;
293
+ transition: width 0.5s ease;
294
+ position: relative;
295
+ }
296
+ .chart-bar .chart-val {
297
+ position: absolute;
298
+ right: 6px;
299
+ top: 50%;
300
+ transform: translateY(-50%);
301
+ font-size: 10px;
302
+ color: var(--bg);
303
+ font-weight: 600;
304
+ }
305
+
306
+ /* Request log */
307
+ .log-wrap { max-height: 420px; overflow-y: auto; }
308
+ .log-wrap::-webkit-scrollbar { width: 6px; }
309
+ .log-wrap::-webkit-scrollbar-track { background: var(--surface); }
310
+ .log-wrap::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
311
+ .query-cell { color: var(--text); max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
312
+ .badge {
313
+ display: inline-block;
314
+ padding: 1px 6px;
315
+ border-radius: 3px;
316
+ font-size: 10px;
317
+ font-weight: 600;
318
+ }
319
+ .badge.success { background: #0a2a1a; color: var(--green); }
320
+ .badge.error { background: #2a0a0a; color: var(--red); }
321
+
322
+ /* Footer */
323
+ .footer {
324
+ margin-top: 32px;
325
+ padding-top: 12px;
326
+ border-top: 1px solid var(--border);
327
+ color: var(--text-dim);
328
+ font-size: 10px;
329
+ text-align: center;
330
+ }
331
+ .refresh-indicator { color: var(--green-dim); }
332
+
333
+ /* Responsive */
334
+ @media (max-width: 900px) {
335
+ .cards { grid-template-columns: repeat(2, 1fr); }
336
+ }
337
+ @media (max-width: 500px) {
338
+ .cards { grid-template-columns: 1fr; }
339
+ }
340
+ </style>
341
+ </head>
342
+ <body>
343
+
344
+ <div class="header">
345
+ <h1>&gt;_ A3M ROUTER</h1>
346
+ <div>
347
+ <span class="uptime" id="uptime">uptime: loading...</span>
348
+ <span class="refresh-indicator" id="refresh-dot"> &#9679;</span>
349
+ </div>
350
+ </div>
351
+
352
+ <!-- Overview Cards -->
353
+ <div class="cards" id="overview-cards">
354
+ <div class="card">
355
+ <div class="label">Requests Today</div>
356
+ <div class="value" id="stat-requests">--</div>
357
+ </div>
358
+ <div class="card">
359
+ <div class="label">Cost Today</div>
360
+ <div class="value cost" id="stat-cost">$--</div>
361
+ </div>
362
+ <div class="card">
363
+ <div class="label">Avg Latency</div>
364
+ <div class="value latency" id="stat-latency">-- ms</div>
365
+ </div>
366
+ <div class="card">
367
+ <div class="label">Active Providers</div>
368
+ <div class="value providers" id="stat-providers">-- / --</div>
369
+ </div>
370
+ </div>
371
+
372
+ <!-- Provider Status -->
373
+ <div class="section">
374
+ <div class="section-title">Provider Status</div>
375
+ <table>
376
+ <thead>
377
+ <tr>
378
+ <th>Status</th>
379
+ <th>Provider</th>
380
+ <th>Requests</th>
381
+ <th>Cost</th>
382
+ <th>Avg Latency</th>
383
+ <th>Last Error</th>
384
+ </tr>
385
+ </thead>
386
+ <tbody id="provider-table"></tbody>
387
+ </table>
388
+ </div>
389
+
390
+ <!-- Cost Chart -->
391
+ <div class="section">
392
+ <div class="section-title">Cost by Provider</div>
393
+ <div id="cost-chart">
394
+ <div style="color:var(--text-dim); font-size:11px;">Loading...</div>
395
+ </div>
396
+ </div>
397
+
398
+ <!-- Request Log -->
399
+ <div class="section">
400
+ <div class="section-title">Recent Requests <span style="color:var(--text-dim);font-weight:400;">(last 50)</span></div>
401
+ <div class="log-wrap">
402
+ <table>
403
+ <thead>
404
+ <tr>
405
+ <th>Time</th>
406
+ <th>Query</th>
407
+ <th>Provider</th>
408
+ <th>Model</th>
409
+ <th>Latency</th>
410
+ <th>Cost</th>
411
+ <th>Status</th>
412
+ </tr>
413
+ </thead>
414
+ <tbody id="request-log"></tbody>
415
+ </table>
416
+ </div>
417
+ </div>
418
+
419
+ <!-- Clear + Footer -->
420
+ <div style="text-align:right; margin-bottom:12px;">
421
+ <button onclick="clearLog()" style="
422
+ background:var(--surface2); color:var(--red); border:1px solid var(--red);
423
+ padding:6px 16px; border-radius:4px; cursor:pointer; font-family:var(--mono);
424
+ font-size:11px; letter-spacing:1px;
425
+ ">CLEAR LOG</button>
426
+ </div>
427
+
428
+ <div class="footer">
429
+ A3M Router Dashboard &middot; Auto-refresh every 5s &middot; <span id="last-refresh">--</span>
430
+ </div>
431
+
432
+ <script>
433
+ const CHART_COLORS = ['#00ff88','#00ccff','#ffcc00','#ff44ff','#ff8800','#ff4444','#88ff00','#44ffff'];
434
+
435
+ function fmt(n, d) { return typeof n === 'number' ? n.toFixed(d || 2) : '--'; }
436
+ function fmtCost(c) { return '$' + fmt(c, 6); }
437
+ function fmtMs(ms) { return fmt(ms, 0) + ' ms'; }
438
+ function fmtTime(ts) {
439
+ const d = new Date(ts);
440
+ return d.toLocaleTimeString('en-US', { hour12: false, hour:'2-digit', minute:'2-digit', second:'2-digit' });
441
+ }
442
+ function uptime(ms) {
443
+ const s = Math.floor(ms/1000);
444
+ const h = Math.floor(s/3600);
445
+ const m = Math.floor((s%3600)/60);
446
+ return 'uptime: ' + h + 'h ' + m + 'm';
447
+ }
448
+ function esc(s) {
449
+ if (!s) return '';
450
+ return s.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');
451
+ }
452
+ function trunc(s, n) { return s && s.length > n ? s.substring(0, n) + '...' : s; }
453
+
454
+ function renderProviders(providers) {
455
+ const tbody = document.getElementById('provider-table');
456
+ if (!providers || providers.length === 0) {
457
+ tbody.innerHTML = '<tr><td colspan="6" style="color:var(--text-dim);">No providers registered</td></tr>';
458
+ return;
459
+ }
460
+ tbody.innerHTML = providers.map(function(p) {
461
+ var dot = p.status === 'online' ? '&#x1F7E2;' : '&#x1F534;';
462
+ var errCell = p.lastError
463
+ ? '<td class="error-text" title="' + esc(p.lastError) + '">' + esc(trunc(p.lastError, 30)) + '</td>'
464
+ : '<td style="color:var(--text-dim);">--</td>';
465
+ return '<tr>' +
466
+ '<td class="status-dot">' + dot + '</td>' +
467
+ '<td>' + esc(p.name || p.id) + '</td>' +
468
+ '<td>' + p.requestsToday + '</td>' +
469
+ '<td>' + fmtCost(p.costToday) + '</td>' +
470
+ '<td>' + (p.avgLatency > 0 ? fmtMs(p.avgLatency) : '--') + '</td>' +
471
+ errCell +
472
+ '</tr>';
473
+ }).join('');
474
+ }
475
+
476
+ function renderChart(costByProvider) {
477
+ var el = document.getElementById('cost-chart');
478
+ var keys = Object.keys(costByProvider || {});
479
+ if (keys.length === 0) {
480
+ el.innerHTML = '<div style="color:var(--text-dim);font-size:11px;">No cost data yet</div>';
481
+ return;
482
+ }
483
+ var max = 0;
484
+ keys.forEach(function(k) { if (costByProvider[k] > max) max = costByProvider[k]; });
485
+ if (max === 0) max = 0.001;
486
+ el.innerHTML = keys.map(function(k, i) {
487
+ var pct = Math.max(1, (costByProvider[k] / max) * 100);
488
+ var color = CHART_COLORS[i % CHART_COLORS.length];
489
+ return '<div class="chart-row">' +
490
+ '<div class="chart-label">' + esc(k) + '</div>' +
491
+ '<div class="chart-bar-wrap">' +
492
+ '<div class="chart-bar" style="width:' + pct + '%;background:' + color + ';">' +
493
+ '<span class="chart-val">' + fmtCost(costByProvider[k]) + '</span>' +
494
+ '</div>' +
495
+ '</div>' +
496
+ '</div>';
497
+ }).join('');
498
+ }
499
+
500
+ function renderRequests(requests) {
501
+ var tbody = document.getElementById('request-log');
502
+ if (!requests || requests.length === 0) {
503
+ tbody.innerHTML = '<tr><td colspan="7" style="color:var(--text-dim);">No requests yet</td></tr>';
504
+ return;
505
+ }
506
+ tbody.innerHTML = requests.map(function(r) {
507
+ var badge = r.status === 'success'
508
+ ? '<span class="badge success">OK</span>'
509
+ : '<span class="badge error">ERR</span>';
510
+ return '<tr>' +
511
+ '<td>' + fmtTime(r.timestamp) + '</td>' +
512
+ '<td class="query-cell" title="' + esc(r.query) + '">' + esc(trunc(r.query || '', 50)) + '</td>' +
513
+ '<td>' + esc(r.provider) + '</td>' +
514
+ '<td style="font-size:10px;color:var(--text-dim);">' + esc(r.model) + '</td>' +
515
+ '<td>' + fmtMs(r.latency) + '</td>' +
516
+ '<td>' + fmtCost(r.cost) + '</td>' +
517
+ '<td>' + badge + '</td>' +
518
+ '</tr>';
519
+ }).join('');
520
+ }
521
+
522
+ function clearLog() {
523
+ fetch('/api/clear', { method: 'POST' }).then(function() { refresh(); });
524
+ }
525
+
526
+ async function refresh() {
527
+ try {
528
+ var resp = await fetch('/api/stats');
529
+ var data = await resp.json();
530
+ document.getElementById('stat-requests').textContent = data.totalRequestsToday || 0;
531
+ document.getElementById('stat-cost').textContent = fmtCost(data.totalCostToday);
532
+ document.getElementById('stat-latency').textContent = data.avgLatency > 0 ? fmtMs(data.avgLatency) : '-- ms';
533
+ document.getElementById('stat-providers').textContent = (data.activeProviders || 0) + ' / ' + (data.totalProviders || 0);
534
+ document.getElementById('uptime').textContent = uptime(data.uptime || 0);
535
+ renderProviders(data.providers);
536
+ renderChart(data.costByProvider);
537
+ renderRequests(data.recentRequests);
538
+ document.getElementById('last-refresh').textContent = 'updated ' + new Date().toLocaleTimeString();
539
+ document.getElementById('refresh-dot').style.color = '#00ff88';
540
+ setTimeout(function() { document.getElementById('refresh-dot').style.color = '#00aa5a'; }, 800);
541
+ } catch (e) {
542
+ document.getElementById('last-refresh').textContent = 'fetch error: ' + e.message;
543
+ document.getElementById('refresh-dot').style.color = '#ff4444';
544
+ }
545
+ }
546
+
547
+ refresh();
548
+ setInterval(refresh, 5000);
549
+ </script>
550
+ </body>
551
+ </html>`;
552
+ }
553
+ //# sourceMappingURL=dashboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.js","sourceRoot":"","sources":["../../src/server/dashboard.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG;;AAuDH,sCAoCC;AAKD,4CAaC;AA+CD,wDA6DC;AAMD,4CA0XC;AA9iBD,+DAA+D;AAC/D,8BAA8B;AAC9B,+DAA+D;AAE/D,MAAM,YAAY,GAAG,EAAE,CAAC;AACxB,MAAM,cAAc,GAAuB,EAAE,CAAC;AAC9C,MAAM,aAAa,GAAmC,IAAI,GAAG,EAAE,CAAC;AAChE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAE7B;;GAEG;AACH,SAAgB,aAAa,CAAC,GAAwC;IACpE,MAAM,KAAK,GAAqB,EAAE,GAAG,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IAClE,cAAc,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,cAAc,CAAC,MAAM,GAAG,YAAY;QAAE,cAAc,CAAC,GAAG,EAAE,CAAC;IAE/D,wBAAwB;IACxB,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,mBAAmB;IAEzC,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,CAAC,aAAa,EAAE,CAAC;QACzB,QAAQ,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,CAAC;QAC/B,0BAA0B;QAC1B,QAAQ,CAAC,UAAU;YACjB,CAAC,QAAQ,CAAC,UAAU,GAAG,CAAC,QAAQ,CAAC,aAAa,GAAG,CAAC,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;gBAClE,QAAQ,CAAC,aAAa,CAAC;QACzB,IAAI,GAAG,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;YAC3B,QAAQ,CAAC,SAAS,GAAG,GAAG,CAAC,KAAK,IAAI,eAAe,CAAC;YAClD,QAAQ,CAAC,aAAa,GAAG,KAAK,CAAC,SAAS,CAAC;YACzC,QAAQ,CAAC,MAAM,GAAG,SAAS,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,QAAQ,CAAC,MAAM,GAAG,QAAQ,CAAC;QAC7B,CAAC;IACH,CAAC;SAAM,CAAC;QACN,aAAa,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE;YAC9B,EAAE,EAAE,GAAG,CAAC,QAAQ;YAChB,IAAI,EAAE,GAAG,CAAC,QAAQ;YAClB,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YACvD,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,GAAG,CAAC,IAAI;YACnB,UAAU,EAAE,GAAG,CAAC,OAAO;YACvB,SAAS,EAAE,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,IAAI,eAAe,CAAC,CAAC,CAAC,IAAI;YACvE,aAAa,EAAE,GAAG,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;SAC/D,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,EAAU,EAAE,IAAY;IACvD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;QAC3B,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE;YACpB,EAAE;YACF,IAAI;YACJ,MAAM,EAAE,QAAQ;YAChB,aAAa,EAAE,CAAC;YAChB,SAAS,EAAE,CAAC;YACZ,UAAU,EAAE,CAAC;YACb,SAAS,EAAE,IAAI;YACf,aAAa,EAAE,IAAI;SACpB,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,UAAU;IACjB,MAAM,SAAS,GAAG,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC;IACrD,MAAM,MAAM,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,MAAM,CAAC;IACrE,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC;IACjE,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC;IAC1D,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,GAAG,CAAC;QAChB,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,MAAM;QAChE,CAAC,CAAC,CAAC,CAAC;IAER,MAAM,cAAc,GAA2B,EAAE,CAAC;IAClD,KAAK,MAAM,CAAC,IAAI,SAAS,EAAE,CAAC;QAC1B,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC;IACrC,CAAC;IAED,OAAO;QACL,kBAAkB,EAAE,SAAS;QAC7B,cAAc,EAAE,SAAS;QACzB,UAAU,EAAE,MAAM;QAClB,eAAe,EAAE,MAAM;QACvB,cAAc,EAAE,SAAS,CAAC,MAAM;QAChC,SAAS;QACT,cAAc;QACd,cAAc;QACd,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;KAC/B,CAAC;AACJ,CAAC;AAED,SAAS,YAAY;IACnB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACvB,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;AACrB,CAAC;AAED,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D;;GAEG;AACH,SAAgB,sBAAsB,CACpC,GAAyB,EACzB,GAAwB;IAExB,MAAM,GAAG,GAAG,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC;IAE3B,eAAe;IACf,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAC;IACpE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,cAAc,CAAC,CAAC;IAE9D,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACnB,GAAG,CAAC,GAAG,EAAE,CAAC;QACV,OAAO,IAAI,CAAC;IACd,CAAC;IAED,yBAAyB;IACzB,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACxC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,0BAA0B,EAAE,CAAC,CAAC;QACnE,GAAG,CAAC,GAAG,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,iBAAiB;IACjB,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACjD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,qBAAqB;IACrB,IAAI,GAAG,KAAK,gBAAgB,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACrD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5D,OAAO,IAAI,CAAC;IACd,CAAC;IAED,oBAAoB;IACpB,IAAI,GAAG,KAAK,eAAe,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QACpD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,kBAAkB;IAClB,IAAI,GAAG,KAAK,YAAY,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAClD,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC;QAC1B,KAAK,MAAM,CAAC,IAAI,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;YACvC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC;YACpB,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC;YACjB,CAAC,CAAC,SAAS,GAAG,IAAI,CAAC;YACnB,CAAC,CAAC,aAAa,GAAG,IAAI,CAAC;QACzB,CAAC;QACD,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAC3D,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,KAAK,CAAC,CAAC,wBAAwB;AACxC,CAAC;AAED,+DAA+D;AAC/D,iBAAiB;AACjB,+DAA+D;AAE/D,SAAgB,gBAAgB;IAC9B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwXD,CAAC;AACT,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A3M Router - Model Mapper
3
+ *
4
+ * Maps OpenAI-compatible model names to our provider/model pairs.
5
+ * Supports:
6
+ * - "auto" → intelligent routing via advancedRouter
7
+ * - "gpt-4" → best available premium provider
8
+ * - "gpt-3.5-turbo" → best available fast provider
9
+ * - "groq/llama-3.3-70b" → specific provider/model
10
+ * - "claude-3.5-sonnet" → Anthropic provider
11
+ * - "gemini-2.0-flash" → Google provider
12
+ */
13
+ export interface ModelMapping {
14
+ providerId: string;
15
+ model: string;
16
+ baseUrl: string;
17
+ apiKey: string | null;
18
+ costPerK: {
19
+ input: number;
20
+ output: number;
21
+ };
22
+ type: string;
23
+ }
24
+ /**
25
+ * Resolve an OpenAI-compatible model name to a concrete provider/model pair.
26
+ *
27
+ * Resolution order:
28
+ * 1. "auto" → route through advancedRouter
29
+ * 2. "provider/model" format → direct lookup
30
+ * 3. OpenAI alias → preference list lookup
31
+ * 4. Bare model name → search across all providers
32
+ * 5. Fallback → first available provider's first model
33
+ */
34
+ export declare function resolveModel(modelName: string, prompt?: string): ModelMapping | null;
35
+ /**
36
+ * List all available models in OpenAI-compatible format.
37
+ */
38
+ export declare function listAvailableModels(): Array<{
39
+ id: string;
40
+ object: string;
41
+ created: number;
42
+ owned_by: string;
43
+ }>;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modelMapper.d.ts","sourceRoot":"","sources":["../../src/server/modelMapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AA0BD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAsDpF;AA4BD;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,KAAK,CAAC;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CA4BD"}