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,260 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Registry
|
|
3
|
+
|
|
4
|
+
Central registry for tracking and managing active agents.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, List, Optional, Set
|
|
9
|
+
|
|
10
|
+
from .base_agent import BaseAIAgent
|
|
11
|
+
from .models import AgentState, AgentType
|
|
12
|
+
from .exceptions import AgentNotFoundError, AgentAlreadyRegisteredError
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AgentRegistry:
|
|
18
|
+
"""
|
|
19
|
+
Central registry for tracking and managing active agents.
|
|
20
|
+
|
|
21
|
+
Thread-safe registry for agent lifecycle management.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
def __init__(self):
|
|
25
|
+
"""Initialize agent registry."""
|
|
26
|
+
self._agents: Dict[str, BaseAIAgent] = {}
|
|
27
|
+
self._agents_by_type: Dict[AgentType, Set[str]] = {}
|
|
28
|
+
self._agents_by_state: Dict[AgentState, Set[str]] = {}
|
|
29
|
+
|
|
30
|
+
logger.info("AgentRegistry initialized")
|
|
31
|
+
|
|
32
|
+
def register(self, agent: BaseAIAgent) -> None:
|
|
33
|
+
"""
|
|
34
|
+
Register an agent.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
agent: Agent to register
|
|
38
|
+
|
|
39
|
+
Raises:
|
|
40
|
+
AgentAlreadyRegisteredError: If agent already registered
|
|
41
|
+
"""
|
|
42
|
+
if agent.agent_id in self._agents:
|
|
43
|
+
raise AgentAlreadyRegisteredError(agent.agent_id)
|
|
44
|
+
|
|
45
|
+
# Register agent
|
|
46
|
+
self._agents[agent.agent_id] = agent
|
|
47
|
+
|
|
48
|
+
# Index by type
|
|
49
|
+
if agent.agent_type not in self._agents_by_type:
|
|
50
|
+
self._agents_by_type[agent.agent_type] = set()
|
|
51
|
+
self._agents_by_type[agent.agent_type].add(agent.agent_id)
|
|
52
|
+
|
|
53
|
+
# Index by state
|
|
54
|
+
if agent.state not in self._agents_by_state:
|
|
55
|
+
self._agents_by_state[agent.state] = set()
|
|
56
|
+
self._agents_by_state[agent.state].add(agent.agent_id)
|
|
57
|
+
|
|
58
|
+
logger.info(f"Agent registered: {agent.agent_id} ({agent.agent_type.value})")
|
|
59
|
+
|
|
60
|
+
def unregister(self, agent_id: str) -> None:
|
|
61
|
+
"""
|
|
62
|
+
Unregister an agent.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
agent_id: Agent identifier
|
|
66
|
+
|
|
67
|
+
Raises:
|
|
68
|
+
AgentNotFoundError: If agent not found
|
|
69
|
+
"""
|
|
70
|
+
agent = self.get(agent_id)
|
|
71
|
+
|
|
72
|
+
# Remove from indexes
|
|
73
|
+
if agent.agent_type in self._agents_by_type:
|
|
74
|
+
self._agents_by_type[agent.agent_type].discard(agent_id)
|
|
75
|
+
|
|
76
|
+
if agent.state in self._agents_by_state:
|
|
77
|
+
self._agents_by_state[agent.state].discard(agent_id)
|
|
78
|
+
|
|
79
|
+
# Remove from main registry
|
|
80
|
+
del self._agents[agent_id]
|
|
81
|
+
|
|
82
|
+
logger.info(f"Agent unregistered: {agent_id}")
|
|
83
|
+
|
|
84
|
+
def get(self, agent_id: str) -> BaseAIAgent:
|
|
85
|
+
"""
|
|
86
|
+
Get agent by ID.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
agent_id: Agent identifier
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Agent instance
|
|
93
|
+
|
|
94
|
+
Raises:
|
|
95
|
+
AgentNotFoundError: If agent not found
|
|
96
|
+
"""
|
|
97
|
+
if agent_id not in self._agents:
|
|
98
|
+
raise AgentNotFoundError(agent_id)
|
|
99
|
+
|
|
100
|
+
return self._agents[agent_id]
|
|
101
|
+
|
|
102
|
+
def get_optional(self, agent_id: str) -> Optional[BaseAIAgent]:
|
|
103
|
+
"""
|
|
104
|
+
Get agent by ID, returning None if not found.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
agent_id: Agent identifier
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Agent instance or None
|
|
111
|
+
"""
|
|
112
|
+
return self._agents.get(agent_id)
|
|
113
|
+
|
|
114
|
+
def exists(self, agent_id: str) -> bool:
|
|
115
|
+
"""
|
|
116
|
+
Check if agent exists.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
agent_id: Agent identifier
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
True if agent exists
|
|
123
|
+
"""
|
|
124
|
+
return agent_id in self._agents
|
|
125
|
+
|
|
126
|
+
def list_all(self) -> List[BaseAIAgent]:
|
|
127
|
+
"""
|
|
128
|
+
List all registered agents.
|
|
129
|
+
|
|
130
|
+
Returns:
|
|
131
|
+
List of all agents
|
|
132
|
+
"""
|
|
133
|
+
return list(self._agents.values())
|
|
134
|
+
|
|
135
|
+
def list_by_type(self, agent_type: AgentType) -> List[BaseAIAgent]:
|
|
136
|
+
"""
|
|
137
|
+
List agents by type.
|
|
138
|
+
|
|
139
|
+
Args:
|
|
140
|
+
agent_type: Agent type
|
|
141
|
+
|
|
142
|
+
Returns:
|
|
143
|
+
List of agents of specified type
|
|
144
|
+
"""
|
|
145
|
+
agent_ids = self._agents_by_type.get(agent_type, set())
|
|
146
|
+
return [self._agents[aid] for aid in agent_ids if aid in self._agents]
|
|
147
|
+
|
|
148
|
+
def list_by_state(self, state: AgentState) -> List[BaseAIAgent]:
|
|
149
|
+
"""
|
|
150
|
+
List agents by state.
|
|
151
|
+
|
|
152
|
+
Args:
|
|
153
|
+
state: Agent state
|
|
154
|
+
|
|
155
|
+
Returns:
|
|
156
|
+
List of agents in specified state
|
|
157
|
+
"""
|
|
158
|
+
agent_ids = self._agents_by_state.get(state, set())
|
|
159
|
+
return [self._agents[aid] for aid in agent_ids if aid in self._agents]
|
|
160
|
+
|
|
161
|
+
def update_state_index(
|
|
162
|
+
self, agent_id: str, old_state: AgentState, new_state: AgentState
|
|
163
|
+
) -> None:
|
|
164
|
+
"""
|
|
165
|
+
Update state index when agent state changes.
|
|
166
|
+
|
|
167
|
+
Args:
|
|
168
|
+
agent_id: Agent identifier
|
|
169
|
+
old_state: Previous state
|
|
170
|
+
new_state: New state
|
|
171
|
+
"""
|
|
172
|
+
# Remove from old state index
|
|
173
|
+
if old_state in self._agents_by_state:
|
|
174
|
+
self._agents_by_state[old_state].discard(agent_id)
|
|
175
|
+
|
|
176
|
+
# Add to new state index
|
|
177
|
+
if new_state not in self._agents_by_state:
|
|
178
|
+
self._agents_by_state[new_state] = set()
|
|
179
|
+
self._agents_by_state[new_state].add(agent_id)
|
|
180
|
+
|
|
181
|
+
def count(self) -> int:
|
|
182
|
+
"""
|
|
183
|
+
Get total number of registered agents.
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
Number of agents
|
|
187
|
+
"""
|
|
188
|
+
return len(self._agents)
|
|
189
|
+
|
|
190
|
+
def count_by_type(self, agent_type: AgentType) -> int:
|
|
191
|
+
"""
|
|
192
|
+
Get count of agents by type.
|
|
193
|
+
|
|
194
|
+
Args:
|
|
195
|
+
agent_type: Agent type
|
|
196
|
+
|
|
197
|
+
Returns:
|
|
198
|
+
Number of agents of specified type
|
|
199
|
+
"""
|
|
200
|
+
return len(self._agents_by_type.get(agent_type, set()))
|
|
201
|
+
|
|
202
|
+
def count_by_state(self, state: AgentState) -> int:
|
|
203
|
+
"""
|
|
204
|
+
Get count of agents by state.
|
|
205
|
+
|
|
206
|
+
Args:
|
|
207
|
+
state: Agent state
|
|
208
|
+
|
|
209
|
+
Returns:
|
|
210
|
+
Number of agents in specified state
|
|
211
|
+
"""
|
|
212
|
+
return len(self._agents_by_state.get(state, set()))
|
|
213
|
+
|
|
214
|
+
def get_stats(self) -> Dict:
|
|
215
|
+
"""
|
|
216
|
+
Get registry statistics.
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
Dictionary with stats
|
|
220
|
+
"""
|
|
221
|
+
return {
|
|
222
|
+
"total_agents": self.count(),
|
|
223
|
+
"by_type": {
|
|
224
|
+
agent_type.value: len(agent_ids)
|
|
225
|
+
for agent_type, agent_ids in self._agents_by_type.items()
|
|
226
|
+
},
|
|
227
|
+
"by_state": {
|
|
228
|
+
state.value: len(agent_ids) for state, agent_ids in self._agents_by_state.items()
|
|
229
|
+
},
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
def clear(self) -> None:
|
|
233
|
+
"""Clear all agents from registry."""
|
|
234
|
+
self._agents.clear()
|
|
235
|
+
self._agents_by_type.clear()
|
|
236
|
+
self._agents_by_state.clear()
|
|
237
|
+
logger.info("AgentRegistry cleared")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# Global registry instance
|
|
241
|
+
_global_registry: Optional[AgentRegistry] = None
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def get_global_registry() -> AgentRegistry:
|
|
245
|
+
"""
|
|
246
|
+
Get or create global agent registry.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
Global AgentRegistry instance
|
|
250
|
+
"""
|
|
251
|
+
global _global_registry
|
|
252
|
+
if _global_registry is None:
|
|
253
|
+
_global_registry = AgentRegistry()
|
|
254
|
+
return _global_registry
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def reset_global_registry() -> None:
|
|
258
|
+
"""Reset global registry (primarily for testing)."""
|
|
259
|
+
global _global_registry
|
|
260
|
+
_global_registry = None
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Tool Agent
|
|
3
|
+
|
|
4
|
+
Agent implementation specialized in tool usage and execution.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, List, Any, Optional
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from aiecs.tools import get_tool, BaseTool
|
|
12
|
+
|
|
13
|
+
from .base_agent import BaseAIAgent
|
|
14
|
+
from .models import AgentType, AgentConfiguration
|
|
15
|
+
from .exceptions import TaskExecutionError, ToolAccessDeniedError
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class ToolAgent(BaseAIAgent):
|
|
21
|
+
"""
|
|
22
|
+
Agent specialized in tool selection and execution.
|
|
23
|
+
|
|
24
|
+
This agent can execute one or more tools to complete tasks.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
agent_id: str,
|
|
30
|
+
name: str,
|
|
31
|
+
tools: List[str],
|
|
32
|
+
config: AgentConfiguration,
|
|
33
|
+
description: Optional[str] = None,
|
|
34
|
+
version: str = "1.0.0",
|
|
35
|
+
):
|
|
36
|
+
"""
|
|
37
|
+
Initialize Tool agent.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
agent_id: Unique agent identifier
|
|
41
|
+
name: Agent name
|
|
42
|
+
tools: List of tool names agent can use
|
|
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.TASK_EXECUTOR,
|
|
51
|
+
config=config,
|
|
52
|
+
description=description or "Tool-based task execution agent",
|
|
53
|
+
version=version,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
self._available_tools = tools
|
|
57
|
+
self._tool_instances: Dict[str, BaseTool] = {}
|
|
58
|
+
self._tool_usage_stats: Dict[str, Dict[str, int]] = {}
|
|
59
|
+
|
|
60
|
+
logger.info(f"ToolAgent initialized: {agent_id} with tools: {', '.join(tools)}")
|
|
61
|
+
|
|
62
|
+
async def _initialize(self) -> None:
|
|
63
|
+
"""Initialize Tool agent - load tools."""
|
|
64
|
+
# Load tool instances
|
|
65
|
+
for tool_name in self._available_tools:
|
|
66
|
+
try:
|
|
67
|
+
self._tool_instances[tool_name] = get_tool(tool_name)
|
|
68
|
+
self._tool_usage_stats[tool_name] = {
|
|
69
|
+
"success_count": 0,
|
|
70
|
+
"failure_count": 0,
|
|
71
|
+
"total_count": 0,
|
|
72
|
+
}
|
|
73
|
+
logger.debug(f"ToolAgent {self.agent_id} loaded tool: {tool_name}")
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.warning(f"Failed to load tool {tool_name}: {e}")
|
|
76
|
+
|
|
77
|
+
logger.info(f"ToolAgent {self.agent_id} initialized with {len(self._tool_instances)} tools")
|
|
78
|
+
|
|
79
|
+
async def _shutdown(self) -> None:
|
|
80
|
+
"""Shutdown Tool agent."""
|
|
81
|
+
self._tool_instances.clear()
|
|
82
|
+
logger.info(f"ToolAgent {self.agent_id} shut down")
|
|
83
|
+
|
|
84
|
+
async def execute_task(self, task: Dict[str, Any], context: Dict[str, Any]) -> Dict[str, Any]:
|
|
85
|
+
"""
|
|
86
|
+
Execute a task using tools.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
task: Task specification with 'tool', 'operation', and 'parameters'
|
|
90
|
+
context: Execution context
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
Execution result with 'output', 'tool_used', 'execution_time'
|
|
94
|
+
|
|
95
|
+
Raises:
|
|
96
|
+
TaskExecutionError: If task execution fails
|
|
97
|
+
"""
|
|
98
|
+
start_time = datetime.utcnow()
|
|
99
|
+
|
|
100
|
+
try:
|
|
101
|
+
# Extract tool and operation
|
|
102
|
+
tool_name = task.get("tool")
|
|
103
|
+
operation = task.get("operation")
|
|
104
|
+
parameters = task.get("parameters", {})
|
|
105
|
+
|
|
106
|
+
if not tool_name:
|
|
107
|
+
raise TaskExecutionError("Task must contain 'tool' field", agent_id=self.agent_id)
|
|
108
|
+
|
|
109
|
+
# Check tool access
|
|
110
|
+
if tool_name not in self._available_tools:
|
|
111
|
+
raise ToolAccessDeniedError(self.agent_id, tool_name)
|
|
112
|
+
|
|
113
|
+
# Transition to busy state
|
|
114
|
+
self._transition_state(self.state.__class__.BUSY)
|
|
115
|
+
self._current_task_id = task.get("task_id")
|
|
116
|
+
|
|
117
|
+
# Execute tool
|
|
118
|
+
result = await self._execute_tool(tool_name, operation, parameters)
|
|
119
|
+
|
|
120
|
+
# Calculate execution time
|
|
121
|
+
execution_time = (datetime.utcnow() - start_time).total_seconds()
|
|
122
|
+
|
|
123
|
+
# Update metrics
|
|
124
|
+
self.update_metrics(
|
|
125
|
+
execution_time=execution_time,
|
|
126
|
+
success=True,
|
|
127
|
+
tool_calls=1,
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
# Update tool usage stats
|
|
131
|
+
self._update_tool_stats(tool_name, success=True)
|
|
132
|
+
|
|
133
|
+
# Transition back to active
|
|
134
|
+
self._transition_state(self.state.__class__.ACTIVE)
|
|
135
|
+
self._current_task_id = None
|
|
136
|
+
self.last_active_at = datetime.utcnow()
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
"success": True,
|
|
140
|
+
"output": result,
|
|
141
|
+
"tool_used": tool_name,
|
|
142
|
+
"operation": operation,
|
|
143
|
+
"execution_time": execution_time,
|
|
144
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
except Exception as e:
|
|
148
|
+
logger.error(f"Task execution failed for {self.agent_id}: {e}")
|
|
149
|
+
|
|
150
|
+
# Update metrics for failure
|
|
151
|
+
execution_time = (datetime.utcnow() - start_time).total_seconds()
|
|
152
|
+
self.update_metrics(execution_time=execution_time, success=False)
|
|
153
|
+
|
|
154
|
+
# Update tool stats if tool was specified
|
|
155
|
+
if tool_name:
|
|
156
|
+
self._update_tool_stats(tool_name, success=False)
|
|
157
|
+
|
|
158
|
+
# Transition to error state
|
|
159
|
+
self._transition_state(self.state.__class__.ERROR)
|
|
160
|
+
self._current_task_id = None
|
|
161
|
+
|
|
162
|
+
raise TaskExecutionError(
|
|
163
|
+
f"Task execution failed: {str(e)}",
|
|
164
|
+
agent_id=self.agent_id,
|
|
165
|
+
task_id=task.get("task_id"),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
async def process_message(
|
|
169
|
+
self, message: str, sender_id: Optional[str] = None
|
|
170
|
+
) -> Dict[str, Any]:
|
|
171
|
+
"""
|
|
172
|
+
Process an incoming message.
|
|
173
|
+
|
|
174
|
+
For ToolAgent, this is limited - it's designed for direct tool execution.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
message: Message content
|
|
178
|
+
sender_id: Optional sender identifier
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
Response dictionary
|
|
182
|
+
"""
|
|
183
|
+
return {
|
|
184
|
+
"response": f"ToolAgent {self.name} received message but requires explicit tool tasks. "
|
|
185
|
+
f"Available tools: {', '.join(self._available_tools)}",
|
|
186
|
+
"available_tools": self._available_tools,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
async def _execute_tool(
|
|
190
|
+
self,
|
|
191
|
+
tool_name: str,
|
|
192
|
+
operation: Optional[str],
|
|
193
|
+
parameters: Dict[str, Any],
|
|
194
|
+
) -> Any:
|
|
195
|
+
"""
|
|
196
|
+
Execute a tool operation.
|
|
197
|
+
|
|
198
|
+
Args:
|
|
199
|
+
tool_name: Tool name
|
|
200
|
+
operation: Operation name (optional for tools with single operation)
|
|
201
|
+
parameters: Operation parameters
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
Tool execution result
|
|
205
|
+
"""
|
|
206
|
+
tool = self._tool_instances.get(tool_name)
|
|
207
|
+
if not tool:
|
|
208
|
+
raise ValueError(f"Tool {tool_name} not loaded")
|
|
209
|
+
|
|
210
|
+
# Execute tool
|
|
211
|
+
if operation:
|
|
212
|
+
result = await tool.run_async(operation, **parameters)
|
|
213
|
+
else:
|
|
214
|
+
# If no operation specified, try to call the tool directly
|
|
215
|
+
if hasattr(tool, "run_async"):
|
|
216
|
+
result = await tool.run_async(**parameters)
|
|
217
|
+
else:
|
|
218
|
+
raise ValueError(f"Tool {tool_name} requires operation to be specified")
|
|
219
|
+
|
|
220
|
+
return result
|
|
221
|
+
|
|
222
|
+
def _update_tool_stats(self, tool_name: str, success: bool) -> None:
|
|
223
|
+
"""Update tool usage statistics."""
|
|
224
|
+
if tool_name not in self._tool_usage_stats:
|
|
225
|
+
self._tool_usage_stats[tool_name] = {
|
|
226
|
+
"success_count": 0,
|
|
227
|
+
"failure_count": 0,
|
|
228
|
+
"total_count": 0,
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
stats = self._tool_usage_stats[tool_name]
|
|
232
|
+
stats["total_count"] += 1
|
|
233
|
+
if success:
|
|
234
|
+
stats["success_count"] += 1
|
|
235
|
+
else:
|
|
236
|
+
stats["failure_count"] += 1
|
|
237
|
+
|
|
238
|
+
def get_tool_stats(self) -> Dict[str, Dict[str, int]]:
|
|
239
|
+
"""Get tool usage statistics."""
|
|
240
|
+
return self._tool_usage_stats.copy()
|
|
241
|
+
|
|
242
|
+
def get_available_tools(self) -> List[str]:
|
|
243
|
+
"""Get list of available tools."""
|
|
244
|
+
return self._available_tools.copy()
|
|
245
|
+
|
|
246
|
+
@classmethod
|
|
247
|
+
def from_dict(cls, data: Dict[str, Any]) -> "ToolAgent":
|
|
248
|
+
"""
|
|
249
|
+
Deserialize ToolAgent from dictionary.
|
|
250
|
+
|
|
251
|
+
Args:
|
|
252
|
+
data: Dictionary representation
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
ToolAgent instance
|
|
256
|
+
"""
|
|
257
|
+
raise NotImplementedError("ToolAgent.from_dict not fully implemented yet")
|