From 375ee94eb855b853a17c194ca8bb663145b2cb02 Mon Sep 17 00:00:00 2001 From: pratyush Date: Thu, 9 Apr 2026 13:25:34 +0530 Subject: [PATCH 1/2] #1777: minimal implementation. --- apps/web/src/components/ChatView.tsx | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index cf09dd8a38..ff58021a2c 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -816,6 +816,9 @@ export default function ChatView(props: ChatViewProps) { const attachmentPreviewHandoffTimeoutByMessageIdRef = useRef>({}); const sendInFlightRef = useRef(false); const dragDepthRef = useRef(0); + const inputHistoryRef = useRef([]); + const historyIdxRef = useRef(-1); + const historyDraftRef = useRef(''); const terminalOpenByThreadRef = useRef>({}); const setMessagesScrollContainerRef = useCallback((element: HTMLDivElement | null) => { messagesScrollRef.current = element; @@ -2509,6 +2512,14 @@ export default function ChatView(props: ChatViewProps) { composerTerminalContextsRef.current = composerTerminalContexts; }, [composerTerminalContexts]); + useEffect(() => { + inputHistoryRef.current = (activeThread?.messages ?? []) + .filter((m) => m.role === 'user' && m.text.trim()) + .map((m) => m.text.trim()) + .reverse(); + historyIdxRef.current = -1; + }, [activeThread?.id]); // eslint-disable-line react-hooks/exhaustive-deps + useEffect(() => { if (!activeThread?.id) return; if (activeThread.messages.length === 0) { @@ -3178,6 +3189,7 @@ export default function ChatView(props: ChatViewProps) { description: toastCopy.description, }); } + if (promptForSend.trim()) { inputHistoryRef.current.unshift(promptForSend.trim()); historyIdxRef.current = -1; } promptRef.current = ""; clearComposerDraftContent(scopeThreadRef(activeThread.environmentId, threadIdForSend)); setComposerHighlightedItemId(null); @@ -4066,6 +4078,18 @@ export default function ChatView(props: ChatViewProps) { } } + if (key === 'ArrowUp' && inputHistoryRef.current.length > 0 && !promptRef.current.includes('\n')) { + if (historyIdxRef.current === -1) historyDraftRef.current = promptRef.current; + historyIdxRef.current = Math.min(historyIdxRef.current + 1, inputHistoryRef.current.length - 1); + setPrompt(inputHistoryRef.current[historyIdxRef.current]!); + return true; + } + if (key === 'ArrowDown' && historyIdxRef.current >= 0) { + const next = historyIdxRef.current - 1; + historyIdxRef.current = next; + setPrompt(next >= 0 ? inputHistoryRef.current[next]! : historyDraftRef.current); + return true; + } if (key === "Enter" && !event.shiftKey) { void onSend(); return true; From 069183cdb2457a791ee2a96736a4995f87fc15ce Mon Sep 17 00:00:00 2001 From: pratyush Date: Thu, 9 Apr 2026 14:29:29 +0530 Subject: [PATCH 2/2] fix buggy interaction for multiline inputs --- apps/web/src/components/ChatView.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index ff58021a2c..82a5bd73c2 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -4078,13 +4078,14 @@ export default function ChatView(props: ChatViewProps) { } } - if (key === 'ArrowUp' && inputHistoryRef.current.length > 0 && !promptRef.current.includes('\n')) { + const cur = composerEditorRef.current?.readSnapshot()?.cursor ?? 0; + if (key === 'ArrowUp' && inputHistoryRef.current.length > 0 && !promptRef.current.slice(0, cur).includes('\n')) { if (historyIdxRef.current === -1) historyDraftRef.current = promptRef.current; historyIdxRef.current = Math.min(historyIdxRef.current + 1, inputHistoryRef.current.length - 1); setPrompt(inputHistoryRef.current[historyIdxRef.current]!); return true; } - if (key === 'ArrowDown' && historyIdxRef.current >= 0) { + if (key === 'ArrowDown' && historyIdxRef.current >= 0 && !promptRef.current.slice(cur).includes('\n')) { const next = historyIdxRef.current - 1; historyIdxRef.current = next; setPrompt(next >= 0 ? inputHistoryRef.current[next]! : historyDraftRef.current);