diff --git a/web/src/chat/normalizeAgent.ts b/web/src/chat/normalizeAgent.ts index 5fe7a8fc..a16f4678 100644 --- a/web/src/chat/normalizeAgent.ts +++ b/web/src/chat/normalizeAgent.ts @@ -246,6 +246,23 @@ export function normalizeAgentRecord( meta } } + if (data.type === 'system' && data.subtype === 'microcompact_boundary') { + const metadata = isObject(data.microcompactMetadata) ? data.microcompactMetadata : null + return { + id: messageId, + localId, + createdAt, + role: 'event', + content: { + type: 'microcompact', + trigger: asString(metadata?.trigger) ?? 'auto', + preTokens: asNumber(metadata?.preTokens) ?? 0, + tokensSaved: asNumber(metadata?.tokensSaved) ?? 0 + }, + isSidechain: false, + meta + } + } return null } diff --git a/web/src/chat/presentation.ts b/web/src/chat/presentation.ts index 49491859..67a0f6ad 100644 --- a/web/src/chat/presentation.ts +++ b/web/src/chat/presentation.ts @@ -58,6 +58,11 @@ export function getEventPresentation(event: AgentEvent): EventPresentation { const ms = typeof event.durationMs === 'number' ? event.durationMs : 0 return { icon: '⏱️', text: `Turn: ${formatDuration(ms)}` } } + if (event.type === 'microcompact') { + const saved = typeof event.tokensSaved === 'number' ? event.tokensSaved : 0 + const formatted = saved >= 1000 ? `${Math.round(saved / 1000)}K` : String(saved) + return { icon: '📦', text: `Context compacted (saved ${formatted} tokens)` } + } try { return { icon: null, text: JSON.stringify(event) } } catch { diff --git a/web/src/chat/types.ts b/web/src/chat/types.ts index fd17d2c7..a171e670 100644 --- a/web/src/chat/types.ts +++ b/web/src/chat/types.ts @@ -16,6 +16,7 @@ export type AgentEvent = | { type: 'ready' } | { type: 'api-error'; retryAttempt: number; maxRetries: number; error: unknown } | { type: 'turn-duration'; durationMs: number } + | { type: 'microcompact'; trigger: string; preTokens: number; tokensSaved: number } | ({ type: string } & Record) export type ToolResultPermission = {