feat(workflow)!: implement inline mode with visual indicators and interrupt recovery - #232
Conversation
… content Refactor spawnSubagent to produce clean output for ralph review-fix loops by instructing the sub-agent to return only its raw output without additional commentary. Hide stream content during sub-agent execution to prevent intermediate steps from polluting the chat UI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reset ralph session state (session dir, session id, task ids, todo items) on /clear and non-ralph slash commands for Copilot agent only. Guard existing ralph panel dismissal on regular messages with agentType check to prevent unintended resets for other agent types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Updated borderColor to conditionally use accent color (teal) when workflowActive is true - Falls back to inputFocus color when workflow is inactive - Single-line change at line 5688 in src/ui/chat.tsx
Tasks #6 and #7: - Remove clearContext() call before review iteration (line 684) - Remove clearContext() call before fix-spec decomposition (line 734) - Update test to remove assertion on clearContext() being called - Maintains context continuity throughout Ralph workflow - All workflow-commands tests passing (14 tests, 32 assertions)
- Add test for workflow completion returning stateUpdate with workflowActive: false - Add test for waitForUserInput presence in CommandContext interface - Add test for mock waitForUserInput resolving with a string - Add test verifying clearContext is not called during workflow execution - Add test for interrupted step1 returning stateUpdate to deactivate workflow All tests pass and typecheck succeeds.
- Test #16: Ralph end-to-end without clearContext calls - Verifies clearContext is never called during full workflow - Tests complete workflow with review and fix cycles - Confirms stateUpdate.workflowActive is false on completion - Test #17: User prompt passthrough after Ctrl+C in workflow - Simulates Ctrl+C interruption during implementation - Verifies waitForUserInput is called to get user's follow-up prompt - Confirms user's prompt is passed to the next streamAndWait call - Test #18: Task list persists after Ctrl+C, hides on completion - Verifies setRalphSessionDir is called with non-null path at start - Confirms session dir is NOT cleared (null) during workflow - Validates stateUpdate.workflowActive is false to signal UI to hide task list
Add comprehensive E2E tests validating the complete lifecycle of the /ralph workflow in inline mode: - Test #19: Teal border lifecycle during /ralph workflow - Verifies workflowActive state drives teal border - Tracks updateWorkflowState calls throughout lifecycle - Validates border returns to normal after completion - Test #20: Ctrl+C + user prompt + workflow continuation E2E - Full lifecycle: decomposition → Ctrl+C → user input → continuation - Verifies waitForUserInput() mechanism - Validates workflow continues with user's prompt - Confirms clean completion after interruption - Test #21: Task list persistence and tasks.json maintenance - Verifies session dir creation and persistence - Validates tasks.json is written and updated correctly - Confirms task tracking through interruption - Ensures final state reflects all completed tasks All tests follow the existing E2E test pattern from background-agent-e2e.test.ts and use the same createMockContext pattern from workflow-commands.test.ts. Tests validate multiple concerns across the workflow lifecycle: - State management (workflowActive, workflowType) - User intervention handling (Ctrl+C, waitForUserInput) - Task persistence (tasks.json, session directory) - Review integration (clean review with no findings) - Cleanup behavior (stateUpdate signals UI reset) All 1426 tests pass including 3 new E2E tests. No type errors.
Fixes stale closure issue in useEffect hook that auto-hides task list panel when workflow ends. The effect references ralphSessionDir in its body but was missing it from the dependency array, causing React to use stale values. Changed line 2685 to include ralphSessionDir in dependencies: [workflowState.workflowActive, ralphSessionDir] Testing: - TypeScript compilation: ✅ Passed - All tests: ✅ Passed (1426 tests, 9410 assertions)
- Display workflow type (e.g., 'plan') instead of generic 'workflow' - Add 'shift+tab switch mode' hint for user guidance - Style label in teal accent color to match workflow theme - Show label when workflow is active and not streaming
Remove separator and 'shift+tab switch mode' hint from the workflow mode label, keeping only the workflow type indicator. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assistant-model: GitHub Copilot
Collapse single newlines to spaces (standard markdown soft-break behavior) while preserving code fences and paragraph breaks. OpenTUI renders literal \n as hard line breaks unlike HTML, so this normalization is needed for correct paragraph rendering. Apply normalizeMarkdownNewlines to both text and reasoning part displays. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Rework Ctrl+C behavior during workflows: single Ctrl+C interrupts the current stream while keeping the workflow alive (waits for user input), double Ctrl+C cancels the workflow entirely. - Change waitForUserInputResolverRef to support reject for cancellation - Add wasCancelled flag to StreamResult interface - ESC during workflow only interrupts the stream, no longer cancels - Show streaming hints (esc/ctrl+q) in workflow mode bar when idle - Handle "Workflow cancelled" error silently in workflow catch block Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Handle interruptions consistently across planning, execution, and review loops by waiting for user input and resuming the stream. Update workflow status hints and tests to reflect cancel-versus-interrupt behavior. Assistant-model: openai/gpt-5.3-codex
PR Review: Workflow SDK Inline Mode ImplementationThis PR implements a significant enhancement to the workflow system, adding visual mode indicators (teal border), double Ctrl+C workflow exit, user prompt passthrough after interruption, and removal of ✅ Code Quality & Best PracticesStrengths:
Suggestions:
|
| Aspect | Rating |
|---|---|
| Code Quality | ⭐⭐⭐⭐ |
| Test Coverage | ⭐⭐⭐⭐⭐ |
| Documentation | ⭐⭐⭐⭐⭐ |
| Performance | ⭐⭐⭐ |
| Security | ⭐⭐⭐⭐⭐ |
Overall: This is a well-structured PR with good documentation and test coverage. The main concerns are around potential edge cases with the waitForUserInput promise lifecycle and some duplicated code that could be refactored. The removal of clearContext() calls is a significant behavioral change that should be validated in manual testing to ensure the reviewer sub-agent still functions correctly with the full conversation context.
Recommendation: Approve with minor suggestions. Consider addressing the waitForUserInput cleanup and duplicated workflow termination logic before merging.
* fix(chat): ensure clean sub-agent output and hide intermediate stream content Refactor spawnSubagent to produce clean output for ralph review-fix loops by instructing the sub-agent to return only its raw output without additional commentary. Hide stream content during sub-agent execution to prevent intermediate steps from polluting the chat UI. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(chat): scope ralph state reset to copilot agent type Reset ralph session state (session dir, session id, task ids, todo items) on /clear and non-ralph slash commands for Copilot agent only. Guard existing ralph panel dismissal on regular messages with agentType check to prevent unintended resets for other agent types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat(ui): change chat input border to teal when workflow is active - Updated borderColor to conditionally use accent color (teal) when workflowActive is true - Falls back to inputFocus color when workflow is inactive - Single-line change at line 5688 in src/ui/chat.tsx * refactor(ralph): remove clearContext() calls from workflow Tasks #6 and #7: - Remove clearContext() call before review iteration (line 684) - Remove clearContext() call before fix-spec decomposition (line 734) - Update test to remove assertion on clearContext() being called - Maintains context continuity throughout Ralph workflow - All workflow-commands tests passing (14 tests, 32 assertions) * test(workflow): add unit tests for workflow inline mode changes - Add test for workflow completion returning stateUpdate with workflowActive: false - Add test for waitForUserInput presence in CommandContext interface - Add test for mock waitForUserInput resolving with a string - Add test verifying clearContext is not called during workflow execution - Add test for interrupted step1 returning stateUpdate to deactivate workflow All tests pass and typecheck succeeds. * test(workflow): add 3 integration tests for workflow inline mode - Test #16: Ralph end-to-end without clearContext calls - Verifies clearContext is never called during full workflow - Tests complete workflow with review and fix cycles - Confirms stateUpdate.workflowActive is false on completion - Test #17: User prompt passthrough after Ctrl+C in workflow - Simulates Ctrl+C interruption during implementation - Verifies waitForUserInput is called to get user's follow-up prompt - Confirms user's prompt is passed to the next streamAndWait call - Test #18: Task list persists after Ctrl+C, hides on completion - Verifies setRalphSessionDir is called with non-null path at start - Confirms session dir is NOT cleared (null) during workflow - Validates stateUpdate.workflowActive is false to signal UI to hide task list * test(workflow): add 3 E2E tests for workflow inline mode Add comprehensive E2E tests validating the complete lifecycle of the /ralph workflow in inline mode: - Test #19: Teal border lifecycle during /ralph workflow - Verifies workflowActive state drives teal border - Tracks updateWorkflowState calls throughout lifecycle - Validates border returns to normal after completion - Test #20: Ctrl+C + user prompt + workflow continuation E2E - Full lifecycle: decomposition → Ctrl+C → user input → continuation - Verifies waitForUserInput() mechanism - Validates workflow continues with user's prompt - Confirms clean completion after interruption - Test #21: Task list persistence and tasks.json maintenance - Verifies session dir creation and persistence - Validates tasks.json is written and updated correctly - Confirms task tracking through interruption - Ensures final state reflects all completed tasks All tests follow the existing E2E test pattern from background-agent-e2e.test.ts and use the same createMockContext pattern from workflow-commands.test.ts. Tests validate multiple concerns across the workflow lifecycle: - State management (workflowActive, workflowType) - User intervention handling (Ctrl+C, waitForUserInput) - Task persistence (tasks.json, session directory) - Review integration (clean review with no findings) - Cleanup behavior (stateUpdate signals UI reset) All 1426 tests pass including 3 new E2E tests. No type errors. * fix(workflow): wrap execute body in try-catch to reset workflowActive on error * fix(chat): add ralphSessionDir to useEffect dependency array Fixes stale closure issue in useEffect hook that auto-hides task list panel when workflow ends. The effect references ralphSessionDir in its body but was missing it from the dependency array, causing React to use stale values. Changed line 2685 to include ralphSessionDir in dependencies: [workflowState.workflowActive, ralphSessionDir] Testing: - TypeScript compilation: ✅ Passed - All tests: ✅ Passed (1426 tests, 9410 assertions) * feat(ui): add workflow mode label with type and keyboard hint - Display workflow type (e.g., 'plan') instead of generic 'workflow' - Add 'shift+tab switch mode' hint for user guidance - Style label in teal accent color to match workflow theme - Show label when workflow is active and not streaming * fix(ui): simplify workflow mode label Remove separator and 'shift+tab switch mode' hint from the workflow mode label, keeping only the workflow type indicator. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Assistant-model: GitHub Copilot * fix(ui): normalize markdown newlines for terminal rendering Collapse single newlines to spaces (standard markdown soft-break behavior) while preserving code fences and paragraph breaks. OpenTUI renders literal \n as hard line breaks unlike HTML, so this normalization is needed for correct paragraph rendering. Apply normalizeMarkdownNewlines to both text and reasoning part displays. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * refactor(workflow): improve interrupt and cancellation handling Rework Ctrl+C behavior during workflows: single Ctrl+C interrupts the current stream while keeping the workflow alive (waits for user input), double Ctrl+C cancels the workflow entirely. - Change waitForUserInputResolverRef to support reject for cancellation - Add wasCancelled flag to StreamResult interface - ESC during workflow only interrupts the stream, no longer cancels - Show streaming hints (esc/ctrl+q) in workflow mode bar when idle - Handle "Workflow cancelled" error silently in workflow catch block Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(workflow): recover /ralph flow after interrupted streams Handle interruptions consistently across planning, execution, and review loops by waiting for user input and resuming the stream. Update workflow status hints and tests to reflect cancel-versus-interrupt behavior. Assistant-model: openai/gpt-5.3-codex --------- Co-authored-by: lavaman131 <dev@example.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Summary
This PR implements a comprehensive workflow inline mode experience that provides clear visual feedback, improved interrupt handling, and context preservation throughout workflow execution. Users can now interrupt and redirect workflows mid-execution without losing orchestration state.
Key Changes
🎨 Visual Indicators
themeColors.accent)⌨️ Improved Interrupt Handling
💾 Context Preservation
clearContext()calls from Ralph workflow (src/ui/commands/workflow-commands.ts:684,734)🐛 Bug Fixes
workflowActiveon workflow failuresBreaking Changes
Testing
Related Documentation
specs/workflow-sdk-inline-mode.mdresearch/docs/2026-02-21-workflow-sdk-inline-mode-research.md