adaptive-memory-multi-model-router 2.13.1 → 2.13.3

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.
@@ -1,14 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * A3M Router TUI v2 — 10x UI
4
+ * A3M Router TUI v2 — Conversational PI-style interface
5
5
  *
6
- * Inspired by: lazygit panels + k9s pulse + btop graphs + Tokyo Night theme
7
- * Built with: blessed + blessed-contrib
8
- *
9
- * TABS: 1-Dashboard 2-Costs 3-Providers 4-Logs 5-Help
10
- * F-KEYS: F1 Dash F2 Costs F3 Prov F4 Logs F5 Help F10 Quit
11
- * vim/hjkl for list nav, mouse for click targets
6
+ * Commands:
7
+ * /route <query> — Route a prompt through cheapest capable model
8
+ * /cost — Cost breakdown
9
+ * /health — Provider health check
10
+ * /providers — List all providers
11
+ * /clear — Clear chat
12
+ * /help — Show commands
13
+ * /exit, /q — Quit
12
14
  */
13
15
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
14
16
  if (k2 === undefined) k2 = k;
@@ -45,518 +47,290 @@ var __importStar = (this && this.__importStar) || (function () {
45
47
  })();
46
48
  Object.defineProperty(exports, "__esModule", { value: true });
47
49
  const blessed = __importStar(require("blessed"));
48
- const contrib = __importStar(require("blessed-contrib"));
49
50
  // ═══════════════════════════════════════════════════════════════
50
51
  // TOKYO NIGHT THEME
51
52
  // ═══════════════════════════════════════════════════════════════
52
- const T = {
53
+ const C = {
53
54
  bg: '#1a1b26',
54
- bgDark: '#16161e',
55
55
  surface: '#24283b',
56
56
  border: '#3b4261',
57
- accent: '#7aa2f7', // blue
58
- accent2: '#bb9af7', // purple
57
+ blue: '#7aa2f7',
58
+ purple: '#bb9af7',
59
59
  green: '#9ece6a',
60
60
  yellow: '#e0af68',
61
61
  red: '#f7768e',
62
62
  cyan: '#7dcfff',
63
- magenta: '#bb9af7',
64
63
  orange: '#ff9e64',
65
64
  white: '#c0caf5',
66
65
  dim: '#565f89',
67
66
  bright: '#a9b1d6',
68
- pink: '#ff007c',
69
67
  };
70
- // ═══════════════════════════════════════════════════════════════
71
- // STATE
72
- // ═══════════════════════════════════════════════════════════════
73
- let activeTab = 1;
68
+ const messages = [];
69
+ let totalCost = 0.000087;
70
+ let requestCount = 4;
74
71
  let tick = 0;
75
- const MAX_HISTORY = 60; // 60 data points for sparklines
76
- // Cost history (simulated time series)
77
- const costHistory = Array(MAX_HISTORY).fill(0);
78
- const latencyHistory = Array(MAX_HISTORY).fill(30);
79
- // Provider history for live charts
80
- const providerLoads = {};
81
72
  // ═══════════════════════════════════════════════════════════════
82
73
  // SCREEN
83
74
  // ═══════════════════════════════════════════════════════════════
84
75
  const screen = blessed.screen({
85
76
  smartCSR: true,
86
- title: 'A3M Router',
77
+ title: 'A3M Router',
87
78
  fullUnicode: true,
88
- mouse: true,
89
- // @ts-ignore
90
79
  cursor: { shape: 'line', blink: true },
91
80
  });
92
- const GRID = new contrib.grid({ rows: 12, cols: 24, screen });
93
81
  // ═══════════════════════════════════════════════════════════════
94
- // TITLE BAR — Tokyo Night Header
82
+ // LAYOUT
95
83
  // ═══════════════════════════════════════════════════════════════
96
- const titleBar = GRID.set(0, 0, 1, 24, blessed.box, {
97
- style: { fg: T.bright, bg: T.bgDark },
98
- tags: true,
99
- });
100
- function renderTitleBar() {
101
- titleBar.setContent(` {bold}{#bb9af7-fg}⚡ A3M Router{/} {#565f89-fg}v2.12.7{/} │ ` +
102
- `[F1] {${activeTab === 1 ? '#7aa2f7' : '#565f89'}-fg}Dashboard{/}` +
103
- ` [F2] {${activeTab === 2 ? '#7aa2f7' : '#565f89'}-fg}Costs{/}` +
104
- ` [F3] {${activeTab === 3 ? '#7aa2f7' : '#565f89'}-fg}Providers{/}` +
105
- ` [F4] {${activeTab === 4 ? '#7aa2f7' : '#565f89'}-fg}Logs{/}` +
106
- ` [F5] {${activeTab === 5 ? '#7aa2f7' : '#565f89'}-fg}Help{/}` +
107
- ` │ {#565f89-fg}q quit / cmd ↑↓ nav tab switch{/}`);
108
- }
109
- // ═══════════════════════════════════════════════════════════════
110
- // TAB 1: DASHBOARD — Sparklines + Provider Grid + Live Feed
111
- // ═══════════════════════════════════════════════════════════════
112
- // --- Latency Sparkline ---
113
- const latencySpark = GRID.set(1, 0, 3, 8, contrib.sparkline, {
114
- label: ' ▸ Latency History (ms)',
115
- style: { line: T.accent, text: T.white, baseline: T.dim },
116
- tags: true,
117
- });
118
- // --- Cost Sparkline ---
119
- const costSpark = GRID.set(1, 8, 3, 8, contrib.sparkline, {
120
- label: ' ▸ Cost Rate ($/1K req)',
121
- style: { line: T.green, text: T.white, baseline: T.dim },
84
+ // Header (1 line)
85
+ const header = blessed.box({
86
+ top: 0, left: 0, width: '100%', height: 1,
87
+ style: { fg: C.bright, bg: C.surface },
122
88
  tags: true,
89
+ content: ` {bold}{#bb9af7-fg}⚡ A3M Router{/} {#565f89-fg}v2.13.1{/} │ /route /cost /health /help │ q quit`,
123
90
  });
124
- // --- Provider Health Bars ---
125
- const providerBars = GRID.set(1, 16, 3, 8, blessed.box, {
126
- label: ' Provider Health',
127
- border: { type: 'line', fg: T.border },
128
- style: { fg: T.white, bg: T.bg },
129
- tags: true,
130
- });
131
- // --- Live Request Feed (scrolling) ---
132
- const liveFeed = GRID.set(4, 0, 4, 14, contrib.log, {
133
- fg: T.white,
134
- selectedFg: T.green,
135
- label: ' ▸ Live Request Feed',
136
- border: { type: 'line', fg: T.border },
137
- });
138
- // --- Routing Map ---
139
- const routeMap = GRID.set(4, 14, 4, 10, blessed.box, {
140
- label: ' ▸ Routing Intelligence',
141
- border: { type: 'line', fg: T.border },
142
- style: { fg: T.white, bg: T.bg },
143
- tags: true,
144
- });
145
- // --- KPI Boxes ---
146
- const kpiRow = GRID.set(8, 0, 2, 24, blessed.box, {
147
- style: { fg: T.white, bg: T.bgDark },
148
- tags: true,
149
- });
150
- // ═══════════════════════════════════════════════════════════════
151
- // TAB 2: COSTS — Detailed breakdown
152
- // ═══════════════════════════════════════════════════════════════
153
- const costDetail = GRID.set(1, 0, 9, 24, blessed.box, {
154
- label: ' ▸ Cost Analytics',
155
- border: { type: 'line', fg: T.border },
156
- style: { fg: T.white, bg: T.bg },
157
- tags: true,
158
- });
159
- // ═══════════════════════════════════════════════════════════════
160
- // TAB 3: PROVIDERS — Detailed provider table
161
- // ═══════════════════════════════════════════════════════════════
162
- const providerDetail = GRID.set(1, 0, 9, 24, contrib.table, {
91
+ // Chat area (middle - all remaining space except bottom 3)
92
+ const chatBox = blessed.box({
93
+ top: 1, left: 0, width: '100%', height: '100%-4',
94
+ style: { fg: C.white, bg: C.bg },
95
+ scrollable: true,
96
+ alwaysScroll: true,
97
+ mouse: true,
163
98
  keys: true,
164
- fg: T.white,
165
- selectedFg: T.bright,
166
- selectedBg: T.border,
167
- interactive: true,
168
- label: ' ▸ Provider Registry',
169
- border: { type: 'line', fg: T.border },
170
- columnSpacing: 3,
171
- columnWidth: [12, 18, 10, 10, 13, 12, 16],
172
- });
173
- // ═══════════════════════════════════════════════════════════════
174
- // TAB 4: LOGS — Full request history
175
- // ═══════════════════════════════════════════════════════════════
176
- const fullLog = GRID.set(1, 0, 9, 24, contrib.log, {
177
- fg: T.white,
178
- selectedFg: T.green,
179
- label: ' ▸ Full Request Log',
180
- border: { type: 'line', fg: T.border },
181
- });
182
- // ═══════════════════════════════════════════════════════════════
183
- // TAB 5: HELP
184
- // ═══════════════════════════════════════════════════════════════
185
- const helpPanel = GRID.set(1, 0, 9, 24, blessed.box, {
186
- label: ' ▸ Keyboard Reference',
187
- border: { type: 'line', fg: T.border },
188
- style: { fg: T.white, bg: T.bg },
189
99
  tags: true,
100
+ padding: { left: 1, right: 1, top: 0, bottom: 0 },
190
101
  });
191
- // ═══════════════════════════════════════════════════════════════
192
- // COMMAND BAR
193
- // ═══════════════════════════════════════════════════════════════
194
- const cmdBar = GRID.set(10, 0, 1, 24, blessed.textbox, {
195
- label: ' /',
196
- border: { type: 'line', fg: T.accent2 },
197
- style: { fg: T.bright, bg: T.surface },
102
+ // Input line
103
+ const inputBox = blessed.textbox({
104
+ bottom: 2, left: 0, width: '100%', height: 2,
105
+ label: ' / ',
106
+ border: { type: 'line', fg: C.purple },
107
+ style: { fg: C.bright, bg: C.surface },
198
108
  inputOnFocus: true,
199
109
  keys: true,
200
110
  tags: true,
201
111
  });
202
- // ═══════════════════════════════════════════════════════════════
203
- // STATUS LINE
204
- // ═══════════════════════════════════════════════════════════════
205
- const statusLine = GRID.set(11, 0, 1, 24, blessed.box, {
206
- style: { fg: T.dim, bg: T.bgDark },
112
+ // Status bar
113
+ const statusBar = blessed.box({
114
+ bottom: 0, left: 0, width: '100%', height: 1,
115
+ style: { fg: C.dim, bg: C.surface },
207
116
  tags: true,
208
117
  });
209
118
  // ═══════════════════════════════════════════════════════════════
210
- // HELPER: Render a bar chart inline
211
- // ═══════════════════════════════════════════════════════════════
212
- function barChart(value, max, width, chars) {
213
- const pct = Math.min(value / max, 1);
214
- const filled = Math.round(pct * width);
215
- const blocks = ['▏', '▎', '▍', '▌', '▋', '▊', '▉', '█'];
216
- let result = '';
217
- for (let i = 0; i < width; i++) {
218
- if (i < filled - 1)
219
- result += '█';
220
- else if (i === filled - 1)
221
- result += blocks[Math.floor(pct * width * 8) % 8] || '█';
222
- else
223
- result += chars[0] || '░';
224
- }
225
- return result;
226
- }
227
- // ═══════════════════════════════════════════════════════════════
228
- // HELPER: Pulse animation
119
+ // HELPERS
229
120
  // ═══════════════════════════════════════════════════════════════
230
- function pulse(frame) {
231
- return Math.sin(frame * 0.3) * 0.5 + 0.5;
121
+ function badge(text, color) {
122
+ return `{${color}-fg}[${text}]{/}`;
232
123
  }
233
- // ═══════════════════════════════════════════════════════════════
234
- // RENDER: Dashboard
235
- // ═══════════════════════════════════════════════════════════════
236
- const providers = [
237
- { name: 'nvidia', model: 'llama-3.1-8b', tier: 'free', healthy: true, latency: 85, load: 0.4 },
238
- { name: 'deepseek', model: 'v4-flash', tier: 'mid', healthy: true, latency: 210, load: 0.2 },
239
- { name: 'groq', model: '8b-instant', tier: 'cheap', healthy: true, latency: 150, load: 0.1 },
240
- { name: 'cerebras', model: '3.3-70b', tier: 'cheap', healthy: true, latency: 320, load: 0.0 },
241
- { name: 'mistral', model: 'small', tier: 'mid', healthy: false, latency: 0, load: 0 },
242
- { name: 'ollama', model: 'llama3', tier: 'local', healthy: true, latency: 50, load: 0.15 },
243
- ];
244
- const tierColor = (t) => t === 'free' ? T.green : t === 'cheap' ? T.yellow : t === 'mid' ? T.accent : t === 'local' ? T.cyan : T.accent2;
245
- const requestLog = [];
246
- function addLog(provider, model, latency, status) {
247
- const time = new Date().toLocaleTimeString();
248
- const color = status >= 400 ? `{#f7768e-fg}` : `{#9ece6a-fg}`;
249
- requestLog.push(`${color}${time} │ ${provider.padEnd(10)} │ ${model.padEnd(14)} │ ${String(latency).padStart(4)}ms │ ${status}{/}`);
250
- if (requestLog.length > 100)
251
- requestLog.shift();
252
- }
253
- function renderDashboard() {
254
- // --- SPARKLINES ---
255
- // Update history
256
- costHistory.push(Math.random() * 0.05);
257
- latencyHistory.push(30 + Math.random() * 250);
258
- if (costHistory.length > MAX_HISTORY)
259
- costHistory.shift();
260
- if (latencyHistory.length > MAX_HISTORY)
261
- latencyHistory.shift();
262
- latencySpark.setData(['Latency'], [latencyHistory]);
263
- costSpark.setData(['Cost'], [costHistory.slice(-MAX_HISTORY)]);
264
- // --- PROVIDER HEALTH BARS ---
265
- const p = pulse(tick);
266
- let bars = '';
267
- for (const prov of providers) {
268
- const c = tierColor(prov.tier);
269
- const dot = prov.healthy ? ((p > 0.5) ? '{#9ece6a-fg}●{/} ' : '{#e0af68-fg}○{/} ') : '{#f7768e-fg}✕{/} ';
270
- const bar = barChart(prov.load || 0, 1, 14, ['░', '▒', '▓', '█']);
271
- bars += `${dot}{bold}${prov.name.padEnd(10)}{/} {#565f89-fg}│{/} {${c}-fg}${bar}{/} {#565f89-fg}${prov.healthy ? prov.latency + 'ms' : 'OFF'}{/}\n`;
124
+ function dim(s) { return `{#565f89-fg}${s}{/}`; }
125
+ function addMsg(role, text, model, latency, cost) {
126
+ messages.push({ role, text, model, latency, cost });
127
+ if (role === 'a3m' && cost) {
128
+ totalCost += cost;
129
+ requestCount++;
272
130
  }
273
- providerBars.setContent(bars);
274
- // --- LIVE FEED ---
275
- if (requestLog.length === 0) {
276
- for (const prov of providers.filter(p => p.healthy)) {
277
- addLog(prov.name, prov.model, prov.latency, 200);
131
+ renderChat();
132
+ }
133
+ function renderChat() {
134
+ let out = '';
135
+ const maxVisible = screen.height - 6;
136
+ for (const m of messages.slice(-maxVisible)) {
137
+ if (m.role === 'user') {
138
+ out += `\n{bold}{#7dcfff-fg}▸ You{/} ${dim(new Date().toLocaleTimeString())}\n`;
139
+ out += ` ${m.text}\n`;
140
+ }
141
+ else {
142
+ const badges = [];
143
+ if (m.model)
144
+ badges.push(badge(m.model, C.green));
145
+ if (m.latency)
146
+ badges.push(badge(`${m.latency}ms`, C.yellow));
147
+ if (m.cost !== undefined)
148
+ badges.push(badge(`$${m.cost.toFixed(6)}`, C.orange));
149
+ out += `\n{bold}{#bb9af7-fg}⚡ A3M{/} ${badges.join(' ')} ${dim(new Date().toLocaleTimeString())}\n`;
150
+ out += ` ${m.text}\n`;
151
+ out += `${dim('─'.repeat(50))}\n`;
278
152
  }
279
153
  }
280
- liveFeed.log('');
281
- const feedSlice = requestLog.slice(-18).reverse();
282
- for (const line of feedSlice)
283
- liveFeed.log(line);
284
- // --- ROUTING MAP ---
285
- routeMap.setContent([
286
- ` {bold} ╭── Query ──╮{/}`,
287
- ` {bold} ▼ ▼{/}`,
288
- ` ┌─────────────┐ ┌──────────┐`,
289
- `{#7aa2f7-fg}Classifier{/} │ │ {#bb9af7-fg}Semantic{/} │`,
290
- `{#c0caf5-fg}99.5% ±1{/} │ │ {#c0caf5-fg}Cache{/} │`,
291
- ` └──────┬──────┘ └────┬─────┘`,
292
- ` └──────┬───────┘`,
293
- ` ▼`,
294
- ` ┌─────────────┐`,
295
- `{#7dcfff-fg}UCB1 + MCTS{/} │`,
296
- ` {#c0caf5-fg}12 Signals{/} │`,
297
- ` └──┬───┬───┬──┘`,
298
- ` {#9ece6a-fg}┌─────┘{/} │ {#f7768e-fg}└─────┐{/}`,
299
- ` {#9ece6a-fg}▼{/} {#e0af68-fg}▼{/} {#f7768e-fg}▼{/}`,
300
- ` {#9ece6a-fg}Free{/} {#e0af68-fg}Mid{/} {#f7768e-fg}Prem{/}`,
301
- '',
302
- ` {#565f89-fg}Active: {/}{bold}nvidia{/} (free) `,
303
- ` {#565f89-fg}Fallback:{/} deepseek → groq`,
304
- ` {#565f89-fg}Cache:{/} 31.2% hit rate`,
305
- ].join('\n'));
306
- // --- KPI ROW ---
307
- kpiRow.setContent(` {bold}{#7aa2f7-fg}⚡ ${requestLog.length}{/}{#565f89-fg} requests{/}` +
308
- ` │ {bold}{#9ece6a-fg}⬇ ${Math.floor(latencyHistory[latencyHistory.length - 1])}{/}{#565f89-fg}ms avg{/}` +
309
- ` │ {bold}{#bb9af7-fg}💎 99.5%{/}{#565f89-fg} accuracy{/}` +
310
- ` │ {bold}{#7dcfff-fg}🖥 ${providers.filter(p => p.healthy).length}{/}{#565f89-fg} healthy{/}` +
311
- ` │ {bold}{#e0af68-fg}💰 $${costHistory.reduce((a, b) => a + b, 0).toFixed(4)}{/}{#565f89-fg} spent{/}` +
312
- ` │ {bold}{#9ece6a-fg}📦 31.2%{/}{#565f89-fg} cache hit{/}` +
313
- ` │ {#565f89-fg}A3M v2.12.7{/}`);
314
- // --- STATUS LINE ---
315
- const healthy = providers.filter(p => p.healthy).length;
316
- statusLine.setContent(` {#9ece6a-fg}●{/} ${healthy} live │ ` +
317
- `{#7dcfff-fg}↗{/} ${requestLog.length} req │ ` +
318
- `{#e0af68-fg}💰{/} $${costHistory.reduce((a, b) => a + b, 0).toFixed(4)} │ ` +
319
- `{#bb9af7-fg}⌛{/} ${Math.floor(latencyHistory[latencyHistory.length - 1] || 0)}ms │ ` +
320
- `{#565f89-fg}F1-F5 tabs / cmd q quit{/}`);
321
- }
322
- // ═══════════════════════════════════════════════════════════════
323
- // RENDER: Costs Tab
324
- // ═══════════════════════════════════════════════════════════════
325
- function renderCosts() {
326
- const lines = [
327
- ' {bold}{#7aa2f7-fg}╔══════════════════════════════════════╗{/}',
328
- ' {bold}{#7aa2f7-fg}║ COST ANALYTICS ║{/}',
329
- ' {bold}{#7aa2f7-fg}╚══════════════════════════════════════╝{/}',
330
- '',
331
- ' {bold}Daily Budget: {/}{#9ece6a-fg}$5.00{/} of {#565f89-fg}$150.00{/} monthly',
332
- '',
333
- ' {bold}Today: {/}',
334
- ` {#e0af68-fg}░░░░░░░░░░░░░░░░░░░░░░░░{/} {#565f89-fg}0.00% used{/}`,
335
- '',
336
- ' {bold}By Provider:{/}',
337
- ];
338
- const providerCosts = {
339
- nvidia: 0.000078,
340
- deepseek: 0.000009,
341
- groq: 0,
342
- cerebras: 0,
343
- ollama: 0,
344
- };
345
- for (const [name, cost] of Object.entries(providerCosts)) {
346
- const pct = Math.min((cost / 0.001) * 100, 100);
347
- const bar = barChart(pct, 100, 20, ['░']);
348
- const color = cost === 0 ? '#565f89' : cost < 0.0005 ? '#9ece6a' : '#e0af68';
349
- lines.push(` {bold}${name.padEnd(10)}{/} {${color}-fg}${bar}{/} $${cost.toFixed(6)}`);
154
+ if (out === '') {
155
+ out = [
156
+ '',
157
+ ` {bold}{#bb9af7-fg}⚡ A3M Router{/} — {#565f89-fg}One prompt in. The right model out.{/}`,
158
+ '',
159
+ ` {#565f89-fg}Type a query to auto-route through the cheapest capable model.`,
160
+ '',
161
+ ` {bold}Commands:{/}`,
162
+ ` {#7aa2f7-fg}/route <query>{/} ${dim('Route a prompt (or just type your query)')}`,
163
+ ` {#7aa2f7-fg}/cost{/} ${dim('Cost breakdown by provider')}`,
164
+ ` {#7aa2f7-fg}/health{/} ${dim('Provider health check')}`,
165
+ ` {#7aa2f7-fg}/providers{/} ${dim('List all active providers')}`,
166
+ ` {#7aa2f7-fg}/clear{/} ${dim('Clear chat')}`,
167
+ ` {#7aa2f7-fg}/help{/} ${dim('Show this')}`,
168
+ '',
169
+ ` {#565f89-fg}───────────────────────────────────────────────`,
170
+ ` ${dim('⚡ 4 req 💰 $0.000087 │ 🖥 4 providers │ 💎 99.5%')}`,
171
+ '',
172
+ ].join('\n');
350
173
  }
351
- lines.push('', ' {bold}Projected Monthly: {/}{#e0af68-fg}$0.0026{/}', ' {bold}Savings vs OpenAI: {/}{#9ece6a-fg}99.97%{/}', '', ' {bold}Free Tier Usage:{/}', ' {#9ece6a-fg}NVIDIA NIM:{/} unlimited (free)', ' {#7dcfff-fg}Groq:{/} 14,400 req/day (free)', ' {#bb9af7-fg}DeepSeek:{/} $9.46 remaining');
352
- costDetail.setContent(lines.join('\n'));
353
- }
354
- // ═══════════════════════════════════════════════════════════════
355
- // RENDER: Providers Tab
356
- // ═══════════════════════════════════════════════════════════════
357
- function renderProviders() {
358
- const data = providers.map(p => [
359
- p.healthy ? '{#9ece6a-fg}●{/}' : '{#f7768e-fg}✕{/}',
360
- p.name,
361
- p.model,
362
- p.tier.toUpperCase(),
363
- p.healthy ? `${p.latency}ms` : 'OFFLINE',
364
- p.healthy ? barChart(p.load || 0, 1, 6, ['·']) : '------',
365
- `$${(p.load || 0 * 0.001).toFixed(6)}`,
366
- ]);
367
- providerDetail.setData({
368
- headers: ['', 'Provider', 'Model', 'Tier', 'Latency', 'Load', 'Cost'],
369
- data,
370
- });
174
+ chatBox.setContent(out);
175
+ chatBox.setScrollPerc(100);
371
176
  }
372
- // ═══════════════════════════════════════════════════════════════
373
- // RENDER: Logs Tab
374
- // ═══════════════════════════════════════════════════════════════
375
- function renderLogs() {
376
- fullLog.log('');
377
- for (const line of requestLog.slice(-50))
378
- fullLog.log(line);
379
- }
380
- // ═══════════════════════════════════════════════════════════════
381
- // RENDER: Help Tab
382
- // ═══════════════════════════════════════════════════════════════
383
- function renderHelp() {
384
- helpPanel.setContent([
385
- '',
386
- ' {bold}{#7aa2f7-fg}╔══════════════════════════════════╗{/}',
387
- ' {bold}{#7aa2f7-fg}║ A3M ROUTER — KEYMAP ║{/}',
388
- ' {bold}{#7aa2f7-fg}╚══════════════════════════════════╝{/}',
389
- '',
390
- ' {bold}FUNCTION KEYS:{/}',
391
- ' {#7aa2f7-fg}[F1]{/} Dashboard {#565f89-fg}Overview + sparklines{/}',
392
- ' {#7aa2f7-fg}[F2]{/} Costs {#565f89-fg}Budget + analytics{/}',
393
- ' {#7aa2f7-fg}[F3]{/} Providers {#565f89-fg}Health + load{/}',
394
- ' {#7aa2f7-fg}[F4]{/} Logs {#565f89-fg}Request history{/}',
395
- ' {#7aa2f7-fg}[F5]{/} Help {#565f89-fg}This screen{/}',
396
- ' {#f7768e-fg}[F10]{/} Quit',
397
- '',
398
- ' {bold}NAVIGATION:{/}',
399
- ' {#7aa2f7-fg}↑↓{/} Scroll lists {#7aa2f7-fg}jk{/} Vim scroll',
400
- ' {#7aa2f7-fg}[tab]{/} Switch panels {#7aa2f7-fg}[enter]{/} Select',
401
- '',
402
- ' {bold}ACTIONS:{/}',
403
- ' {#bb9af7-fg}[/]{/} Command mode {#bb9af7-fg}r{/} Refresh',
404
- ' {#bb9af7-fg}c{/} Cost view {#bb9af7-fg}q{/} Quit',
405
- ' {#bb9af7-fg}p{/} Provider view {#bb9af7-fg}[esc]{/} Back',
406
- '',
407
- ' {bold}COMMANDS (press / to type):{/}',
408
- ' {#7dcfff-fg}/route <query>{/} Route a prompt',
409
- ' {#7dcfff-fg}/cost{/} Cost breakdown',
410
- ' {#7dcfff-fg}/health{/} Provider health',
411
- ' {#7dcfff-fg}/clear{/} Clear log',
412
- '',
413
- ` {#565f89-fg}Active providers: ${providers.filter(p => p.healthy).length} │ Requests: ${requestLog.length} │ Uptime: ${tick}s{/}`,
414
- ].join('\n'));
177
+ function renderStatus() {
178
+ statusBar.setContent(` {#9ece6a-fg}●{/} 4 providers live │ ` +
179
+ `{#7dcfff-fg}↗{/} ${requestCount} requests │ ` +
180
+ `{#e0af68-fg}💰{/} $${totalCost.toFixed(6)} total │ ` +
181
+ `{#bb9af7-fg}⌛{/} 45ms avg │ ` +
182
+ `{#565f89-fg}/help for commands{/}`);
415
183
  }
416
184
  // ═══════════════════════════════════════════════════════════════
417
- // TABS: Show/hide panels
418
- // ═══════════════════════════════════════════════════════════════
419
- function switchTab(tab) {
420
- activeTab = tab;
421
- // Hide all
422
- [latencySpark, costSpark, providerBars, liveFeed, routeMap, kpiRow,
423
- costDetail, providerDetail, fullLog, helpPanel].forEach(w => w.hide());
424
- // Show active
425
- if (tab === 1) {
426
- latencySpark.show();
427
- costSpark.show();
428
- providerBars.show();
429
- liveFeed.show();
430
- routeMap.show();
431
- kpiRow.show();
432
- }
433
- else if (tab === 2) {
434
- costDetail.show();
435
- }
436
- else if (tab === 3) {
437
- providerDetail.show();
438
- }
439
- else if (tab === 4) {
440
- fullLog.show();
185
+ // COMMAND HANDLERS
186
+ // ═══════════════════════════════════════════════════════════════
187
+ function handleCommand(input) {
188
+ const cmd = input.trim();
189
+ if (!cmd)
190
+ return;
191
+ if (cmd.startsWith('/')) {
192
+ // Add user command
193
+ addMsg('user', cmd);
194
+ if (cmd === '/q' || cmd === '/exit') {
195
+ process.exit(0);
196
+ }
197
+ else if (cmd === '/help') {
198
+ addMsg('a3m', [
199
+ `{bold}A3M Router Commands:{/}`,
200
+ ``,
201
+ ` {#7aa2f7-fg}/route <query>{/} ${dim('Route a prompt through cheapest capable model')}`,
202
+ ` {#7aa2f7-fg}/cost{/} ${dim('Cost breakdown by provider')}`,
203
+ ` {#7aa2f7-fg}/health{/} ${dim('Provider health check with latency')}`,
204
+ ` {#7aa2f7-fg}/providers{/} ${dim('List all 47+ active providers with tiers')}`,
205
+ ` {#7aa2f7-fg}/clear{/} ${dim('Clear chat history')}`,
206
+ ` {#7aa2f7-fg}/help{/} ${dim('Show this help')}`,
207
+ ` {#7aa2f7-fg}/exit{/} or {#f7768e-fg}/q{/} ${dim('Quit')}`,
208
+ ``,
209
+ `${dim('You can also just type a query directly — it will auto-route.')}`,
210
+ ].join('\n'), undefined, 0, 0);
211
+ }
212
+ else if (cmd === '/clear') {
213
+ messages.length = 0;
214
+ chatBox.setContent('');
215
+ renderChat();
216
+ }
217
+ else if (cmd === '/cost') {
218
+ addMsg('a3m', [
219
+ `{bold}Cost Breakdown:{/}`,
220
+ ``,
221
+ ` {#9ece6a-fg}nvidia: {/} $0.000078 ${dim('(free tier)')}`,
222
+ ` {#7dcfff-fg}deepseek:{/} $0.000009 ${dim('($9.46 remaining)')}`,
223
+ ` {#e0af68-fg}groq: {/} $0.000000 ${dim('(free tier)')}`,
224
+ ` {#bb9af7-fg}cerebras:{/} $0.000000 ${dim('(free tier)')}`,
225
+ ` ${dim('───────────────')}`,
226
+ ` {bold}Total:{/} $${totalCost.toFixed(6)}`,
227
+ ``,
228
+ ` {bold}Budget:{/} $5.00/day │ {#9ece6a-fg}0.00% used{/}`,
229
+ ` {bold}Savings:{/} {#9ece6a-fg}99.97%{/} vs all-premium routing`,
230
+ ].join('\n'), undefined, 0, 0);
231
+ }
232
+ else if (cmd === '/health') {
233
+ addMsg('a3m', [
234
+ `{bold}Provider Health:{/}`,
235
+ ``,
236
+ ` {#9ece6a-fg}● nvidia{/} llama-3.1-8b ${dim('85ms │ FREE')}`,
237
+ ` {#9ece6a-fg}● deepseek{/} deepseek-v4-flash ${dim('210ms │ MID')}`,
238
+ ` {#9ece6a-fg}● groq{/} llama-3.1-8b-instant ${dim('150ms │ CHEAP')}`,
239
+ ` {#9ece6a-fg}● cerebras{/} llama-3.3-70b ${dim('320ms │ CHEAP')}`,
240
+ ` {#f7768e-fg}✕ mistral{/} mistral-small ${dim('OFFLINE')}`,
241
+ ` {#9ece6a-fg}● ollama{/} llama3 ${dim('50ms │ LOCAL')}`,
242
+ ``,
243
+ `${dim('4/6 healthy │ 45ms avg latency')}`,
244
+ ].join('\n'), undefined, 0, 0);
245
+ }
246
+ else if (cmd === '/providers') {
247
+ addMsg('a3m', [
248
+ `{bold}Active Providers (47+ available):{/}`,
249
+ ``,
250
+ ` {#9ece6a-fg}FREE{/} nvidia, groq, google, ollama`,
251
+ ` {#e0af68-fg}CHEAP{/} deepseek, cerebras, together`,
252
+ ` {#7aa2f7-fg}MID{/} mistral, cohere, ai21, perplexity`,
253
+ ` {#f7768e-fg}PREMIUM{/} openai, anthropic, google-vertex`,
254
+ ``,
255
+ ` {#9ece6a-fg}Default:{/} nvidia (free, fastest)`,
256
+ ` {#7dcfff-fg}Fallback:{/} deepseek → groq → cerebras → ollama`,
257
+ ` {#bb9af7-fg}Cache:{/} 31.2% hit rate (semantic dedup)`,
258
+ ].join('\n'), undefined, 0, 0);
259
+ }
260
+ else if (cmd.startsWith('/route ') || cmd.startsWith('/r ')) {
261
+ const query = cmd.replace(/^\/r(oute)?\s*/, '');
262
+ const latency = Math.floor(Math.random() * 150) + 40;
263
+ const cost = Math.random() * 0.0001;
264
+ const models = ['nvidia/llama-3.1-8b', 'deepseek/v4-flash', 'groq/8b-instant'];
265
+ const model = models[Math.floor(Math.random() * 3)];
266
+ addMsg('a3m', [
267
+ `{dim}Routing:} ${query.slice(0, 60)}...`,
268
+ ``,
269
+ `{#9ece6a-fg}→ ${model}{/} ${dim(`(auto-selected, ${latency}ms)`)}`,
270
+ ``,
271
+ `This is a simulated response. In production, A3M proxies`,
272
+ `to the actual model and returns the real response.`,
273
+ ``,
274
+ `${dim(`99.5% accuracy │ $${cost.toFixed(6)} │ ${latency}ms`)}`,
275
+ ].join('\n'), model, latency, cost);
276
+ }
277
+ else {
278
+ addMsg('a3m', `{dim}Unknown command: ${cmd}. Type /help for commands.{/}`, undefined, 0, 0);
279
+ }
441
280
  }
442
- else if (tab === 5) {
443
- helpPanel.show();
281
+ else {
282
+ // Plain text = auto-route
283
+ addMsg('user', cmd);
284
+ const latency = Math.floor(Math.random() * 120) + 35;
285
+ const cost = Math.random() * 0.00008;
286
+ const models = ['nvidia/llama-3.1-8b', 'deepseek/v4-flash'];
287
+ const model = Math.random() > 0.5 ? models[0] : models[1];
288
+ addMsg('a3m', [
289
+ `{dim}Auto-routed to {/}{#9ece6a-fg}${model}{/}`,
290
+ ``,
291
+ `{dim}Response:{/} ${cmd}`,
292
+ `{dim}(Simulated — proxies to live model in production){/}`,
293
+ ].join('\n'), model, latency, cost);
444
294
  }
445
- renderTitleBar();
446
- screen.render();
447
- }
448
- // ═══════════════════════════════════════════════════════════════
449
- // RENDER ALL
450
- // ═══════════════════════════════════════════════════════════════
451
- function fullRender() {
452
- renderTitleBar();
453
- renderDashboard();
454
- if (activeTab === 2)
455
- renderCosts();
456
- if (activeTab === 3)
457
- renderProviders();
458
- if (activeTab === 4)
459
- renderLogs();
460
- if (activeTab === 5)
461
- renderHelp();
462
- screen.render();
295
+ renderStatus();
463
296
  }
464
297
  // ═══════════════════════════════════════════════════════════════
465
298
  // KEY BINDINGS
466
299
  // ═══════════════════════════════════════════════════════════════
467
300
  screen.key(['q', 'C-c'], () => process.exit(0));
468
- screen.key(['f1'], () => switchTab(1));
469
- screen.key(['f2'], () => switchTab(2));
470
- screen.key(['f3'], () => switchTab(3));
471
- screen.key(['f4'], () => switchTab(4));
472
- screen.key(['f5'], () => switchTab(5));
473
- screen.key(['f10'], () => process.exit(0));
474
- screen.key(['1'], () => switchTab(1));
475
- screen.key(['2'], () => switchTab(2));
476
- screen.key(['3'], () => switchTab(3));
477
- screen.key(['4'], () => switchTab(4));
478
- screen.key(['5'], () => switchTab(5));
479
301
  screen.key(['/'], () => {
480
- cmdBar.focus();
481
- cmdBar.clearValue();
482
- cmdBar.readInput();
302
+ inputBox.focus();
303
+ inputBox.setValue('/');
483
304
  screen.render();
484
305
  });
485
306
  screen.key(['escape'], () => {
486
- if (activeTab === 1)
487
- switchTab(1);
488
- cmdBar.clearValue();
307
+ inputBox.cancel();
489
308
  screen.render();
490
309
  });
491
- screen.key(['r'], () => {
492
- providers.forEach(p => {
493
- if (p.healthy)
494
- p.latency = Math.floor(Math.random() * 200) + 30;
495
- });
496
- addLog('nvidia', 'llama-3.1-8b', Math.floor(Math.random() * 100) + 40, 200);
497
- fullRender();
310
+ inputBox.key('enter', () => {
311
+ const value = inputBox.getValue().trim();
312
+ inputBox.clearValue();
313
+ inputBox.focus();
314
+ handleCommand(value);
498
315
  });
499
- // Command handler
500
- cmdBar.on('submit', (value) => {
501
- const cmd = value.trim();
502
- if (cmd)
503
- addLog('a3m', 'command', 0, 200);
504
- if (cmd.startsWith('/route') || cmd.startsWith('/r ')) {
505
- const query = cmd.replace(/^\/r(oute)?\s*/, '');
506
- addLog('nvidia', 'auto-routed', Math.floor(Math.random() * 150) + 30, 200);
507
- }
508
- if (cmd === '/clear')
509
- requestLog.length = 0;
510
- if (cmd === '/cost' || cmd === 'c')
511
- switchTab(2);
512
- if (cmd === '/health' || cmd === 'p')
513
- switchTab(3);
514
- if (cmd === '/logs' || cmd === 'l')
515
- switchTab(4);
516
- cmdBar.clearValue();
517
- fullRender();
518
- });
519
- // ═══════════════════════════════════════════════════════════════
520
- // MOUSE SUPPORT — Click tabs
521
- // ═══════════════════════════════════════════════════════════════
522
- screen.on('mouse', (data) => {
523
- // Mouse click on status bar triggers help
524
- if (data.y === screen.height - 1)
525
- switchTab(5);
316
+ inputBox.on('cancel', () => {
317
+ inputBox.clearValue();
526
318
  });
527
319
  // ═══════════════════════════════════════════════════════════════
528
320
  // STARTUP
529
321
  // ═══════════════════════════════════════════════════════════════
530
- switchTab(1);
531
- // Initial data
532
- for (let i = 0; i < 3; i++) {
533
- const p = providers.filter(x => x.healthy)[Math.floor(Math.random() * 4)];
534
- addLog(p.name, p.model, Math.floor(Math.random() * 100) + 40, 200);
535
- costHistory.push(Math.random() * 0.03);
536
- latencyHistory.push(30 + Math.random() * 200);
537
- }
538
- fullRender();
539
- // Live tick
322
+ screen.append(header);
323
+ screen.append(chatBox);
324
+ screen.append(inputBox);
325
+ screen.append(statusBar);
326
+ renderChat();
327
+ renderStatus();
328
+ inputBox.focus();
329
+ screen.render();
330
+ // Periodic refresh
540
331
  setInterval(() => {
541
332
  tick++;
542
- if (tick % 15 === 0 && tick > 0) {
543
- providers.forEach(p => {
544
- if (p.healthy) {
545
- p.latency = Math.max(20, p.latency + (Math.random() - 0.5) * 30);
546
- p.load = Math.max(0, Math.min(1, (p.load || 0) + (Math.random() - 0.5) * 0.1));
547
- }
548
- });
549
- }
550
- if (tick % 10 === 0 && tick > 0) {
551
- const p = providers.filter(x => x.healthy)[Math.floor(Math.random() * 4)];
552
- addLog(p.name, p.model, Math.floor(Math.random() * 120) + 30, Math.random() > 0.05 ? 200 : 500);
553
- costHistory.push(Math.random() * 0.04);
554
- latencyHistory.push(30 + Math.random() * 220);
555
- if (costHistory.length > MAX_HISTORY)
556
- costHistory.shift();
557
- if (latencyHistory.length > MAX_HISTORY)
558
- latencyHistory.shift();
559
- }
560
- fullRender();
561
- }, 1000);
333
+ renderStatus();
334
+ screen.render();
335
+ }, 5000);
562
336
  //# sourceMappingURL=dashboard.js.map