mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 12:21:13 -05:00
Allow feedback to tool or command use
This commit is contained in:
@@ -334,7 +334,7 @@ export class ClaudeDev {
|
|||||||
})
|
})
|
||||||
.join("")
|
.join("")
|
||||||
|
|
||||||
const { response } = await this.ask(
|
const { response, text } = await this.ask(
|
||||||
"tool",
|
"tool",
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
tool: "editedExistingFile",
|
tool: "editedExistingFile",
|
||||||
@@ -343,18 +343,26 @@ export class ClaudeDev {
|
|||||||
} as ClaudeSayTool)
|
} as ClaudeSayTool)
|
||||||
)
|
)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "This operation was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.writeFile(filePath, newContent)
|
await fs.writeFile(filePath, newContent)
|
||||||
return `Changes applied to ${filePath}:\n${diffResult}`
|
return `Changes applied to ${filePath}:\n${diffResult}`
|
||||||
} else {
|
} else {
|
||||||
const { response } = await this.ask(
|
const { response, text } = await this.ask(
|
||||||
"tool",
|
"tool",
|
||||||
JSON.stringify({ tool: "newFileCreated", path: filePath, content: newContent } as ClaudeSayTool)
|
JSON.stringify({ tool: "newFileCreated", path: filePath, content: newContent } as ClaudeSayTool)
|
||||||
)
|
)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "This operation was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
await fs.mkdir(path.dirname(filePath), { recursive: true })
|
||||||
await fs.writeFile(filePath, newContent)
|
await fs.writeFile(filePath, newContent)
|
||||||
@@ -370,12 +378,16 @@ export class ClaudeDev {
|
|||||||
async readFile(filePath: string): Promise<string> {
|
async readFile(filePath: string): Promise<string> {
|
||||||
try {
|
try {
|
||||||
const content = await fs.readFile(filePath, "utf-8")
|
const content = await fs.readFile(filePath, "utf-8")
|
||||||
const { response } = await this.ask(
|
const { response, text } = await this.ask(
|
||||||
"tool",
|
"tool",
|
||||||
JSON.stringify({ tool: "readFile", path: filePath, content } as ClaudeSayTool)
|
JSON.stringify({ tool: "readFile", path: filePath, content } as ClaudeSayTool)
|
||||||
)
|
)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "This operation was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
return content
|
return content
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -391,12 +403,16 @@ export class ClaudeDev {
|
|||||||
const isRoot = absolutePath === root
|
const isRoot = absolutePath === root
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
const { response } = await this.ask(
|
const { response, text } = await this.ask(
|
||||||
"tool",
|
"tool",
|
||||||
JSON.stringify({ tool: "listFiles", path: dirPath, content: root } as ClaudeSayTool)
|
JSON.stringify({ tool: "listFiles", path: dirPath, content: root } as ClaudeSayTool)
|
||||||
)
|
)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "This operation was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return root
|
return root
|
||||||
@@ -412,12 +428,16 @@ export class ClaudeDev {
|
|||||||
const entries = await glob("*", options)
|
const entries = await glob("*", options)
|
||||||
const result = entries.slice(0, 500).join("\n") // truncate to 500 entries
|
const result = entries.slice(0, 500).join("\n") // truncate to 500 entries
|
||||||
if (shouldLog) {
|
if (shouldLog) {
|
||||||
const { response } = await this.ask(
|
const { response, text } = await this.ask(
|
||||||
"tool",
|
"tool",
|
||||||
JSON.stringify({ tool: "listFiles", path: dirPath, content: result } as ClaudeSayTool)
|
JSON.stringify({ tool: "listFiles", path: dirPath, content: result } as ClaudeSayTool)
|
||||||
)
|
)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "This operation was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
@@ -434,9 +454,13 @@ export class ClaudeDev {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async executeCommand(command: string): Promise<string> {
|
async executeCommand(command: string): Promise<string> {
|
||||||
const { response } = await this.ask("command", command)
|
const { response, text } = await this.ask("command", command)
|
||||||
if (response !== "yesButtonTapped") {
|
if (response !== "yesButtonTapped") {
|
||||||
return "Command execution was not approved by the user."
|
if (response === "textResponse" && text) {
|
||||||
|
await this.say("user_feedback", text)
|
||||||
|
return `The user denied this operation and provided the following feedback:\n\"${text}\"`
|
||||||
|
}
|
||||||
|
return "The user denied this operation."
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
let result = ""
|
let result = ""
|
||||||
|
|||||||
@@ -99,18 +99,18 @@ const ChatView = ({ messages, isHidden, vscodeThemeName }: ChatViewProps) => {
|
|||||||
// setSecondaryButtonText(undefined)
|
// setSecondaryButtonText(undefined)
|
||||||
break
|
break
|
||||||
case "tool":
|
case "tool":
|
||||||
setTextAreaDisabled(true)
|
setTextAreaDisabled(false)
|
||||||
setClaudeAsk("tool")
|
setClaudeAsk("tool")
|
||||||
setEnableButtons(true)
|
setEnableButtons(true)
|
||||||
setPrimaryButtonText("Approve")
|
setPrimaryButtonText("Approve")
|
||||||
setSecondaryButtonText("Cancel")
|
setSecondaryButtonText("Reject")
|
||||||
break
|
break
|
||||||
case "command":
|
case "command":
|
||||||
setTextAreaDisabled(true)
|
setTextAreaDisabled(false)
|
||||||
setClaudeAsk("command")
|
setClaudeAsk("command")
|
||||||
setEnableButtons(true)
|
setEnableButtons(true)
|
||||||
setPrimaryButtonText("Run Command")
|
setPrimaryButtonText("Run Command")
|
||||||
setSecondaryButtonText("Cancel")
|
setSecondaryButtonText("Reject")
|
||||||
break
|
break
|
||||||
case "completion_result":
|
case "completion_result":
|
||||||
// extension waiting for feedback. but we can just present a new task button
|
// extension waiting for feedback. but we can just present a new task button
|
||||||
@@ -170,6 +170,8 @@ const ChatView = ({ messages, isHidden, vscodeThemeName }: ChatViewProps) => {
|
|||||||
} else if (claudeAsk) {
|
} else if (claudeAsk) {
|
||||||
switch (claudeAsk) {
|
switch (claudeAsk) {
|
||||||
case "followup":
|
case "followup":
|
||||||
|
case "tool":
|
||||||
|
case "command": // user can provide feedback to a tool or command use
|
||||||
case "completion_result": // if this happens then the user has feedback for the completion result
|
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
|
||||||
@@ -210,10 +212,11 @@ const ChatView = ({ messages, isHidden, vscodeThemeName }: ChatViewProps) => {
|
|||||||
const handleSecondaryButtonClick = () => {
|
const handleSecondaryButtonClick = () => {
|
||||||
switch (claudeAsk) {
|
switch (claudeAsk) {
|
||||||
case "request_limit_reached":
|
case "request_limit_reached":
|
||||||
case "tool": // TODO: for now when a user cancels, it starts a new task. But we could easily just respond to the API with a "This operation failed" and let it try again.
|
|
||||||
startNewTask()
|
startNewTask()
|
||||||
break
|
break
|
||||||
case "command":
|
case "command":
|
||||||
|
case "tool":
|
||||||
|
// responds to the API with a "This operation failed" and lets it try again
|
||||||
vscode.postMessage({ type: "askResponse", askResponse: "noButtonTapped" })
|
vscode.postMessage({ type: "askResponse", askResponse: "noButtonTapped" })
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -272,7 +275,7 @@ const ChatView = ({ messages, isHidden, vscodeThemeName }: ChatViewProps) => {
|
|||||||
}, [textAreaRef.current])
|
}, [textAreaRef.current])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isHidden && !textAreaDisabled) {
|
if (!isHidden && !textAreaDisabled && !enableButtons) {
|
||||||
textAreaRef.current?.focus()
|
textAreaRef.current?.focus()
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
@@ -280,13 +283,14 @@ const ChatView = ({ messages, isHidden, vscodeThemeName }: ChatViewProps) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const timer = setTimeout(() => {
|
const timer = setTimeout(() => {
|
||||||
if (!textAreaDisabled) {
|
if (!textAreaDisabled && !enableButtons) {
|
||||||
textAreaRef.current?.focus()
|
textAreaRef.current?.focus()
|
||||||
}
|
}
|
||||||
}, 50)
|
}, 50)
|
||||||
return () => {
|
return () => {
|
||||||
clearTimeout(timer)
|
clearTimeout(timer)
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [textAreaDisabled])
|
}, [textAreaDisabled])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user