Skip to content

refactor: Make agent mode interruptions more robust#516

Merged
dwash96 merged 9 commits into
cecli-dev:v0.100.0from
szmania:cli-22-robust-interruption
May 19, 2026
Merged

refactor: Make agent mode interruptions more robust#516
dwash96 merged 9 commits into
cecli-dev:v0.100.0from
szmania:cli-22-robust-interruption

Conversation

@szmania
Copy link
Copy Markdown

@szmania szmania commented May 18, 2026

Summary

This PR makes agent mode interruptions more robust by ensuring that long-running operations (linting, command execution, streaming responses, and LLM completion calls) can be properly interrupted via the existing interrupt_event mechanism.

Changes

Core Interruption Infrastructure

  • cecli/helpers/coroutines.py: Added interruptible_async_generator() - a utility that wraps async generators to make them interruptible via an asyncio.Event, enabling cancellation of streaming LLM responses mid-generation.

Linting (cecli/linter.py)

  • Made Linter.lint(), Linter.run_cmd(), Linter.py_lint(), and Linter.flake8_lint() all async so they can be interrupted.
  • Linter now accepts an interrupt_event parameter and uses run_cmd_async instead of blocking subprocess.run() calls.
  • When interrupted during linting, returns None (graceful handling) instead of crashing.

Command Execution (cecli/run_cmd.py)

  • Added run_cmd_async() - an async version of run_cmd that uses asyncio.create_subprocess_shell and monitors an interrupt_event to terminate processes early when interrupted.

Agent Coder (cecli/coders/agent_coder.py)

  • Linting in the agent loop now uses coroutines.interruptible() to allow interruption.
  • Waiting for background commands now uses coroutines.interruptible() instead of a blocking asyncio.sleep().

Base Coder (cecli/coders/base_coder.py)

  • Streaming responses: The show_send_output_stream() method now wraps the async generator with interruptible_async_generator(), allowing Ctrl+C to interrupt streaming LLM responses mid-generation.
  • Message formatting: Uses coroutines.interruptible() to allow interruption during format_messages().
  • Lint editing: lint_edited() is now async and handles asyncio.CancelledError gracefully.
  • Run commands: Uses run_cmd_async() instead of asyncio.to_thread(run_cmd, ...) for interruptible command execution.

Run Command (cecli/commands/run.py)

  • Switched from asyncio.to_thread(run_cmd, ...) to run_cmd_async() for interruptible execution.

Models (cecli/models.py)

  • LLM completion calls (litellm.acompletion) now use coroutines.interruptible() to allow interruption during API calls.

Testing

  • All existing tests pass.
  • Manual testing confirms Ctrl+C properly interrupts linting, command execution, and streaming responses in agent mode.

Your Name added 9 commits May 15, 2026 11:42
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
Co-authored-by: cecli (openai/gemini_cli_local/gemini-2.5-pro)
@dwash96 dwash96 merged commit a383202 into cecli-dev:v0.100.0 May 19, 2026
1 check passed
@dwash96 dwash96 mentioned this pull request May 19, 2026
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.

2 participants