Skip to content

Conversation

@tcdent
Copy link
Owner

@tcdent tcdent commented Feb 3, 2026

This commit fixes several bugs that could occur when cancelling a task:

  1. Effect queue not cleared on cancel: Pending effects remained in the
    queue after cancel, which could lead to effects being processed after
    the turn was already finished.

  2. Stage not cleared on cancel: Blocks that were in the Stage awaiting
    approval remained orphaned after cancel.

  3. Tool executor not cancelled: The cancel() function only cancelled
    the agent's streaming, not the tool executor's active pipelines.

  4. Panic in start_block after finish_turn: If decide_pending_tool was
    called after the turn was finished (e.g., due to race conditions),
    start_block would panic with "No active turn".

Changes:

  • Add EffectQueue::clear() method to drop all pending effects
  • Add Transcript::has_active_turn() method to check turn state
  • Add Transcript::try_start_block() method that returns false instead of
    panicking when no turn is active
  • Update App::cancel() to:
    • Cancel the tool executor
    • Clear the effect queue
    • Drain orphaned blocks from the stage
  • Update decide_pending_tool() to use try_start_block() instead of
    start_block() for defensive safety
  • Add comprehensive tests for cancellation scenarios

https://claude.ai/code/session_0198d69SpWL6JAZo8nu3fpMN

This commit fixes several bugs that could occur when cancelling a task:

1. **Effect queue not cleared on cancel**: Pending effects remained in the
   queue after cancel, which could lead to effects being processed after
   the turn was already finished.

2. **Stage not cleared on cancel**: Blocks that were in the Stage awaiting
   approval remained orphaned after cancel.

3. **Tool executor not cancelled**: The cancel() function only cancelled
   the agent's streaming, not the tool executor's active pipelines.

4. **Panic in start_block after finish_turn**: If decide_pending_tool was
   called after the turn was finished (e.g., due to race conditions),
   start_block would panic with "No active turn".

Changes:
- Add EffectQueue::clear() method to drop all pending effects
- Add Transcript::has_active_turn() method to check turn state
- Add Transcript::try_start_block() method that returns false instead of
  panicking when no turn is active
- Update App::cancel() to:
  - Cancel the tool executor
  - Clear the effect queue
  - Drain orphaned blocks from the stage
- Update decide_pending_tool() to use try_start_block() instead of
  start_block() for defensive safety
- Add comprehensive tests for cancellation scenarios

https://claude.ai/code/session_0198d69SpWL6JAZo8nu3fpMN
When a user presses Esc to cancel a running tool, the shell process
is now properly killed instead of being left running in the background.

Changes:
- Add CancellationToken and CancellationSource types to pipeline.rs
  for cooperative cancellation between the executor and handlers
- Update EffectHandler trait to accept CancellationToken parameter
- Update all handler implementations to accept the token (most ignore it)
- Update Shell handler to pass the token to execute_shell
- Update execute_shell in io.rs to use tokio::select! to monitor both
  the child process and the cancellation token, killing the process
  when cancellation is requested
- Update ToolExecutor to create cancellation sources for each pipeline
  and trigger them in cancel()
- Update README.md with new handler signature

The cancellation flow:
1. User presses Esc → App::cancel() is called
2. App calls tool_executor.cancel()
3. Executor triggers cancel_source.cancel() for all active pipelines
4. Running handlers receive the signal via their CancellationToken
5. Shell handler's execute_shell uses select! to detect cancellation
6. Child process is killed with child.kill()

https://claude.ai/code/session_0198d69SpWL6JAZo8nu3fpMN
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants