Skip to content

Commit 1de59f8

Browse files
jwesleyeclaude
andcommitted
fix: properly clean up thinking task on CTRL-C
Fixes issue where pressing CTRL-C during agent processing would not exit cleanly. The thinking indicator task was not being cancelled because KeyboardInterrupt doesn't inherit from Exception. Problem: - KeyboardInterrupt inherits from BaseException, not Exception - The `except Exception as e:` block didn't catch KeyboardInterrupt - Thinking task kept running in background after CTRL-C - Process appeared to hang or not exit fully Solution: - Added `finally` block to _stream_agent_response() - Always cancels and awaits the thinking task cleanup - Properly handles CancelledError from task cancellation - Ensures clean exit even when interrupted Testing: All 273 tests passing 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent a0bb0b0 commit 1de59f8

1 file changed

Lines changed: 10 additions & 5 deletions

File tree

src/basic_agent_chat_loop/chat_loop.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -935,11 +935,6 @@ async def _stream_agent_response(self, query: str) -> Dict[str, Any]:
935935
return {"duration": duration, "usage": usage_info}
936936

937937
except Exception as e:
938-
# Cleanup thinking indicator on error
939-
stop_thinking.set()
940-
if thinking_task and not thinking_task.done():
941-
await thinking_task
942-
943938
duration = time.time() - start_time
944939
print(f"\n{Colors.DIM}{'-' * 60}{Colors.RESET}")
945940
print(Colors.error(f"{self.agent_name}: Query failed - {e}"))
@@ -954,6 +949,16 @@ async def _stream_agent_response(self, query: str) -> Dict[str, Any]:
954949

955950
return {"duration": duration, "usage": None}
956951

952+
finally:
953+
# Always cleanup thinking indicator, even on KeyboardInterrupt
954+
stop_thinking.set()
955+
if thinking_task and not thinking_task.done():
956+
thinking_task.cancel()
957+
try:
958+
await thinking_task
959+
except asyncio.CancelledError:
960+
pass # Expected when cancelling
961+
957962
async def process_query(self, query: str):
958963
"""Process query through agent with streaming and error recovery."""
959964
for attempt in range(1, self.max_retries + 1):

0 commit comments

Comments
 (0)