feat: persistent context-window tracker in ChatPane
Adds a floating popover above the chat input showing current context-window usage. Modeled on Paseo's tracker. - New hook useChatContextStats(chatId, messages) finds the latest assistant message in the chat with both ctx_used and ctx_max set, computes percent, and returns null when data unavailable. - New component ChatContextPopover renders a small card with the "Context window" label, big percent, and "used / max tokens" subline. Hidden when stats is null. - Color thresholds: <60% muted, 60-85 amber, >85 destructive. - Not a portal — absolutely positioned inside a new relative wrapper around ChatInput in ChatPane.tsx, so it's pane-local (multi-pane safe). - Live updates via the existing messages-array dependency. - No API / schema / WS changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
apps/web/src/hooks/useChatContextStats.ts
Normal file
37
apps/web/src/hooks/useChatContextStats.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { useMemo } from 'react';
|
||||
import type { Message } from '@/api/types';
|
||||
|
||||
export interface ChatContextStats {
|
||||
used: number;
|
||||
max: number;
|
||||
percent: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the latest context-window usage for the given chat, derived from the
|
||||
* assistant message (with both ctx_used and ctx_max populated) having the most
|
||||
* recent created_at. Returns null when no such message exists.
|
||||
*
|
||||
* Re-evaluates whenever the `messages` reference or `chatId` changes, which
|
||||
* matches the cadence of streaming updates from `useSessionStream`.
|
||||
*/
|
||||
export function useChatContextStats(
|
||||
chatId: string,
|
||||
messages: Message[],
|
||||
): ChatContextStats | null {
|
||||
return useMemo(() => {
|
||||
let latest: Message | null = null;
|
||||
for (const m of messages) {
|
||||
if (m.chat_id !== chatId) continue;
|
||||
if (m.role !== 'assistant') continue;
|
||||
if (m.ctx_used == null || m.ctx_max == null) continue;
|
||||
if (!latest || m.created_at > latest.created_at) latest = m;
|
||||
}
|
||||
if (!latest || latest.ctx_used == null || latest.ctx_max == null) return null;
|
||||
const used = latest.ctx_used;
|
||||
const max = latest.ctx_max;
|
||||
if (max <= 0) return null;
|
||||
const percent = Math.round((used / max) * 100);
|
||||
return { used, max, percent };
|
||||
}, [chatId, messages]);
|
||||
}
|
||||
Reference in New Issue
Block a user