From b1b264e2bb7e836e8f11aab520ab59353b77354b Mon Sep 17 00:00:00 2001 From: OpenClaw Contributor Date: Mon, 16 Mar 2026 18:59:21 +0000 Subject: [PATCH] Surface history truncation when capped at 25 (Codex P2) - Add chatHistoryTruncated state; set when response length >= request limit. - Show 'Showing last 25 messages (older messages not loaded).' in chat view when history was truncated, so users see that context may be missing. Made-with: Cursor --- ui/src/ui/app-render.ts | 1 + ui/src/ui/app.ts | 1 + ui/src/ui/controllers/chat.ts | 3 +++ ui/src/ui/views/chat.ts | 14 ++++++++++++-- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/ui/src/ui/app-render.ts b/ui/src/ui/app-render.ts index 11bcacae1ee..376b0e4bc8d 100644 --- a/ui/src/ui/app-render.ts +++ b/ui/src/ui/app-render.ts @@ -1359,6 +1359,7 @@ export function renderApp(state: AppViewState) { fallbackStatus: state.fallbackStatus, assistantAvatarUrl: chatAvatarUrl, messages: state.chatMessages, + historyTruncated: state.chatHistoryTruncated, toolMessages: state.chatToolMessages, streamSegments: state.chatStreamSegments, stream: state.chatStream, diff --git a/ui/src/ui/app.ts b/ui/src/ui/app.ts index af0d0cb9c96..6d58f1b6d1d 100644 --- a/ui/src/ui/app.ts +++ b/ui/src/ui/app.ts @@ -159,6 +159,7 @@ export class OpenClawApp extends LitElement { @state() fallbackStatus: FallbackStatus | null = null; @state() chatAvatarUrl: string | null = null; @state() chatThinkingLevel: string | null = null; + @state() chatHistoryTruncated = false; @state() chatModelOverrides: Record = {}; @state() chatModelsLoading = false; @state() chatModelCatalog: ModelCatalogEntry[] = []; diff --git a/ui/src/ui/controllers/chat.ts b/ui/src/ui/controllers/chat.ts index 138b83d3b81..c9026ed0efe 100644 --- a/ui/src/ui/controllers/chat.ts +++ b/ui/src/ui/controllers/chat.ts @@ -38,6 +38,7 @@ export type ChatState = { chatLoading: boolean; chatMessages: unknown[]; chatThinkingLevel: string | null; + chatHistoryTruncated?: boolean; chatSending: boolean; chatMessage: string; chatAttachments: ChatAttachment[]; @@ -88,8 +89,10 @@ export async function loadChatHistory(state: ChatState) { state.chatStream = null; state.chatStreamStartedAt = null; state.chatMessages = filtered; + state.chatHistoryTruncated = filtered.length >= CHAT_HISTORY_REQUEST_LIMIT; } catch (err) { state.lastError = String(err); + state.chatHistoryTruncated = false; } finally { state.chatLoading = false; } diff --git a/ui/src/ui/views/chat.ts b/ui/src/ui/views/chat.ts index 077b3c3bd87..310b3fb1fc4 100644 --- a/ui/src/ui/views/chat.ts +++ b/ui/src/ui/views/chat.ts @@ -63,6 +63,8 @@ export type ChatProps = { compactionStatus?: CompactionIndicatorStatus | null; fallbackStatus?: FallbackIndicatorStatus | null; messages: unknown[]; + /** True when history was limited by request limit (older messages not loaded). */ + historyTruncated?: boolean; toolMessages: unknown[]; streamSegments: Array<{ text: string; ts: number }>; stream: string | null; @@ -1383,13 +1385,21 @@ function buildChatItems(props: ChatProps): Array { const history = Array.isArray(props.messages) ? props.messages : []; const tools = Array.isArray(props.toolMessages) ? props.toolMessages : []; const historyStart = Math.max(0, history.length - CHAT_HISTORY_RENDER_LIMIT); - if (historyStart > 0) { + const showTruncationNotice = + historyStart > 0 || + (Boolean(props.historyTruncated) && history.length >= CHAT_HISTORY_RENDER_LIMIT); + if (showTruncationNotice) { + const hiddenCount = historyStart > 0 ? historyStart : "older"; + const label = + typeof hiddenCount === "number" + ? `Showing last ${CHAT_HISTORY_RENDER_LIMIT} messages (${hiddenCount} hidden).` + : `Showing last ${CHAT_HISTORY_RENDER_LIMIT} messages (older messages not loaded).`; items.push({ kind: "message", key: "chat:history:notice", message: { role: "system", - content: `Showing last ${CHAT_HISTORY_RENDER_LIMIT} messages (${historyStart} hidden).`, + content: label, timestamp: Date.now(), }, });