LLM popup: show live usage stats as probability slider moves
Browse filesSlider now shows real-time estimates that update on drag:
- "X% of decisions via LLM" (how many agent actions use LLM vs routine)
- "~Y calls/hour" (accounting for RPM cap, budget per tick, agent count)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- web/index.html +31 -5
web/index.html
CHANGED
|
@@ -3469,21 +3469,42 @@ document.getElementById('llm-model').addEventListener('click', async (e) => {
|
|
| 3469 |
}
|
| 3470 |
|
| 3471 |
const runtime = estimateRuntime(pqForCalc);
|
|
|
|
| 3472 |
// Default probability for rate-limited providers (not inherited from NN's 100%)
|
| 3473 |
const defaultProb = 10;
|
| 3474 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3475 |
panel.innerHTML =
|
| 3476 |
`<div style="color:#4ecca3;font-weight:600;margin-bottom:4px">${p.icon} ${p.label}</div>` +
|
| 3477 |
-
`<div style="margin-bottom:4px">Daily limit: <b>${lim}</b> requests</div>` +
|
| 3478 |
-
`<div style="margin-bottom:6px;font-size:10px;color:#8899aa">` +
|
| 3479 |
-
`${rpm} req/min · Max runtime: <b style="color:#4ecca3">${runtime}</b></div>` +
|
| 3480 |
`<div style="display:flex;align-items:center;gap:8px;margin-top:6px">` +
|
| 3481 |
`<label style="font-size:11px;color:#8899aa">Probability:</label>` +
|
| 3482 |
`<input type="range" min="1" max="100" value="${defaultProb}" style="flex:1;accent-color:#4ecca3" class="popup-prob-slider">` +
|
| 3483 |
`<span class="popup-prob-val" style="font-size:12px;color:#4ecca3;min-width:32px">${defaultProb}%</span>` +
|
| 3484 |
`</div>` +
|
| 3485 |
-
`<div style="font-size:10px;color:#8899aa;margin:
|
| 3486 |
-
`
|
|
|
|
|
|
|
| 3487 |
`<button class="popup-switch-btn" style="width:100%;padding:6px;border:none;border-radius:4px;` +
|
| 3488 |
`background:#4ecca3;color:#0a0a23;font-weight:600;cursor:pointer;font-size:12px">` +
|
| 3489 |
`Switch to ${p.label} at ${defaultProb}%</button>`;
|
|
@@ -3493,12 +3514,17 @@ document.getElementById('llm-model').addEventListener('click', async (e) => {
|
|
| 3493 |
// Wire up slider
|
| 3494 |
const slider = panel.querySelector('.popup-prob-slider');
|
| 3495 |
const valLabel = panel.querySelector('.popup-prob-val');
|
|
|
|
| 3496 |
const btn = panel.querySelector('.popup-switch-btn');
|
| 3497 |
|
| 3498 |
slider.addEventListener('input', (e) => {
|
| 3499 |
e.stopPropagation();
|
| 3500 |
const pv = parseInt(slider.value);
|
| 3501 |
valLabel.textContent = pv + '%';
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3502 |
btn.textContent = `Switch to ${p.label} at ${pv}%`;
|
| 3503 |
});
|
| 3504 |
|
|
|
|
| 3469 |
}
|
| 3470 |
|
| 3471 |
const runtime = estimateRuntime(pqForCalc);
|
| 3472 |
+
const numAgents = quota.num_agents || 50;
|
| 3473 |
// Default probability for rate-limited providers (not inherited from NN's 100%)
|
| 3474 |
const defaultProb = 10;
|
| 3475 |
|
| 3476 |
+
// Calculate usage stats for a given probability
|
| 3477 |
+
function usageStats(probPct) {
|
| 3478 |
+
const prob = probPct / 100;
|
| 3479 |
+
// ~40% of agents are idle (not busy/sleeping) and eligible for LLM each tick
|
| 3480 |
+
const idleFraction = 0.4;
|
| 3481 |
+
const eligibleAgents = Math.round(numAgents * idleFraction);
|
| 3482 |
+
// Expected LLM attempts per tick: eligible agents × prob (action) + prob (social)
|
| 3483 |
+
const attemptsPerTick = eligibleAgents * prob + prob;
|
| 3484 |
+
// Budget caps at 2 calls/tick for rate-limited providers
|
| 3485 |
+
const callsPerTick = Math.min(attemptsPerTick, 2);
|
| 3486 |
+
// Ticks per hour (4s tick delay at 1x speed)
|
| 3487 |
+
const ticksH = 900;
|
| 3488 |
+
const callsPerHour = Math.min(callsPerTick * ticksH, rpm * 60);
|
| 3489 |
+
// What % of agent decisions go through LLM vs routine
|
| 3490 |
+
const llmPct = Math.min(prob * 100, 100);
|
| 3491 |
+
return { callsPerHour: Math.round(callsPerHour), llmPct: Math.round(llmPct) };
|
| 3492 |
+
}
|
| 3493 |
+
|
| 3494 |
+
const initStats = usageStats(defaultProb);
|
| 3495 |
+
|
| 3496 |
panel.innerHTML =
|
| 3497 |
`<div style="color:#4ecca3;font-weight:600;margin-bottom:4px">${p.icon} ${p.label}</div>` +
|
| 3498 |
+
`<div style="margin-bottom:4px">Daily limit: <b>${lim}</b> requests · ${rpm} req/min</div>` +
|
|
|
|
|
|
|
| 3499 |
`<div style="display:flex;align-items:center;gap:8px;margin-top:6px">` +
|
| 3500 |
`<label style="font-size:11px;color:#8899aa">Probability:</label>` +
|
| 3501 |
`<input type="range" min="1" max="100" value="${defaultProb}" style="flex:1;accent-color:#4ecca3" class="popup-prob-slider">` +
|
| 3502 |
`<span class="popup-prob-val" style="font-size:12px;color:#4ecca3;min-width:32px">${defaultProb}%</span>` +
|
| 3503 |
`</div>` +
|
| 3504 |
+
`<div class="popup-usage-info" style="font-size:10px;color:#8899aa;margin:4px 0 8px 0;line-height:1.5">` +
|
| 3505 |
+
`<span style="color:#c8c8d8">${initStats.llmPct}%</span> of decisions via LLM · ` +
|
| 3506 |
+
`<span style="color:#c8c8d8">~${initStats.callsPerHour}</span> calls/hour` +
|
| 3507 |
+
`</div>` +
|
| 3508 |
`<button class="popup-switch-btn" style="width:100%;padding:6px;border:none;border-radius:4px;` +
|
| 3509 |
`background:#4ecca3;color:#0a0a23;font-weight:600;cursor:pointer;font-size:12px">` +
|
| 3510 |
`Switch to ${p.label} at ${defaultProb}%</button>`;
|
|
|
|
| 3514 |
// Wire up slider
|
| 3515 |
const slider = panel.querySelector('.popup-prob-slider');
|
| 3516 |
const valLabel = panel.querySelector('.popup-prob-val');
|
| 3517 |
+
const usageInfo = panel.querySelector('.popup-usage-info');
|
| 3518 |
const btn = panel.querySelector('.popup-switch-btn');
|
| 3519 |
|
| 3520 |
slider.addEventListener('input', (e) => {
|
| 3521 |
e.stopPropagation();
|
| 3522 |
const pv = parseInt(slider.value);
|
| 3523 |
valLabel.textContent = pv + '%';
|
| 3524 |
+
const stats = usageStats(pv);
|
| 3525 |
+
usageInfo.innerHTML =
|
| 3526 |
+
`<span style="color:#c8c8d8">${stats.llmPct}%</span> of decisions via LLM · ` +
|
| 3527 |
+
`<span style="color:#c8c8d8">~${stats.callsPerHour}</span> calls/hour`;
|
| 3528 |
btn.textContent = `Switch to ${p.label} at ${pv}%`;
|
| 3529 |
});
|
| 3530 |
|