diff --git a/frontend/src/components/NormalizedConversation/RetryEditorInline.tsx b/frontend/src/components/NormalizedConversation/RetryEditorInline.tsx index 906b9ebe..45e375e5 100644 --- a/frontend/src/components/NormalizedConversation/RetryEditorInline.tsx +++ b/frontend/src/components/NormalizedConversation/RetryEditorInline.tsx @@ -68,6 +68,7 @@ export function RetryEditorInline({ setImages, handleImageUploaded, clearImagesAndUploads, + isMessageLocallyDirty, } = useDraftEditor({ draft, taskId: attempt.task_id, @@ -120,7 +121,7 @@ export function RetryEditorInline({ useEffect(() => { if (!isRetryLoaded || !draft) return; const serverPrompt = draft.prompt || ''; - if (message === '' && serverPrompt !== '') { + if (message === '' && serverPrompt !== '' && !isMessageLocallyDirty()) { setMessage(serverPrompt); if (import.meta.env.DEV) { // One-shot debug to validate hydration ordering in dev @@ -138,6 +139,7 @@ export function RetryEditorInline({ isRetryLoaded, message, setMessage, + isMessageLocallyDirty, ]); const onSend = async () => { diff --git a/frontend/src/hooks/follow-up/useDraftEditor.ts b/frontend/src/hooks/follow-up/useDraftEditor.ts index 1cd22e0b..d5b398e6 100644 --- a/frontend/src/hooks/follow-up/useDraftEditor.ts +++ b/frontend/src/hooks/follow-up/useDraftEditor.ts @@ -20,6 +20,8 @@ export function useDraftEditor({ draft, taskId }: Args) { const localDirtyRef = useRef(false); const imagesDirtyRef = useRef(false); + const isMessageLocallyDirty = useCallback(() => localDirtyRef.current, []); + // Sync message with server when not locally dirty useEffect(() => { if (!draft) return; @@ -84,5 +86,6 @@ export function useDraftEditor({ draft, taskId }: Args) { newlyUploadedImageIds, handleImageUploaded, clearImagesAndUploads, + isMessageLocallyDirty, } as const; }