diff --git a/src/App.stories.tsx b/src/App.stories.tsx index bcae352a3..5651766e6 100644 --- a/src/App.stories.tsx +++ b/src/App.stories.tsx @@ -65,6 +65,7 @@ function setupMockAPI(options: { sendMessage: () => Promise.resolve({ success: true, data: undefined }), resumeStream: () => Promise.resolve({ success: true, data: undefined }), interruptStream: () => Promise.resolve({ success: true, data: undefined }), + clearQueue: () => Promise.resolve({ success: true, data: undefined }), truncateHistory: () => Promise.resolve({ success: true, data: undefined }), replaceChatHistory: () => Promise.resolve({ success: true, data: undefined }), getInfo: () => Promise.resolve(null), @@ -655,6 +656,7 @@ export const ActiveWorkspaceWithChat: Story = { sendMessage: () => Promise.resolve({ success: true, data: undefined }), resumeStream: () => Promise.resolve({ success: true, data: undefined }), interruptStream: () => Promise.resolve({ success: true, data: undefined }), + clearQueue: () => Promise.resolve({ success: true, data: undefined }), truncateHistory: () => Promise.resolve({ success: true, data: undefined }), replaceChatHistory: () => Promise.resolve({ success: true, data: undefined }), getInfo: () => Promise.resolve(null), @@ -851,6 +853,7 @@ These tables should render cleanly without any disruptive copy or download actio sendMessage: () => Promise.resolve({ success: true, data: undefined }), resumeStream: () => Promise.resolve({ success: true, data: undefined }), interruptStream: () => Promise.resolve({ success: true, data: undefined }), + clearQueue: () => Promise.resolve({ success: true, data: undefined }), truncateHistory: () => Promise.resolve({ success: true, data: undefined }), replaceChatHistory: () => Promise.resolve({ success: true, data: undefined }), getInfo: () => Promise.resolve(null), diff --git a/src/browser/api.ts b/src/browser/api.ts index b1f6d637c..c350364d9 100644 --- a/src/browser/api.ts +++ b/src/browser/api.ts @@ -225,6 +225,7 @@ const webApi: IPCApi = { invokeIPC(IPC_CHANNELS.WORKSPACE_RESUME_STREAM, workspaceId, options), interruptStream: (workspaceId, options) => invokeIPC(IPC_CHANNELS.WORKSPACE_INTERRUPT_STREAM, workspaceId, options), + clearQueue: (workspaceId) => invokeIPC(IPC_CHANNELS.WORKSPACE_QUEUE_CLEAR, workspaceId), truncateHistory: (workspaceId, percentage) => invokeIPC(IPC_CHANNELS.WORKSPACE_TRUNCATE_HISTORY, workspaceId, percentage), replaceChatHistory: (workspaceId, summaryMessage) => diff --git a/src/components/AIView.tsx b/src/components/AIView.tsx index c0740836b..4add113d3 100644 --- a/src/components/AIView.tsx +++ b/src/components/AIView.tsx @@ -4,6 +4,7 @@ import { MessageRenderer } from "./Messages/MessageRenderer"; import { InterruptedBarrier } from "./Messages/ChatBarrier/InterruptedBarrier"; import { StreamingBarrier } from "./Messages/ChatBarrier/StreamingBarrier"; import { RetryBarrier } from "./Messages/ChatBarrier/RetryBarrier"; +import { QueuedMessage } from "./Messages/QueuedMessage"; import { PinnedTodoList } from "./PinnedTodoList"; import { getAutoRetryKey, VIM_ENABLED_KEY } from "@/constants/storage"; import { ChatInput, type ChatInputAPI } from "./ChatInput/index"; @@ -113,8 +114,28 @@ const AIViewInner: React.FC = ({ setEditingMessage({ id: messageId, content }); }, []); - const handleEditLastUserMessage = useCallback(() => { + const handleEditQueuedMessage = useCallback(async () => { + const queuedMessage = workspaceState?.queuedMessage; + if (!queuedMessage) return; + + await window.api.workspace.clearQueue(workspaceId); + chatInputAPI.current?.restoreText(queuedMessage.content); + + // Restore images if present + if (queuedMessage.imageParts && queuedMessage.imageParts.length > 0) { + chatInputAPI.current?.restoreImages(queuedMessage.imageParts); + } + }, [workspaceId, workspaceState?.queuedMessage, chatInputAPI]); + + const handleEditLastUserMessage = useCallback(async () => { if (!workspaceState) return; + + if (workspaceState.queuedMessage) { + await handleEditQueuedMessage(); + return; + } + + // Otherwise, edit last user message const mergedMessages = mergeConsecutiveStreamErrors(workspaceState.messages); const lastUserMessage = [...mergedMessages] .reverse() @@ -131,7 +152,7 @@ const AIViewInner: React.FC = ({ element?.scrollIntoView({ behavior: "smooth", block: "center" }); }); } - }, [workspaceState, contentRef, setAutoScroll]); + }, [workspaceState, contentRef, setAutoScroll, handleEditQueuedMessage]); const handleCancelEdit = useCallback(() => { setEditingMessage(undefined); @@ -435,6 +456,12 @@ const AIViewInner: React.FC = ({ } /> )} + {workspaceState?.queuedMessage && ( + void handleEditQueuedMessage()} + /> + )} {!autoScroll && (