@@ -973,11 +973,14 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
973973 [ lockedProvider , providerModelsByProvider , selectableProviders ] ,
974974 ) ;
975975 const phase = derivePhase ( activeThread ?. session ?? null ) ;
976+ const isTurnActive =
977+ activeThread ?. session ?. activeTurnId !== undefined &&
978+ activeThread ?. session ?. activeTurnId !== null ;
976979 const isSendBusy = sendPhase !== "idle" ;
977980 const isPreparingWorktree = sendPhase === "preparing-worktree" ;
978981 const isTransportReady = transportState === "open" ;
979982 const isRemoteActionBlocked = ! isTransportReady ;
980- const isWorking = phase === "running" || isSendBusy || isConnecting || isRevertingCheckpoint ;
983+ const isWorking = isTurnActive || isSendBusy || isConnecting || isRevertingCheckpoint ;
981984 const nowIso = new Date ( nowTick ) . toISOString ( ) ;
982985 const activeWorkStartedAt = deriveActiveWorkStartedAt (
983986 activeLatestTurn ,
@@ -2529,10 +2532,10 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
25292532 scheduleStickToBottom ( ) ;
25302533 } , [ messageCount , scheduleStickToBottom ] ) ;
25312534 useEffect ( ( ) => {
2532- if ( phase !== "running" ) return ;
2535+ if ( ! isTurnActive ) return ;
25332536 if ( ! shouldAutoScrollRef . current ) return ;
25342537 scheduleStickToBottom ( ) ;
2535- } , [ phase , scheduleStickToBottom , timelineEntries ] ) ;
2538+ } , [ isTurnActive , scheduleStickToBottom , timelineEntries ] ) ;
25362539
25372540 // Aggressively scroll to bottom after the user submits a new message.
25382541 // The virtualizer may not have settled by the time the first scroll fires,
@@ -2777,14 +2780,14 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
27772780 : "local" ;
27782781
27792782 useEffect ( ( ) => {
2780- if ( phase !== "running" ) return ;
2783+ if ( ! isTurnActive ) return ;
27812784 const timer = window . setInterval ( ( ) => {
27822785 setNowTick ( Date . now ( ) ) ;
27832786 } , 1000 ) ;
27842787 return ( ) => {
27852788 window . clearInterval ( timer ) ;
27862789 } ;
2787- } , [ phase ] ) ;
2790+ } , [ isTurnActive ] ) ;
27882791
27892792 const beginSendPhase = useCallback ( ( nextPhase : Exclude < SendPhase , "idle" > ) => {
27902793 setSendStartedAt ( ( current ) => current ?? new Date ( ) . toISOString ( ) ) ;
@@ -2801,7 +2804,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
28012804 return ;
28022805 }
28032806 if (
2804- phase === "running" ||
2807+ isTurnActive ||
28052808 activePendingApproval !== null ||
28062809 activePendingUserInput !== null ||
28072810 activeThread ?. error
@@ -2812,7 +2815,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
28122815 activePendingApproval ,
28132816 activePendingUserInput ,
28142817 activeThread ?. error ,
2815- phase ,
2818+ isTurnActive ,
28162819 resetSendPhase ,
28172820 sendPhase ,
28182821 ] ) ;
@@ -3170,7 +3173,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
31703173 const api = readNativeApi ( ) ;
31713174 if ( ! api || ! activeThread || isRevertingCheckpoint ) return ;
31723175
3173- if ( phase === "running" || isSendBusy || isConnecting ) {
3176+ if ( isTurnActive || isSendBusy || isConnecting ) {
31743177 setThreadError ( activeThread . id , "Interrupt the current turn before reverting checkpoints." ) ;
31753178 return ;
31763179 }
@@ -3203,7 +3206,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
32033206 }
32043207 setIsRevertingCheckpoint ( false ) ;
32053208 } ,
3206- [ activeThread , isConnecting , isRevertingCheckpoint , isSendBusy , phase , setThreadError ] ,
3209+ [ activeThread , isConnecting , isRevertingCheckpoint , isSendBusy , isTurnActive , setThreadError ] ,
32073210 ) ;
32083211
32093212 const readLiveComposerDraftSnapshot = useCallback ( ( ) => {
@@ -3447,7 +3450,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
34473450 }
34483451
34493452 // ── Queue message if a turn is already running ────────────────────
3450- if ( phase === "running" ) {
3453+ if ( isTurnActive ) {
34513454 const composerAttachmentsSnapshot = [ ...composerAttachmentsForSend ] ;
34523455 const hiddenProviderInput = buildHiddenProviderInput ( {
34533456 prompt : promptForSend ,
@@ -5547,7 +5550,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
55475550 Preparing worktree...
55485551 </ span >
55495552 ) : null }
5550- { queuedMessages . length > 0 && phase === "running" ? (
5553+ { queuedMessages . length > 0 && isTurnActive ? (
55515554 < button
55525555 type = "button"
55535556 className = "flex items-center gap-1 text-muted-foreground/60 text-xs transition-colors hover:text-destructive"
@@ -5604,7 +5607,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
56045607 : "Next question" }
56055608 </ Button >
56065609 </ div >
5607- ) : phase === "running" ? (
5610+ ) : isTurnActive ? (
56085611 < div className = "flex items-center gap-1.5" >
56095612 < button
56105613 type = "button"
0 commit comments