@@ -2901,7 +2901,11 @@ export class SessionService {
29012901 isNotification ( msg . method , POSTHOG_NOTIFICATIONS . RUN_STARTED )
29022902 ) {
29032903 const session = this . d . store . getSessions ( ) [ taskRunId ] ;
2904- const params = ( msg as { params ?: { agentVersion ?: unknown } } ) . params ;
2904+ const params = (
2905+ msg as {
2906+ params ?: { agentVersion ?: unknown ; steering ?: unknown } ;
2907+ }
2908+ ) . params ;
29052909 const agentVersion =
29062910 typeof params ?. agentVersion === "string"
29072911 ? params . agentVersion
@@ -2910,6 +2914,12 @@ export class SessionService {
29102914 if ( agentVersion && session ?. agentVersion !== agentVersion ) {
29112915 updates . agentVersion = agentVersion ;
29122916 }
2917+ if (
2918+ typeof params ?. steering === "string" &&
2919+ session ?. steering !== params . steering
2920+ ) {
2921+ updates . steering = params . steering ;
2922+ }
29132923 if ( session ?. isCloud && session . status !== "connected" ) {
29142924 updates . status = "connected" ;
29152925 }
@@ -3384,22 +3394,27 @@ export class SessionService {
33843394 // Steer: the user sent a message mid-turn and asked to fold it into the
33853395 // running turn rather than queue it. Adapters that negotiated
33863396 // `steering: "native"` (Claude, codex) inject at the next tool boundary;
3387- // unknown adapters cancel and resend. Cloud has no real mid-turn steer
3388- // (the backend only delivers messages between turns), so it falls through
3389- // to the queue; compaction too.
3390- if (
3391- options ?. steer &&
3392- ! session . isCloud &&
3393- session . isPromptPending &&
3394- ! session . isCompacting
3395- ) {
3397+ // unknown local adapters cancel and resend. Cloud sessions only enter this
3398+ // path after the sandbox advertises native steering; compaction still queues.
3399+ if ( options ?. steer && session . isPromptPending && ! session . isCompacting ) {
33963400 if ( sessionSupportsNativeSteer ( session ) ) {
3397- return this . sendSteerPrompt ( session , prompt ) ;
3401+ if ( session . isCloud ) {
3402+ if ( session . status === "connected" ) {
3403+ return this . sendCloudPrompt ( session , prompt , {
3404+ skipQueueGuard : true ,
3405+ steer : true ,
3406+ } ) ;
3407+ }
3408+ } else {
3409+ return this . sendSteerPrompt ( session , prompt ) ;
3410+ }
33983411 }
3399- await this . cancelPrompt ( taskId ) ;
3400- const refreshed = this . d . store . getSessionByTaskId ( taskId ) ;
3401- if ( refreshed ) {
3402- session = refreshed ;
3412+ if ( ! session . isCloud ) {
3413+ await this . cancelPrompt ( taskId ) ;
3414+ const refreshed = this . d . store . getSessionByTaskId ( taskId ) ;
3415+ if ( refreshed ) {
3416+ session = refreshed ;
3417+ }
34033418 }
34043419 }
34053420
@@ -3931,7 +3946,7 @@ export class SessionService {
39313946 private async sendCloudPrompt (
39323947 session : AgentSession ,
39333948 prompt : string | ContentBlock [ ] ,
3934- options ?: { skipQueueGuard ?: boolean } ,
3949+ options ?: { skipQueueGuard ?: boolean ; steer ?: boolean } ,
39353950 ) : Promise < { stopReason : string } > {
39363951 const normalizedPrompt = await this . resolveCloudPrompt ( prompt ) ;
39373952 const transport = this . d . h . getCloudPromptTransport ( normalizedPrompt ) ;
@@ -4063,19 +4078,24 @@ export class SessionService {
40634078 if ( artifactIds . length > 0 ) {
40644079 params . artifact_ids = artifactIds ;
40654080 }
4081+ if ( options ?. steer ) {
4082+ params . steer = true ;
4083+ }
40664084
40674085 const currentSessionBeforeSend =
40684086 this . getSessionByRunId ( session . taskRunId ) ?? session ;
40694087 const idleEvidenceBeforeSend = this . cloudRunIdleTracker . capture (
40704088 currentSessionBeforeSend ,
40714089 ) ;
4072- this . d . store . updateSession ( session . taskRunId , {
4073- isPromptPending : true ,
4074- promptStartedAt : Date . now ( ) ,
4075- pausedDurationMs : 0 ,
4076- agentIdleForRunId : undefined ,
4077- } ) ;
4078- this . cloudRunIdleTracker . markBusy ( currentSessionBeforeSend ) ;
4090+ if ( ! options ?. steer ) {
4091+ this . d . store . updateSession ( session . taskRunId , {
4092+ isPromptPending : true ,
4093+ promptStartedAt : Date . now ( ) ,
4094+ pausedDurationMs : 0 ,
4095+ agentIdleForRunId : undefined ,
4096+ } ) ;
4097+ this . cloudRunIdleTracker . markBusy ( currentSessionBeforeSend ) ;
4098+ }
40794099 this . d . store . appendOptimisticItem ( session . taskRunId , {
40804100 type : "user_message" ,
40814101 content : transport . promptText ,
@@ -4088,6 +4108,7 @@ export class SessionService {
40884108 is_initial : session . events . length === 0 ,
40894109 execution_type : "cloud" ,
40904110 prompt_length_chars : transport . promptText . length ,
4111+ ...( options ?. steer ? { is_steer : true } : { } ) ,
40914112 } ) ;
40924113
40934114 try {
@@ -4105,23 +4126,25 @@ export class SessionService {
41054126 }
41064127
41074128 const commandResult = result . result as
4108- | { queued ?: boolean ; stopReason ?: string }
4129+ | { queued ?: boolean ; steered ?: boolean ; stopReason ?: string }
41094130 | undefined ;
41104131 const stopReason = commandResult ?. queued
41114132 ? "queued"
41124133 : ( commandResult ?. stopReason ?? "end_turn" ) ;
41134134
41144135 return { stopReason } ;
41154136 } catch ( error ) {
4116- this . d . store . updateSession ( session . taskRunId , {
4117- isPromptPending : false ,
4118- promptStartedAt : null ,
4119- } ) ;
4137+ if ( ! options ?. steer ) {
4138+ this . d . store . updateSession ( session . taskRunId , {
4139+ isPromptPending : false ,
4140+ promptStartedAt : null ,
4141+ } ) ;
4142+ }
41204143 this . d . store . clearTailOptimisticItems ( session . taskRunId ) ;
41214144 const currentSessionAfterFailure = this . getSessionByRunId (
41224145 session . taskRunId ,
41234146 ) ;
4124- if ( currentSessionAfterFailure ) {
4147+ if ( currentSessionAfterFailure && ! options ?. steer ) {
41254148 const restoreResult = this . cloudRunIdleTracker . restoreAfterFailedSend (
41264149 idleEvidenceBeforeSend ,
41274150 currentSessionAfterFailure ,
0 commit comments