chore: migrate config paths to XDG base directory and add hit_count tracking to api_cache
This commit is contained in:
+33
-31
@@ -6,6 +6,7 @@ from pr.tools.agents import (
|
||||
remove_agent,
|
||||
)
|
||||
from pr.tools.base import get_tools_definition
|
||||
from pr.tools.vision import post_image
|
||||
from pr.tools.command import (
|
||||
kill_process,
|
||||
run_command,
|
||||
@@ -44,43 +45,44 @@ from pr.tools.python_exec import python_exec
|
||||
from pr.tools.web import http_fetch, web_search, web_search_news
|
||||
|
||||
__all__ = [
|
||||
"get_tools_definition",
|
||||
"read_file",
|
||||
"write_file",
|
||||
"list_directory",
|
||||
"mkdir",
|
||||
"add_knowledge_entry",
|
||||
"apply_patch",
|
||||
"chdir",
|
||||
"getpwd",
|
||||
"index_source_directory",
|
||||
"search_replace",
|
||||
"open_editor",
|
||||
"close_editor",
|
||||
"collaborate_agents",
|
||||
"create_agent",
|
||||
"create_diff",
|
||||
"db_get",
|
||||
"db_query",
|
||||
"db_set",
|
||||
"delete_knowledge_entry",
|
||||
"post_image",
|
||||
"editor_insert_text",
|
||||
"editor_replace_text",
|
||||
"editor_search",
|
||||
"close_editor",
|
||||
"execute_agent_task",
|
||||
"get_knowledge_by_category",
|
||||
"get_knowledge_entry",
|
||||
"get_knowledge_statistics",
|
||||
"get_tools_definition",
|
||||
"getpwd",
|
||||
"http_fetch",
|
||||
"index_source_directory",
|
||||
"kill_process",
|
||||
"list_agents",
|
||||
"list_directory",
|
||||
"mkdir",
|
||||
"open_editor",
|
||||
"python_exec",
|
||||
"read_file",
|
||||
"remove_agent",
|
||||
"run_command",
|
||||
"run_command_interactive",
|
||||
"db_set",
|
||||
"db_get",
|
||||
"db_query",
|
||||
"http_fetch",
|
||||
"search_knowledge",
|
||||
"search_replace",
|
||||
"tail_process",
|
||||
"update_knowledge_importance",
|
||||
"web_search",
|
||||
"web_search_news",
|
||||
"python_exec",
|
||||
"tail_process",
|
||||
"kill_process",
|
||||
"apply_patch",
|
||||
"create_diff",
|
||||
"create_agent",
|
||||
"list_agents",
|
||||
"execute_agent_task",
|
||||
"remove_agent",
|
||||
"collaborate_agents",
|
||||
"add_knowledge_entry",
|
||||
"get_knowledge_entry",
|
||||
"search_knowledge",
|
||||
"get_knowledge_by_category",
|
||||
"update_knowledge_importance",
|
||||
"delete_knowledge_entry",
|
||||
"get_knowledge_statistics",
|
||||
"write_file",
|
||||
]
|
||||
|
||||
+34
-6
@@ -3,16 +3,40 @@ from typing import Any, Dict, List
|
||||
|
||||
from pr.agents.agent_manager import AgentManager
|
||||
from pr.core.api import call_api
|
||||
from pr.config import DEFAULT_MODEL, DEFAULT_API_URL
|
||||
from pr.tools.base import get_tools_definition
|
||||
|
||||
|
||||
def _create_api_wrapper():
|
||||
"""Create a wrapper function for call_api that matches AgentManager expectations."""
|
||||
model = os.environ.get("AI_MODEL", DEFAULT_MODEL)
|
||||
api_url = os.environ.get("API_URL", DEFAULT_API_URL)
|
||||
api_key = os.environ.get("OPENROUTER_API_KEY", "")
|
||||
use_tools = int(os.environ.get("USE_TOOLS", "0"))
|
||||
tools_definition = get_tools_definition() if use_tools else []
|
||||
|
||||
def api_wrapper(messages, temperature=None, max_tokens=None, **kwargs):
|
||||
return call_api(
|
||||
messages=messages,
|
||||
model=model,
|
||||
api_url=api_url,
|
||||
api_key=api_key,
|
||||
use_tools=use_tools,
|
||||
tools_definition=tools_definition,
|
||||
verbose=False,
|
||||
)
|
||||
|
||||
return api_wrapper
|
||||
|
||||
|
||||
def create_agent(role_name: str, agent_id: str = None) -> Dict[str, Any]:
|
||||
"""Create a new agent with the specified role."""
|
||||
try:
|
||||
# Get db_path from environment or default
|
||||
db_path = os.environ.get("ASSISTANT_DB_PATH", "~/.assistant_db.sqlite")
|
||||
db_path = os.path.expanduser(db_path)
|
||||
|
||||
manager = AgentManager(db_path, call_api)
|
||||
api_wrapper = _create_api_wrapper()
|
||||
manager = AgentManager(db_path, api_wrapper)
|
||||
agent_id = manager.create_agent(role_name, agent_id)
|
||||
return {"status": "success", "agent_id": agent_id, "role": role_name}
|
||||
except Exception as e:
|
||||
@@ -23,7 +47,8 @@ def list_agents() -> Dict[str, Any]:
|
||||
"""List all active agents."""
|
||||
try:
|
||||
db_path = os.path.expanduser("~/.assistant_db.sqlite")
|
||||
manager = AgentManager(db_path, call_api)
|
||||
api_wrapper = _create_api_wrapper()
|
||||
manager = AgentManager(db_path, api_wrapper)
|
||||
agents = []
|
||||
for agent_id, agent in manager.active_agents.items():
|
||||
agents.append(
|
||||
@@ -43,7 +68,8 @@ def execute_agent_task(agent_id: str, task: str, context: Dict[str, Any] = None)
|
||||
"""Execute a task with the specified agent."""
|
||||
try:
|
||||
db_path = os.path.expanduser("~/.assistant_db.sqlite")
|
||||
manager = AgentManager(db_path, call_api)
|
||||
api_wrapper = _create_api_wrapper()
|
||||
manager = AgentManager(db_path, api_wrapper)
|
||||
result = manager.execute_agent_task(agent_id, task, context)
|
||||
return result
|
||||
except Exception as e:
|
||||
@@ -54,7 +80,8 @@ def remove_agent(agent_id: str) -> Dict[str, Any]:
|
||||
"""Remove an agent."""
|
||||
try:
|
||||
db_path = os.path.expanduser("~/.assistant_db.sqlite")
|
||||
manager = AgentManager(db_path, call_api)
|
||||
api_wrapper = _create_api_wrapper()
|
||||
manager = AgentManager(db_path, api_wrapper)
|
||||
success = manager.remove_agent(agent_id)
|
||||
return {"status": "success" if success else "not_found", "agent_id": agent_id}
|
||||
except Exception as e:
|
||||
@@ -65,7 +92,8 @@ def collaborate_agents(orchestrator_id: str, task: str, agent_roles: List[str])
|
||||
"""Collaborate multiple agents on a task."""
|
||||
try:
|
||||
db_path = os.path.expanduser("~/.assistant_db.sqlite")
|
||||
manager = AgentManager(db_path, call_api)
|
||||
api_wrapper = _create_api_wrapper()
|
||||
manager = AgentManager(db_path, api_wrapper)
|
||||
result = manager.collaborate_agents(orchestrator_id, task, agent_roles)
|
||||
return result
|
||||
except Exception as e:
|
||||
|
||||
+2
-2
@@ -1,4 +1,3 @@
|
||||
import os
|
||||
import select
|
||||
import subprocess
|
||||
import time
|
||||
@@ -99,7 +98,7 @@ def tail_process(pid: int, timeout: int = 30):
|
||||
return {"status": "error", "error": f"Process {pid} not found"}
|
||||
|
||||
|
||||
def run_command(command, timeout=30, monitored=False):
|
||||
def run_command(command, timeout=30, monitored=False, cwd=None):
|
||||
mux_name = None
|
||||
try:
|
||||
process = subprocess.Popen(
|
||||
@@ -108,6 +107,7 @@ def run_command(command, timeout=30, monitored=False):
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
cwd=cwd,
|
||||
)
|
||||
_register_process(process.pid, process)
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from pr.multiplexer import (
|
||||
)
|
||||
|
||||
|
||||
def start_interactive_session(command, session_name=None, process_type="generic"):
|
||||
def start_interactive_session(command, session_name=None, process_type="generic", cwd=None):
|
||||
"""
|
||||
Start an interactive session in a dedicated multiplexer.
|
||||
|
||||
@@ -17,6 +17,7 @@ def start_interactive_session(command, session_name=None, process_type="generic"
|
||||
command: The command to run (list or string)
|
||||
session_name: Optional name for the session
|
||||
process_type: Type of process (ssh, vim, apt, etc.)
|
||||
cwd: Current working directory for the command
|
||||
|
||||
Returns:
|
||||
session_name: The name of the created session
|
||||
@@ -36,21 +37,24 @@ def start_interactive_session(command, session_name=None, process_type="generic"
|
||||
stderr=subprocess.PIPE,
|
||||
text=True,
|
||||
bufsize=1,
|
||||
cwd=cwd,
|
||||
)
|
||||
|
||||
mux.process = process
|
||||
mux.update_metadata("pid", process.pid)
|
||||
|
||||
# Set process type and handler
|
||||
from pr.tools.process_handlers import detect_process_type
|
||||
|
||||
detected_type = detect_process_type(command)
|
||||
mux.set_process_type(detected_type)
|
||||
|
||||
# Start output readers
|
||||
stdout_thread = threading.Thread(
|
||||
target=_read_output, args=(process.stdout, mux.write_stdout), daemon=True
|
||||
target=_read_output, args=(process.stdout, mux.write_stdout, detected_type), daemon=True
|
||||
)
|
||||
stderr_thread = threading.Thread(
|
||||
target=_read_output, args=(process.stderr, mux.write_stderr), daemon=True
|
||||
target=_read_output, args=(process.stderr, mux.write_stderr, detected_type), daemon=True
|
||||
)
|
||||
|
||||
stdout_thread.start()
|
||||
@@ -65,14 +69,24 @@ def start_interactive_session(command, session_name=None, process_type="generic"
|
||||
raise e
|
||||
|
||||
|
||||
def _read_output(stream, write_func):
|
||||
def _read_output(stream, write_func, process_type):
|
||||
"""Read from a stream and write to multiplexer buffer."""
|
||||
try:
|
||||
for line in iter(stream.readline, ""):
|
||||
if line:
|
||||
write_func(line.rstrip("\n"))
|
||||
except Exception as e:
|
||||
print(f"Error reading output: {e}")
|
||||
if process_type in ["vim", "ssh"]:
|
||||
try:
|
||||
while True:
|
||||
char = stream.read(1)
|
||||
if not char:
|
||||
break
|
||||
write_func(char)
|
||||
except Exception as e:
|
||||
print(f"Error reading output: {e}")
|
||||
else:
|
||||
try:
|
||||
for line in iter(stream.readline, ""):
|
||||
if line:
|
||||
write_func(line.rstrip("\n"))
|
||||
except Exception as e:
|
||||
print(f"Error reading output: {e}")
|
||||
|
||||
|
||||
def send_input_to_session(session_name, input_data):
|
||||
|
||||
+12
-1
@@ -1,14 +1,25 @@
|
||||
import contextlib
|
||||
import os
|
||||
import traceback
|
||||
from io import StringIO
|
||||
|
||||
|
||||
def python_exec(code, python_globals):
|
||||
def python_exec(code, python_globals, cwd=None):
|
||||
try:
|
||||
original_cwd = None
|
||||
if cwd:
|
||||
original_cwd = os.getcwd()
|
||||
os.chdir(cwd)
|
||||
|
||||
output = StringIO()
|
||||
with contextlib.redirect_stdout(output):
|
||||
exec(code, python_globals)
|
||||
|
||||
if original_cwd:
|
||||
os.chdir(original_cwd)
|
||||
|
||||
return {"status": "success", "output": output.getvalue()}
|
||||
except Exception as e:
|
||||
if original_cwd:
|
||||
os.chdir(original_cwd)
|
||||
return {"status": "error", "error": str(e), "traceback": traceback.format_exc()}
|
||||
|
||||
Reference in New Issue
Block a user