@yemi33/minions 0.1.1926 → 0.1.1927

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.
@@ -166,9 +166,15 @@ function renderLlmPerf(metrics) {
166
166
  el.innerHTML = '<p class="empty">No LLM performance data yet.</p>';
167
167
  return;
168
168
  }
169
- let html = '<table class="pr-table"><thead><tr><th>Call Type</th><th>Calls</th><th>Total Time</th><th>Avg Time</th><th>Cost</th></tr></thead><tbody>';
170
- const entries = Object.entries(engine).filter(([k]) => !k.startsWith('test')).sort((a, b) => (b[1].calls || 0) - (a[1].calls || 0));
171
- for (const [type, m] of entries) {
169
+ // Split entries: per-LLM-call rows vs per-agent-task agent-dispatch row.
170
+ // `calls` semantics differ between the two agent-dispatch counts dispatched
171
+ // work items (with runtimeMs = wall-clock of the agent process), the others
172
+ // count LLM API round-trips (with totalDurationMs = sum of per-call latencies).
173
+ const filtered = Object.entries(engine).filter(([k]) => !k.startsWith('test'));
174
+ const perCall = filtered.filter(([k]) => k !== 'agent-dispatch')
175
+ .sort((a, b) => (b[1].calls || 0) - (a[1].calls || 0));
176
+ const perTask = filtered.filter(([k]) => k === 'agent-dispatch');
177
+ function renderRow(type, m) {
172
178
  const calls = m.calls || 0;
173
179
  const totalMs = m.totalDurationMs || 0;
174
180
  const timedCalls = m.timedCalls || 0;
@@ -176,16 +182,48 @@ function renderLlmPerf(metrics) {
176
182
  const fmtTotal = totalMs < 60000 ? Math.round(totalMs / 1000) + 's' : Math.round(totalMs / 60000) + 'm';
177
183
  const fmtAvg = avgMs < 1000 ? Math.round(avgMs) + 'ms' : avgMs < 60000 ? Math.round(avgMs / 1000) + 's' : Math.round(avgMs / 60000) + 'm';
178
184
  const cost = m.costUsd ? '$' + m.costUsd.toFixed(2) : '-';
179
- html += '<tr><td style="font-weight:600">' + escHtml(type) + '</td>' +
185
+ return '<tr><td style="font-weight:600">' + escHtml(type) + '</td>' +
180
186
  '<td>' + calls + '</td>' +
181
187
  '<td style="color:var(--muted)">' + (totalMs ? fmtTotal : '-') + '</td>' +
182
188
  '<td style="color:var(--blue)">' + (avgMs ? fmtAvg : '-') + '</td>' +
183
189
  '<td style="color:var(--muted)">' + cost + '</td></tr>';
184
190
  }
191
+ let html = '<table class="pr-table"><thead><tr><th>Call Type</th><th>Calls</th><th>Total Time</th><th>Avg Time</th><th>Cost</th></tr></thead><tbody>';
192
+ for (const [type, m] of perCall) {
193
+ html += renderRow(type, m);
194
+ }
195
+ if (perTask.length > 0) {
196
+ // Visual divider + caption row to distinguish per-call (above) from
197
+ // per-task (below) — column units differ.
198
+ html += '<tr><td colspan="5" style="border-top:2px solid var(--border);padding-top:6px;font-size:10px;color:var(--muted);font-style:italic">— per agent task (calls = dispatched work items, time = wall-clock of agent process) —</td></tr>';
199
+ for (const [type, m] of perTask) {
200
+ html += renderRow(type + ' (per task)', m);
201
+ }
202
+ }
185
203
  html += '</tbody></table>';
186
204
  el.innerHTML = html;
187
205
  }
188
206
 
207
+ // Aggregate _engine entries for the Token Usage summary tiles.
208
+ // Excludes:
209
+ // - 'agent-dispatch' (already counted in per-agent metrics[agentId] totals;
210
+ // summing both would double-count agent spend in the tile)
211
+ // - 'test-*' / '_test*' (matching engine/llm.js trackEngineUsage filter so
212
+ // stale test categories don't inflate engineCalls)
213
+ function _aggregateEngineUsageForTokenTile(engine) {
214
+ let cost = 0, input = 0, output = 0, cache = 0, calls = 0;
215
+ for (const [k, e] of Object.entries(engine || {})) {
216
+ if (k === 'agent-dispatch') continue;
217
+ if (k.startsWith('test-') || k.startsWith('_test')) continue;
218
+ cost += e.costUsd || 0;
219
+ input += e.inputTokens || 0;
220
+ output += e.outputTokens || 0;
221
+ cache += e.cacheRead || 0;
222
+ calls += e.calls || 0;
223
+ }
224
+ return { cost, input, output, cache, calls };
225
+ }
226
+
189
227
  function renderTokenUsage(metrics) {
190
228
  const el = document.getElementById('token-usage-content');
191
229
  const agents = Object.entries(metrics).filter(([k]) => !k.startsWith('_'));
@@ -201,15 +239,11 @@ function renderTokenUsage(metrics) {
201
239
  agentCache += m.totalCacheRead || 0;
202
240
  }
203
241
 
204
- // Aggregate engine totals
205
- let engineCost = 0, engineInput = 0, engineOutput = 0, engineCache = 0, engineCalls = 0;
206
- for (const [, e] of Object.entries(engine)) {
207
- engineCost += e.costUsd || 0;
208
- engineInput += e.inputTokens || 0;
209
- engineOutput += e.outputTokens || 0;
210
- engineCache += e.cacheRead || 0;
211
- engineCalls += e.calls || 0;
212
- }
242
+ // Aggregate engine totals (excludes agent-dispatch + test-* — see helper)
243
+ const engAgg = _aggregateEngineUsageForTokenTile(engine);
244
+ const engineCost = engAgg.cost, engineInput = engAgg.input,
245
+ engineOutput = engAgg.output, engineCache = engAgg.cache,
246
+ engineCalls = engAgg.calls; // eslint-disable-line no-unused-vars
213
247
 
214
248
  const totalCost = agentCost + engineCost;
215
249
  const totalInput = agentInput + engineInput;
@@ -430,4 +464,4 @@ async function _addSelectedProjects() {
430
464
  }
431
465
  }
432
466
 
433
- window.MinionsOther = { renderProjects, optimisticallyAddProject, projectChipRemove, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, openScanProjectsModal };
467
+ window.MinionsOther = { renderProjects, optimisticallyAddProject, projectChipRemove, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, _aggregateEngineUsageForTokenTile, openScanProjectsModal };
@@ -0,0 +1,5 @@
1
+ {
2
+ "runtime": "copilot",
3
+ "models": null,
4
+ "cachedAt": "2026-05-14T02:06:41.197Z"
5
+ }
@@ -2550,8 +2550,14 @@ function updateMetrics(agentId, dispatchItem, result, taskUsage, prsCreatedCount
2550
2550
  metrics._engine['agent-dispatch'] = { calls: 0, costUsd: 0, inputTokens: 0, outputTokens: 0, cacheRead: 0, cacheCreation: 0, totalDurationMs: 0 };
2551
2551
  }
2552
2552
  const eng = metrics._engine['agent-dispatch'];
2553
- eng.calls++;
2553
+ // Gate calls on runtimeMs > 0 so pre-spawn skips (deps unmet, cooldown,
2554
+ // classified-fail) don't inflate the dispatch-tile call count. `calls` and
2555
+ // `timedCalls` advance together for agent-dispatch; both fields are kept
2556
+ // for schema parity with other _engine entries (CC/doc-chat/consolidation/
2557
+ // kb-sweep) where calls = LLM round-trips and timedCalls subset = ones with
2558
+ // a measured durationMs.
2554
2559
  if (runtimeMs > 0) {
2560
+ eng.calls++;
2555
2561
  eng.totalDurationMs = (eng.totalDurationMs || 0) + runtimeMs;
2556
2562
  eng.timedCalls = (eng.timedCalls || 0) + 1;
2557
2563
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.1926",
3
+ "version": "0.1.1927",
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"