adaptive-memory-multi-model-router 2.13.8 → 2.13.9

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,209 +1,287 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * A3M Router CLI Inline REPL (no fullscreen)
4
- * Like PI's /search prints inline, no terminal takeover.
5
- *
6
- * Usage: node dist/tui/dashboard.js
7
- * Then type queries or /slash commands.
3
+ * A3M Router — Terminal Overlay Box
4
+ * Draws a centered overlay ON TOP of existing terminal content.
5
+ * Does NOT clear the screen. Restores terminal when done.
6
+ * Pure ANSI — no fullscreen, no alt-buffer.
8
7
  */
9
8
 
10
9
  import * as readline from 'readline';
11
- // @ts-ignore
12
- import chalk from 'chalk';
13
- // @ts-ignore
14
- import boxen from 'boxen';
15
10
 
16
- // ═══════════════════════════════════════════════
17
- // STATE
18
- // ═══════════════════════════════════════════════
11
+
12
+ const ansi = (n: number) => `\x1b[${n}m`;
13
+ const R = ansi(0);
14
+ const BOLD = ansi(1);
15
+ const DIM = ansi(2);
16
+
17
+ const C = {
18
+ bg: '\x1b[48;5;234m', // #1a1b26
19
+ surface: '\x1b[48;5;236m', // #24283b
20
+ border: '\x1b[38;5;60m', // #3b4261
21
+ dim: '\x1b[38;5;60m', // #565f89
22
+ text: '\x1b[38;5;189m', // #c0caf5
23
+ blue: '\x1b[38;5;111m', // #7aa2f7
24
+ purple: '\x1b[38;5;183m', // #bb9af7
25
+ green: '\x1b[38;5;114m', // #9ece6a
26
+ yellow: '\x1b[38;5;180m', // #e0af68
27
+ red: '\x1b[38;5;204m', // #f7768e
28
+ cyan: '\x1b[38;5;117m', // #7dcfff
29
+ orange: '\x1b[38;5;216m', // #ff9e64
30
+ };
31
+
19
32
 
20
33
  let activeModel = 'nvidia/llama-3.1-8b';
21
34
  let totalCost = 0.000087;
22
35
  let reqCount = 4;
23
- let showStats = true;
24
-
25
- // ═══════════════════════════════════════════════
26
- // HELPERS
27
- // ═══════════════════════════════════════════════
28
-
29
- function dim(s: string) { return chalk.dim(s); }
30
- function badge(t: string) { return chalk.dim(`[${t}]`); }
31
-
32
- function headerLine(): string {
33
- return [
34
- chalk.bold.hex('#bb9af7')('⚡ A3M Router'),
35
- dim('·'),
36
- chalk.hex('#9ece6a')(activeModel),
37
- dim('·'),
38
- dim(`${reqCount} req`),
39
- dim('·'),
40
- dim(`$${totalCost.toFixed(6)}`),
41
- ].join(' ');
36
+ const log: string[] = [];
37
+
38
+
39
+ function getSize(): [number, number] {
40
+ return [process.stdout.columns || 80, process.stdout.rows || 24];
42
41
  }
43
42
 
44
- function printSystem(text: string) {
45
- console.log(' ' + dim(text));
43
+ function saveCursor() { process.stdout.write('\x1b[s'); }
44
+ function restoreCursor() { process.stdout.write('\x1b[u'); }
45
+ function moveTo(row: number, col: number) { process.stdout.write(`\x1b[${row};${col}H`); }
46
+ function clearLine() { process.stdout.write('\x1b[2K'); }
47
+ function hideCursor() { process.stdout.write('\x1b[?25l'); }
48
+ function showCursor() { process.stdout.write('\x1b[?25h'); }
49
+
50
+ const B = { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };
51
+
52
+ function drawOverlay(rows: number, cols: number, top: number, left: number, lines: string[]) {
53
+ const w = cols - 2;
54
+
55
+ // Top border
56
+ moveTo(top, left);
57
+ process.stdout.write(C.bg + C.purple + B.tl + B.h.repeat(w) + B.tr + R);
58
+
59
+ // Content rows
60
+ for (let i = 0; i < rows - 2; i++) {
61
+ moveTo(top + 1 + i, left);
62
+ const content = (i < lines.length ? lines[i] : '').padEnd(w, ' ');
63
+ process.stdout.write(C.bg + C.purple + B.v + R + C.bg + content + C.purple + B.v + R);
64
+ }
65
+
66
+ // Bottom border
67
+ moveTo(top + rows - 1, left);
68
+ process.stdout.write(C.bg + C.purple + B.bl + B.h.repeat(w) + B.br + R);
46
69
  }
47
70
 
48
- function printUser(text: string) {
49
- console.log('');
50
- console.log(' ' + chalk.bold.hex('#7dcfff')('▸ ') + text);
71
+ function drawPrompt(top: number, left: number, w: number, text: string) {
72
+ moveTo(top, left);
73
+ clearLine();
74
+ process.stdout.write(C.surface + C.text + BOLD + ' ▸ ' + R + C.surface + C.text + text + R);
75
+ moveTo(top, left + 3); // cursor after " ▸ "
51
76
  }
52
77
 
53
- function printA3M(text: string, model?: string, ms?: number, cost?: number) {
54
- const parts: string[] = [];
55
- if (model) parts.push(chalk.hex('#9ece6a')(model));
56
- if (ms) parts.push(chalk.hex('#e0af68')(`${ms}ms`));
57
- if (cost !== undefined) parts.push(chalk.hex('#ff9e64')(`$${cost.toFixed(6)}`));
58
- console.log('');
59
- console.log(' ' + chalk.bold.hex('#bb9af7')('A3M') + ' ' + parts.join(' ' + dim('·') + ' '));
60
- console.log(' ' + text);
78
+
79
+ let inputBuf = '';
80
+ let cursorPos = 3;
81
+
82
+ function handleInput(char: string) {
83
+ if (char === '\r' || char === '\n') {
84
+ // Submit
85
+ const cmd = inputBuf.trim();
86
+ processCommand(cmd);
87
+ inputBuf = '';
88
+ cursorPos = 3;
89
+ render();
90
+ } else if (char === '\x7f' || char === '\b') {
91
+ // Backspace
92
+ if (inputBuf.length > 0) {
93
+ inputBuf = inputBuf.slice(0, -1);
94
+ cursorPos = Math.max(3, cursorPos - 1);
95
+ renderPromptLine();
96
+ }
97
+ } else if (char === '\x1b') {
98
+ // Escape — handled separately
99
+ } else if (char >= ' ') {
100
+ inputBuf += char;
101
+ cursorPos++;
102
+ renderPromptLine();
103
+ }
61
104
  }
62
105
 
63
- // ═══════════════════════════════════════════════
64
- // COMMANDS
65
- // ═══════════════════════════════════════════════
66
-
67
- function handle(input: string) {
68
- const cmd = input.trim();
69
- if (!cmd) return;
70
-
71
- printUser(cmd);
72
-
73
- if (cmd === '/help' || cmd === '/h') {
74
- printA3M([
75
- chalk.bold('Commands:'),
76
- '',
77
- ` ${chalk.hex('#7aa2f7')('/route <query>')} ${dim('Route a prompt')}`,
78
- ` ${chalk.hex('#7aa2f7')('/model <provider>')} ${dim('Switch provider (nvidia, deepseek, groq, etc)')}`,
79
- ` ${chalk.hex('#7aa2f7')('/cost')} ${dim('Cost breakdown')}`,
80
- ` ${chalk.hex('#7aa2f7')('/health')} ${dim('Provider status')}`,
81
- ` ${chalk.hex('#7aa2f7')('/models')} ${dim('List available providers')}`,
82
- ` ${chalk.hex('#7aa2f7')('/stats')} ${dim('Toggle stats header')}`,
83
- ` ${chalk.hex('#7aa2f7')('/clear')} ${dim('Clear screen')}`,
84
- ` ${chalk.hex('#7aa2f7')('/exit, /q')} ${dim('Quit')}`,
85
- '',
86
- dim('Or just type anything — auto-routed to cheapest model.'),
87
- ].join('\n'));
88
- } else if (cmd === '/exit' || cmd === '/q' || cmd === ':q') {
89
- console.log(dim('\n Goodbye.\n'));
90
- process.exit(0);
91
- } else if (cmd === '/clear' || cmd === '/cls') {
92
- console.clear();
93
- console.log(headerLine());
94
- console.log('');
95
- } else if (cmd === '/stats') {
96
- showStats = !showStats;
97
- printSystem(showStats ? 'Stats header: ON' : 'Stats header: OFF');
98
- } else if (cmd === '/cost') {
99
- printA3M('Cost breakdown:', '—', 0, 0);
100
- printSystem(` nvidia $0.000000 (free)`);
101
- printSystem(` deepseek $0.000009 ($9.46 remaining)`);
102
- printSystem(` groq $0.000000 (free)`);
103
- printSystem(` cerebras $0.000000 (free)`);
104
- printSystem(` ───────────────────────`);
105
- printSystem(` TOTAL $${totalCost.toFixed(6)} (${reqCount} requests)`);
106
- printSystem(` Savings 99.97% vs all-premium`);
107
- } else if (cmd === '/health') {
108
- printA3M('Provider health:', '—', 0, 0);
109
- printSystem(` ${chalk.hex('#9ece6a')('●')} nvidia llama-3.1-8b 85ms free`);
110
- printSystem(` ${chalk.hex('#9ece6a')('●')} deepseek v4-flash 210ms mid`);
111
- printSystem(` ${chalk.hex('#9ece6a')('●')} groq 8b-instant 150ms cheap`);
112
- printSystem(` ${chalk.hex('#9ece6a')('●')} cerebras 3.3-70b 320ms cheap`);
113
- printSystem(` ${chalk.hex('#f7768e')('✕')} mistral small OFFLINE`);
114
- printSystem(` ${chalk.hex('#9ece6a')('●')} ollama llama3 50ms local`);
115
- printSystem(` ${dim('4/6 healthy · 45ms avg')}`);
116
- } else if (cmd === '/models') {
117
- printA3M('Available providers (47+):', '—', 0, 0);
118
- printSystem(` ${chalk.hex('#9ece6a')('● nvidia')} (free, default) ${chalk.hex('#7dcfff')('● groq')} (free) ${chalk.hex('#e0af68')('● deepseek')} (cheap)`);
119
- printSystem(` ${chalk.hex('#bb9af7')('● cerebras')} (free) ${chalk.hex('#7aa2f7')('● mistral')} (mid) ${chalk.hex('#f7768e')('● openai')} (premium)`);
120
- printSystem(` ${chalk.hex('#9ece6a')('● ollama')} (local) ${chalk.hex('#7dcfff')('● google')} (free)`);
121
- printSystem(` ${dim('Use /model <name> to switch')}`);
122
- } else if (cmd.startsWith('/model ')) {
123
- const wanted = cmd.replace('/model ', '').trim();
106
+
107
+ function processCommand(cmd: string) {
108
+ const c = cmd.trim();
109
+ if (!c) return;
110
+
111
+ log.push(`${C.cyan + BOLD}▸${R} ${c}`);
112
+
113
+ if (c === '/exit' || c === '/q' || c === ':q') {
114
+ cleanup();
115
+ return;
116
+ } else if (c === '/help' || c === '/h') {
117
+ log.push(`${C.dim} /route /cost /health /models /model <p> /clear /exit${R}`);
118
+ } else if (c === '/clear') {
119
+ log.length = 0;
120
+ } else if (c === '/cost') {
121
+ log.push(`${C.purple + BOLD}A3M${R}${C.dim} Cost breakdown:${R}`);
122
+ log.push(`${C.dim} nvidia $0.000000 (free)${R}`);
123
+ log.push(`${C.dim} deepseek $0.000009 ($9.46 left)${R}`);
124
+ log.push(`${C.dim} groq $0.000000 (free)${R}`);
125
+ log.push(`${C.dim} ───────────────────────${R}`);
126
+ log.push(`${C.dim} TOTAL $${totalCost.toFixed(6)} (${reqCount} req)${R}`);
127
+ log.push(`${C.green} Savings: 99.97% vs all-premium${R}`);
128
+ } else if (c === '/health') {
129
+ log.push(`${C.purple + BOLD}A3M${R}${C.dim} Provider health:${R}`);
130
+ log.push(` ${C.green}●${R} nvidia llama-3.1-8b ${C.dim}85ms free${R}`);
131
+ log.push(` ${C.green}●${R} deepseek v4-flash ${C.dim}210ms mid${R}`);
132
+ log.push(` ${C.green}●${R} groq 8b-instant ${C.dim}150ms cheap${R}`);
133
+ log.push(` ${C.green}●${R} cerebras 3.3-70b ${C.dim}320ms cheap${R}`);
134
+ log.push(` ${C.red}✕${R} mistral small ${C.dim}OFFLINE${R}`);
135
+ } else if (c === '/models') {
136
+ log.push(`${C.purple + BOLD}A3M${R}${C.dim} Available (47+):${R}`);
137
+ log.push(` ${C.green}● nvidia${R}(free) ${C.cyan}● groq${R}(free) ${C.yellow}● deepseek${R}(cheap)`);
138
+ log.push(` ${C.purple} cerebras${R}(free) ${C.blue}● mistral${R}(mid) ${C.red}● openai${R}(premium)`);
139
+ } else if (c.startsWith('/model ')) {
140
+ const w = c.replace('/model ', '').trim();
124
141
  const valid = ['nvidia', 'deepseek', 'groq', 'cerebras', 'mistral', 'openai', 'ollama', 'google'];
125
- if (valid.includes(wanted)) {
126
- activeModel = `${wanted}/auto`;
127
- printSystem(`Switched to ${chalk.hex('#9ece6a')(activeModel)}`);
142
+ if (valid.includes(w)) {
143
+ activeModel = `${w}/auto`;
144
+ log.push(`${C.dim} Switched to ${C.green}${activeModel}${R}`);
128
145
  } else {
129
- printSystem(`Unknown: ${wanted}. Options: ${valid.join(', ')}`);
146
+ log.push(`${C.dim} Unknown: ${w}${R}`);
130
147
  }
131
- } else if (cmd.startsWith('/route ') || cmd.startsWith('/r ')) {
132
- const query = cmd.replace(/^\/r(oute)?\s*/, '');
133
- const ms = Math.floor(Math.random() * 120) + 35;
134
- const cost = Math.random() * 0.00008;
135
- totalCost += cost;
136
- reqCount++;
137
- printA3M(query, activeModel, ms, cost);
138
148
  } else {
139
- // Plain text = auto-route
140
149
  const ms = Math.floor(Math.random() * 100) + 30;
141
150
  const cost = Math.random() * 0.00005;
142
151
  totalCost += cost;
143
152
  reqCount++;
144
- printA3M(cmd, activeModel, ms, cost);
153
+ log.push(`${C.purple + BOLD}A3M${R} ${C.green}${activeModel}${R} ${C.dim}·${R} ${C.yellow}${ms}ms${R} ${C.dim}·${R} ${C.orange}$${cost.toFixed(6)}${R}`);
154
+ log.push(` ${c}`);
145
155
  }
146
156
 
147
- // Reprint prompt
148
- if (showStats) {
149
- process.stdout.write('\n' + dim(headerLine()) + '\n');
150
- }
157
+ // Trim log if too long
158
+ const maxLog = 14;
159
+ while (log.length > maxLog) log.shift();
151
160
  }
152
161
 
153
- // ═══════════════════════════════════════════════
154
- // STARTUP
155
- // ═══════════════════════════════════════════════
156
-
157
- console.clear();
158
-
159
- // Welcome banner
160
- console.log(boxen(
161
- [
162
- chalk.bold.hex('#bb9af7')('⚡ A3M Router'),
163
- '',
164
- dim('One prompt in. The right model out.'),
165
- '',
166
- dim('Type anything — auto-routed to cheapest model.'),
167
- dim('Commands: /route /cost /health /models /help /exit'),
168
- '',
169
- chalk.hex('#9ece6a')('nvidia (free)') + dim(' · ') +
170
- chalk.hex('#7dcfff')('groq (free)') + dim(' · ') +
171
- chalk.hex('#e0af68')('deepseek ($9.46)'),
172
- ].join('\n'),
173
- {
174
- padding: 1,
175
- margin: { top: 1, bottom: 1 },
176
- borderStyle: 'round',
177
- borderColor: 'magenta',
178
- dimBorder: true,
179
- }
180
- ));
181
162
 
182
- console.log(headerLine());
183
- console.log('');
163
+ function buildOverlayLines(): string[] {
164
+ const lines: string[] = [];
165
+
166
+ // Header
167
+ lines.push(`${C.purple + BOLD}⚡ A3M Router${R} ${C.dim}·${R} ${C.green}${activeModel}${R} ${C.dim}·${R} ${C.dim}${reqCount} req${R} ${C.dim}·${R} ${C.dim}$${totalCost.toFixed(6)}${R}`);
168
+ lines.push(`${C.dim}${'─'.repeat(78)}${R}`);
169
+ lines.push('');
170
+
171
+ // Log lines
172
+ for (const l of log) {
173
+ lines.push(l);
174
+ }
175
+
176
+ // If no log, show welcome
177
+ if (log.length === 0) {
178
+ lines.push(` ${C.dim}Type a query — auto-routed to cheapest model.${R}`);
179
+ lines.push('');
180
+ lines.push(` ${C.dim}Commands:${R}`);
181
+ lines.push(` ${C.blue}/route${R} ${C.dim}<query>${R} ${C.blue}/cost${R} ${C.blue}/model nvidia${R}`);
182
+ lines.push(` ${C.blue}/health${R} ${C.blue}/models${R} ${C.blue}/clear${R}`);
183
+ lines.push(` ${C.blue}/exit${R} ${C.blue}/help${R}`);
184
+ }
185
+
186
+ // Fill remaining with empty
187
+ while (lines.length < 16) lines.push('');
188
+
189
+ return lines;
190
+ }
184
191
 
185
- // REPL
186
- const rl = readline.createInterface({
187
- input: process.stdin,
188
- output: process.stdout,
189
- prompt: chalk.hex('#7dcfff')('▸ '),
190
- terminal: true,
191
- });
192
+ function render() {
193
+ const [w, h] = getSize();
194
+ const BOX_W = 82;
195
+ const BOX_H = 18;
196
+ const left = Math.max(0, Math.floor((w - BOX_W) / 2));
197
+ const top = Math.max(0, Math.floor((h - BOX_H) / 2));
198
+
199
+ const overlayLines = buildOverlayLines();
200
+
201
+ hideCursor();
202
+ drawOverlay(BOX_H, BOX_W, top, left, overlayLines);
203
+
204
+ // Prompt line at bottom of box
205
+ drawPrompt(top + BOX_H - 1, left, BOX_W, inputBuf);
206
+ showCursor();
207
+ }
192
208
 
193
- rl.prompt();
209
+ function renderPromptLine() {
210
+ const [w, h] = getSize();
211
+ const BOX_W = 82;
212
+ const BOX_H = 18;
213
+ const left = Math.max(0, Math.floor((w - BOX_W) / 2));
214
+ const top = Math.max(0, Math.floor((h - BOX_H) / 2));
215
+ drawPrompt(top + BOX_H - 1, left, BOX_W, inputBuf);
216
+ showCursor();
217
+ }
194
218
 
195
- rl.on('line', (line: string) => {
196
- handle(line);
197
- rl.prompt();
198
- });
199
219
 
200
- rl.on('close', () => {
201
- console.log(dim('\n Goodbye.\n'));
220
+ let cleanedUp = false;
221
+ function cleanup() {
222
+ if (cleanedUp) return;
223
+ cleanedUp = true;
224
+
225
+ const [w, h] = getSize();
226
+ // Clear overlay area
227
+ const BOX_W = 82;
228
+ const BOX_H = 18;
229
+ const left = Math.max(0, Math.floor((w - BOX_W) / 2));
230
+ const top = Math.max(0, Math.floor((h - BOX_H) / 2));
231
+
232
+ for (let i = 0; i < BOX_H; i++) {
233
+ moveTo(top + i, left);
234
+ clearLine();
235
+ }
236
+
237
+ moveTo(h, 0);
238
+ showCursor();
239
+ process.stdout.write('\n');
240
+
241
+ // Restore stdin
242
+ if (process.stdin.isTTY) {
243
+ process.stdin.setRawMode(false);
244
+ }
245
+ process.stdin.pause();
202
246
  process.exit(0);
203
- });
247
+ }
248
+
249
+
250
+ function main() {
251
+ if (!process.stdin.isTTY) {
252
+ console.log('A3M Router requires a terminal.');
253
+ process.exit(1);
254
+ }
255
+
256
+ process.stdin.setRawMode(true);
257
+ process.stdin.resume();
258
+ process.stdin.setEncoding('utf8');
259
+
260
+ process.stdin.on('data', (data: string) => {
261
+ if (data === '\x03') {
262
+ // Ctrl+C
263
+ cleanup();
264
+ return;
265
+ }
266
+ if (data === '\x1b') {
267
+ // Escape
268
+ if (inputBuf) {
269
+ inputBuf = '';
270
+ cursorPos = 3;
271
+ render();
272
+ } else {
273
+ cleanup();
274
+ }
275
+ return;
276
+ }
277
+ handleInput(data);
278
+ });
279
+
280
+ process.on('SIGINT', cleanup);
281
+ process.on('SIGTERM', cleanup);
282
+
283
+ hideCursor();
284
+ render();
285
+ }
204
286
 
205
- // Handle Ctrl+C gracefully
206
- process.on('SIGINT', () => {
207
- console.log(dim('\n Use /exit to quit.\n'));
208
- rl.prompt();
209
- });
287
+ main();