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.
Files changed (302) hide show
  1. aiecs/__init__.py +72 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +469 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +363 -0
  7. aiecs/application/knowledge_graph/__init__.py +7 -0
  8. aiecs/application/knowledge_graph/builder/__init__.py +37 -0
  9. aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
  10. aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
  11. aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
  12. aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
  13. aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
  14. aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
  15. aiecs/application/knowledge_graph/extractors/base.py +100 -0
  16. aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
  17. aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
  18. aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
  19. aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
  20. aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
  21. aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
  22. aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
  23. aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
  24. aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
  25. aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
  26. aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
  27. aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
  28. aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
  29. aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
  30. aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
  31. aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
  32. aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
  33. aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
  34. aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
  35. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
  36. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
  37. aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
  38. aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
  39. aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
  40. aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
  41. aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
  42. aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
  43. aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
  44. aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
  45. aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
  46. aiecs/application/knowledge_graph/search/__init__.py +59 -0
  47. aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
  48. aiecs/application/knowledge_graph/search/reranker.py +295 -0
  49. aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
  50. aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
  51. aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
  52. aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
  53. aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
  54. aiecs/application/knowledge_graph/validators/__init__.py +13 -0
  55. aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
  56. aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
  57. aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
  58. aiecs/common/__init__.py +9 -0
  59. aiecs/common/knowledge_graph/__init__.py +17 -0
  60. aiecs/common/knowledge_graph/runnable.py +484 -0
  61. aiecs/config/__init__.py +16 -0
  62. aiecs/config/config.py +498 -0
  63. aiecs/config/graph_config.py +137 -0
  64. aiecs/config/registry.py +23 -0
  65. aiecs/core/__init__.py +46 -0
  66. aiecs/core/interface/__init__.py +34 -0
  67. aiecs/core/interface/execution_interface.py +152 -0
  68. aiecs/core/interface/storage_interface.py +171 -0
  69. aiecs/domain/__init__.py +289 -0
  70. aiecs/domain/agent/__init__.py +189 -0
  71. aiecs/domain/agent/base_agent.py +697 -0
  72. aiecs/domain/agent/exceptions.py +103 -0
  73. aiecs/domain/agent/graph_aware_mixin.py +559 -0
  74. aiecs/domain/agent/hybrid_agent.py +490 -0
  75. aiecs/domain/agent/integration/__init__.py +26 -0
  76. aiecs/domain/agent/integration/context_compressor.py +222 -0
  77. aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
  78. aiecs/domain/agent/integration/retry_policy.py +219 -0
  79. aiecs/domain/agent/integration/role_config.py +213 -0
  80. aiecs/domain/agent/knowledge_aware_agent.py +646 -0
  81. aiecs/domain/agent/lifecycle.py +296 -0
  82. aiecs/domain/agent/llm_agent.py +300 -0
  83. aiecs/domain/agent/memory/__init__.py +12 -0
  84. aiecs/domain/agent/memory/conversation.py +197 -0
  85. aiecs/domain/agent/migration/__init__.py +14 -0
  86. aiecs/domain/agent/migration/conversion.py +160 -0
  87. aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
  88. aiecs/domain/agent/models.py +317 -0
  89. aiecs/domain/agent/observability.py +407 -0
  90. aiecs/domain/agent/persistence.py +289 -0
  91. aiecs/domain/agent/prompts/__init__.py +29 -0
  92. aiecs/domain/agent/prompts/builder.py +161 -0
  93. aiecs/domain/agent/prompts/formatters.py +189 -0
  94. aiecs/domain/agent/prompts/template.py +255 -0
  95. aiecs/domain/agent/registry.py +260 -0
  96. aiecs/domain/agent/tool_agent.py +257 -0
  97. aiecs/domain/agent/tools/__init__.py +12 -0
  98. aiecs/domain/agent/tools/schema_generator.py +221 -0
  99. aiecs/domain/community/__init__.py +155 -0
  100. aiecs/domain/community/agent_adapter.py +477 -0
  101. aiecs/domain/community/analytics.py +481 -0
  102. aiecs/domain/community/collaborative_workflow.py +642 -0
  103. aiecs/domain/community/communication_hub.py +645 -0
  104. aiecs/domain/community/community_builder.py +320 -0
  105. aiecs/domain/community/community_integration.py +800 -0
  106. aiecs/domain/community/community_manager.py +813 -0
  107. aiecs/domain/community/decision_engine.py +879 -0
  108. aiecs/domain/community/exceptions.py +225 -0
  109. aiecs/domain/community/models/__init__.py +33 -0
  110. aiecs/domain/community/models/community_models.py +268 -0
  111. aiecs/domain/community/resource_manager.py +457 -0
  112. aiecs/domain/community/shared_context_manager.py +603 -0
  113. aiecs/domain/context/__init__.py +58 -0
  114. aiecs/domain/context/context_engine.py +989 -0
  115. aiecs/domain/context/conversation_models.py +354 -0
  116. aiecs/domain/context/graph_memory.py +467 -0
  117. aiecs/domain/execution/__init__.py +12 -0
  118. aiecs/domain/execution/model.py +57 -0
  119. aiecs/domain/knowledge_graph/__init__.py +19 -0
  120. aiecs/domain/knowledge_graph/models/__init__.py +52 -0
  121. aiecs/domain/knowledge_graph/models/entity.py +130 -0
  122. aiecs/domain/knowledge_graph/models/evidence.py +194 -0
  123. aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
  124. aiecs/domain/knowledge_graph/models/path.py +179 -0
  125. aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
  126. aiecs/domain/knowledge_graph/models/query.py +272 -0
  127. aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
  128. aiecs/domain/knowledge_graph/models/relation.py +136 -0
  129. aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
  130. aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
  131. aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
  132. aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
  133. aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
  134. aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
  135. aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
  136. aiecs/domain/task/__init__.py +13 -0
  137. aiecs/domain/task/dsl_processor.py +613 -0
  138. aiecs/domain/task/model.py +62 -0
  139. aiecs/domain/task/task_context.py +268 -0
  140. aiecs/infrastructure/__init__.py +24 -0
  141. aiecs/infrastructure/graph_storage/__init__.py +11 -0
  142. aiecs/infrastructure/graph_storage/base.py +601 -0
  143. aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
  144. aiecs/infrastructure/graph_storage/cache.py +429 -0
  145. aiecs/infrastructure/graph_storage/distributed.py +226 -0
  146. aiecs/infrastructure/graph_storage/error_handling.py +390 -0
  147. aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
  148. aiecs/infrastructure/graph_storage/health_checks.py +378 -0
  149. aiecs/infrastructure/graph_storage/in_memory.py +514 -0
  150. aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
  151. aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
  152. aiecs/infrastructure/graph_storage/metrics.py +357 -0
  153. aiecs/infrastructure/graph_storage/migration.py +413 -0
  154. aiecs/infrastructure/graph_storage/pagination.py +471 -0
  155. aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
  156. aiecs/infrastructure/graph_storage/postgres.py +871 -0
  157. aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
  158. aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
  159. aiecs/infrastructure/graph_storage/sqlite.py +623 -0
  160. aiecs/infrastructure/graph_storage/streaming.py +495 -0
  161. aiecs/infrastructure/messaging/__init__.py +13 -0
  162. aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
  163. aiecs/infrastructure/messaging/websocket_manager.py +298 -0
  164. aiecs/infrastructure/monitoring/__init__.py +34 -0
  165. aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
  166. aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
  167. aiecs/infrastructure/monitoring/structured_logger.py +48 -0
  168. aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
  169. aiecs/infrastructure/persistence/__init__.py +24 -0
  170. aiecs/infrastructure/persistence/context_engine_client.py +187 -0
  171. aiecs/infrastructure/persistence/database_manager.py +333 -0
  172. aiecs/infrastructure/persistence/file_storage.py +754 -0
  173. aiecs/infrastructure/persistence/redis_client.py +220 -0
  174. aiecs/llm/__init__.py +86 -0
  175. aiecs/llm/callbacks/__init__.py +11 -0
  176. aiecs/llm/callbacks/custom_callbacks.py +264 -0
  177. aiecs/llm/client_factory.py +420 -0
  178. aiecs/llm/clients/__init__.py +33 -0
  179. aiecs/llm/clients/base_client.py +193 -0
  180. aiecs/llm/clients/googleai_client.py +181 -0
  181. aiecs/llm/clients/openai_client.py +131 -0
  182. aiecs/llm/clients/vertex_client.py +437 -0
  183. aiecs/llm/clients/xai_client.py +184 -0
  184. aiecs/llm/config/__init__.py +51 -0
  185. aiecs/llm/config/config_loader.py +275 -0
  186. aiecs/llm/config/config_validator.py +236 -0
  187. aiecs/llm/config/model_config.py +151 -0
  188. aiecs/llm/utils/__init__.py +10 -0
  189. aiecs/llm/utils/validate_config.py +91 -0
  190. aiecs/main.py +363 -0
  191. aiecs/scripts/__init__.py +3 -0
  192. aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
  193. aiecs/scripts/aid/__init__.py +19 -0
  194. aiecs/scripts/aid/version_manager.py +215 -0
  195. aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
  196. aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
  197. aiecs/scripts/dependance_check/__init__.py +17 -0
  198. aiecs/scripts/dependance_check/dependency_checker.py +938 -0
  199. aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
  200. aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
  201. aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
  202. aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
  203. aiecs/scripts/dependance_patch/__init__.py +7 -0
  204. aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
  205. aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
  206. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
  207. aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
  208. aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
  209. aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
  210. aiecs/scripts/tools_develop/README.md +449 -0
  211. aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
  212. aiecs/scripts/tools_develop/__init__.py +21 -0
  213. aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
  214. aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
  215. aiecs/scripts/tools_develop/verify_tools.py +356 -0
  216. aiecs/tasks/__init__.py +1 -0
  217. aiecs/tasks/worker.py +172 -0
  218. aiecs/tools/__init__.py +299 -0
  219. aiecs/tools/apisource/__init__.py +99 -0
  220. aiecs/tools/apisource/intelligence/__init__.py +19 -0
  221. aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
  222. aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
  223. aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
  224. aiecs/tools/apisource/monitoring/__init__.py +9 -0
  225. aiecs/tools/apisource/monitoring/metrics.py +303 -0
  226. aiecs/tools/apisource/providers/__init__.py +115 -0
  227. aiecs/tools/apisource/providers/base.py +664 -0
  228. aiecs/tools/apisource/providers/census.py +401 -0
  229. aiecs/tools/apisource/providers/fred.py +564 -0
  230. aiecs/tools/apisource/providers/newsapi.py +412 -0
  231. aiecs/tools/apisource/providers/worldbank.py +357 -0
  232. aiecs/tools/apisource/reliability/__init__.py +12 -0
  233. aiecs/tools/apisource/reliability/error_handler.py +375 -0
  234. aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
  235. aiecs/tools/apisource/tool.py +850 -0
  236. aiecs/tools/apisource/utils/__init__.py +9 -0
  237. aiecs/tools/apisource/utils/validators.py +338 -0
  238. aiecs/tools/base_tool.py +201 -0
  239. aiecs/tools/docs/__init__.py +121 -0
  240. aiecs/tools/docs/ai_document_orchestrator.py +599 -0
  241. aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
  242. aiecs/tools/docs/content_insertion_tool.py +1333 -0
  243. aiecs/tools/docs/document_creator_tool.py +1317 -0
  244. aiecs/tools/docs/document_layout_tool.py +1166 -0
  245. aiecs/tools/docs/document_parser_tool.py +994 -0
  246. aiecs/tools/docs/document_writer_tool.py +1818 -0
  247. aiecs/tools/knowledge_graph/__init__.py +17 -0
  248. aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
  249. aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
  250. aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
  251. aiecs/tools/langchain_adapter.py +542 -0
  252. aiecs/tools/schema_generator.py +275 -0
  253. aiecs/tools/search_tool/__init__.py +100 -0
  254. aiecs/tools/search_tool/analyzers.py +589 -0
  255. aiecs/tools/search_tool/cache.py +260 -0
  256. aiecs/tools/search_tool/constants.py +128 -0
  257. aiecs/tools/search_tool/context.py +216 -0
  258. aiecs/tools/search_tool/core.py +749 -0
  259. aiecs/tools/search_tool/deduplicator.py +123 -0
  260. aiecs/tools/search_tool/error_handler.py +271 -0
  261. aiecs/tools/search_tool/metrics.py +371 -0
  262. aiecs/tools/search_tool/rate_limiter.py +178 -0
  263. aiecs/tools/search_tool/schemas.py +277 -0
  264. aiecs/tools/statistics/__init__.py +80 -0
  265. aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
  266. aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
  267. aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
  268. aiecs/tools/statistics/data_loader_tool.py +564 -0
  269. aiecs/tools/statistics/data_profiler_tool.py +658 -0
  270. aiecs/tools/statistics/data_transformer_tool.py +573 -0
  271. aiecs/tools/statistics/data_visualizer_tool.py +495 -0
  272. aiecs/tools/statistics/model_trainer_tool.py +487 -0
  273. aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
  274. aiecs/tools/task_tools/__init__.py +86 -0
  275. aiecs/tools/task_tools/chart_tool.py +732 -0
  276. aiecs/tools/task_tools/classfire_tool.py +922 -0
  277. aiecs/tools/task_tools/image_tool.py +447 -0
  278. aiecs/tools/task_tools/office_tool.py +684 -0
  279. aiecs/tools/task_tools/pandas_tool.py +635 -0
  280. aiecs/tools/task_tools/report_tool.py +635 -0
  281. aiecs/tools/task_tools/research_tool.py +392 -0
  282. aiecs/tools/task_tools/scraper_tool.py +715 -0
  283. aiecs/tools/task_tools/stats_tool.py +688 -0
  284. aiecs/tools/temp_file_manager.py +130 -0
  285. aiecs/tools/tool_executor/__init__.py +37 -0
  286. aiecs/tools/tool_executor/tool_executor.py +881 -0
  287. aiecs/utils/LLM_output_structor.py +445 -0
  288. aiecs/utils/__init__.py +34 -0
  289. aiecs/utils/base_callback.py +47 -0
  290. aiecs/utils/cache_provider.py +695 -0
  291. aiecs/utils/execution_utils.py +184 -0
  292. aiecs/utils/logging.py +1 -0
  293. aiecs/utils/prompt_loader.py +14 -0
  294. aiecs/utils/token_usage_repository.py +323 -0
  295. aiecs/ws/__init__.py +0 -0
  296. aiecs/ws/socket_server.py +52 -0
  297. aiecs-1.5.1.dist-info/METADATA +608 -0
  298. aiecs-1.5.1.dist-info/RECORD +302 -0
  299. aiecs-1.5.1.dist-info/WHEEL +5 -0
  300. aiecs-1.5.1.dist-info/entry_points.txt +10 -0
  301. aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
  302. 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