224 lines
7.9 KiB
Python
Raw Normal View History

2025-11-04 05:17:27 +01:00
import json
import logging
2025-11-04 08:09:12 +01:00
import time
2025-11-04 05:17:27 +01:00
from pr.autonomous.detection import is_task_complete
from pr.core.context import truncate_tool_result
2025-11-04 08:09:12 +01:00
from pr.ui import Colors, display_tool_call
logger = logging.getLogger("pr")
2025-11-04 05:17:27 +01:00
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}")
from pr.core.knowledge_context import inject_knowledge_context
inject_knowledge_context(assistant, task)
2025-11-04 08:09:12 +01:00
assistant.messages.append({"role": "user", "content": f"{task}"})
2025-11-04 05:17:27 +01:00
try:
while True:
assistant.autonomous_iterations += 1
2025-11-04 08:10:37 +01:00
logger.debug(f"--- Autonomous iteration {assistant.autonomous_iterations} ---")
logger.debug(f"Messages before context management: {len(assistant.messages)}")
2025-11-04 05:17:27 +01:00
from pr.core.context import manage_context_window
2025-11-04 08:10:37 +01:00
assistant.messages = manage_context_window(assistant.messages, assistant.verbose)
2025-11-04 08:09:12 +01:00
2025-11-04 08:10:37 +01:00
logger.debug(f"Messages after context management: {len(assistant.messages)}")
2025-11-04 05:17:27 +01:00
from pr.core.api import call_api
from pr.tools.base import get_tools_definition
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
response = call_api(
assistant.messages,
assistant.model,
assistant.api_url,
assistant.api_key,
assistant.use_tools,
get_tools_definition(),
2025-11-04 08:09:12 +01:00
verbose=assistant.verbose,
2025-11-04 05:17:27 +01:00
)
2025-11-04 08:09:12 +01:00
if "error" in response:
2025-11-04 05:17:27 +01:00
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 ===")
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
def process_response_autonomous(assistant, response):
2025-11-04 08:09:12 +01:00
if "error" in response:
2025-11-04 05:17:27 +01:00
return f"Error: {response['error']}"
2025-11-04 08:09:12 +01:00
if "choices" not in response or not response["choices"]:
2025-11-04 05:17:27 +01:00
return "No response from API"
2025-11-04 08:09:12 +01:00
message = response["choices"][0]["message"]
2025-11-04 05:17:27 +01:00
assistant.messages.append(message)
2025-11-04 08:09:12 +01:00
if "tool_calls" in message and message["tool_calls"]:
2025-11-04 05:17:27 +01:00
tool_results = []
2025-11-04 08:09:12 +01:00
for tool_call in message["tool_calls"]:
func_name = tool_call["function"]["name"]
arguments = json.loads(tool_call["function"]["arguments"])
2025-11-04 05:17:27 +01:00
result = execute_single_tool(assistant, func_name, arguments)
if isinstance(result, str):
try:
result = json.loads(result)
except json.JSONDecodeError as ex:
result = {"error": str(ex)}
2025-11-04 05:17:27 +01:00
status = "success" if result.get("status") == "success" else "error"
result = truncate_tool_result(result)
2025-11-04 05:17:27 +01:00
display_tool_call(func_name, arguments, status, result)
2025-11-04 08:09:12 +01:00
tool_results.append(
{
"tool_call_id": tool_call["id"],
"role": "tool",
"content": json.dumps(result),
}
)
2025-11-04 05:17:27 +01:00
for result in tool_results:
assistant.messages.append(result)
from pr.core.api import call_api
from pr.tools.base import get_tools_definition
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
follow_up = call_api(
assistant.messages,
assistant.model,
assistant.api_url,
assistant.api_key,
assistant.use_tools,
get_tools_definition(),
2025-11-04 08:09:12 +01:00
verbose=assistant.verbose,
2025-11-04 05:17:27 +01:00
)
return process_response_autonomous(assistant, follow_up)
2025-11-04 08:09:12 +01:00
content = message.get("content", "")
2025-11-04 05:17:27 +01:00
from pr.ui import render_markdown
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
return render_markdown(content, assistant.syntax_highlighting)
2025-11-04 08:09:12 +01:00
2025-11-04 05:17:27 +01:00
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 (
2025-11-04 08:09:12 +01:00
apply_patch,
chdir,
close_editor,
create_diff,
db_get,
db_query,
db_set,
# editor_insert_text,
# editor_replace_text,
# editor_search,
2025-11-04 08:09:12 +01:00
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,
2025-11-04 05:17:27 +01:00
)
from pr.tools.patch import display_file_diff
func_map = {
2025-11-04 08:09:12 +01:00
"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),
2025-11-04 08:10:37 +01:00
"python_exec": lambda **kw: python_exec(**kw, python_globals=assistant.python_globals),
2025-11-04 08:09:12 +01:00
"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(),
2025-11-04 05:17:27 +01:00
}
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}"}