218 lines
8.4 KiB
Python
218 lines
8.4 KiB
Python
from typing import Dict, Any, Type, TypeVar, List
|
|
from abc import ABC, abstractmethod
|
|
from flask import current_app
|
|
|
|
from common.extensions import cache_manager, db
|
|
from common.models.interaction import EveAIAgent, EveAITask, EveAITool, Specialist
|
|
from common.utils.cache.crewai_configuration import (
|
|
ProcessedAgentConfig, ProcessedTaskConfig, ProcessedToolConfig,
|
|
SpecialistProcessedConfig
|
|
)
|
|
|
|
T = TypeVar('T') # For generic model types
|
|
|
|
|
|
class BaseCrewAIConfigProcessor:
|
|
"""Base processor for specialist configurations"""
|
|
|
|
# Standard mapping between model fields and template placeholders
|
|
AGENT_FIELD_MAPPING = {
|
|
'role': 'custom_role',
|
|
'goal': 'custom_goal',
|
|
'backstory': 'custom_backstory'
|
|
}
|
|
|
|
TASK_FIELD_MAPPING = {
|
|
'task_description': 'custom_description',
|
|
'expected_output': 'custom_expected_output'
|
|
}
|
|
|
|
def __init__(self, tenant_id: int, specialist_id: int):
|
|
self.tenant_id = tenant_id
|
|
self.specialist_id = specialist_id
|
|
self.specialist = self._get_specialist()
|
|
self.verbose = self._get_verbose_setting()
|
|
|
|
def _get_specialist(self) -> Specialist:
|
|
"""Get specialist and verify existence"""
|
|
specialist = Specialist.query.get(self.specialist_id)
|
|
if not specialist:
|
|
raise ValueError(f"Specialist {self.specialist_id} not found")
|
|
return specialist
|
|
|
|
def _get_verbose_setting(self) -> bool:
|
|
"""Get verbose setting from specialist"""
|
|
return bool(self.specialist.tuning)
|
|
|
|
def _get_db_items(self, model_class: Type[T], type_list: List[str]) -> Dict[str, T]:
|
|
"""Get database items of specified type"""
|
|
items = (model_class.query
|
|
.filter_by(specialist_id=self.specialist_id)
|
|
.filter(model_class.type.in_(type_list))
|
|
.all())
|
|
return {item.type: item for item in items}
|
|
|
|
def _apply_replacements(self, text: str, replacements: Dict[str, str]) -> str:
|
|
"""Apply text replacements to a string"""
|
|
result = text
|
|
for key, value in replacements.items():
|
|
if value is not None: # Only replace if value exists
|
|
placeholder = "{" + key + "}"
|
|
result = result.replace(placeholder, str(value))
|
|
return result
|
|
|
|
def _process_agent_configs(self, specialist_config: Dict[str, Any]) -> Dict[str, ProcessedAgentConfig]:
|
|
"""Process all agent configurations"""
|
|
agent_configs = {}
|
|
|
|
if 'agents' not in specialist_config:
|
|
return agent_configs
|
|
|
|
# Get all DB agents at once
|
|
agent_types = [agent_def['type'] for agent_def in specialist_config['agents']]
|
|
db_agents = self._get_db_items(EveAIAgent, agent_types)
|
|
|
|
for agent_def in specialist_config['agents']:
|
|
agent_type = agent_def['type']
|
|
agent_type_lower = agent_type.lower()
|
|
db_agent = db_agents.get(agent_type)
|
|
|
|
# Get full configuration
|
|
config = cache_manager.agents_config_cache.get_config(
|
|
agent_type,
|
|
agent_def.get('version', '1.0')
|
|
)
|
|
|
|
# Start with YAML values
|
|
role = config['role']
|
|
goal = config['goal']
|
|
backstory = config['backstory']
|
|
|
|
# Apply DB values if they exist
|
|
if db_agent:
|
|
for model_field, placeholder in self.AGENT_FIELD_MAPPING.items():
|
|
value = getattr(db_agent, model_field)
|
|
if value:
|
|
placeholder_text = "{" + placeholder + "}"
|
|
role = role.replace(placeholder_text, value)
|
|
goal = goal.replace(placeholder_text, value)
|
|
backstory = backstory.replace(placeholder_text, value)
|
|
|
|
agent_configs[agent_type_lower] = ProcessedAgentConfig(
|
|
role=role,
|
|
goal=goal,
|
|
backstory=backstory,
|
|
name=agent_def.get('name') or config.get('name', agent_type_lower),
|
|
type=agent_type,
|
|
description=agent_def.get('description') or config.get('description'),
|
|
verbose=self.verbose
|
|
)
|
|
|
|
return agent_configs
|
|
|
|
def _process_task_configs(self, specialist_config: Dict[str, Any]) -> Dict[str, ProcessedTaskConfig]:
|
|
"""Process all task configurations"""
|
|
task_configs = {}
|
|
|
|
if 'tasks' not in specialist_config:
|
|
return task_configs
|
|
|
|
# Get all DB tasks at once
|
|
task_types = [task_def['type'] for task_def in specialist_config['tasks']]
|
|
db_tasks = self._get_db_items(EveAITask, task_types)
|
|
|
|
for task_def in specialist_config['tasks']:
|
|
task_type = task_def['type']
|
|
task_type_lower = task_type.lower()
|
|
db_task = db_tasks.get(task_type)
|
|
|
|
# Get full configuration
|
|
config = cache_manager.tasks_config_cache.get_config(
|
|
task_type,
|
|
task_def.get('version', '1.0')
|
|
)
|
|
|
|
# Start with YAML values
|
|
task_description = config['task_description']
|
|
expected_output = config['expected_output']
|
|
|
|
# Apply DB values if they exist
|
|
if db_task:
|
|
for model_field, placeholder in self.TASK_FIELD_MAPPING.items():
|
|
value = getattr(db_task, model_field)
|
|
if value:
|
|
placeholder_text = "{" + placeholder + "}"
|
|
task_description = task_description.replace(placeholder_text, value)
|
|
expected_output = expected_output.replace(placeholder_text, value)
|
|
|
|
task_configs[task_type_lower] = ProcessedTaskConfig(
|
|
task_description=task_description,
|
|
expected_output=expected_output,
|
|
name=task_def.get('name') or config.get('name', task_type_lower),
|
|
type=task_type,
|
|
description=task_def.get('description') or config.get('description'),
|
|
verbose=self.verbose
|
|
)
|
|
|
|
return task_configs
|
|
|
|
def _process_tool_configs(self, specialist_config: Dict[str, Any]) -> Dict[str, ProcessedToolConfig]:
|
|
"""Process all tool configurations"""
|
|
tool_configs = {}
|
|
|
|
if 'tools' not in specialist_config:
|
|
return tool_configs
|
|
|
|
# Get all DB tools at once
|
|
tool_types = [tool_def['type'] for tool_def in specialist_config['tools']]
|
|
db_tools = self._get_db_items(EveAITool, tool_types)
|
|
|
|
for tool_def in specialist_config['tools']:
|
|
tool_type = tool_def['type']
|
|
tool_type_lower = tool_type.lower()
|
|
db_tool = db_tools.get(tool_type)
|
|
|
|
# Get full configuration
|
|
config = cache_manager.tools_config_cache.get_config(
|
|
tool_type,
|
|
tool_def.get('version', '1.0')
|
|
)
|
|
|
|
# Combine configuration
|
|
tool_config = config.get('configuration', {})
|
|
if db_tool and db_tool.configuration:
|
|
tool_config.update(db_tool.configuration)
|
|
|
|
tool_configs[tool_type_lower] = ProcessedToolConfig(
|
|
name=tool_def.get('name') or config.get('name', tool_type_lower),
|
|
type=tool_type,
|
|
description=tool_def.get('description') or config.get('description'),
|
|
configuration=tool_config,
|
|
verbose=self.verbose
|
|
)
|
|
|
|
return tool_configs
|
|
|
|
def process_config(self) -> SpecialistProcessedConfig:
|
|
"""Process complete specialist configuration"""
|
|
try:
|
|
# Get full specialist configuration
|
|
specialist_config = cache_manager.specialists_config_cache.get_config(
|
|
self.specialist.type,
|
|
self.specialist.type_version
|
|
)
|
|
|
|
if not specialist_config:
|
|
raise ValueError(f"No configuration found for {self.specialist.type}")
|
|
|
|
# Process all configurations
|
|
processed_config = SpecialistProcessedConfig(
|
|
agents=self._process_agent_configs(specialist_config),
|
|
tasks=self._process_task_configs(specialist_config),
|
|
tools=self._process_tool_configs(specialist_config)
|
|
)
|
|
return processed_config
|
|
|
|
except Exception as e:
|
|
current_app.logger.error(f"Error processing specialist configuration: {e}")
|
|
raise |