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,103 @@
1
+ """
2
+ Agent Domain Exceptions
3
+
4
+ Defines agent-specific exceptions for the base AI agent model.
5
+ """
6
+
7
+ from typing import Optional
8
+
9
+
10
+ class AgentException(Exception):
11
+ """Base exception for agent-related errors."""
12
+
13
+ def __init__(self, message: str, agent_id: Optional[str] = None):
14
+ super().__init__(message)
15
+ self.agent_id = agent_id
16
+ self.message = message
17
+
18
+
19
+ class AgentNotFoundError(AgentException):
20
+ """Raised when an agent cannot be found."""
21
+
22
+ def __init__(self, agent_id: str, message: Optional[str] = None):
23
+ msg = message or f"Agent with ID '{agent_id}' not found"
24
+ super().__init__(msg, agent_id)
25
+
26
+
27
+ class AgentAlreadyRegisteredError(AgentException):
28
+ """Raised when attempting to register an agent with an existing ID."""
29
+
30
+ def __init__(self, agent_id: str):
31
+ msg = f"Agent with ID '{agent_id}' is already registered"
32
+ super().__init__(msg, agent_id)
33
+
34
+
35
+ class InvalidStateTransitionError(AgentException):
36
+ """Raised when an invalid agent state transition is attempted."""
37
+
38
+ def __init__(
39
+ self,
40
+ agent_id: str,
41
+ current_state: str,
42
+ attempted_state: str,
43
+ message: Optional[str] = None,
44
+ ):
45
+ msg = (
46
+ message
47
+ or f"Invalid state transition for agent '{agent_id}': "
48
+ f"cannot transition from '{current_state}' to '{attempted_state}'"
49
+ )
50
+ super().__init__(msg, agent_id)
51
+ self.current_state = current_state
52
+ self.attempted_state = attempted_state
53
+
54
+
55
+ class ConfigurationError(AgentException):
56
+ """Raised when agent configuration is invalid."""
57
+
58
+ def __init__(
59
+ self,
60
+ message: str,
61
+ agent_id: Optional[str] = None,
62
+ field: Optional[str] = None,
63
+ ):
64
+ super().__init__(message, agent_id)
65
+ self.field = field
66
+
67
+
68
+ class TaskExecutionError(AgentException):
69
+ """Raised when task execution fails."""
70
+
71
+ def __init__(
72
+ self,
73
+ message: str,
74
+ agent_id: Optional[str] = None,
75
+ task_id: Optional[str] = None,
76
+ retry_count: Optional[int] = None,
77
+ ):
78
+ super().__init__(message, agent_id)
79
+ self.task_id = task_id
80
+ self.retry_count = retry_count
81
+
82
+
83
+ class ToolAccessDeniedError(AgentException):
84
+ """Raised when an agent attempts to use a tool it doesn't have access to."""
85
+
86
+ def __init__(self, agent_id: str, tool_name: str):
87
+ msg = f"Agent '{agent_id}' does not have access to tool '{tool_name}'"
88
+ super().__init__(msg, agent_id)
89
+ self.tool_name = tool_name
90
+
91
+
92
+ class SerializationError(AgentException):
93
+ """Raised when agent serialization/deserialization fails."""
94
+
95
+ def __init__(self, message: str, agent_id: Optional[str] = None):
96
+ super().__init__(message, agent_id)
97
+
98
+
99
+ class AgentInitializationError(AgentException):
100
+ """Raised when agent initialization fails."""
101
+
102
+ def __init__(self, message: str, agent_id: Optional[str] = None):
103
+ super().__init__(message, agent_id)
@@ -0,0 +1,559 @@
1
+ """
2
+ Graph-Aware Agent Mixin
3
+
4
+ Provides reusable knowledge graph functionality for agents.
5
+ Can be mixed into any agent class to add graph capabilities.
6
+ """
7
+
8
+ import logging
9
+ from typing import Dict, List, Any, Optional, Set
10
+
11
+ from aiecs.domain.knowledge_graph.models.entity import Entity
12
+ from aiecs.domain.knowledge_graph.models.relation import Relation
13
+ from aiecs.domain.knowledge_graph.models.path import Path
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ class GraphAwareAgentMixin:
19
+ """
20
+ Mixin to add knowledge graph capabilities to any agent.
21
+
22
+ Provides:
23
+ - Graph store integration
24
+ - Knowledge formatting utilities
25
+ - Graph query helpers
26
+ - Entity/relation utilities
27
+
28
+ Usage:
29
+ class MyAgent(BaseAIAgent, GraphAwareAgentMixin):
30
+ def __init__(self, graph_store, ...):
31
+ super().__init__(...)
32
+ self.graph_store = graph_store
33
+ """
34
+
35
+ # Note: Assumes the class has self.graph_store: Optional[GraphStore]
36
+
37
+ # ==================== Knowledge Formatting ====================
38
+
39
+ def format_entity(self, entity: Entity, include_properties: bool = True) -> str:
40
+ """
41
+ Format a single entity as a readable string.
42
+
43
+ Args:
44
+ entity: Entity to format
45
+ include_properties: Whether to include properties
46
+
47
+ Returns:
48
+ Formatted string
49
+
50
+ Example:
51
+ >>> entity = Entity(id="alice", entity_type="Person", properties={"name": "Alice"})
52
+ >>> mixin.format_entity(entity)
53
+ "Person: alice (name=Alice)"
54
+ """
55
+ parts = [f"{entity.entity_type}: {entity.id}"]
56
+
57
+ if include_properties and entity.properties:
58
+ props_str = ", ".join(f"{k}={v}" for k, v in entity.properties.items())
59
+ parts.append(f"({props_str})")
60
+
61
+ return " ".join(parts)
62
+
63
+ def format_entities(self, entities: List[Entity], max_items: int = 10) -> str:
64
+ """
65
+ Format a list of entities as a readable string.
66
+
67
+ Args:
68
+ entities: List of entities to format
69
+ max_items: Maximum number of entities to include
70
+
71
+ Returns:
72
+ Formatted string with one entity per line
73
+
74
+ Example:
75
+ >>> entities = [Entity(id="alice", entity_type="Person", ...), ...]
76
+ >>> mixin.format_entities(entities)
77
+ "- Person: alice (name=Alice)\n- Company: tech_corp (name=TechCorp)"
78
+ """
79
+ if not entities:
80
+ return ""
81
+
82
+ lines = []
83
+ for entity in entities[:max_items]:
84
+ lines.append(f"- {self.format_entity(entity)}")
85
+
86
+ if len(entities) > max_items:
87
+ lines.append(f"... and {len(entities) - max_items} more")
88
+
89
+ return "\n".join(lines)
90
+
91
+ def format_relation(self, relation: Relation, include_entities: bool = False) -> str:
92
+ """
93
+ Format a relation as a readable string.
94
+
95
+ Args:
96
+ relation: Relation to format
97
+ include_entities: Whether to fetch and include entity details
98
+
99
+ Returns:
100
+ Formatted string
101
+
102
+ Example:
103
+ >>> relation = Relation(id="r1", source_id="alice", target_id="bob", relation_type="KNOWS")
104
+ >>> mixin.format_relation(relation)
105
+ "alice --[KNOWS]--> bob"
106
+ """
107
+ if include_entities and hasattr(self, "graph_store") and self.graph_store:
108
+ # Fetch entity details (async, but this is a sync method)
109
+ # In production, this would be async
110
+ return f"{relation.source_id} --[{relation.relation_type}]--> {relation.target_id}"
111
+
112
+ return f"{relation.source_id} --[{relation.relation_type}]--> {relation.target_id}"
113
+
114
+ def format_path(self, path: Path, include_properties: bool = False) -> str:
115
+ """
116
+ Format a graph path as a readable string.
117
+
118
+ Args:
119
+ path: Path to format
120
+ include_properties: Whether to include entity properties
121
+
122
+ Returns:
123
+ Formatted string showing the path
124
+
125
+ Example:
126
+ >>> path = Path(nodes=[e1, e2], edges=[r1], weight=1.0)
127
+ >>> mixin.format_path(path)
128
+ "alice --[KNOWS]--> bob --[WORKS_FOR]--> tech_corp"
129
+ """
130
+ if not path.nodes:
131
+ return ""
132
+
133
+ parts = []
134
+
135
+ # Add first node
136
+ parts.append(self.format_entity(path.nodes[0], include_properties))
137
+
138
+ # Add edges and subsequent nodes
139
+ for i, edge in enumerate(path.edges):
140
+ parts.append(f"--[{edge.relation_type}]-->")
141
+ if i + 1 < len(path.nodes):
142
+ parts.append(self.format_entity(path.nodes[i + 1], include_properties))
143
+
144
+ return " ".join(parts)
145
+
146
+ def format_knowledge_summary(
147
+ self,
148
+ entities: List[Entity],
149
+ relations: Optional[List[Relation]] = None,
150
+ max_entities: int = 5,
151
+ max_relations: int = 5,
152
+ ) -> str:
153
+ """
154
+ Format a summary of knowledge (entities and relations).
155
+
156
+ Args:
157
+ entities: List of entities
158
+ relations: Optional list of relations
159
+ max_entities: Maximum entities to show
160
+ max_relations: Maximum relations to show
161
+
162
+ Returns:
163
+ Formatted summary string
164
+ """
165
+ lines = []
166
+
167
+ if entities:
168
+ lines.append(f"Entities ({len(entities)}):")
169
+ lines.append(self.format_entities(entities, max_items=max_entities))
170
+
171
+ if relations:
172
+ lines.append(f"\nRelations ({len(relations)}):")
173
+ for rel in relations[:max_relations]:
174
+ lines.append(f" {self.format_relation(rel)}")
175
+ if len(relations) > max_relations:
176
+ lines.append(f" ... and {len(relations) - max_relations} more")
177
+
178
+ return "\n".join(lines)
179
+
180
+ # ==================== Graph Query Utilities ====================
181
+
182
+ async def find_entity_by_property(
183
+ self,
184
+ entity_type: Optional[str] = None,
185
+ property_name: str = "name",
186
+ property_value: Any = None,
187
+ limit: int = 10,
188
+ ) -> List[Entity]:
189
+ """
190
+ Find entities by property value.
191
+
192
+ Args:
193
+ entity_type: Optional filter by entity type
194
+ property_name: Property name to search
195
+ property_value: Property value to match
196
+ limit: Maximum results
197
+
198
+ Returns:
199
+ List of matching entities
200
+
201
+ Example:
202
+ >>> entities = await mixin.find_entity_by_property(
203
+ ... entity_type="Person",
204
+ ... property_name="name",
205
+ ... property_value="Alice"
206
+ ... )
207
+ """
208
+ if not hasattr(self, "graph_store") or self.graph_store is None:
209
+ logger.warning("GraphStore not available")
210
+ return []
211
+
212
+ # This is a simplified implementation
213
+ # In production, would use proper graph query or filtering
214
+ try:
215
+ # For now, return empty - would need graph query support
216
+ # This is a placeholder for future enhancement
217
+ return []
218
+ except Exception as e:
219
+ logger.error(f"Error finding entity by property: {e}")
220
+ return []
221
+
222
+ async def get_entity_neighbors(
223
+ self,
224
+ entity_id: str,
225
+ relation_type: Optional[str] = None,
226
+ direction: str = "outgoing",
227
+ limit: int = 10,
228
+ ) -> List[Entity]:
229
+ """
230
+ Get neighboring entities for a given entity.
231
+
232
+ Args:
233
+ entity_id: Entity ID
234
+ relation_type: Optional filter by relation type
235
+ direction: "outgoing", "incoming", or "both"
236
+ limit: Maximum results
237
+
238
+ Returns:
239
+ List of neighboring entities
240
+
241
+ Example:
242
+ >>> neighbors = await mixin.get_entity_neighbors(
243
+ ... entity_id="alice",
244
+ ... relation_type="KNOWS",
245
+ ... direction="outgoing"
246
+ ... )
247
+ """
248
+ if not hasattr(self, "graph_store") or self.graph_store is None:
249
+ logger.warning("GraphStore not available")
250
+ return []
251
+
252
+ try:
253
+ neighbors = await self.graph_store.get_neighbors(
254
+ entity_id=entity_id,
255
+ relation_type=relation_type,
256
+ direction=direction,
257
+ )
258
+ return neighbors[:limit]
259
+ except Exception as e:
260
+ logger.error(f"Error getting neighbors: {e}")
261
+ return []
262
+
263
+ async def find_paths_between(
264
+ self,
265
+ source_id: str,
266
+ target_id: str,
267
+ max_depth: int = 3,
268
+ relation_types: Optional[List[str]] = None,
269
+ ) -> List[Path]:
270
+ """
271
+ Find paths between two entities.
272
+
273
+ Args:
274
+ source_id: Source entity ID
275
+ target_id: Target entity ID
276
+ max_depth: Maximum path depth
277
+ relation_types: Optional filter by relation types
278
+
279
+ Returns:
280
+ List of paths
281
+
282
+ Example:
283
+ >>> paths = await mixin.find_paths_between(
284
+ ... source_id="alice",
285
+ ... target_id="tech_corp",
286
+ ... max_depth=2
287
+ ... )
288
+ """
289
+ if not hasattr(self, "graph_store") or self.graph_store is None:
290
+ logger.warning("GraphStore not available")
291
+ return []
292
+
293
+ try:
294
+ # Use graph store's find_paths method
295
+ paths = await self.graph_store.find_paths(
296
+ source_entity_id=source_id,
297
+ target_entity_id=target_id,
298
+ max_depth=max_depth,
299
+ max_paths=10,
300
+ )
301
+
302
+ # Filter by relation types if specified
303
+ if relation_types:
304
+ filtered_paths = []
305
+ for path in paths:
306
+ # Check if all edges match relation types
307
+ if all(edge.relation_type in relation_types for edge in path.edges):
308
+ filtered_paths.append(path)
309
+ return filtered_paths
310
+
311
+ return paths
312
+ except Exception as e:
313
+ logger.error(f"Error finding paths: {e}")
314
+ return []
315
+
316
+ async def get_entity_subgraph(
317
+ self,
318
+ entity_id: str,
319
+ max_depth: int = 2,
320
+ relation_types: Optional[List[str]] = None,
321
+ ) -> Dict[str, Any]:
322
+ """
323
+ Get a subgraph centered around an entity.
324
+
325
+ Args:
326
+ entity_id: Center entity ID
327
+ max_depth: Maximum depth for traversal
328
+ relation_types: Optional filter by relation types
329
+
330
+ Returns:
331
+ Dictionary with 'entities' and 'relations' lists
332
+
333
+ Example:
334
+ >>> subgraph = await mixin.get_entity_subgraph(
335
+ ... entity_id="alice",
336
+ ... max_depth=2
337
+ ... )
338
+ >>> print(f"Entities: {len(subgraph['entities'])}")
339
+ """
340
+ if not hasattr(self, "graph_store") or self.graph_store is None:
341
+ logger.warning("GraphStore not available")
342
+ return {"entities": [], "relations": []}
343
+
344
+ try:
345
+ entities = []
346
+ relations = []
347
+ visited: Set[str] = {entity_id}
348
+
349
+ # Get center entity
350
+ center = await self.graph_store.get_entity(entity_id)
351
+ if not center:
352
+ return {"entities": [], "relations": []}
353
+
354
+ entities.append(center)
355
+ current_level = [entity_id]
356
+
357
+ for depth in range(max_depth):
358
+ next_level = []
359
+
360
+ for e_id in current_level:
361
+ neighbors = await self.graph_store.get_neighbors(
362
+ entity_id=e_id,
363
+ relation_type=None, # Get all relation types
364
+ direction="both",
365
+ )
366
+
367
+ for neighbor in neighbors:
368
+ if neighbor.id not in visited:
369
+ visited.add(neighbor.id)
370
+ entities.append(neighbor)
371
+ next_level.append(neighbor.id)
372
+
373
+ # Note: In a full implementation, we'd also collect relations
374
+ # This is simplified
375
+
376
+ current_level = next_level
377
+ if not current_level:
378
+ break
379
+
380
+ return {
381
+ "entities": [e.model_dump() for e in entities],
382
+ "relations": relations,
383
+ }
384
+ except Exception as e:
385
+ logger.error(f"Error getting subgraph: {e}")
386
+ return {"entities": [], "relations": []}
387
+
388
+ async def search_entities(
389
+ self,
390
+ query: Optional[str] = None,
391
+ entity_types: Optional[List[str]] = None,
392
+ limit: int = 10,
393
+ threshold: float = 0.7,
394
+ ) -> List[Entity]:
395
+ """
396
+ Search for entities using vector search or filtering.
397
+
398
+ Args:
399
+ query: Optional search query (for vector search)
400
+ entity_types: Optional filter by entity types
401
+ limit: Maximum results
402
+ threshold: Similarity threshold for vector search
403
+
404
+ Returns:
405
+ List of matching entities
406
+
407
+ Example:
408
+ >>> entities = await mixin.search_entities(
409
+ ... query="engineer at tech company",
410
+ ... entity_types=["Person"],
411
+ ... limit=5
412
+ ... )
413
+ """
414
+ if not hasattr(self, "graph_store") or self.graph_store is None:
415
+ logger.warning("GraphStore not available")
416
+ return []
417
+
418
+ try:
419
+ # If query provided, try vector search
420
+ if query:
421
+ # Note: This would require embedding generation
422
+ # For now, this is a placeholder
423
+ # In production: generate embedding and use vector_search
424
+ pass
425
+
426
+ # For now, return empty
427
+ # In production, would use vector_search or filtering
428
+ return []
429
+ except Exception as e:
430
+ logger.error(f"Error searching entities: {e}")
431
+ return []
432
+
433
+ # ==================== Knowledge Context Utilities ====================
434
+
435
+ def extract_entity_mentions(self, text: str) -> List[str]:
436
+ """
437
+ Extract potential entity mentions from text.
438
+
439
+ Simple implementation - in production would use NER or more sophisticated methods.
440
+
441
+ Args:
442
+ text: Text to analyze
443
+
444
+ Returns:
445
+ List of potential entity IDs or names
446
+
447
+ Example:
448
+ >>> mentions = mixin.extract_entity_mentions("Alice works at TechCorp")
449
+ >>> # Returns: ["Alice", "TechCorp"]
450
+ """
451
+ # Simple implementation - split by common delimiters
452
+ # In production, would use NER or entity linking
453
+ words = text.split()
454
+ mentions = []
455
+
456
+ # Look for capitalized words (potential entity names)
457
+ for word in words:
458
+ if word and word[0].isupper() and len(word) > 1:
459
+ mentions.append(word.strip(".,!?;:"))
460
+
461
+ return mentions
462
+
463
+ def build_knowledge_context_prompt(
464
+ self,
465
+ entities: List[Entity],
466
+ relations: Optional[List[Relation]] = None,
467
+ max_length: int = 500,
468
+ ) -> str:
469
+ """
470
+ Build a prompt section with knowledge context.
471
+
472
+ Args:
473
+ entities: List of entities to include
474
+ relations: Optional list of relations
475
+ max_length: Maximum length of formatted text
476
+
477
+ Returns:
478
+ Formatted prompt section
479
+
480
+ Example:
481
+ >>> prompt = mixin.build_knowledge_context_prompt(
482
+ ... entities=[alice, bob],
483
+ ... relations=[knows_rel]
484
+ ... )
485
+ >>> # Returns formatted string for inclusion in prompt
486
+ """
487
+ lines = ["RELEVANT KNOWLEDGE:"]
488
+
489
+ # Add entities
490
+ if entities:
491
+ lines.append("\nEntities:")
492
+ entity_text = self.format_entities(entities, max_items=5)
493
+ lines.append(entity_text)
494
+
495
+ # Add relations
496
+ if relations:
497
+ lines.append("\nRelations:")
498
+ for rel in relations[:5]:
499
+ lines.append(f" {self.format_relation(rel)}")
500
+
501
+ full_text = "\n".join(lines)
502
+
503
+ # Truncate if too long
504
+ if len(full_text) > max_length:
505
+ full_text = full_text[:max_length] + "..."
506
+
507
+ return full_text
508
+
509
+ def validate_graph_store(self) -> bool:
510
+ """
511
+ Validate that graph store is available and initialized.
512
+
513
+ Returns:
514
+ True if graph store is available, False otherwise
515
+ """
516
+ if not hasattr(self, "graph_store"):
517
+ return False
518
+
519
+ if self.graph_store is None:
520
+ return False
521
+
522
+ # Could add more validation (e.g., ping the store)
523
+ return True
524
+
525
+ def get_graph_stats(self) -> Dict[str, Any]:
526
+ """
527
+ Get statistics about the knowledge graph.
528
+
529
+ Returns:
530
+ Dictionary with graph statistics
531
+
532
+ Example:
533
+ >>> stats = mixin.get_graph_stats()
534
+ >>> print(f"Entities: {stats['entity_count']}")
535
+ """
536
+ if not self.validate_graph_store():
537
+ return {"available": False, "entity_count": 0, "relation_count": 0}
538
+
539
+ try:
540
+ # Use graph store's get_stats if available
541
+ if hasattr(self.graph_store, "get_stats"):
542
+ stats = self.graph_store.get_stats()
543
+ # Normalize stats format
544
+ return {
545
+ "available": True,
546
+ "entity_count": stats.get("entities", stats.get("nodes", "unknown")),
547
+ "relation_count": stats.get("relations", stats.get("edges", "unknown")),
548
+ **stats, # Include all original stats
549
+ }
550
+
551
+ # Otherwise return basic info
552
+ return {
553
+ "available": True,
554
+ "entity_count": "unknown",
555
+ "relation_count": "unknown",
556
+ }
557
+ except Exception as e:
558
+ logger.error(f"Error getting graph stats: {e}")
559
+ return {"available": False, "error": str(e)}