feat: enable autonomous mode by default
feat: improve content extraction in autonomous mode refactor: remove user message in autonomous mode refactor: display tool call arguments maintenance: update version to 1.54.0 refactor: handle tool call execution errors refactor: prevent excessive autonomous mode exits perf: display execution time in progress indicator
This commit is contained in:
parent
20668d9086
commit
8e6af2b32b
@ -4,6 +4,14 @@
|
||||
|
||||
|
||||
|
||||
|
||||
## Version 1.53.0 - 2025-11-10
|
||||
|
||||
Autonomous mode is now enabled by default, streamlining workflows. We've also improved the underlying code and fixed some issues with content extraction in autonomous mode.
|
||||
|
||||
**Changes:** 15 files, 433 lines
|
||||
**Languages:** Markdown (47 lines), Python (384 lines), TOML (2 lines)
|
||||
|
||||
## Version 1.52.0 - 2025-11-10
|
||||
|
||||
This release updates the project version to 1.52.0. No new features or changes are introduced for users or developers.
|
||||
|
||||
@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "rp"
|
||||
version = "1.52.0"
|
||||
version = "1.53.0"
|
||||
description = "R python edition. The ultimate autonomous AI CLI."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@ -99,6 +99,9 @@ def run_autonomous_mode(assistant, task):
|
||||
except KeyboardInterrupt:
|
||||
logger.debug("Autonomous mode interrupted by user")
|
||||
print(f"\n{Colors.YELLOW}Autonomous mode interrupted by user{Colors.RESET}")
|
||||
# Cancel the last API call and remove the user message to keep messages clean
|
||||
if assistant.messages and assistant.messages[-1]["role"] == "user":
|
||||
assistant.messages.pop()
|
||||
finally:
|
||||
assistant.autonomous_mode = False
|
||||
logger.debug("=== AUTONOMOUS MODE END ===")
|
||||
@ -113,10 +116,13 @@ def process_response_autonomous(assistant, response):
|
||||
assistant.messages.append(message)
|
||||
if "tool_calls" in message and message["tool_calls"]:
|
||||
tool_results = []
|
||||
with ProgressIndicator("Executing tools..."):
|
||||
for tool_call in message["tool_calls"]:
|
||||
func_name = tool_call["function"]["name"]
|
||||
arguments = json.loads(tool_call["function"]["arguments"])
|
||||
args_str = ", ".join([f"{k}={repr(v)}" for k, v in arguments.items()])
|
||||
if len(args_str) > 100:
|
||||
args_str = args_str[:97] + "..."
|
||||
print(f"{Colors.BLUE}⠋ Executing tools......{func_name}({args_str}){Colors.RESET}")
|
||||
result = execute_single_tool(assistant, func_name, arguments)
|
||||
if isinstance(result, str):
|
||||
try:
|
||||
@ -125,7 +131,6 @@ def process_response_autonomous(assistant, response):
|
||||
result = {"error": str(ex)}
|
||||
status = "success" if result.get("status") == "success" else "error"
|
||||
result = truncate_tool_result(result)
|
||||
display_tool_call(func_name, arguments, status, result)
|
||||
sanitized_result = sanitize_for_json(result)
|
||||
tool_results.append(
|
||||
{
|
||||
|
||||
@ -6,6 +6,7 @@ import readline
|
||||
import signal
|
||||
import sqlite3
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
@ -99,7 +100,7 @@ class Assistant:
|
||||
"MODEL_LIST_URL", MODEL_LIST_URL
|
||||
)
|
||||
self.use_tools = os.environ.get("USE_TOOLS", "1") == "1"
|
||||
self.interrupt_count = 0
|
||||
self.last_interrupt_time = 0
|
||||
self.python_globals = {}
|
||||
self.db_conn = None
|
||||
self.autonomous_mode = False
|
||||
@ -238,6 +239,10 @@ class Assistant:
|
||||
func_name = tool_call["function"]["name"]
|
||||
arguments = json.loads(tool_call["function"]["arguments"])
|
||||
logger.debug(f"Tool call: {func_name} with arguments: {arguments}")
|
||||
args_str = ", ".join([f"{k}={repr(v)}" for k, v in arguments.items()])
|
||||
if len(args_str) > 100:
|
||||
args_str = args_str[:97] + "..."
|
||||
print(f"{Colors.BLUE}⠋ Executing tools......{func_name}({args_str}){Colors.RESET}")
|
||||
func_map = {
|
||||
"http_fetch": lambda **kw: http_fetch(**kw),
|
||||
"run_command": lambda **kw: run_command(**kw),
|
||||
@ -351,22 +356,15 @@ class Assistant:
|
||||
return render_markdown(cleaned_content, self.syntax_highlighting)
|
||||
|
||||
def signal_handler(self, signum, frame):
|
||||
if self.autonomous_mode:
|
||||
self.interrupt_count += 1
|
||||
if self.interrupt_count >= 2:
|
||||
print(f"\n{Colors.RED}Force exiting autonomous mode...{Colors.RESET}")
|
||||
self.autonomous_mode = False
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(f"\n{Colors.YELLOW}Press Ctrl+C again to force exit{Colors.RESET}")
|
||||
return
|
||||
self.interrupt_count += 1
|
||||
if self.interrupt_count >= 2:
|
||||
print(f"\n{Colors.RED}Exiting...{Colors.RESET}")
|
||||
current_time = time.time()
|
||||
if current_time - self.last_interrupt_time < 1.0:
|
||||
print(f"\n{Colors.RED}Force exiting...{Colors.RESET}")
|
||||
self.cleanup()
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(f"\n{Colors.YELLOW}Press Ctrl+C again to exit{Colors.RESET}")
|
||||
self.last_interrupt_time = current_time
|
||||
print(f"\n{Colors.YELLOW}Interrupted{Colors.RESET}")
|
||||
raise KeyboardInterrupt
|
||||
|
||||
def setup_readline(self):
|
||||
try:
|
||||
@ -446,7 +444,8 @@ class Assistant:
|
||||
except EOFError:
|
||||
break
|
||||
except KeyboardInterrupt:
|
||||
self.signal_handler(None, None)
|
||||
print(f"\n{Colors.YELLOW}Interrupted, returning to prompt{Colors.RESET}")
|
||||
continue
|
||||
except Exception as e:
|
||||
print(f"{Colors.RED}Error: {e}{Colors.RESET}")
|
||||
logging.error(f"REPL error: {e}\n{traceback.format_exc()}")
|
||||
|
||||
@ -10,6 +10,7 @@ class ProgressIndicator:
|
||||
self.show = show
|
||||
self.running = False
|
||||
self.thread = None
|
||||
self.start_time = None
|
||||
|
||||
def __enter__(self):
|
||||
if self.show:
|
||||
@ -21,6 +22,7 @@ class ProgressIndicator:
|
||||
self.stop()
|
||||
|
||||
def start(self):
|
||||
self.start_time = time.time()
|
||||
self.running = True
|
||||
self.thread = threading.Thread(target=self._animate, daemon=True)
|
||||
self.thread.start()
|
||||
@ -30,14 +32,15 @@ class ProgressIndicator:
|
||||
self.running = False
|
||||
if self.thread:
|
||||
self.thread.join(timeout=1.0)
|
||||
sys.stdout.write("\r" + " " * (len(self.message) + 10) + "\r")
|
||||
sys.stdout.write("\r" + " " * (len(self.message) + 20) + "\r")
|
||||
sys.stdout.flush()
|
||||
|
||||
def _animate(self):
|
||||
spinner = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
||||
idx = 0
|
||||
while self.running:
|
||||
sys.stdout.write(f"\r{spinner[idx]} {self.message}...")
|
||||
elapsed = time.time() - self.start_time
|
||||
sys.stdout.write(f"\r{spinner[idx]} {self.message}... ({elapsed:.1f}s)")
|
||||
sys.stdout.flush()
|
||||
idx = (idx + 1) % len(spinner)
|
||||
time.sleep(0.1)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user