@yemi33/minions 0.1.1583 → 0.1.1584
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/CHANGELOG.md +4 -1
- package/dashboard/js/modal-qa.js +54 -30
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dashboard/js/modal-qa.js
CHANGED
|
@@ -27,8 +27,8 @@ let _qaProcessing = false; // true while waiting for response
|
|
|
27
27
|
let _qaAbortController = null;
|
|
28
28
|
let _qaQueue = []; // queued messages while processing
|
|
29
29
|
const QA_QUEUE_CAP = 10; // max queued messages
|
|
30
|
+
const QA_STREAM_STALL_MS = 90000; // abort doc-chat if heartbeats continue but no chunk/tool progress arrives
|
|
30
31
|
let _qaSessionKey = ''; // key for current conversation (title or filePath)
|
|
31
|
-
let _qaThreadCollapsed = false; // sticky while streaming so collapse doesn't bounce open on updates
|
|
32
32
|
|
|
33
33
|
function _renderQaUserMessage(thread, message, selection) {
|
|
34
34
|
let qHtml = '<div class="modal-qa-q">' + escHtml(message);
|
|
@@ -38,7 +38,7 @@ function _renderQaUserMessage(thread, message, selection) {
|
|
|
38
38
|
qHtml += '</div>';
|
|
39
39
|
thread.insertAdjacentHTML('beforeend', qHtml);
|
|
40
40
|
thread.scrollTop = thread.scrollHeight;
|
|
41
|
-
_showThreadWrap(
|
|
41
|
+
_showThreadWrap();
|
|
42
42
|
}
|
|
43
43
|
const _qaSessions = new Map(); // persist conversations across modal open/close {key → {history, threadHtml}}
|
|
44
44
|
const _qaRuntime = new Map(); // key → {history, processing, abortController, queue}
|
|
@@ -199,28 +199,29 @@ function _qaBuildAssistantHtml(text, opts) {
|
|
|
199
199
|
|
|
200
200
|
function _qaBuildLiveProgressHtml(loadingId, label, elapsedSeconds, streamedText, toolsUsed, queueCount) {
|
|
201
201
|
const qaQueueBadge = queueCount > 0 ? ' <span style="font-size:9px;color:var(--muted);background:var(--surface);padding:1px 5px;border-radius:8px;border:1px solid var(--border)">+' + queueCount + ' queued</span>' : '';
|
|
202
|
-
|
|
202
|
+
// Wrap in a column-flex container so chain-of-thought (tool calls) stack
|
|
203
|
+
// vertically on top and the progress block sits at the bottom. Overrides the
|
|
204
|
+
// parent .modal-qa-loading row-flex (which is right for the simple
|
|
205
|
+
// "Thinking..." initial state but wrong once tools/streamed text appear).
|
|
206
|
+
let html = '<div style="display:flex;flex-direction:column;align-items:stretch;gap:6px;width:100%">';
|
|
203
207
|
if (toolsUsed && toolsUsed.length > 0) {
|
|
204
|
-
html += '<div style="
|
|
208
|
+
html += '<div style="display:flex;flex-direction:column;gap:2px">';
|
|
205
209
|
toolsUsed.forEach(function(t) {
|
|
206
210
|
const name = typeof t === 'string' ? t : t.name;
|
|
207
211
|
const input = typeof t === 'string' ? {} : (t.input || {});
|
|
208
|
-
html += '<div style="color:var(--muted);font-size:10px;font-family:monospace"><span style="flex-shrink:0">●</span>
|
|
212
|
+
html += '<div style="color:var(--muted);font-size:10px;font-family:monospace;display:flex;align-items:flex-start;gap:6px"><span style="flex-shrink:0">●</span><span style="word-break:break-all">' + formatToolSummary(name, input) + '</span></div>';
|
|
209
213
|
});
|
|
210
214
|
html += '</div>';
|
|
211
215
|
}
|
|
212
|
-
if (streamedText) html += '<div
|
|
213
|
-
html += '<div style="display:flex;
|
|
214
|
-
'<
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
'</
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
qaQueueBadge +
|
|
222
|
-
'</div>' +
|
|
223
|
-
'</div>';
|
|
216
|
+
if (streamedText) html += '<div>' + renderMd(streamedText) + '</div>';
|
|
217
|
+
html += '<div style="display:flex;align-items:center;gap:8px;flex-wrap:wrap">' +
|
|
218
|
+
'<span class="dot-pulse"><span></span><span></span><span></span></span>' +
|
|
219
|
+
'<span id="' + loadingId + '-text">' + escHtml(label) + '</span>' +
|
|
220
|
+
'<span id="' + loadingId + '-time" style="font-size:10px;color:var(--muted)">' + elapsedSeconds + 's</span>' +
|
|
221
|
+
'<button onclick="qaAbort()" style="font-size:9px;padding:2px 8px;background:var(--surface2);border:1px solid var(--border);border-radius:4px;color:var(--red);cursor:pointer">Stop</button>' +
|
|
222
|
+
qaQueueBadge +
|
|
223
|
+
'</div>';
|
|
224
|
+
html += '</div>';
|
|
224
225
|
return html;
|
|
225
226
|
}
|
|
226
227
|
|
|
@@ -291,7 +292,6 @@ function _initQaSession() {
|
|
|
291
292
|
if (!key || _qaSessionKey === key) return;
|
|
292
293
|
if (_qaSessionKey && _qaSessionKey !== key) _qaSaveActiveSessionState();
|
|
293
294
|
_qaSessionKey = key;
|
|
294
|
-
_qaThreadCollapsed = false;
|
|
295
295
|
const card = findCardForFile(_modalFilePath);
|
|
296
296
|
if (card) clearNotifBadge(card);
|
|
297
297
|
var prior = _qaSessions.get(key);
|
|
@@ -307,7 +307,7 @@ function _initQaSession() {
|
|
|
307
307
|
});
|
|
308
308
|
}
|
|
309
309
|
if (prior.filePath) _modalFilePath = prior.filePath;
|
|
310
|
-
_showThreadWrap(
|
|
310
|
+
_showThreadWrap();
|
|
311
311
|
requestAnimationFrame(function() {
|
|
312
312
|
var thread = document.getElementById('modal-qa-thread');
|
|
313
313
|
if (thread) thread.scrollTop = thread.scrollHeight;
|
|
@@ -333,7 +333,6 @@ function clearQaConversation() {
|
|
|
333
333
|
_qaQueue = [];
|
|
334
334
|
_qaProcessing = false;
|
|
335
335
|
_qaAbortController = null;
|
|
336
|
-
_qaThreadCollapsed = false;
|
|
337
336
|
document.getElementById('modal-qa-thread').innerHTML = '';
|
|
338
337
|
var wrap = document.getElementById('modal-qa-thread-wrap');
|
|
339
338
|
var expandBar = document.getElementById('qa-expand-bar');
|
|
@@ -433,6 +432,21 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
433
432
|
: [[0,'Thinking...'],[3000,'Reading document...'],[8000,'Analyzing...'],[20000,'Still working...'],[60000,'Taking a while...']];
|
|
434
433
|
let streamedText = '';
|
|
435
434
|
let toolsUsed = [];
|
|
435
|
+
let _qaStreamStalled = false;
|
|
436
|
+
let _qaStallTimer = null;
|
|
437
|
+
function _clearQaStreamWatchdog() {
|
|
438
|
+
if (_qaStallTimer) {
|
|
439
|
+
clearTimeout(_qaStallTimer);
|
|
440
|
+
_qaStallTimer = null;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
function _resetQaStreamWatchdog() {
|
|
444
|
+
_clearQaStreamWatchdog();
|
|
445
|
+
_qaStallTimer = setTimeout(() => {
|
|
446
|
+
_qaStreamStalled = true;
|
|
447
|
+
try { abortController.abort(); } catch {}
|
|
448
|
+
}, QA_STREAM_STALL_MS);
|
|
449
|
+
}
|
|
436
450
|
function _qaProgressLabel(elapsed) {
|
|
437
451
|
let label = qaPhases[0][1];
|
|
438
452
|
for (let i = qaPhases.length - 1; i >= 0; i--) {
|
|
@@ -471,6 +485,7 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
471
485
|
_qaRenderProgress(false);
|
|
472
486
|
}, 500);
|
|
473
487
|
_qaRenderProgress(false);
|
|
488
|
+
_resetQaStreamWatchdog();
|
|
474
489
|
|
|
475
490
|
try {
|
|
476
491
|
const res = await fetch('/api/doc-chat/stream', {
|
|
@@ -507,11 +522,13 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
507
522
|
if (!evt || !evt.type) return;
|
|
508
523
|
if (evt.type === 'heartbeat') return;
|
|
509
524
|
if (evt.type === 'chunk') {
|
|
525
|
+
_resetQaStreamWatchdog();
|
|
510
526
|
streamedText = evt.text || '';
|
|
511
527
|
_qaRenderProgress(true);
|
|
512
528
|
return;
|
|
513
529
|
}
|
|
514
530
|
if (evt.type === 'tool') {
|
|
531
|
+
_resetQaStreamWatchdog();
|
|
515
532
|
toolsUsed.push({ name: evt.name, input: evt.input || {} });
|
|
516
533
|
_qaRenderProgress(true);
|
|
517
534
|
return;
|
|
@@ -519,6 +536,7 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
519
536
|
if (evt.type === 'done') {
|
|
520
537
|
terminalEventSeen = true;
|
|
521
538
|
clearInterval(qaTimer);
|
|
539
|
+
_clearQaStreamWatchdog();
|
|
522
540
|
const qaElapsed = Math.round((Date.now() - qaStartTime) / 1000);
|
|
523
541
|
const borderColor = evt.edited ? 'var(--green)' : 'var(--blue)';
|
|
524
542
|
const suffix = evt.edited ? '\n\n\u2713 Document saved.' : '';
|
|
@@ -565,7 +583,10 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
565
583
|
});
|
|
566
584
|
return;
|
|
567
585
|
}
|
|
568
|
-
if (evt.type === 'error')
|
|
586
|
+
if (evt.type === 'error') {
|
|
587
|
+
_clearQaStreamWatchdog();
|
|
588
|
+
throw new Error(evt.error || 'Failed');
|
|
589
|
+
}
|
|
569
590
|
}
|
|
570
591
|
|
|
571
592
|
while (true) {
|
|
@@ -591,8 +612,14 @@ async function _processQaMessage(message, selection, opts) {
|
|
|
591
612
|
if (!terminalEventSeen) throw new Error('The response stream ended before completion.');
|
|
592
613
|
} catch (e) {
|
|
593
614
|
clearInterval(qaTimer);
|
|
615
|
+
_clearQaStreamWatchdog();
|
|
594
616
|
const qaElapsedExc = Math.round((Date.now() - qaStartTime) / 1000);
|
|
595
|
-
const
|
|
617
|
+
const stallMessage = 'Doc chat stalled with no tool or text progress for 90s.';
|
|
618
|
+
const messageHtml = _qaStreamStalled
|
|
619
|
+
? (streamedText
|
|
620
|
+
? _qaBuildAssistantHtml(streamedText + '\n\nError: ' + stallMessage, { borderColor: 'var(--red)', elapsed: qaElapsedExc })
|
|
621
|
+
: _qaBuildAssistantHtml('Error: ' + stallMessage, { color: 'var(--red)', isError: true, elapsed: qaElapsedExc }))
|
|
622
|
+
: e.name === 'AbortError'
|
|
596
623
|
? (streamedText
|
|
597
624
|
? _qaBuildAssistantHtml(streamedText + '\n\n_Stopped._', { borderColor: 'var(--muted)', elapsed: qaElapsedExc })
|
|
598
625
|
: _qaBuildAssistantHtml('Stopped', { color: 'var(--muted)', isError: true, elapsed: qaElapsedExc }))
|
|
@@ -674,18 +701,15 @@ function toggleDocChat() {
|
|
|
674
701
|
var expandBar = document.getElementById('qa-expand-bar');
|
|
675
702
|
if (!wrap) return;
|
|
676
703
|
var visible = wrap.style.display !== 'none';
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
wrap.style.display = nextVisible ? '' : 'none';
|
|
680
|
-
if (expandBar) expandBar.style.display = nextVisible ? 'none' : '';
|
|
704
|
+
wrap.style.display = visible ? 'none' : '';
|
|
705
|
+
if (expandBar) expandBar.style.display = visible ? '' : 'none';
|
|
681
706
|
}
|
|
682
707
|
|
|
683
|
-
function _showThreadWrap(
|
|
708
|
+
function _showThreadWrap() {
|
|
684
709
|
var wrap = document.getElementById('modal-qa-thread-wrap');
|
|
685
710
|
var expandBar = document.getElementById('qa-expand-bar');
|
|
686
|
-
if (
|
|
687
|
-
if (
|
|
688
|
-
if (expandBar) expandBar.style.display = _qaThreadCollapsed ? '' : 'none';
|
|
711
|
+
if (wrap) wrap.style.display = '';
|
|
712
|
+
if (expandBar) expandBar.style.display = 'none';
|
|
689
713
|
}
|
|
690
714
|
|
|
691
715
|
// ── Drag-to-resize doc chat thread ──────────────────────────────────────────
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1584",
|
|
4
4
|
"description": "Multi-agent AI dev team that runs from ~/.minions/ — five autonomous agents share a single engine, dashboard, and knowledge base",
|
|
5
5
|
"bin": {
|
|
6
6
|
"minions": "bin/minions.js"
|