Skip to content

Conversation

@roomote
Copy link

@roomote roomote bot commented Oct 30, 2025

This PR attempts to address Issue #8935 by adding automatic mode switching and command execution after task completion.

Summary

This enhancement adds the ability for modes to define automatic actions that should occur when a task completes. Users can configure modes to automatically:

  • Switch to another mode
  • Execute a slash command or other command
  • Include task completion summary as context

Implementation

Changes Made

  1. Added onComplete field to ModeConfig type (packages/types/src/mode.ts)

    • switchToMode: Optional mode to switch to after completion
    • runCommand: Optional command to execute after completion
    • includeSummary: Whether to include task result as context for the command
  2. Updated attemptCompletionTool (src/core/tools/attemptCompletionTool.ts)

    • Checks for onComplete configuration in current mode
    • Executes mode switch if specified
    • Executes command if specified, optionally with task summary
  3. Added comprehensive tests (src/core/tools/__tests__/attemptCompletionTool.spec.ts)

    • Tests for automatic mode switching
    • Tests for command execution with/without summary
    • Tests for combined mode switch and command execution
    • Tests for graceful error handling

Use Cases

This feature enables several workflow improvements:

  • Architect mode can automatically switch to Code mode after planning
  • Code mode can automatically run a review command after implementation
  • Debug mode can switch back to Code mode after diagnosis
  • Custom modes can chain together complex workflows

Testing

All new functionality is covered by unit tests. The implementation gracefully handles errors and does not break task completion if onComplete actions fail.

Fixes #8935

Feedback and guidance are welcome!


Important

Adds automatic mode switching and command execution on task completion with configurable onComplete actions in ModeConfig.

  • Behavior:
    • Adds onComplete field to ModeConfig in mode.ts with switchToMode, runCommand, and includeSummary options.
    • Updates attemptCompletionTool in attemptCompletionTool.ts to execute onComplete actions: mode switch, command execution, and optional summary inclusion.
  • Testing:
    • Adds tests in attemptCompletionTool.spec.ts for mode switching, command execution, summary inclusion, and error handling.
    • Tests cover scenarios with and without onComplete configurations and provider availability.

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

- Add onComplete field to ModeConfig type with switchToMode, runCommand, and includeSummary options
- Update attemptCompletionTool to check for and execute onComplete actions after task completion
- Add comprehensive tests for automatic mode switching and command execution
- Allow modes to define actions that should be taken automatically when a task completes

Fixes #8935
@roomote roomote bot requested review from cte, jr and mrubens as code owners October 30, 2025 18:36
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Oct 30, 2025
@roomote
Copy link
Author

roomote bot commented Oct 30, 2025

Review Summary

I've reviewed the changes and identified 3 issues that need to be addressed:

Issues Found

  • Line 103: Uses current provider mode instead of task's mode - should use await cline.getTaskMode() to get the task's actual mode, not state?.mode
  • Lines 491-524: Tests don't verify the correct mode is used - should add assertions to verify getModeConfig is called with the task's mode
  • Lines 99-143: onComplete actions execute for subtasks - should guard with if (!cline.parentTask) to prevent subtasks from executing mode switches

Key Concerns

  1. Mode Mismatch Bug: The implementation retrieves the current provider mode from state instead of using the task's stored mode. This breaks the fundamental design where tasks preserve their mode across sessions.

  2. Subtask Interference: Subtasks will execute their mode's onComplete actions before returning control to their parent task, potentially causing unexpected mode switches or command executions that interfere with the parent task's workflow.

  3. Test Coverage Gap: The tests mock inconsistent state (provider mode vs task mode) which masks the mode retrieval bug.

Follow Along on Roo Code Cloud


// Execute mode switch if specified
if (switchToMode) {
await cline.say("text", `Automatically switching to ${switchToMode} mode as configured...`)
Copy link

Choose a reason for hiding this comment

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

The user-facing messages for automatic actions (e.g. 'Automatically switching to ... mode as configured...' and 'Automatically executing command: ...') are hardcoded. Consider using an internationalization function (like t()) to support localization of these messages.

This comment was generated because it violated a code review rule: irule_C0ez7Rji6ANcGkkX.

const provider = cline.providerRef.deref()
if (provider) {
const state = await provider.getState()
const currentMode = state?.mode || "code"
Copy link
Author

Choose a reason for hiding this comment

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

The implementation uses the current provider mode (state?.mode) instead of the task's mode. This is incorrect because a task stores its own mode when created, and the onComplete configuration should be based on the mode the task was running in, not the current provider mode (which could be different if the user manually switched modes). Change to: const currentMode = await cline.getTaskMode() to use the task's actual mode.

Comment on lines +491 to +524
it("should execute mode switch when onComplete.switchToMode is configured", async () => {
const block: AttemptCompletionToolUse = {
type: "tool_use",
name: "attempt_completion",
params: { result: "Task completed successfully" },
partial: false,
}

// Configure mode with onComplete.switchToMode
vi.mocked(getModeConfig).mockReturnValue({
slug: "architect",
name: "Architect",
roleDefinition: "Test role",
groups: ["read", "edit"],
onComplete: {
switchToMode: "code",
},
} as ModeConfig)

await attemptCompletionTool(
mockTask as Task,
block,
mockAskApproval,
mockHandleError,
mockPushToolResult,
mockRemoveClosingTag,
mockToolDescription,
mockAskFinishSubTaskApproval,
)

// Verify mode switch was called
expect(mockHandleModeSwitch).toHaveBeenCalledWith("code")
expect(mockSay).toHaveBeenCalledWith("text", "Automatically switching to code mode as configured...")
})
Copy link
Author

Choose a reason for hiding this comment

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

The tests mock getState() to return mode: "code" but then use getModeConfig to return different mode configurations. This creates an inconsistency that masks the bug in line 103 where the implementation uses state?.mode instead of cline.getTaskMode(). The tests should verify that getModeConfig is called with the task's mode, not the provider's current mode. Consider adding: expect(getModeConfig).toHaveBeenCalledWith(await mockTask.getTaskMode(), customModes)

Comment on lines +99 to +143
// Check for onComplete actions in the current mode configuration
const provider = cline.providerRef.deref()
if (provider) {
const state = await provider.getState()
const currentMode = state?.mode || "code"
const customModes = state?.customModes || []

try {
const modeConfig = getModeConfig(currentMode, customModes)

if (modeConfig.onComplete) {
const { switchToMode, runCommand, includeSummary } = modeConfig.onComplete

// Prepare context for onComplete actions
const context = includeSummary ? result : undefined

// Execute mode switch if specified
if (switchToMode) {
await cline.say("text", `Automatically switching to ${switchToMode} mode as configured...`)
await provider.handleModeSwitch(switchToMode)
}

// Execute command if specified
if (runCommand) {
await cline.say("text", `Automatically executing command: ${runCommand}`)

// Create a new message with the command, optionally including the summary
let commandMessage = runCommand
if (context) {
commandMessage = `${runCommand}\n\nContext from previous task:\n${context}`
}

// Send the command as a new user message
await provider.postMessageToWebview({
type: "invoke",
invoke: "sendMessage",
text: commandMessage,
})
}
}
} catch (error) {
// Log error but don't fail the completion
console.error("Failed to execute onComplete actions:", error)
}
}
Copy link
Author

Choose a reason for hiding this comment

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

The onComplete actions execute before checking if this is a subtask completion (which happens at line 145). This means subtasks will execute their mode's onComplete actions, potentially interfering with the parent task's flow. For example, if a subtask in Code mode has onComplete.switchToMode: "architect", it would switch modes instead of returning control to the parent task. The onComplete logic should be guarded with if (!cline.parentTask) to only execute for top-level tasks, not subtasks.

@daniel-lxs
Copy link
Member

#8935 (comment)

@daniel-lxs daniel-lxs closed this Oct 30, 2025
@github-project-automation github-project-automation bot moved this from New to Done in Roo Code Roadmap Oct 30, 2025
@github-project-automation github-project-automation bot moved this from Triage to Done in Roo Code Roadmap Oct 30, 2025
@hannesrudolph hannesrudolph added the Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. label Oct 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request Issue/PR - Triage New issue. Needs quick review to confirm validity and assign labels. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[ENHANCEMENT] Add automatic mode switch / slash command after task completion

4 participants