openaxies 0.5.1 → 0.5.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openaxies",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/App.js CHANGED
@@ -10,32 +10,43 @@ const h = React.createElement;
10
10
 
11
11
  export default AppRoot;
12
12
 
13
+ const LOGO = [
14
+ ' \u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588\u2588 \u2588 \u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588',
15
+ '\u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 ',
16
+ '\u2588 \u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588\u2588\u2588\u2588 \u2588\u2588\u2588',
17
+ '\u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588',
18
+ ' \u2588\u2588\u2588 \u2588 \u2588\u2588\u2588\u2588\u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588 \u2588\u2588\u2588\u2588\u2588 \u2588\u2588\u2588 ',
19
+ ];
20
+
21
+ const LOGO_COLORS = ['#00F0FF', '#00DDFF', '#00CCFF', '#00BBFF', '#00AAFF'];
22
+
13
23
  function buildHistory(messages, newText) {
14
- const history = [];
24
+ const h = [];
15
25
  for (let i = 0; i < messages.length; i++) {
16
26
  const m = messages[i];
17
27
  if (m === null || m === undefined || typeof m !== 'object') continue;
18
28
  if (m.role === 'user' || m.role === 'assistant') {
19
- const content = typeof m.content === 'string' ? m.content : '';
20
- history.push({ role: m.role, content: content });
29
+ const c = typeof m.content === 'string' ? m.content : '';
30
+ h.push({ role: m.role, content: c });
21
31
  }
22
32
  }
23
33
  if (typeof newText === 'string' && newText.length > 0) {
24
- history.push({ role: 'user', content: newText });
34
+ h.push({ role: 'user', content: newText });
25
35
  }
26
- return history;
36
+ return h;
27
37
  }
28
38
 
29
- function formatTimer(seconds) {
30
- if (typeof seconds !== 'number' || seconds < 0) return '0.0s';
31
- return seconds.toFixed(1) + 's';
39
+ function formatTimer(s) {
40
+ if (typeof s !== 'number' || s < 0) return '0.0s';
41
+ return s.toFixed(1) + 's';
32
42
  }
33
43
 
34
- function hr(cols) {
44
+ function hr(cols, color) {
35
45
  const n = typeof cols === 'number' && cols > 0 ? cols : 80;
46
+ const c = typeof color === 'string' ? color : '#1A1A28';
36
47
  let s = '';
37
48
  for (let i = 0; i < n; i++) s = s + '\u2500';
38
- return h(Text, { color: '#1A1A28' }, s);
49
+ return h(Text, { color: c }, s);
39
50
  }
40
51
 
41
52
  const SPINNER = ['\u25CB', '\u25D4', '\u25D0', '\u25D5', '\u25CF', '\u25D5', '\u25D0', '\u25D4'];
@@ -58,8 +69,9 @@ function AppRoot() {
58
69
  const [toolInfo, setToolInfo] = React.useState(null);
59
70
 
60
71
  const commands = getCommands();
72
+ const LOGO_H = 5;
61
73
  const overlayH = showOverlay ? 6 : 0;
62
- const fixedH = 1 + overlayH + DOCK_HEIGHT;
74
+ const fixedH = LOGO_H + overlayH + DOCK_HEIGHT;
63
75
  const availLines = Math.max(1, rows - fixedH);
64
76
 
65
77
  const abortRef = React.useRef(null);
@@ -124,12 +136,10 @@ function AppRoot() {
124
136
  async function handleSubmit(text) {
125
137
  const safe = typeof text === 'string' ? text : '';
126
138
  if (safe.length === 0 || streamingActive === true) return;
127
-
128
139
  setStreamingActive(true);
129
140
  setToolInfo(null);
130
141
  setStreamText(' connecting');
131
142
  setThinkingElapsed(0);
132
-
133
143
  connRef.current = setInterval(function () {
134
144
  setStreamText(function (p) {
135
145
  if (p === ' connecting') return ' connecting.';
@@ -138,52 +148,36 @@ function AppRoot() {
138
148
  return ' connecting';
139
149
  });
140
150
  }, 400);
141
-
142
151
  setMessages(function (p) {
143
152
  return p.concat([{ role: 'user', content: safe, id: 'u-' + Date.now() }]);
144
153
  });
145
154
  setInputBuffer('');
146
-
147
155
  const modelInfo = getModelById(activeModel);
148
156
  if (modelInfo === null) {
149
- if (connRef.current !== null) {
150
- clearInterval(connRef.current);
151
- connRef.current = null;
152
- }
157
+ if (connRef.current !== null) clearInterval(connRef.current), connRef.current = null;
153
158
  setStreamingActive(false);
154
159
  setStreamText('');
155
- setMessages(function (p) {
156
- return p.concat([{ role: 'assistant', content: 'No model selected. Use /model.', id: 'e-' + Date.now() }]);
157
- });
160
+ setMessages(function (p) { return p.concat([{ role: 'assistant', content: 'No model selected. Use /model.', id: 'e-' + Date.now() }]); });
158
161
  return;
159
162
  }
160
-
161
163
  const history = buildHistory(messages, safe);
162
164
  const abortController = new AbortController();
163
165
  abortRef.current = abortController;
164
-
165
166
  try {
166
167
  const gen = callModel(modelInfo, history, abortController.signal);
167
168
  let accumulated = '';
168
169
  let firstEvent = true;
169
170
  let thinkStarted = false;
170
-
171
171
  for await (const event of gen) {
172
172
  if (abortController.signal.aborted === true) break;
173
-
174
173
  if (firstEvent === true) {
175
174
  firstEvent = false;
176
- if (connRef.current !== null) {
177
- clearInterval(connRef.current);
178
- connRef.current = null;
179
- }
175
+ if (connRef.current !== null) clearInterval(connRef.current), connRef.current = null;
180
176
  }
181
-
182
177
  if (event.type === 'tool') {
183
178
  setToolInfo({ tool: event.tool, used: event.used, sites: event.sites, query: event.query });
184
179
  continue;
185
180
  }
186
-
187
181
  if (event.type === 'thinking' || event.type === 'token') {
188
182
  const content = typeof event.content === 'string' ? event.content : '';
189
183
  for (let i = 0; i < content.length; i++) {
@@ -204,53 +198,33 @@ function AppRoot() {
204
198
  await new Promise(function (r) { setTimeout(r, 0); });
205
199
  }
206
200
  }
207
-
208
201
  if (event.type === 'done') break;
209
202
  if (event.type === 'timeout') {
210
- if (accumulated.length > 0) {
211
- accumulated = accumulated + '\n\n\u2014 stream timed out \u2014';
212
- }
203
+ if (accumulated.length > 0) accumulated = accumulated + '\n\n\u2014 stream timed out \u2014';
213
204
  setStreamText(accumulated);
214
205
  break;
215
206
  }
216
207
  }
217
-
218
- if (connRef.current !== null) {
219
- clearInterval(connRef.current);
220
- connRef.current = null;
221
- }
208
+ if (connRef.current !== null) clearInterval(connRef.current), connRef.current = null;
222
209
  setIsThinking(false);
223
210
  thinkStartRef.current = null;
224
211
  setThinkingElapsed(0);
225
212
  setStreamingActive(false);
226
-
227
213
  const finalText = streamText;
228
214
  setStreamText('');
229
-
230
215
  if (finalText.length > 0) {
231
- setMessages(function (p) {
232
- return p.concat([{ role: 'assistant', content: finalText, id: 'a-' + Date.now() }]);
233
- });
216
+ setMessages(function (p) { return p.concat([{ role: 'assistant', content: finalText, id: 'a-' + Date.now() }]); });
234
217
  }
235
218
  } catch (err) {
236
- if (connRef.current !== null) {
237
- clearInterval(connRef.current);
238
- connRef.current = null;
239
- }
219
+ if (connRef.current !== null) clearInterval(connRef.current), connRef.current = null;
240
220
  setIsThinking(false);
241
221
  thinkStartRef.current = null;
242
222
  setThinkingElapsed(0);
243
223
  setStreamingActive(false);
244
224
  setStreamText('');
245
- const errMsg = err !== null && err !== undefined
246
- ? (err.message || String(err))
247
- : 'Unknown error';
225
+ const errMsg = err !== null && err !== undefined ? (err.message || String(err)) : 'Unknown error';
248
226
  setMessages(function (p) {
249
- return p.concat([{
250
- role: 'assistant',
251
- content: 'Error: ' + errMsg + '\n\nSpace cold-starting? Try again.',
252
- id: 'er-' + Date.now(),
253
- }]);
227
+ return p.concat([{ role: 'assistant', content: 'Error: ' + errMsg + '\n\nSpace cold-starting? Try again.', id: 'er-' + Date.now() }]);
254
228
  });
255
229
  }
256
230
  }
@@ -258,13 +232,8 @@ function AppRoot() {
258
232
  function handleChange(v) {
259
233
  const s = typeof v === 'string' ? v : '';
260
234
  setInputBuffer(s);
261
- if (s.length === 1 && s[0] === '/' && showOverlay === false) {
262
- setShowOverlay(true);
263
- setOverlayIndex(0);
264
- }
265
- if (showOverlay === true && (s.length === 0 || s[0] !== '/')) {
266
- setShowOverlay(false);
267
- }
235
+ if (s.length === 1 && s[0] === '/' && showOverlay === false) { setShowOverlay(true); setOverlayIndex(0); }
236
+ if (showOverlay === true && (s.length === 0 || s[0] !== '/')) { setShowOverlay(false); }
268
237
  }
269
238
 
270
239
  function handleCmd(item) {
@@ -275,9 +244,7 @@ function AppRoot() {
275
244
  if (t === '/clear') setMessages([]);
276
245
  if (t === '/model') cycleModel();
277
246
  if (t === '/help') {
278
- setMessages(function (p) {
279
- return p.concat([{ role: 'assistant', content: 'Commands: /help /clear /model /exit', id: 'h-' + Date.now() }]);
280
- });
247
+ setMessages(function (p) { return p.concat([{ role: 'assistant', content: 'Commands: /help /clear /model /exit', id: 'h-' + Date.now() }]); });
281
248
  }
282
249
  setInputBuffer('');
283
250
  setShowOverlay(false);
@@ -286,48 +253,33 @@ function AppRoot() {
286
253
 
287
254
  useInput(function handleInput(input, key) {
288
255
  if (showOverlay === true) {
289
- if (key.escape === true) {
290
- setShowOverlay(false);
291
- setInputBuffer('');
292
- setOverlayIndex(0);
293
- return;
294
- }
295
- if (key.upArrow === true) {
296
- setOverlayIndex(function (p) { return p > 0 ? p - 1 : commands.length - 1; });
297
- return;
298
- }
299
- if (key.downArrow === true) {
300
- setOverlayIndex(function (p) { return p < commands.length - 1 ? p + 1 : 0; });
301
- return;
302
- }
303
- if (key.return === true) {
304
- const cmd = commands[overlayIndex];
305
- if (cmd !== null && cmd !== undefined) handleCmd({ value: cmd.trigger });
306
- return;
307
- }
256
+ if (key.escape === true) { setShowOverlay(false); setInputBuffer(''); setOverlayIndex(0); return; }
257
+ if (key.upArrow === true) { setOverlayIndex(function (p) { return p > 0 ? p - 1 : commands.length - 1; }); return; }
258
+ if (key.downArrow === true) { setOverlayIndex(function (p) { return p < commands.length - 1 ? p + 1 : 0; }); return; }
259
+ if (key.return === true) { const cmd = commands[overlayIndex]; if (cmd !== null && cmd !== undefined) handleCmd({ value: cmd.trigger }); return; }
308
260
  return;
309
261
  }
310
-
311
262
  if (key.return === true) {
312
263
  const s = typeof inputBuffer === 'string' ? inputBuffer : '';
313
264
  if (s.length > 0 && streamingActive === false) handleSubmit(s);
314
265
  return;
315
266
  }
316
-
317
267
  if (key.ctrl === true && (input === 'c' || input === 'C')) {
318
- if (abortRef.current !== null) {
319
- try { abortRef.current.abort(); } catch (_) {}
320
- abortRef.current = null;
321
- setStreamingActive(false);
322
- setStreamText('');
323
- }
268
+ if (abortRef.current !== null) { try { abortRef.current.abort(); } catch (_) {} abortRef.current = null; setStreamingActive(false); setStreamText(''); }
324
269
  process.exit(0);
325
270
  }
326
271
  });
327
272
 
328
273
  const activeInfo = getModelById(activeModel);
329
274
  const activeLabel = activeInfo !== null ? activeInfo.label : 'OpenAxies';
330
- const activeBadge = activeInfo !== null ? activeInfo.badge : '';
275
+
276
+ const logoEls = [];
277
+ for (let r = 0; r < LOGO.length; r++) {
278
+ logoEls.push(
279
+ h(Text, { key: 'l' + r, color: LOGO_COLORS[r % LOGO_COLORS.length], bold: true }, LOGO[r])
280
+ );
281
+ }
282
+ const logo = h(Box, { flexDirection: 'column', width: '100%', flexShrink: 0, paddingLeft: 1 }, ...logoEls);
331
283
 
332
284
  const viewLines = [];
333
285
  for (let i = 0; i < messages.length; i++) {
@@ -335,11 +287,8 @@ function AppRoot() {
335
287
  if (msg === null || typeof msg !== 'object') continue;
336
288
  const content = typeof msg.content === 'string' ? msg.content : '';
337
289
  if (content.length === 0) continue;
338
-
339
290
  if (msg.role === 'user') {
340
- if (i > 0) viewLines.push({ t: 'sep' });
341
- viewLines.push({ t: 'user', text: content });
342
- viewLines.push({ t: 'sep' });
291
+ viewLines.push({ t: 'user', text: '\u25B7 ' + content });
343
292
  } else {
344
293
  viewLines.push({ t: 'text', text: content });
345
294
  }
@@ -347,7 +296,6 @@ function AppRoot() {
347
296
 
348
297
  const hasStream = typeof streamText === 'string' && streamText.length > 0;
349
298
  if (hasStream === true) {
350
- viewLines.push({ t: 'sep' });
351
299
  if (toolInfo !== null && toolInfo.used === true && toolInfo.query.length > 0) {
352
300
  viewLines.push({ t: 'tool', text: '\u2500\u2500 ' + toolInfo.tool + ': "' + toolInfo.query + '" (' + toolInfo.sites + ' sites)' });
353
301
  }
@@ -362,7 +310,7 @@ function AppRoot() {
362
310
  }
363
311
 
364
312
  if (viewLines.length === 0) {
365
- viewLines.push({ t: 'idle', text: ' start typing to chat...' });
313
+ viewLines.push({ t: 'idle', text: ' \u25B8 type a message to begin... [/help for commands]' });
366
314
  }
367
315
 
368
316
  const visible = Math.max(1, availLines - 1);
@@ -371,23 +319,21 @@ function AppRoot() {
371
319
 
372
320
  for (let i = 0; i < display.length; i++) {
373
321
  const l = display[i];
374
- if (l.t === 'sep') {
375
- viewEls.push(h(Box, { key: 's-' + i, height: 1 }, hr(cols)));
376
- } else if (l.t === 'think') {
322
+ if (l.t === 'think') {
377
323
  viewEls.push(
378
- h(Box, { key: 'k-' + i, height: 1, paddingLeft: 1 },
379
- h(Text, { color: '#FF9F43', bold: true }, ' ' + l.spin + ' Thinking \u2022 ' + l.elapsed)
324
+ h(Box, { key: 'k-' + i, height: 1, paddingLeft: 2 },
325
+ h(Text, { color: '#FF9F43', bold: true }, l.spin + ' Thinking \u2022 ' + l.elapsed)
380
326
  )
381
327
  );
382
328
  } else if (l.t === 'think-text') {
383
329
  viewEls.push(
384
- h(Box, { key: 'kt-' + i, height: 1, paddingLeft: 2 },
330
+ h(Box, { key: 'kt-' + i, height: 1, paddingLeft: 3 },
385
331
  h(Text, { color: '#FF9F43' }, l.text)
386
332
  )
387
333
  );
388
334
  } else if (l.t === 'tool') {
389
335
  viewEls.push(
390
- h(Box, { key: 'tl-' + i, height: 1, paddingLeft: 1 },
336
+ h(Box, { key: 'tl-' + i, height: 1, paddingLeft: 2 },
391
337
  h(Text, { color: '#5B5B8A' }, l.text)
392
338
  )
393
339
  );
@@ -399,14 +345,14 @@ function AppRoot() {
399
345
  );
400
346
  } else if (l.t === 'text') {
401
347
  viewEls.push(
402
- h(Box, { key: 'a-' + i, height: 1, paddingLeft: 1 },
348
+ h(Box, { key: 'a-' + i, height: 1, paddingLeft: 2 },
403
349
  h(Text, { color: hex.primary }, l.text)
404
350
  )
405
351
  );
406
352
  } else if (l.t === 'idle') {
407
353
  viewEls.push(
408
354
  h(Box, { key: 'i-' + i, height: 1, paddingLeft: 1 },
409
- h(Text, { color: '#333355' }, l.text)
355
+ h(Text, { color: '#444466' }, l.text)
410
356
  )
411
357
  );
412
358
  }
@@ -417,12 +363,11 @@ function AppRoot() {
417
363
  height: availLines,
418
364
  flexDirection: 'column',
419
365
  overflow: 'hidden',
420
- paddingBottom: 1,
366
+ paddingTop: 0,
367
+ paddingBottom: 0,
421
368
  }, ...viewEls);
422
369
 
423
- const slashOverlay = showOverlay === true
424
- ? createSlashOverlay(commands, overlayIndex)
425
- : null;
370
+ const slashOverlay = showOverlay === true ? createSlashOverlay(commands, overlayIndex) : null;
426
371
 
427
372
  const dock = createComposerDock({
428
373
  value: inputBuffer,
@@ -442,7 +387,8 @@ function AppRoot() {
442
387
  backgroundColor: hex.black,
443
388
  overflow: 'hidden',
444
389
  },
445
- h(Box, { height: 1 }, hr(cols)),
390
+ logo,
391
+ h(Box, { height: 1 }, hr(cols, '#1A1A2E')),
446
392
  viewport,
447
393
  slashOverlay,
448
394
  dock
@@ -5,7 +5,7 @@ import { hex } from '../config/theme.js';
5
5
 
6
6
  const h = React.createElement;
7
7
 
8
- export const DOCK_HEIGHT = 3;
8
+ export const DOCK_HEIGHT = 4;
9
9
 
10
10
  const PROMPT = '> ';
11
11
 
@@ -21,8 +21,10 @@ export function createComposerDock(config) {
21
21
  const isStreaming = config.isStreaming === true;
22
22
  const modelLabel = typeof config.modelLabel === 'string' ? config.modelLabel : '';
23
23
  const modelStatus = config.modelStatus === true;
24
+ const safeCols = typeof config.terminalWidth === 'number' && config.terminalWidth > 0 ? config.terminalWidth : 80;
24
25
 
25
26
  const placeholder = isStreaming ? 'Ctrl+C to interrupt...' : 'type a message...';
27
+ const innerW = safeCols - 2;
26
28
 
27
29
  return h(Box, {
28
30
  width: '100%',
@@ -30,8 +32,12 @@ export function createComposerDock(config) {
30
32
  flexDirection: 'column',
31
33
  flexShrink: 0,
32
34
  },
35
+ h(Box, { height: 1, paddingLeft: 1 },
36
+ h(Text, { color: '#1A1A28' }, '\u2500'.repeat(innerW))
37
+ ),
33
38
  h(Box, { height: 1, paddingLeft: 1, paddingRight: 1 },
34
- h(Text, { color: inputActive ? hex.primary : '#444466' }, PROMPT),
39
+ h(Text, { color: hex.border }, '\u2502'),
40
+ h(Text, { color: inputActive ? hex.neonBlue : '#444466', bold: true }, ' ' + PROMPT),
35
41
  h(Box, { flexGrow: 1, height: 1, overflow: 'hidden' },
36
42
  h(TextInput, {
37
43
  value: value,
@@ -42,13 +48,19 @@ export function createComposerDock(config) {
42
48
  showCursor: true,
43
49
  })
44
50
  ),
45
- h(Text, { color: '#444466' }, ' '),
46
- h(Text, { color: modelStatus ? hex.greenOnline : '#444466', bold: modelStatus }, modelLabel || '')
51
+ h(Text, { color: '#444466' }, ' '),
52
+ h(Text, { color: hex.border }, '\u2502')
47
53
  ),
48
54
  h(Box, { height: 1, paddingLeft: 1, paddingRight: 1 },
49
- h(Text, { color: '#333344' }, '/help /clear /model /exit'),
55
+ h(Text, { color: hex.border }, '\u2514'),
56
+ h(Box, { flexGrow: 1, height: 1, overflow: 'hidden' },
57
+ h(Text, { color: '#333344' }, '\u2500'.repeat(innerW - 2))
58
+ ),
59
+ h(Text, { color: hex.border }, '\u2518')
60
+ ),
61
+ h(Box, { height: 1, paddingRight: 1 },
50
62
  h(Box, { flexGrow: 1 }),
51
- h(Text, { color: '#333344' }, isStreaming ? 'Ctrl+C to stop' : '')
63
+ h(Text, { color: '#444466', bold: modelStatus }, modelLabel || '')
52
64
  )
53
65
  );
54
66
  }