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

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,21 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  /**
4
- * A3M Router TUI — Terminal Dashboard
4
+ * A3M Router TUI v2 10x UI
5
5
  *
6
- * Inspired by: k9s, lazygit, btop, htop, PI CLI
6
+ * Inspired by: lazygit panels + k9s pulse + btop graphs + Tokyo Night theme
7
7
  * Built with: blessed + blessed-contrib
8
8
  *
9
- * Key Bindings:
10
- * / — Command mode (route queries)
11
- * r — Refresh provider health
12
- * c — Cost breakdown view
13
- * p — Provider detail view
14
- * l — Live request log
15
- * b — Budget alerts
16
- * q — Quit
17
- * tab — Switch panel focus
18
- * ↑↓ — Navigate lists
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
19
12
  */
20
13
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
21
14
  if (k2 === undefined) k2 = k;
@@ -53,310 +46,517 @@ var __importStar = (this && this.__importStar) || (function () {
53
46
  Object.defineProperty(exports, "__esModule", { value: true });
54
47
  const blessed = __importStar(require("blessed"));
55
48
  const contrib = __importStar(require("blessed-contrib"));
56
- const providers = [
57
- { name: 'nvidia', model: 'llama-3.1-8b', healthy: true, latency: 85, costPerK: 0, requests: 2, tier: 'free' },
58
- { name: 'deepseek', model: 'deepseek-v4-flash', healthy: true, latency: 210, costPerK: 0.14, requests: 1, tier: 'mid' },
59
- { name: 'groq', model: 'llama-3.1-8b-instant', healthy: true, latency: 150, costPerK: 0.05, requests: 0, tier: 'cheap' },
60
- { name: 'cerebras', model: 'llama-3.3-70b', healthy: true, latency: 320, costPerK: 0.10, requests: 0, tier: 'cheap' },
61
- { name: 'mistral', model: 'mistral-small', healthy: false, latency: 0, costPerK: 0.20, requests: 0, tier: 'mid' },
62
- { name: 'openai', model: 'gpt-4o', healthy: false, latency: 0, costPerK: 2.50, requests: 0, tier: 'premium' },
63
- { name: 'anthropic', model: 'claude-sonnet-4', healthy: false, latency: 0, costPerK: 3.00, requests: 0, tier: 'premium' },
64
- { name: 'google', model: 'gemma-4-31b', healthy: false, latency: 0, costPerK: 0, requests: 0, tier: 'free' },
65
- { name: 'ollama', model: 'llama3', healthy: true, latency: 50, costPerK: 0, requests: 1, tier: 'local' },
66
- ];
67
- const costSnapshot = {
68
- total: 0.000087,
69
- daily: { '2026-05-25': 0.000087 },
70
- monthly: { '2026-05': 0.000087 },
71
- byProvider: { nvidia: 0.000078, deepseek: 0.000009 },
72
- requestCount: 4,
73
- };
74
- const requestLogs = [
75
- { timestamp: '10:32:15', model: 'deepseek-v4-flash', provider: 'deepseek', latency: 210, tokens: 47, cost: 0.000009, status: 200 },
76
- { timestamp: '10:31:42', model: 'llama-3.1-8b', provider: 'nvidia', latency: 85, tokens: 38, cost: 0, status: 200 },
77
- { timestamp: '10:30:11', model: 'llama-3.1-8b', provider: 'nvidia', latency: 92, tokens: 52, cost: 0, status: 200 },
78
- { timestamp: '10:29:03', model: 'llama3', provider: 'ollama', latency: 55, tokens: 31, cost: 0, status: 200 },
79
- ];
80
- // ============================================================
81
- // COLORS — Elegant Dark Theme
82
- // ============================================================
83
- const C = {
84
- bg: '#0a0e14',
85
- surface: '#131820',
86
- border: '#253040',
87
- accent: '#39bae6',
88
- accent2: '#ff8f40',
89
- green: '#7fd962',
90
- yellow: '#ffcc66',
91
- red: '#f26d78',
92
- white: '#bfbab0',
93
- dim: '#5c6773',
94
- bright: '#e6e1cf',
95
- header: '#d4bfff',
49
+ // ═══════════════════════════════════════════════════════════════
50
+ // TOKYO NIGHT THEME
51
+ // ═══════════════════════════════════════════════════════════════
52
+ const T = {
53
+ bg: '#1a1b26',
54
+ bgDark: '#16161e',
55
+ surface: '#24283b',
56
+ border: '#3b4261',
57
+ accent: '#7aa2f7', // blue
58
+ accent2: '#bb9af7', // purple
59
+ green: '#9ece6a',
60
+ yellow: '#e0af68',
61
+ red: '#f7768e',
62
+ cyan: '#7dcfff',
63
+ magenta: '#bb9af7',
64
+ orange: '#ff9e64',
65
+ white: '#c0caf5',
66
+ dim: '#565f89',
67
+ bright: '#a9b1d6',
68
+ pink: '#ff007c',
96
69
  };
97
- const colorScheme = {
98
- healthy: C.green,
99
- unhealthy: C.red,
100
- free: C.green,
101
- cheap: C.yellow,
102
- mid: C.accent,
103
- premium: C.accent2,
104
- local: C.dim,
105
- };
106
- // ============================================================
107
- // SCREEN SETUP
108
- // ============================================================
70
+ // ═══════════════════════════════════════════════════════════════
71
+ // STATE
72
+ // ═══════════════════════════════════════════════════════════════
73
+ let activeTab = 1;
74
+ 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
+ // ═══════════════════════════════════════════════════════════════
82
+ // SCREEN
83
+ // ═══════════════════════════════════════════════════════════════
109
84
  const screen = blessed.screen({
110
85
  smartCSR: true,
111
- title: 'A3M Router',
112
- dockBorders: false,
86
+ title: 'A3M Router',
113
87
  fullUnicode: true,
114
- cursor: { shape: 'block', blink: true },
88
+ mouse: true,
89
+ // @ts-ignore
90
+ cursor: { shape: 'line', blink: true },
115
91
  });
116
- const grid = new contrib.grid({ rows: 12, cols: 12, screen: screen });
117
- // ============================================================
118
- // HEADER
119
- // ============================================================
120
- const header = grid.set(0, 0, 1, 12, blessed.box, {
121
- content: '{center}{bold}A3M Router Dashboard{/bold} | ───────────────────────────────────────────────── | q quit / cmd r refresh c costs p providers l logs b alerts{/center}',
122
- style: { fg: C.bright, bg: C.surface },
92
+ const GRID = new contrib.grid({ rows: 12, cols: 24, screen });
93
+ // ═══════════════════════════════════════════════════════════════
94
+ // TITLE BAR — Tokyo Night Header
95
+ // ═══════════════════════════════════════════════════════════════
96
+ const titleBar = GRID.set(0, 0, 1, 24, blessed.box, {
97
+ style: { fg: T.bright, bg: T.bgDark },
123
98
  tags: true,
124
99
  });
125
- // ============================================================
126
- // PROVIDER HEALTH GRID (Top Left 5x4)
127
- // ============================================================
128
- const providerTable = grid.set(1, 0, 5, 4, contrib.table, {
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 },
122
+ tags: true,
123
+ });
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, {
129
163
  keys: true,
130
- fg: C.white,
131
- selectedFg: C.bright,
132
- selectedBg: C.border,
164
+ fg: T.white,
165
+ selectedFg: T.bright,
166
+ selectedBg: T.border,
133
167
  interactive: true,
134
- label: ' ▸ Providers',
135
- width: '30%',
136
- height: '50%',
137
- border: { type: 'line', fg: C.border },
138
- columnSpacing: 2,
139
- columnWidth: [12, 14, 6, 8, 8],
168
+ label: ' ▸ Provider Registry',
169
+ border: { type: 'line', fg: T.border },
170
+ columnSpacing: 3,
171
+ columnWidth: [12, 18, 10, 10, 13, 12, 16],
140
172
  });
141
- function renderProviders() {
142
- const data = providers.map(p => [
143
- p.name,
144
- p.model,
145
- p.tier.toUpperCase(),
146
- p.healthy ? `● ${p.latency}ms` : '○ OFFLINE',
147
- p.requests > 0 ? `${p.requests}` : '—',
148
- ]);
149
- providerTable.setData({
150
- headers: ['Provider', 'Model', 'Tier', 'Status', 'Req'],
151
- data: data,
152
- });
153
- // Color-code rows
154
- const rows = providerTable.rows;
155
- if (rows) {
156
- providers.forEach((p, i) => {
157
- if (rows[i]) {
158
- const color = p.healthy ? colorScheme[p.tier] || C.white : C.red;
159
- rows[i].style.fg = color;
160
- }
161
- });
162
- }
163
- }
164
- // ============================================================
165
- // COST GAUGE (Top Right 5x4)
166
- // ============================================================
167
- const costGauge = grid.set(1, 4, 3, 4, contrib.gauge, {
168
- label: ' ▸ Cost Tracker',
169
- stroke: C.accent,
170
- fill: C.accent + '20',
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 },
171
181
  });
172
- const costBox = grid.set(4, 4, 2, 4, blessed.box, {
173
- label: ' Breakdown',
174
- border: { type: 'line', fg: C.border },
175
- style: { fg: C.white, bg: C.bg },
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 },
176
189
  tags: true,
177
190
  });
178
- function renderCosts() {
179
- const maxBudget = 5.00; // $5 daily budget
180
- const pct = Math.min((costSnapshot.total / maxBudget) * 100, 100);
181
- costGauge.setPercent(pct);
182
- costGauge.setLabel(`Cost Tracker — $${costSnapshot.total.toFixed(4)} / $${maxBudget.toFixed(2)} (${pct.toFixed(1)}%)`);
183
- const lines = ['{bold}By Provider:{/bold}'];
184
- for (const [provider, cost] of Object.entries(costSnapshot.byProvider)) {
185
- lines.push(` {${cost === 0 ? 'grey' : cost < 0.001 ? 'green' : 'yellow'}-fg}${provider}: $${cost.toFixed(6)}{/}`);
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 },
198
+ inputOnFocus: true,
199
+ keys: true,
200
+ tags: true,
201
+ });
202
+ // ═══════════════════════════════════════════════════════════════
203
+ // STATUS LINE
204
+ // ═══════════════════════════════════════════════════════════════
205
+ const statusLine = GRID.set(11, 0, 1, 24, blessed.box, {
206
+ style: { fg: T.dim, bg: T.bgDark },
207
+ tags: true,
208
+ });
209
+ // ═══════════════════════════════════════════════════════════════
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] || '░';
186
224
  }
187
- lines.push('');
188
- lines.push(`{bold}Total Requests: {/bold}${costSnapshot.requestCount}`);
189
- lines.push(`{bold}Monthly: {/bold}$${Object.values(costSnapshot.monthly)[0]?.toFixed(6) || '0.00'}`);
190
- costBox.setContent(lines.join('\n'));
225
+ return result;
191
226
  }
192
- // ============================================================
193
- // LIVE REQUEST LOG (Bottom Left 5x4)
194
- // ============================================================
195
- const requestLog = grid.set(6, 0, 5, 4, contrib.log, {
196
- fg: C.white,
197
- selectedFg: C.green,
198
- label: ' ▸ Live Requests',
199
- border: { type: 'line', fg: C.border },
200
- });
201
- function renderRequestLog() {
202
- requestLog.log('');
203
- for (const r of requestLogs.slice(-20).reverse()) {
204
- const color = r.status === 200 ? '{green-fg}' : r.status >= 400 ? '{red-fg}' : '{yellow-fg}';
205
- requestLog.log(`${color}${r.timestamp} ${r.provider}/${r.model} │ ${r.latency}ms ${r.tokens} tok $${r.cost.toFixed(6)}{/}`);
227
+ // ═══════════════════════════════════════════════════════════════
228
+ // HELPER: Pulse animation
229
+ // ═══════════════════════════════════════════════════════════════
230
+ function pulse(frame) {
231
+ return Math.sin(frame * 0.3) * 0.5 + 0.5;
232
+ }
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`;
272
+ }
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);
278
+ }
206
279
  }
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{/}`);
207
321
  }
208
- // ============================================================
209
- // MODEL ROUTING TREE (Bottom Right 5x4)
210
- // ============================================================
211
- const routingBox = grid.set(6, 4, 5, 4, blessed.box, {
212
- label: ' ▸ Routing Flow',
213
- border: { type: 'line', fg: C.border },
214
- style: { fg: C.white, bg: C.bg },
215
- tags: true,
216
- });
217
- function renderRoutingFlow() {
322
+ // ═══════════════════════════════════════════════════════════════
323
+ // RENDER: Costs Tab
324
+ // ═══════════════════════════════════════════════════════════════
325
+ function renderCosts() {
218
326
  const lines = [
219
- '{center}{bold}Query → A3M Router → Best Model{/bold}{/center}',
327
+ ' {bold}{#7aa2f7-fg}╔══════════════════════════════════════╗{/}',
328
+ ' {bold}{#7aa2f7-fg}║ COST ANALYTICS ║{/}',
329
+ ' {bold}{#7aa2f7-fg}╚══════════════════════════════════════╝{/}',
220
330
  '',
221
- ' ┌──────────┐',
222
- ' │ Query │',
223
- ' └────┬─────┘',
224
- ' ▼',
225
- ' ┌─────────────┐',
226
- ' │ Classifier │',
227
- ' │ 99.5% ±1 │',
228
- ' └─────┬───────┘',
229
- ' ▼',
230
- ' ┌─────────────┐',
231
- ' │ 12 Signals │',
232
- ' │ UCB1 + MCTS │',
233
- ' └──┬──┬──┬───┘',
234
- ' │ │ │',
235
- ' {green-fg}┌──┘ {/} {yellow-fg}┌─┘ {/} {blue-fg}└─{/}',
236
- ' {green-fg}▼{/} {yellow-fg}▼{/} {blue-fg}▼{/}',
237
- ' {green-fg}Free{/} {yellow-fg}Mid{/} {blue-fg}Prem{/}',
331
+ ' {bold}Daily Budget: {/}{#9ece6a-fg}$5.00{/} of {#565f89-fg}$150.00{/} monthly',
238
332
  '',
239
- '{dim}Active: {/}{bold}nvidia/llama-3.1-8b{/bold} {green-fg}(free, 85ms){/}',
240
- '{dim}Fallback: {/}deepseek/groq/cerebras',
333
+ ' {bold}Today: {/}',
334
+ ` {#e0af68-fg}░░░░░░░░░░░░░░░░░░░░░░░░{/} {#565f89-fg}0.00% used{/}`,
335
+ '',
336
+ ' {bold}By Provider:{/}',
241
337
  ];
242
- routingBox.setContent(lines.join('\n'));
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)}`);
350
+ }
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'));
243
353
  }
244
- // ============================================================
245
- // COMMAND BAR (Bottom)
246
- // ============================================================
247
- const cmdBar = grid.set(11, 0, 1, 12, blessed.textbox, {
248
- label: ' Command',
249
- border: { type: 'line', fg: C.accent },
250
- style: { fg: C.bright, bg: C.surface },
251
- inputOnFocus: true,
252
- keys: true,
253
- tags: true,
254
- });
255
- // ============================================================
256
- // STATUS BAR
257
- // ============================================================
258
- const statusBar = blessed.box({
259
- bottom: 0,
260
- left: 0,
261
- width: '100%',
262
- height: 1,
263
- content: ' {green-fg}●{/} 4 providers healthy │ {yellow-fg}⚠{/} $0.00 spent today │ {cyan-fg}↗{/} 4 requests │ {magenta-fg}⌛{/} 45ms avg latency',
264
- style: { fg: C.dim, bg: C.surface },
265
- tags: true,
266
- });
267
- // ============================================================
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
+ });
371
+ }
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'));
415
+ }
416
+ // ═══════════════════════════════════════════════════════════════
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();
441
+ }
442
+ else if (tab === 5) {
443
+ helpPanel.show();
444
+ }
445
+ renderTitleBar();
446
+ screen.render();
447
+ }
448
+ // ═══════════════════════════════════════════════════════════════
268
449
  // RENDER ALL
269
- // ============================================================
270
- function renderAll() {
271
- renderProviders();
272
- renderCosts();
273
- renderRequestLog();
274
- renderRoutingFlow();
275
- screen.append(statusBar);
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();
276
462
  screen.render();
277
463
  }
278
- // ============================================================
464
+ // ═══════════════════════════════════════════════════════════════
279
465
  // KEY BINDINGS
280
- // ============================================================
281
- let activePanel = 'providers';
466
+ // ═══════════════════════════════════════════════════════════════
282
467
  screen.key(['q', 'C-c'], () => process.exit(0));
283
- screen.key(['r'], () => {
284
- // Simulate health refresh
285
- providers.forEach(p => {
286
- if (p.healthy)
287
- p.latency = Math.floor(Math.random() * 200) + 30;
288
- });
289
- renderAll();
290
- });
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));
291
479
  screen.key(['/'], () => {
292
- activePanel = 'cmd';
293
480
  cmdBar.focus();
481
+ cmdBar.clearValue();
294
482
  cmdBar.readInput();
295
483
  screen.render();
296
484
  });
297
485
  screen.key(['escape'], () => {
298
- activePanel = 'providers';
299
- providerTable.focus();
486
+ if (activeTab === 1)
487
+ switchTab(1);
300
488
  cmdBar.clearValue();
301
489
  screen.render();
302
490
  });
303
- screen.key(['tab'], () => {
304
- activePanel = activePanel === 'providers' ? 'cmd' : 'providers';
305
- if (activePanel === 'providers')
306
- providerTable.focus();
307
- else
308
- cmdBar.focus();
309
- screen.render();
310
- });
311
- screen.key(['c'], () => {
312
- const pct = Math.min((costSnapshot.total / 5) * 100, 100);
313
- costGauge.setPercent(pct + 0.1);
314
- renderAll();
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();
315
498
  });
316
- // Handle command input
499
+ // Command handler
317
500
  cmdBar.on('submit', (value) => {
318
501
  const cmd = value.trim();
502
+ if (cmd)
503
+ addLog('a3m', 'command', 0, 200);
319
504
  if (cmd.startsWith('/route') || cmd.startsWith('/r ')) {
320
505
  const query = cmd.replace(/^\/r(oute)?\s*/, '');
321
- requestLogs.push({
322
- timestamp: new Date().toLocaleTimeString(),
323
- model: 'auto',
324
- provider: 'nvidia',
325
- latency: Math.floor(Math.random() * 150) + 30,
326
- tokens: Math.floor(Math.random() * 100),
327
- cost: 0,
328
- status: 200,
329
- });
330
- costSnapshot.requestCount++;
331
- renderAll();
506
+ addLog('nvidia', 'auto-routed', Math.floor(Math.random() * 150) + 30, 200);
332
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);
333
516
  cmdBar.clearValue();
334
- providerTable.focus();
335
- screen.render();
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);
336
526
  });
337
- // ============================================================
527
+ // ═══════════════════════════════════════════════════════════════
338
528
  // STARTUP
339
- // ============================================================
340
- screen.append(statusBar);
341
- renderAll();
342
- providerTable.focus();
343
- screen.render();
344
- // Auto-refresh every 5s
529
+ // ═══════════════════════════════════════════════════════════════
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
345
540
  setInterval(() => {
346
- // Simulate live request
347
- if (Math.random() > 0.7) {
348
- requestLogs.push({
349
- timestamp: new Date().toLocaleTimeString(),
350
- model: providers[Math.floor(Math.random() * providers.length)].model,
351
- provider: providers[Math.floor(Math.random() * providers.length)].name,
352
- latency: Math.floor(Math.random() * 200) + 30,
353
- tokens: Math.floor(Math.random() * 100),
354
- cost: Math.random() * 0.0001,
355
- status: Math.random() > 0.1 ? 200 : 500,
541
+ 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
+ }
356
548
  });
357
- costSnapshot.requestCount++;
358
549
  }
359
- renderAll();
360
- }, 5000);
361
- console.log('[A3M TUI] Dashboard loaded. Press q to quit.');
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);
362
562
  //# sourceMappingURL=dashboard.js.map