Skip to content

Commit 77768f8

Browse files
committed
feat: pause auto-approve while typing in chat input
- Auto-approve operations are now paused when there is text in the chat input box - Added visual indicator showing "Auto-approve paused while typing" when paused - Added tests to verify the pause/resume functionality - Addresses user feedback about auto-approve continuing while typing hints Fixes #8074
1 parent 7b1e3a0 commit 77768f8

File tree

3 files changed

+175
-0
lines changed

3 files changed

+175
-0
lines changed

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

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,13 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
15941594
return
15951595
}
15961596

1597+
// Check if there's text in the input box - pause auto-approve if there is
1598+
const hasInputText = inputValueRef.current.trim().length > 0
1599+
if (hasInputText) {
1600+
// User is typing, don't auto-approve
1601+
return
1602+
}
1603+
15971604
const autoApproveOrReject = async () => {
15981605
// Check for auto-reject first (commands that should be denied)
15991606
if (lastMessage?.ask === "command" && isDeniedCommand(lastMessage)) {
@@ -1703,6 +1710,7 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
17031710
isDeniedCommand,
17041711
getDeniedPrefix,
17051712
tSettings,
1713+
inputValue, // Add inputValue dependency to re-run when input changes
17061714
])
17071715

17081716
// Function to handle mode switching
@@ -1898,6 +1906,16 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
18981906
? "opacity-100"
18991907
: "opacity-50"
19001908
}`}>
1909+
{/* Show auto-approve paused indicator when there's input text */}
1910+
{enableButtons &&
1911+
autoApprovalEnabled &&
1912+
hasEnabledOptions &&
1913+
inputValue.trim().length > 0 &&
1914+
!showScrollToBottom && (
1915+
<div className="flex-1 text-xs text-vscode-descriptionForeground opacity-75 text-center">
1916+
{t("chat:autoApprovePaused")}
1917+
</div>
1918+
)}
19011919
{showScrollToBottom ? (
19021920
<StandardTooltip content={t("chat:scrollToBottom")}>
19031921
<VSCodeButton

webview-ui/src/components/chat/__tests__/ChatView.auto-approve.spec.tsx

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -671,4 +671,160 @@ describe("ChatView - Auto Approval Tests", () => {
671671
askResponse: "yesButtonClicked",
672672
})
673673
})
674+
675+
it("does not auto-approve when there is text in the input box", async () => {
676+
const { container } = renderChatView()
677+
678+
// First hydrate state with initial task
679+
mockPostMessage({
680+
alwaysAllowReadOnly: true,
681+
autoApprovalEnabled: true,
682+
clineMessages: [
683+
{
684+
type: "say",
685+
say: "task",
686+
ts: Date.now() - 2000,
687+
text: "Initial task",
688+
},
689+
],
690+
})
691+
692+
// Simulate typing in the input box
693+
const textarea = container.querySelector("textarea")
694+
if (textarea) {
695+
// Simulate user typing
696+
Object.defineProperty(textarea, "value", {
697+
writable: true,
698+
value: "User is typing something...",
699+
})
700+
// Trigger input event
701+
const inputEvent = new Event("input", { bubbles: true })
702+
textarea.dispatchEvent(inputEvent)
703+
}
704+
705+
// Then send the read tool ask message
706+
mockPostMessage({
707+
alwaysAllowReadOnly: true,
708+
autoApprovalEnabled: true,
709+
clineMessages: [
710+
{
711+
type: "say",
712+
say: "task",
713+
ts: Date.now() - 2000,
714+
text: "Initial task",
715+
},
716+
{
717+
type: "ask",
718+
ask: "tool",
719+
ts: Date.now(),
720+
text: JSON.stringify({ tool: "readFile", path: "test.txt" }),
721+
partial: false,
722+
},
723+
],
724+
})
725+
726+
// Wait a short time and verify no auto-approval message was sent
727+
await new Promise((resolve) => setTimeout(resolve, 200))
728+
expect(vscode.postMessage).not.toHaveBeenCalledWith({
729+
type: "askResponse",
730+
askResponse: "yesButtonClicked",
731+
})
732+
})
733+
734+
it("resumes auto-approve when input text is cleared", async () => {
735+
const { container } = renderChatView()
736+
737+
// First hydrate state with initial task
738+
mockPostMessage({
739+
alwaysAllowReadOnly: true,
740+
autoApprovalEnabled: true,
741+
clineMessages: [
742+
{
743+
type: "say",
744+
say: "task",
745+
ts: Date.now() - 2000,
746+
text: "Initial task",
747+
},
748+
],
749+
})
750+
751+
// Simulate typing in the input box
752+
const textarea = container.querySelector("textarea")
753+
if (textarea) {
754+
// First add text
755+
Object.defineProperty(textarea, "value", {
756+
writable: true,
757+
value: "User is typing...",
758+
})
759+
const inputEvent = new Event("input", { bubbles: true })
760+
textarea.dispatchEvent(inputEvent)
761+
}
762+
763+
// Send a tool ask message while text is present
764+
mockPostMessage({
765+
alwaysAllowReadOnly: true,
766+
autoApprovalEnabled: true,
767+
clineMessages: [
768+
{
769+
type: "say",
770+
say: "task",
771+
ts: Date.now() - 2000,
772+
text: "Initial task",
773+
},
774+
{
775+
type: "ask",
776+
ask: "tool",
777+
ts: Date.now() - 100,
778+
text: JSON.stringify({ tool: "readFile", path: "test1.txt" }),
779+
partial: false,
780+
},
781+
],
782+
})
783+
784+
// Wait and verify no auto-approval
785+
await new Promise((resolve) => setTimeout(resolve, 100))
786+
expect(vscode.postMessage).not.toHaveBeenCalledWith({
787+
type: "askResponse",
788+
askResponse: "yesButtonClicked",
789+
})
790+
791+
// Now clear the input
792+
if (textarea) {
793+
Object.defineProperty(textarea, "value", {
794+
writable: true,
795+
value: "",
796+
})
797+
const clearEvent = new Event("input", { bubbles: true })
798+
textarea.dispatchEvent(clearEvent)
799+
}
800+
801+
// Send another tool ask message after clearing text
802+
mockPostMessage({
803+
alwaysAllowReadOnly: true,
804+
autoApprovalEnabled: true,
805+
clineMessages: [
806+
{
807+
type: "say",
808+
say: "task",
809+
ts: Date.now() - 2000,
810+
text: "Initial task",
811+
},
812+
{
813+
type: "ask",
814+
ask: "tool",
815+
ts: Date.now(),
816+
text: JSON.stringify({ tool: "readFile", path: "test2.txt" }),
817+
partial: false,
818+
},
819+
],
820+
})
821+
822+
// Now it should auto-approve since input is cleared
823+
await waitFor(() => {
824+
expect(vscode.postMessage).toHaveBeenCalledWith({
825+
type: "askResponse",
826+
askResponse: "yesButtonClicked",
827+
})
828+
})
829+
})
674830
})

webview-ui/src/i18n/locales/en/chat.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,7 @@
272272
},
273273
"autoApprove": {
274274
"tooltipManage": "Manage auto-approval settings",
275+
"autoApprovePaused": "Auto-approve paused while typing",
275276
"tooltipStatus": "Auto-approval enabled for: {{toggles}}",
276277
"title": "Auto-approve",
277278
"all": "All",

0 commit comments

Comments
 (0)