129 lines
5.5 KiB
Python
129 lines
5.5 KiB
Python
# methodDiscovery.py
|
|
# Method discovery and management for workflow execution
|
|
|
|
import logging
|
|
import importlib
|
|
import pkgutil
|
|
import inspect
|
|
from typing import Any, Dict, List
|
|
from modules.workflows.methods.methodBase import MethodBase
|
|
|
|
# Set up logger
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Global methods catalog - moved from serviceCenter
|
|
methods = {}
|
|
|
|
def discoverMethods(serviceCenter):
|
|
"""Dynamically discover all method classes and their actions in modules methods package"""
|
|
try:
|
|
# Import the methods package
|
|
methodsPackage = importlib.import_module('modules.workflows.methods')
|
|
|
|
# Discover all modules in the package
|
|
for _, name, isPkg in pkgutil.iter_modules(methodsPackage.__path__):
|
|
if not isPkg and name.startswith('method'):
|
|
try:
|
|
# Import the module
|
|
module = importlib.import_module(f'modules.workflows.methods.{name}')
|
|
|
|
# Find all classes in the module that inherit from MethodBase
|
|
for itemName, item in inspect.getmembers(module):
|
|
if (inspect.isclass(item) and
|
|
issubclass(item, MethodBase) and
|
|
item != MethodBase):
|
|
# Instantiate the method
|
|
methodInstance = item(serviceCenter)
|
|
|
|
# Use the actions property from MethodBase which handles @action decorator
|
|
actions = methodInstance.actions
|
|
|
|
# Create method info
|
|
methodInfo = {
|
|
'instance': methodInstance,
|
|
'actions': actions,
|
|
'description': item.__doc__ or f"Method {itemName}"
|
|
}
|
|
|
|
# Store the method with full class name
|
|
methods[itemName] = methodInfo
|
|
|
|
# Also store with short name for action executor access
|
|
shortName = itemName.replace('Method', '').lower()
|
|
methods[shortName] = methodInfo
|
|
|
|
logger.info(f"Discovered method {itemName} (short: {shortName}) with {len(actions)} actions")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error discovering method {name}: {str(e)}")
|
|
continue
|
|
|
|
logger.info(f"Discovered {len(methods)} method entries total")
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error discovering methods: {str(e)}")
|
|
|
|
def getMethodsList(serviceCenter):
|
|
"""Get a list of available methods with their signatures"""
|
|
if not methods:
|
|
discoverMethods(serviceCenter)
|
|
|
|
methodsList = []
|
|
for methodName, methodInfo in methods.items():
|
|
methodDescription = methodInfo['description']
|
|
actionsList = []
|
|
|
|
for actionName, actionInfo in methodInfo['actions'].items():
|
|
actionDescription = actionInfo['description']
|
|
parameters = actionInfo['parameters']
|
|
|
|
# Build parameter signature
|
|
paramSig = []
|
|
for paramName, paramInfo in parameters.items():
|
|
paramType = paramInfo['type']
|
|
paramRequired = paramInfo['required']
|
|
paramDefault = paramInfo['default']
|
|
|
|
if paramRequired:
|
|
paramSig.append(f"{paramName}: {paramType}")
|
|
else:
|
|
defaultStr = f" = {paramDefault}" if paramDefault is not None else " = None"
|
|
paramSig.append(f"{paramName}: {paramType}{defaultStr}")
|
|
|
|
paramSignature = f"({', '.join(paramSig)})" if paramSig else "()"
|
|
actionsList.append(f"- {actionName}{paramSignature}: {actionDescription}")
|
|
|
|
actionsStr = "\n".join(actionsList)
|
|
methodsList.append(f"**{methodName}**: {methodDescription}\n{actionsStr}")
|
|
|
|
return "\n\n".join(methodsList)
|
|
|
|
def getActionParameterList(methodName: str, actionName: str, methods: Dict[str, Any]) -> str:
|
|
"""Get action parameter list from method docstring for AI parameter generation (list only)."""
|
|
try:
|
|
if not methods or methodName not in methods:
|
|
return ""
|
|
|
|
methodInstance = methods[methodName]['instance']
|
|
if actionName not in methodInstance.actions:
|
|
return ""
|
|
|
|
action_info = methodInstance.actions[actionName]
|
|
# Extract parameter descriptions from docstring
|
|
docstring = action_info.get('description', '')
|
|
paramDescriptions, paramTypes = methodInstance._extractParameterDetails(docstring)
|
|
|
|
param_list = []
|
|
for paramName, paramDesc in paramDescriptions.items():
|
|
paramType = paramTypes.get(paramName, 'Any')
|
|
if paramDesc:
|
|
param_list.append(f"- {paramName} ({paramType}): {paramDesc}")
|
|
else:
|
|
param_list.append(f"- {paramName} ({paramType})")
|
|
|
|
# Return list only, without leading headings or trailing text
|
|
return "\n".join(param_list)
|
|
except Exception as e:
|
|
logger.error(f"Error getting action parameter signature for {methodName}.{actionName}: {str(e)}")
|
|
return ""
|
|
|