feat: Add live context window tracking with visual progress bar
- Extract token usage from message_delta events in backend - Calculate context usage percentage (input + cache tokens / 200k) - Add context_update, compacting_started/finished, compact_boundary events - Display progress bar that fills up as context is consumed - Color-coded warnings (green→yellow→red) based on usage - Show compacting status indicator when auto-compact runs - Display system messages for compact start/finish with usage stats 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -851,6 +851,56 @@ wss.on('connection', async (ws, req) => {
|
||||
// Ignore write errors
|
||||
}
|
||||
|
||||
// Extract context window metrics from stream_event message_delta
|
||||
if (event.type === 'stream_event' && event.event?.type === 'message_delta') {
|
||||
const usage = event.event.usage;
|
||||
if (usage) {
|
||||
// Total input tokens = input + cache_read + cache_creation
|
||||
// This represents the full context sent to the model
|
||||
const totalInputTokens = (usage.input_tokens || 0) +
|
||||
(usage.cache_read_input_tokens || 0) +
|
||||
(usage.cache_creation_input_tokens || 0);
|
||||
// Context window is typically 200000 for Opus
|
||||
const contextWindow = 200000;
|
||||
const percentUsed = Math.min(100, Math.round((totalInputTokens / contextWindow) * 100));
|
||||
|
||||
if (DEBUG) {
|
||||
console.log(`[${sessionId}] Context: ${totalInputTokens}/${contextWindow} tokens (${percentUsed}%)`);
|
||||
}
|
||||
|
||||
sendToClient('context_update', {
|
||||
tokensUsed: totalInputTokens,
|
||||
contextWindow,
|
||||
percentUsed,
|
||||
percentRemaining: 100 - percentUsed
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Detect compacting status from system events
|
||||
if (event.type === 'system' && event.subtype === 'status') {
|
||||
if (event.status === 'compacting') {
|
||||
sendToClient('compacting_started', {});
|
||||
} else if (event.status === null) {
|
||||
// Compacting finished
|
||||
sendToClient('compacting_finished', {});
|
||||
}
|
||||
}
|
||||
|
||||
// Extract pre_tokens from compact_boundary event
|
||||
if (event.type === 'system' && event.subtype === 'compact_boundary') {
|
||||
const preTokens = event.compact_metadata?.pre_tokens;
|
||||
const trigger = event.compact_metadata?.trigger;
|
||||
if (preTokens) {
|
||||
sendToClient('compact_boundary', {
|
||||
preTokens,
|
||||
trigger,
|
||||
contextWindow: 200000,
|
||||
percentUsedBeforeCompact: Math.round((preTokens / 200000) * 100)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
sendToClient('claude_event', { event });
|
||||
} catch (e) {
|
||||
// Non-JSON output, send as raw
|
||||
|
||||
Reference in New Issue
Block a user