Skip to content

Commit 28940f6

Browse files
committed
fix: keep cancel button enabled during API requests with tool approval dialogs
- Add separate isApiRequestInProgress state to track actual API streaming - Use isApiRequestInProgress for cancel button disabled state - Ensures cancel button remains clickable when tool approval dialog appears - Fixes issue #9068 where cancel button becomes incorrectly disabled
1 parent 7320d79 commit 28940f6

File tree

1 file changed

+49
-9
lines changed

1 file changed

+49
-9
lines changed

webview-ui/src/components/chat/ChatView.tsx

Lines changed: 49 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -558,6 +558,37 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
558558
return false
559559
}, [modifiedMessages, clineAsk, enableButtons, primaryButtonText])
560560

561+
// Track the actual streaming state for the cancel button separately.
562+
// This ensures the cancel button remains enabled during API requests,
563+
// even when there's a tool approval dialog.
564+
const isApiRequestInProgress = useMemo(() => {
565+
const isLastMessagePartial = modifiedMessages.at(-1)?.partial === true
566+
567+
if (isLastMessagePartial) {
568+
return true
569+
}
570+
571+
const lastApiReqStarted = findLast(
572+
modifiedMessages,
573+
(message: ClineMessage) => message.say === "api_req_started",
574+
)
575+
576+
if (
577+
lastApiReqStarted &&
578+
lastApiReqStarted.text !== null &&
579+
lastApiReqStarted.text !== undefined &&
580+
lastApiReqStarted.say === "api_req_started"
581+
) {
582+
const cost = JSON.parse(lastApiReqStarted.text).cost
583+
584+
if (cost === undefined) {
585+
return true // API request has not finished yet.
586+
}
587+
}
588+
589+
return false
590+
}, [modifiedMessages])
591+
561592
const markFollowUpAsAnswered = useCallback(() => {
562593
const lastFollowUpMessage = messagesRef.current.findLast((msg: ClineMessage) => msg.ask === "followup")
563594
if (lastFollowUpMessage) {
@@ -733,7 +764,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
733764

734765
const trimmedInput = text?.trim()
735766

736-
if (isStreaming) {
767+
if (isStreaming || isApiRequestInProgress) {
737768
vscode.postMessage({ type: "cancelTask" })
738769
setDidClickCancel(true)
739770
return
@@ -773,7 +804,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
773804
setClineAsk(undefined)
774805
setEnableButtons(false)
775806
},
776-
[clineAsk, startNewTask, isStreaming],
807+
[clineAsk, startNewTask, isStreaming, isApiRequestInProgress],
777808
)
778809

779810
const { info: model } = useSelectedModel(apiConfiguration)
@@ -1763,7 +1794,8 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
17631794
vscode.postMessage({ type: "condenseTaskContextRequest", text: taskId })
17641795
}
17651796

1766-
const areButtonsVisible = showScrollToBottom || primaryButtonText || secondaryButtonText || isStreaming
1797+
const areButtonsVisible =
1798+
showScrollToBottom || primaryButtonText || secondaryButtonText || isStreaming || isApiRequestInProgress
17671799

17681800
return (
17691801
<div
@@ -1887,7 +1919,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18871919
className={`flex h-9 items-center mb-1 px-[15px] ${
18881920
showScrollToBottom
18891921
? "opacity-100"
1890-
: enableButtons || (isStreaming && !didClickCancel)
1922+
: enableButtons || ((isStreaming || isApiRequestInProgress) && !didClickCancel)
18911923
? "opacity-100"
18921924
: "opacity-50"
18931925
}`}>
@@ -1937,10 +1969,10 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
19371969
</VSCodeButton>
19381970
</StandardTooltip>
19391971
)}
1940-
{(secondaryButtonText || isStreaming) && (
1972+
{(secondaryButtonText || isStreaming || isApiRequestInProgress) && (
19411973
<StandardTooltip
19421974
content={
1943-
isStreaming
1975+
isStreaming || isApiRequestInProgress
19441976
? t("chat:cancel.tooltip")
19451977
: secondaryButtonText === t("chat:startNewTask.title")
19461978
? t("chat:startNewTask.tooltip")
@@ -1952,10 +1984,18 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
19521984
}>
19531985
<VSCodeButton
19541986
appearance="secondary"
1955-
disabled={!enableButtons && !(isStreaming && !didClickCancel)}
1956-
className={isStreaming ? "flex-[2] ml-0" : "flex-1 ml-[6px]"}
1987+
disabled={
1988+
!enableButtons && !(isApiRequestInProgress && !didClickCancel)
1989+
}
1990+
className={
1991+
isStreaming || isApiRequestInProgress
1992+
? "flex-[2] ml-0"
1993+
: "flex-1 ml-[6px]"
1994+
}
19571995
onClick={() => handleSecondaryButtonClick(inputValue, selectedImages)}>
1958-
{isStreaming ? t("chat:cancel.title") : secondaryButtonText}
1996+
{isStreaming || isApiRequestInProgress
1997+
? t("chat:cancel.title")
1998+
: secondaryButtonText}
19591999
</VSCodeButton>
19602000
</StandardTooltip>
19612001
)}

0 commit comments

Comments
 (0)