@@ -1556,6 +1556,7 @@ const Composer: FC<{
15561556 const draftThreadId = referenceThreadId ;
15571557 const draftKey = draftThreadId ? composerDraftKey ( draftThreadId ) : null ;
15581558 const lastDraftKeyRef = useRef ( draftKey ) ;
1559+ const draftSaveTimerRef = useRef < ReturnType < typeof setTimeout > | null > ( null ) ;
15591560 useEffect ( ( ) => {
15601561 const draft = draftKey ? ( readComposerDraft ( draftKey ) ?? "" ) : "" ;
15611562 const composer = aui . composer ( ) ;
@@ -1574,8 +1575,25 @@ const Composer: FC<{
15741575 return ;
15751576 }
15761577 const t = setTimeout ( ( ) => writeComposerDraft ( draftKey , composerText ) , 300 ) ;
1578+ draftSaveTimerRef . current = t ;
15771579 return ( ) => clearTimeout ( t ) ;
15781580 } , [ composerText , draftKey ] ) ;
1581+ // Without this the restore effect above puts the sent text back when the
1582+ // runtime rebinds on the first message.
1583+ const draftKeyRef = useRef ( draftKey ) ;
1584+ useEffect ( ( ) => {
1585+ draftKeyRef . current = draftKey ;
1586+ } , [ draftKey ] ) ;
1587+ const clearStoredDraft = useCallback ( ( ) => {
1588+ if ( draftSaveTimerRef . current !== null ) {
1589+ clearTimeout ( draftSaveTimerRef . current ) ;
1590+ draftSaveTimerRef . current = null ;
1591+ }
1592+ const key = draftKeyRef . current ;
1593+ if ( key ) {
1594+ writeComposerDraft ( key , "" ) ;
1595+ }
1596+ } , [ ] ) ;
15791597 // react-textarea-autosize re-measures only on value change or window resize,
15801598 // not on the width swap from expanding, so it keeps the taller height and
15811599 // leaves a stray blank row. Nudge a resize whenever input width changes.
@@ -1726,9 +1744,10 @@ const Composer: FC<{
17261744 setPendingSend ( false ) ;
17271745 dismissWaitToast ( ) ;
17281746 if ( text . trim ( ) . length > 0 || attachments . length > 0 ) {
1747+ clearStoredDraft ( ) ;
17291748 aui . composer ( ) . send ( ) ;
17301749 }
1731- } , [ pendingSend , indexingActive , aui , dismissWaitToast ] ) ;
1750+ } , [ pendingSend , indexingActive , aui , clearStoredDraft , dismissWaitToast ] ) ;
17321751
17331752 // Drop any queued send + toast on unmount (e.g. thread switch).
17341753 useEffect (
@@ -1771,6 +1790,7 @@ const Composer: FC<{
17711790 flushResourcesSync ( ( ) => {
17721791 aui . composer ( ) . setText ( "" ) ;
17731792 } ) ;
1793+ clearStoredDraft ( ) ;
17741794 startPromptQueue (
17751795 [ queuedPrompt ] ,
17761796 createPromptQueueTarget ( ) ,
@@ -1804,6 +1824,7 @@ const Composer: FC<{
18041824 closeOverlay ( ) ;
18051825 return ;
18061826 }
1827+ clearStoredDraft ( ) ;
18071828 setImageToolsEnabled ( true ) ;
18081829 setPendingImageEditReference ( {
18091830 threadId : overlay . threadId ?? referenceThreadId ,
@@ -1821,11 +1842,15 @@ const Composer: FC<{
18211842 ) ;
18221843 } ) ;
18231844 closeOverlay ( ) ;
1845+ return ;
18241846 }
1847+
1848+ clearStoredDraft ( ) ;
18251849 } ,
18261850 [
18271851 aui ,
18281852 canQueueCurrentPrompt ,
1853+ clearStoredDraft ,
18291854 closeOverlay ,
18301855 composerText ,
18311856 createPromptQueueTarget ,
@@ -1947,6 +1972,7 @@ const Composer: FC<{
19471972 flushResourcesSync ( ( ) => {
19481973 aui . composer ( ) . setText ( "" ) ;
19491974 } ) ;
1975+ clearStoredDraft ( ) ;
19501976 startPromptQueue ( [ queuedPrompt ] , createPromptQueueTarget ( ) , true ) ;
19511977 } }
19521978 onSendClick = { interceptSend }
0 commit comments