diff --git a/apps/web/src/components/ChatView.tsx b/apps/web/src/components/ChatView.tsx index 9ef221e262..b6751bcb2d 100644 --- a/apps/web/src/components/ChatView.tsx +++ b/apps/web/src/components/ChatView.tsx @@ -134,6 +134,7 @@ import { } from "../composerDraftStore"; import { appendTerminalContextsToPrompt, + deriveDisplayedUserMessageState, formatTerminalContextLabel, type TerminalContextDraft, type TerminalContextSelection, @@ -3490,6 +3491,29 @@ export default function ChatView(props: ChatViewProps) { void onRevertToTurnCountRef.current(targetTurnCount); }, []); + const onEditUserMessage = useCallback( + async (messageId: MessageId, text: string) => { + const targetTurnCount = revertTurnCountRef.current.get(messageId); + if (typeof targetTurnCount !== "number") { + return; + } + + const displayedMessage = deriveDisplayedUserMessageState(text); + const draftText = displayedMessage.visibleText || text; + clearComposerDraftContent(composerDraftTarget); + setComposerDraftPrompt(composerDraftTarget, draftText); + promptRef.current = draftText; + composerRef.current?.resetCursorState({ + cursor: draftText.length, + prompt: draftText, + detectTrigger: true, + }); + composerRef.current?.focusAtEnd(); + await onRevertToTurnCountRef.current(targetTurnCount); + }, + [clearComposerDraftContent, composerDraftTarget, composerRef, setComposerDraftPrompt], + ); + // Empty state: no active thread if (!activeThread) { return ; @@ -3568,6 +3592,7 @@ export default function ChatView(props: ChatViewProps) { onOpenTurnDiff={onOpenTurnDiff} revertTurnCountByUserMessageId={revertTurnCountByUserMessageId} onRevertUserMessage={onRevertUserMessage} + onEditUserMessage={onEditUserMessage} isRevertingCheckpoint={isRevertingCheckpoint} onImageExpand={onExpandTimelineImage} markdownCwd={gitCwd ?? undefined} diff --git a/apps/web/src/components/chat/MessagesTimeline.browser.tsx b/apps/web/src/components/chat/MessagesTimeline.browser.tsx index 0eb5c8a1fc..efd52aa604 100644 --- a/apps/web/src/components/chat/MessagesTimeline.browser.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.browser.tsx @@ -62,6 +62,7 @@ function buildProps() { onOpenTurnDiff: vi.fn(), revertTurnCountByUserMessageId: new Map(), onRevertUserMessage: vi.fn(), + onEditUserMessage: vi.fn(), isRevertingCheckpoint: false, onImageExpand: vi.fn(), activeThreadEnvironmentId: EnvironmentId.make("environment-local"), diff --git a/apps/web/src/components/chat/MessagesTimeline.test.tsx b/apps/web/src/components/chat/MessagesTimeline.test.tsx index a8a53831a2..45c3f6cf12 100644 --- a/apps/web/src/components/chat/MessagesTimeline.test.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.test.tsx @@ -88,6 +88,7 @@ function buildProps() { onOpenTurnDiff: () => {}, revertTurnCountByUserMessageId: new Map(), onRevertUserMessage: () => {}, + onEditUserMessage: () => {}, isRevertingCheckpoint: false, onImageExpand: () => {}, activeThreadEnvironmentId: ACTIVE_THREAD_ENVIRONMENT_ID, diff --git a/apps/web/src/components/chat/MessagesTimeline.tsx b/apps/web/src/components/chat/MessagesTimeline.tsx index e4b683592e..314ebdd3b4 100644 --- a/apps/web/src/components/chat/MessagesTimeline.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.tsx @@ -82,6 +82,7 @@ interface TimelineRowSharedState { workspaceRoot: string | undefined; activeThreadEnvironmentId: EnvironmentId; onRevertUserMessage: (messageId: MessageId) => void; + onEditUserMessage: (messageId: MessageId, text: string) => void; onImageExpand: (preview: ExpandedImagePreview) => void; onOpenTurnDiff: (turnId: TurnId, filePath?: string) => void; } @@ -106,6 +107,7 @@ interface MessagesTimelineProps { onOpenTurnDiff: (turnId: TurnId, filePath?: string) => void; revertTurnCountByUserMessageId: Map; onRevertUserMessage: (messageId: MessageId) => void; + onEditUserMessage: (messageId: MessageId, text: string) => void; isRevertingCheckpoint: boolean; onImageExpand: (preview: ExpandedImagePreview) => void; activeThreadEnvironmentId: EnvironmentId; @@ -134,6 +136,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ onOpenTurnDiff, revertTurnCountByUserMessageId, onRevertUserMessage, + onEditUserMessage, isRevertingCheckpoint, onImageExpand, activeThreadEnvironmentId, @@ -205,6 +208,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ workspaceRoot, activeThreadEnvironmentId, onRevertUserMessage, + onEditUserMessage, onImageExpand, onOpenTurnDiff, }), @@ -221,6 +225,7 @@ export const MessagesTimeline = memo(function MessagesTimeline({ workspaceRoot, activeThreadEnvironmentId, onRevertUserMessage, + onEditUserMessage, onImageExpand, onOpenTurnDiff, ], @@ -355,16 +360,28 @@ function TimelineRowContent({ row }: { row: TimelineRow }) { )} {canRevertAgentWork && ( - + <> + + + )}