@@ -737,8 +737,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
737737 // deallocated. (Although we set Cline = undefined in provider, that
738738 // simply removes the reference to this instance, but the instance is
739739 // still alive until this promise resolves or rejects.)
740- // Exception: Allow resume asks even when aborted for soft-interrupt UX
741- if ( this . abort && type !== "resume_task" && type !== "resume_completed_task" ) {
740+ if ( this . abort ) {
742741 throw new Error ( `[RooCode#ask] task ${ this . taskId } .${ this . instanceId } aborted` )
743742 }
744743
@@ -1256,7 +1255,7 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
12561255 ] )
12571256 }
12581257
1259- public async resumeTaskFromHistory ( ) {
1258+ private async resumeTaskFromHistory ( ) {
12601259 if ( this . enableBridge ) {
12611260 try {
12621261 await BridgeOrchestrator . subscribeToTask ( this )
@@ -1348,13 +1347,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
13481347
13491348 const { response, text, images } = await this . ask ( askType ) // Calls `postStateToWebview`.
13501349
1351- // Reset abort flags AFTER user responds to resume ask.
1352- // This is critical for the cancel → resume flow: when a task is soft-aborted
1353- // (abandoned = false), we keep the instance alive but set abort = true.
1354- // We only clear these flags after the user confirms they want to resume,
1355- // preventing the old stream from continuing if abort was set.
1356- this . resetAbortAndStreamingState ( )
1357-
13581350 let responseText : string | undefined
13591351 let responseImages : string [ ] | undefined
13601352
@@ -1533,86 +1525,6 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
15331525 await this . initiateTaskLoop ( newUserContent )
15341526 }
15351527
1536- /**
1537- * Resets abort flags and streaming state to allow task resumption.
1538- * Centralizes the state reset logic used after user confirms task resumption.
1539- *
1540- * @private
1541- */
1542- private resetAbortAndStreamingState ( ) : void {
1543- this . abort = false
1544- this . abandoned = false
1545- this . abortReason = undefined
1546- this . didFinishAbortingStream = false
1547- this . isStreaming = false
1548-
1549- // Reset streaming-local fields to avoid stale state from previous stream
1550- this . currentStreamingContentIndex = 0
1551- this . currentStreamingDidCheckpoint = false
1552- this . assistantMessageContent = [ ]
1553- this . didCompleteReadingStream = false
1554- this . userMessageContent = [ ]
1555- this . userMessageContentReady = false
1556- this . didRejectTool = false
1557- this . didAlreadyUseTool = false
1558- this . presentAssistantMessageLocked = false
1559- this . presentAssistantMessageHasPendingUpdates = false
1560- this . assistantMessageParser . reset ( )
1561- }
1562-
1563- /**
1564- * Present a resumable ask on an aborted task without rehydrating.
1565- * Used by soft-interrupt (cancelTask) to show Resume/Terminate UI.
1566- * Selects the appropriate ask type based on the last relevant message.
1567- * If the user clicks Resume, resets abort flags and continues the task loop.
1568- */
1569- public async presentResumableAsk ( ) : Promise < void > {
1570- const lastClineMessage = this . clineMessages
1571- . slice ( )
1572- . reverse ( )
1573- . find ( ( m ) => ! ( m . ask === "resume_task" || m . ask === "resume_completed_task" ) )
1574-
1575- let askType : ClineAsk
1576- if ( lastClineMessage ?. ask === "completion_result" ) {
1577- askType = "resume_completed_task"
1578- } else {
1579- askType = "resume_task"
1580- }
1581-
1582- const { response, text, images } = await this . ask ( askType )
1583-
1584- // If user clicked Resume (not Terminate), reset abort flags and continue
1585- if ( response === "yesButtonClicked" || response === "messageResponse" ) {
1586- // Reset abort flags to allow the loop to continue
1587- this . resetAbortAndStreamingState ( )
1588-
1589- // Prepare content for resuming the task loop
1590- let userContent : Anthropic . Messages . ContentBlockParam [ ] = [ ]
1591-
1592- if ( response === "messageResponse" && text ) {
1593- // User provided additional instructions
1594- await this . say ( "user_feedback" , text , images )
1595- userContent . push ( {
1596- type : "text" ,
1597- text : `\n\nNew instructions for task continuation:\n<user_message>\n${ text } \n</user_message>` ,
1598- } )
1599- if ( images && images . length > 0 ) {
1600- userContent . push ( ...formatResponse . imageBlocks ( images ) )
1601- }
1602- } else {
1603- // Simple resume with no new instructions
1604- userContent . push ( {
1605- type : "text" ,
1606- text : "[TASK RESUMPTION] Resuming task..." ,
1607- } )
1608- }
1609-
1610- // Continue the task loop
1611- await this . initiateTaskLoop ( userContent )
1612- }
1613- // If user clicked Terminate (noButtonClicked), do nothing - task stays aborted
1614- }
1615-
16161528 public async abortTask ( isAbandoned = false ) {
16171529 // Aborting task
16181530
@@ -1624,17 +1536,12 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
16241536 this . abort = true
16251537 this . emit ( RooCodeEventName . TaskAborted )
16261538
1627- // Only dispose if this is a hard abort (abandoned)
1628- // For soft abort (user cancel), keep the instance alive so we can present a resumable ask
1629- if ( isAbandoned ) {
1630- try {
1631- this . dispose ( ) // Call the centralized dispose method
1632- } catch ( error ) {
1633- console . error ( `Error during task ${ this . taskId } .${ this . instanceId } disposal:` , error )
1634- // Don't rethrow - we want abort to always succeed
1635- }
1539+ try {
1540+ this . dispose ( ) // Call the centralized dispose method
1541+ } catch ( error ) {
1542+ console . error ( `Error during task ${ this . taskId } .${ this . instanceId } disposal:` , error )
1543+ // Don't rethrow - we want abort to always succeed
16361544 }
1637-
16381545 // Save the countdown message in the automatic retry or other content.
16391546 try {
16401547 // Save the countdown message in the automatic retry or other content.
0 commit comments