aiecs 1.5.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Lifecycle Management
|
|
3
|
+
|
|
4
|
+
Manages agent lifecycle transitions and state management.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, Any, Optional, List
|
|
9
|
+
|
|
10
|
+
from .base_agent import BaseAIAgent
|
|
11
|
+
from .models import AgentState
|
|
12
|
+
from .registry import AgentRegistry, get_global_registry
|
|
13
|
+
from .exceptions import (
|
|
14
|
+
AgentInitializationError,
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class AgentLifecycleManager:
|
|
21
|
+
"""
|
|
22
|
+
Manages agent lifecycle: creation, initialization, activation, deactivation, shutdown.
|
|
23
|
+
|
|
24
|
+
Ensures proper state transitions and coordinates with registry.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(self, registry: Optional[AgentRegistry] = None):
|
|
28
|
+
"""
|
|
29
|
+
Initialize lifecycle manager.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
registry: Optional custom registry (uses global if not provided)
|
|
33
|
+
"""
|
|
34
|
+
self.registry = registry or get_global_registry()
|
|
35
|
+
logger.info("AgentLifecycleManager initialized")
|
|
36
|
+
|
|
37
|
+
async def create_and_initialize(self, agent: BaseAIAgent) -> BaseAIAgent:
|
|
38
|
+
"""
|
|
39
|
+
Register and initialize an agent.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
agent: Agent to initialize
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Initialized agent
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
AgentInitializationError: If initialization fails
|
|
49
|
+
"""
|
|
50
|
+
try:
|
|
51
|
+
# Register agent
|
|
52
|
+
self.registry.register(agent)
|
|
53
|
+
logger.info(f"Agent {agent.agent_id} registered")
|
|
54
|
+
|
|
55
|
+
# Initialize agent
|
|
56
|
+
await agent.initialize()
|
|
57
|
+
logger.info(f"Agent {agent.agent_id} initialized")
|
|
58
|
+
|
|
59
|
+
return agent
|
|
60
|
+
|
|
61
|
+
except Exception as e:
|
|
62
|
+
logger.error(f"Failed to create and initialize agent {agent.agent_id}: {e}")
|
|
63
|
+
|
|
64
|
+
# Cleanup on failure
|
|
65
|
+
try:
|
|
66
|
+
if self.registry.exists(agent.agent_id):
|
|
67
|
+
self.registry.unregister(agent.agent_id)
|
|
68
|
+
except Exception as cleanup_error:
|
|
69
|
+
logger.error(f"Cleanup failed: {cleanup_error}")
|
|
70
|
+
|
|
71
|
+
raise AgentInitializationError(
|
|
72
|
+
f"Agent initialization failed: {str(e)}",
|
|
73
|
+
agent_id=agent.agent_id,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
async def activate(self, agent_id: str) -> None:
|
|
77
|
+
"""
|
|
78
|
+
Activate an agent.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
agent_id: Agent identifier
|
|
82
|
+
|
|
83
|
+
Raises:
|
|
84
|
+
AgentNotFoundError: If agent not found
|
|
85
|
+
InvalidStateTransitionError: If activation not allowed
|
|
86
|
+
"""
|
|
87
|
+
agent = self.registry.get(agent_id)
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
await agent.activate()
|
|
91
|
+
logger.info(f"Agent {agent_id} activated")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
logger.error(f"Failed to activate agent {agent_id}: {e}")
|
|
94
|
+
raise
|
|
95
|
+
|
|
96
|
+
async def deactivate(self, agent_id: str) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Deactivate an agent.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
agent_id: Agent identifier
|
|
102
|
+
|
|
103
|
+
Raises:
|
|
104
|
+
AgentNotFoundError: If agent not found
|
|
105
|
+
InvalidStateTransitionError: If deactivation not allowed
|
|
106
|
+
"""
|
|
107
|
+
agent = self.registry.get(agent_id)
|
|
108
|
+
|
|
109
|
+
try:
|
|
110
|
+
await agent.deactivate()
|
|
111
|
+
logger.info(f"Agent {agent_id} deactivated")
|
|
112
|
+
except Exception as e:
|
|
113
|
+
logger.error(f"Failed to deactivate agent {agent_id}: {e}")
|
|
114
|
+
raise
|
|
115
|
+
|
|
116
|
+
async def shutdown(self, agent_id: str, unregister: bool = True) -> None:
|
|
117
|
+
"""
|
|
118
|
+
Shutdown an agent.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
agent_id: Agent identifier
|
|
122
|
+
unregister: Whether to unregister after shutdown
|
|
123
|
+
|
|
124
|
+
Raises:
|
|
125
|
+
AgentNotFoundError: If agent not found
|
|
126
|
+
"""
|
|
127
|
+
agent = self.registry.get(agent_id)
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
await agent.shutdown()
|
|
131
|
+
logger.info(f"Agent {agent_id} shut down")
|
|
132
|
+
|
|
133
|
+
if unregister:
|
|
134
|
+
self.registry.unregister(agent_id)
|
|
135
|
+
logger.info(f"Agent {agent_id} unregistered")
|
|
136
|
+
|
|
137
|
+
except Exception as e:
|
|
138
|
+
logger.error(f"Failed to shutdown agent {agent_id}: {e}")
|
|
139
|
+
raise
|
|
140
|
+
|
|
141
|
+
async def restart(self, agent_id: str) -> None:
|
|
142
|
+
"""
|
|
143
|
+
Restart an agent (deactivate → initialize → activate).
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
agent_id: Agent identifier
|
|
147
|
+
|
|
148
|
+
Raises:
|
|
149
|
+
AgentNotFoundError: If agent not found
|
|
150
|
+
"""
|
|
151
|
+
agent = self.registry.get(agent_id)
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
# Deactivate
|
|
155
|
+
if agent.state in [AgentState.ACTIVE, AgentState.BUSY]:
|
|
156
|
+
await agent.deactivate()
|
|
157
|
+
|
|
158
|
+
# Re-initialize
|
|
159
|
+
await agent.initialize()
|
|
160
|
+
|
|
161
|
+
# Re-activate
|
|
162
|
+
await agent.activate()
|
|
163
|
+
|
|
164
|
+
logger.info(f"Agent {agent_id} restarted")
|
|
165
|
+
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.error(f"Failed to restart agent {agent_id}: {e}")
|
|
168
|
+
raise
|
|
169
|
+
|
|
170
|
+
async def shutdown_all(self) -> Dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
Shutdown all registered agents.
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
Dictionary with shutdown results
|
|
176
|
+
"""
|
|
177
|
+
results = {
|
|
178
|
+
"success": [],
|
|
179
|
+
"failed": [],
|
|
180
|
+
"total": self.registry.count(),
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
agents = self.registry.list_all()
|
|
184
|
+
|
|
185
|
+
for agent in agents:
|
|
186
|
+
try:
|
|
187
|
+
await self.shutdown(agent.agent_id, unregister=True)
|
|
188
|
+
results["success"].append(agent.agent_id)
|
|
189
|
+
except Exception as e:
|
|
190
|
+
logger.error(f"Failed to shutdown agent {agent.agent_id}: {e}")
|
|
191
|
+
results["failed"].append(
|
|
192
|
+
{
|
|
193
|
+
"agent_id": agent.agent_id,
|
|
194
|
+
"error": str(e),
|
|
195
|
+
}
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
logger.info(
|
|
199
|
+
f"Shutdown all agents: {len(results['success'])} succeeded, "
|
|
200
|
+
f"{len(results['failed'])} failed"
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
return results
|
|
204
|
+
|
|
205
|
+
def get_agent_status(self, agent_id: str) -> Dict[str, Any]:
|
|
206
|
+
"""
|
|
207
|
+
Get agent status information.
|
|
208
|
+
|
|
209
|
+
Args:
|
|
210
|
+
agent_id: Agent identifier
|
|
211
|
+
|
|
212
|
+
Returns:
|
|
213
|
+
Status dictionary
|
|
214
|
+
|
|
215
|
+
Raises:
|
|
216
|
+
AgentNotFoundError: If agent not found
|
|
217
|
+
"""
|
|
218
|
+
agent = self.registry.get(agent_id)
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
"agent_id": agent.agent_id,
|
|
222
|
+
"name": agent.name,
|
|
223
|
+
"type": agent.agent_type.value,
|
|
224
|
+
"state": agent.state.value,
|
|
225
|
+
"version": agent.version,
|
|
226
|
+
"created_at": (agent.created_at.isoformat() if agent.created_at else None),
|
|
227
|
+
"last_active_at": (agent.last_active_at.isoformat() if agent.last_active_at else None),
|
|
228
|
+
"current_task_id": agent._current_task_id,
|
|
229
|
+
"metrics": {
|
|
230
|
+
"total_tasks_executed": agent.get_metrics().total_tasks_executed,
|
|
231
|
+
"successful_tasks": agent.get_metrics().successful_tasks,
|
|
232
|
+
"failed_tasks": agent.get_metrics().failed_tasks,
|
|
233
|
+
"average_execution_time": agent.get_metrics().average_execution_time,
|
|
234
|
+
"total_tool_calls": agent.get_metrics().total_tool_calls,
|
|
235
|
+
},
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
def list_agent_statuses(
|
|
239
|
+
self, agent_type: Optional[str] = None, state: Optional[str] = None
|
|
240
|
+
) -> "List[Dict[str, Any]]":
|
|
241
|
+
"""
|
|
242
|
+
List agent statuses with optional filtering.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
agent_type: Optional filter by agent type
|
|
246
|
+
state: Optional filter by state
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
List of status dictionaries
|
|
250
|
+
"""
|
|
251
|
+
agents = self.registry.list_all()
|
|
252
|
+
|
|
253
|
+
# Filter by type
|
|
254
|
+
if agent_type:
|
|
255
|
+
from .models import AgentType
|
|
256
|
+
|
|
257
|
+
try:
|
|
258
|
+
type_enum = AgentType(agent_type)
|
|
259
|
+
agents = [a for a in agents if a.agent_type == type_enum]
|
|
260
|
+
except ValueError:
|
|
261
|
+
logger.warning(f"Invalid agent type: {agent_type}")
|
|
262
|
+
|
|
263
|
+
# Filter by state
|
|
264
|
+
if state:
|
|
265
|
+
from .models import AgentState
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
state_enum = AgentState(state)
|
|
269
|
+
agents = [a for a in agents if a.state == state_enum]
|
|
270
|
+
except ValueError:
|
|
271
|
+
logger.warning(f"Invalid state: {state}")
|
|
272
|
+
|
|
273
|
+
return [self.get_agent_status(a.agent_id) for a in agents]
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
# Global lifecycle manager
|
|
277
|
+
_global_lifecycle_manager: Optional[AgentLifecycleManager] = None
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
def get_global_lifecycle_manager() -> AgentLifecycleManager:
|
|
281
|
+
"""
|
|
282
|
+
Get or create global lifecycle manager.
|
|
283
|
+
|
|
284
|
+
Returns:
|
|
285
|
+
Global AgentLifecycleManager instance
|
|
286
|
+
"""
|
|
287
|
+
global _global_lifecycle_manager
|
|
288
|
+
if _global_lifecycle_manager is None:
|
|
289
|
+
_global_lifecycle_manager = AgentLifecycleManager()
|
|
290
|
+
return _global_lifecycle_manager
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
def reset_global_lifecycle_manager() -> None:
|
|
294
|
+
"""Reset global lifecycle manager (primarily for testing)."""
|
|
295
|
+
global _global_lifecycle_manager
|
|
296
|
+
_global_lifecycle_manager = None
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
"""
|
|
2
|
+
LLM Agent
|
|
3
|
+
|
|
4
|
+
Agent implementation powered by LLM for text generation and reasoning.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, List, Any, Optional
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from aiecs.llm import BaseLLMClient, LLMMessage
|
|
12
|
+
|
|
13
|
+
from .base_agent import BaseAIAgent
|
|
14
|
+
from .models import AgentType, AgentConfiguration
|
|
15
|
+
from .exceptions import TaskExecutionError
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class LLMAgent(BaseAIAgent):
|
|
21
|
+
"""
|
|
22
|
+
LLM-powered agent for text generation and reasoning.
|
|
23
|
+
|
|
24
|
+
This agent uses an LLM client to process tasks and generate responses.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
agent_id: str,
|
|
30
|
+
name: str,
|
|
31
|
+
llm_client: BaseLLMClient,
|
|
32
|
+
config: AgentConfiguration,
|
|
33
|
+
description: Optional[str] = None,
|
|
34
|
+
version: str = "1.0.0",
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Initialize LLM agent.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
agent_id: Unique agent identifier
|
|
41
|
+
name: Agent name
|
|
42
|
+
llm_client: LLM client instance
|
|
43
|
+
config: Agent configuration
|
|
44
|
+
description: Optional description
|
|
45
|
+
version: Agent version
|
|
46
|
+
"""
|
|
47
|
+
super().__init__(
|
|
48
|
+
agent_id=agent_id,
|
|
49
|
+
name=name,
|
|
50
|
+
agent_type=AgentType.CONVERSATIONAL,
|
|
51
|
+
config=config,
|
|
52
|
+
description=description or "LLM-powered conversational agent",
|
|
53
|
+
version=version,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self.llm_client = llm_client
|
|
57
|
+
self._system_prompt: Optional[str] = None
|
|
58
|
+
self._conversation_history: List[LLMMessage] = []
|
|
59
|
+
|
|
60
|
+
logger.info(f"LLMAgent initialized: {agent_id} with client {llm_client.provider_name}")
|
|
61
|
+
|
|
62
|
+
async def _initialize(self) -> None:
|
|
63
|
+
"""Initialize LLM agent."""
|
|
64
|
+
# Build system prompt
|
|
65
|
+
self._system_prompt = self._build_system_prompt()
|
|
66
|
+
logger.debug(f"LLMAgent {self.agent_id} initialized with system prompt")
|
|
67
|
+
|
|
68
|
+
async def _shutdown(self) -> None:
|
|
69
|
+
"""Shutdown LLM agent."""
|
|
70
|
+
# Clear conversation history
|
|
71
|
+
self._conversation_history.clear()
|
|
72
|
+
|
|
73
|
+
# Close LLM client if it has a close method
|
|
74
|
+
if hasattr(self.llm_client, "close"):
|
|
75
|
+
await self.llm_client.close()
|
|
76
|
+
|
|
77
|
+
logger.info(f"LLMAgent {self.agent_id} shut down")
|
|
78
|
+
|
|
79
|
+
def _build_system_prompt(self) -> str:
|
|
80
|
+
"""Build system prompt from configuration."""
|
|
81
|
+
parts = []
|
|
82
|
+
|
|
83
|
+
if self._config.goal:
|
|
84
|
+
parts.append(f"Goal: {self._config.goal}")
|
|
85
|
+
|
|
86
|
+
if self._config.backstory:
|
|
87
|
+
parts.append(f"Background: {self._config.backstory}")
|
|
88
|
+
|
|
89
|
+
if self._config.domain_knowledge:
|
|
90
|
+
parts.append(f"Domain Knowledge: {self._config.domain_knowledge}")
|
|
91
|
+
|
|
92
|
+
if self._config.reasoning_guidance:
|
|
93
|
+
parts.append(f"Reasoning Approach: {self._config.reasoning_guidance}")
|
|
94
|
+
|
|
95
|
+
if not parts:
|
|
96
|
+
return "You are a helpful AI assistant."
|
|
97
|
+
|
|
98
|
+
return "\n\n".join(parts)
|
|
99
|
+
|
|
100
|
+
async def execute_task(self, task: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
|
|
101
|
+
"""
|
|
102
|
+
Execute a task using the LLM.
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
task: Task specification with 'description' or 'prompt'
|
|
106
|
+
context: Execution context
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
Execution result with 'output', 'reasoning', 'tokens_used'
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
TaskExecutionError: If task execution fails
|
|
113
|
+
"""
|
|
114
|
+
start_time = datetime.utcnow()
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
# Extract task description
|
|
118
|
+
task_description = task.get("description") or task.get("prompt") or task.get("task")
|
|
119
|
+
if not task_description:
|
|
120
|
+
raise TaskExecutionError(
|
|
121
|
+
"Task must contain 'description', 'prompt', or 'task' field",
|
|
122
|
+
agent_id=self.agent_id,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# Transition to busy state
|
|
126
|
+
self._transition_state(self.state.__class__.BUSY)
|
|
127
|
+
self._current_task_id = task.get("task_id")
|
|
128
|
+
|
|
129
|
+
# Build messages
|
|
130
|
+
messages = self._build_messages(task_description, context)
|
|
131
|
+
|
|
132
|
+
# Call LLM
|
|
133
|
+
response = await self.llm_client.generate_text(
|
|
134
|
+
messages=messages,
|
|
135
|
+
model=self._config.llm_model,
|
|
136
|
+
temperature=self._config.temperature,
|
|
137
|
+
max_tokens=self._config.max_tokens,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
# Extract result
|
|
141
|
+
output = response.content
|
|
142
|
+
|
|
143
|
+
# Store in conversation history if enabled
|
|
144
|
+
if self._config.memory_enabled:
|
|
145
|
+
self._conversation_history.append(LLMMessage(role="user", content=task_description))
|
|
146
|
+
self._conversation_history.append(LLMMessage(role="assistant", content=output))
|
|
147
|
+
|
|
148
|
+
# Calculate execution time
|
|
149
|
+
execution_time = (datetime.utcnow() - start_time).total_seconds()
|
|
150
|
+
|
|
151
|
+
# Update metrics
|
|
152
|
+
self.update_metrics(
|
|
153
|
+
execution_time=execution_time,
|
|
154
|
+
success=True,
|
|
155
|
+
tokens_used=getattr(response, "total_tokens", None),
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Transition back to active
|
|
159
|
+
self._transition_state(self.state.__class__.ACTIVE)
|
|
160
|
+
self._current_task_id = None
|
|
161
|
+
self.last_active_at = datetime.utcnow()
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
"success": True,
|
|
165
|
+
"output": output,
|
|
166
|
+
"provider": response.provider,
|
|
167
|
+
"model": response.model,
|
|
168
|
+
"tokens_used": getattr(response, "total_tokens", None),
|
|
169
|
+
"execution_time": execution_time,
|
|
170
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
logger.error(f"Task execution failed for {self.agent_id}: {e}")
|
|
175
|
+
|
|
176
|
+
# Update metrics for failure
|
|
177
|
+
execution_time = (datetime.utcnow() - start_time).total_seconds()
|
|
178
|
+
self.update_metrics(execution_time=execution_time, success=False)
|
|
179
|
+
|
|
180
|
+
# Transition to error state
|
|
181
|
+
self._transition_state(self.state.__class__.ERROR)
|
|
182
|
+
self._current_task_id = None
|
|
183
|
+
|
|
184
|
+
raise TaskExecutionError(
|
|
185
|
+
f"Task execution failed: {str(e)}",
|
|
186
|
+
agent_id=self.agent_id,
|
|
187
|
+
task_id=task.get("task_id"),
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
async def process_message(
|
|
191
|
+
self, message: str, sender_id: Optional[str] = None
|
|
192
|
+
) -> Dict[str, Any]:
|
|
193
|
+
"""
|
|
194
|
+
Process an incoming message.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
message: Message content
|
|
198
|
+
sender_id: Optional sender identifier
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Response dictionary with 'response', 'tokens_used'
|
|
202
|
+
"""
|
|
203
|
+
try:
|
|
204
|
+
# Build task from message
|
|
205
|
+
task = {
|
|
206
|
+
"description": message,
|
|
207
|
+
"task_id": f"msg_{datetime.utcnow().timestamp()}",
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# Execute as task
|
|
211
|
+
result = await self.execute_task(task, {"sender_id": sender_id})
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
"response": result.get("output"),
|
|
215
|
+
"tokens_used": result.get("tokens_used"),
|
|
216
|
+
"timestamp": result.get("timestamp"),
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
except Exception as e:
|
|
220
|
+
logger.error(f"Message processing failed for {self.agent_id}: {e}")
|
|
221
|
+
raise
|
|
222
|
+
|
|
223
|
+
def _build_messages(self, user_message: str, context: Dict[str, Any]) -> List[LLMMessage]:
|
|
224
|
+
"""
|
|
225
|
+
Build LLM messages from task and context.
|
|
226
|
+
|
|
227
|
+
Args:
|
|
228
|
+
user_message: User message
|
|
229
|
+
context: Context dictionary
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
List of LLM messages
|
|
233
|
+
"""
|
|
234
|
+
messages = []
|
|
235
|
+
|
|
236
|
+
# Add system prompt
|
|
237
|
+
if self._system_prompt:
|
|
238
|
+
messages.append(LLMMessage(role="system", content=self._system_prompt))
|
|
239
|
+
|
|
240
|
+
# Add conversation history if available and memory enabled
|
|
241
|
+
if self._config.memory_enabled and self._conversation_history:
|
|
242
|
+
# Limit history to prevent token overflow
|
|
243
|
+
max_history = 10 # Keep last 10 exchanges
|
|
244
|
+
messages.extend(self._conversation_history[-max_history:])
|
|
245
|
+
|
|
246
|
+
# Add additional context if provided
|
|
247
|
+
if context:
|
|
248
|
+
context_str = self._format_context(context)
|
|
249
|
+
if context_str:
|
|
250
|
+
messages.append(
|
|
251
|
+
LLMMessage(
|
|
252
|
+
role="system",
|
|
253
|
+
content=f"Additional Context:\n{context_str}",
|
|
254
|
+
)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
# Add user message
|
|
258
|
+
messages.append(LLMMessage(role="user", content=user_message))
|
|
259
|
+
|
|
260
|
+
return messages
|
|
261
|
+
|
|
262
|
+
def _format_context(self, context: Dict[str, Any]) -> str:
|
|
263
|
+
"""Format context dictionary as string."""
|
|
264
|
+
relevant_fields = []
|
|
265
|
+
|
|
266
|
+
# Filter out internal fields
|
|
267
|
+
for key, value in context.items():
|
|
268
|
+
if not key.startswith("_") and value is not None:
|
|
269
|
+
relevant_fields.append(f"{key}: {value}")
|
|
270
|
+
|
|
271
|
+
return "\n".join(relevant_fields) if relevant_fields else ""
|
|
272
|
+
|
|
273
|
+
def clear_conversation_history(self) -> None:
|
|
274
|
+
"""Clear conversation history."""
|
|
275
|
+
self._conversation_history.clear()
|
|
276
|
+
logger.info(f"LLMAgent {self.agent_id} conversation history cleared")
|
|
277
|
+
|
|
278
|
+
def get_conversation_history(self) -> List[Dict[str, str]]:
|
|
279
|
+
"""Get conversation history."""
|
|
280
|
+
return [{"role": msg.role, "content": msg.content} for msg in self._conversation_history]
|
|
281
|
+
|
|
282
|
+
@classmethod
|
|
283
|
+
def from_dict(cls, data: Dict[str, Any]) -> "LLMAgent":
|
|
284
|
+
"""
|
|
285
|
+
Deserialize LLMAgent from dictionary.
|
|
286
|
+
|
|
287
|
+
Note: LLM client must be provided separately as it cannot be serialized.
|
|
288
|
+
|
|
289
|
+
Args:
|
|
290
|
+
data: Dictionary representation
|
|
291
|
+
|
|
292
|
+
Returns:
|
|
293
|
+
LLMAgent instance
|
|
294
|
+
"""
|
|
295
|
+
# This is a placeholder - actual implementation would require
|
|
296
|
+
# providing the LLM client separately
|
|
297
|
+
raise NotImplementedError(
|
|
298
|
+
"LLMAgent.from_dict requires LLM client to be provided separately. "
|
|
299
|
+
"Use constructor instead."
|
|
300
|
+
)
|