adaptive-memory-multi-model-router 2.13.0 → 2.13.2

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