@@ -85,15 +85,18 @@ export function createComposerSubmit(input: ComposerSubmitInput) {
8585 }
8686 if ( submitting . has ( input . adapter . state ) ) return
8787 // Images restored from a draft or history carry ids only; the optimistic message shows their URLs.
88- const value = {
89- ...read ,
90- images : await Promise . all (
91- read . images . map ( async ( image ) => ( {
92- ...image ,
93- blob : { ...image . blob , url : ( await resolveBlobUrl ( image . blob ) ) ?? image . blob . url } ,
94- } ) ) ,
95- ) ,
96- }
88+ const value =
89+ read . images . length === 0
90+ ? read
91+ : {
92+ ...read ,
93+ images : await Promise . all (
94+ read . images . map ( async ( image ) => ( {
95+ ...image ,
96+ blob : { ...image . blob , url : ( await resolveBlobUrl ( image . blob ) ) ?? image . blob . url } ,
97+ } ) ) ,
98+ ) ,
99+ }
97100 submitting . add ( input . adapter . state )
98101 const comments = input . comments . capture ( )
99102 // Capture command intent before starting a session in a worktree whose catalog has not loaded.
@@ -116,6 +119,7 @@ export function createComposerSubmit(input: ComposerSubmitInput) {
116119 const optimisticBusy = ! input . adapter . working ( )
117120 if ( optimisticBusy && input . adapter . kind === "new-session" )
118121 session . data . session . setStatus ( session . id , "running" )
122+ // Reserve before any await so a later revert or prompt cannot overtake this admission.
119123 const sending = sendPrompt ( session , value , input . adapter . controls ( ) . model . selection . trackSessionCommit , ( ) => {
120124 if ( optimisticBusy && input . adapter . kind === "active-session" )
121125 session . data . session . setStatus ( session . id , "running" )
@@ -374,44 +378,46 @@ async function applySelection(
374378 }
375379}
376380
377- async function sendPrompt (
381+ function sendPrompt (
378382 session : ComposerSession ,
379383 value : ComposerSubmission ,
380384 track : ModelSelection [ "trackSessionCommit" ] | undefined ,
381385 onAdmit : ( ) => void ,
382386) {
383- const request = await buildSubmissionRequest ( session , value )
384- // Switching agent or model reconfigures the session immediately, and with it
385- // the remainder of a running turn. A steer targets that turn, so its
386- // selection applies now; a queued follow-up must not reconfigure the turn it
387- // waits behind, so it runs with the session selection at delivery time (the
388- // intended selection stays recorded in its metadata).
389- if ( value . delivery === "steer" ) {
390- await applySelection ( session , value . selection , track )
391- }
387+ return session . data . session . mutate ( session . id , async ( mutation ) => {
388+ const request = await buildSubmissionRequest ( session , value )
389+ // Switching agent or model reconfigures the session immediately, and with it
390+ // the remainder of a running turn. A steer targets that turn, so its
391+ // selection applies now; a queued follow-up must not reconfigure the turn it
392+ // waits behind, so it runs with the session selection at delivery time (the
393+ // intended selection stays recorded in its metadata).
394+ if ( value . delivery === "steer" ) {
395+ await applySelection ( session , value . selection , track )
396+ }
392397
393- const admission = {
394- id : value . id ,
395- sessionID : session . id ,
396- delivery : value . delivery ,
397- text : request . text ,
398- files : request . files . map ( ( file ) => ( { uri : file . uri , name : file . name , mention : file . mention } ) ) ,
399- agents : request . agents ,
400- skills : request . skills ,
401- metadata : {
402- displayText : request . displayText ,
403- comments : request . comments ,
404- attachments : request . attachments ,
405- agent : value . selection . agent ,
406- model : {
407- ...value . selection . model ,
408- ...( value . selection . variant ? { variant : value . selection . variant } : { } ) ,
398+ const admission = {
399+ id : value . id ,
400+ sessionID : session . id ,
401+ delivery : value . delivery ,
402+ text : request . text ,
403+ files : request . files . map ( ( file ) => ( { uri : file . uri , name : file . name , mention : file . mention } ) ) ,
404+ agents : request . agents ,
405+ skills : request . skills ,
406+ metadata : {
407+ displayText : request . displayText ,
408+ comments : request . comments ,
409+ attachments : request . attachments ,
410+ agent : value . selection . agent ,
411+ model : {
412+ ...value . selection . model ,
413+ ...( value . selection . variant ? { variant : value . selection . variant } : { } ) ,
414+ } ,
409415 } ,
410- } ,
411- }
412- const sending = session . data . session . prompt ( admission ) . catch ( ( ) => session . data . session . prompt ( admission ) )
413- onAdmit ( )
414- await sending
416+ }
417+ const sending = mutation . prompt ( admission )
418+ onAdmit ( )
419+ await sending
420+ } )
415421}
416422
417423async function buildSubmissionRequest ( session : ComposerSession , value : ComposerSubmission ) {
0 commit comments