openaxies 0.6.0 → 0.7.0

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.6.0",
3
+ "version": "0.7.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/App.js CHANGED
@@ -1,16 +1,22 @@
1
1
  import React from 'react';
2
2
  import { Box, Text, useInput, useStdout } from 'ink';
3
3
  import { hex } from './config/theme.js';
4
-
5
4
  import { getModels, getModelById, DEFAULT_MODEL_ID } from './config/models.js';
6
5
  import { callModel } from './providers/index.js';
7
- import { createBrandHeader, BRAND_HEIGHT } from './components/BrandHeader.js';
6
+ import { createHeaderBar, HEADER_HEIGHT } from './components/BrandHeader.js';
8
7
  import TextInput from 'ink-text-input';
9
8
 
10
9
  const h = React.createElement;
11
-
12
10
  export default AppRoot;
13
11
 
12
+ const STARTUP_LOGO = [
13
+ ' \u2588\u2588\u2588\u2588\u2588\u2588\u2557',
14
+ ' \u2588\u2588\u2594\u2594\u2594\u2594\u2588\u2588\u2557',
15
+ ' \u2588\u2588\u2591 \u2588\u2588\u2591',
16
+ ' \u2588\u2588\u2591 \u2588\u2588\u2591',
17
+ ' \u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2594\u259d',
18
+ ];
19
+
14
20
  function buildHistory(messages, newText) {
15
21
  const h = [];
16
22
  for (let i = 0; i < messages.length; i++) {
@@ -67,11 +73,14 @@ function AppRoot() {
67
73
  const [overlayIndex, setOverlayIndex] = React.useState(0);
68
74
  const [toolInfo, setToolInfo] = React.useState(null);
69
75
  const [showThoughts, setShowThoughts] = React.useState(true);
76
+ const [startupDone, setStartupDone] = React.useState(false);
70
77
 
71
- const STATUS_H = 3;
78
+ const SEP_H = 1;
79
+ const FIXED_H = startupDone ? (HEADER_HEIGHT + SEP_H + 1 + 1) : 0;
72
80
  const DOCK_H = 1;
73
- const fixedH = BRAND_HEIGHT + STATUS_H + DOCK_H;
74
- const availLines = Math.max(10, rows - fixedH);
81
+ const STATUS_H = 1;
82
+ const totalFixed = startupDone ? (HEADER_HEIGHT + SEP_H + DOCK_H + STATUS_H) : 11;
83
+ const availLines = Math.max(10, rows - totalFixed);
75
84
 
76
85
  const abortRef = React.useRef(null);
77
86
  const connRef = React.useRef(null);
@@ -89,9 +98,7 @@ function AppRoot() {
89
98
  }, 100);
90
99
  spinnerRef.current = si;
91
100
  timerRef.current = ti;
92
- return function () {
93
- clearInterval(si); clearInterval(ti);
94
- };
101
+ return function () { clearInterval(si); clearInterval(ti); };
95
102
  }, [isThinking]);
96
103
 
97
104
  function cycleModel() {
@@ -113,9 +120,15 @@ function AppRoot() {
113
120
  return o > c;
114
121
  }
115
122
 
123
+ function filterText(t) {
124
+ if (showThoughts === true) return t;
125
+ return t.split('<think>').join('').split('</think>').join('');
126
+ }
127
+
116
128
  async function handleSubmit(text) {
117
129
  const safe = typeof text === 'string' ? text : '';
118
130
  if (safe.length === 0 || streamingActive === true) return;
131
+ if (startupDone === false) setStartupDone(true);
119
132
  lastQueryRef.current = safe;
120
133
  setStreamingActive(true);
121
134
  setToolInfo(null);
@@ -239,55 +252,44 @@ function AppRoot() {
239
252
  }
240
253
  });
241
254
 
242
- function filterText(t) {
243
- if (showThoughts === true) return t;
244
- return t.split('<think>').join('').split('</think>').join('');
245
- }
246
-
247
- const activeInfo = getModelById(activeModel);
248
- const activeLabel = activeInfo !== null ? activeInfo.label : 'OpenAxies';
255
+ const modelInfo = getModelById(activeModel);
256
+ const modelLabel = modelInfo !== null ? modelInfo.label : 'OpenAxies Llama';
249
257
 
250
- // Build sections
258
+ // Build viewport sections
251
259
  const sections = [];
252
260
 
253
- // Show overlay items
261
+ // Overlay items
254
262
  if (showOverlay === true) {
255
263
  sections.push({ t: 'sep' });
256
- sections.push({ t: 'header_bright', text: 'Commands' });
264
+ sections.push({ t: 'overlay_header' });
257
265
  for (let i = 0; i < COMMANDS.length; i++) {
258
266
  const c = COMMANDS[i];
259
- const sel = i === overlayIndex;
260
- sections.push({ t: 'cmd', trigger: c.trigger, desc: c.desc, selected: sel });
267
+ sections.push({ t: 'cmd', trigger: c.trigger, desc: c.desc, sel: i === overlayIndex });
261
268
  }
262
269
  sections.push({ t: 'sep' });
263
270
  }
264
271
 
265
- // Conversation history
272
+ // Messages
266
273
  for (let i = 0; i < messages.length; i++) {
267
274
  const msg = messages[i];
268
275
  if (msg === null || typeof msg !== 'object') continue;
269
276
  const content = typeof msg.content === 'string' ? msg.content : '';
270
277
  if (content.length === 0) continue;
271
-
272
278
  if (msg.role === 'user') {
273
279
  sections.push({ t: 'sep' });
274
280
  sections.push({ t: 'user', text: content });
275
281
  } else {
276
282
  if (sections.length > 0 && sections[sections.length - 1].t !== 'sep') sections.push({ t: 'sep' });
277
- const display = filterText(content);
278
- sections.push({ t: 'text', text: display });
283
+ sections.push({ t: 'assistant', text: filterText(content) });
279
284
  }
280
285
  }
281
286
 
282
- // Streaming section
283
- const hasStream = typeof streamText === 'string' && streamText.length > 0;
284
- if (hasStream === true) {
287
+ // Streaming
288
+ if (typeof streamText === 'string' && streamText.length > 0) {
285
289
  const clean = filterText(streamText);
286
-
287
290
  if (toolInfo !== null && toolInfo.used === true && toolInfo.query.length > 0) {
288
291
  sections.push({ t: 'tool', tool: toolInfo.tool, query: toolInfo.query, sites: toolInfo.sites });
289
292
  }
290
-
291
293
  if (isThinking === true) {
292
294
  sections.push({ t: 'thinking', spin: SPINNER[spinnerIdx], elapsed: fmtTime(thinkingElapsed), content: clean });
293
295
  } else {
@@ -295,24 +297,28 @@ function AppRoot() {
295
297
  }
296
298
  }
297
299
 
298
- // Idle ready state
300
+ // Startup screen
301
+ if (startupDone === false && messages.length === 0) {
302
+ sections.push({ t: 'startup' });
303
+ }
304
+
305
+ // Ready state
299
306
  if (sections.length === 0) {
300
307
  sections.push({ t: 'sep' });
301
- sections.push({ t: 'ready', text: 'Ready' });
308
+ sections.push({ t: 'ready' });
302
309
  sections.push({ t: 'sep' });
303
310
  }
304
311
 
305
- // Estimate line count per section
312
+ // Estimate and limit sections
306
313
  function estLines(s) {
307
- if (s.t === 'sep' || s.t === 'ready' || s.t === 'stream' || s.t === 'text' || s.t === 'tool') return 1;
314
+ if (s.t === 'sep' || s.t === 'assistant' || s.t === 'stream' || s.t === 'tool' || s.t === 'ready' || s.t === 'overlay_header') return 1;
308
315
  if (s.t === 'cmd') return 1;
309
- if (s.t === 'header_bright') return 1;
310
316
  if (s.t === 'user') return 2;
311
317
  if (s.t === 'thinking') return 2;
318
+ if (s.t === 'startup') return 11;
312
319
  return 1;
313
320
  }
314
321
 
315
- // Limit to available lines - show the LAST (newest) sections
316
322
  let totalEst = 0;
317
323
  let lastN = 0;
318
324
  for (let i = sections.length - 1; i >= 0; i--) {
@@ -323,7 +329,7 @@ function AppRoot() {
323
329
  }
324
330
  const visible = sections.slice(sections.length - lastN);
325
331
 
326
- // Render
332
+ // Render sections
327
333
  const sectionEls = [];
328
334
  for (let i = 0; i < visible.length; i++) {
329
335
  const s = visible[i];
@@ -342,7 +348,7 @@ function AppRoot() {
342
348
  h(Text, { color: hex.neonBlue, wrap: 'wrap' }, s.text)
343
349
  )
344
350
  );
345
- } else if (s.t === 'text' || s.t === 'stream') {
351
+ } else if (s.t === 'assistant' || s.t === 'stream') {
346
352
  sectionEls.push(
347
353
  h(Box, { key: ki, height: 1, paddingLeft: 1 },
348
354
  h(Text, { color: hex.primary, wrap: 'wrap' }, s.text)
@@ -351,7 +357,7 @@ function AppRoot() {
351
357
  } else if (s.t === 'thinking') {
352
358
  sectionEls.push(
353
359
  h(Box, { key: ki + '-h', height: 1, paddingLeft: 1 },
354
- h(Text, { color: '#FF9F43', bold: true }, ' ' + s.spin + ' Thinking \u2022 ' + s.elapsed)
360
+ h(Text, { color: '#FF9F43', bold: true }, s.spin + ' Thinking \u2022 ' + s.elapsed)
355
361
  )
356
362
  );
357
363
  sectionEls.push(
@@ -365,15 +371,15 @@ function AppRoot() {
365
371
  h(Text, { color: '#5B5B8A' }, '\u2500\u2500 ' + s.tool + ' \u2014 ' + (s.query || '') + ' (' + (s.sites || 0) + ' sites)')
366
372
  )
367
373
  );
368
- } else if (s.t === 'header_bright') {
374
+ } else if (s.t === 'overlay_header') {
369
375
  sectionEls.push(
370
376
  h(Box, { key: ki, height: 1, paddingLeft: 1 },
371
- h(Text, { color: '#888899', bold: true }, s.text || '')
377
+ h(Text, { color: '#888899', bold: true }, 'Commands')
372
378
  )
373
379
  );
374
380
  } else if (s.t === 'cmd') {
375
- const prefix = s.selected === true ? '\u276F ' : ' ';
376
- const col = s.selected === true ? hex.neonBlue : '#666688';
381
+ const prefix = s.sel === true ? '\u276F ' : ' ';
382
+ const col = s.sel === true ? hex.neonBlue : '#666688';
377
383
  sectionEls.push(
378
384
  h(Box, { key: ki, height: 1, paddingLeft: 2 },
379
385
  h(Text, { color: col }, prefix + s.trigger),
@@ -383,13 +389,38 @@ function AppRoot() {
383
389
  } else if (s.t === 'ready') {
384
390
  sectionEls.push(
385
391
  h(Box, { key: ki, height: 1, paddingLeft: 1 },
386
- h(Text, { color: '#00FF88', bold: true }, s.text)
392
+ h(Text, { color: '#00FF88', bold: true }, 'Ready')
393
+ )
394
+ );
395
+ } else if (s.t === 'startup') {
396
+ for (let li = 0; li < STARTUP_LOGO.length; li++) {
397
+ sectionEls.push(
398
+ h(Box, { key: ki + '-l' + li, height: 1, paddingLeft: 1 },
399
+ h(Text, { color: '#00BBFF', bold: true }, STARTUP_LOGO[li])
400
+ )
401
+ );
402
+ }
403
+ sectionEls.push(h(Box, { key: ki + '-e1', height: 1 }, null));
404
+ sectionEls.push(
405
+ h(Box, { key: ki + '-t1', height: 1, paddingLeft: 1 },
406
+ h(Text, { color: '#FFFFFF', bold: true }, 'OpenAxies')
407
+ )
408
+ );
409
+ sectionEls.push(
410
+ h(Box, { key: ki + '-t2', height: 1, paddingLeft: 1 },
411
+ h(Text, { color: '#777788' }, 'local agent runtime')
412
+ )
413
+ );
414
+ sectionEls.push(h(Box, { key: ki + '-e2', height: 1 }, null));
415
+ sectionEls.push(
416
+ h(Box, { key: ki + '-t3', height: 1, paddingLeft: 1 },
417
+ h(Text, { color: '#555577' }, 'Press Enter to begin')
387
418
  )
388
419
  );
389
420
  }
390
421
  }
391
422
 
392
- // Fill remaining lines
423
+ // Fill remaining
393
424
  while (sectionEls.length < availLines) {
394
425
  sectionEls.push(h(Box, { key: 'fl-' + sectionEls.length, height: 1 }, h(Text, {}, '')));
395
426
  }
@@ -401,20 +432,14 @@ function AppRoot() {
401
432
  overflow: 'hidden',
402
433
  }, ...sectionEls);
403
434
 
404
- // Status bar
405
- const statusBar = h(Box, { flexDirection: 'column', height: STATUS_H, flexShrink: 0 },
406
- h(Box, { height: 1 }, hr(cols)),
407
- h(Box, { height: 1, paddingLeft: 2 },
408
- h(Text, { color: '#444466' }, 'esc interrupt ctrl+t thoughts ctrl+p models'),
409
- ),
410
- h(Box, { height: 1, paddingLeft: 2 },
411
- h(Text, { color: '#444466' }, 'ctrl+l clear ctrl+r resume ctrl+k commands'),
412
- )
413
- );
435
+ // Main layout
436
+ const headerBar = startupDone === true ? createHeaderBar(modelLabel) : null;
437
+ const headerSep = startupDone === true ? h(Box, { height: 1 }, hr(cols)) : null;
414
438
 
415
- // Prompt
416
- const promptLine = h(Box, { height: DOCK_H, flexShrink: 0, paddingLeft: 2, paddingRight: 2 },
439
+ // Input line
440
+ const inputLine = h(Box, { height: DOCK_H, flexShrink: 0, paddingLeft: 2, paddingRight: 2 },
417
441
  h(Text, { color: hex.greenOnline }, '\u258C'),
442
+ h(Text, { color: '#555577' }, ' Ask OpenAxies'),
418
443
  h(TextInput, {
419
444
  value: inputBuffer,
420
445
  onChange: handleChange,
@@ -425,10 +450,22 @@ function AppRoot() {
425
450
  })
426
451
  );
427
452
 
453
+ // Shortcuts footer
454
+ const modelShort = modelLabel.replace('OpenAxies ', '');
455
+ const footerLine = h(Box, { height: STATUS_H, flexShrink: 0, paddingLeft: 2, paddingRight: 2 },
456
+ h(Text, { color: '#444466' }, 'esc \u2248 '),
457
+ h(Text, { color: '#444466' }, 'ctrl+t '),
458
+ h(Text, { color: '#444466' }, 'ctrl+p '),
459
+ h(Text, { color: '#444466' }, 'ctrl+k'),
460
+ h(Box, { flexGrow: 1 }),
461
+ h(Text, { color: '#555577' }, modelShort.toLowerCase() + ' \u2022 local'),
462
+ );
463
+
428
464
  return h(Box, { flexDirection: 'column', width: '100%', height: rows, overflow: 'hidden' },
429
- createBrandHeader(),
465
+ headerBar,
466
+ headerSep,
430
467
  viewport,
431
- statusBar,
432
- promptLine
468
+ inputLine,
469
+ footerLine,
433
470
  );
434
471
  }
@@ -1,36 +1,17 @@
1
1
  import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
- import { hex } from '../config/theme.js';
4
3
 
5
4
  const h = React.createElement;
6
5
 
7
- const LOGO = [
8
- '██████╗ ██████╗ ███████╗███╗ ██╗ █████╗ ██╗ ██╗██╗███████╗███████╗',
9
- '██╔═══██╗██╔══██╗██╔════╝████╗ ██║██╔══██╗╚██╗██╔╝██║██╔════╝██╔════╝',
10
- '██║ ██║██████╔╝█████╗ ██╔██╗ ██║███████║ ╚███╔╝ ██║█████╗ ███████╗',
11
- '██║ ██║██╔═══╝ ██╔══╝ ██║╚██╗██║██╔══██║ ██╔██╗ ██║██╔══╝ ╚════██║',
12
- '╚██████╔╝██║ ███████╗██║ ╚████║██║ ██║██╔╝ ██╗██║███████╗███████║',
13
- ' ╚═════╝ ╚═╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝',
14
- ];
15
-
16
- export function createBrandHeader() {
17
- const els = [];
18
- for (let r = 0; r < LOGO.length; r++) {
19
- els.push(
20
- h(Text, { key: 'l' + r, color: '#00BBFF', bold: true }, LOGO[r])
21
- );
22
- }
23
- els.push(
24
- h(Text, { key: 'sub', color: '#666688' }, 'OpenAxies Agent Runtime')
6
+ export function createHeaderBar(modelLabel) {
7
+ const label = typeof modelLabel === 'string' && modelLabel.length > 0 ? modelLabel : 'OpenAxies Llama';
8
+ return h(Box, { height: 1, paddingLeft: 1, paddingTop: 0, paddingBottom: 0 },
9
+ h(Text, { color: '#00BBFF', bold: true }, 'OpenAxies'),
10
+ h(Text, { color: '#555577' }, ' \u2022 '),
11
+ h(Text, { color: '#FFFFFF' }, label),
12
+ h(Text, { color: '#555577' }, ' \u2022 '),
13
+ h(Text, { color: '#777788' }, 'local'),
25
14
  );
26
- return h(Box, {
27
- flexDirection: 'column',
28
- width: '100%',
29
- flexShrink: 0,
30
- paddingLeft: 0,
31
- paddingTop: 0,
32
- paddingBottom: 0,
33
- }, ...els);
34
15
  }
35
16
 
36
- export const BRAND_HEIGHT = 7;
17
+ export const HEADER_HEIGHT = 1;
@@ -4,15 +4,12 @@ import { runWebSearchGraph, shouldUseWebSearch } from './websearch.js';
4
4
  const MODEL_ROUTES = Object.freeze({
5
5
  'openaxis/openaxis-llama': Object.freeze([
6
6
  'https://universal-618-clarity-main.hf.space/v1/chat/completions',
7
- 'https://universal-618-clarity-4.hf.space/v1/chat/completions',
8
7
  ]),
9
8
  'openaxis/openaxis-gpt': Object.freeze([
10
9
  'https://universal-618-clarity-2.hf.space/v1/chat/completions',
11
- 'https://universal-618-clarity-5.hf.space/v1/chat/completions',
12
10
  ]),
13
11
  'openaxis/openaxis-deepseek': Object.freeze([
14
12
  'https://universal-618-clarity-3.hf.space/v1/chat/completions',
15
- 'https://universal-618-clarity-6.hf.space/v1/chat/completions',
16
13
  ]),
17
14
  });
18
15
 
@@ -1,5 +1,5 @@
1
- const CONNECT_TIMEOUT = 120000;
2
- const READ_TIMEOUT = 60000;
1
+ const CONNECT_TIMEOUT = 10000;
2
+ const READ_TIMEOUT = 30000;
3
3
 
4
4
  function checkEndpoint(endpoint) {
5
5
  if (typeof endpoint !== 'string') {