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,189 @@
1
+ """
2
+ Relation Validator
3
+
4
+ Validates relations against knowledge graph schema.
5
+ """
6
+
7
+ from typing import List, Optional, Tuple
8
+ from aiecs.domain.knowledge_graph.models.entity import Entity
9
+ from aiecs.domain.knowledge_graph.models.relation import Relation
10
+ from aiecs.domain.knowledge_graph.schema.graph_schema import GraphSchema
11
+
12
+
13
+ class RelationValidator:
14
+ """
15
+ Validate relations against schema rules
16
+
17
+ Ensures that:
18
+ - Relation type exists in schema
19
+ - Source and target entity types are compatible
20
+ - Relation properties match schema
21
+ - Required properties are present
22
+
23
+ Example:
24
+ ```python
25
+ validator = RelationValidator(schema)
26
+
27
+ is_valid, errors = validator.validate_relation(
28
+ relation,
29
+ source_entity,
30
+ target_entity
31
+ )
32
+
33
+ if not is_valid:
34
+ print(f"Invalid relation: {errors}")
35
+ ```
36
+ """
37
+
38
+ def __init__(self, schema: Optional[GraphSchema] = None, strict: bool = False):
39
+ """
40
+ Initialize relation validator
41
+
42
+ Args:
43
+ schema: GraphSchema to validate against (optional)
44
+ strict: If True, reject relations not in schema; if False, allow unknown types
45
+ """
46
+ self.schema = schema
47
+ self.strict = strict
48
+
49
+ def validate_relation(
50
+ self, relation: Relation, source_entity: Entity, target_entity: Entity
51
+ ) -> Tuple[bool, List[str]]:
52
+ """
53
+ Validate a relation against schema
54
+
55
+ Args:
56
+ relation: Relation to validate
57
+ source_entity: Source entity
58
+ target_entity: Target entity
59
+
60
+ Returns:
61
+ Tuple of (is_valid, error_messages)
62
+ """
63
+ errors = []
64
+
65
+ # Basic validation (always performed)
66
+ if not relation.source_id:
67
+ errors.append("Relation missing source_id")
68
+ if not relation.target_id:
69
+ errors.append("Relation missing target_id")
70
+ if not relation.relation_type:
71
+ errors.append("Relation missing relation_type")
72
+
73
+ # Check entity IDs match
74
+ if relation.source_id != source_entity.id:
75
+ errors.append(
76
+ f"Relation source_id '{relation.source_id}' does not match "
77
+ f"source_entity id '{source_entity.id}'"
78
+ )
79
+ if relation.target_id != target_entity.id:
80
+ errors.append(
81
+ f"Relation target_id '{relation.target_id}' does not match "
82
+ f"target_entity id '{target_entity.id}'"
83
+ )
84
+
85
+ # Schema-based validation (if schema provided)
86
+ if self.schema:
87
+ schema_errors = self._validate_against_schema(relation, source_entity, target_entity)
88
+ errors.extend(schema_errors)
89
+
90
+ return (len(errors) == 0, errors)
91
+
92
+ def validate_relations(
93
+ self, relations: List[Relation], entities: List[Entity]
94
+ ) -> List[Tuple[Relation, bool, List[str]]]:
95
+ """
96
+ Validate multiple relations
97
+
98
+ Args:
99
+ relations: List of relations to validate
100
+ entities: List of entities (source and targets)
101
+
102
+ Returns:
103
+ List of (relation, is_valid, errors) tuples
104
+ """
105
+ # Build entity lookup
106
+ entity_lookup = {e.id: e for e in entities}
107
+
108
+ results = []
109
+ for relation in relations:
110
+ source = entity_lookup.get(relation.source_id)
111
+ target = entity_lookup.get(relation.target_id)
112
+
113
+ if not source or not target:
114
+ is_valid = False
115
+ errors = [f"Source or target entity not found for relation {relation.id}"]
116
+ else:
117
+ is_valid, errors = self.validate_relation(relation, source, target)
118
+
119
+ results.append((relation, is_valid, errors))
120
+
121
+ return results
122
+
123
+ def filter_valid_relations(
124
+ self, relations: List[Relation], entities: List[Entity]
125
+ ) -> List[Relation]:
126
+ """
127
+ Filter relations to only valid ones
128
+
129
+ Args:
130
+ relations: List of relations
131
+ entities: List of entities
132
+
133
+ Returns:
134
+ List of valid relations
135
+ """
136
+ validation_results = self.validate_relations(relations, entities)
137
+ return [relation for relation, is_valid, errors in validation_results if is_valid]
138
+
139
+ def _validate_against_schema(
140
+ self, relation: Relation, source_entity: Entity, target_entity: Entity
141
+ ) -> List[str]:
142
+ """
143
+ Validate relation against schema rules
144
+
145
+ Args:
146
+ relation: Relation to validate
147
+ source_entity: Source entity
148
+ target_entity: Target entity
149
+
150
+ Returns:
151
+ List of error messages (empty if valid)
152
+ """
153
+ errors = []
154
+
155
+ # Check if relation type exists in schema
156
+ if not self.schema.has_relation_type(relation.relation_type):
157
+ if self.strict:
158
+ errors.append(f"Relation type '{relation.relation_type}' not found in schema")
159
+ # In non-strict mode, allow unknown relation types
160
+ return errors
161
+
162
+ # Get relation type schema
163
+ rel_type_schema = self.schema.get_relation_type(relation.relation_type)
164
+
165
+ # Validate source entity type
166
+ if rel_type_schema.source_entity_types:
167
+ if source_entity.entity_type not in rel_type_schema.source_entity_types:
168
+ errors.append(
169
+ f"Source entity type '{source_entity.entity_type}' not allowed for "
170
+ f"relation '{relation.relation_type}'. "
171
+ f"Allowed types: {rel_type_schema.source_entity_types}"
172
+ )
173
+
174
+ # Validate target entity type
175
+ if rel_type_schema.target_entity_types:
176
+ if target_entity.entity_type not in rel_type_schema.target_entity_types:
177
+ errors.append(
178
+ f"Target entity type '{target_entity.entity_type}' not allowed for "
179
+ f"relation '{relation.relation_type}'. "
180
+ f"Allowed types: {rel_type_schema.target_entity_types}"
181
+ )
182
+
183
+ # TODO: Validate relation properties against schema (if PropertySchema defined)
184
+ # This would check:
185
+ # - Required properties are present
186
+ # - Property types match schema
187
+ # - Values are within allowed ranges/values
188
+
189
+ return errors
@@ -0,0 +1,11 @@
1
+ """
2
+ Knowledge Graph Visualization
3
+
4
+ Tools for visualizing and exporting knowledge graphs.
5
+ """
6
+
7
+ from aiecs.application.knowledge_graph.visualization.graph_visualizer import (
8
+ GraphVisualizer,
9
+ )
10
+
11
+ __all__ = ["GraphVisualizer"]
@@ -0,0 +1,321 @@
1
+ """
2
+ Graph Visualization Utilities
3
+
4
+ Export knowledge graphs to various formats for visualization.
5
+ """
6
+
7
+ from typing import List, Dict, Any
8
+ from aiecs.domain.knowledge_graph.models.entity import Entity
9
+ from aiecs.domain.knowledge_graph.models.relation import Relation
10
+ from aiecs.domain.knowledge_graph.models.path import Path
11
+
12
+
13
+ class GraphVisualizer:
14
+ """
15
+ Visualize knowledge graphs in various formats
16
+
17
+ Supports export to:
18
+ - DOT format (Graphviz)
19
+ - JSON for D3.js, Cytoscape.js, etc.
20
+ - NetworkX-compatible format
21
+
22
+ Example:
23
+ ```python
24
+ visualizer = GraphVisualizer()
25
+
26
+ # Export to DOT
27
+ dot = visualizer.to_dot(entities, relations)
28
+ with open("graph.dot", "w") as f:
29
+ f.write(dot)
30
+
31
+ # Export to JSON
32
+ json_data = visualizer.to_json(entities, relations)
33
+ ```
34
+ """
35
+
36
+ def to_dot(
37
+ self,
38
+ entities: List[Entity],
39
+ relations: List[Relation],
40
+ graph_name: str = "knowledge_graph",
41
+ include_properties: bool = True,
42
+ max_label_length: int = 50,
43
+ ) -> str:
44
+ """
45
+ Export graph to DOT format (Graphviz)
46
+
47
+ Args:
48
+ entities: List of entities
49
+ relations: List of relations
50
+ graph_name: Name of the graph
51
+ include_properties: Include entity properties in labels
52
+ max_label_length: Maximum label length
53
+
54
+ Returns:
55
+ DOT format string
56
+ """
57
+ lines = []
58
+ lines.append(f"digraph {graph_name} {{")
59
+ lines.append(" rankdir=LR;")
60
+ lines.append(" node [shape=box, style=rounded];")
61
+ lines.append("")
62
+
63
+ # Add nodes
64
+ for entity in entities:
65
+ label = self._create_entity_label(entity, include_properties, max_label_length)
66
+ node_id = self._sanitize_id(entity.id)
67
+ color = self._get_entity_color(entity.entity_type)
68
+
69
+ lines.append(
70
+ f' {node_id} [label="{label}", fillcolor="{color}", style="rounded,filled"];'
71
+ )
72
+
73
+ lines.append("")
74
+
75
+ # Add edges
76
+ for relation in relations:
77
+ source_id = self._sanitize_id(relation.source_id)
78
+ target_id = self._sanitize_id(relation.target_id)
79
+ label = relation.relation_type
80
+
81
+ lines.append(f' {source_id} -> {target_id} [label="{label}"];')
82
+
83
+ lines.append("}")
84
+ return "\n".join(lines)
85
+
86
+ def to_json(
87
+ self,
88
+ entities: List[Entity],
89
+ relations: List[Relation],
90
+ format: str = "d3",
91
+ ) -> Dict[str, Any]:
92
+ """
93
+ Export graph to JSON format
94
+
95
+ Args:
96
+ entities: List of entities
97
+ relations: List of relations
98
+ format: JSON format ("d3", "cytoscape", "networkx")
99
+
100
+ Returns:
101
+ Dictionary suitable for JSON export
102
+ """
103
+ if format == "d3":
104
+ return self._to_d3_json(entities, relations)
105
+ elif format == "cytoscape":
106
+ return self._to_cytoscape_json(entities, relations)
107
+ elif format == "networkx":
108
+ return self._to_networkx_json(entities, relations)
109
+ else:
110
+ raise ValueError(f"Unsupported format: {format}")
111
+
112
+ def _to_d3_json(self, entities: List[Entity], relations: List[Relation]) -> Dict[str, Any]:
113
+ """Export to D3.js force-directed graph format"""
114
+ nodes = []
115
+ for entity in entities:
116
+ nodes.append(
117
+ {
118
+ "id": entity.id,
119
+ "name": entity.properties.get("name", entity.id),
120
+ "type": entity.entity_type,
121
+ "properties": entity.properties,
122
+ "group": hash(entity.entity_type) % 10, # Color group
123
+ }
124
+ )
125
+
126
+ links = []
127
+ for relation in relations:
128
+ links.append(
129
+ {
130
+ "source": relation.source_id,
131
+ "target": relation.target_id,
132
+ "type": relation.relation_type,
133
+ "properties": relation.properties,
134
+ }
135
+ )
136
+
137
+ return {"nodes": nodes, "links": links}
138
+
139
+ def _to_cytoscape_json(
140
+ self, entities: List[Entity], relations: List[Relation]
141
+ ) -> Dict[str, Any]:
142
+ """Export to Cytoscape.js format"""
143
+ elements = []
144
+
145
+ # Add nodes
146
+ for entity in entities:
147
+ elements.append(
148
+ {
149
+ "data": {
150
+ "id": entity.id,
151
+ "label": entity.properties.get("name", entity.id),
152
+ "type": entity.entity_type,
153
+ "properties": entity.properties,
154
+ },
155
+ "group": "nodes",
156
+ }
157
+ )
158
+
159
+ # Add edges
160
+ for relation in relations:
161
+ elements.append(
162
+ {
163
+ "data": {
164
+ "id": relation.id,
165
+ "source": relation.source_id,
166
+ "target": relation.target_id,
167
+ "label": relation.relation_type,
168
+ "properties": relation.properties,
169
+ },
170
+ "group": "edges",
171
+ }
172
+ )
173
+
174
+ return {"elements": elements}
175
+
176
+ def _to_networkx_json(
177
+ self, entities: List[Entity], relations: List[Relation]
178
+ ) -> Dict[str, Any]:
179
+ """Export to NetworkX node-link format"""
180
+ nodes = []
181
+ for entity in entities:
182
+ nodes.append(
183
+ {
184
+ "id": entity.id,
185
+ "entity_type": entity.entity_type,
186
+ **entity.properties,
187
+ }
188
+ )
189
+
190
+ links = []
191
+ for relation in relations:
192
+ links.append(
193
+ {
194
+ "source": relation.source_id,
195
+ "target": relation.target_id,
196
+ "relation_type": relation.relation_type,
197
+ **relation.properties,
198
+ }
199
+ )
200
+
201
+ return {
202
+ "directed": True,
203
+ "multigraph": False,
204
+ "graph": {},
205
+ "nodes": nodes,
206
+ "links": links,
207
+ }
208
+
209
+ def to_mermaid(
210
+ self,
211
+ entities: List[Entity],
212
+ relations: List[Relation],
213
+ max_entities: int = 50,
214
+ ) -> str:
215
+ """
216
+ Export graph to Mermaid diagram format
217
+
218
+ Args:
219
+ entities: List of entities
220
+ relations: List of relations
221
+ max_entities: Maximum entities to include
222
+
223
+ Returns:
224
+ Mermaid diagram string
225
+ """
226
+ lines = []
227
+ lines.append("graph LR")
228
+
229
+ # Limit entities for readability
230
+ entities_subset = entities[:max_entities]
231
+ entity_ids = {e.id for e in entities_subset}
232
+
233
+ # Add nodes
234
+ for entity in entities_subset:
235
+ label = entity.properties.get("name", entity.id)
236
+ label = label[:30] # Truncate long labels
237
+ node_id = self._sanitize_id(entity.id)
238
+ lines.append(f' {node_id}["{label}"]')
239
+
240
+ # Add edges (only between included entities)
241
+ for relation in relations:
242
+ if relation.source_id in entity_ids and relation.target_id in entity_ids:
243
+ source_id = self._sanitize_id(relation.source_id)
244
+ target_id = self._sanitize_id(relation.target_id)
245
+ label = relation.relation_type
246
+ lines.append(f" {source_id} -->|{label}| {target_id}")
247
+
248
+ return "\n".join(lines)
249
+
250
+ def export_path_to_dot(self, path: Path) -> str:
251
+ """
252
+ Export a single path to DOT format
253
+
254
+ Args:
255
+ path: Path to export
256
+
257
+ Returns:
258
+ DOT format string
259
+ """
260
+ lines = []
261
+ lines.append("digraph path {")
262
+ lines.append(" rankdir=LR;")
263
+ lines.append(" node [shape=box, style=rounded];")
264
+ lines.append("")
265
+
266
+ # Add nodes from path
267
+ for entity in path.nodes:
268
+ label = entity.properties.get("name", entity.id)
269
+ node_id = self._sanitize_id(entity.id)
270
+ lines.append(f' {node_id} [label="{label}"];')
271
+
272
+ lines.append("")
273
+
274
+ # Add edges from path
275
+ for relation in path.edges:
276
+ source_id = self._sanitize_id(relation.source_id)
277
+ target_id = self._sanitize_id(relation.target_id)
278
+ label = relation.relation_type
279
+ lines.append(f' {source_id} -> {target_id} [label="{label}"];')
280
+
281
+ lines.append("}")
282
+ return "\n".join(lines)
283
+
284
+ def _create_entity_label(
285
+ self, entity: Entity, include_properties: bool, max_length: int
286
+ ) -> str:
287
+ """Create label for entity node"""
288
+ label_parts = [f"{entity.entity_type}: {entity.id}"]
289
+
290
+ if include_properties and entity.properties:
291
+ # Add key properties
292
+ for key, value in list(entity.properties.items())[:3]:
293
+ label_parts.append(f"{key}: {value}")
294
+
295
+ label = "\\n".join(label_parts)
296
+
297
+ if len(label) > max_length:
298
+ label = label[:max_length] + "..."
299
+
300
+ return label
301
+
302
+ def _sanitize_id(self, id_str: str) -> str:
303
+ """Sanitize ID for DOT format"""
304
+ # Replace special characters
305
+ sanitized = id_str.replace("-", "_").replace(":", "_").replace(" ", "_")
306
+ # Ensure it starts with a letter
307
+ if not sanitized[0].isalpha():
308
+ sanitized = "n_" + sanitized
309
+ return sanitized
310
+
311
+ def _get_entity_color(self, entity_type: str) -> str:
312
+ """Get color for entity type"""
313
+ colors = {
314
+ "Person": "lightblue",
315
+ "Company": "lightgreen",
316
+ "Product": "lightyellow",
317
+ "Location": "lightcoral",
318
+ "Event": "lightpink",
319
+ "Document": "lightgray",
320
+ }
321
+ return colors.get(entity_type, "white")
@@ -0,0 +1,9 @@
1
+ """
2
+ Common utilities and shared components
3
+ """
4
+
5
+ from . import knowledge_graph
6
+
7
+ __all__ = [
8
+ "knowledge_graph",
9
+ ]
@@ -0,0 +1,17 @@
1
+ """Common knowledge graph utilities and patterns"""
2
+
3
+ from .runnable import (
4
+ Runnable,
5
+ RunnableConfig,
6
+ RunnableState,
7
+ ExecutionMetrics,
8
+ CircuitBreaker,
9
+ )
10
+
11
+ __all__ = [
12
+ "Runnable",
13
+ "RunnableConfig",
14
+ "RunnableState",
15
+ "ExecutionMetrics",
16
+ "CircuitBreaker",
17
+ ]