Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions cecli/coders/agent_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -848,11 +848,12 @@ async def reply_completed(self):
)
self.io.tool_output(waiting_msg)
await asyncio.sleep(command_timeout / 2)
return True
return False

# Check for recently finished commands that need reflection
if recently_finished_commands and not self.agent_finished:
return True # Retrigger reflection to process recently finished command outputs
self.reflected_message = "Background command finished, processing output."
return False # Retrigger reflection to process recently finished command outputs

# 3. If no content and no tools, we might be done or just empty response
if (not content or not content.strip()) and not tool_calls_found:
Expand Down
75 changes: 54 additions & 21 deletions cecli/coders/base_coder.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import asyncio
import base64
import asyncio
import hashlib
import json
import locale
Expand Down Expand Up @@ -375,6 +376,7 @@

self.context_compaction_max_tokens = context_compaction_max_tokens
self.context_compaction_summary_tokens = context_compaction_summary_tokens
self.globally_approved_tool_calls = False
self.max_reflections = (
3 if self.edit_format == "agent" else nested.getter(self.args, "max_reflections", 3)
)
Expand Down Expand Up @@ -1290,7 +1292,11 @@
try:
if with_message:
self.io.user_input(with_message)
await self.run_one(with_message, preproc)
self.io.is_processing_prompt = True
try:
await self.run_one(with_message, preproc)
finally:
self.io.is_processing_prompt = False
return self.partial_response_content

user_message = None
Expand Down Expand Up @@ -1352,7 +1358,11 @@
try:
if with_message:
self.io.user_input(with_message)
await self.run_one(with_message, preproc)
self.io.is_processing_prompt = True
try:
await self.run_one(with_message, preproc)
finally:
self.io.is_processing_prompt = False
return self.partial_response_content

# Initialize state for task coordination
Expand Down Expand Up @@ -1537,7 +1547,11 @@
self.compact_context_completed = True

self.run_one_completed = False
await self.run_one(user_message, preproc)
self.io.is_processing_prompt = True
try:
await self.run_one(user_message, preproc)
finally:
self.io.is_processing_prompt = False
self.show_undo_hint()
except asyncio.CancelledError:
# Don't show undo hint if cancelled
Expand Down Expand Up @@ -1740,7 +1754,9 @@
# Ensure cursor is visible on exit
Console().show_cursor(True)

self.io.tool_warning("^C KeyboardInterrupt")
self.io.tool_warning("\n\n^C KeyboardInterrupt")
self.interrupt_event.set()

self.interrupt_event.set()
self.last_keyboard_interrupt = time.time()

Expand Down Expand Up @@ -2746,20 +2762,36 @@
self._print_tool_call_info(server_tool_calls=tool_groups)

# 4. Ask for user confirmation
if not await self.io.confirm_ask("Run tools?", group_response="Run MCP Tools"):
return False
try:
self.globally_approved_tool_calls = False
if not await self.io.confirm_ask("Run tools?", group_response="Run MCP Tools"):
return False

# 5. Execute tools

Check failure on line 2770 in cecli/coders/base_coder.py

View workflow job for this annotation

GitHub Actions / pre-commit

E999 SyntaxError: expected 'except' or 'finally' block
self.interrupt_event.clear()

tool_responses_by_server, interrupted = await coroutines.interruptible(
self._execute_tool_groups(tool_groups), self.interrupt_event
)
tool_responses_by_server = {}
try:
tool_responses_by_server, interrupted = await coroutines.interruptible(
self._execute_tool_groups(tool_groups),
self.interrupt_event
)

if interrupted:
self.io.tool_warning("Tool execution interrupted.")
if interrupted:
self.io.tool_warning("Tool execution interrupted.")
return False

except asyncio.CancelledError:
self.io.tool_warning("Tool execution cancelled.")
return False

if self.io.group_responses.get("Run MCP Tools"):
self.globally_approved_tool_calls = True

try:
return tool_responses_by_server
finally:
self.globally_approved_tool_calls = False
# 6. Add responses to conversation (re-prefixing if necessary)
tool_responses = []
for server, server_responses in tool_responses_by_server.items():
Expand All @@ -2778,7 +2810,6 @@

def _print_tool_call_info(self, server_tool_calls):
"""Print information about an MCP tool call."""
self.io.ring_bell()
# self.io.tool_output("Preparing to run MCP tools", bold=False)

for server, tool_calls in server_tool_calls.items():
Expand Down Expand Up @@ -3070,15 +3101,17 @@
self.token_profiler.start()

try:
completion_coro = model.send_completion(
messages,
functions,
self.stream,
self.temperature,
# This could include any tools, but for now it is just MCP tools
tools=tools,
override_kwargs=self.model_kwargs.copy(),
interrupt_event=self.interrupt_event,
completion_coro = asyncio.create_task(
model.send_completion(
messages,
functions,
self.stream,
self.temperature,
# This could include any tools, but for now it is just MCP tools
tools=tools,
override_kwargs=self.model_kwargs.copy(),
interrupt_event=self.interrupt_event,
)
)

(hash_object, completion), interrupted = await coroutines.interruptible(
Expand Down
Loading
Loading