mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Merge pull request #638 from napter/approval-feedback
Allow the user to send context with approval or rejection
This commit is contained in:
@@ -1093,35 +1093,23 @@ export class Cline {
|
|||||||
const askApproval = async (type: ClineAsk, partialMessage?: string) => {
|
const askApproval = async (type: ClineAsk, partialMessage?: string) => {
|
||||||
const { response, text, images } = await this.ask(type, partialMessage, false)
|
const { response, text, images } = await this.ask(type, partialMessage, false)
|
||||||
if (response !== "yesButtonClicked") {
|
if (response !== "yesButtonClicked") {
|
||||||
if (response === "messageResponse") {
|
// Handle both messageResponse and noButtonClicked with text
|
||||||
|
if (text) {
|
||||||
await this.say("user_feedback", text, images)
|
await this.say("user_feedback", text, images)
|
||||||
pushToolResult(
|
pushToolResult(
|
||||||
formatResponse.toolResult(formatResponse.toolDeniedWithFeedback(text), images),
|
formatResponse.toolResult(formatResponse.toolDeniedWithFeedback(text), images),
|
||||||
)
|
)
|
||||||
// this.userMessageContent.push({
|
} else {
|
||||||
// type: "text",
|
pushToolResult(formatResponse.toolDenied())
|
||||||
// text: `${toolDescription()}`,
|
|
||||||
// })
|
|
||||||
// this.toolResults.push({
|
|
||||||
// type: "tool_result",
|
|
||||||
// tool_use_id: toolUseId,
|
|
||||||
// content: this.formatToolResponseWithImages(
|
|
||||||
// await this.formatToolDeniedFeedback(text),
|
|
||||||
// images
|
|
||||||
// ),
|
|
||||||
// })
|
|
||||||
this.didRejectTool = true
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
pushToolResult(formatResponse.toolDenied())
|
|
||||||
// this.toolResults.push({
|
|
||||||
// type: "tool_result",
|
|
||||||
// tool_use_id: toolUseId,
|
|
||||||
// content: await this.formatToolDenied(),
|
|
||||||
// })
|
|
||||||
this.didRejectTool = true
|
this.didRejectTool = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
// Handle yesButtonClicked with text
|
||||||
|
if (text) {
|
||||||
|
await this.say("user_feedback", text, images)
|
||||||
|
pushToolResult(formatResponse.toolResult(formatResponse.toolApprovedWithFeedback(text), images))
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ export const formatResponse = {
|
|||||||
toolDeniedWithFeedback: (feedback?: string) =>
|
toolDeniedWithFeedback: (feedback?: string) =>
|
||||||
`The user denied this operation and provided the following feedback:\n<feedback>\n${feedback}\n</feedback>`,
|
`The user denied this operation and provided the following feedback:\n<feedback>\n${feedback}\n</feedback>`,
|
||||||
|
|
||||||
|
toolApprovedWithFeedback: (feedback?: string) =>
|
||||||
|
`The user approved this operation and provided the following context:\n<feedback>\n${feedback}\n</feedback>`,
|
||||||
|
|
||||||
toolError: (error?: string) => `The tool execution failed with the following error:\n<error>\n${error}\n</error>`,
|
toolError: (error?: string) => `The tool execution failed with the following error:\n<error>\n${error}\n</error>`,
|
||||||
|
|
||||||
noToolsUsed: () =>
|
noToolsUsed: () =>
|
||||||
|
|||||||
@@ -337,56 +337,96 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
/*
|
/*
|
||||||
This logic depends on the useEffect[messages] above to set clineAsk, after which buttons are shown and we then send an askResponse to the extension.
|
This logic depends on the useEffect[messages] above to set clineAsk, after which buttons are shown and we then send an askResponse to the extension.
|
||||||
*/
|
*/
|
||||||
const handlePrimaryButtonClick = useCallback(() => {
|
const handlePrimaryButtonClick = useCallback(
|
||||||
switch (clineAsk) {
|
(text?: string, images?: string[]) => {
|
||||||
case "api_req_failed":
|
const trimmedInput = text?.trim()
|
||||||
case "command":
|
switch (clineAsk) {
|
||||||
case "command_output":
|
case "api_req_failed":
|
||||||
case "tool":
|
case "command":
|
||||||
case "browser_action_launch":
|
case "command_output":
|
||||||
case "use_mcp_server":
|
case "tool":
|
||||||
case "resume_task":
|
case "browser_action_launch":
|
||||||
case "mistake_limit_reached":
|
case "use_mcp_server":
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: "yesButtonClicked" })
|
case "resume_task":
|
||||||
break
|
case "mistake_limit_reached":
|
||||||
case "completion_result":
|
// Only send text/images if they exist
|
||||||
case "resume_completed_task":
|
if (trimmedInput || (images && images.length > 0)) {
|
||||||
// extension waiting for feedback. but we can just present a new task button
|
vscode.postMessage({
|
||||||
startNewTask()
|
type: "askResponse",
|
||||||
break
|
askResponse: "yesButtonClicked",
|
||||||
}
|
text: trimmedInput,
|
||||||
setTextAreaDisabled(true)
|
images: images,
|
||||||
setClineAsk(undefined)
|
})
|
||||||
setEnableButtons(false)
|
} else {
|
||||||
disableAutoScrollRef.current = false
|
vscode.postMessage({
|
||||||
}, [clineAsk, startNewTask])
|
type: "askResponse",
|
||||||
|
askResponse: "yesButtonClicked",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Clear input state after sending
|
||||||
|
setInputValue("")
|
||||||
|
setSelectedImages([])
|
||||||
|
break
|
||||||
|
case "completion_result":
|
||||||
|
case "resume_completed_task":
|
||||||
|
// extension waiting for feedback. but we can just present a new task button
|
||||||
|
startNewTask()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClineAsk(undefined)
|
||||||
|
setEnableButtons(false)
|
||||||
|
disableAutoScrollRef.current = false
|
||||||
|
},
|
||||||
|
[clineAsk, startNewTask],
|
||||||
|
)
|
||||||
|
|
||||||
const handleSecondaryButtonClick = useCallback(() => {
|
const handleSecondaryButtonClick = useCallback(
|
||||||
if (isStreaming) {
|
(text?: string, images?: string[]) => {
|
||||||
vscode.postMessage({ type: "cancelTask" })
|
const trimmedInput = text?.trim()
|
||||||
setDidClickCancel(true)
|
if (isStreaming) {
|
||||||
return
|
vscode.postMessage({ type: "cancelTask" })
|
||||||
}
|
setDidClickCancel(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
switch (clineAsk) {
|
switch (clineAsk) {
|
||||||
case "api_req_failed":
|
case "api_req_failed":
|
||||||
case "mistake_limit_reached":
|
case "mistake_limit_reached":
|
||||||
case "resume_task":
|
case "resume_task":
|
||||||
startNewTask()
|
startNewTask()
|
||||||
break
|
break
|
||||||
case "command":
|
case "command":
|
||||||
case "tool":
|
case "tool":
|
||||||
case "browser_action_launch":
|
case "browser_action_launch":
|
||||||
case "use_mcp_server":
|
case "use_mcp_server":
|
||||||
// responds to the API with a "This operation failed" and lets it try again
|
// Only send text/images if they exist
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: "noButtonClicked" })
|
if (trimmedInput || (images && images.length > 0)) {
|
||||||
break
|
vscode.postMessage({
|
||||||
}
|
type: "askResponse",
|
||||||
setTextAreaDisabled(true)
|
askResponse: "noButtonClicked",
|
||||||
setClineAsk(undefined)
|
text: trimmedInput,
|
||||||
setEnableButtons(false)
|
images: images,
|
||||||
disableAutoScrollRef.current = false
|
})
|
||||||
}, [clineAsk, startNewTask, isStreaming])
|
} else {
|
||||||
|
// responds to the API with a "This operation failed" and lets it try again
|
||||||
|
vscode.postMessage({
|
||||||
|
type: "askResponse",
|
||||||
|
askResponse: "noButtonClicked",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// Clear input state after sending
|
||||||
|
setInputValue("")
|
||||||
|
setSelectedImages([])
|
||||||
|
break
|
||||||
|
}
|
||||||
|
setTextAreaDisabled(true)
|
||||||
|
setClineAsk(undefined)
|
||||||
|
setEnableButtons(false)
|
||||||
|
disableAutoScrollRef.current = false
|
||||||
|
},
|
||||||
|
[clineAsk, startNewTask, isStreaming],
|
||||||
|
)
|
||||||
|
|
||||||
const handleTaskCloseButtonClick = useCallback(() => {
|
const handleTaskCloseButtonClick = useCallback(() => {
|
||||||
startNewTask()
|
startNewTask()
|
||||||
@@ -430,10 +470,10 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
handleSendMessage(message.text ?? "", message.images ?? [])
|
handleSendMessage(message.text ?? "", message.images ?? [])
|
||||||
break
|
break
|
||||||
case "primaryButtonClick":
|
case "primaryButtonClick":
|
||||||
handlePrimaryButtonClick()
|
handlePrimaryButtonClick(message.text ?? "", message.images ?? [])
|
||||||
break
|
break
|
||||||
case "secondaryButtonClick":
|
case "secondaryButtonClick":
|
||||||
handleSecondaryButtonClick()
|
handleSecondaryButtonClick(message.text ?? "", message.images ?? [])
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1038,7 +1078,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
flex: secondaryButtonText ? 1 : 2,
|
flex: secondaryButtonText ? 1 : 2,
|
||||||
marginRight: secondaryButtonText ? "6px" : "0",
|
marginRight: secondaryButtonText ? "6px" : "0",
|
||||||
}}
|
}}
|
||||||
onClick={handlePrimaryButtonClick}>
|
onClick={(e) => handlePrimaryButtonClick(inputValue, selectedImages)}>
|
||||||
{primaryButtonText}
|
{primaryButtonText}
|
||||||
</VSCodeButton>
|
</VSCodeButton>
|
||||||
)}
|
)}
|
||||||
@@ -1050,7 +1090,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
flex: isStreaming ? 2 : 1,
|
flex: isStreaming ? 2 : 1,
|
||||||
marginLeft: isStreaming ? 0 : "6px",
|
marginLeft: isStreaming ? 0 : "6px",
|
||||||
}}
|
}}
|
||||||
onClick={handleSecondaryButtonClick}>
|
onClick={(e) => handleSecondaryButtonClick(inputValue, selectedImages)}>
|
||||||
{isStreaming ? "Cancel" : secondaryButtonText}
|
{isStreaming ? "Cancel" : secondaryButtonText}
|
||||||
</VSCodeButton>
|
</VSCodeButton>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user