mirror of
https://github.com/RooVetGit/Roo-Code.git
synced 2026-09-05 08:10:14 +00:00
feat: add edit functionality for AI-generated responses
- Add edit button to AI text messages in ChatRow component - Implement edit mode UI with textarea and controls for AI messages - Update ChatView to pass editable prop for AI text responses - Handle AI message edits in webviewMessageHandler - Preserve message history when editing AI responses Fixes #8395
This commit is contained in:
parent
702b269a1b
commit
28476572fe
5 changed files with 112 additions and 28 deletions
|
|
@ -1530,12 +1530,54 @@ export const webviewMessageHandler = async (
|
|||
message.value &&
|
||||
message.editedMessageContent
|
||||
) {
|
||||
await handleMessageModificationsOperation(
|
||||
message.value,
|
||||
"edit",
|
||||
message.editedMessageContent,
|
||||
message.images,
|
||||
)
|
||||
// Check if this is an AI message edit
|
||||
const currentCline = provider.getCurrentTask()
|
||||
if (currentCline) {
|
||||
const messageIndex = currentCline.clineMessages.findIndex(
|
||||
(msg: ClineMessage) => msg.ts === message.value,
|
||||
)
|
||||
if (messageIndex !== -1) {
|
||||
const targetMessage = currentCline.clineMessages[messageIndex]
|
||||
|
||||
// If this is an AI text message, handle it differently
|
||||
if (targetMessage.say === "text" && !targetMessage.partial) {
|
||||
// For AI messages, we need to update the message directly
|
||||
// and update the API conversation history
|
||||
targetMessage.text = message.editedMessageContent
|
||||
if (message.images) {
|
||||
targetMessage.images = message.images
|
||||
}
|
||||
|
||||
// Save the updated messages
|
||||
await saveTaskMessages({
|
||||
messages: currentCline.clineMessages,
|
||||
taskId: currentCline.taskId,
|
||||
globalStoragePath: provider.contextProxy.globalStorageUri.fsPath,
|
||||
})
|
||||
|
||||
// Also update the API conversation history if this message exists there
|
||||
const apiIndex = currentCline.apiConversationHistory.findIndex(
|
||||
(msg: ApiMessage) => msg.ts === message.value,
|
||||
)
|
||||
if (apiIndex !== -1) {
|
||||
// Update the content for assistant messages in API history
|
||||
// Note: ApiMessage type doesn't support images property directly
|
||||
currentCline.apiConversationHistory[apiIndex].content = message.editedMessageContent
|
||||
}
|
||||
|
||||
// Update the UI to reflect the changes
|
||||
await provider.postStateToWebview()
|
||||
} else {
|
||||
// For user feedback messages, use the existing edit flow
|
||||
await handleMessageModificationsOperation(
|
||||
message.value,
|
||||
"edit",
|
||||
message.editedMessageContent,
|
||||
message.images,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
|
|
|
|||
1
tmp/Roo-Code
Submodule
1
tmp/Roo-Code
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 8111da66bd59ca8d500e5eae23b24a0419ed7345
|
||||
1
tmp/Roo-Code-rc
Submodule
1
tmp/Roo-Code-rc
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7b7bb49572975c4aeff2381a0ebea99b3aa4542c
|
||||
|
|
@ -1118,19 +1118,54 @@ export const ChatRowContent = ({
|
|||
return null // we should never see this message type
|
||||
case "text":
|
||||
return (
|
||||
<div>
|
||||
<div className="group">
|
||||
<div style={headerStyle}>
|
||||
<MessageCircle className="w-4 shrink-0" aria-label="Speech bubble icon" />
|
||||
<span style={{ fontWeight: "bold" }}>{t("chat:text.rooSaid")}</span>
|
||||
{/* Add edit button for AI responses */}
|
||||
{!isStreaming && !message.partial && editable && (
|
||||
<div
|
||||
className="cursor-pointer shrink-0 opacity-0 group-hover:opacity-100 transition-opacity ml-auto"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
handleEditClick()
|
||||
}}>
|
||||
<Edit className="w-4 shrink-0" aria-label="Edit AI response icon" />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="pl-6">
|
||||
<Markdown markdown={message.text} partial={message.partial} />
|
||||
{message.images && message.images.length > 0 && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{message.images.map((image, index) => (
|
||||
<ImageBlock key={index} imageData={image} />
|
||||
))}
|
||||
{isEditing ? (
|
||||
<div className="flex flex-col gap-2">
|
||||
<ChatTextArea
|
||||
inputValue={editedContent}
|
||||
setInputValue={setEditedContent}
|
||||
sendingDisabled={false}
|
||||
selectApiConfigDisabled={true}
|
||||
placeholderText={t("chat:editMessage.placeholder")}
|
||||
selectedImages={editImages}
|
||||
setSelectedImages={setEditImages}
|
||||
onSend={handleSaveEdit}
|
||||
onSelectImages={handleSelectImages}
|
||||
shouldDisableImages={!model?.supportsImages}
|
||||
mode={editMode}
|
||||
setMode={setEditMode}
|
||||
modeShortcutText=""
|
||||
isEditMode={true}
|
||||
onCancel={handleCancelEdit}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<Markdown markdown={message.text} partial={message.partial} />
|
||||
{message.images && message.images.length > 0 && (
|
||||
<div style={{ marginTop: "10px" }}>
|
||||
{message.images.map((image, index) => (
|
||||
<ImageBlock key={index} imageData={image} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1542,22 +1542,27 @@ const ChatViewComponent: React.ForwardRefRenderFunction<ChatViewRef, ChatViewPro
|
|||
onFollowUpUnmount={handleFollowUpUnmount}
|
||||
isFollowUpAnswered={messageOrGroup.isAnswered === true || messageOrGroup.ts === currentFollowUpTs}
|
||||
editable={
|
||||
messageOrGroup.type === "ask" &&
|
||||
messageOrGroup.ask === "tool" &&
|
||||
(() => {
|
||||
let tool: any = {}
|
||||
try {
|
||||
tool = JSON.parse(messageOrGroup.text || "{}")
|
||||
} catch (_) {
|
||||
if (messageOrGroup.text?.includes("updateTodoList")) {
|
||||
tool = { tool: "updateTodoList" }
|
||||
// Allow editing of user feedback messages
|
||||
messageOrGroup.say === "user_feedback" ||
|
||||
// Allow editing of AI text responses
|
||||
(messageOrGroup.say === "text" && !messageOrGroup.partial) ||
|
||||
// Allow editing of updateTodoList tool messages when buttons are enabled
|
||||
(messageOrGroup.type === "ask" &&
|
||||
messageOrGroup.ask === "tool" &&
|
||||
(() => {
|
||||
let tool: any = {}
|
||||
try {
|
||||
tool = JSON.parse(messageOrGroup.text || "{}")
|
||||
} catch (_) {
|
||||
if (messageOrGroup.text?.includes("updateTodoList")) {
|
||||
tool = { tool: "updateTodoList" }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tool.tool === "updateTodoList" && alwaysAllowUpdateTodoList) {
|
||||
return false
|
||||
}
|
||||
return tool.tool === "updateTodoList" && enableButtons && !!primaryButtonText
|
||||
})()
|
||||
if (tool.tool === "updateTodoList" && alwaysAllowUpdateTodoList) {
|
||||
return false
|
||||
}
|
||||
return tool.tool === "updateTodoList" && enableButtons && !!primaryButtonText
|
||||
})())
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue