@@ -974,11 +974,14 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
974974 [ lockedProvider , providerModelsByProvider , selectableProviders ] ,
975975 ) ;
976976 const phase = derivePhase ( activeThread ?. session ?? null ) ;
977+ const isTurnActive =
978+ activeThread ?. session ?. activeTurnId !== undefined &&
979+ activeThread ?. session ?. activeTurnId !== null ;
977980 const isSendBusy = sendPhase !== "idle" ;
978981 const isPreparingWorktree = sendPhase === "preparing-worktree" ;
979982 const isTransportReady = transportState === "open" ;
980983 const isRemoteActionBlocked = ! isTransportReady ;
981- const isWorking = phase === "running" || isSendBusy || isConnecting || isRevertingCheckpoint ;
984+ const isWorking = isTurnActive || isSendBusy || isConnecting || isRevertingCheckpoint ;
982985 const nowIso = new Date ( nowTick ) . toISOString ( ) ;
983986 const activeWorkStartedAt = deriveActiveWorkStartedAt (
984987 activeLatestTurn ,
@@ -2530,10 +2533,10 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
25302533 scheduleStickToBottom ( ) ;
25312534 } , [ messageCount , scheduleStickToBottom ] ) ;
25322535 useEffect ( ( ) => {
2533- if ( phase !== "running" ) return ;
2536+ if ( ! isTurnActive ) return ;
25342537 if ( ! shouldAutoScrollRef . current ) return ;
25352538 scheduleStickToBottom ( ) ;
2536- } , [ phase , scheduleStickToBottom , timelineEntries ] ) ;
2539+ } , [ isTurnActive , scheduleStickToBottom , timelineEntries ] ) ;
25372540
25382541 // Aggressively scroll to bottom after the user submits a new message.
25392542 // The virtualizer may not have settled by the time the first scroll fires,
@@ -2778,14 +2781,14 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
27782781 : "local" ;
27792782
27802783 useEffect ( ( ) => {
2781- if ( phase !== "running" ) return ;
2784+ if ( ! isTurnActive ) return ;
27822785 const timer = window . setInterval ( ( ) => {
27832786 setNowTick ( Date . now ( ) ) ;
27842787 } , 1000 ) ;
27852788 return ( ) => {
27862789 window . clearInterval ( timer ) ;
27872790 } ;
2788- } , [ phase ] ) ;
2791+ } , [ isTurnActive ] ) ;
27892792
27902793 const beginSendPhase = useCallback ( ( nextPhase : Exclude < SendPhase , "idle" > ) => {
27912794 setSendStartedAt ( ( current ) => current ?? new Date ( ) . toISOString ( ) ) ;
@@ -2802,7 +2805,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
28022805 return ;
28032806 }
28042807 if (
2805- phase === "running" ||
2808+ isTurnActive ||
28062809 activePendingApproval !== null ||
28072810 activePendingUserInput !== null ||
28082811 activeThread ?. error
@@ -2813,7 +2816,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
28132816 activePendingApproval ,
28142817 activePendingUserInput ,
28152818 activeThread ?. error ,
2816- phase ,
2819+ isTurnActive ,
28172820 resetSendPhase ,
28182821 sendPhase ,
28192822 ] ) ;
@@ -3171,7 +3174,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
31713174 const api = readNativeApi ( ) ;
31723175 if ( ! api || ! activeThread || isRevertingCheckpoint ) return ;
31733176
3174- if ( phase === "running" || isSendBusy || isConnecting ) {
3177+ if ( isTurnActive || isSendBusy || isConnecting ) {
31753178 setThreadError ( activeThread . id , "Interrupt the current turn before reverting checkpoints." ) ;
31763179 return ;
31773180 }
@@ -3204,7 +3207,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
32043207 }
32053208 setIsRevertingCheckpoint ( false ) ;
32063209 } ,
3207- [ activeThread , isConnecting , isRevertingCheckpoint , isSendBusy , phase , setThreadError ] ,
3210+ [ activeThread , isConnecting , isRevertingCheckpoint , isSendBusy , isTurnActive , setThreadError ] ,
32083211 ) ;
32093212
32103213 const readLiveComposerDraftSnapshot = useCallback ( ( ) => {
@@ -3448,7 +3451,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
34483451 }
34493452
34503453 // ── Queue message if a turn is already running ────────────────────
3451- if ( phase === "running" ) {
3454+ if ( isTurnActive ) {
34523455 const composerAttachmentsSnapshot = [ ...composerAttachmentsForSend ] ;
34533456 const hiddenProviderInput = buildHiddenProviderInput ( {
34543457 prompt : promptForSend ,
@@ -5548,7 +5551,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
55485551 Preparing worktree...
55495552 </ span >
55505553 ) : null }
5551- { queuedMessages . length > 0 && phase === "running" ? (
5554+ { queuedMessages . length > 0 && isTurnActive ? (
55525555 < button
55535556 type = "button"
55545557 className = "flex items-center gap-1 text-muted-foreground/60 text-xs transition-colors hover:text-destructive"
@@ -5605,7 +5608,7 @@ export default function ChatView({ threadId, onMinimize }: ChatViewProps) {
56055608 : "Next question" }
56065609 </ Button >
56075610 </ div >
5608- ) : phase === "running" ? (
5611+ ) : isTurnActive ? (
56095612 < div className = "flex items-center gap-1.5" >
56105613 < button
56115614 type = "button"
0 commit comments