mirror of
https://github.com/pacnpal/Roo-Code.git
synced 2025-12-20 04:11:10 -05:00
Add a button to delete user messages
This commit is contained in:
5
.changeset/khaki-pets-approve.md
Normal file
5
.changeset/khaki-pets-approve.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"roo-cline": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Add a button to delete user messages
|
||||||
@@ -5,6 +5,7 @@ A fork of Cline, an autonomous coding agent, with some additional experimental f
|
|||||||
## Experimental Features
|
## Experimental Features
|
||||||
|
|
||||||
- Drag and drop images into chats
|
- Drag and drop images into chats
|
||||||
|
- Delete messages from chats
|
||||||
- "Enhance prompt" button (OpenRouter models only for now)
|
- "Enhance prompt" button (OpenRouter models only for now)
|
||||||
- Sound effects for feedback
|
- Sound effects for feedback
|
||||||
- Option to use browsers of different sizes and adjust screenshot quality
|
- Option to use browsers of different sizes and adjust screenshot quality
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export class Cline {
|
|||||||
diffStrategy?: DiffStrategy
|
diffStrategy?: DiffStrategy
|
||||||
diffEnabled: boolean = false
|
diffEnabled: boolean = false
|
||||||
|
|
||||||
apiConversationHistory: Anthropic.MessageParam[] = []
|
apiConversationHistory: (Anthropic.MessageParam & { ts?: number })[] = []
|
||||||
clineMessages: ClineMessage[] = []
|
clineMessages: ClineMessage[] = []
|
||||||
private askResponse?: ClineAskResponse
|
private askResponse?: ClineAskResponse
|
||||||
private askResponseText?: string
|
private askResponseText?: string
|
||||||
@@ -165,11 +165,12 @@ export class Cline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async addToApiConversationHistory(message: Anthropic.MessageParam) {
|
private async addToApiConversationHistory(message: Anthropic.MessageParam) {
|
||||||
this.apiConversationHistory.push(message)
|
const messageWithTs = { ...message, ts: Date.now() }
|
||||||
|
this.apiConversationHistory.push(messageWithTs)
|
||||||
await this.saveApiConversationHistory()
|
await this.saveApiConversationHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async overwriteApiConversationHistory(newHistory: Anthropic.MessageParam[]) {
|
async overwriteApiConversationHistory(newHistory: Anthropic.MessageParam[]) {
|
||||||
this.apiConversationHistory = newHistory
|
this.apiConversationHistory = newHistory
|
||||||
await this.saveApiConversationHistory()
|
await this.saveApiConversationHistory()
|
||||||
}
|
}
|
||||||
@@ -205,7 +206,7 @@ export class Cline {
|
|||||||
await this.saveClineMessages()
|
await this.saveClineMessages()
|
||||||
}
|
}
|
||||||
|
|
||||||
private async overwriteClineMessages(newMessages: ClineMessage[]) {
|
public async overwriteClineMessages(newMessages: ClineMessage[]) {
|
||||||
this.clineMessages = newMessages
|
this.clineMessages = newMessages
|
||||||
await this.saveClineMessages()
|
await this.saveClineMessages()
|
||||||
}
|
}
|
||||||
@@ -460,6 +461,11 @@ export class Cline {
|
|||||||
await this.overwriteClineMessages(modifiedClineMessages)
|
await this.overwriteClineMessages(modifiedClineMessages)
|
||||||
this.clineMessages = await this.getSavedClineMessages()
|
this.clineMessages = await this.getSavedClineMessages()
|
||||||
|
|
||||||
|
// need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages
|
||||||
|
|
||||||
|
let existingApiConversationHistory: Anthropic.Messages.MessageParam[] =
|
||||||
|
await this.getSavedApiConversationHistory()
|
||||||
|
|
||||||
// Now present the cline messages to the user and ask if they want to resume
|
// Now present the cline messages to the user and ask if they want to resume
|
||||||
|
|
||||||
const lastClineMessage = this.clineMessages
|
const lastClineMessage = this.clineMessages
|
||||||
@@ -493,11 +499,6 @@ export class Cline {
|
|||||||
responseImages = images
|
responseImages = images
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to make sure that the api conversation history can be resumed by the api, even if it goes out of sync with cline messages
|
|
||||||
|
|
||||||
let existingApiConversationHistory: Anthropic.Messages.MessageParam[] =
|
|
||||||
await this.getSavedApiConversationHistory()
|
|
||||||
|
|
||||||
// v2.0 xml tags refactor caveat: since we don't use tools anymore, we need to replace all tool use blocks with a text block since the API disallows conversations with tool uses and no tool schema
|
// v2.0 xml tags refactor caveat: since we don't use tools anymore, we need to replace all tool use blocks with a text block since the API disallows conversations with tool uses and no tool schema
|
||||||
const conversationWithoutToolBlocks = existingApiConversationHistory.map((message) => {
|
const conversationWithoutToolBlocks = existingApiConversationHistory.map((message) => {
|
||||||
if (Array.isArray(message.content)) {
|
if (Array.isArray(message.content)) {
|
||||||
|
|||||||
@@ -642,6 +642,28 @@ export class ClineProvider implements vscode.WebviewViewProvider {
|
|||||||
await this.updateGlobalState("writeDelayMs", message.value)
|
await this.updateGlobalState("writeDelayMs", message.value)
|
||||||
await this.postStateToWebview()
|
await this.postStateToWebview()
|
||||||
break
|
break
|
||||||
|
case "deleteMessage": {
|
||||||
|
const answer = await vscode.window.showInformationMessage(
|
||||||
|
"Are you sure you want to delete this message and all subsequent messages?",
|
||||||
|
{ modal: true },
|
||||||
|
"Yes",
|
||||||
|
"No"
|
||||||
|
)
|
||||||
|
if (answer === "Yes" && this.cline && typeof message.value === 'number' && message.value) {
|
||||||
|
const timeCutoff = message.value - 1000; // 1 second buffer before the message to delete
|
||||||
|
const messageIndex = this.cline.clineMessages.findIndex(msg => msg.ts && msg.ts >= timeCutoff)
|
||||||
|
const apiConversationHistoryIndex = this.cline.apiConversationHistory.findIndex(msg => msg.ts && msg.ts >= timeCutoff)
|
||||||
|
if (messageIndex !== -1) {
|
||||||
|
const { historyItem } = await this.getTaskWithId(this.cline.taskId)
|
||||||
|
await this.cline.overwriteClineMessages(this.cline.clineMessages.slice(0, messageIndex))
|
||||||
|
if (apiConversationHistoryIndex !== -1) {
|
||||||
|
await this.cline.overwriteApiConversationHistory(this.cline.apiConversationHistory.slice(0, apiConversationHistoryIndex))
|
||||||
|
}
|
||||||
|
await this.initClineWithHistoryItem(historyItem)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
case "screenshotQuality":
|
case "screenshotQuality":
|
||||||
await this.updateGlobalState("screenshotQuality", message.value)
|
await this.updateGlobalState("screenshotQuality", message.value)
|
||||||
await this.postStateToWebview()
|
await this.postStateToWebview()
|
||||||
|
|||||||
@@ -47,6 +47,7 @@ export interface WebviewMessage {
|
|||||||
| "enhancePrompt"
|
| "enhancePrompt"
|
||||||
| "enhancedPrompt"
|
| "enhancedPrompt"
|
||||||
| "draggedImages"
|
| "draggedImages"
|
||||||
|
| "deleteMessage"
|
||||||
text?: string
|
text?: string
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
askResponse?: ClineAskResponse
|
askResponse?: ClineAskResponse
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ interface BrowserSessionRowProps {
|
|||||||
lastModifiedMessage?: ClineMessage
|
lastModifiedMessage?: ClineMessage
|
||||||
isLast: boolean
|
isLast: boolean
|
||||||
onHeightChange: (isTaller: boolean) => void
|
onHeightChange: (isTaller: boolean) => void
|
||||||
|
isStreaming: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
|
const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
|
||||||
@@ -408,6 +409,7 @@ const BrowserSessionRow = memo((props: BrowserSessionRowProps) => {
|
|||||||
interface BrowserSessionRowContentProps extends Omit<BrowserSessionRowProps, "messages"> {
|
interface BrowserSessionRowContentProps extends Omit<BrowserSessionRowProps, "messages"> {
|
||||||
message: ClineMessage
|
message: ClineMessage
|
||||||
setMaxActionHeight: (height: number) => void
|
setMaxActionHeight: (height: number) => void
|
||||||
|
isStreaming: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const BrowserSessionRowContent = ({
|
const BrowserSessionRowContent = ({
|
||||||
@@ -417,6 +419,7 @@ const BrowserSessionRowContent = ({
|
|||||||
lastModifiedMessage,
|
lastModifiedMessage,
|
||||||
isLast,
|
isLast,
|
||||||
setMaxActionHeight,
|
setMaxActionHeight,
|
||||||
|
isStreaming,
|
||||||
}: BrowserSessionRowContentProps) => {
|
}: BrowserSessionRowContentProps) => {
|
||||||
const headerStyle: React.CSSProperties = {
|
const headerStyle: React.CSSProperties = {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
@@ -443,6 +446,7 @@ const BrowserSessionRowContent = ({
|
|||||||
}}
|
}}
|
||||||
lastModifiedMessage={lastModifiedMessage}
|
lastModifiedMessage={lastModifiedMessage}
|
||||||
isLast={isLast}
|
isLast={isLast}
|
||||||
|
isStreaming={isStreaming}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { VSCodeBadge, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
|
import { VSCodeBadge, VSCodeButton, VSCodeProgressRing } from "@vscode/webview-ui-toolkit/react"
|
||||||
import deepEqual from "fast-deep-equal"
|
import deepEqual from "fast-deep-equal"
|
||||||
import React, { memo, useEffect, useMemo, useRef } from "react"
|
import React, { memo, useEffect, useMemo, useRef } from "react"
|
||||||
import { useSize } from "react-use"
|
import { useSize } from "react-use"
|
||||||
@@ -27,6 +27,7 @@ interface ChatRowProps {
|
|||||||
lastModifiedMessage?: ClineMessage
|
lastModifiedMessage?: ClineMessage
|
||||||
isLast: boolean
|
isLast: boolean
|
||||||
onHeightChange: (isTaller: boolean) => void
|
onHeightChange: (isTaller: boolean) => void
|
||||||
|
isStreaming: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ChatRowContentProps extends Omit<ChatRowProps, "onHeightChange"> {}
|
interface ChatRowContentProps extends Omit<ChatRowProps, "onHeightChange"> {}
|
||||||
@@ -75,6 +76,7 @@ export const ChatRowContent = ({
|
|||||||
onToggleExpand,
|
onToggleExpand,
|
||||||
lastModifiedMessage,
|
lastModifiedMessage,
|
||||||
isLast,
|
isLast,
|
||||||
|
isStreaming,
|
||||||
}: ChatRowContentProps) => {
|
}: ChatRowContentProps) => {
|
||||||
const { mcpServers } = useExtensionState()
|
const { mcpServers } = useExtensionState()
|
||||||
const [cost, apiReqCancelReason, apiReqStreamingFailedMessage] = useMemo(() => {
|
const [cost, apiReqCancelReason, apiReqStreamingFailedMessage] = useMemo(() => {
|
||||||
@@ -475,10 +477,9 @@ export const ChatRowContent = ({
|
|||||||
msUserSelect: "none",
|
msUserSelect: "none",
|
||||||
}}
|
}}
|
||||||
onClick={onToggleExpand}>
|
onClick={onToggleExpand}>
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: "10px" }}>
|
<div style={{ display: "flex", alignItems: "center", gap: "10px", flexGrow: 1 }}>
|
||||||
{icon}
|
{icon}
|
||||||
{title}
|
{title}
|
||||||
{/* Need to render this everytime since it affects height of row by 2px */}
|
|
||||||
<VSCodeBadge style={{ opacity: cost != null && cost > 0 ? 1 : 0 }}>
|
<VSCodeBadge style={{ opacity: cost != null && cost > 0 ? 1 : 0 }}>
|
||||||
${Number(cost || 0)?.toFixed(4)}
|
${Number(cost || 0)?.toFixed(4)}
|
||||||
</VSCodeBadge>
|
</VSCodeBadge>
|
||||||
@@ -570,7 +571,29 @@ export const ChatRowContent = ({
|
|||||||
whiteSpace: "pre-line",
|
whiteSpace: "pre-line",
|
||||||
wordWrap: "break-word",
|
wordWrap: "break-word",
|
||||||
}}>
|
}}>
|
||||||
<span style={{ display: "block" }}>{highlightMentions(message.text)}</span>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: "10px" }}>
|
||||||
|
<span style={{ display: "block", flexGrow: 1 }}>{highlightMentions(message.text)}</span>
|
||||||
|
<VSCodeButton
|
||||||
|
appearance="icon"
|
||||||
|
style={{
|
||||||
|
padding: "3px",
|
||||||
|
flexShrink: 0,
|
||||||
|
height: "24px",
|
||||||
|
marginTop: "-6px",
|
||||||
|
marginRight: "-6px"
|
||||||
|
}}
|
||||||
|
disabled={isStreaming}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
vscode.postMessage({
|
||||||
|
type: "deleteMessage",
|
||||||
|
value: message.ts
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span className="codicon codicon-trash"></span>
|
||||||
|
</VSCodeButton>
|
||||||
|
</div>
|
||||||
{message.images && message.images.length > 0 && (
|
{message.images && message.images.length > 0 && (
|
||||||
<Thumbnails images={message.images} style={{ marginTop: "8px" }} />
|
<Thumbnails images={message.images} style={{ marginTop: "8px" }} />
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -787,6 +787,7 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
isLast={index === groupedMessages.length - 1}
|
isLast={index === groupedMessages.length - 1}
|
||||||
lastModifiedMessage={modifiedMessages.at(-1)}
|
lastModifiedMessage={modifiedMessages.at(-1)}
|
||||||
onHeightChange={handleRowHeightChange}
|
onHeightChange={handleRowHeightChange}
|
||||||
|
isStreaming={isStreaming}
|
||||||
// Pass handlers for each message in the group
|
// Pass handlers for each message in the group
|
||||||
isExpanded={(messageTs: number) => expandedRows[messageTs] ?? false}
|
isExpanded={(messageTs: number) => expandedRows[messageTs] ?? false}
|
||||||
onToggleExpand={(messageTs: number) => {
|
onToggleExpand={(messageTs: number) => {
|
||||||
@@ -809,10 +810,11 @@ const ChatView = ({ isHidden, showAnnouncement, hideAnnouncement, showHistoryVie
|
|||||||
lastModifiedMessage={modifiedMessages.at(-1)}
|
lastModifiedMessage={modifiedMessages.at(-1)}
|
||||||
isLast={index === groupedMessages.length - 1}
|
isLast={index === groupedMessages.length - 1}
|
||||||
onHeightChange={handleRowHeightChange}
|
onHeightChange={handleRowHeightChange}
|
||||||
|
isStreaming={isStreaming}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
[expandedRows, modifiedMessages, groupedMessages.length, toggleRowExpansion, handleRowHeightChange],
|
[expandedRows, modifiedMessages, groupedMessages.length, handleRowHeightChange, isStreaming, toggleRowExpansion],
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
Reference in New Issue
Block a user