openaxies 0.5.1 → 0.5.3
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 +70 -115
- package/src/components/ComposerDock.js +18 -6
- package/src/providers/index.js +1 -0
- package/src/providers/streaming.js +37 -1
package/package.json
CHANGED
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
|
|
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
|
|
20
|
-
|
|
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
|
-
|
|
34
|
+
h.push({ role: 'user', content: newText });
|
|
25
35
|
}
|
|
26
|
-
return
|
|
36
|
+
return h;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
|
-
function formatTimer(
|
|
30
|
-
if (typeof
|
|
31
|
-
return
|
|
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:
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
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: 0 }, ...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
|
-
|
|
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,10 @@ function AppRoot() {
|
|
|
362
310
|
}
|
|
363
311
|
|
|
364
312
|
if (viewLines.length === 0) {
|
|
365
|
-
viewLines.push({ t: 'idle', text: '
|
|
313
|
+
viewLines.push({ t: 'idle', text: ' \u25B8 type a message to begin | /model to switch models | /help for commands' });
|
|
314
|
+
viewLines.push({ t: 'idle', text: '' });
|
|
315
|
+
viewLines.push({ t: 'idle-sm', text: ' Models: OpenAxies Llama | OpenAxies GPT | OpenAxies DeepSeek' });
|
|
316
|
+
viewLines.push({ t: 'idle-sm', text: ' Current: ' + activeLabel });
|
|
366
317
|
}
|
|
367
318
|
|
|
368
319
|
const visible = Math.max(1, availLines - 1);
|
|
@@ -371,23 +322,21 @@ function AppRoot() {
|
|
|
371
322
|
|
|
372
323
|
for (let i = 0; i < display.length; i++) {
|
|
373
324
|
const l = display[i];
|
|
374
|
-
if (l.t === '
|
|
375
|
-
viewEls.push(h(Box, { key: 's-' + i, height: 1 }, hr(cols)));
|
|
376
|
-
} else if (l.t === 'think') {
|
|
325
|
+
if (l.t === 'think') {
|
|
377
326
|
viewEls.push(
|
|
378
|
-
h(Box, { key: 'k-' + i, height: 1, paddingLeft:
|
|
379
|
-
h(Text, { color: '#FF9F43', bold: true },
|
|
327
|
+
h(Box, { key: 'k-' + i, height: 1, paddingLeft: 2 },
|
|
328
|
+
h(Text, { color: '#FF9F43', bold: true }, l.spin + ' Thinking \u2022 ' + l.elapsed)
|
|
380
329
|
)
|
|
381
330
|
);
|
|
382
331
|
} else if (l.t === 'think-text') {
|
|
383
332
|
viewEls.push(
|
|
384
|
-
h(Box, { key: 'kt-' + i, height: 1, paddingLeft:
|
|
333
|
+
h(Box, { key: 'kt-' + i, height: 1, paddingLeft: 3 },
|
|
385
334
|
h(Text, { color: '#FF9F43' }, l.text)
|
|
386
335
|
)
|
|
387
336
|
);
|
|
388
337
|
} else if (l.t === 'tool') {
|
|
389
338
|
viewEls.push(
|
|
390
|
-
h(Box, { key: 'tl-' + i, height: 1, paddingLeft:
|
|
339
|
+
h(Box, { key: 'tl-' + i, height: 1, paddingLeft: 2 },
|
|
391
340
|
h(Text, { color: '#5B5B8A' }, l.text)
|
|
392
341
|
)
|
|
393
342
|
);
|
|
@@ -399,13 +348,19 @@ function AppRoot() {
|
|
|
399
348
|
);
|
|
400
349
|
} else if (l.t === 'text') {
|
|
401
350
|
viewEls.push(
|
|
402
|
-
h(Box, { key: 'a-' + i, height: 1, paddingLeft:
|
|
351
|
+
h(Box, { key: 'a-' + i, height: 1, paddingLeft: 2 },
|
|
403
352
|
h(Text, { color: hex.primary }, l.text)
|
|
404
353
|
)
|
|
405
354
|
);
|
|
406
355
|
} else if (l.t === 'idle') {
|
|
407
356
|
viewEls.push(
|
|
408
357
|
h(Box, { key: 'i-' + i, height: 1, paddingLeft: 1 },
|
|
358
|
+
h(Text, { color: '#555577' }, l.text)
|
|
359
|
+
)
|
|
360
|
+
);
|
|
361
|
+
} else if (l.t === 'idle-sm') {
|
|
362
|
+
viewEls.push(
|
|
363
|
+
h(Box, { key: 'is-' + i, height: 1, paddingLeft: 1 },
|
|
409
364
|
h(Text, { color: '#333355' }, l.text)
|
|
410
365
|
)
|
|
411
366
|
);
|
|
@@ -417,12 +372,11 @@ function AppRoot() {
|
|
|
417
372
|
height: availLines,
|
|
418
373
|
flexDirection: 'column',
|
|
419
374
|
overflow: 'hidden',
|
|
420
|
-
|
|
375
|
+
paddingTop: 0,
|
|
376
|
+
paddingBottom: 0,
|
|
421
377
|
}, ...viewEls);
|
|
422
378
|
|
|
423
|
-
const slashOverlay = showOverlay === true
|
|
424
|
-
? createSlashOverlay(commands, overlayIndex)
|
|
425
|
-
: null;
|
|
379
|
+
const slashOverlay = showOverlay === true ? createSlashOverlay(commands, overlayIndex) : null;
|
|
426
380
|
|
|
427
381
|
const dock = createComposerDock({
|
|
428
382
|
value: inputBuffer,
|
|
@@ -442,7 +396,8 @@ function AppRoot() {
|
|
|
442
396
|
backgroundColor: hex.black,
|
|
443
397
|
overflow: 'hidden',
|
|
444
398
|
},
|
|
445
|
-
|
|
399
|
+
logo,
|
|
400
|
+
h(Box, { height: 1 }, hr(cols, '#1A1A2E')),
|
|
446
401
|
viewport,
|
|
447
402
|
slashOverlay,
|
|
448
403
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
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: '#
|
|
63
|
+
h(Text, { color: '#444466', bold: modelStatus }, modelLabel || '')
|
|
52
64
|
)
|
|
53
65
|
);
|
|
54
66
|
}
|
package/src/providers/index.js
CHANGED
|
@@ -78,7 +78,7 @@ export async function* streamResponse(endpoint, body, signal) {
|
|
|
78
78
|
}, READ_TIMEOUT);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
let firstChunk = true;
|
|
82
82
|
|
|
83
83
|
try {
|
|
84
84
|
while (true) {
|
|
@@ -86,12 +86,48 @@ export async function* streamResponse(endpoint, body, signal) {
|
|
|
86
86
|
resetReadTimeout();
|
|
87
87
|
|
|
88
88
|
if (result.done === true) {
|
|
89
|
+
if (buffer.trim().length > 0 && firstChunk === false) {
|
|
90
|
+
try {
|
|
91
|
+
const parsed = JSON.parse(buffer);
|
|
92
|
+
const choice = parsed.choices && parsed.choices[0];
|
|
93
|
+
if (choice !== null && choice !== undefined) {
|
|
94
|
+
const msg = choice.message || choice.delta;
|
|
95
|
+
if (msg !== null && msg !== undefined) {
|
|
96
|
+
if (typeof msg.content === 'string' && msg.content.length > 0) {
|
|
97
|
+
yield { type: 'token', content: msg.content };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (_) {
|
|
102
|
+
}
|
|
103
|
+
}
|
|
89
104
|
yield { type: 'done' };
|
|
90
105
|
return;
|
|
91
106
|
}
|
|
92
107
|
|
|
93
108
|
const chunk = decoder.decode(result.value, { stream: true });
|
|
94
109
|
buffer = buffer + chunk;
|
|
110
|
+
|
|
111
|
+
if (firstChunk === true && buffer.includes('data: ') === false && buffer.trim().startsWith('{') === true) {
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(buffer);
|
|
114
|
+
const choice = parsed.choices && parsed.choices[0];
|
|
115
|
+
if (choice !== null && choice !== undefined) {
|
|
116
|
+
const msg = choice.message || choice.delta;
|
|
117
|
+
if (msg !== null && msg !== undefined) {
|
|
118
|
+
if (typeof msg.content === 'string' && msg.content.length > 0) {
|
|
119
|
+
yield { type: 'token', content: msg.content };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
yield { type: 'done' };
|
|
124
|
+
return;
|
|
125
|
+
} catch (_) {
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
firstChunk = false;
|
|
130
|
+
|
|
95
131
|
const lines = buffer.split('\n');
|
|
96
132
|
buffer = lines.pop() || '';
|
|
97
133
|
|