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,407 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Observability
|
|
3
|
+
|
|
4
|
+
Observer pattern and controllers for monitoring agent behavior.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
from typing import Dict, Any, List, Protocol
|
|
9
|
+
from datetime import datetime
|
|
10
|
+
|
|
11
|
+
from .base_agent import BaseAIAgent
|
|
12
|
+
from .models import AgentState
|
|
13
|
+
|
|
14
|
+
logger = logging.getLogger(__name__)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class AgentObserver(Protocol):
|
|
18
|
+
"""Protocol for observing agent events."""
|
|
19
|
+
|
|
20
|
+
def on_state_changed(
|
|
21
|
+
self,
|
|
22
|
+
agent_id: str,
|
|
23
|
+
old_state: AgentState,
|
|
24
|
+
new_state: AgentState,
|
|
25
|
+
timestamp: datetime,
|
|
26
|
+
) -> None:
|
|
27
|
+
"""
|
|
28
|
+
Called when agent state changes.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
agent_id: Agent identifier
|
|
32
|
+
old_state: Previous state
|
|
33
|
+
new_state: New state
|
|
34
|
+
timestamp: Change timestamp
|
|
35
|
+
"""
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
def on_task_started(
|
|
39
|
+
self,
|
|
40
|
+
agent_id: str,
|
|
41
|
+
task_id: str,
|
|
42
|
+
task: Dict[str, Any],
|
|
43
|
+
timestamp: datetime,
|
|
44
|
+
) -> None:
|
|
45
|
+
"""
|
|
46
|
+
Called when agent starts a task.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
agent_id: Agent identifier
|
|
50
|
+
task_id: Task identifier
|
|
51
|
+
task: Task specification
|
|
52
|
+
timestamp: Start timestamp
|
|
53
|
+
"""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
def on_task_completed(
|
|
57
|
+
self,
|
|
58
|
+
agent_id: str,
|
|
59
|
+
task_id: str,
|
|
60
|
+
result: Dict[str, Any],
|
|
61
|
+
timestamp: datetime,
|
|
62
|
+
) -> None:
|
|
63
|
+
"""
|
|
64
|
+
Called when agent completes a task.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
agent_id: Agent identifier
|
|
68
|
+
task_id: Task identifier
|
|
69
|
+
result: Task result
|
|
70
|
+
timestamp: Completion timestamp
|
|
71
|
+
"""
|
|
72
|
+
...
|
|
73
|
+
|
|
74
|
+
def on_task_failed(
|
|
75
|
+
self,
|
|
76
|
+
agent_id: str,
|
|
77
|
+
task_id: str,
|
|
78
|
+
error: Exception,
|
|
79
|
+
timestamp: datetime,
|
|
80
|
+
) -> None:
|
|
81
|
+
"""
|
|
82
|
+
Called when agent task fails.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
agent_id: Agent identifier
|
|
86
|
+
task_id: Task identifier
|
|
87
|
+
error: Error that occurred
|
|
88
|
+
timestamp: Failure timestamp
|
|
89
|
+
"""
|
|
90
|
+
...
|
|
91
|
+
|
|
92
|
+
def on_tool_called(
|
|
93
|
+
self,
|
|
94
|
+
agent_id: str,
|
|
95
|
+
tool_name: str,
|
|
96
|
+
parameters: Dict[str, Any],
|
|
97
|
+
timestamp: datetime,
|
|
98
|
+
) -> None:
|
|
99
|
+
"""
|
|
100
|
+
Called when agent calls a tool.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
agent_id: Agent identifier
|
|
104
|
+
tool_name: Tool name
|
|
105
|
+
parameters: Tool parameters
|
|
106
|
+
timestamp: Call timestamp
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
class LoggingObserver:
|
|
112
|
+
"""Observer that logs agent events."""
|
|
113
|
+
|
|
114
|
+
def __init__(self, log_level: int = logging.INFO):
|
|
115
|
+
"""
|
|
116
|
+
Initialize logging observer.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
log_level: Logging level
|
|
120
|
+
"""
|
|
121
|
+
self.logger = logging.getLogger(f"{__name__}.LoggingObserver")
|
|
122
|
+
self.log_level = log_level
|
|
123
|
+
|
|
124
|
+
def on_state_changed(
|
|
125
|
+
self,
|
|
126
|
+
agent_id: str,
|
|
127
|
+
old_state: AgentState,
|
|
128
|
+
new_state: AgentState,
|
|
129
|
+
timestamp: datetime,
|
|
130
|
+
) -> None:
|
|
131
|
+
"""Log state change."""
|
|
132
|
+
self.logger.log(
|
|
133
|
+
self.log_level,
|
|
134
|
+
f"Agent {agent_id}: {old_state.value} → {new_state.value}",
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
def on_task_started(
|
|
138
|
+
self,
|
|
139
|
+
agent_id: str,
|
|
140
|
+
task_id: str,
|
|
141
|
+
task: Dict[str, Any],
|
|
142
|
+
timestamp: datetime,
|
|
143
|
+
) -> None:
|
|
144
|
+
"""Log task start."""
|
|
145
|
+
self.logger.log(self.log_level, f"Agent {agent_id}: Task {task_id} started")
|
|
146
|
+
|
|
147
|
+
def on_task_completed(
|
|
148
|
+
self,
|
|
149
|
+
agent_id: str,
|
|
150
|
+
task_id: str,
|
|
151
|
+
result: Dict[str, Any],
|
|
152
|
+
timestamp: datetime,
|
|
153
|
+
) -> None:
|
|
154
|
+
"""Log task completion."""
|
|
155
|
+
self.logger.log(self.log_level, f"Agent {agent_id}: Task {task_id} completed")
|
|
156
|
+
|
|
157
|
+
def on_task_failed(
|
|
158
|
+
self,
|
|
159
|
+
agent_id: str,
|
|
160
|
+
task_id: str,
|
|
161
|
+
error: Exception,
|
|
162
|
+
timestamp: datetime,
|
|
163
|
+
) -> None:
|
|
164
|
+
"""Log task failure."""
|
|
165
|
+
self.logger.log(
|
|
166
|
+
self.log_level,
|
|
167
|
+
f"Agent {agent_id}: Task {task_id} failed - {str(error)}",
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def on_tool_called(
|
|
171
|
+
self,
|
|
172
|
+
agent_id: str,
|
|
173
|
+
tool_name: str,
|
|
174
|
+
parameters: Dict[str, Any],
|
|
175
|
+
timestamp: datetime,
|
|
176
|
+
) -> None:
|
|
177
|
+
"""Log tool call."""
|
|
178
|
+
self.logger.log(self.log_level, f"Agent {agent_id}: Tool '{tool_name}' called")
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class MetricsObserver:
|
|
182
|
+
"""Observer that collects metrics."""
|
|
183
|
+
|
|
184
|
+
def __init__(self):
|
|
185
|
+
"""Initialize metrics observer."""
|
|
186
|
+
self.state_changes: List[Dict[str, Any]] = []
|
|
187
|
+
self.task_events: List[Dict[str, Any]] = []
|
|
188
|
+
self.tool_calls: List[Dict[str, Any]] = []
|
|
189
|
+
|
|
190
|
+
def on_state_changed(
|
|
191
|
+
self,
|
|
192
|
+
agent_id: str,
|
|
193
|
+
old_state: AgentState,
|
|
194
|
+
new_state: AgentState,
|
|
195
|
+
timestamp: datetime,
|
|
196
|
+
) -> None:
|
|
197
|
+
"""Record state change."""
|
|
198
|
+
self.state_changes.append(
|
|
199
|
+
{
|
|
200
|
+
"agent_id": agent_id,
|
|
201
|
+
"old_state": old_state.value,
|
|
202
|
+
"new_state": new_state.value,
|
|
203
|
+
"timestamp": timestamp.isoformat(),
|
|
204
|
+
}
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
def on_task_started(
|
|
208
|
+
self,
|
|
209
|
+
agent_id: str,
|
|
210
|
+
task_id: str,
|
|
211
|
+
task: Dict[str, Any],
|
|
212
|
+
timestamp: datetime,
|
|
213
|
+
) -> None:
|
|
214
|
+
"""Record task start."""
|
|
215
|
+
self.task_events.append(
|
|
216
|
+
{
|
|
217
|
+
"agent_id": agent_id,
|
|
218
|
+
"task_id": task_id,
|
|
219
|
+
"event": "started",
|
|
220
|
+
"timestamp": timestamp.isoformat(),
|
|
221
|
+
}
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def on_task_completed(
|
|
225
|
+
self,
|
|
226
|
+
agent_id: str,
|
|
227
|
+
task_id: str,
|
|
228
|
+
result: Dict[str, Any],
|
|
229
|
+
timestamp: datetime,
|
|
230
|
+
) -> None:
|
|
231
|
+
"""Record task completion."""
|
|
232
|
+
self.task_events.append(
|
|
233
|
+
{
|
|
234
|
+
"agent_id": agent_id,
|
|
235
|
+
"task_id": task_id,
|
|
236
|
+
"event": "completed",
|
|
237
|
+
"timestamp": timestamp.isoformat(),
|
|
238
|
+
}
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
def on_task_failed(
|
|
242
|
+
self,
|
|
243
|
+
agent_id: str,
|
|
244
|
+
task_id: str,
|
|
245
|
+
error: Exception,
|
|
246
|
+
timestamp: datetime,
|
|
247
|
+
) -> None:
|
|
248
|
+
"""Record task failure."""
|
|
249
|
+
self.task_events.append(
|
|
250
|
+
{
|
|
251
|
+
"agent_id": agent_id,
|
|
252
|
+
"task_id": task_id,
|
|
253
|
+
"event": "failed",
|
|
254
|
+
"error": str(error),
|
|
255
|
+
"timestamp": timestamp.isoformat(),
|
|
256
|
+
}
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
def on_tool_called(
|
|
260
|
+
self,
|
|
261
|
+
agent_id: str,
|
|
262
|
+
tool_name: str,
|
|
263
|
+
parameters: Dict[str, Any],
|
|
264
|
+
timestamp: datetime,
|
|
265
|
+
) -> None:
|
|
266
|
+
"""Record tool call."""
|
|
267
|
+
self.tool_calls.append(
|
|
268
|
+
{
|
|
269
|
+
"agent_id": agent_id,
|
|
270
|
+
"tool_name": tool_name,
|
|
271
|
+
"timestamp": timestamp.isoformat(),
|
|
272
|
+
}
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
def get_metrics(self) -> Dict[str, Any]:
|
|
276
|
+
"""Get collected metrics."""
|
|
277
|
+
return {
|
|
278
|
+
"state_changes": len(self.state_changes),
|
|
279
|
+
"task_events": len(self.task_events),
|
|
280
|
+
"tool_calls": len(self.tool_calls),
|
|
281
|
+
"state_changes_data": self.state_changes,
|
|
282
|
+
"task_events_data": self.task_events,
|
|
283
|
+
"tool_calls_data": self.tool_calls,
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
def clear(self) -> None:
|
|
287
|
+
"""Clear all metrics."""
|
|
288
|
+
self.state_changes.clear()
|
|
289
|
+
self.task_events.clear()
|
|
290
|
+
self.tool_calls.clear()
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
class AgentController:
|
|
294
|
+
"""
|
|
295
|
+
Controller for managing agent execution and monitoring.
|
|
296
|
+
|
|
297
|
+
Integrates with observers for event tracking.
|
|
298
|
+
"""
|
|
299
|
+
|
|
300
|
+
def __init__(self, agent: BaseAIAgent):
|
|
301
|
+
"""
|
|
302
|
+
Initialize agent controller.
|
|
303
|
+
|
|
304
|
+
Args:
|
|
305
|
+
agent: Agent to control
|
|
306
|
+
"""
|
|
307
|
+
self.agent = agent
|
|
308
|
+
self.observers: List[AgentObserver] = []
|
|
309
|
+
logger.info(f"AgentController initialized for agent {agent.agent_id}")
|
|
310
|
+
|
|
311
|
+
def add_observer(self, observer: AgentObserver) -> None:
|
|
312
|
+
"""
|
|
313
|
+
Add an observer.
|
|
314
|
+
|
|
315
|
+
Args:
|
|
316
|
+
observer: Observer to add
|
|
317
|
+
"""
|
|
318
|
+
self.observers.append(observer)
|
|
319
|
+
logger.debug(f"Observer added to agent {self.agent.agent_id}")
|
|
320
|
+
|
|
321
|
+
def remove_observer(self, observer: AgentObserver) -> None:
|
|
322
|
+
"""
|
|
323
|
+
Remove an observer.
|
|
324
|
+
|
|
325
|
+
Args:
|
|
326
|
+
observer: Observer to remove
|
|
327
|
+
"""
|
|
328
|
+
if observer in self.observers:
|
|
329
|
+
self.observers.remove(observer)
|
|
330
|
+
logger.debug(f"Observer removed from agent {self.agent.agent_id}")
|
|
331
|
+
|
|
332
|
+
def notify_state_changed(self, old_state: AgentState, new_state: AgentState) -> None:
|
|
333
|
+
"""Notify observers of state change."""
|
|
334
|
+
timestamp = datetime.utcnow()
|
|
335
|
+
for observer in self.observers:
|
|
336
|
+
try:
|
|
337
|
+
observer.on_state_changed(self.agent.agent_id, old_state, new_state, timestamp)
|
|
338
|
+
except Exception as e:
|
|
339
|
+
logger.error(f"Observer notification failed: {e}")
|
|
340
|
+
|
|
341
|
+
def notify_task_started(self, task_id: str, task: Dict[str, Any]) -> None:
|
|
342
|
+
"""Notify observers of task start."""
|
|
343
|
+
timestamp = datetime.utcnow()
|
|
344
|
+
for observer in self.observers:
|
|
345
|
+
try:
|
|
346
|
+
observer.on_task_started(self.agent.agent_id, task_id, task, timestamp)
|
|
347
|
+
except Exception as e:
|
|
348
|
+
logger.error(f"Observer notification failed: {e}")
|
|
349
|
+
|
|
350
|
+
def notify_task_completed(self, task_id: str, result: Dict[str, Any]) -> None:
|
|
351
|
+
"""Notify observers of task completion."""
|
|
352
|
+
timestamp = datetime.utcnow()
|
|
353
|
+
for observer in self.observers:
|
|
354
|
+
try:
|
|
355
|
+
observer.on_task_completed(self.agent.agent_id, task_id, result, timestamp)
|
|
356
|
+
except Exception as e:
|
|
357
|
+
logger.error(f"Observer notification failed: {e}")
|
|
358
|
+
|
|
359
|
+
def notify_task_failed(self, task_id: str, error: Exception) -> None:
|
|
360
|
+
"""Notify observers of task failure."""
|
|
361
|
+
timestamp = datetime.utcnow()
|
|
362
|
+
for observer in self.observers:
|
|
363
|
+
try:
|
|
364
|
+
observer.on_task_failed(self.agent.agent_id, task_id, error, timestamp)
|
|
365
|
+
except Exception as e:
|
|
366
|
+
logger.error(f"Observer notification failed: {e}")
|
|
367
|
+
|
|
368
|
+
def notify_tool_called(self, tool_name: str, parameters: Dict[str, Any]) -> None:
|
|
369
|
+
"""Notify observers of tool call."""
|
|
370
|
+
timestamp = datetime.utcnow()
|
|
371
|
+
for observer in self.observers:
|
|
372
|
+
try:
|
|
373
|
+
observer.on_tool_called(self.agent.agent_id, tool_name, parameters, timestamp)
|
|
374
|
+
except Exception as e:
|
|
375
|
+
logger.error(f"Observer notification failed: {e}")
|
|
376
|
+
|
|
377
|
+
async def execute_task_with_observation(
|
|
378
|
+
self, task: Dict[str, Any], context: Dict[str, Any]
|
|
379
|
+
) -> Dict[str, Any]:
|
|
380
|
+
"""
|
|
381
|
+
Execute task with observer notifications.
|
|
382
|
+
|
|
383
|
+
Args:
|
|
384
|
+
task: Task specification
|
|
385
|
+
context: Execution context
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
Task result
|
|
389
|
+
"""
|
|
390
|
+
task_id = task.get("task_id", f"task_{datetime.utcnow().timestamp()}")
|
|
391
|
+
|
|
392
|
+
# Notify start
|
|
393
|
+
self.notify_task_started(task_id, task)
|
|
394
|
+
|
|
395
|
+
try:
|
|
396
|
+
# Execute task
|
|
397
|
+
result = await self.agent.execute_task(task, context)
|
|
398
|
+
|
|
399
|
+
# Notify completion
|
|
400
|
+
self.notify_task_completed(task_id, result)
|
|
401
|
+
|
|
402
|
+
return result
|
|
403
|
+
|
|
404
|
+
except Exception as e:
|
|
405
|
+
# Notify failure
|
|
406
|
+
self.notify_task_failed(task_id, e)
|
|
407
|
+
raise
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Persistence
|
|
3
|
+
|
|
4
|
+
Interfaces and implementations for saving/loading agent state.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import logging
|
|
8
|
+
import json
|
|
9
|
+
from typing import Dict, Any, Optional, Protocol
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
|
|
12
|
+
from .base_agent import BaseAIAgent
|
|
13
|
+
from .exceptions import SerializationError
|
|
14
|
+
|
|
15
|
+
logger = logging.getLogger(__name__)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class AgentPersistence(Protocol):
|
|
19
|
+
"""Protocol for agent persistence implementations."""
|
|
20
|
+
|
|
21
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
22
|
+
"""
|
|
23
|
+
Save agent state.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
agent: Agent to save
|
|
27
|
+
"""
|
|
28
|
+
...
|
|
29
|
+
|
|
30
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
31
|
+
"""
|
|
32
|
+
Load agent state.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
agent_id: Agent identifier
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Agent state dictionary
|
|
39
|
+
"""
|
|
40
|
+
...
|
|
41
|
+
|
|
42
|
+
async def exists(self, agent_id: str) -> bool:
|
|
43
|
+
"""
|
|
44
|
+
Check if agent state exists.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
agent_id: Agent identifier
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
True if exists
|
|
51
|
+
"""
|
|
52
|
+
...
|
|
53
|
+
|
|
54
|
+
async def delete(self, agent_id: str) -> None:
|
|
55
|
+
"""
|
|
56
|
+
Delete agent state.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
agent_id: Agent identifier
|
|
60
|
+
"""
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class InMemoryPersistence:
|
|
65
|
+
"""In-memory agent persistence (for testing/development)."""
|
|
66
|
+
|
|
67
|
+
def __init__(self):
|
|
68
|
+
"""Initialize in-memory storage."""
|
|
69
|
+
self._storage: Dict[str, Dict[str, Any]] = {}
|
|
70
|
+
logger.info("InMemoryPersistence initialized")
|
|
71
|
+
|
|
72
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
73
|
+
"""Save agent state to memory."""
|
|
74
|
+
try:
|
|
75
|
+
state = agent.to_dict()
|
|
76
|
+
# Convert any remaining datetime objects to ISO strings
|
|
77
|
+
state = self._serialize_datetimes(state)
|
|
78
|
+
self._storage[agent.agent_id] = {
|
|
79
|
+
"state": state,
|
|
80
|
+
"saved_at": datetime.utcnow().isoformat(),
|
|
81
|
+
}
|
|
82
|
+
logger.debug(f"Agent {agent.agent_id} saved to memory")
|
|
83
|
+
except Exception as e:
|
|
84
|
+
logger.error(f"Failed to save agent {agent.agent_id}: {e}")
|
|
85
|
+
raise SerializationError(f"Failed to save agent: {str(e)}")
|
|
86
|
+
|
|
87
|
+
def _serialize_datetimes(self, obj: Any) -> Any:
|
|
88
|
+
"""Recursively serialize datetime objects to ISO strings."""
|
|
89
|
+
if isinstance(obj, dict):
|
|
90
|
+
return {k: self._serialize_datetimes(v) for k, v in obj.items()}
|
|
91
|
+
elif isinstance(obj, list):
|
|
92
|
+
return [self._serialize_datetimes(item) for item in obj]
|
|
93
|
+
elif isinstance(obj, datetime):
|
|
94
|
+
return obj.isoformat()
|
|
95
|
+
else:
|
|
96
|
+
return obj
|
|
97
|
+
|
|
98
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
99
|
+
"""Load agent state from memory."""
|
|
100
|
+
if agent_id not in self._storage:
|
|
101
|
+
raise KeyError(f"Agent {agent_id} not found in storage")
|
|
102
|
+
|
|
103
|
+
data = self._storage[agent_id]
|
|
104
|
+
logger.debug(f"Agent {agent_id} loaded from memory")
|
|
105
|
+
return data["state"]
|
|
106
|
+
|
|
107
|
+
async def exists(self, agent_id: str) -> bool:
|
|
108
|
+
"""Check if agent exists in memory."""
|
|
109
|
+
return agent_id in self._storage
|
|
110
|
+
|
|
111
|
+
async def delete(self, agent_id: str) -> None:
|
|
112
|
+
"""Delete agent from memory."""
|
|
113
|
+
if agent_id in self._storage:
|
|
114
|
+
del self._storage[agent_id]
|
|
115
|
+
logger.debug(f"Agent {agent_id} deleted from memory")
|
|
116
|
+
|
|
117
|
+
def clear(self) -> None:
|
|
118
|
+
"""Clear all stored agents."""
|
|
119
|
+
self._storage.clear()
|
|
120
|
+
logger.info("InMemoryPersistence cleared")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
class FilePersistence:
|
|
124
|
+
"""File-based agent persistence."""
|
|
125
|
+
|
|
126
|
+
def __init__(self, base_path: str = "./agent_states"):
|
|
127
|
+
"""
|
|
128
|
+
Initialize file-based storage.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
base_path: Base directory for agent states
|
|
132
|
+
"""
|
|
133
|
+
import os
|
|
134
|
+
|
|
135
|
+
self.base_path = base_path
|
|
136
|
+
os.makedirs(base_path, exist_ok=True)
|
|
137
|
+
logger.info(f"FilePersistence initialized with base_path: {base_path}")
|
|
138
|
+
|
|
139
|
+
def _get_file_path(self, agent_id: str) -> str:
|
|
140
|
+
"""Get file path for agent."""
|
|
141
|
+
import os
|
|
142
|
+
|
|
143
|
+
# Sanitize agent_id for filesystem
|
|
144
|
+
safe_id = agent_id.replace("/", "_").replace("\\", "_")
|
|
145
|
+
return os.path.join(self.base_path, f"{safe_id}.json")
|
|
146
|
+
|
|
147
|
+
async def save(self, agent: BaseAIAgent) -> None:
|
|
148
|
+
"""Save agent state to file."""
|
|
149
|
+
try:
|
|
150
|
+
state = agent.to_dict()
|
|
151
|
+
# Convert any remaining datetime objects to ISO strings for JSON
|
|
152
|
+
# serialization
|
|
153
|
+
state = self._serialize_datetimes(state)
|
|
154
|
+
file_path = self._get_file_path(agent.agent_id)
|
|
155
|
+
|
|
156
|
+
data = {
|
|
157
|
+
"state": state,
|
|
158
|
+
"saved_at": datetime.utcnow().isoformat(),
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
with open(file_path, "w") as f:
|
|
162
|
+
# default=str handles any remaining non-serializable objects
|
|
163
|
+
json.dump(data, f, indent=2, default=str)
|
|
164
|
+
|
|
165
|
+
logger.debug(f"Agent {agent.agent_id} saved to {file_path}")
|
|
166
|
+
except Exception as e:
|
|
167
|
+
logger.error(f"Failed to save agent {agent.agent_id}: {e}")
|
|
168
|
+
raise SerializationError(f"Failed to save agent: {str(e)}")
|
|
169
|
+
|
|
170
|
+
def _serialize_datetimes(self, obj: Any) -> Any:
|
|
171
|
+
"""Recursively serialize datetime objects to ISO strings."""
|
|
172
|
+
if isinstance(obj, dict):
|
|
173
|
+
return {k: self._serialize_datetimes(v) for k, v in obj.items()}
|
|
174
|
+
elif isinstance(obj, list):
|
|
175
|
+
return [self._serialize_datetimes(item) for item in obj]
|
|
176
|
+
elif isinstance(obj, datetime):
|
|
177
|
+
return obj.isoformat()
|
|
178
|
+
else:
|
|
179
|
+
return obj
|
|
180
|
+
|
|
181
|
+
async def load(self, agent_id: str) -> Dict[str, Any]:
|
|
182
|
+
"""Load agent state from file."""
|
|
183
|
+
file_path = self._get_file_path(agent_id)
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
with open(file_path, "r") as f:
|
|
187
|
+
data = json.load(f)
|
|
188
|
+
|
|
189
|
+
logger.debug(f"Agent {agent_id} loaded from {file_path}")
|
|
190
|
+
return data["state"]
|
|
191
|
+
except FileNotFoundError:
|
|
192
|
+
raise KeyError(f"Agent {agent_id} not found in storage")
|
|
193
|
+
except Exception as e:
|
|
194
|
+
logger.error(f"Failed to load agent {agent_id}: {e}")
|
|
195
|
+
raise SerializationError(f"Failed to load agent: {str(e)}")
|
|
196
|
+
|
|
197
|
+
async def exists(self, agent_id: str) -> bool:
|
|
198
|
+
"""Check if agent file exists."""
|
|
199
|
+
import os
|
|
200
|
+
|
|
201
|
+
file_path = self._get_file_path(agent_id)
|
|
202
|
+
return os.path.exists(file_path)
|
|
203
|
+
|
|
204
|
+
async def delete(self, agent_id: str) -> None:
|
|
205
|
+
"""Delete agent file."""
|
|
206
|
+
import os
|
|
207
|
+
|
|
208
|
+
file_path = self._get_file_path(agent_id)
|
|
209
|
+
|
|
210
|
+
try:
|
|
211
|
+
if os.path.exists(file_path):
|
|
212
|
+
os.remove(file_path)
|
|
213
|
+
logger.debug(f"Agent {agent_id} deleted from {file_path}")
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logger.error(f"Failed to delete agent {agent_id}: {e}")
|
|
216
|
+
raise
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
class AgentStateSerializer:
|
|
220
|
+
"""
|
|
221
|
+
Helper class for serializing/deserializing agent state.
|
|
222
|
+
|
|
223
|
+
Handles complex types that need special serialization.
|
|
224
|
+
"""
|
|
225
|
+
|
|
226
|
+
@staticmethod
|
|
227
|
+
def serialize(agent: BaseAIAgent) -> Dict[str, Any]:
|
|
228
|
+
"""
|
|
229
|
+
Serialize agent to dictionary.
|
|
230
|
+
|
|
231
|
+
Args:
|
|
232
|
+
agent: Agent to serialize
|
|
233
|
+
|
|
234
|
+
Returns:
|
|
235
|
+
Serialized state dictionary
|
|
236
|
+
"""
|
|
237
|
+
return agent.to_dict()
|
|
238
|
+
|
|
239
|
+
@staticmethod
|
|
240
|
+
def deserialize(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
241
|
+
"""
|
|
242
|
+
Deserialize agent state.
|
|
243
|
+
|
|
244
|
+
Args:
|
|
245
|
+
data: Serialized state
|
|
246
|
+
|
|
247
|
+
Returns:
|
|
248
|
+
Deserialized state dictionary
|
|
249
|
+
|
|
250
|
+
Note: This returns a state dictionary, not an agent instance.
|
|
251
|
+
Agent reconstruction requires the appropriate agent class.
|
|
252
|
+
"""
|
|
253
|
+
# In the future, this could handle type conversion, validation, etc.
|
|
254
|
+
return data
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
# Global persistence instance
|
|
258
|
+
_global_persistence: Optional[AgentPersistence] = None
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def get_global_persistence() -> AgentPersistence:
|
|
262
|
+
"""
|
|
263
|
+
Get or create global persistence instance.
|
|
264
|
+
|
|
265
|
+
Returns:
|
|
266
|
+
Global persistence instance (defaults to InMemoryPersistence)
|
|
267
|
+
"""
|
|
268
|
+
global _global_persistence
|
|
269
|
+
if _global_persistence is None:
|
|
270
|
+
_global_persistence = InMemoryPersistence()
|
|
271
|
+
return _global_persistence
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
def set_global_persistence(persistence: AgentPersistence) -> None:
|
|
275
|
+
"""
|
|
276
|
+
Set global persistence instance.
|
|
277
|
+
|
|
278
|
+
Args:
|
|
279
|
+
persistence: Persistence implementation to use
|
|
280
|
+
"""
|
|
281
|
+
global _global_persistence
|
|
282
|
+
_global_persistence = persistence
|
|
283
|
+
logger.info(f"Global persistence set to {type(persistence).__name__}")
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def reset_global_persistence() -> None:
|
|
287
|
+
"""Reset global persistence (primarily for testing)."""
|
|
288
|
+
global _global_persistence
|
|
289
|
+
_global_persistence = None
|