Skip to content

Conversation

@latent-variable
Copy link

Summary

  • add a pause flag to the Agent so ESC can stop a run mid-step without discarding the log or step counter; the next agent.run() resumes from the original step until the task finishes or errors
  • introduce an EscapeKeyListener in the CLI that switches the terminal to cbreak mode (when supported) and watches for ESC via asyncio.add_reader, calling agent.request_stop() as soon as the key is pressed
  • document the new shortcut in /help so users know they can press ESC to halt long tool runs while keeping the session alive

Testing

  • manual: invoked mini-agent, kicked off a multi-step task, pressed ESC mid-run, observed "Agent paused" message and that the next command resumed at the prior step rather than starting over
  • manual: after completion, confirmed the prompt immediately reappears (no blank line requiring extra typing)

@AkairoDev
Copy link
Collaborator

AkairoDev commented Nov 18, 2025

Thanks for this PR! The ESC interrupt feature is very useful. However, there's a potential issue when ESC is pressed during tool execution:

Problem: If the user presses ESC after assistant message with tool_calls is added to history but before all tool results are collected, the conversation history becomes incomplete:

Incomplete state:
Message(role="assistant", tool_calls=[call1, call2, call3]) # Added at line 316
Message(role="tool", tool_call_id=call1.id, ...) # call1 executed

call2 and call3 missing ❌This will cause the next LLM call to fail since most LLM APIs require each tool_call to have a corresponding tool result message.

Suggestion: Don't check stop request during tool execution loop (lines 332-404). Only check at safe checkpoints:

  • Before LLM call (line 288)
  • After all tool results are collected (line 405)

This ensures conversation history integrity while adding minimal delay (most tools execute in <1s).

Please add test cases in tests/ to verify ESC interrupt behavior and conversation history integrity after interruption.

@latent-variable
Copy link
Author

Addressed the cache/history issue AkairoDev pointed out:

  • Agent now finishes executing every tool call before honoring ESC, so each assistant tool_call list always has matching tool messages.
  • Pause/resume state lives entirely inside the agent; resuming reuses the existing log/step without injecting extra content, so deterministic caching is unaffected.
  • Added regression tests in tests/test_agent_interrupts.py that:
    • pause after the first tool result and verify both tool messages exist in history
    • resume the same run and ensure it completes (no duplicate tool calls).

Let me know if you want me to expand coverage further, but the current suite demonstrates both conversation integrity and successful resumption.

@AkairoDev
Copy link
Collaborator

Thank you so much for this PR and the thoughtful implementation! 🙏
We really appreciate you taking the time to add ESC interrupt support - it's a feature we've been thinking about, and your approach of preserving tool batches and maintaining state for resumption is well-designed.
After testing the implementation, we've identified a couple of areas that need further consideration:
Windows Compatibility: The current implementation relies on termios/tty which aren't available on Windows. We'd like to ensure a consistent cross-platform experience for all our users.
Responsiveness: The interrupt mechanism needs to wait for the current operation to complete before responding, which can create a noticeable lag. We'd like to explore approaches that provide more immediate feedback to users when they request a pause.
Given these considerations, we're planning to implement an official version that addresses these concerns. We'll definitely reference your implementation and the valuable patterns you've established here - particularly around state management and graceful resumption.
Thanks again for your contribution and for helping us think through this feature! We truly appreciate community involvement like this. 🎉
If you have any thoughts or suggestions on the implementation approach, we'd love to hear them!

@latent-variable
Copy link
Author

Totally understand—really appreciate you digging into it. I’m glad the state-management approach was useful, and I’m looking forward to seeing the official cross-platform version land. Happy to help test early builds or experiment with alternate signaling strategies if that’s helpful. Thanks again for the thoughtful review!

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