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,554 @@
1
+ """
2
+ Reasoning Engine
3
+
4
+ Multi-hop reasoning over knowledge graphs with evidence collection and answer generation.
5
+ """
6
+
7
+ import uuid
8
+ import time
9
+ from typing import List, Optional, Dict, Any, Tuple
10
+ from aiecs.infrastructure.graph_storage.base import GraphStore
11
+ from aiecs.domain.knowledge_graph.models.path import Path
12
+ from aiecs.domain.knowledge_graph.models.evidence import (
13
+ Evidence,
14
+ EvidenceType,
15
+ ReasoningResult,
16
+ )
17
+ from aiecs.domain.knowledge_graph.models.query_plan import QueryPlan, QueryStep
18
+ from aiecs.domain.knowledge_graph.models.query import QueryType
19
+ from aiecs.application.knowledge_graph.traversal.enhanced_traversal import (
20
+ EnhancedTraversal,
21
+ )
22
+ from aiecs.application.knowledge_graph.traversal.path_scorer import PathScorer
23
+ from aiecs.application.knowledge_graph.reasoning.query_planner import (
24
+ QueryPlanner,
25
+ )
26
+
27
+
28
+ class ReasoningEngine:
29
+ """
30
+ Multi-Hop Reasoning Engine
31
+
32
+ Executes query plans, collects evidence, and generates answers
33
+ for complex multi-hop queries over knowledge graphs.
34
+
35
+ Features:
36
+ - Execute query plans from QueryPlanner
37
+ - Multi-hop path finding
38
+ - Evidence collection and scoring
39
+ - Path ranking by relevance
40
+ - Answer generation from evidence
41
+
42
+ Example:
43
+ ```python
44
+ engine = ReasoningEngine(graph_store)
45
+
46
+ # Reason over a query
47
+ result = await engine.reason(
48
+ query="What companies does Alice know people at?",
49
+ context={"start_entity_id": "person_alice"}
50
+ )
51
+
52
+ print(f"Answer: {result.answer}")
53
+ print(f"Confidence: {result.confidence}")
54
+ print(f"Evidence: {result.evidence_count} pieces")
55
+ ```
56
+ """
57
+
58
+ def __init__(
59
+ self,
60
+ graph_store: GraphStore,
61
+ query_planner: Optional[QueryPlanner] = None,
62
+ ):
63
+ """
64
+ Initialize reasoning engine
65
+
66
+ Args:
67
+ graph_store: Graph storage backend
68
+ query_planner: Query planner (creates one if not provided)
69
+ """
70
+ self.graph_store = graph_store
71
+ self.query_planner = query_planner or QueryPlanner(graph_store)
72
+ self.traversal = EnhancedTraversal(graph_store)
73
+ self.path_scorer = PathScorer()
74
+
75
+ async def reason(
76
+ self,
77
+ query: str,
78
+ context: Optional[Dict[str, Any]] = None,
79
+ max_hops: int = 3,
80
+ max_evidence: int = 20,
81
+ ) -> ReasoningResult:
82
+ """
83
+ Perform multi-hop reasoning on a query
84
+
85
+ Args:
86
+ query: Natural language query
87
+ context: Query context (entity IDs, embeddings, etc.)
88
+ max_hops: Maximum number of hops for traversal
89
+ max_evidence: Maximum number of evidence pieces to collect
90
+
91
+ Returns:
92
+ Reasoning result with evidence and answer
93
+ """
94
+ start_time = time.time()
95
+ context = context or {}
96
+ trace = []
97
+
98
+ # Step 1: Plan the query
99
+ trace.append(f"Planning query: {query}")
100
+ plan = self.query_planner.plan_query(query, context)
101
+ trace.append(f"Created plan with {len(plan.steps)} steps")
102
+
103
+ # Step 2: Execute plan and collect evidence
104
+ trace.append("Executing query plan...")
105
+ evidence = await self._execute_plan_with_evidence(plan, trace)
106
+
107
+ # Fallback: If no evidence found but start_entity_id is provided, try
108
+ # direct traversal
109
+ if not evidence and context.get("start_entity_id"):
110
+ import logging
111
+
112
+ logger = logging.getLogger(__name__)
113
+
114
+ trace.append(
115
+ f"WARNING: Query plan returned no evidence. Plan had {len(plan.steps)} steps."
116
+ )
117
+ trace.append(f"Plan steps: {[s.step_id + ':' + s.operation.value for s in plan.steps]}")
118
+ logger.warning(
119
+ f"Query plan returned no evidence. "
120
+ f"Plan ID: {plan.plan_id}, Steps: {len(plan.steps)}, "
121
+ f"Query: {query}, Context: {context}"
122
+ )
123
+
124
+ trace.append(f"FALLBACK: Trying direct traversal from {context['start_entity_id']}")
125
+ start_id = context["start_entity_id"]
126
+ target_id = context.get("target_entity_id")
127
+
128
+ try:
129
+ paths = await self.find_multi_hop_paths(
130
+ start_entity_id=start_id,
131
+ target_entity_id=target_id,
132
+ max_hops=max_hops,
133
+ relation_types=context.get("relation_types"),
134
+ max_paths=max_evidence,
135
+ )
136
+
137
+ if paths:
138
+ path_evidence = await self.collect_evidence_from_paths(
139
+ paths, source="direct_traversal_fallback"
140
+ )
141
+ evidence.extend(path_evidence)
142
+ trace.append(
143
+ f"FALLBACK SUCCESS: Found {len(path_evidence)} evidence pieces from direct traversal"
144
+ )
145
+ logger.info(
146
+ f"Fallback traversal succeeded: {len(path_evidence)} evidence pieces from {start_id}"
147
+ )
148
+ else:
149
+ trace.append(f"FALLBACK FAILED: No paths found from {start_id}")
150
+ logger.warning(f"Fallback traversal found no paths from {start_id}")
151
+ except Exception as e:
152
+ trace.append(f"FALLBACK ERROR: {str(e)}")
153
+ logger.error(f"Fallback traversal failed: {str(e)}", exc_info=True)
154
+
155
+ # Step 3: Rank and filter evidence
156
+ trace.append(f"Collected {len(evidence)} pieces of evidence")
157
+ evidence = self._rank_and_filter_evidence(evidence, max_evidence)
158
+ trace.append(f"Filtered to top {len(evidence)} pieces")
159
+
160
+ # Step 4: Generate answer
161
+ trace.append("Generating answer from evidence...")
162
+ answer, confidence = self._generate_answer(query, evidence)
163
+
164
+ execution_time = (time.time() - start_time) * 1000
165
+
166
+ return ReasoningResult(
167
+ query=query,
168
+ evidence=evidence,
169
+ answer=answer,
170
+ confidence=confidence,
171
+ reasoning_trace=trace,
172
+ execution_time_ms=execution_time,
173
+ metadata={"plan_id": plan.plan_id, "num_steps": len(plan.steps)},
174
+ )
175
+
176
+ async def find_multi_hop_paths(
177
+ self,
178
+ start_entity_id: str,
179
+ target_entity_id: Optional[str] = None,
180
+ max_hops: int = 3,
181
+ relation_types: Optional[List[str]] = None,
182
+ max_paths: int = 10,
183
+ ) -> List[Path]:
184
+ """
185
+ Find multi-hop paths between entities
186
+
187
+ Args:
188
+ start_entity_id: Starting entity ID
189
+ target_entity_id: Target entity ID (None for all reachable)
190
+ max_hops: Maximum number of hops
191
+ relation_types: Allowed relation types (None for all)
192
+ max_paths: Maximum number of paths to return
193
+
194
+ Returns:
195
+ List of paths found
196
+ """
197
+ # Use graph store's traverse method
198
+ paths = await self.graph_store.traverse(
199
+ start_entity_id=start_entity_id,
200
+ relation_type=None, # Will filter later if needed
201
+ max_depth=max_hops,
202
+ max_results=max_paths * 2, # Get more, then filter
203
+ )
204
+
205
+ # Filter by target if specified
206
+ if target_entity_id:
207
+ paths = [path for path in paths if path.nodes[-1].id == target_entity_id]
208
+
209
+ # Filter by relation types if specified
210
+ if relation_types:
211
+ paths = [
212
+ path
213
+ for path in paths
214
+ if all(rel.relation_type in relation_types for rel in path.edges)
215
+ ]
216
+
217
+ return paths[:max_paths]
218
+
219
+ async def collect_evidence_from_paths(
220
+ self, paths: List[Path], source: str = "path_finding"
221
+ ) -> List[Evidence]:
222
+ """
223
+ Collect evidence from paths
224
+
225
+ Args:
226
+ paths: List of paths to extract evidence from
227
+ source: Source identifier for the evidence
228
+
229
+ Returns:
230
+ List of evidence pieces
231
+ """
232
+ evidence_list = []
233
+
234
+ for i, path in enumerate(paths):
235
+ # Calculate confidence based on path properties
236
+ confidence = self._calculate_path_confidence(path)
237
+
238
+ # Calculate relevance (for now, use path length as proxy)
239
+ relevance = 1.0 / max(1, len(path.nodes) - 1)
240
+
241
+ # Create explanation
242
+ explanation = self._create_path_explanation(path)
243
+
244
+ evidence = Evidence(
245
+ evidence_id=f"ev_{uuid.uuid4().hex[:8]}",
246
+ evidence_type=EvidenceType.PATH,
247
+ entities=path.nodes,
248
+ relations=path.edges,
249
+ paths=[path],
250
+ confidence=confidence,
251
+ relevance_score=relevance,
252
+ explanation=explanation,
253
+ source=source,
254
+ metadata={"path_index": i, "path_length": len(path.nodes)},
255
+ )
256
+
257
+ evidence_list.append(evidence)
258
+
259
+ return evidence_list
260
+
261
+ def rank_evidence(
262
+ self, evidence: List[Evidence], ranking_method: str = "combined_score"
263
+ ) -> List[Evidence]:
264
+ """
265
+ Rank evidence by relevance
266
+
267
+ Args:
268
+ evidence: List of evidence to rank
269
+ ranking_method: Method to use for ranking
270
+ - "combined_score": confidence * relevance
271
+ - "confidence": confidence only
272
+ - "relevance": relevance only
273
+
274
+ Returns:
275
+ Ranked evidence list
276
+ """
277
+ if ranking_method == "combined_score":
278
+ return sorted(evidence, key=lambda e: e.combined_score, reverse=True)
279
+ elif ranking_method == "confidence":
280
+ return sorted(evidence, key=lambda e: e.confidence, reverse=True)
281
+ elif ranking_method == "relevance":
282
+ return sorted(evidence, key=lambda e: e.relevance_score, reverse=True)
283
+ else:
284
+ return evidence
285
+
286
+ def _calculate_path_confidence(self, path: Path) -> float:
287
+ """Calculate confidence score for a path"""
288
+ if not path.edges:
289
+ return 1.0
290
+
291
+ # Use average weight of relations as confidence proxy
292
+ weights = [rel.weight for rel in path.edges if rel.weight is not None]
293
+ if not weights:
294
+ return 0.5
295
+
296
+ return sum(weights) / len(weights)
297
+
298
+ def _create_path_explanation(self, path: Path) -> str:
299
+ """Create human-readable explanation of a path"""
300
+ if len(path.nodes) == 1:
301
+ entity = path.nodes[0]
302
+ return f"Entity: {entity.properties.get('name', entity.id)} ({entity.entity_type})"
303
+
304
+ parts = []
305
+ for i, entity in enumerate(path.nodes):
306
+ entity_name = entity.properties.get("name", entity.id)
307
+ entity_type = entity.entity_type
308
+ parts.append(f"{entity_name} ({entity_type})")
309
+
310
+ if i < len(path.edges):
311
+ relation = path.edges[i]
312
+ parts.append(f" --[{relation.relation_type}]--> ")
313
+
314
+ return "".join(parts)
315
+
316
+ async def _execute_plan_with_evidence(
317
+ self, plan: QueryPlan, trace: List[str]
318
+ ) -> List[Evidence]:
319
+ """Execute query plan and collect evidence"""
320
+ import logging
321
+
322
+ logger = logging.getLogger(__name__)
323
+
324
+ all_evidence = []
325
+ completed_steps = set()
326
+ step_results: Dict[str, Any] = {}
327
+
328
+ # Get execution order
329
+ execution_order = plan.get_execution_order()
330
+ trace.append(f"Plan has {len(plan.steps)} steps, execution order: {execution_order}")
331
+
332
+ for level, step_ids in enumerate(execution_order):
333
+ trace.append(f"Executing level {level}: {step_ids}")
334
+
335
+ # Execute steps in this level (could be parallelized)
336
+ for step_id in step_ids:
337
+ try:
338
+ step = next(s for s in plan.steps if s.step_id == step_id)
339
+ trace.append(
340
+ f" Executing {step_id}: {step.operation.value} - {step.description}"
341
+ )
342
+
343
+ # Execute step
344
+ step_evidence = await self._execute_step(step, step_results)
345
+ all_evidence.extend(step_evidence)
346
+
347
+ # Store results for dependent steps
348
+ step_results[step_id] = step_evidence
349
+ completed_steps.add(step_id)
350
+
351
+ trace.append(f" {step_id}: Collected {len(step_evidence)} evidence")
352
+ logger.debug(f"Step {step_id} completed: {len(step_evidence)} evidence pieces")
353
+
354
+ if len(step_evidence) == 0:
355
+ trace.append(f" WARNING: {step_id} returned no evidence")
356
+ logger.warning(
357
+ f"Step {step_id} ({step.operation.value}) returned no evidence. "
358
+ f"Query: {step.query.query_type}, "
359
+ f"Entity ID: {getattr(step.query, 'entity_id', None)}, "
360
+ f"Source: {getattr(step.query, 'source_entity_id', None)}"
361
+ )
362
+ except Exception as e:
363
+ error_msg = f"Error executing step {step_id}: {str(e)}"
364
+ trace.append(f" ERROR: {error_msg}")
365
+ logger.error(error_msg, exc_info=True)
366
+ # Continue with other steps even if one fails
367
+
368
+ return all_evidence
369
+
370
+ async def _execute_step(
371
+ self, step: QueryStep, previous_results: Dict[str, Any]
372
+ ) -> List[Evidence]:
373
+ """Execute a single query step"""
374
+ query = step.query
375
+ evidence = []
376
+
377
+ # Entity lookup
378
+ if query.query_type == QueryType.ENTITY_LOOKUP:
379
+ if query.entity_id:
380
+ entity = await self.graph_store.get_entity(query.entity_id)
381
+ if entity:
382
+ evidence.append(
383
+ Evidence(
384
+ evidence_id=f"ev_{uuid.uuid4().hex[:8]}",
385
+ evidence_type=EvidenceType.ENTITY,
386
+ entities=[entity],
387
+ confidence=1.0,
388
+ relevance_score=1.0,
389
+ explanation=f"Found entity: {entity.id}",
390
+ source=step.step_id,
391
+ )
392
+ )
393
+
394
+ # Vector search
395
+ elif query.query_type == QueryType.VECTOR_SEARCH:
396
+ if query.embedding:
397
+ results = await self.graph_store.vector_search(
398
+ query_embedding=query.embedding,
399
+ entity_type=query.entity_type,
400
+ max_results=query.max_results,
401
+ score_threshold=query.score_threshold,
402
+ )
403
+
404
+ for entity, score in results:
405
+ evidence.append(
406
+ Evidence(
407
+ evidence_id=f"ev_{uuid.uuid4().hex[:8]}",
408
+ evidence_type=EvidenceType.ENTITY,
409
+ entities=[entity],
410
+ confidence=score,
411
+ relevance_score=score,
412
+ explanation=f"Similar entity: {entity.id} (score: {score:.2f})",
413
+ source=step.step_id,
414
+ )
415
+ )
416
+
417
+ # Traversal
418
+ elif query.query_type == QueryType.TRAVERSAL:
419
+ import logging
420
+
421
+ logger = logging.getLogger(__name__)
422
+
423
+ # Get starting entities from previous steps or query
424
+ start_ids = []
425
+ if query.entity_id:
426
+ start_ids = [query.entity_id]
427
+ logger.debug(f"TRAVERSAL: Using entity_id from query: {query.entity_id}")
428
+ elif step.depends_on:
429
+ # Get entities from dependent steps
430
+ for dep_id in step.depends_on:
431
+ if dep_id in previous_results:
432
+ dep_evidence = previous_results[dep_id]
433
+ extracted_ids = [e.id for ev in dep_evidence for e in ev.entities]
434
+ start_ids.extend(extracted_ids)
435
+ logger.debug(
436
+ f"TRAVERSAL: Extracted {len(extracted_ids)} entity IDs from step {dep_id}"
437
+ )
438
+ else:
439
+ logger.warning(
440
+ f"TRAVERSAL: Dependent step {dep_id} not found in previous_results"
441
+ )
442
+ else:
443
+ logger.warning("TRAVERSAL: No entity_id and no dependencies. Cannot traverse.")
444
+
445
+ if not start_ids:
446
+ logger.warning(
447
+ f"TRAVERSAL step {step.step_id} has no starting entities. "
448
+ f"Query entity_id: {getattr(query, 'entity_id', None)}, "
449
+ f"Dependencies: {step.depends_on}, "
450
+ f"Previous results keys: {list(previous_results.keys())}"
451
+ )
452
+ else:
453
+ # Traverse from each starting entity
454
+ # Limit starting points
455
+ for start_id in start_ids[: query.max_results]:
456
+ try:
457
+ paths = await self.graph_store.traverse(
458
+ start_entity_id=start_id,
459
+ relation_type=query.relation_type,
460
+ max_depth=query.max_depth,
461
+ max_results=query.max_results,
462
+ )
463
+ logger.debug(f"TRAVERSAL: Found {len(paths)} paths from {start_id}")
464
+
465
+ # Convert paths to evidence
466
+ path_evidence = await self.collect_evidence_from_paths(
467
+ paths, source=step.step_id
468
+ )
469
+ evidence.extend(path_evidence)
470
+ logger.debug(
471
+ f"TRAVERSAL: Collected {len(path_evidence)} evidence from {start_id}"
472
+ )
473
+ except Exception as e:
474
+ logger.error(
475
+ f"TRAVERSAL: Error traversing from {start_id}: {str(e)}",
476
+ exc_info=True,
477
+ )
478
+
479
+ # Path finding
480
+ elif query.query_type == QueryType.PATH_FINDING:
481
+ if query.source_entity_id and query.target_entity_id:
482
+ paths = await self.find_multi_hop_paths(
483
+ start_entity_id=query.source_entity_id,
484
+ target_entity_id=query.target_entity_id,
485
+ max_hops=query.max_depth,
486
+ max_paths=query.max_results,
487
+ )
488
+
489
+ path_evidence = await self.collect_evidence_from_paths(paths, source=step.step_id)
490
+ evidence.extend(path_evidence)
491
+
492
+ return evidence
493
+
494
+ def _rank_and_filter_evidence(
495
+ self, evidence: List[Evidence], max_evidence: int
496
+ ) -> List[Evidence]:
497
+ """Rank and filter evidence to top N"""
498
+ # Rank by combined score
499
+ ranked = self.rank_evidence(evidence, ranking_method="combined_score")
500
+
501
+ # Filter to top N
502
+ return ranked[:max_evidence]
503
+
504
+ def _generate_answer(self, query: str, evidence: List[Evidence]) -> Tuple[str, float]:
505
+ """
506
+ Generate answer from evidence
507
+
508
+ Args:
509
+ query: Original query
510
+ evidence: Collected evidence
511
+
512
+ Returns:
513
+ (answer, confidence) tuple
514
+ """
515
+ if not evidence:
516
+ return "No evidence found to answer the query.", 0.0
517
+
518
+ # Calculate overall confidence
519
+ if evidence:
520
+ confidence = sum(e.combined_score for e in evidence) / len(evidence)
521
+ else:
522
+ confidence = 0.0
523
+
524
+ # Generate answer based on evidence type
525
+ top_evidence = evidence[:5] # Top 5 pieces
526
+
527
+ # Collect unique entities from evidence
528
+ entity_ids = set()
529
+ entity_names = []
530
+
531
+ for ev in top_evidence:
532
+ for entity in ev.entities:
533
+ if entity.id not in entity_ids:
534
+ entity_ids.add(entity.id)
535
+ name = entity.properties.get("name", entity.id)
536
+ entity_type = entity.entity_type
537
+ entity_names.append(f"{name} ({entity_type})")
538
+
539
+ # Build answer
540
+ if len(entity_names) == 0:
541
+ answer = "No relevant entities found."
542
+ elif len(entity_names) == 1:
543
+ answer = f"Found: {entity_names[0]}"
544
+ elif len(entity_names) <= 3:
545
+ answer = f"Found: {', '.join(entity_names)}"
546
+ else:
547
+ answer = f"Found {len(entity_names)} entities: {', '.join(entity_names[:3])}, and {len(entity_names) - 3} more"
548
+
549
+ # Add path information if available
550
+ path_count = sum(1 for ev in top_evidence if ev.evidence_type == EvidenceType.PATH)
551
+ if path_count > 0:
552
+ answer += f" (through {path_count} connection{'s' if path_count != 1 else ''})"
553
+
554
+ return answer, confidence
@@ -0,0 +1,19 @@
1
+ """
2
+ Knowledge Graph Retrieval Application Layer
3
+
4
+ Advanced retrieval strategies for knowledge graph queries.
5
+ """
6
+
7
+ from aiecs.application.knowledge_graph.retrieval.retrieval_strategies import (
8
+ PersonalizedPageRank,
9
+ MultiHopRetrieval,
10
+ FilteredRetrieval,
11
+ RetrievalCache,
12
+ )
13
+
14
+ __all__ = [
15
+ "PersonalizedPageRank",
16
+ "MultiHopRetrieval",
17
+ "FilteredRetrieval",
18
+ "RetrievalCache",
19
+ ]