@@ -182,6 +182,13 @@ async function centralOrchestrator(question, userId, chatId = 1, isFollowUp = fa
182182 contextManager . resetContext ( userId , chatId ) ;
183183 }
184184
185+ // Clear any previous cancellation history when starting a new task
186+ contextManager . clearCancellationHistory ( userId , chatId ) ;
187+
188+ // Create AbortController for cancellation support
189+ const abortController = new AbortController ( ) ;
190+ contextManager . setCancellationToken ( abortController , userId , chatId ) ;
191+
185192 // Set task as running only once after context is initialized/reset
186193 contextManager . setTaskRunning ( true , userId , chatId ) ;
187194
@@ -192,12 +199,22 @@ async function centralOrchestrator(question, userId, chatId = 1, isFollowUp = fa
192199 // Set the question in context
193200 contextManager . setQuestion ( question , userId , chatId ) ;
194201
202+ // Check for cancellation
203+ if ( contextManager . isTaskCancelled ( userId , chatId ) ) {
204+ throw new Error ( 'Task cancelled by user' ) ;
205+ }
206+
195207 // Generate planning prompt
196208 const history = contextManager . getHistoryWithChatId ( userId , chatId ) ;
197209 const prompt = await prompts . generatePlanningPrompt ( question , history , userId ) ;
198210
199211 io . to ( `user:${ userId } ` ) . emit ( 'status_update' , { userId, chatId, status : 'Planning task execution' } ) ;
200212
213+ // Check for cancellation
214+ if ( contextManager . isTaskCancelled ( userId , chatId ) ) {
215+ throw new Error ( 'Task cancelled by user' ) ;
216+ }
217+
201218 // Get plan from AI using planning model
202219 let planObject = await ai . callAI ( prompt , question , history , undefined , true , "planning" , userId , chatId ) ;
203220
@@ -212,15 +229,27 @@ async function centralOrchestrator(question, userId, chatId = 1, isFollowUp = fa
212229 } catch ( error ) {
213230 console . error ( "Critical error in orchestration:" , error . message ) ;
214231
215- io . to ( `user:${ userId } ` ) . emit ( 'task_error' , { userId, chatId, error : error . message } ) ;
232+ // Check if this was a cancellation
233+ const isCancelled = error . message === 'Task cancelled by user' ;
234+
235+ // Clean up task state
236+ contextManager . setTaskRunning ( false , userId , chatId ) ;
237+ contextManager . clearCancellationToken ( userId , chatId ) ;
238+
239+ // Send appropriate message to client
240+ if ( isCancelled ) {
241+ io . to ( `user:${ userId } ` ) . emit ( 'task_cancelled' , { userId, chatId, message : 'Task cancelled successfully' } ) ;
242+ } else {
243+ io . to ( `user:${ userId } ` ) . emit ( 'task_error' , { userId, chatId, error : error . message } ) ;
244+ }
216245
217246 try {
218247 await cleanupUserResources ( userId ) ;
219248 } catch ( cleanupError ) {
220249 console . error ( "Error during cleanup:" , cleanupError . message ) ;
221250 }
222251
223- return `Critical error occurred during execution: ${ error . message } ` ;
252+ return isCancelled ? 'Task cancelled by user' : `Critical error occurred during execution: ${ error . message } ` ;
224253 }
225254}
226255
@@ -269,6 +298,7 @@ async function handleDirectAnswer(planObject, question, userId, chatId) {
269298
270299 // Mark task as no longer running
271300 contextManager . setTaskRunning ( false , userId , chatId ) ;
301+ contextManager . clearCancellationToken ( userId , chatId ) ;
272302
273303 await cleanupUserResources ( userId ) ;
274304 return planObject . answer ;
@@ -368,6 +398,11 @@ function setupScreenshotInterval(plan, userId, chatId) {
368398 */
369399async function executeSteps ( plan , question , userId , chatId ) {
370400 while ( contextManager . getCurrentStepIndex ( userId , chatId ) < plan . length ) {
401+ // Check for cancellation before each step
402+ if ( contextManager . isTaskCancelled ( userId , chatId ) ) {
403+ throw new Error ( 'Task cancelled by user' ) ;
404+ }
405+
371406 const currentStepIndex = contextManager . getCurrentStepIndex ( userId , chatId ) ;
372407 const step = plan [ currentStepIndex ] ;
373408
@@ -693,6 +728,7 @@ async function finalizeAndReturn(question, plan, userId, chatId) {
693728
694729 // Mark task as no longer running
695730 contextManager . setTaskRunning ( false , userId , chatId ) ;
731+ contextManager . clearCancellationToken ( userId , chatId ) ;
696732
697733 await cleanupUserResources ( userId ) ;
698734 return finalOutput ;
0 commit comments