@yemi33/minions 0.1.568 → 0.1.570

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 CHANGED
@@ -1,10 +1,14 @@
1
1
  # Changelog
2
2
 
3
- ## 0.1.568 (2026-04-08)
3
+ ## 0.1.570 (2026-04-08)
4
4
 
5
5
  ### Features
6
+ - add LLM Call Performance tile to engine page
6
7
  - add ccModel/ccEffort settings and agent runtime tracking
7
8
 
9
+ ### Fixes
10
+ - remove dead Context Pressure tile from engine page
11
+
8
12
  ### Other
9
13
  - refactor: use safeJson/safeWrite for spawn-agent cache, remove unused checkedAt
10
14
 
@@ -42,7 +42,6 @@ function renderMetrics(metrics) {
42
42
  if (agents.length === 0) {
43
43
  el.innerHTML = '<p class="empty">No metrics yet. Metrics appear after agents complete tasks.</p>';
44
44
  renderTokenUsage(metrics);
45
- renderContextPressure(metrics);
46
45
  return;
47
46
  }
48
47
  // Consolidate temp-* agents into one row
@@ -90,8 +89,35 @@ function renderMetrics(metrics) {
90
89
  }
91
90
  html += '</tbody></table>';
92
91
  el.innerHTML = html;
92
+ renderLlmPerf(metrics);
93
93
  renderTokenUsage(metrics);
94
- renderContextPressure(metrics);
94
+ }
95
+
96
+ function renderLlmPerf(metrics) {
97
+ const el = document.getElementById('llm-perf-content');
98
+ if (!el) return;
99
+ const engine = metrics._engine;
100
+ if (!engine || Object.keys(engine).length === 0) {
101
+ el.innerHTML = '<p class="empty">No LLM performance data yet.</p>';
102
+ return;
103
+ }
104
+ 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>';
105
+ const entries = Object.entries(engine).sort((a, b) => (b[1].calls || 0) - (a[1].calls || 0));
106
+ for (const [type, m] of entries) {
107
+ const calls = m.calls || 0;
108
+ const totalMs = m.totalDurationMs || 0;
109
+ const avgMs = calls > 0 ? totalMs / calls : 0;
110
+ const fmtTotal = totalMs < 60000 ? Math.round(totalMs / 1000) + 's' : Math.round(totalMs / 60000) + 'm';
111
+ const fmtAvg = avgMs < 1000 ? Math.round(avgMs) + 'ms' : avgMs < 60000 ? Math.round(avgMs / 1000) + 's' : Math.round(avgMs / 60000) + 'm';
112
+ const cost = m.costUsd ? '$' + m.costUsd.toFixed(2) : '-';
113
+ html += '<tr><td style="font-weight:600">' + escHtml(type) + '</td>' +
114
+ '<td>' + calls + '</td>' +
115
+ '<td style="color:var(--muted)">' + (totalMs ? fmtTotal : '-') + '</td>' +
116
+ '<td style="color:var(--blue)">' + (avgMs ? fmtAvg : '-') + '</td>' +
117
+ '<td style="color:var(--muted)">' + cost + '</td></tr>';
118
+ }
119
+ html += '</tbody></table>';
120
+ el.innerHTML = html;
95
121
  }
96
122
 
97
123
  function renderTokenUsage(metrics) {
@@ -229,26 +255,6 @@ function renderTokenUsage(metrics) {
229
255
  el.innerHTML = html;
230
256
  }
231
257
 
232
- function renderContextPressure(metrics) {
233
- const el = document.getElementById('context-pressure-content');
234
- if (!el) return;
235
- const cp = metrics._contextPressure;
236
- if (!cp || !cp.dispatches) {
237
- el.innerHTML = '<p class="empty">No context pressure data yet. Data appears after agents complete tasks.</p>';
238
- return;
239
- }
240
- const avgTurns = (cp.totalTurns / cp.dispatches).toFixed(1);
241
- const turnLimitPct = ((cp.turnLimitHits / cp.dispatches) * 100).toFixed(1);
242
- const pctColor = parseFloat(turnLimitPct) > 20 ? 'var(--red)' : parseFloat(turnLimitPct) > 5 ? 'var(--yellow, orange)' : 'var(--green)';
243
-
244
- let html = '<div class="token-tiles">';
245
- html += '<div class="token-tile"><div class="token-tile-label">Avg Turns</div><div class="token-tile-value">' + avgTurns + '</div><div class="token-tile-sub">per dispatch</div></div>';
246
- html += '<div class="token-tile"><div class="token-tile-label">Max Turns</div><div class="token-tile-value">' + cp.maxTurns + '</div></div>';
247
- html += '<div class="token-tile"><div class="token-tile-label">Hit Turn Limit</div><div class="token-tile-value" style="color:' + pctColor + '">' + turnLimitPct + '%</div><div class="token-tile-sub">' + cp.turnLimitHits + ' of ' + cp.dispatches + ' dispatches</div></div>';
248
- html += '<div class="token-tile"><div class="token-tile-label">Total Dispatches</div><div class="token-tile-value">' + cp.dispatches + '</div></div>';
249
- html += '</div>';
250
- el.innerHTML = html;
251
- }
252
258
 
253
259
  async function openScanProjectsModal() {
254
260
  document.getElementById('modal-title').textContent = 'Scan for Projects';
@@ -345,4 +351,4 @@ async function _addSelectedProjects() {
345
351
  }
346
352
  }
347
353
 
348
- window.MinionsOther = { renderProjects, renderMcpServers, renderMetrics, renderTokenUsage, renderContextPressure, openScanProjectsModal };
354
+ window.MinionsOther = { renderProjects, renderMcpServers, renderMetrics, renderLlmPerf, renderTokenUsage, openScanProjectsModal };
@@ -2,6 +2,10 @@
2
2
  <h2>Engine Log <span style="font-size:10px;color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0">tick-by-tick audit trail of engine operations</span></h2>
3
3
  <div class="log-list" id="engine-log">No log entries yet.</div>
4
4
  </section>
5
+ <section>
6
+ <h2>LLM Call Performance</h2>
7
+ <div id="llm-perf-content"><p class="empty">No LLM performance data yet. Data appears after CC, doc-chat, or consolidation calls.</p></div>
8
+ </section>
5
9
  <section>
6
10
  <h2>Agent Metrics</h2>
7
11
  <div id="metrics-content"><p class="empty">No metrics yet. Metrics appear after agents complete tasks.</p></div>
@@ -10,7 +14,3 @@
10
14
  <h2>Token Usage</h2>
11
15
  <div id="token-usage-content"><p class="empty">No usage data yet.</p></div>
12
16
  </section>
13
- <section>
14
- <h2>Context Pressure</h2>
15
- <div id="context-pressure-content"><p class="empty">No context pressure data yet. Data appears after agents complete tasks.</p></div>
16
- </section>
package/engine/llm.js CHANGED
@@ -27,6 +27,7 @@ function trackEngineUsage(category, usage) {
27
27
  cat.outputTokens += usage.outputTokens || 0;
28
28
  cat.cacheRead += usage.cacheRead || 0;
29
29
  cat.cacheCreation = (cat.cacheCreation || 0) + (usage.cacheCreation || 0);
30
+ if (usage.durationMs) cat.totalDurationMs = (cat.totalDurationMs || 0) + usage.durationMs;
30
31
 
31
32
  const today = ts().slice(0, 10);
32
33
  if (!metrics._daily) metrics._daily = {};
@@ -66,6 +67,7 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
66
67
 
67
68
  if (sessionId) args.push('--resume', sessionId);
68
69
 
70
+ const _startMs = Date.now();
69
71
  const proc = runFile(process.execPath, args, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
70
72
 
71
73
  let stdout = '';
@@ -80,7 +82,9 @@ function callLLM(promptText, sysPromptText, { timeout = 120000, label = 'llm', m
80
82
  safeUnlink(promptPath);
81
83
  safeUnlink(sysPath);
82
84
  const parsed = parseStreamJsonOutput(stdout);
83
- resolve({ text: parsed.text || '', usage: parsed.usage, sessionId: parsed.sessionId || null, code, stderr, raw: stdout });
85
+ const durationMs = Date.now() - _startMs;
86
+ const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
87
+ resolve({ text: parsed.text || '', usage, sessionId: parsed.sessionId || null, code, stderr, raw: stdout });
84
88
  });
85
89
 
86
90
  proc.on('error', (err) => {
@@ -136,6 +140,7 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
136
140
  args.push('--permission-mode', 'bypassPermissions');
137
141
  if (sessionId) args.push('--resume', sessionId);
138
142
 
143
+ const _startMs = Date.now();
139
144
  const proc = runFile(process.execPath, args, { cwd: MINIONS_DIR, stdio: ['pipe', 'pipe', 'pipe'], env: cleanChildEnv() });
140
145
 
141
146
  _abort = () => { shared.killImmediate(proc); };
@@ -179,7 +184,9 @@ function callLLMStreaming(promptText, sysPromptText, { timeout = 120000, label =
179
184
  safeUnlink(promptPath);
180
185
  safeUnlink(sysPath);
181
186
  const parsed = parseStreamJsonOutput(stdout);
182
- resolve({ text: parsed.text || '', usage: parsed.usage, sessionId: parsed.sessionId || null, code, stderr, raw: stdout });
187
+ const durationMs = Date.now() - _startMs;
188
+ const usage = parsed.usage ? { ...parsed.usage, durationMs } : { durationMs };
189
+ resolve({ text: parsed.text || '', usage, sessionId: parsed.sessionId || null, code, stderr, raw: stdout });
183
190
  });
184
191
 
185
192
  proc.on('error', (err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yemi33/minions",
3
- "version": "0.1.568",
3
+ "version": "0.1.570",
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"