mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Add logic for handling different ask states in the webview
This commit is contained in:
@@ -196,7 +196,7 @@ export class SidebarProvider implements vscode.WebviewViewProvider {
|
|||||||
case "askResponse":
|
case "askResponse":
|
||||||
this.claudeDev?.handleWebviewAskResponse(message.askResponse!, message.text)
|
this.claudeDev?.handleWebviewAskResponse(message.askResponse!, message.text)
|
||||||
break
|
break
|
||||||
case "abortTask":
|
case "clearTask":
|
||||||
await this.clearTask()
|
await this.clearTask()
|
||||||
await this.postStateToWebview()
|
await this.postStateToWebview()
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export interface WebviewMessage {
|
export interface WebviewMessage {
|
||||||
type: "apiKey" | "maxRequestsPerTask" | "webviewDidLaunch" | "newTask" | "askResponse" | "abortTask"
|
type: "apiKey" | "maxRequestsPerTask" | "webviewDidLaunch" | "newTask" | "askResponse" | "clearTask"
|
||||||
text?: string
|
text?: string
|
||||||
askResponse?: ClaudeAskResponse
|
askResponse?: ClaudeAskResponse
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ClaudeAskResponse = "newTaskButtonTapped" | "yesButtonTapped" | "noButtonTapped" | "textResponse"
|
export type ClaudeAskResponse = "yesButtonTapped" | "noButtonTapped" | "textResponse"
|
||||||
@@ -244,7 +244,7 @@ const ChatRow: React.FC<ChatRowProps> = ({ message }) => {
|
|||||||
{title}
|
{title}
|
||||||
</div>
|
</div>
|
||||||
<div style={contentStyle}>
|
<div style={contentStyle}>
|
||||||
<p style={contentStyle}>Claude Dev wants to execute the following command:</p>
|
<p style={contentStyle}>Claude Dev wants to execute the following terminal command. Would you like to proceed?</p>
|
||||||
<p style={contentStyle}>{command}</p>
|
<p style={contentStyle}>{command}</p>
|
||||||
{output && (
|
{output && (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
const [textAreaHeight, setTextAreaHeight] = useState<number | undefined>(undefined)
|
const [textAreaHeight, setTextAreaHeight] = useState<number | undefined>(undefined)
|
||||||
const [textAreaDisabled, setTextAreaDisabled] = useState(false)
|
const [textAreaDisabled, setTextAreaDisabled] = useState(false)
|
||||||
|
|
||||||
|
// we need to hold on to the ask because useEffect > lastMessage will always let us know when an ask comes in and handle it, but by the time handleMessage is called, the last message might not be the ask anymore (it could be a say that followed)
|
||||||
const [claudeAsk, setClaudeAsk] = useState<ClaudeAsk | undefined>(undefined)
|
const [claudeAsk, setClaudeAsk] = useState<ClaudeAsk | undefined>(undefined)
|
||||||
|
|
||||||
const [primaryButtonText, setPrimaryButtonText] = useState<string | undefined>(undefined)
|
const [primaryButtonText, setPrimaryButtonText] = useState<string | undefined>(undefined)
|
||||||
@@ -40,19 +41,6 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handlePrimaryButtonClick = () => {
|
|
||||||
//vscode.postMessage({ type: "askResponse", askResponse: "primaryButton" })
|
|
||||||
setPrimaryButtonText(undefined)
|
|
||||||
setSecondaryButtonText(undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
// New function to handle secondary button click
|
|
||||||
const handleSecondaryButtonClick = () => {
|
|
||||||
//vscode.postMessage({ type: "askResponse", askResponse: "secondaryButton" })
|
|
||||||
setPrimaryButtonText(undefined)
|
|
||||||
setSecondaryButtonText(undefined)
|
|
||||||
}
|
|
||||||
|
|
||||||
// scroll to bottom when new message is added
|
// scroll to bottom when new message is added
|
||||||
const visibleMessages = useMemo(
|
const visibleMessages = useMemo(
|
||||||
() =>
|
() =>
|
||||||
@@ -73,50 +61,125 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
|
|
||||||
const lastMessage = messages.at(-1)
|
const lastMessage = messages.at(-1)
|
||||||
if (lastMessage) {
|
if (lastMessage) {
|
||||||
if (lastMessage.type === "ask") {
|
switch (lastMessage.type) {
|
||||||
//setTextAreaDisabled(false) // should enable for certain asks
|
case "ask":
|
||||||
setClaudeAsk(lastMessage.ask)
|
switch (lastMessage.ask) {
|
||||||
// Set button texts based on the ask
|
case "request_limit_reached":
|
||||||
// setPrimaryButtonText(lastMessage.ask === "command" ? "Yes" : "Continue")
|
setTextAreaDisabled(true)
|
||||||
// setSecondaryButtonText(lastMessage.ask === "yesno" ? "No" : undefined)
|
setClaudeAsk("request_limit_reached")
|
||||||
setPrimaryButtonText("Yes")
|
setPrimaryButtonText("Proceed")
|
||||||
setSecondaryButtonText("No")
|
setSecondaryButtonText("Start New Task")
|
||||||
} else {
|
break
|
||||||
//setTextAreaDisabled(true)
|
case "followup":
|
||||||
setClaudeAsk(undefined)
|
setTextAreaDisabled(false)
|
||||||
// setPrimaryButtonText(undefined)
|
setClaudeAsk("followup")
|
||||||
// setSecondaryButtonText(undefined)
|
setPrimaryButtonText(undefined)
|
||||||
setPrimaryButtonText("Yes")
|
setSecondaryButtonText(undefined)
|
||||||
setSecondaryButtonText("No")
|
break
|
||||||
|
case "command":
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClaudeAsk("command")
|
||||||
|
setPrimaryButtonText("Yes")
|
||||||
|
setSecondaryButtonText("No")
|
||||||
|
break
|
||||||
|
case "completion_result":
|
||||||
|
// extension waiting for feedback. but we can just present a new task button
|
||||||
|
setTextAreaDisabled(false)
|
||||||
|
setClaudeAsk("completion_result")
|
||||||
|
setPrimaryButtonText("Start New Task")
|
||||||
|
setSecondaryButtonText(undefined)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case "say":
|
||||||
|
// don't want to reset since there could be a "say" after an "ask" while ask is waiting for response
|
||||||
|
switch (lastMessage.say) {
|
||||||
|
case "task":
|
||||||
|
break
|
||||||
|
case "error":
|
||||||
|
break
|
||||||
|
case "api_req_started":
|
||||||
|
break
|
||||||
|
case "api_req_finished":
|
||||||
|
break
|
||||||
|
case "text":
|
||||||
|
break
|
||||||
|
case "tool":
|
||||||
|
break
|
||||||
|
case "command_output":
|
||||||
|
break
|
||||||
|
case "completion_result":
|
||||||
|
break
|
||||||
|
}
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// No messages, so user has to submit a task
|
||||||
|
setTextAreaDisabled(false)
|
||||||
|
setClaudeAsk(undefined)
|
||||||
|
setPrimaryButtonText(undefined)
|
||||||
|
setSecondaryButtonText(undefined)
|
||||||
}
|
}
|
||||||
}, [messages])
|
}, [messages])
|
||||||
|
|
||||||
const handleSendMessage = () => {
|
const handleSendMessage = () => {
|
||||||
const text = inputValue.trim()
|
const text = inputValue.trim()
|
||||||
if (text) {
|
if (text) {
|
||||||
setInputValue("")
|
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
vscode.postMessage({ type: "newTask", text })
|
vscode.postMessage({ type: "newTask", text })
|
||||||
} else if (claudeAsk) {
|
} else if (claudeAsk) {
|
||||||
switch (claudeAsk) {
|
switch (claudeAsk) {
|
||||||
case "followup":
|
case "followup":
|
||||||
|
case "completion_result": // if this happens then the user has feedback for the completion result
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: "textResponse", text })
|
vscode.postMessage({ type: "askResponse", askResponse: "textResponse", text })
|
||||||
break
|
break
|
||||||
// case "completion_result":
|
// there is no other case that a textfield should be enabled
|
||||||
// vscode.postMessage({ type: "askResponse", text })
|
|
||||||
// break
|
|
||||||
default:
|
|
||||||
// for now we'll type the askResponses
|
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: text as ClaudeAskResponse })
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
setInputValue("")
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClaudeAsk(undefined)
|
||||||
|
setPrimaryButtonText(undefined)
|
||||||
|
setSecondaryButtonText(undefined)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handle ask buttons
|
/*
|
||||||
// be sure to setInputValue("")
|
This logic depends on the useEffect[messages] above to set claudeAsk, after which buttons are shown and we then send an askResponse to the extension.
|
||||||
|
*/
|
||||||
|
const handlePrimaryButtonClick = () => {
|
||||||
|
switch (claudeAsk) {
|
||||||
|
case "request_limit_reached":
|
||||||
|
vscode.postMessage({ type: "askResponse", askResponse: "yesButtonTapped" })
|
||||||
|
break
|
||||||
|
case "command":
|
||||||
|
vscode.postMessage({ type: "askResponse", askResponse: "yesButtonTapped" })
|
||||||
|
break
|
||||||
|
case "completion_result":
|
||||||
|
// extension waiting for feedback. but we can just present a new task button
|
||||||
|
startNewTask()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClaudeAsk(undefined)
|
||||||
|
setPrimaryButtonText(undefined)
|
||||||
|
setSecondaryButtonText(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleSecondaryButtonClick = () => {
|
||||||
|
switch (claudeAsk) {
|
||||||
|
case "request_limit_reached":
|
||||||
|
startNewTask()
|
||||||
|
break
|
||||||
|
case "command":
|
||||||
|
vscode.postMessage({ type: "askResponse", askResponse: "noButtonTapped" })
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClaudeAsk(undefined)
|
||||||
|
setPrimaryButtonText(undefined)
|
||||||
|
setSecondaryButtonText(undefined)
|
||||||
|
}
|
||||||
|
|
||||||
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
const handleKeyDown = (event: KeyboardEvent<HTMLTextAreaElement>) => {
|
||||||
if (event.key === "Enter" && !event.shiftKey) {
|
if (event.key === "Enter" && !event.shiftKey) {
|
||||||
@@ -126,7 +189,11 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleTaskCloseButtonClick = () => {
|
const handleTaskCloseButtonClick = () => {
|
||||||
vscode.postMessage({ type: "abortTask" })
|
startNewTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
const startNewTask = () => {
|
||||||
|
vscode.postMessage({ type: "clearTask" })
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -172,13 +239,15 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}>
|
}}>
|
||||||
<TaskHeader
|
{task && (
|
||||||
taskText={task?.text || ""}
|
<TaskHeader
|
||||||
tokensIn={apiMetrics.totalTokensIn}
|
taskText={task.text || ""}
|
||||||
tokensOut={apiMetrics.totalTokensOut}
|
tokensIn={apiMetrics.totalTokensIn}
|
||||||
totalCost={apiMetrics.totalCost}
|
tokensOut={apiMetrics.totalTokensOut}
|
||||||
onClose={handleTaskCloseButtonClick}
|
totalCost={apiMetrics.totalCost}
|
||||||
/>
|
onClose={handleTaskCloseButtonClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div
|
<div
|
||||||
className="scrollable"
|
className="scrollable"
|
||||||
style={{
|
style={{
|
||||||
@@ -249,7 +318,7 @@ const ChatView = ({ messages }: ChatViewProps) => {
|
|||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
}}>
|
}}>
|
||||||
<VSCodeButton appearance="icon" aria-label="Send Message" onClick={handleSendMessage}>
|
<VSCodeButton disabled={textAreaDisabled} appearance="icon" aria-label="Send Message" onClick={handleSendMessage}>
|
||||||
<span className="codicon codicon-send"></span>
|
<span className="codicon codicon-send"></span>
|
||||||
</VSCodeButton>
|
</VSCodeButton>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user