Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/kilo-ui/src/components/message-part.css
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] {
font-size: var(--font-size-small);
color: var(--text-weak);
user-select: none;
display: flex;
align-items: center;
justify-content: flex-end;
gap: 4px;
}
}

Expand Down
10 changes: 10 additions & 0 deletions packages/kilo-ui/src/components/message-part.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,7 @@ export function UserMessageDisplay(props: {
interrupted?: boolean
animate?: boolean
queued?: boolean
onDeleteQueued?: () => void
onRevert?: () => void
}) {
const data = useData()
Expand Down Expand Up @@ -823,6 +824,15 @@ export function UserMessageDisplay(props: {
<GrowBox animate={!!props.animate} open={!!props.queued}>
<div data-slot="user-message-queued-indicator">
<TextShimmer text={i18n.t("ui.message.queued")} />
<Show when={props.onDeleteQueued}>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Attachment-only queued messages never show the delete action

This button is rendered inside the surrounding Show when={text()} block. PromptInput allows sending prompts with only image/PDF attachments, so those queued messages will never render the queued indicator or delete control and cannot be removed with this feature.

<IconButton
icon="trash"
label={i18n.t("ui.message.deleteQueued")}
size="xs"
variant="ghost"
onClick={props.onDeleteQueued}
/>
</Show>
</div>
</GrowBox>
</div>
Expand Down
22 changes: 22 additions & 0 deletions packages/kilo-vscode/src/KiloProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
case "deleteSession":
await this.handleDeleteSession(message.sessionID)
break
case "deleteMessage":
await this.handleDeleteMessage(message.sessionID, message.messageID)
break
case "renameSession":
await this.handleRenameSession(message.sessionID, message.title)
break
Expand Down Expand Up @@ -1501,6 +1504,25 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}

private async handleDeleteMessage(sessionID: string, messageID: string): Promise<void> {
if (!this.client) {
this.postMessage({ type: "error", message: "Not connected to CLI backend" })
return
}

try {
const dir = this.getWorkspaceDirectory(sessionID)
await this.client.session.deleteMessage({ sessionID, messageID, directory: dir }, { throwOnError: true })
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to delete message:", error)
this.postMessage({
type: "error",
message: getErrorMessage(error) || "Failed to delete message",
sessionID,
})
}
}

/**
* Handle renaming a session.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ export const MessageList: Component<MessageListProps> = (props) => {
sessionID={session.currentSessionID() ?? ""}
messageID={msg.id}
queued={queued()}
onDeleteQueued={
queued() ? () => session.deleteMessage(session.currentSessionID() ?? "", msg.id) : undefined
}
/>
)
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ interface VscodeSessionTurnProps {
sessionID: string
messageID: string
queued?: boolean
onDeleteQueued?: () => void
}

export const VscodeSessionTurn: Component<VscodeSessionTurnProps> = (props) => {
Expand Down Expand Up @@ -169,6 +170,7 @@ export const VscodeSessionTurn: Component<VscodeSessionTurnProps> = (props) => {
parts={parts() as unknown as Parameters<typeof UserMessageDisplay>[0]["parts"]}
interrupted={interrupted()}
queued={props.queued}
onDeleteQueued={props.onDeleteQueued}
onRevert={
assistantMessages().length > 0 && !session.revert()
? () => {
Expand Down
11 changes: 11 additions & 0 deletions packages/kilo-vscode/webview-ui/src/context/session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ interface SessionContextValue {
loadSessions: () => void
selectSession: (id: string) => void
deleteSession: (id: string) => void
deleteMessage: (sessionID: string, messageID: string) => void
renameSession: (id: string, title: string) => void
syncSession: (sessionID: string) => void

Expand Down Expand Up @@ -1643,6 +1644,15 @@ export const SessionProvider: ParentComponent = (props) => {
vscode.postMessage({ type: "deleteSession", sessionID: id })
}

function deleteMessage(sessionID: string, messageID: string) {
if (!server.isConnected()) {
console.warn("[Kilo New] Cannot delete message: not connected")
return
}
handleMessageRemoved(sessionID, messageID)
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL: Queued deletes cannot succeed while the session is busy

onDeleteQueued is only exposed for queued prompts, which only exist while another turn is still running. The server-side delete route calls SessionPrompt.assertNotBusy(), so this request is rejected every time the button is shown. Because the message is removed optimistically before the request returns, the UI looks successful until the session reloads. This needs either a queue-aware backend delete path or a rollback instead of unconditional local removal.

vscode.postMessage({ type: "deleteMessage", sessionID, messageID })
}

function renameSession(id: string, title: string) {
if (!server.isConnected()) {
console.warn("[Kilo New] Cannot rename session: not connected")
Expand Down Expand Up @@ -1878,6 +1888,7 @@ export const SessionProvider: ParentComponent = (props) => {
loadSessions,
selectSession,
deleteSession,
deleteMessage,
renameSession,
syncSession,
cloudPreviewId,
Expand Down
7 changes: 7 additions & 0 deletions packages/kilo-vscode/webview-ui/src/types/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1753,6 +1753,12 @@ export interface DeleteSessionRequest {
sessionID: string
}

export interface DeleteMessageRequest {
type: "deleteMessage"
sessionID: string
messageID: string
}

export interface RenameSessionRequest {
type: "renameSession"
sessionID: string
Expand Down Expand Up @@ -2364,6 +2370,7 @@ export type WebviewMessage =
| QuestionReplyRequest
| QuestionRejectRequest
| DeleteSessionRequest
| DeleteMessageRequest
| RenameSessionRequest
| RequestAutocompleteSettingsMessage
| UpdateAutocompleteSettingMessage
Expand Down
1 change: 1 addition & 0 deletions packages/ui/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export const dict: Record<string, string> = {
"ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s",
"ui.message.interrupted": "Interrupted",
"ui.message.queued": "Queued",
"ui.message.deleteQueued": "Remove queued message",
"ui.message.attachment.alt": "attachment",

"ui.patch.action.deleted": "Deleted",
Expand Down
Loading