+
+ {formatTokens(used)}/{formatTokens(limit)}
+
+
+ {recent.length > 0 && (
+
+ {recent.map((tokens, i) => (
+
+ ))}
+
+ )}
+
+ )
+}
diff --git a/components/frontend/src/hooks/agui/event-handlers.ts b/components/frontend/src/hooks/agui/event-handlers.ts
index 2829411cf..9345550d2 100644
--- a/components/frontend/src/hooks/agui/event-handlers.ts
+++ b/components/frontend/src/hooks/agui/event-handlers.ts
@@ -25,12 +25,12 @@ import type {
PlatformMessage,
PlatformToolCall,
PlatformRawEvent,
+ PlatformRunFinishedEvent,
AGUIMetaEvent,
PlatformActivitySnapshotEvent,
PlatformActivityDeltaEvent,
WireToolCallStartEvent,
RunStartedEvent,
- RunFinishedEvent,
RunErrorEvent,
TextMessageStartEvent,
TextMessageContentEvent,
@@ -212,7 +212,7 @@ function handleRunStarted(
function handleRunFinished(
state: AGUIClientState,
- event: RunFinishedEvent,
+ event: PlatformRunFinishedEvent,
callbacks: EventHandlerCallbacks,
): AGUIClientState {
state.status = 'completed'
@@ -271,6 +271,17 @@ function handleRunFinished(
}
state.currentThinking = null
+ // Track context usage from result.usage
+ if (event.result?.usage) {
+ const { input_tokens = 0, output_tokens = 0 } = event.result.usage
+ const turnTokens = input_tokens + output_tokens
+
+ state.contextUsage = {
+ used: state.contextUsage.used + turnTokens,
+ perTurn: [...state.contextUsage.perTurn, turnTokens],
+ }
+ }
+
return state
}
diff --git a/components/frontend/src/hooks/agui/types.ts b/components/frontend/src/hooks/agui/types.ts
index 3622ead09..a1caba861 100644
--- a/components/frontend/src/hooks/agui/types.ts
+++ b/components/frontend/src/hooks/agui/types.ts
@@ -47,4 +47,8 @@ export const initialState: AGUIClientState = {
messageFeedback: new Map(), // Track feedback for messages
currentReasoning: null,
currentThinking: null,
+ contextUsage: {
+ used: 0,
+ perTurn: [],
+ },
}
diff --git a/components/frontend/src/types/agui.ts b/components/frontend/src/types/agui.ts
index 1c6046843..c21e30bef 100644
--- a/components/frontend/src/types/agui.ts
+++ b/components/frontend/src/types/agui.ts
@@ -113,6 +113,25 @@ export type PlatformRawEvent = {
source?: string
}
+/** Token usage from RUN_FINISHED result */
+export type ResultUsage = {
+ input_tokens?: number
+ output_tokens?: number
+ cache_read_input_tokens?: number
+ cache_creation_input_tokens?: number
+}
+
+/** Platform extension of RunFinishedEvent with result metadata */
+export type PlatformRunFinishedEvent = RunFinishedEvent & {
+ result?: {
+ usage?: ResultUsage
+ num_turns?: number
+ duration_ms?: number
+ total_cost_usd?: number
+ is_error?: boolean
+ }
+}
+
// ── Platform Activity types ──
// The core ActivitySnapshotEvent/ActivityDeltaEvent are per-message, not
// array-based. The platform uses an array-based model for UI rendering.
@@ -212,6 +231,11 @@ export type AGUIClientState = {
content: string
timestamp?: string
} | null
+ // Context window usage tracking
+ contextUsage: {
+ used: number
+ perTurn: number[]
+ }
}
// ── Type Guards ──
@@ -260,3 +284,30 @@ export function isMessagesSnapshotEvent(event: { type: string }): event is Messa
export function isActivitySnapshotEvent(event: { type: string }): event is PlatformActivitySnapshotEvent {
return event.type === EventType.ACTIVITY_SNAPSHOT
}
+
+// ── Context Window Utilities ──
+
+/** Context window limits by model family (tokens) */
+const CONTEXT_LIMITS: Record