openaxies 0.2.1 → 0.3.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.2.1",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
package/src/App.js CHANGED
@@ -72,6 +72,7 @@ function AppRoot() {
72
72
  const availLines = Math.max(1, rows - fixedH);
73
73
 
74
74
  const abortRef = React.useRef(null);
75
+ const connectingRef = React.useRef(null);
75
76
 
76
77
  // ---------------------------------------------------------------------------
77
78
  // Input handlers
@@ -117,10 +118,10 @@ function AppRoot() {
117
118
  if (trigger === '/model') {
118
119
  // Toggle between the two local models
119
120
  setActiveModel(function (prev) {
120
- if (prev === 'openaxis/openaxis-flash') {
121
+ if (prev === 'openaxis/openaxis-mixtral') {
121
122
  return 'openaxis/openaxis-heavy';
122
123
  }
123
- return 'openaxis/openaxis-flash';
124
+ return 'openaxis/openaxis-mixtral';
124
125
  });
125
126
  }
126
127
 
@@ -133,7 +134,7 @@ function AppRoot() {
133
134
  '**Available commands:**\n' +
134
135
  '- `/help` — Show this help\n' +
135
136
  '- `/clear` — Clear the conversation\n' +
136
- '- `/model` — Toggle between OpenAxies Flash and Heavy\n' +
137
+ '- `/model` — Toggle between Mixtral and Heavy\n' +
137
138
  '- `/exit` — Quit the application\n\n' +
138
139
  'Type your message and press **Enter** to chat.',
139
140
  id: 'help-' + Date.now(),
@@ -161,10 +162,23 @@ function AppRoot() {
161
162
  return prev.concat([{ role: 'user', content: safeText, id: msgId }]);
162
163
  });
163
164
  setInputBuffer('');
164
- setStreamText('\u2022\u2022\u2022'); // animated placeholder
165
+ setStreamText(' connecting');
166
+ connectingRef.current = setInterval(function () {
167
+ setStreamText(function (prev) {
168
+ if (prev === ' connecting') return ' connecting.';
169
+ if (prev === ' connecting.') return ' connecting..';
170
+ if (prev === ' connecting..') return ' connecting...';
171
+ if (prev === ' connecting...') return ' connecting';
172
+ return prev;
173
+ });
174
+ }, 400);
165
175
 
166
176
  const modelInfo = getModelById(activeModel);
167
177
  if (modelInfo === null || modelInfo === undefined) {
178
+ if (connectingRef.current !== null) {
179
+ clearInterval(connectingRef.current);
180
+ connectingRef.current = null;
181
+ }
168
182
  setStreamingActive(false);
169
183
  setStreamText('');
170
184
  setScrollOffset(0);
@@ -185,39 +199,20 @@ function AppRoot() {
185
199
  try {
186
200
  const gen = callModel(modelInfo, history, abortController.signal);
187
201
  let accumulated = '';
188
- let thinkingId = null;
189
- const thinkingLines = [];
202
+ let firstEvent = true;
190
203
 
191
204
  for await (const event of gen) {
192
205
  if (abortController.signal.aborted === true) {
193
206
  break;
194
207
  }
195
- if (event.type === 'thinking') {
196
- if (thinkingId === null) {
197
- thinkingId = 'think-' + Date.now() + '-' + Math.random().toString(36).slice(2, 8);
208
+ if (firstEvent === true) {
209
+ firstEvent = false;
210
+ if (connectingRef.current !== null) {
211
+ clearInterval(connectingRef.current);
212
+ connectingRef.current = null;
198
213
  }
199
- thinkingLines.push(typeof event.content === 'string' ? event.content : '');
200
- const content = thinkingLines.join('\n');
201
- setMessages(function (prev) {
202
- let replaced = false;
203
- const next = [];
204
- for (let i = 0; i < prev.length; i++) {
205
- const item = prev[i];
206
- if (item !== null && item !== undefined && item.id === thinkingId) {
207
- next.push({ role: 'thinking', content: content, id: thinkingId });
208
- replaced = true;
209
- } else {
210
- next.push(item);
211
- }
212
- }
213
- if (replaced === false) {
214
- next.push({ role: 'thinking', content: content, id: thinkingId });
215
- }
216
- return next;
217
- });
218
- setScrollOffset(0);
219
214
  }
220
- if (event.type === 'token') {
215
+ if (event.type === 'thinking' || event.type === 'token') {
221
216
  const content = typeof event.content === 'string' ? event.content : '';
222
217
  for (let i = 0; i < content.length; i++) {
223
218
  accumulated = accumulated + content[i];
@@ -240,6 +235,10 @@ function AppRoot() {
240
235
  }
241
236
  }
242
237
 
238
+ if (connectingRef.current !== null) {
239
+ clearInterval(connectingRef.current);
240
+ connectingRef.current = null;
241
+ }
243
242
  setStreamingActive(false);
244
243
  setStreamText('');
245
244
 
@@ -253,6 +252,10 @@ function AppRoot() {
253
252
  });
254
253
  }
255
254
  } catch (err) {
255
+ if (connectingRef.current !== null) {
256
+ clearInterval(connectingRef.current);
257
+ connectingRef.current = null;
258
+ }
256
259
  setStreamingActive(false);
257
260
  setStreamText('');
258
261
  setScrollOffset(0);
@@ -11,49 +11,6 @@ function checkArray(arr) {
11
11
  return arr;
12
12
  }
13
13
 
14
- // Splits content on <think>...</think> tags.
15
- // Returns an array of { type: 'text' | 'think', content: string } parts.
16
- function parseThinkTags(content) {
17
- if (typeof content !== 'string') {
18
- return [];
19
- }
20
- const parts = [];
21
- let remaining = content;
22
- let inThink = false;
23
-
24
- while (remaining.length > 0) {
25
- if (inThink === false) {
26
- const startIdx = remaining.indexOf('<think>');
27
- if (startIdx === -1) {
28
- if (remaining.length > 0) {
29
- parts.push({ type: 'text', content: remaining });
30
- }
31
- break;
32
- }
33
- if (startIdx > 0) {
34
- parts.push({ type: 'text', content: remaining.slice(0, startIdx) });
35
- }
36
- remaining = remaining.slice(startIdx + 7);
37
- inThink = true;
38
- } else {
39
- const endIdx = remaining.indexOf('</think>');
40
- if (endIdx === -1) {
41
- if (remaining.length > 0) {
42
- parts.push({ type: 'think', content: remaining });
43
- }
44
- break;
45
- }
46
- if (endIdx > 0) {
47
- parts.push({ type: 'think', content: remaining.slice(0, endIdx) });
48
- }
49
- remaining = remaining.slice(endIdx + 8);
50
- inThink = false;
51
- }
52
- }
53
-
54
- return parts;
55
- }
56
-
57
14
  function clampWidth(width) {
58
15
  if (typeof width !== 'number' || width < 20) {
59
16
  return 80;
@@ -104,39 +61,22 @@ function pushWrapped(lines, text, width, color, bold) {
104
61
  }
105
62
  }
106
63
 
107
- function pushContentLines(lines, content, width) {
108
- const parts = parseThinkTags(content);
109
- for (let i = 0; i < parts.length; i++) {
110
- const part = parts[i];
111
- if (part.type === 'think') {
112
- pushWrapped(lines, '# think ' + part.content.trim(), width, '#555577', false);
113
- } else {
114
- pushWrapped(lines, part.content, width, hex.primary, false);
115
- }
116
- }
117
- }
118
-
119
- // Transcript message - linear terminal flow, no side panels or bubbles.
120
- function pushMessageLines(lines, msg, safeCols) {
64
+ function pushRawMessage(lines, msg, safeCols) {
121
65
  if (msg === null || msg === undefined || typeof msg !== 'object') {
122
66
  return;
123
67
  }
124
68
 
125
69
  const content = typeof msg.content === 'string' ? msg.content : '';
126
-
127
- if (msg.role === 'thinking') {
128
- pushWrapped(lines, content, safeCols, hex.orange, false);
70
+ if (content.length === 0) {
129
71
  return;
130
72
  }
131
73
 
132
74
  if (msg.role === 'user') {
133
- pushWrapped(lines, 'You > ' + content, safeCols, hex.neonBlue, true);
75
+ pushWrapped(lines, content, safeCols, hex.neonBlue, false);
134
76
  return;
135
77
  }
136
78
 
137
- pushLine(lines, 'OpenAxies $', hex.greenOnline, true);
138
- pushContentLines(lines, content, safeCols);
139
- pushLine(lines, '', hex.primary, false);
79
+ pushWrapped(lines, content, safeCols, hex.primary, false);
140
80
  }
141
81
 
142
82
  export function createChatViewport(messages, streamText, availLines, cols, scrollOffset) {
@@ -150,16 +90,15 @@ export function createChatViewport(messages, streamText, availLines, cols, scrol
150
90
  const transcriptLines = [];
151
91
 
152
92
  for (let i = 0; i < safeMessages.length; i++) {
153
- pushMessageLines(transcriptLines, safeMessages[i], safeCols);
93
+ pushRawMessage(transcriptLines, safeMessages[i], safeCols);
154
94
  }
155
95
 
156
96
  if (hasStream === true) {
157
- pushLine(transcriptLines, 'OpenAxies $ streaming...', hex.greenOnline, true);
158
- pushContentLines(transcriptLines, streamText, safeCols);
97
+ pushWrapped(transcriptLines, streamText, safeCols, hex.primary, false);
159
98
  }
160
99
 
161
100
  if (transcriptLines.length === 0) {
162
- pushLine(transcriptLines, '# waiting for input', '#333355', false);
101
+ pushLine(transcriptLines, ' awaiting input...', '#333355', false);
163
102
  }
164
103
 
165
104
  const visibleHeight = Math.max(1, safeAvail - 1);
@@ -8,7 +8,7 @@ export const ROUTER_HEIGHT = 2;
8
8
 
9
9
  function checkActiveModel(modelId) {
10
10
  if (typeof modelId !== 'string') {
11
- return 'openaxis/openaxis-flash';
11
+ return 'openaxis/openaxis-mixtral';
12
12
  }
13
13
  return modelId;
14
14
  }
@@ -34,7 +34,7 @@ function buildSeparator(cols) {
34
34
  // Row 2: full-width separator line
35
35
  export function createRouterBar(activeModel, cols) {
36
36
  const modelStr = checkActiveModel(activeModel);
37
- const isFlash = modelStr === 'openaxis/openaxis-flash';
37
+ const isMixtral = modelStr === 'openaxis/openaxis-mixtral';
38
38
  const sepLine = buildSeparator(cols);
39
39
 
40
40
  return h(Box, {
@@ -52,42 +52,42 @@ export function createRouterBar(activeModel, cols) {
52
52
  alignItems: 'center',
53
53
  },
54
54
 
55
- // ── Flash slot ──
55
+ // ── Mixtral slot ──
56
56
  h(Text, {
57
- color: isFlash ? hex.neonBlue : '#333355',
58
- bold: isFlash,
59
- }, isFlash ? '\u25B6 ' : '\u25B7 '),
57
+ color: isMixtral ? hex.neonBlue : '#333355',
58
+ bold: isMixtral,
59
+ }, isMixtral ? '\u25B6 ' : '\u25B7 '),
60
60
  h(Text, {
61
- color: isFlash ? hex.primary : '#444466',
62
- bold: isFlash,
63
- }, 'Flash'),
61
+ color: isMixtral ? hex.primary : '#444466',
62
+ bold: isMixtral,
63
+ }, 'Mixtral'),
64
64
  h(Text, {
65
- color: isFlash ? hex.greenOnline : '#2A3A2A',
65
+ color: isMixtral ? hex.greenOnline : '#2A3A2A',
66
66
  }, ' \u25CF '),
67
67
  h(Text, {
68
- color: isFlash ? hex.greenOnline : '#2A3A2A',
69
- dimColor: !isFlash,
70
- }, isFlash ? 'ACTIVE' : 'STANDBY'),
68
+ color: isMixtral ? hex.greenOnline : '#2A3A2A',
69
+ dimColor: !isMixtral,
70
+ }, isMixtral ? 'ACTIVE' : 'STANDBY'),
71
71
 
72
72
  // ── Divider ──
73
73
  h(Text, { color: '#1E1E2E' }, ' \u2502 '),
74
74
 
75
75
  // ── Heavy slot ──
76
76
  h(Text, {
77
- color: !isFlash ? hex.neonBlue : '#333355',
78
- bold: !isFlash,
79
- }, !isFlash ? '\u25B6 ' : '\u25B7 '),
77
+ color: !isMixtral ? hex.neonBlue : '#333355',
78
+ bold: !isMixtral,
79
+ }, !isMixtral ? '\u25B6 ' : '\u25B7 '),
80
80
  h(Text, {
81
- color: !isFlash ? hex.primary : '#444466',
82
- bold: !isFlash,
81
+ color: !isMixtral ? hex.primary : '#444466',
82
+ bold: !isMixtral,
83
83
  }, 'Heavy'),
84
84
  h(Text, {
85
- color: !isFlash ? hex.greenOnline : '#2A3A2A',
85
+ color: !isMixtral ? hex.greenOnline : '#2A3A2A',
86
86
  }, ' \u25CF '),
87
87
  h(Text, {
88
- color: !isFlash ? hex.greenOnline : '#2A3A2A',
89
- dimColor: isFlash,
90
- }, !isFlash ? 'ACTIVE' : 'STANDBY'),
88
+ color: !isMixtral ? hex.greenOnline : '#2A3A2A',
89
+ dimColor: isMixtral,
90
+ }, !isMixtral ? 'ACTIVE' : 'STANDBY'),
91
91
 
92
92
  // ── Right-side hint ──
93
93
  h(Text, { color: '#1E1E2E' }, ' \u2502 '),
@@ -34,7 +34,7 @@ function checkCommands(arr) {
34
34
  const COMMAND_DEFS = Object.freeze([
35
35
  { trigger: '/help', description: 'Show available commands' },
36
36
  { trigger: '/clear', description: 'Clear the conversation' },
37
- { trigger: '/model', description: 'Switch between Flash and Heavy' },
37
+ { trigger: '/model', description: 'Switch between Mixtral and Heavy' },
38
38
  { trigger: '/exit', description: 'Quit the application' },
39
39
  ]);
40
40
 
@@ -33,12 +33,12 @@ function checkModels(arr) {
33
33
  return arr;
34
34
  }
35
35
 
36
- // Two routed models only — Flash (fast) and Heavy (quality).
36
+ // Mixtral (fast/light) and Heavy (quality).
37
37
  const MODELS = Object.freeze([
38
38
  {
39
- id: 'openaxis/openaxis-flash',
39
+ id: 'openaxis/openaxis-mixtral',
40
40
  provider: 'openaxis',
41
- label: 'OpenAxies Flash',
41
+ label: 'OpenAxies Mixtral',
42
42
  badge: 'Fast',
43
43
  },
44
44
  {
@@ -5,7 +5,7 @@ import { runWebSearchGraph, shouldUseWebSearch } from './websearch.js';
5
5
  // HF Spaces cold-start on first request (30–120 s model download).
6
6
  // If the primary is waking up, we fall through to the next Space.
7
7
  const MODEL_ROUTES = Object.freeze({
8
- 'openaxis/openaxis-flash': Object.freeze([
8
+ 'openaxis/openaxis-mixtral': Object.freeze([
9
9
  'https://universal-618-clarity-main.hf.space/v1/chat/completions',
10
10
  'https://universal-618-clarity-2.hf.space/v1/chat/completions',
11
11
  'https://universal-618-clarity-3.hf.space/v1/chat/completions',
@@ -55,26 +55,18 @@ export async function* callModel(modelConfig, messages, signal) {
55
55
  let modelMessages = messages;
56
56
 
57
57
  if (shouldUseWebSearch(messages) === true) {
58
- yield { type: 'thinking', content: 'OpenAxies thinking > [Internal reasoning]' };
59
- yield { type: 'thinking', content: 'Checking tools...' };
60
- yield { type: 'thinking', content: 'Let me do websearch' };
61
- yield { type: 'thinking', content: 'Doing websearch' };
62
-
63
58
  try {
64
59
  const webResult = await runWebSearchGraph(messages, signal);
65
- if (webResult.used === true) {
66
- yield { type: 'thinking', content: 'Searched ' + webResult.sites + ' sites' };
67
- yield { type: 'thinking', content: 'Thinking...' };
60
+ if (webResult.used === true && webResult.sites > 0) {
68
61
  modelMessages = [{
69
62
  role: 'system',
70
63
  content:
71
- 'Use these websearch results when they are relevant. Cite URLs inline when possible.\n\n' +
72
- webResult.summary,
64
+ 'Current web search results (use when relevant, cite URLs inline):\n\n' +
65
+ webResult.summary +
66
+ '\n\nNow respond to the user using these results as needed.',
73
67
  }].concat(messages);
74
68
  }
75
- } catch (err) {
76
- yield { type: 'thinking', content: 'Searched 0 sites' };
77
- yield { type: 'thinking', content: 'Thinking...' };
69
+ } catch (_) {
78
70
  }
79
71
  }
80
72
 
@@ -1,5 +1,5 @@
1
- const CONNECT_TIMEOUT = 120000;
2
- const READ_TIMEOUT = 15000;
1
+ const CONNECT_TIMEOUT = 20000;
2
+ const READ_TIMEOUT = 8000;
3
3
 
4
4
  function readWithTimeout(reader, timeoutMs) {
5
5
  return Promise.race([