- Implementation of specialist execution api, including SSE protocol
- eveai_chat becomes deprecated and should be replaced with SSE - Adaptation of STANDARD_RAG specialist - Base class definition allowing to realise specialists with crewai framework - Implementation of SPIN_SPECIALIST - Implementation of test app for testing specialists (test_specialist_client). Also serves as an example for future SSE-based client - Improvements to startup scripts to better handle and scale multiple connections - Small improvements to the interaction forms and views - Caching implementation improved and augmented with additional caches
This commit is contained in:
@@ -13,10 +13,9 @@ from common.extensions import db, cache_manager
|
||||
from common.utils.celery_utils import current_celery
|
||||
from common.utils.business_event import BusinessEvent
|
||||
from common.utils.business_event_context import current_event
|
||||
from config.type_defs.specialist_types import SPECIALIST_TYPES
|
||||
from eveai_chat_workers.specialists.registry import SpecialistRegistry
|
||||
from config.type_defs.retriever_types import RETRIEVER_TYPES
|
||||
from eveai_chat_workers.specialists.specialist_typing import SpecialistArguments
|
||||
from eveai_chat_workers.specialists.base_specialist import get_specialist_class
|
||||
from common.utils.execution_progress import ExecutionProgressTracker
|
||||
|
||||
|
||||
# Healthcheck task
|
||||
@@ -30,18 +29,19 @@ class ArgumentPreparationError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def validate_specialist_arguments(specialist_type: str, arguments: Dict[str, Any]) -> None:
|
||||
def validate_specialist_arguments(specialist_type: str, specialist_type_version:str, arguments: Dict[str, Any]) -> None:
|
||||
"""
|
||||
Validate specialist-specific arguments
|
||||
|
||||
Args:
|
||||
specialist_type: Type of specialist
|
||||
specialist_type_version: Version of specialist type
|
||||
arguments: Arguments to validate (excluding retriever-specific arguments)
|
||||
|
||||
Raises:
|
||||
ArgumentPreparationError: If validation fails
|
||||
"""
|
||||
specialist_config = SPECIALIST_TYPES.get(specialist_type)
|
||||
specialist_config = cache_manager.specialists_config_cache.get_config(specialist_type, specialist_type_version)
|
||||
if not specialist_config:
|
||||
raise ArgumentPreparationError(f"Unknown specialist type: {specialist_type}")
|
||||
|
||||
@@ -61,20 +61,21 @@ def validate_specialist_arguments(specialist_type: str, arguments: Dict[str, Any
|
||||
raise ArgumentPreparationError(f"Argument '{arg_name}' must be an integer")
|
||||
|
||||
|
||||
def validate_retriever_arguments(retriever_type: str, arguments: Dict[str, Any],
|
||||
def validate_retriever_arguments(retriever_type: str, retriever_type_version: str, arguments: Dict[str, Any],
|
||||
catalog_config: Optional[Dict[str, Any]] = None) -> None:
|
||||
"""
|
||||
Validate retriever-specific arguments
|
||||
|
||||
Args:
|
||||
retriever_type: Type of retriever
|
||||
retriever_type_version: Version of retriever type
|
||||
arguments: Arguments to validate
|
||||
catalog_config: Optional catalog configuration for metadata validation
|
||||
|
||||
Raises:
|
||||
ArgumentPreparationError: If validation fails
|
||||
"""
|
||||
retriever_config = RETRIEVER_TYPES.get(retriever_type)
|
||||
retriever_config = cache_manager.retrievers_config_cache.get_config(retriever_type, retriever_type_version)
|
||||
if not retriever_config:
|
||||
raise ArgumentPreparationError(f"Unknown retriever type: {retriever_type}")
|
||||
|
||||
@@ -141,7 +142,7 @@ def prepare_arguments(specialist: Any, arguments: Dict[str, Any]) -> Dict[str, A
|
||||
specialist_args[key] = value
|
||||
|
||||
# Validate specialist arguments
|
||||
validate_specialist_arguments(specialist.type, specialist_args)
|
||||
validate_specialist_arguments(specialist.type, specialist.type_version, specialist_args)
|
||||
|
||||
# Get all retrievers associated with this specialist
|
||||
specialist_retrievers = (
|
||||
@@ -177,10 +178,11 @@ def prepare_arguments(specialist: Any, arguments: Dict[str, Any]) -> Dict[str, A
|
||||
|
||||
# Always include the retriever type
|
||||
inherited_args['type'] = retriever.type
|
||||
inherited_args['type_version'] = retriever.type_version
|
||||
|
||||
# Validate the combined arguments
|
||||
validate_retriever_arguments(
|
||||
retriever.type,
|
||||
retriever.type, retriever.type_version,
|
||||
inherited_args,
|
||||
catalog_config
|
||||
)
|
||||
@@ -202,9 +204,9 @@ def prepare_arguments(specialist: Any, arguments: Dict[str, Any]) -> Dict[str, A
|
||||
raise ArgumentPreparationError(str(e))
|
||||
|
||||
|
||||
@current_celery.task(name='execute_specialist', queue='llm_interactions')
|
||||
def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str, Any],
|
||||
session_id: str, user_timezone: str, room: str) -> dict:
|
||||
@current_celery.task(name='execute_specialist', queue='llm_interactions', bind=True)
|
||||
def execute_specialist(self, tenant_id: int, specialist_id: int, arguments: Dict[str, Any],
|
||||
session_id: str, user_timezone: str) -> dict:
|
||||
"""
|
||||
Execute a specialist with given arguments
|
||||
|
||||
@@ -214,15 +216,16 @@ def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str,
|
||||
arguments: Dictionary containing all required arguments for specialist and retrievers
|
||||
session_id: Chat session ID
|
||||
user_timezone: User's timezone
|
||||
room: Socket.IO room for the response
|
||||
|
||||
Returns:
|
||||
dict: {
|
||||
'result': Dict - Specialist execution result
|
||||
'interaction_id': int - Created interaction ID
|
||||
'room': str - Socket.IO room
|
||||
}
|
||||
"""
|
||||
task_id = self.request.id
|
||||
ept = ExecutionProgressTracker()
|
||||
ept.send_update(task_id, "EveAI Specialist Started", {})
|
||||
with BusinessEvent("Execute Specialist", tenant_id=tenant_id, chat_session_id=session_id) as event:
|
||||
current_app.logger.info(
|
||||
f'execute_specialist: Processing request for tenant {tenant_id} using specialist {specialist_id}')
|
||||
@@ -241,6 +244,10 @@ def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str,
|
||||
session_id,
|
||||
create_params={'timezone': user_timezone}
|
||||
)
|
||||
if cached_session:
|
||||
current_app.logger.debug(f"Cached Session successfully retrieved for {session_id}: {cached_session.id}")
|
||||
else:
|
||||
current_app.logger.debug(f"No Cached Session retrieved for {session_id}")
|
||||
|
||||
# Get specialist from database
|
||||
specialist = Specialist.query.get_or_404(specialist_id)
|
||||
@@ -251,6 +258,7 @@ def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str,
|
||||
# Convert the prepared arguments into a SpecialistArguments instance
|
||||
complete_arguments = SpecialistArguments.create(
|
||||
type_name=specialist.type,
|
||||
type_version=specialist.type_version,
|
||||
specialist_args={k: v for k, v in raw_arguments.items() if k != 'retriever_arguments'},
|
||||
retriever_args=raw_arguments.get('retriever_arguments', {})
|
||||
)
|
||||
@@ -276,12 +284,14 @@ def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str,
|
||||
raise
|
||||
|
||||
with current_event.create_span("Specialist invocation"):
|
||||
ept.send_update(task_id, "EveAI Specialist Start", {})
|
||||
# Initialize specialist instance
|
||||
specialist_class = SpecialistRegistry.get_specialist_class(specialist.type)
|
||||
specialist_class = get_specialist_class(specialist.type, specialist.type_version)
|
||||
specialist_instance = specialist_class(
|
||||
tenant_id=tenant_id,
|
||||
specialist_id=specialist_id,
|
||||
session_id=session_id,
|
||||
task_id=task_id,
|
||||
)
|
||||
|
||||
# Execute specialist
|
||||
@@ -304,13 +314,14 @@ def execute_specialist(tenant_id: int, specialist_id: int, arguments: Dict[str,
|
||||
# Prepare response
|
||||
response = {
|
||||
'result': result.model_dump(),
|
||||
'interaction_id': new_interaction.id,
|
||||
'room': room
|
||||
'interaction_id': new_interaction.id
|
||||
}
|
||||
ept.send_update(task_id, "EveAI Specialist Complete", response)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
ept.send_update(task_id, "EveAI Specialist Error", {'Error': str(e)})
|
||||
current_app.logger.error(f'execute_specialist: Error executing specialist: {e}')
|
||||
raise
|
||||
|
||||
|
||||
Reference in New Issue
Block a user