Include panel member tokens in the chain cost badge
Panel member token usage was tracked but discarded, so the cost badge only ever showed the worker's tokens — misleading for MoA where the real cost is roughly rounds x agents. Collect each member's usage and add it to the badge. Each member fills its own TokenUsage in parallel (Anthropic loop via the existing memberUsage, CLI via the now-captured CliChatResult return value; OpenAI members stay null, nachruestbar). RunPanel sums them after the Task.WhenAll barrier — single-threaded, so no lock or Interlocked needed — across all MoA rounds and emits a panel_usage SSE event before panel_done. The frontend adds those tokens onto the worker totals in the done handler so the badge reflects the full chain cost. - SseHelper: add TokenUsage.Add() - AnthropicService.Panel.cs: PanelMemberResult.Usage, accumulate per round after the barrier, emit panel_usage; RunPanelMemberViaCli returns usage - chat.js: _panelUsage state, panel_usage case, add to worker tokens on done, reset on stream start - TODO.md: check off the member-token item v1 limit: live badge only — FinalizeChain still persists worker tokens, so a reload shows worker-only cost. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
1 parent
0f87ccdcab
commit
47557c9724
4 files changed
+82
-10
No files matched your search
+22
-1
@@ -170,6 +170,11 @@ function handleStreamEvent(eventType, data) {
|
||||
endPanel(data);
|
||||
break;
|
||||
|
||||
case 'panel_usage':
|
||||
// Panel-Member-Tokens merken → im done-Event auf die Worker-Tokens addieren.
|
||||
_panelUsage = data;
|
||||
break;
|
||||
|
||||
case 'auto_context':
|
||||
addAutoContextBubble(data.context);
|
||||
break;
|
||||
@@ -199,14 +204,18 @@ function handleStreamEvent(eventType, data) {
|
||||
if (data.stopReason === 'max_tokens') {
|
||||
addWarningBubble('Antwort wurde abgeschnitten (max_tokens erreicht). Bitte frage nach dem Rest.', true);
|
||||
}
|
||||
// Panel-Member-Tokens (live gesammelt) auf die Worker-Tokens addieren → Badge = Gesamtkosten.
|
||||
var _pu = _panelUsage;
|
||||
_panelUsage = null;
|
||||
_lastDoneChainData = null;
|
||||
if (data.model) {
|
||||
_addPanelUsage(data, _pu);
|
||||
_lastDoneChainData = data;
|
||||
} else if (data.chainId) {
|
||||
// Fallback: Chain-Daten vom Server nachladen und Badge direkt rendern
|
||||
// (async – _lastDoneChainData wäre im finally schon gelesen)
|
||||
apiGetChain(data.chainId).then(chain => {
|
||||
if (chain) addChainMetaBubble(chain, false);
|
||||
if (chain) { _addPanelUsage(chain, _pu); addChainMetaBubble(chain, false); }
|
||||
}).catch(() => {});
|
||||
}
|
||||
setMeta(data.stopReason === 'stopped' ? 'Gestoppt' : 'Bereit');
|
||||
@@ -235,6 +244,17 @@ function togglePlanMode() {
|
||||
|
||||
let isStreaming = false;
|
||||
let _lastDoneChainData = null; // Chain-Daten vom letzten done-Event
|
||||
let _panelUsage = null; // Panel-Member-Tokens (panel_usage-Event) → werden auf die Worker-Tokens des done-Events addiert
|
||||
|
||||
// Addiert die live gesammelten Panel-Member-Tokens auf ein Chain-/done-Objekt, sodass das
|
||||
// Token-Badge die Gesamtkosten (Worker + alle Panel-Member aller Runden) zeigt.
|
||||
function _addPanelUsage(target, pu) {
|
||||
if (!target || !pu) return;
|
||||
target.inputTokens = (target.inputTokens || 0) + (pu.inputTokens || 0);
|
||||
target.outputTokens = (target.outputTokens || 0) + (pu.outputTokens || 0);
|
||||
target.cacheCreationTokens = (target.cacheCreationTokens || 0) + (pu.cacheCreationTokens || 0);
|
||||
target.cacheReadTokens = (target.cacheReadTokens || 0) + (pu.cacheReadTokens || 0);
|
||||
}
|
||||
let _currentToolBox = null; // Aktuell laufende Tool-Box (für Stream-Events)
|
||||
let _lastFinishedToolBox = null; // Letzte fertige Tool-Box (für tool_result Zuordnung)
|
||||
let _chatAbandoned = false; // true wenn User weg-navigiert während Stream läuft
|
||||
@@ -320,6 +340,7 @@ async function _runStream(fetchPromise) {
|
||||
sendBtn.hidden = true;
|
||||
stopBtn.hidden = false;
|
||||
isStreaming = true;
|
||||
_panelUsage = null; // frische Chain → alte Panel-Tokens verwerfen
|
||||
_abortController = new AbortController();
|
||||
// Eine Live-SSE-Antwort rendert ALLEIN. Einen evtl. noch laufenden Recovery-Poll
|
||||
// (_streamingPollInterval – gestartet beim Betreten des Chats WAEHREND eine Chain
|
||||
|
||||
Reference in new issue
Block a user