|
16 | 16 | from cecli.helpers import nested, responses |
17 | 17 | from cecli.helpers.background_commands import BackgroundCommandManager |
18 | 18 | from cecli.helpers.conversation import ConversationService, MessageTag |
| 19 | +from cecli.helpers.coroutines import interruptible |
19 | 20 | from cecli.helpers.similarity import ( |
20 | 21 | cosine_similarity, |
21 | 22 | create_bigram_vector, |
@@ -301,25 +302,15 @@ async def _execute_local_tool_calls(self, tool_calls_list): |
301 | 302 | else: |
302 | 303 | all_results_content.append(f"Error: Unknown tool name '{tool_name}'") |
303 | 304 | if tasks: |
304 | | - gather_future = asyncio.gather(*tasks, return_exceptions=True) |
305 | | - interrupt_task = asyncio.create_task(self.interrupt_event.wait()) |
306 | | - |
307 | | - done, pending = await asyncio.wait( |
308 | | - {gather_future, interrupt_task}, |
309 | | - return_when=asyncio.FIRST_COMPLETED, |
| 305 | + gather_coro = asyncio.gather(*tasks, return_exceptions=True) |
| 306 | + task_results, interrupted = await interruptible( |
| 307 | + gather_coro, self.interrupt_event |
310 | 308 | ) |
311 | 309 |
|
312 | | - if interrupt_task in done: |
313 | | - gather_future.cancel() |
314 | | - try: |
315 | | - await gather_future |
316 | | - except asyncio.CancelledError: |
317 | | - pass |
| 310 | + if interrupted: |
318 | 311 | self.io.tool_warning("Tool execution interrupted.") |
319 | | - # Append a message indicating interruption |
320 | 312 | all_results_content.append("Tool execution interrupted by user.") |
321 | | - else: |
322 | | - task_results = gather_future.result() |
| 313 | + elif task_results: |
323 | 314 | for res in task_results: |
324 | 315 | if isinstance(res, Exception): |
325 | 316 | all_results_content.append(f"Error in tool execution: {res}") |
@@ -415,24 +406,11 @@ async def _exec_async(): |
415 | 406 | """) |
416 | 407 | return f"Error executing tool call {tool_name}: {e}" |
417 | 408 |
|
418 | | - exec_future = asyncio.create_task(_exec_async()) |
419 | | - interrupt_task = asyncio.create_task(self.interrupt_event.wait()) |
420 | | - |
421 | | - done, pending = await asyncio.wait( |
422 | | - {exec_future, interrupt_task}, |
423 | | - return_when=asyncio.FIRST_COMPLETED, |
424 | | - ) |
| 409 | + result, interrupted = await interruptible(_exec_async(), self.interrupt_event) |
425 | 410 |
|
426 | | - if interrupt_task in done: |
427 | | - exec_future.cancel() |
428 | | - try: |
429 | | - await exec_future |
430 | | - except asyncio.CancelledError: |
431 | | - pass |
| 411 | + if interrupted: |
432 | 412 | return "Tool execution interrupted by user." |
433 | | - else: |
434 | | - interrupt_task.cancel() |
435 | | - return await exec_future |
| 413 | + return result |
436 | 414 |
|
437 | 415 | def _calculate_context_block_tokens(self, force=False): |
438 | 416 | """ |
|
0 commit comments