129 lines
3.7 KiB
Python
Raw Normal View History

2025-11-04 05:17:27 +01:00
import os
import sys
import importlib.util
from typing import List, Dict, Callable, Any
from pr.core.logging import get_logger
logger = get_logger('plugins')
PLUGINS_DIR = os.path.expanduser("~/.pr/plugins")
class PluginLoader:
def __init__(self):
self.loaded_plugins = {}
self.plugin_tools = []
os.makedirs(PLUGINS_DIR, exist_ok=True)
def load_plugins(self) -> List[Dict]:
if not os.path.exists(PLUGINS_DIR):
logger.info("No plugins directory found")
return []
plugin_files = [f for f in os.listdir(PLUGINS_DIR) if f.endswith('.py')]
for plugin_file in plugin_files:
try:
self._load_plugin_file(plugin_file)
except Exception as e:
logger.error(f"Error loading plugin {plugin_file}: {e}")
return self.plugin_tools
def _load_plugin_file(self, filename: str):
plugin_path = os.path.join(PLUGINS_DIR, filename)
plugin_name = filename[:-3]
spec = importlib.util.spec_from_file_location(plugin_name, plugin_path)
if spec is None or spec.loader is None:
logger.error(f"Could not load spec for {filename}")
return
module = importlib.util.module_from_spec(spec)
sys.modules[plugin_name] = module
spec.loader.exec_module(module)
if hasattr(module, 'register_tools'):
tools = module.register_tools()
if isinstance(tools, list):
self.plugin_tools.extend(tools)
self.loaded_plugins[plugin_name] = module
logger.info(f"Loaded plugin: {plugin_name} ({len(tools)} tools)")
else:
logger.warning(f"Plugin {plugin_name} register_tools() did not return a list")
else:
logger.warning(f"Plugin {plugin_name} does not have register_tools() function")
def get_plugin_function(self, tool_name: str) -> Callable:
for plugin_name, module in self.loaded_plugins.items():
if hasattr(module, tool_name):
return getattr(module, tool_name)
raise ValueError(f"Plugin function not found: {tool_name}")
def list_loaded_plugins(self) -> List[str]:
return list(self.loaded_plugins.keys())
def create_example_plugin():
example_plugin = os.path.join(PLUGINS_DIR, 'example_plugin.py')
if os.path.exists(example_plugin):
return
example_code = '''"""
Example plugin for PR Assistant
This plugin demonstrates how to create custom tools.
"""
def my_custom_tool(argument: str) -> str:
"""
A custom tool that does something useful.
Args:
argument: Some input
Returns:
A result string
"""
return f"Custom tool processed: {argument}"
def register_tools():
"""
Register tools with the PR assistant.
Returns:
List of tool definitions
"""
return [
{
"type": "function",
"function": {
"name": "my_custom_tool",
"description": "A custom tool that processes input",
"parameters": {
"type": "object",
"properties": {
"argument": {
"type": "string",
"description": "The input to process"
}
},
"required": ["argument"]
}
}
}
]
'''
try:
os.makedirs(PLUGINS_DIR, exist_ok=True)
with open(example_plugin, 'w') as f:
f.write(example_code)
logger.info(f"Created example plugin at {example_plugin}")
except Exception as e:
logger.error(f"Error creating example plugin: {e}")