@@ -68,12 +68,21 @@ export class AgentQueryEngine {
6868 goal : string ,
6969 options : AgentTaskRunOptions ,
7070 ) : Promise < boolean > {
71+ const activeRunMode = session . activeTaskRun ?. mode ;
7172 const siteFollowUpGoal = looksLikeSiteFollowUpGoal ( goal ) ;
7273 const continuingRun =
7374 options . resumeRequested &&
7475 Boolean ( session . activeTaskRun ) &&
7576 ! [ 'completed' , 'failed' ] . includes ( session . activeTaskRun ?. status || '' ) ;
7677
78+ if ( continuingRun && activeRunMode && activeRunMode !== 'project' ) {
79+ return this . runGenericTask ( session , goal , {
80+ continuingRun : true ,
81+ sourceLabel : session . activeTaskRun ?. source ?. label ,
82+ mode : activeRunMode ,
83+ } ) ;
84+ }
85+
7786 const sourceLabel = continuingRun
7887 ? session . activeTaskRun ?. source ?. label || await this . store . resolveDeploySource ( session , goal )
7988 : await this . store . resolveDeploySource ( session , goal ) ;
@@ -94,23 +103,69 @@ export class AgentQueryEngine {
94103 return this . runGenericTask ( session , goal ) ;
95104 }
96105
97- async runGenericTask ( session : AgentThreadSession , goal : string ) : Promise < boolean > {
106+ async runGenericTask (
107+ session : AgentThreadSession ,
108+ goal : string ,
109+ options ?: {
110+ continuingRun ?: boolean ;
111+ sourceLabel ?: string ;
112+ mode ?: 'generic' | 'site-followup' ;
113+ } ,
114+ ) : Promise < boolean > {
98115 session . planState . global_goal = goal ;
99116 session . planState . scratchpad = appendScratchpad ( session . planState . scratchpad , `Goal: ${ goal } ` ) ;
100117 this . events . emitPlanUpdate ( session , 'generating' ) ;
101118
119+ const continuingRun = Boolean ( options ?. continuingRun && session . activeTaskRun ) ;
120+ if ( ! continuingRun ) {
121+ const run = this . store . createGenericTaskRun ( goal , {
122+ mode : options ?. mode || 'generic' ,
123+ sourceLabel : options ?. sourceLabel ,
124+ currentAction : options ?. mode === 'site-followup'
125+ ? 'Inspecting the current site, nginx, and certificate state'
126+ : 'Understanding the goal and deciding the next action' ,
127+ nextAction : 'Inspect the current state and continue execution' ,
128+ } ) ;
129+ this . store . attachTaskRun ( session , run ) ;
130+ session . recentHttpProbes = [ ] ;
131+ session . lastToolFailure = undefined ;
132+ } else if ( session . activeTaskRun ) {
133+ this . store . upsertTaskRun ( session , {
134+ status : 'running' ,
135+ phase : 'act' ,
136+ currentAction : options ?. mode === 'site-followup'
137+ ? 'Resuming the site follow-up task'
138+ : 'Resuming the current task' ,
139+ } , {
140+ phase : 'act' ,
141+ nextAction : 'Continue from the preserved task state' ,
142+ } ) ;
143+ }
144+
102145 let completed = false ;
103146 try {
104147 while ( ! session . aborted && session . turnCounter < MAX_GENERIC_TURNS ) {
105148 session . turnCounter += 1 ;
106149 await this . compactService . maybeCompact ( session ) ;
150+ if ( session . activeTaskRun ) {
151+ this . store . upsertTaskRun ( session , {
152+ status : 'running' ,
153+ phase : 'act' ,
154+ currentAction : options ?. mode === 'site-followup'
155+ ? 'Inspecting and updating the current site configuration'
156+ : 'Thinking, inspecting facts, and deciding the next action' ,
157+ } , {
158+ phase : 'act' ,
159+ nextAction : 'Continue the current task loop' ,
160+ } ) ;
161+ }
107162 this . events . emitPlanUpdate ( session , 'executing' ) ;
108163
109164 const response = await this . callLLMWithRetries ( session ) ;
110165 this . store . updateContextWindow ( session , response . usage ) ;
166+ const text = response . content ?. trim ( ) || '' ;
111167
112- if ( response . content ?. trim ( ) ) {
113- const text = response . content . trim ( ) ;
168+ if ( text ) {
114169 this . events . emitAssistantMessage ( session , {
115170 id : `assistant-${ Date . now ( ) } ` ,
116171 role : 'assistant' ,
@@ -125,6 +180,18 @@ export class AgentQueryEngine {
125180 }
126181
127182 if ( ! response . toolCalls ?. length ) {
183+ if ( session . activeTaskRun ) {
184+ const verifiedUrl = this . store . detectVerifiedUrl ( session , text ) ;
185+ this . store . upsertTaskRun ( session , {
186+ status : 'completed' ,
187+ phase : 'complete' ,
188+ finalUrl : verifiedUrl ,
189+ currentAction : 'The task finished and produced a final answer.' ,
190+ } , {
191+ phase : 'complete' ,
192+ nextAction : undefined ,
193+ } ) ;
194+ }
128195 completed = true ;
129196 return true ;
130197 }
@@ -139,6 +206,16 @@ export class AgentQueryEngine {
139206 }
140207
141208 const limitMessage = 'The current task reached the autonomous turn budget. Context is preserved, and you can ask me to continue.' ;
209+ if ( session . activeTaskRun ) {
210+ this . store . upsertTaskRun ( session , {
211+ status : 'paused' ,
212+ phase : 'paused' ,
213+ currentAction : limitMessage ,
214+ } , {
215+ phase : 'paused' ,
216+ nextAction : 'Send continue to resume the same task' ,
217+ } ) ;
218+ }
142219 this . store . historyPush ( session , { role : 'assistant' , content : limitMessage } ) ;
143220 this . events . emitAssistantMessage ( session , {
144221 id : `limit-${ Date . now ( ) } ` ,
@@ -148,8 +225,49 @@ export class AgentQueryEngine {
148225 isError : true ,
149226 } ) ;
150227 return true ;
228+ } catch ( error : any ) {
229+ const failureClass = this . store . classifyAutonomousFailure ( undefined , error ?. message || String ( error ) ) ;
230+ const failure : TaskRunFailure = {
231+ attempt : Math . max ( ( session . activeTaskRun ?. attemptCount || 0 ) + 1 , 1 ) ,
232+ routeId : session . activeTaskRun ?. activeHypothesisId ,
233+ failureClass,
234+ message : error ?. message || String ( error ) ,
235+ timestamp : now ( ) ,
236+ } ;
237+ if ( session . activeTaskRun ) {
238+ this . store . upsertTaskRun ( session , {
239+ status : failureClass === 'llm_overloaded' ? 'retryable_paused' : 'failed' ,
240+ phase : failureClass === 'llm_overloaded' ? 'paused' : 'failed' ,
241+ attemptCount : failure . attempt ,
242+ failureHistory : [ ...( session . activeTaskRun . failureHistory || [ ] ) , failure ] . slice ( - 20 ) ,
243+ currentAction : this . store . failureText ( failure , true ) ,
244+ } , {
245+ phase : failureClass === 'llm_overloaded' ? 'paused' : 'failed' ,
246+ attemptCount : failure . attempt ,
247+ nextAction : failureClass === 'llm_overloaded' ? 'Send continue to resume the same task' : undefined ,
248+ } ) ;
249+ }
250+ const failureText = this . store . failureText ( failure , true ) ;
251+ this . store . historyPush ( session , { role : 'assistant' , content : failureText } ) ;
252+ this . events . emitAssistantMessage ( session , {
253+ id : `generic-task-error-${ Date . now ( ) } ` ,
254+ role : 'assistant' ,
255+ content : failureText ,
256+ timestamp : now ( ) ,
257+ isError : true ,
258+ } ) ;
259+ return true ;
151260 } finally {
152- this . events . emitPlanUpdate ( session , session . aborted ? 'stopped' : completed ? 'done' : 'stopped' ) ;
261+ this . events . emitPlanUpdate (
262+ session ,
263+ session . activeTaskRun
264+ ? phaseToPlanStatus ( session . activeTaskRun )
265+ : session . aborted
266+ ? 'stopped'
267+ : completed
268+ ? 'done'
269+ : 'stopped' ,
270+ ) ;
153271 }
154272 }
155273
@@ -174,7 +292,10 @@ export class AgentQueryEngine {
174292 : 'I will treat this as an existing-site operation and inspect the current server, nginx, and certificate state before applying domain and HTTPS changes.' ,
175293 timestamp : now ( ) ,
176294 } ) ;
177- return this . runGenericTask ( session , goal ) ;
295+ return this . runGenericTask ( session , goal , {
296+ mode : 'site-followup' ,
297+ sourceLabel : inheritedSource ,
298+ } ) ;
178299 }
179300
180301 async executeRoute ( session : AgentThreadSession , route : RouteHypothesis ) : Promise < RouteExecutionResult > {
0 commit comments