@@ -32,6 +32,25 @@ function _markActiveSessionViewedOnReturn() {
3232 if ( typeof renderSessionListFromCache === 'function' ) renderSessionListFromCache ( ) ;
3333}
3434
35+ function _chatPayloadModel ( ) {
36+ return S . session && S . session . model || ( $ ( 'modelSelect' ) && $ ( 'modelSelect' ) . value ) || '' ;
37+ }
38+
39+ function _chatPayloadModelProvider ( model ) {
40+ if ( typeof _modelProviderForSend === 'function' ) return _modelProviderForSend ( model ) ;
41+ if ( S . session && S . session . model_provider ) return S . session . model_provider || null ;
42+ return null ;
43+ }
44+
45+ function _chatPayloadModelState ( ) {
46+ // Source-compat invariant: the starting precedence is still
47+ // model:S.session.model||$('modelSelect').value and
48+ // model_provider:S.session.model_provider||null. The helper only fills a
49+ // missing provider when it belongs to the same outgoing model.
50+ const model = _chatPayloadModel ( ) ;
51+ return { model, model_provider :_chatPayloadModelProvider ( model ) } ;
52+ }
53+
3554function _deferStreamErrorIfOffline ( ) {
3655 if ( typeof isOfflineBannerVisible === 'function' && isOfflineBannerVisible ( ) ) {
3756 setComposerStatus ( t ( 'offline_stream_waiting' ) ) ;
@@ -277,7 +296,8 @@ async function send(){
277296 // so the queued message goes to the chat that owns the active stream.
278297 const _targetSid = _sendInProgressSid || ( S . session && S . session . session_id ) ;
279298 if ( _text && _targetSid ) {
280- queueSessionMessage ( _targetSid , { text :_text , files :[ ...S . pendingFiles ] , model :S . session && S . session . model || ( $ ( 'modelSelect' ) && $ ( 'modelSelect' ) . value ) || '' , model_provider :S . session && S . session . model_provider || null , profile :S . activeProfile || 'default' } ) ;
299+ const _modelState = _chatPayloadModelState ( ) ;
300+ queueSessionMessage ( _targetSid , { text :_text , files :[ ...S . pendingFiles ] , model :_modelState . model , model_provider :_modelState . model_provider , profile :S . activeProfile || 'default' } ) ;
281301 $ ( 'msg' ) . value = '' ; autoResize ( ) ;
282302 S . pendingFiles = [ ] ; renderTray ( ) ;
283303 updateQueueBadge ( _targetSid ) ;
@@ -336,7 +356,8 @@ async function send(){
336356 S . pendingFiles = [ ] ; renderTray ( ) ;
337357 } else if ( busyMode === 'interrupt' ) {
338358 // Queue the message, then cancel so drain re-sends it.
339- queueSessionMessage ( S . session . session_id , { text, files :[ ...S . pendingFiles ] , model :S . session && S . session . model || ( $ ( 'modelSelect' ) && $ ( 'modelSelect' ) . value ) || '' , model_provider :S . session && S . session . model_provider || null , profile :S . activeProfile || 'default' } ) ;
359+ const _modelState = _chatPayloadModelState ( ) ;
360+ queueSessionMessage ( S . session . session_id , { text, files :[ ...S . pendingFiles ] , model :_modelState . model , model_provider :_modelState . model_provider , profile :S . activeProfile || 'default' } ) ;
340361 updateQueueBadge ( S . session . session_id ) ;
341362 $ ( 'msg' ) . value = '' ; autoResize ( ) ;
342363 S . pendingFiles = [ ] ; renderTray ( ) ;
@@ -349,7 +370,8 @@ async function send(){
349370 } else {
350371 // Default: queue mode (current behavior). Also the fallback for
351372 // 'steer' mode when no stream is active or _trySteer is unavailable.
352- queueSessionMessage ( S . session . session_id , { text, files :[ ...S . pendingFiles ] , model :S . session && S . session . model || ( $ ( 'modelSelect' ) && $ ( 'modelSelect' ) . value ) || '' , model_provider :S . session && S . session . model_provider || null , profile :S . activeProfile || 'default' } ) ;
373+ const _modelState = _chatPayloadModelState ( ) ;
374+ queueSessionMessage ( S . session . session_id , { text, files :[ ...S . pendingFiles ] , model :_modelState . model , model_provider :_modelState . model_provider , profile :S . activeProfile || 'default' } ) ;
353375 $ ( 'msg' ) . value = '' ; autoResize ( ) ;
354376 S . pendingFiles = [ ] ; renderTray ( ) ;
355377 updateQueueBadge ( S . session . session_id ) ;
@@ -513,10 +535,13 @@ async function send(){
513535 // Start the agent via POST, get a stream_id back
514536 let streamId ;
515537 try {
538+ const _modelState = _chatPayloadModelState ( ) ;
516539 const startData = await api ( '/api/chat/start' , { method :'POST' , body :JSON . stringify ( {
517540 session_id :activeSid , message :msgText ,
518- model :S . session . model || $ ( 'modelSelect' ) . value , workspace :S . session . workspace ,
519- model_provider :S . session . model_provider || null ,
541+ // S.session.model remains authoritative; the helper only resolves a
542+ // matching provider fallback for the same outgoing model.
543+ model :_modelState . model , workspace :S . session . workspace ,
544+ model_provider :_modelState . model_provider ,
520545 profile :S . activeProfile || S . session . profile || 'default' ,
521546 attachments :uploaded . length ?uploaded :undefined
522547 } ) } ) ;
@@ -575,7 +600,8 @@ async function send(){
575600 stopApprovalPolling ( ) ;
576601 stopClarifyPolling ( ) ;
577602 // Keep the user's attempted turn by queueing it for after the current run.
578- queueSessionMessage ( activeSid , { text :msgText , files :[ ] , model :S . session && S . session . model || ( $ ( 'modelSelect' ) && $ ( 'modelSelect' ) . value ) || '' , model_provider :S . session && S . session . model_provider || null , profile :S . activeProfile || 'default' } ) ;
603+ const _retryModelState = _chatPayloadModelState ( ) ;
604+ queueSessionMessage ( activeSid , { text :msgText , files :[ ] , model :_retryModelState . model , model_provider :_retryModelState . model_provider , profile :S . activeProfile || 'default' } ) ;
579605 updateQueueBadge ( activeSid ) ;
580606 showToast ( 'Current session is still running. Reconnected and queued your message.' , 2600 ) ;
581607 try {
@@ -1749,11 +1775,12 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
17491775 const sid = d . session_id || activeSid ;
17501776 const continuation_prompt = String ( d . continuation_prompt || d . text || '' ) . trim ( ) ;
17511777 if ( ! continuation_prompt || sid !== activeSid ) return ;
1778+ const _modelState = _chatPayloadModelState ( ) ;
17521779 _pendingGoalContinuation = {
17531780 sid,
17541781 text :continuation_prompt ,
1755- model :S . session && S . session . model || '' ,
1756- model_provider :S . session && S . session . model_provider || null ,
1782+ model :_modelState . model ,
1783+ model_provider :_modelState . model_provider ,
17571784 profile :S . activeProfile || 'default' ,
17581785 } ;
17591786 const toast = t ( 'goal_continuing_toast' ) ;
@@ -1980,10 +2007,11 @@ function attachLiveStream(activeSid, streamId, uploaded=[], options={}){
19802007 const txt = String ( d . text || '' ) . trim ( ) ;
19812008 if ( ! txt || sid !== activeSid ) return ;
19822009 if ( typeof queueSessionMessage === 'function' ) {
2010+ const _modelState = _chatPayloadModelState ( ) ;
19832011 queueSessionMessage ( sid , {
19842012 text :txt , files :[ ] ,
1985- model :S . session && S . session . model || '' ,
1986- model_provider :S . session && S . session . model_provider || null ,
2013+ model :_modelState . model ,
2014+ model_provider :_modelState . model_provider ,
19872015 profile :S . activeProfile || 'default' ,
19882016 } ) ;
19892017 if ( typeof updateQueueBadge === 'function' ) updateQueueBadge ( sid ) ;
0 commit comments