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(), }, });