@yemi33/minions 0.1.1932 → 0.1.1933
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/dashboard.js +31 -0
- package/engine/cc-worker-pool.js +9 -0
- package/engine/copilot-models.json +1 -1
- package/package.json +1 -1
package/dashboard.js
CHANGED
|
@@ -6368,7 +6368,28 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6368
6368
|
let accumulated = '';
|
|
6369
6369
|
let sessionHandle = null;
|
|
6370
6370
|
let resolveResult;
|
|
6371
|
+
// Per-turn phase timing — emitted as one structured [cc-timing] log line
|
|
6372
|
+
// so we can attribute Copilot CC slowness (e.g. 36s) to spawn vs first-byte
|
|
6373
|
+
// vs streaming vs trailing inference. Parallels engine.js's [spawn-timing].
|
|
6374
|
+
const _tStart = Date.now();
|
|
6375
|
+
let _tFirstByte = null;
|
|
6376
|
+
let _tFirstTool = null;
|
|
6377
|
+
let _chunkCount = 0;
|
|
6378
|
+
let _toolUseCount = 0;
|
|
6371
6379
|
const promise = new Promise((resolve) => { resolveResult = resolve; });
|
|
6380
|
+
const _emitTimingLog = (lifecycle, sessionReady, streamEnd, outcome) => {
|
|
6381
|
+
try {
|
|
6382
|
+
const _diff = (a, b) => (a != null && b != null) ? (b - a) : null;
|
|
6383
|
+
const timings = {
|
|
6384
|
+
get_session: _diff(_tStart, sessionReady),
|
|
6385
|
+
first_byte: _diff(sessionReady, _tFirstByte),
|
|
6386
|
+
first_tool: _diff(sessionReady, _tFirstTool),
|
|
6387
|
+
stream: _diff(sessionReady, streamEnd),
|
|
6388
|
+
total: _diff(_tStart, streamEnd),
|
|
6389
|
+
};
|
|
6390
|
+
shared.log('info', `[cc-timing] tab=${resolvedTabId} lifecycle=${lifecycle || 'unknown'} outcome=${outcome} chunks=${_chunkCount} tools=${_toolUseCount} ${JSON.stringify(timings)}`);
|
|
6391
|
+
} catch { /* telemetry is best-effort */ }
|
|
6392
|
+
};
|
|
6372
6393
|
promise.abort = () => {
|
|
6373
6394
|
cancelled = true;
|
|
6374
6395
|
try { sessionHandle && sessionHandle.cancel(); } catch { /* swallow */ }
|
|
@@ -6383,6 +6404,7 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6383
6404
|
systemPromptHash: _ccPromptHash,
|
|
6384
6405
|
});
|
|
6385
6406
|
} catch (err) {
|
|
6407
|
+
_emitTimingLog(null, null, Date.now(), 'spawn-failed');
|
|
6386
6408
|
return resolveResult({
|
|
6387
6409
|
text: '',
|
|
6388
6410
|
sessionId: null,
|
|
@@ -6392,19 +6414,26 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6392
6414
|
stderr: String((err && err.message) || err || 'cc-worker-pool spawn failed'),
|
|
6393
6415
|
});
|
|
6394
6416
|
}
|
|
6417
|
+
const _tSessionReady = Date.now();
|
|
6418
|
+
const _lifecycle = sessionHandle.lifecycle || 'unknown';
|
|
6395
6419
|
if (cancelled) {
|
|
6396
6420
|
try { sessionHandle.cancel(); } catch { /* swallow */ }
|
|
6421
|
+
_emitTimingLog(_lifecycle, _tSessionReady, Date.now(), 'cancelled-pre-stream');
|
|
6397
6422
|
return resolveResult({ text: accumulated, sessionId: sessionHandle.sessionId, code: 0, usage: {}, raw: accumulated, stderr: '' });
|
|
6398
6423
|
}
|
|
6399
6424
|
await sessionHandle.stream(prompt, {
|
|
6400
6425
|
systemPromptText: systemPrompt,
|
|
6401
6426
|
onChunk: (delta) => {
|
|
6427
|
+
if (_tFirstByte == null) _tFirstByte = Date.now();
|
|
6428
|
+
_chunkCount += 1;
|
|
6402
6429
|
accumulated += delta;
|
|
6403
6430
|
_touchCcLiveStream(liveState);
|
|
6404
6431
|
liveState.text = accumulated;
|
|
6405
6432
|
if (liveState.writer) liveState.writer({ type: 'chunk', text: accumulated });
|
|
6406
6433
|
},
|
|
6407
6434
|
onToolUse: (name, input) => {
|
|
6435
|
+
if (_tFirstTool == null) _tFirstTool = Date.now();
|
|
6436
|
+
_toolUseCount += 1;
|
|
6408
6437
|
_touchCcLiveStream(liveState);
|
|
6409
6438
|
const safeInput = input || {};
|
|
6410
6439
|
if (Array.isArray(toolUses)) toolUses.push({ name, input: safeInput });
|
|
@@ -6412,9 +6441,11 @@ What would you like to discuss or change? When you're happy, say "approve" and I
|
|
|
6412
6441
|
if (liveState.writer) liveState.writer({ type: 'tool', name, input: _lightToolInput(safeInput) });
|
|
6413
6442
|
},
|
|
6414
6443
|
onDone: () => {
|
|
6444
|
+
_emitTimingLog(_lifecycle, _tSessionReady, Date.now(), 'done');
|
|
6415
6445
|
resolveResult({ text: accumulated, sessionId: sessionHandle.sessionId, code: 0, usage: {}, raw: accumulated, stderr: '' });
|
|
6416
6446
|
},
|
|
6417
6447
|
onError: (err) => {
|
|
6448
|
+
_emitTimingLog(_lifecycle, _tSessionReady, Date.now(), cancelled ? 'cancelled' : 'error');
|
|
6418
6449
|
resolveResult({
|
|
6419
6450
|
text: accumulated,
|
|
6420
6451
|
sessionId: sessionHandle.sessionId,
|
package/engine/cc-worker-pool.js
CHANGED
|
@@ -483,6 +483,12 @@ async function getSession({ tabId, model, effort, mcpServers, systemPromptHash,
|
|
|
483
483
|
if (!tabId) throw new Error('cc-worker-pool.getSession: tabId is required');
|
|
484
484
|
const mcpServersHash = _hashMcpServers(mcpServers);
|
|
485
485
|
let worker = _tabs.get(tabId);
|
|
486
|
+
// Track which lifecycle path we took so the dashboard's [cc-timing] log can
|
|
487
|
+
// attribute warm-reuse vs new-session vs cold-spawn. One of:
|
|
488
|
+
// 'warm-reuse' — proc + session both reused (no spawn, no session/new)
|
|
489
|
+
// 'new-session' — proc reused, fresh session/new (sysprompt hash changed)
|
|
490
|
+
// 'cold-spawn' — fresh proc + initialize + session/new
|
|
491
|
+
let lifecycle = 'warm-reuse';
|
|
486
492
|
|
|
487
493
|
if (worker) {
|
|
488
494
|
if (worker.killed) {
|
|
@@ -501,6 +507,7 @@ async function getSession({ tabId, model, effort, mcpServers, systemPromptHash,
|
|
|
501
507
|
// caller has rotated in (Bug B / issue #2479).
|
|
502
508
|
await worker.newSession({ mcpServers, systemPromptHash, model, effort });
|
|
503
509
|
worker.lastUsedAt = _internals.now();
|
|
510
|
+
lifecycle = 'new-session';
|
|
504
511
|
} else {
|
|
505
512
|
// Warm reuse — only update bookkeeping. model/effort changes on a
|
|
506
513
|
// warm session are tracked here but not pushed via configOptions in
|
|
@@ -524,12 +531,14 @@ async function getSession({ tabId, model, effort, mcpServers, systemPromptHash,
|
|
|
524
531
|
try { worker.close(); } catch { /* already torn down */ }
|
|
525
532
|
throw err;
|
|
526
533
|
}
|
|
534
|
+
lifecycle = 'cold-spawn';
|
|
527
535
|
}
|
|
528
536
|
|
|
529
537
|
_ensureReaper();
|
|
530
538
|
|
|
531
539
|
return {
|
|
532
540
|
sessionId: worker.sessionId,
|
|
541
|
+
lifecycle,
|
|
533
542
|
stream: (promptText, opts) => worker.stream(promptText, opts),
|
|
534
543
|
cancel: () => worker.cancel(),
|
|
535
544
|
close: () => closeTab(tabId),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yemi33/minions",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1933",
|
|
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"
|