@@ -1635,8 +1635,9 @@ export class ClineProvider
16351635 * Handle switching to a new mode, including updating the associated API configuration
16361636 * @param newMode The mode to switch to
16371637 */
1638- public async handleModeSwitch ( newMode : Mode ) {
1639- const task = this . getCurrentTask ( )
1638+ public async handleModeSwitch ( newMode : Mode , options : { updateCurrentTask ?: boolean } = { } ) {
1639+ const { updateCurrentTask = true } = options
1640+ const task = updateCurrentTask ? this . getCurrentTask ( ) : undefined
16401641
16411642 if ( task ) {
16421643 task . emit ( RooCodeEventName . TaskModeSwitched , task . taskId , newMode )
@@ -1698,7 +1699,7 @@ export class ClineProvider
16981699 const hasActualSettings = ! ! fullProfile . apiProvider
16991700
17001701 if ( hasActualSettings ) {
1701- await this . activateProviderProfile ( { name : profile . name } )
1702+ await this . activateProviderProfile ( { name : profile . name } , { updateCurrentTask } )
17021703 } else {
17031704 // The task will continue with the current/default configuration.
17041705 }
@@ -1881,12 +1882,13 @@ export class ClineProvider
18811882
18821883 async activateProviderProfile (
18831884 args : { name : string } | { id : string } ,
1884- options ?: { persistModeConfig ?: boolean ; persistTaskHistory ?: boolean } ,
1885+ options ?: { persistModeConfig ?: boolean ; persistTaskHistory ?: boolean ; updateCurrentTask ?: boolean } ,
18851886 ) {
18861887 const { name, id, ...providerSettings } = await this . providerSettingsManager . activateProfile ( args )
18871888
18881889 const persistModeConfig = options ?. persistModeConfig ?? true
18891890 const persistTaskHistory = options ?. persistTaskHistory ?? true
1891+ const updateCurrentTask = options ?. updateCurrentTask ?? true
18901892
18911893 // See `upsertProviderProfile` for a description of what this is doing.
18921894 await Promise . all ( [
@@ -1901,13 +1903,15 @@ export class ClineProvider
19011903 await this . providerSettingsManager . setModeConfig ( mode , id )
19021904 }
19031905
1904- // Change the provider for the current task.
1905- this . updateTaskApiHandlerIfNeeded ( providerSettings , { forceRebuild : true } )
1906+ if ( updateCurrentTask ) {
1907+ // Change the provider for the current task.
1908+ this . updateTaskApiHandlerIfNeeded ( providerSettings , { forceRebuild : true } )
19061909
1907- // Update the current task's sticky provider profile, unless this activation is
1908- // being used purely as a non-persisting restoration (e.g., reopening a task from history).
1909- if ( persistTaskHistory ) {
1910- await this . persistStickyProviderProfileToCurrentTask ( name )
1910+ // Update the current task's sticky provider profile, unless this activation is
1911+ // being used purely as a non-persisting restoration (e.g., reopening a task from history).
1912+ if ( persistTaskHistory ) {
1913+ await this . persistStickyProviderProfileToCurrentTask ( name )
1914+ }
19111915 }
19121916
19131917 await this . postStateToWebview ( )
@@ -3515,7 +3519,7 @@ export class ClineProvider
35153519 /**
35163520 * Delegate parent task and open child task.
35173521 *
3518- * - Enforce single-open invariant
3522+ * - Resolve the invoking parent by id, independent of current visible selection
35193523 * - Persist parent delegation metadata
35203524 * - Emit TaskDelegated (task-level; API forwards to provider/bridge)
35213525 * - Create child as sole active and switch mode to child's mode
@@ -3530,14 +3534,14 @@ export class ClineProvider
35303534
35313535 // Metadata-driven delegation is always enabled
35323536
3533- // 1) Get parent (must be current task)
3534- const parent = this . getCurrentTask ( )
3537+ // 1) Get the exact live parent that invoked new_task. Do not use getCurrentTask()
3538+ // here: the visible/current task can change while approval or async state work is
3539+ // pending, and rejecting on that stale selection blocks valid delegation.
3540+ const parent = this . getTaskById ( parentTaskId )
35353541 if ( ! parent ) {
3536- throw new Error ( "[delegateParentAndOpenChild] No current task" )
3537- }
3538- if ( parent . taskId !== parentTaskId ) {
3542+ const current = this . getCurrentTask ( )
35393543 throw new Error (
3540- `[delegateParentAndOpenChild] Parent mismatch : expected ${ parentTaskId } , current ${ parent . taskId } ` ,
3544+ `[delegateParentAndOpenChild] Parent task not open : expected ${ parentTaskId } , current ${ current ? .taskId ?? "none" } ` ,
35413545 )
35423546 }
35433547 // 2) Flush pending tool results to API history BEFORE disposing the parent.
@@ -3578,7 +3582,7 @@ export class ClineProvider
35783582 // This ensures we never have >1 tasks open at any time during delegation.
35793583 // Await abort completion to ensure clean disposal and prevent unhandled rejections.
35803584 try {
3581- await this . removeClineFromStack ( { skipDelegationRepair : true } )
3585+ await this . removeClineFromStack ( { taskId : parentTaskId , skipDelegationRepair : true } )
35823586 } catch ( error ) {
35833587 this . log (
35843588 `[delegateParentAndOpenChild] Error during parent disposal (non-fatal): ${
@@ -3593,7 +3597,7 @@ export class ClineProvider
35933597 // The mode switch must happen before createTask() because the Task constructor
35943598 // initializes its mode from provider.getState() during initializeTaskMode().
35953599 try {
3596- await this . handleModeSwitch ( mode as any )
3600+ await this . handleModeSwitch ( mode as any , { updateCurrentTask : false } )
35973601 } catch ( e ) {
35983602 this . log (
35993603 `[delegateParentAndOpenChild] handleModeSwitch failed for mode '${ mode } ': ${
0 commit comments