@@ -179,6 +179,106 @@ export class RuntimeAgent {
179179 }
180180 }
181181
182+ /**
183+ * Execute exactly one action for a step without owning step lifecycle.
184+ *
185+ * This is intended for orchestrators that already call `runtime.beginStep(...)` /
186+ * `runtime.emitStepEnd(...)` and want to reuse the SDK's snapshot-first action proposal
187+ * and execution logic without double-counting budgets or emitting duplicate events.
188+ */
189+ async actOnce ( opts : {
190+ taskGoal : string ;
191+ step : RuntimeStep ;
192+ allowVisionFallback ?: boolean ;
193+ historySummary ?: string ;
194+ } ) : Promise < string > {
195+ const res = await this . actOnceResult ( opts ) ;
196+ return res . action ;
197+ }
198+
199+ /**
200+ * Like `actOnce`, but also returns the pre-action snapshot used for proposal.
201+ */
202+ async actOnceWithSnapshot ( opts : {
203+ taskGoal : string ;
204+ step : RuntimeStep ;
205+ allowVisionFallback ?: boolean ;
206+ historySummary ?: string ;
207+ } ) : Promise < { action : string ; snap : Snapshot } > {
208+ const res = await this . actOnceResult ( opts ) ;
209+ return { action : res . action , snap : res . snap } ;
210+ }
211+
212+ /**
213+ * Like `actOnce`, but also indicates whether vision was used.
214+ */
215+ async actOnceResult ( opts : {
216+ taskGoal : string ;
217+ step : RuntimeStep ;
218+ allowVisionFallback ?: boolean ;
219+ historySummary ?: string ;
220+ } ) : Promise < { action : string ; snap : Snapshot ; usedVision : boolean } > {
221+ const { taskGoal, step } = opts ;
222+ const allowVisionFallback = opts . allowVisionFallback ?? true ;
223+ const historySummary = ( opts . historySummary ?? '' ) . trim ( ) ;
224+
225+ const snap = await this . snapshotWithRamp ( step ) ;
226+
227+ if ( allowVisionFallback && ( await this . shouldShortCircuitToVision ( step , snap ) ) ) {
228+ const provider = this . visionExecutor ;
229+ if ( provider && provider . supportsVision ?.( ) ) {
230+ const url = this . runtime . page ?. url ?.( ) ?? snap ?. url ?? '(unknown)' ;
231+ const buf = ( await ( this . runtime . page as any ) . screenshot ( { type : 'png' } ) ) as Buffer ;
232+ const imageBase64 = Buffer . from ( buf ) . toString ( 'base64' ) ;
233+
234+ const { systemPrompt, userPrompt } = this . visionExecutorPrompts ( {
235+ taskGoal,
236+ step,
237+ url,
238+ snap,
239+ } ) ;
240+
241+ const resp = await provider . generateWithImage ( systemPrompt , userPrompt , imageBase64 , {
242+ temperature : 0.0 ,
243+ } ) ;
244+ const action = this . extractActionFromText ( resp . content ) ;
245+ await this . executeAction ( action , snap ?? undefined ) ;
246+ return { action, snap, usedVision : true } ;
247+ }
248+ }
249+
250+ // Structured snapshot-first proposal.
251+ let domContext = this . structuredLLM . buildContext ( snap , step . goal ) ;
252+ if ( this . domContextPostprocessor ) {
253+ domContext = this . domContextPostprocessor ( domContext ) ;
254+ }
255+
256+ let action : string ;
257+ if ( this . structuredPromptBuilder ) {
258+ const { systemPrompt, userPrompt } = this . structuredPromptBuilder (
259+ taskGoal ,
260+ step . goal ,
261+ domContext ,
262+ snap ,
263+ historySummary || ( this . historySummaryProvider ?.( ) ?? '' ) . trim ( )
264+ ) ;
265+ const resp = await this . executor . generate ( systemPrompt , userPrompt , { temperature : 0.0 } ) ;
266+ action = this . extractActionFromText ( resp . content ) ;
267+ } else {
268+ let combinedGoal = taskGoal ;
269+ const hs = historySummary || ( this . historySummaryProvider ?.( ) ?? '' ) . trim ( ) ;
270+ if ( hs ) {
271+ combinedGoal = `${ taskGoal } \n\nRECENT STEPS:\n${ hs } ` ;
272+ }
273+ combinedGoal = `${ combinedGoal } \n\nSTEP: ${ step . goal } ` ;
274+ const resp = await this . structuredLLM . queryLLM ( domContext , combinedGoal ) ;
275+ action = this . extractActionFromText ( resp . content ) ;
276+ }
277+
278+ await this . executeAction ( action , snap ) ;
279+ return { action, snap, usedVision : false } ;
280+ }
281+
182282 private async runHook (
183283 hook : ( ( ctx : StepHookContext ) => void | Promise < void > ) | undefined ,
184284 ctx : StepHookContext
0 commit comments