adaptive-memory-multi-model-router 2.13.11 → 2.13.13

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,302 +1,130 @@
1
1
  #!/usr/bin/env node
2
2
  /**
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.
3
+ * A3M Router — Overlay Box (blessed, non-fullscreen)
7
4
  */
8
5
 
9
- import * as readline from 'readline';
10
-
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
-
6
+ import * as blessed from 'blessed';
32
7
 
8
+ // State
33
9
  let activeModel = 'nvidia/llama-3.1-8b';
34
10
  let totalCost = 0.000087;
35
11
  let reqCount = 4;
36
12
  const log: string[] = [];
37
13
 
14
+ // Screen — floating overlay, not fullscreen
15
+ const screen = blessed.screen({
16
+ smartCSR: true,
17
+ fullUnicode: true,
18
+ dockBorders: false,
19
+ cursor: { shape: 'line', blink: true },
20
+ });
21
+
22
+ // Box settings
23
+ const BW = 82;
24
+ const BH = 18;
25
+
26
+ function boxLeft() { return Math.max(0, Math.floor(((screen.width as number) - BW) / 2)); }
27
+ function boxTop() { return Math.max(0, Math.floor(((screen.height as number) - BH) / 2)); }
28
+
29
+ // Overlay box
30
+ const box = blessed.box({
31
+ top: boxTop(),
32
+ left: boxLeft(),
33
+ width: BW,
34
+ height: BH,
35
+ border: { type: 'line', fg: 'magenta' },
36
+ style: { fg: '#c0caf5', bg: '#1a1b26' },
37
+ tags: true,
38
+ scrollable: true,
39
+ mouse: true,
40
+ keys: true,
41
+ padding: { left: 1, right: 1, top: 0, bottom: 0 },
42
+ });
43
+
44
+ // Prompt
45
+ const prompt = blessed.textbox({
46
+ parent: box,
47
+ bottom: 1,
48
+ left: 0,
49
+ width: BW - 4,
50
+ height: 1,
51
+ style: { fg: '#c0caf5', bg: '#24283b' },
52
+ inputOnFocus: true,
53
+ keys: true,
54
+ tags: true,
55
+ });
56
+
57
+ // Helpers
58
+ const D = (s: string) => `{#565f89-fg}${s}{/}`;
38
59
 
39
- function getSize(): [number, number] {
40
- return [process.stdout.columns || 80, process.stdout.rows || 24];
41
- }
42
-
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
- function stripAnsi(s: string): string {
51
- return s.replace(/\x1b\[[0-9;]*m/g, '');
52
- }
53
-
54
- const B = { tl: '╭', tr: '╮', bl: '╰', br: '╯', h: '─', v: '│' };
60
+ function render() {
61
+ const maxLines = BH - 4;
62
+ const visible = log.slice(-maxLines);
63
+
64
+ let out = '';
65
+ out += `{bold}{#bb9af7-fg}⚡ A3M Router{/} ${D('·')} {#9ece6a-fg}${activeModel}{/} ${D('·')} ${D(`${reqCount} req`)} ${D('·')} ${D(`$${totalCost.toFixed(6)}`)}\n`;
66
+ out += `${D('─'.repeat(BW - 6))}\n`;
67
+ out += '\n';
55
68
 
56
- let inputBuf = '';
57
- let cursorPos = 3;
69
+ for (const line of visible) {
70
+ out += line + '\n';
71
+ }
58
72
 
59
- function handleInput(char: string) {
60
- if (char === '\r' || char === '\n') {
61
- // Submit
62
- const cmd = inputBuf.trim();
63
- processCommand(cmd);
64
- inputBuf = '';
65
- cursorPos = 3;
66
- render();
67
- } else if (char === '\x7f' || char === '\b') {
68
- // Backspace
69
- if (inputBuf.length > 0) {
70
- inputBuf = inputBuf.slice(0, -1);
71
- cursorPos = Math.max(3, cursorPos - 1);
72
- renderPromptLine();
73
- }
74
- } else if (char === '\x1b') {
75
- // Escape — handled separately
76
- } else if (char >= ' ') {
77
- inputBuf += char;
78
- cursorPos++;
79
- renderPromptLine();
73
+ if (visible.length === 0) {
74
+ out += ` ${D('Type a query auto-routed to cheapest model.')}\n\n`;
75
+ out += ` ${D('Commands:')}\n`;
76
+ out += ` {#7aa2f7-fg}/route{/} ${D('<query>')} /cost /model nvidia\n`;
77
+ out += ` {#7aa2f7-fg}/health{/} /models /clear\n`;
78
+ out += ` {#7aa2f7-fg}/exit{/} /help\n\n`;
79
+ out += ` ${D('nvidia (free) · groq (free) · deepseek ($9.46)')}\n`;
80
80
  }
81
- }
82
81
 
82
+ box.setContent(out);
83
+ screen.render();
84
+ }
83
85
 
84
- function processCommand(cmd: string) {
85
- const c = cmd.trim();
86
+ function cmd(c: string) {
86
87
  if (!c) return;
87
-
88
- log.push(`${C.cyan + BOLD}▸${R} ${c}`);
89
-
90
- if (c === '/exit' || c === '/q' || c === ':q') {
91
- cleanup();
92
- return;
93
- } else if (c === '/help' || c === '/h') {
94
- log.push(`${C.dim} /route /cost /health /models /model <p> /clear /exit${R}`);
95
- } else if (c === '/clear') {
96
- log.length = 0;
97
- } else if (c === '/cost') {
98
- log.push(`${C.purple + BOLD}A3M${R}${C.dim} Cost breakdown:${R}`);
99
- log.push(`${C.dim} nvidia $0.000000 (free)${R}`);
100
- log.push(`${C.dim} deepseek $0.000009 ($9.46 left)${R}`);
101
- log.push(`${C.dim} groq $0.000000 (free)${R}`);
102
- log.push(`${C.dim} ───────────────────────${R}`);
103
- log.push(`${C.dim} TOTAL $${totalCost.toFixed(6)} (${reqCount} req)${R}`);
104
- log.push(`${C.green} Savings: 99.97% vs all-premium${R}`);
88
+ log.push(`{bold}{#7dcfff-fg}▸{/} ${c}`);
89
+
90
+ if (c === '/exit' || c === '/q') { screen.destroy(); process.exit(0); }
91
+ else if (c === '/help') log.push(` ${D('/route /cost /health /models /model <p> /clear /exit')}`);
92
+ else if (c === '/clear') log.length = 0;
93
+ else if (c === '/cost') {
94
+ log.push(` {#bb9af7-fg}A3M{/} Cost:`);
95
+ log.push(` ${D('nvidia $0 | deepseek $0.000009 | groq $0 | cerebras $0')}`);
96
+ log.push(` ${D(`TOTAL $${totalCost.toFixed(6)} | ${reqCount} req | 99.97% saved`)}`);
105
97
  } else if (c === '/health') {
106
- log.push(`${C.purple + BOLD}A3M${R}${C.dim} Provider health:${R}`);
107
- log.push(` ${C.green}●${R} nvidia llama-3.1-8b ${C.dim}85ms free${R}`);
108
- log.push(` ${C.green}●${R} deepseek v4-flash ${C.dim}210ms mid${R}`);
109
- log.push(` ${C.green}●${R} groq 8b-instant ${C.dim}150ms cheap${R}`);
110
- log.push(` ${C.green}●${R} cerebras 3.3-70b ${C.dim}320ms cheap${R}`);
111
- log.push(` ${C.red}✕${R} mistral small ${C.dim}OFFLINE${R}`);
98
+ log.push(` {#bb9af7-fg}A3M{/} Health:`);
99
+ log.push(` {#9ece6a-fg}{/} nvidia 85ms {#9ece6a-fg}●{/} deepseek 210ms {#9ece6a-fg}●{/} groq 150ms {#9ece6a-fg}●{/} cerebras 320ms`);
100
+ log.push(` {#f7768e-fg}{/} mistral OFFLINE {#9ece6a-fg}{/} ollama 50ms`);
112
101
  } else if (c === '/models') {
113
- log.push(`${C.purple + BOLD}A3M${R}${C.dim} Available (47+):${R}`);
114
- log.push(` ${C.green}● nvidia${R}(free) ${C.cyan}● groq${R}(free) ${C.yellow}● deepseek${R}(cheap)`);
115
- log.push(` ${C.purple}● cerebras${R}(free) ${C.blue}● mistral${R}(mid) ${C.red}● openai${R}(premium)`);
102
+ log.push(` {#bb9af7-fg}A3M{/} 47+ providers:`);
103
+ log.push(` {#9ece6a-fg}● nvidia{/} (free) {#7dcfff-fg}● groq{/} (free) {#e0af68-fg}● deepseek{/} (cheap) {#bb9af7-fg}● cerebras{/} (free)`);
116
104
  } else if (c.startsWith('/model ')) {
117
105
  const w = c.replace('/model ', '').trim();
118
- const valid = ['nvidia', 'deepseek', 'groq', 'cerebras', 'mistral', 'openai', 'ollama', 'google'];
119
- if (valid.includes(w)) {
120
- activeModel = `${w}/auto`;
121
- log.push(`${C.dim} Switched to ${C.green}${activeModel}${R}`);
122
- } else {
123
- log.push(`${C.dim} Unknown: ${w}${R}`);
124
- }
106
+ const valid = ['nvidia', 'deepseek', 'groq', 'cerebras', 'mistral', 'openai', 'ollama'];
107
+ if (valid.includes(w)) { activeModel = `${w}/auto`; log.push(` ${D(`→ {#9ece6a-fg}${activeModel}{/}`)}`); }
108
+ else log.push(` ${D(`Unknown: ${w}`)}`);
125
109
  } else {
126
110
  const ms = Math.floor(Math.random() * 100) + 30;
127
111
  const cost = Math.random() * 0.00005;
128
- totalCost += cost;
129
- reqCount++;
130
- 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}`);
112
+ totalCost += cost; reqCount++;
113
+ log.push(` {#bb9af7-fg}A3M{/} {#9ece6a-fg}${activeModel}{/} ${D('·')} {#e0af68-fg}${ms}ms{/} ${D('·')} {#ff9e64-fg}$${cost.toFixed(6)}{/}`);
131
114
  log.push(` ${c}`);
132
115
  }
133
116
 
134
- // Trim log if too long
135
- const maxLog = 14;
136
- while (log.length > maxLog) log.shift();
137
- }
138
-
139
-
140
- function buildOverlayLines(boxW: number): string[] {
141
- const contentW = boxW - 4; // inside padding
142
- const lines: string[] = [];
143
-
144
- // Header row
145
- const hdr = `${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}`;
146
- lines.push(hdr.padEnd(contentW));
147
-
148
- // Separator
149
- lines.push(`${C.dim}${'─'.repeat(Math.max(0, contentW))}${R}`);
150
- lines.push('');
151
-
152
- // Log lines
153
- for (const l of log) {
154
- lines.push(l.padEnd(contentW));
155
- }
156
-
157
- // Welcome message if empty
158
- if (log.length === 0) {
159
- lines.push(` ${C.dim}Type a query — auto-routed to cheapest model.${R}`.padEnd(contentW));
160
- lines.push('');
161
- lines.push(` ${C.dim}Commands:${R}`.padEnd(contentW));
162
- lines.push(` ${C.blue}/route${R} ${C.dim}<query>${R} ${C.blue}/cost${R} ${C.blue}/model nvidia${R}`.padEnd(contentW));
163
- lines.push(` ${C.blue}/health${R} ${C.blue}/models${R} ${C.blue}/clear${R}`.padEnd(contentW));
164
- lines.push(` ${C.blue}/exit${R} ${C.blue}/help${R}`.padEnd(contentW));
165
- }
166
-
167
- return lines;
168
- }
169
-
170
- function render() {
171
- const [w, h] = getSize();
172
- const BOX_W = Math.min(82, w - 4);
173
- const BOX_H = 18;
174
- const left = Math.max(0, Math.floor((w - BOX_W) / 2));
175
- const top = Math.max(0, Math.floor((h - BOX_H) / 2));
176
-
177
- const overlayLines = buildOverlayLines(BOX_W);
178
-
179
- hideCursor();
180
-
181
- // Draw the box
182
- const innerW = BOX_W - 2;
183
-
184
- // Top border
185
- moveTo(top, left);
186
- clearLine();
187
- process.stdout.write(C.bg + C.purple + B.tl + B.h.repeat(innerW) + B.tr + R);
188
-
189
- // Content rows (BOX_H - 3 for borders + prompt)
190
- const contentRows = BOX_H - 3;
191
- for (let i = 0; i < contentRows; i++) {
192
- moveTo(top + 1 + i, left);
193
- clearLine();
194
- const content = (overlayLines[i] || '').slice(0, innerW);
195
- const padded = content + ' '.repeat(Math.max(0, innerW - stripAnsi(content).length));
196
- process.stdout.write(C.bg + C.purple + B.v + R + C.bg + padded + C.purple + B.v + R);
197
- }
198
-
199
- // Prompt row (second-to-last)
200
- const promptRow = top + 1 + contentRows;
201
- moveTo(promptRow, left);
202
- clearLine();
203
- const promptText = `${BOLD} ▸ ${R}${inputBuf}`;
204
- const promptPadded = promptText + ' '.repeat(Math.max(0, innerW - stripAnsi(promptText).length));
205
- process.stdout.write(C.bg + C.purple + B.v + R + C.surface + promptPadded + C.purple + B.v + R);
206
- // Cursor position
207
- moveTo(promptRow, left + 2 + stripAnsi(BOLD + ' ▸ ' + R).length + inputBuf.length);
208
-
209
- // Bottom border
210
- moveTo(promptRow + 1, left);
211
- clearLine();
212
- process.stdout.write(C.bg + C.purple + B.bl + B.h.repeat(innerW) + B.br + R);
213
-
214
- showCursor();
215
- }
216
-
217
- function renderPromptLine() {
218
- const [w, h] = getSize();
219
- const BOX_W = Math.min(82, w - 4);
220
- const BOX_H = 18;
221
- const left = Math.max(0, Math.floor((w - BOX_W) / 2));
222
- const top = Math.max(0, Math.floor((h - BOX_H) / 2));
223
- const innerW = BOX_W - 2;
224
- const promptRow = top + 1 + (BOX_H - 3);
225
-
226
- moveTo(promptRow, left);
227
- clearLine();
228
- const promptText = `${BOLD} ▸ ${R}${inputBuf}`;
229
- const promptPadded = promptText + ' '.repeat(Math.max(0, innerW - stripAnsi(promptText).length));
230
- process.stdout.write(C.bg + C.purple + B.v + R + C.surface + promptPadded + C.purple + B.v + R);
231
- moveTo(promptRow, left + 2 + stripAnsi(BOLD + ' ▸ ' + R).length + inputBuf.length);
232
- showCursor();
233
- }
234
-
235
-
236
- let cleanedUp = false;
237
- function cleanup() {
238
- if (cleanedUp) return;
239
- cleanedUp = true;
240
-
241
- const [w, h] = getSize();
242
- const BOX_W = Math.min(82, w - 4);
243
- const BOX_H = 18;
244
- const left = Math.max(0, Math.floor((w - BOX_W) / 2));
245
- const top = Math.max(0, Math.floor((h - BOX_H) / 2));
246
-
247
- for (let i = 0; i < BOX_H; i++) {
248
- moveTo(top + i, left);
249
- clearLine();
250
- }
251
-
252
- moveTo(h, 0);
253
- showCursor();
254
- process.stdout.write('\n');
255
-
256
- // Restore stdin
257
- if (process.stdin.isTTY) {
258
- process.stdin.setRawMode(false);
259
- }
260
- process.stdin.pause();
261
- process.exit(0);
262
- }
263
-
264
-
265
- function main() {
266
- if (!process.stdin.isTTY) {
267
- console.log('A3M Router requires a terminal.');
268
- process.exit(1);
269
- }
270
-
271
- process.stdin.setRawMode(true);
272
- process.stdin.resume();
273
- process.stdin.setEncoding('utf8');
274
-
275
- process.stdin.on('data', (data: string) => {
276
- if (data === '\x03') {
277
- // Ctrl+C
278
- cleanup();
279
- return;
280
- }
281
- if (data === '\x1b') {
282
- // Escape
283
- if (inputBuf) {
284
- inputBuf = '';
285
- cursorPos = 3;
286
- render();
287
- } else {
288
- cleanup();
289
- }
290
- return;
291
- }
292
- handleInput(data);
293
- });
294
-
295
- process.on('SIGINT', cleanup);
296
- process.on('SIGTERM', cleanup);
297
-
298
- hideCursor();
117
+ while (log.length > 25) log.shift();
299
118
  render();
119
+ prompt.focus();
300
120
  }
301
121
 
302
- main();
122
+ // Keys
123
+ screen.key(['C-c', 'escape'], () => { screen.destroy(); process.exit(0); });
124
+ prompt.key('enter', () => { const v = prompt.getValue().trim(); prompt.clearValue(); cmd(v); });
125
+
126
+ // Start
127
+ screen.append(box);
128
+ render();
129
+ prompt.focus();
130
+ screen.render();