import json import logging import time from pr.autonomous.detection import is_task_complete from pr.core.context import truncate_tool_result from pr.ui import Colors, display_tool_call logger = logging.getLogger("pr") def run_autonomous_mode(assistant, task): assistant.autonomous_mode = True assistant.autonomous_iterations = 0 logger.debug(f"=== AUTONOMOUS MODE START ===") logger.debug(f"Task: {task}") assistant.messages.append({"role": "user", "content": f"{task}"}) try: while True: assistant.autonomous_iterations += 1 logger.debug( f"--- Autonomous iteration {assistant.autonomous_iterations} ---" ) logger.debug( f"Messages before context management: {len(assistant.messages)}" ) from pr.core.context import manage_context_window assistant.messages = manage_context_window( assistant.messages, assistant.verbose ) logger.debug( f"Messages after context management: {len(assistant.messages)}" ) from pr.core.api import call_api from pr.tools.base import get_tools_definition response = call_api( assistant.messages, assistant.model, assistant.api_url, assistant.api_key, assistant.use_tools, get_tools_definition(), verbose=assistant.verbose, ) if "error" in response: logger.error(f"API error in autonomous mode: {response['error']}") print(f"{Colors.RED}Error: {response['error']}{Colors.RESET}") break is_complete = is_task_complete(response, assistant.autonomous_iterations) logger.debug(f"Task completion check: {is_complete}") if is_complete: result = process_response_autonomous(assistant, response) print(f"\n{Colors.GREEN}r:{Colors.RESET} {result}\n") logger.debug(f"=== AUTONOMOUS MODE COMPLETE ===") logger.debug(f"Total iterations: {assistant.autonomous_iterations}") logger.debug(f"Final message count: {len(assistant.messages)}") break result = process_response_autonomous(assistant, response) if result: print(f"\n{Colors.GREEN}r:{Colors.RESET} {result}\n") time.sleep(0.5) except KeyboardInterrupt: logger.debug("Autonomous mode interrupted by user") print(f"\n{Colors.YELLOW}Autonomous mode interrupted by user{Colors.RESET}") finally: assistant.autonomous_mode = False logger.debug("=== AUTONOMOUS MODE END ===") def process_response_autonomous(assistant, response): if "error" in response: return f"Error: {response['error']}" if "choices" not in response or not response["choices"]: return "No response from API" message = response["choices"][0]["message"] assistant.messages.append(message) if "tool_calls" in message and message["tool_calls"]: tool_results = [] for tool_call in message["tool_calls"]: func_name = tool_call["function"]["name"] arguments = json.loads(tool_call["function"]["arguments"]) result = execute_single_tool(assistant, func_name, arguments) result = truncate_tool_result(result) status = "success" if result.get("status") == "success" else "error" display_tool_call(func_name, arguments, status, result) tool_results.append( { "tool_call_id": tool_call["id"], "role": "tool", "content": json.dumps(result), } ) for result in tool_results: assistant.messages.append(result) from pr.core.api import call_api from pr.tools.base import get_tools_definition follow_up = call_api( assistant.messages, assistant.model, assistant.api_url, assistant.api_key, assistant.use_tools, get_tools_definition(), verbose=assistant.verbose, ) return process_response_autonomous(assistant, follow_up) content = message.get("content", "") from pr.ui import render_markdown return render_markdown(content, assistant.syntax_highlighting) def execute_single_tool(assistant, func_name, arguments): logger.debug(f"Executing tool in autonomous mode: {func_name}") logger.debug(f"Tool arguments: {arguments}") from pr.tools import ( apply_patch, chdir, close_editor, create_diff, db_get, db_query, db_set, editor_insert_text, editor_replace_text, editor_search, getpwd, http_fetch, index_source_directory, kill_process, list_directory, mkdir, open_editor, python_exec, read_file, run_command, run_command_interactive, search_replace, tail_process, web_search, web_search_news, write_file, ) from pr.tools.filesystem import ( clear_edit_tracker, display_edit_summary, display_edit_timeline, ) from pr.tools.patch import display_file_diff func_map = { "http_fetch": lambda **kw: http_fetch(**kw), "run_command": lambda **kw: run_command(**kw), "tail_process": lambda **kw: tail_process(**kw), "kill_process": lambda **kw: kill_process(**kw), "run_command_interactive": lambda **kw: run_command_interactive(**kw), "read_file": lambda **kw: read_file(**kw), "write_file": lambda **kw: write_file(**kw, db_conn=assistant.db_conn), "list_directory": lambda **kw: list_directory(**kw), "mkdir": lambda **kw: mkdir(**kw), "chdir": lambda **kw: chdir(**kw), "getpwd": lambda **kw: getpwd(**kw), "db_set": lambda **kw: db_set(**kw, db_conn=assistant.db_conn), "db_get": lambda **kw: db_get(**kw, db_conn=assistant.db_conn), "db_query": lambda **kw: db_query(**kw, db_conn=assistant.db_conn), "web_search": lambda **kw: web_search(**kw), "web_search_news": lambda **kw: web_search_news(**kw), "python_exec": lambda **kw: python_exec( **kw, python_globals=assistant.python_globals ), "index_source_directory": lambda **kw: index_source_directory(**kw), "search_replace": lambda **kw: search_replace(**kw), "open_editor": lambda **kw: open_editor(**kw), "editor_insert_text": lambda **kw: editor_insert_text(**kw), "editor_replace_text": lambda **kw: editor_replace_text(**kw), "editor_search": lambda **kw: editor_search(**kw), "close_editor": lambda **kw: close_editor(**kw), "create_diff": lambda **kw: create_diff(**kw), "apply_patch": lambda **kw: apply_patch(**kw), "display_file_diff": lambda **kw: display_file_diff(**kw), "display_edit_summary": lambda **kw: display_edit_summary(), "display_edit_timeline": lambda **kw: display_edit_timeline(**kw), "clear_edit_tracker": lambda **kw: clear_edit_tracker(), } if func_name in func_map: try: result = func_map[func_name](**arguments) logger.debug(f"Tool execution result: {str(result)[:200]}...") return result except Exception as e: logger.error(f"Tool execution error: {str(e)}") return {"status": "error", "error": str(e)} else: logger.error(f"Unknown function requested: {func_name}") return {"status": "error", "error": f"Unknown function: {func_name}"}