From d9cea94e7809e138cab2886a4122d1f76b09d3ba Mon Sep 17 00:00:00 2001 From: Beck Wangthumboon Date: Fri, 27 Mar 2026 15:36:59 -0500 Subject: [PATCH 1/2] fix(web): block enter send while running --- apps/web/src/components/ChatView.browser.tsx | 51 ++++++++++++++++++++ apps/web/src/components/ChatView.tsx | 11 ++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx index 7bf3ecf26c..b346187614 100644 --- a/apps/web/src/components/ChatView.browser.tsx +++ b/apps/web/src/components/ChatView.browser.tsx @@ -1758,6 +1758,57 @@ describe("ChatView timeline estimator parity (full app)", () => { } }); + it("does not start a new turn when Enter is pressed while the thread is running", async () => { + useComposerDraftStore.getState().setPrompt(THREAD_ID, "follow-up while running"); + + const mounted = await mountChatView({ + viewport: DEFAULT_VIEWPORT, + snapshot: createSnapshotForTargetUser({ + targetMessageId: "msg-user-enter-while-running" as MessageId, + targetText: "enter while running target", + sessionStatus: "running", + }), + }); + + try { + const composerEditor = await waitForComposerEditor(); + const initialTurnStartRequestCount = wsRequests.filter( + (request) => + request._tag === ORCHESTRATION_WS_METHODS.dispatchCommand && + request.command && + typeof request.command === "object" && + "type" in request.command && + request.command.type === "thread.turn.start", + ).length; + + composerEditor.focus(); + composerEditor.dispatchEvent( + new KeyboardEvent("keydown", { + key: "Enter", + bubbles: true, + cancelable: true, + }), + ); + await waitForLayout(); + + const nextTurnStartRequestCount = wsRequests.filter( + (request) => + request._tag === ORCHESTRATION_WS_METHODS.dispatchCommand && + request.command && + typeof request.command === "object" && + "type" in request.command && + request.command.type === "thread.turn.start", + ).length; + + expect(nextTurnStartRequestCount).toBe(initialTurnStartRequestCount); + expect(document.querySelector('button[aria-label="Stop generation"]')).toBeInstanceOf( + HTMLButtonElement, + ); + } finally { + await mounted.cleanup(); + } + }); + it("keeps the new thread selected after clicking the new-thread button", async () => { const mounted = await mountChatView({ viewport: DEFAULT_VIEWPORT, diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 1d926bf308..67e37adf8c 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -2431,7 +2431,16 @@ export default function ChatView({ threadId }: ChatViewProps) { const onSend = async (e?: { preventDefault: () => void }) => { e?.preventDefault(); const api = readNativeApi(); - if (!api || !activeThread || isSendBusy || isConnecting || sendInFlightRef.current) return; + if ( + !api || + !activeThread || + phase === "running" || + isSendBusy || + isConnecting || + sendInFlightRef.current + ) { + return; + } if (activePendingProgress) { onAdvanceActivePendingUserInput(); return; From 3e096b7e93e55ff899b18403eda06a1a94ac973e Mon Sep 17 00:00:00 2001 From: Beck Wangthumboon Date: Fri, 27 Mar 2026 16:27:36 -0500 Subject: [PATCH 2/2] fix(web): allow enter for pending user input --- apps/web/src/components/ChatView.tsx | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 67e37adf8c..7622eb94b1 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -2431,20 +2431,14 @@ export default function ChatView({ threadId }: ChatViewProps) { const onSend = async (e?: { preventDefault: () => void }) => { e?.preventDefault(); const api = readNativeApi(); - if ( - !api || - !activeThread || - phase === "running" || - isSendBusy || - isConnecting || - sendInFlightRef.current - ) { - return; - } + if (!api || !activeThread) return; if (activePendingProgress) { onAdvanceActivePendingUserInput(); return; } + if (phase === "running" || isSendBusy || isConnecting || sendInFlightRef.current) { + return; + } const promptForSend = promptRef.current; const { trimmedPrompt: trimmed,