@@ -128,9 +128,38 @@ export async function runControllerView(
128128 return { ran : false } ;
129129 }
130130
131- // Initialize controller agent
132- // Engine/model resolution happens inside executeAgent (single source of truth)
133- // Only pass overrides from workflow definition.options
131+ // Resolve engine and model upfront (before execution) like step agents do
132+ // This ensures UI shows engine/model immediately, not after first turn
133+ debug ( '[ControllerView] Resolving engine and model upfront' ) ;
134+ const { selectEngine } = await import ( '../step/engine.js' ) ;
135+ const { registry } = await import ( '../../infra/engines/index.js' ) ;
136+
137+ // Create a step-like object for selectEngine
138+ const stepLike = {
139+ engine : definition . options ?. engine ,
140+ agentId : controller . id ,
141+ agentName : ( controller . name as string | undefined ) ?? controller . id ,
142+ } ;
143+
144+ const resolvedEngine = await selectEngine ( stepLike , emitter , controller . id ) ;
145+ debug ( '[ControllerView] Resolved engine: %s' , resolvedEngine ) ;
146+
147+ // Resolve model from definition override or engine default
148+ const engineModule = registry . get ( resolvedEngine ) ;
149+ const resolvedModel = definition . options ?. model ?? engineModule ?. metadata . defaultModel ;
150+ debug ( '[ControllerView] Resolved model: %s' , resolvedModel ) ;
151+
152+ // Emit controller info BEFORE execution so UI shows it immediately
153+ const controllerName = ( controller . name as string | undefined ) ?? controller . id ;
154+ emitter . setControllerInfo (
155+ controller . id ,
156+ controllerName ,
157+ resolvedEngine ,
158+ resolvedModel
159+ ) ;
160+ debug ( '[ControllerView] Emitted controller info upfront: engine=%s, model=%s' , resolvedEngine , resolvedModel ) ;
161+
162+ // Initialize controller agent with resolved engine/model
134163 debug ( '[ControllerView] Initializing controller agent' ) ;
135164 let controllerMonitoringId : number | undefined ;
136165
@@ -146,23 +175,14 @@ export async function runControllerView(
146175 controllerMonitoringId = monitoringId ;
147176 emitter . registerControllerMonitoring ( monitoringId ) ;
148177 } ,
149- engineOverride : definition . options ?. engine ,
150- modelOverride : definition . options ?. model ,
178+ engineOverride : resolvedEngine ,
179+ modelOverride : resolvedModel ,
151180 }
152181 ) ;
153182
154183 debug ( '[ControllerView] Controller initialized: sessionId=%s, monitoringId=%d, engine=%s, model=%s' ,
155184 config . sessionId , controllerMonitoringId , config . engine , config . model ) ;
156185
157- // Emit controller info for UI (use resolved values from initControllerAgent)
158- const controllerName = ( controller . name as string | undefined ) ?? controller . id ;
159- emitter . setControllerInfo (
160- controller . id ,
161- controllerName ,
162- config . engine ,
163- config . model
164- ) ;
165-
166186 // Set up conversational loop
167187 // 1. Set input state active so UI shows input box
168188 // 2. Wait for user input
0 commit comments