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 +1 -1
- package/src/App.js +33 -30
- package/src/components/ChatViewport.js +7 -68
- package/src/components/RouterBar.js +22 -22
- package/src/config/commands.js +1 -1
- package/src/config/models.js +3 -3
- package/src/providers/index.js +6 -14
- package/src/providers/streaming.js +2 -2
package/package.json
CHANGED
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-
|
|
121
|
+
if (prev === 'openaxis/openaxis-mixtral') {
|
|
121
122
|
return 'openaxis/openaxis-heavy';
|
|
122
123
|
}
|
|
123
|
-
|
|
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
|
|
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('
|
|
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
|
|
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 (
|
|
196
|
-
|
|
197
|
-
|
|
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
|
|
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,
|
|
75
|
+
pushWrapped(lines, content, safeCols, hex.neonBlue, false);
|
|
134
76
|
return;
|
|
135
77
|
}
|
|
136
78
|
|
|
137
|
-
|
|
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
|
-
|
|
93
|
+
pushRawMessage(transcriptLines, safeMessages[i], safeCols);
|
|
154
94
|
}
|
|
155
95
|
|
|
156
96
|
if (hasStream === true) {
|
|
157
|
-
|
|
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, '
|
|
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-
|
|
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
|
|
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
|
-
// ──
|
|
55
|
+
// ── Mixtral slot ──
|
|
56
56
|
h(Text, {
|
|
57
|
-
color:
|
|
58
|
-
bold:
|
|
59
|
-
},
|
|
57
|
+
color: isMixtral ? hex.neonBlue : '#333355',
|
|
58
|
+
bold: isMixtral,
|
|
59
|
+
}, isMixtral ? '\u25B6 ' : '\u25B7 '),
|
|
60
60
|
h(Text, {
|
|
61
|
-
color:
|
|
62
|
-
bold:
|
|
63
|
-
}, '
|
|
61
|
+
color: isMixtral ? hex.primary : '#444466',
|
|
62
|
+
bold: isMixtral,
|
|
63
|
+
}, 'Mixtral'),
|
|
64
64
|
h(Text, {
|
|
65
|
-
color:
|
|
65
|
+
color: isMixtral ? hex.greenOnline : '#2A3A2A',
|
|
66
66
|
}, ' \u25CF '),
|
|
67
67
|
h(Text, {
|
|
68
|
-
color:
|
|
69
|
-
dimColor: !
|
|
70
|
-
},
|
|
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: !
|
|
78
|
-
bold: !
|
|
79
|
-
}, !
|
|
77
|
+
color: !isMixtral ? hex.neonBlue : '#333355',
|
|
78
|
+
bold: !isMixtral,
|
|
79
|
+
}, !isMixtral ? '\u25B6 ' : '\u25B7 '),
|
|
80
80
|
h(Text, {
|
|
81
|
-
color: !
|
|
82
|
-
bold: !
|
|
81
|
+
color: !isMixtral ? hex.primary : '#444466',
|
|
82
|
+
bold: !isMixtral,
|
|
83
83
|
}, 'Heavy'),
|
|
84
84
|
h(Text, {
|
|
85
|
-
color: !
|
|
85
|
+
color: !isMixtral ? hex.greenOnline : '#2A3A2A',
|
|
86
86
|
}, ' \u25CF '),
|
|
87
87
|
h(Text, {
|
|
88
|
-
color: !
|
|
89
|
-
dimColor:
|
|
90
|
-
}, !
|
|
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 '),
|
package/src/config/commands.js
CHANGED
|
@@ -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
|
|
37
|
+
{ trigger: '/model', description: 'Switch between Mixtral and Heavy' },
|
|
38
38
|
{ trigger: '/exit', description: 'Quit the application' },
|
|
39
39
|
]);
|
|
40
40
|
|
package/src/config/models.js
CHANGED
|
@@ -33,12 +33,12 @@ function checkModels(arr) {
|
|
|
33
33
|
return arr;
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
//
|
|
36
|
+
// Mixtral (fast/light) and Heavy (quality).
|
|
37
37
|
const MODELS = Object.freeze([
|
|
38
38
|
{
|
|
39
|
-
id: 'openaxis/openaxis-
|
|
39
|
+
id: 'openaxis/openaxis-mixtral',
|
|
40
40
|
provider: 'openaxis',
|
|
41
|
-
label: 'OpenAxies
|
|
41
|
+
label: 'OpenAxies Mixtral',
|
|
42
42
|
badge: 'Fast',
|
|
43
43
|
},
|
|
44
44
|
{
|
package/src/providers/index.js
CHANGED
|
@@ -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-
|
|
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
|
-
'
|
|
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 (
|
|
76
|
-
yield { type: 'thinking', content: 'Searched 0 sites' };
|
|
77
|
-
yield { type: 'thinking', content: 'Thinking...' };
|
|
69
|
+
} catch (_) {
|
|
78
70
|
}
|
|
79
71
|
}
|
|
80
72
|
|