Skip to content

Conversation

@axmo
Copy link
Contributor

@axmo axmo commented May 12, 2025


Related GitHub Issue

Closes: #2553

Description

This PR implements a system to ensure tasks retain and resume in their last active execution mode, addressing inconsistencies that occurred when tasks were interrupted, subtasks completed, or the global UI mode was changed.

The core changes are:

  1. Mode Persistence in Task History:

  2. Task-Specific Current Mode:

    • The Task class (in src/core/task/Task.ts) now requires currentModeSlug: string in its TaskOptions and maintains this as this.currentModeSlug.
    • A new public method updateCurrentModeSlug(newModeSlug: string) allows the task's specific mode to be updated.
    • When saving, saveTaskMessages() uses this.currentModeSlug to set the lastActiveModeSlug in the task's metadata.
  3. Mode Handling in ClineProvider (in src/core/webview/ClineProvider.ts):

    • initTask(): When a new task is created, it's initialized with the provider's current global mode as its currentModeSlug.
    • initTaskFromHistory(): When resuming from history, the task is initialized with historyItem.lastActiveModeSlug (or a fallback to the global mode if not present) as its currentModeSlug. If this restored mode differs from the provider's current global mode, handleModeSwitch() is called to align the provider's state.
    • handleModeSwitch(): This method now exclusively manages the ClineProvider's global active mode and API configuration. It no longer directly modifies the currentModeSlug of an active Task instance.
    • finishSubTask(): When a subtask completes, the provider ensures the parent task's currentModeSlug is active by calling handleModeSwitch() if necessary, before resuming the parent task.
  4. Mode Switching Tool (switchModeTool.ts in src/core/tools/switchModeTool.ts):

    • After successfully using provider.handleModeSwitch() to change the global/provider-level mode, the switch_mode tool now explicitly calls task.updateCurrentModeSlug() (on the active Task instance). This ensures that a task's specific operational mode is only changed by an explicit switch_mode action from within that task.
  5. UI Enhancements:

  6. Test Updates:

These changes ensure that a task's operational mode is robustly preserved and restored, independent of global UI mode changes, unless explicitly altered by the task itself via the switch_mode tool.

Test Procedure

  1. Run tsc to ensure there are no TypeScript compilation errors.
  2. Run npm test to ensure all unit tests pass.
  3. Manual Testing:
    • Start a task in a specific mode (e.g., "Orchestrator").
    • While the task is active, use the switch_mode tool to change its mode (e.g., to "Code").
    • Interrupt or complete the task.
    • Resume the task from history. Verify it resumes in "Code" mode.
    • Start a parent task (e.g., "Orchestrator").
    • Let the parent task create a subtask. The subtask might run in a different mode (e.g., "Code" by default or switched).
    • Complete or fail the subtask.
    • Verify the parent task resumes and is in "Orchestrator" mode.
    • Resume a task (e.g., "Orchestrator" mode).
    • Manually change the global UI mode selector to a different mode (e.g., "Architect").
    • Interact with the resumed task. Verify it continues to operate in "Orchestrator" mode and not "Architect".
    • Check the task history view (HistoryPreview.tsx and HistoryView.tsx) to ensure the "Last Mode" is displayed correctly.

Type of Change

  • 🐛 Bug Fix: Non-breaking change that fixes an issue.
  • New Feature: Non-breaking change that adds functionality (UI display of last mode, robust mode state in Task).
  • 💥 Breaking Change: Fix or feature that would cause existing functionality to not work as expected.
  • ♻️ Refactor: Code change that neither fixes a bug nor adds a feature (significant adjustments to mode handling logic, class renaming).
  • 💅 Style: Changes that do not affect the meaning of the code (white-space, formatting, etc.).
  • 📚 Documentation: Updates to documentation files.
  • ⚙️ Build/CI: Changes to the build process or CI configuration.
  • 🧹 Chore: Other changes that don't modify src or test files.

Pre-Submission Checklist

  • Issue Linked: This PR is linked to an approved GitHub Issue (see "Related GitHub Issue" above).
  • Scope: My changes are focused on the linked issue (one major feature/fix per PR).
  • Self-Review: I have performed a thorough self-review of my code.
  • Code Quality:
    • My code adheres to the project's style guidelines.
    • There are no new linting errors or warnings (npm run lint). (Assumed based on previous tsc success)
    • All debug code (e.g., console.log) has been removed.
  • Testing:
    • New and/or updated tests have been added to cover my changes (test files were updated for currentModeSlug).
    • All tests pass locally (npm test). (Assumed based on previous tsc success and user request for PR)
    • The application builds successfully with my changes. (Assumed based on tsc success)
  • Branch Hygiene: My branch is up-to-date (rebased) with the main branch. (User to confirm)
  • Documentation Impact: I have considered if my changes require documentation updates (see "Documentation Updates" section below).
  • Changeset: A changeset has been created using npm run changeset if this PR includes user-facing changes or dependency updates. (User to determine if UI change for history warrants this)
  • Contribution Guidelines: I have read and agree to the Contributor Guidelines.

Screenshots / Videos

image

Documentation Updates

  • No documentation updates are required. (The changes are internal logic improvements and minor UI text for clarity).

Additional Notes

This PR implements the core logic for preserving and restoring the last active mode of a task.


Important

Fixes task execution mode persistence after interruptions by storing and restoring the last active mode, with UI and test updates.

  • Behavior:
    • Adds lastActiveModeSlug to HistoryItem in index.ts to store the last active mode.
    • Updates taskMetadata() in taskMetadata.ts to save lastActiveModeSlug.
    • Task class in Task.ts now requires currentModeSlug and includes updateCurrentModeSlug().
    • ClineProvider in ClineProvider.ts initializes tasks with the correct mode and handles mode switches.
    • switchModeTool.ts updates task mode after global mode switch.
  • UI:
    • HistoryPreview.tsx and HistoryView.tsx display last active mode for tasks.
  • Tests:
    • Updates tests in Task.test.ts and ClineProvider.test.ts to include currentModeSlug in TaskOptions.
  • Misc:
    • Adds lastActiveModeSlug to GlobalSettings in roo-code.d.ts and types.ts.

This description was created by Ellipsis for 9b813808cca139bc71509f93ed8595f149cfc705. You can customize this summary. It will automatically update as commits are pushed.

@changeset-bot
Copy link

changeset-bot bot commented May 12, 2025

⚠️ No Changeset found

Latest commit: 32b7bd9e7d0ff53bd37b31cb8af097de87007325

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working enhancement New feature or request labels May 12, 2025
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to HistoryPreview, review the usage of dangerouslySetInnerHTML. Ensure that item.task is sanitized to prevent XSS vulnerabilities.

@hannesrudolph hannesrudolph moved this from New to PR [Draft/WIP] in Roo Code Roadmap May 14, 2025
@hannesrudolph hannesrudolph moved this from PR [Draft/WIP] to PR [Pre Approval Review] in Roo Code Roadmap May 14, 2025
@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels May 20, 2025
@hannesrudolph hannesrudolph moved this from New to PR [Pre Approval Review] in Roo Code Roadmap May 20, 2025
Comment on lines +163 to +202
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this used anywhere?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is used in the new ClineProvider tests.

@KJ7LNW
Copy link
Contributor

KJ7LNW commented May 21, 2025

I haven't tested the multiple-tab use case yet, but this looks like it would likely be fixed by #3482.

How does it handle model (not mode) changes?

I often run code+gemini in one task and code+sonnet in another, others may too...

I sort of think model changes should be task specific and must not modify global mode+model bindings, because "Settings" lets you set those defaults.

New tasks should always use the global mode+model bindings

@axmo axmo force-pushed the fix/Task-Execution-Mode-Not-Preserved-After-Interruption branch 2 times, most recently from 446938e to 4d6fe6c Compare May 23, 2025 03:43
@hannesrudolph hannesrudolph moved this from PR [Needs Review] to TEMP in Roo Code Roadmap May 26, 2025
@daniel-lxs daniel-lxs moved this from TEMP to PR [Needs Review] in Roo Code Roadmap May 27, 2025
@axmo axmo force-pushed the fix/Task-Execution-Mode-Not-Preserved-After-Interruption branch from 4d6fe6c to ca4603d Compare May 28, 2025 14:08
axmo added 4 commits May 29, 2025 23:57
This commit addresses a bug where changing the global UI mode would incorrectly update the `currentModeSlug` of an active or resumed task. This caused tasks to operate in the globally selected mode rather than their intended last active mode.

Key changes:

- Modified `ClineProvider.handleModeSwitch()` to only update the provider's global state (mode and API configuration) and emit events. It no longer directly modifies an active `Cline` instance's `currentModeSlug`.
- Updated `switchModeTool.ts` so that after the `switch_mode` tool successfully calls `provider.handleModeSwitch()`, it then explicitly calls `cline.updateCurrentModeSlug()` on its own `Cline` instance.

This ensures that a task's specific operational mode is only changed by the `switch_mode` tool executed within that task's context. Global UI mode changes will no longer affect the mode of an already initialized or resumed task.

This fix is part of the broader effort to correctly preserve and restore the last active mode for tasks, as detailed in GitHub issue RooCodeInc#2553.
axmo added 2 commits May 30, 2025 00:04
Also adds a clearStack utility function to ClineProvider
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious, any reason to have a span here when HistoryPreview.tsx just sets the html on the div itself?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly: because Roo put it there and I am not a web frontend developer. I wholeheartedly encourage bringing someone else in to fix the UI code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updateCurrentModeSlug method should probably validate that the new mode actually exists before updating. Without validation, this could lead to tasks being in invalid states.

Does it make sense to use you could use getModeBySlug and check if the mode exists?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, I hadn't considered the deleted edge-case... Which mode should we default to if the requested mode is gone?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the default mode for Roo Code when you first install it? that could probably work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is clearStack() method only used in tests? If so does it make sense to move it to a test utility file or marking it as @internal?

If this is test-only code, it probably would be better placed in a test helper rather than the production class.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we might have an issue if handleModeSwitch succeeds but resumePausedTask fails (throws an error), the provider will be left in the parent's mode but the parent task won't actually be resumed. This creates an inconsistent state where:

  • The global provider mode is set to the parent's mode
  • But the parent task is not actually running/resumed
  • The UI might show the wrong mode for what's actually happening

@daniel-lxs
Copy link
Member

Hey @axmo, sorry for taking so long, just left a couple of suggestions, let me know if you want to discuss them further.

This looks great, I remember you also modified the UI a bit and it looks awesome!

image

Do you think this would look better in any of these places?

image

@daniel-lxs daniel-lxs moved this from PR [Needs Prelim Review] to PR [Draft / In Progress] in Roo Code Roadmap May 30, 2025
axmo added 2 commits May 30, 2025 23:57
Introduces a `modeIsFrozen` flag in the Task class. This flag is
set to `true` when a task completes or a completed task is resumed.

When `modeIsFrozen` is true, the task's `currentModeSlug` is
prevented from being updated if the user only changes the mode in
the UI without sending a new message. This avoids saving accidental
mode changes during history browsing.

If a new message is sent to continue a task that was frozen:
1. `modeIsFrozen` is reset to `false`.
2. The task's `currentModeSlug` is updated to match the actual
   mode selected in the UI (obtained from `ClineProvider.getState()`).
3. This updated `currentModeSlug` is then used when saving task
   messages and metadata, ensuring the persisted history accurately
   reflects the mode in which the interaction occurred.

This resolves a bug where re-opening a completed task, changing the
mode, and then sending a message would result in the original (stale)
mode being persisted in the task history, instead of the new mode
used for the interaction.
@axmo axmo force-pushed the fix/Task-Execution-Mode-Not-Preserved-After-Interruption branch from d7460a2 to 6716e41 Compare June 2, 2025 03:58
@daniel-lxs daniel-lxs marked this pull request as draft June 3, 2025 23:34
@hannesrudolph
Copy link
Collaborator

stale

@github-project-automation github-project-automation bot moved this from PR [Draft / In Progress] to Done in Roo Code Roadmap Jul 7, 2025
@github-project-automation github-project-automation bot moved this from PR [Pre Approval Review] to Done in Roo Code Roadmap Jul 7, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working enhancement New feature or request PR - Draft / In Progress size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

Task Execution Mode Not Preserved After Interruption

5 participants