diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css index b4a7c60c159..db273be3cb2 100644 --- a/packages/kilo-ui/src/components/message-part.css +++ b/packages/kilo-ui/src/components/message-part.css @@ -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; } } diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx index 41388c8622a..3264fccd8e6 100644 --- a/packages/kilo-ui/src/components/message-part.tsx +++ b/packages/kilo-ui/src/components/message-part.tsx @@ -706,6 +706,7 @@ export function UserMessageDisplay(props: { interrupted?: boolean animate?: boolean queued?: boolean + onDeleteQueued?: () => void onRevert?: () => void }) { const data = useData() @@ -823,10 +824,38 @@ export function UserMessageDisplay(props: {
+ + +
- + + + + +
+ + + + +
+
+
+ + <>
diff --git a/packages/kilo-vscode/src/KiloProvider.ts b/packages/kilo-vscode/src/KiloProvider.ts index 0db78a29768..610db43944d 100644 --- a/packages/kilo-vscode/src/KiloProvider.ts +++ b/packages/kilo-vscode/src/KiloProvider.ts @@ -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 @@ -1501,6 +1504,25 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper } } + private async handleDeleteMessage(sessionID: string, messageID: string): Promise { + 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. */ diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx index 6e1e6549dc8..59ab41f665c 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx @@ -157,6 +157,9 @@ export const MessageList: Component = (props) => { sessionID={session.currentSessionID() ?? ""} messageID={msg.id} queued={queued()} + onDeleteQueued={ + queued() ? () => session.deleteMessage(session.currentSessionID() ?? "", msg.id) : undefined + } /> ) }} diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx index 4cb75cf03e1..d0115baa535 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/VscodeSessionTurn.tsx @@ -48,6 +48,7 @@ interface VscodeSessionTurnProps { sessionID: string messageID: string queued?: boolean + onDeleteQueued?: () => void } export const VscodeSessionTurn: Component = (props) => { @@ -169,6 +170,7 @@ export const VscodeSessionTurn: Component = (props) => { parts={parts() as unknown as Parameters[0]["parts"]} interrupted={interrupted()} queued={props.queued} + onDeleteQueued={props.onDeleteQueued} onRevert={ assistantMessages().length > 0 && !session.revert() ? () => { diff --git a/packages/kilo-vscode/webview-ui/src/context/session.tsx b/packages/kilo-vscode/webview-ui/src/context/session.tsx index 9c1430532f4..acbbc35d7d3 100644 --- a/packages/kilo-vscode/webview-ui/src/context/session.tsx +++ b/packages/kilo-vscode/webview-ui/src/context/session.tsx @@ -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 @@ -1643,6 +1644,14 @@ 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 + } + vscode.postMessage({ type: "deleteMessage", sessionID, messageID }) + } + function renameSession(id: string, title: string) { if (!server.isConnected()) { console.warn("[Kilo New] Cannot rename session: not connected") @@ -1878,6 +1887,7 @@ export const SessionProvider: ParentComponent = (props) => { loadSessions, selectSession, deleteSession, + deleteMessage, renameSession, syncSession, cloudPreviewId, diff --git a/packages/kilo-vscode/webview-ui/src/types/messages.ts b/packages/kilo-vscode/webview-ui/src/types/messages.ts index 68429da62c7..dc080b6bcad 100644 --- a/packages/kilo-vscode/webview-ui/src/types/messages.ts +++ b/packages/kilo-vscode/webview-ui/src/types/messages.ts @@ -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 @@ -2364,6 +2370,7 @@ export type WebviewMessage = | QuestionReplyRequest | QuestionRejectRequest | DeleteSessionRequest + | DeleteMessageRequest | RenameSessionRequest | RequestAutocompleteSettingsMessage | UpdateAutocompleteSettingMessage diff --git a/packages/opencode/src/server/routes/session.ts b/packages/opencode/src/server/routes/session.ts index a1ea14c840d..6c75f0e65a3 100644 --- a/packages/opencode/src/server/routes/session.ts +++ b/packages/opencode/src/server/routes/session.ts @@ -699,7 +699,14 @@ export const SessionRoutes = lazy(() => ), async (c) => { const params = c.req.valid("param") - await SessionPrompt.assertNotBusy(params.sessionID) + // kilocode_change start + const messages = await Session.messages({ sessionID: params.sessionID }) + const user = messages.filter((msg) => msg.info.role === "user") + const target = user.find((msg) => msg.info.id === params.messageID) + const latest = messages.filter((msg) => msg.info.role === "assistant" && msg.info.finish).at(-1) + const current = user.find((msg) => !latest || msg.info.id > latest.info.id) ?? user.at(-1) + if (!target || target.info.id <= (current?.info.id ?? "")) await SessionPrompt.assertNotBusy(params.sessionID) + // kilocode_change end await Session.removeMessage({ sessionID: params.sessionID, messageID: params.messageID, diff --git a/packages/ui/src/i18n/ar.ts b/packages/ui/src/i18n/ar.ts index 3aa568c6e2e..3f8668e3e92 100644 --- a/packages/ui/src/i18n/ar.ts +++ b/packages/ui/src/i18n/ar.ts @@ -135,6 +135,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "تمت المقاطعة", "ui.message.queued": "في الانتظار", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "مرفق", "ui.patch.action.deleted": "محذوف", diff --git a/packages/ui/src/i18n/br.ts b/packages/ui/src/i18n/br.ts index d3474d10190..bfa5619b100 100644 --- a/packages/ui/src/i18n/br.ts +++ b/packages/ui/src/i18n/br.ts @@ -135,6 +135,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrompido", "ui.message.queued": "Na fila", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "anexo", "ui.patch.action.deleted": "Excluído", diff --git a/packages/ui/src/i18n/bs.ts b/packages/ui/src/i18n/bs.ts index 470dd3d8ee1..4ee0f9a51d2 100644 --- a/packages/ui/src/i18n/bs.ts +++ b/packages/ui/src/i18n/bs.ts @@ -139,6 +139,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Prekinuto", "ui.message.queued": "U redu", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "prilog", "ui.patch.action.deleted": "Obrisano", diff --git a/packages/ui/src/i18n/da.ts b/packages/ui/src/i18n/da.ts index c9273a6db73..d97717ee2d5 100644 --- a/packages/ui/src/i18n/da.ts +++ b/packages/ui/src/i18n/da.ts @@ -134,6 +134,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Afbrudt", "ui.message.queued": "I kø", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "vedhæftning", "ui.patch.action.deleted": "Slettet", diff --git a/packages/ui/src/i18n/de.ts b/packages/ui/src/i18n/de.ts index 3c0d6dff7d3..99abb14259c 100644 --- a/packages/ui/src/i18n/de.ts +++ b/packages/ui/src/i18n/de.ts @@ -140,6 +140,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Unterbrochen", "ui.message.queued": "In Warteschlange", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "Anhang", "ui.patch.action.deleted": "Gelöscht", diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts index 8dbc8975134..fef626110a1 100644 --- a/packages/ui/src/i18n/en.ts +++ b/packages/ui/src/i18n/en.ts @@ -148,6 +148,7 @@ export const dict: Record = { "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", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index 5e46a745f28..45008bfe918 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -135,6 +135,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrumpido", "ui.message.queued": "En cola", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "adjunto", "ui.patch.action.deleted": "Eliminado", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index 1b096424c38..bb45af7a3e1 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -135,6 +135,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Interrompu", "ui.message.queued": "En file", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "pièce jointe", "ui.patch.action.deleted": "Supprimé", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index e585a304db9..59931742921 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -134,6 +134,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "中断", "ui.message.queued": "待機中", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "添付ファイル", "ui.patch.action.deleted": "削除済み", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index 0ff97ebbddb..6bcf4f24c71 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -135,6 +135,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "중단됨", "ui.message.queued": "대기 중", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "첨부 파일", "ui.patch.action.deleted": "삭제됨", diff --git a/packages/ui/src/i18n/nl.ts b/packages/ui/src/i18n/nl.ts index 2e41dda2951..64c76242548 100644 --- a/packages/ui/src/i18n/nl.ts +++ b/packages/ui/src/i18n/nl.ts @@ -148,6 +148,7 @@ export const dict: Record = { "ui.message.revert": "Hiernaar terugdraaien", "ui.message.interrupted": "Onderbroken", "ui.message.queued": "In wachtrij", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "bijlage", "ui.message.duration.seconds": "{{count}}s", "ui.message.duration.minutesSeconds": "{{minutes}}m {{seconds}}s", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index 5703b68b3d5..11ab22d06de 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -138,6 +138,7 @@ export const dict: Record = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Avbrutt", "ui.message.queued": "I kø", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "vedlegg", "ui.patch.action.deleted": "Slettet", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index 913f804aed9..1ce5c95d9fb 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -134,6 +134,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Przerwano", "ui.message.queued": "W kolejce", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "załącznik", "ui.patch.action.deleted": "Usunięto", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 8a4dacf7c90..4dd56d7a713 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -134,6 +134,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "Прервано", "ui.message.queued": "В очереди", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "вложение", "ui.patch.action.deleted": "Удалено", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index fa84bdaf269..39d2139bc1f 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -136,6 +136,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "ถูกขัดจังหวะ", "ui.message.queued": "อยู่ในคิว", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "ไฟล์แนบ", "ui.patch.action.deleted": "ลบ", diff --git a/packages/ui/src/i18n/tr.ts b/packages/ui/src/i18n/tr.ts index f82d280caf8..853c5c85fd8 100644 --- a/packages/ui/src/i18n/tr.ts +++ b/packages/ui/src/i18n/tr.ts @@ -141,6 +141,7 @@ export const dict = { "ui.message.copied": "Kopyalandı", "ui.message.interrupted": "Kesildi", "ui.message.queued": "Sırada", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "ek", "ui.patch.action.deleted": "Silindi", diff --git a/packages/ui/src/i18n/uk.ts b/packages/ui/src/i18n/uk.ts index 2ee5c8315f4..ec2d7325249 100644 --- a/packages/ui/src/i18n/uk.ts +++ b/packages/ui/src/i18n/uk.ts @@ -153,6 +153,7 @@ export const dict = { "ui.message.revert": "Повернутися до цього місця", "ui.message.interrupted": "Перервано", "ui.message.queued": "В черзі", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "вкладення", "ui.message.duration.seconds": "{{count}}с", "ui.message.duration.minutesSeconds": "{{minutes}}хв {{seconds}}с", diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index 30441e0b2b8..4e1b25628d9 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -139,6 +139,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "已中断", "ui.message.queued": "排队中", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "附件", "ui.patch.action.deleted": "已删除", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index 6a6f1032bf9..249951498c1 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -139,6 +139,7 @@ export const dict = { "ui.message.revert": "Revert to here", "ui.message.interrupted": "已中斷", "ui.message.queued": "排隊中", + "ui.message.deleteQueued": "Remove queued message", "ui.message.attachment.alt": "附件", "ui.patch.action.deleted": "已刪除",