fix: Simplify context display to use Claude's reported value

Remove broken token-based context calculation. The StatusBar now only
shows context remaining when Claude reports "Context left until
auto-compact: X%" - which happens when context is actually getting low.

This eliminates confusing/incorrect percentages and only shows relevant
information when needed.

TODO: Test this in a long session to verify the context warning appears
when Claude reports it.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-18 09:24:51 +01:00
parent a91ba61dd8
commit a3fcc3cb7f
2 changed files with 56 additions and 48 deletions

View File

@@ -33,6 +33,7 @@ export function useClaudeSession() {
cacheCreationTokens: 0,
numTurns: 0,
contextWindow: 200000, // Default, updated from modelUsage
contextLeftPercent: null, // From Claude's "Context left until auto-compact: X%" message
isCompacting: false,
});
@@ -371,18 +372,38 @@ export function useClaudeSession() {
|| Object.keys(modelUsage)[0];
const primaryUsage = primaryModel ? modelUsage[primaryModel] : null;
// Calculate effective input tokens (what's actually in context)
// This is: new input + cache read (cache creation doesn't count towards context limit)
const effectiveInput = (event.usage?.input_tokens || 0) +
(event.usage?.cache_read_input_tokens || 0);
// Context calculation: Use top-level usage (aggregated) as primary source
// Per GitHub issue anthropics/claude-agent-sdk-typescript#66:
// Cache tokens DON'T count toward the 200K context window - they're handled separately
// Only input_tokens + output_tokens count toward the context window
// Cache tokens can appear in the millions because they're cumulative across the session
const usage = event.usage || {};
// Prefer top-level usage (aggregated), fallback to primaryUsage (per-model)
const inputTokens = usage.input_tokens ?? primaryUsage?.inputTokens ?? 0;
const cacheRead = usage.cache_read_input_tokens ?? primaryUsage?.cacheReadInputTokens ?? 0;
const cacheCreation = usage.cache_creation_input_tokens ?? primaryUsage?.cacheCreationInputTokens ?? 0;
const outputTokens = usage.output_tokens ?? primaryUsage?.outputTokens ?? 0;
// Context = input + output tokens ONLY (cache tokens are separate)
const totalContextUsed = inputTokens + outputTokens;
console.log('Result event stats:', {
inputTokens,
cacheRead,
cacheCreation,
totalContextUsed,
outputTokens,
contextWindow: primaryUsage?.contextWindow
});
setSessionStats(prev => ({
totalCost: event.total_cost_usd ?? prev.totalCost,
// Use modelUsage for accurate per-turn counts, fallback to usage
inputTokens: primaryUsage?.inputTokens ?? effectiveInput ?? prev.inputTokens,
outputTokens: primaryUsage?.outputTokens ?? event.usage?.output_tokens ?? prev.outputTokens,
cacheReadTokens: primaryUsage?.cacheReadInputTokens ?? event.usage?.cache_read_input_tokens ?? prev.cacheReadTokens,
cacheCreationTokens: primaryUsage?.cacheCreationInputTokens ?? event.usage?.cache_creation_input_tokens ?? prev.cacheCreationTokens,
// Context = input + output tokens only (cache tokens don't count toward window)
inputTokens: totalContextUsed,
outputTokens: outputTokens,
cacheReadTokens: cacheRead,
cacheCreationTokens: cacheCreation,
numTurns: event.num_turns ?? prev.numTurns,
contextWindow: primaryUsage?.contextWindow ?? prev.contextWindow,
isCompacting: false,
@@ -390,9 +411,22 @@ export function useClaudeSession() {
}
} else if (event.type === 'system' && event.subtype === 'result') {
setIsProcessing(false);
} else if (event.type === 'system' && event.message?.includes?.('compact')) {
} else if (event.type === 'system' && event.message) {
// Parse "Context left until auto-compact: X%" message
const contextMatch = event.message.match(/Context left until auto-compact:\s*(\d+)%/i);
if (contextMatch) {
const contextLeft = parseInt(contextMatch[1], 10);
console.log('Context left from Claude:', contextLeft + '%');
setSessionStats(prev => ({
...prev,
contextLeftPercent: contextLeft,
isCompacting: false,
}));
}
// Detect compacting
setSessionStats(prev => ({ ...prev, isCompacting: true }));
if (event.message.includes('compact')) {
setSessionStats(prev => ({ ...prev, isCompacting: true }));
}
}
}, []);