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,514 @@
1
+ """
2
+ In-Memory Graph Store Implementation
3
+
4
+ Implements Tier 1 of GraphStore interface using networkx.
5
+ Tier 2 methods work automatically via default implementations.
6
+
7
+ This is ideal for:
8
+ - Development and testing
9
+ - Small graphs (< 100K nodes)
10
+ - Prototyping
11
+ - Scenarios where persistence is not required
12
+ """
13
+
14
+ from typing import List, Optional, Dict
15
+ import networkx as nx
16
+ from aiecs.domain.knowledge_graph.models.entity import Entity
17
+ from aiecs.domain.knowledge_graph.models.relation import Relation
18
+ from aiecs.infrastructure.graph_storage.base import GraphStore
19
+
20
+
21
+ class InMemoryGraphStore(GraphStore):
22
+ """
23
+ In-Memory Graph Store using NetworkX
24
+
25
+ **Implementation Strategy**:
26
+ - Uses networkx.DiGraph for graph structure
27
+ - Stores Entity objects as node attributes
28
+ - Stores Relation objects as edge attributes
29
+ - Implements ONLY Tier 1 methods
30
+ - Tier 2 methods (traverse, find_paths, etc.) work automatically!
31
+
32
+ **Features**:
33
+ - Fast for small-medium graphs
34
+ - No external dependencies
35
+ - Full Python ecosystem integration
36
+ - Rich graph algorithms from networkx
37
+
38
+ **Limitations**:
39
+ - Not persistent (lost on restart)
40
+ - Limited by RAM
41
+ - No concurrent access control
42
+ - No vector search optimization
43
+
44
+ Example:
45
+ ```python
46
+ store = InMemoryGraphStore()
47
+ await store.initialize()
48
+
49
+ # Add entities
50
+ entity = Entity(id="person_1", entity_type="Person", properties={"name": "Alice"})
51
+ await store.add_entity(entity)
52
+
53
+ # Tier 2 methods work automatically
54
+ paths = await store.traverse("person_1", max_depth=3)
55
+ ```
56
+ """
57
+
58
+ def __init__(self):
59
+ """Initialize in-memory graph store"""
60
+ self.graph: Optional[nx.DiGraph] = None
61
+ self.entities: Dict[str, Entity] = {}
62
+ self.relations: Dict[str, Relation] = {}
63
+ self._initialized = False
64
+
65
+ # =========================================================================
66
+ # TIER 1 IMPLEMENTATION - Core CRUD Operations
67
+ # =========================================================================
68
+
69
+ async def initialize(self) -> None:
70
+ """Initialize the in-memory graph"""
71
+ if self._initialized:
72
+ return
73
+
74
+ self.graph = nx.DiGraph()
75
+ self.entities = {}
76
+ self.relations = {}
77
+ self._initialized = True
78
+
79
+ async def close(self) -> None:
80
+ """Close and cleanup (nothing to do for in-memory)"""
81
+ self.graph = None
82
+ self.entities = {}
83
+ self.relations = {}
84
+ self._initialized = False
85
+
86
+ async def add_entity(self, entity: Entity) -> None:
87
+ """
88
+ Add entity to graph
89
+
90
+ Args:
91
+ entity: Entity to add
92
+
93
+ Raises:
94
+ ValueError: If entity already exists
95
+ RuntimeError: If store not initialized
96
+ """
97
+ if not self._initialized:
98
+ raise RuntimeError("GraphStore not initialized. Call initialize() first.")
99
+
100
+ if entity.id in self.entities:
101
+ raise ValueError(f"Entity with ID '{entity.id}' already exists")
102
+
103
+ # Add to networkx graph
104
+ self.graph.add_node(entity.id, entity=entity)
105
+
106
+ # Add to entity index
107
+ self.entities[entity.id] = entity
108
+
109
+ async def get_entity(self, entity_id: str) -> Optional[Entity]:
110
+ """
111
+ Get entity by ID
112
+
113
+ Args:
114
+ entity_id: Entity ID
115
+
116
+ Returns:
117
+ Entity if found, None otherwise
118
+ """
119
+ if not self._initialized:
120
+ return None
121
+
122
+ return self.entities.get(entity_id)
123
+
124
+ async def add_relation(self, relation: Relation) -> None:
125
+ """
126
+ Add relation to graph
127
+
128
+ Args:
129
+ relation: Relation to add
130
+
131
+ Raises:
132
+ ValueError: If relation already exists or entities don't exist
133
+ RuntimeError: If store not initialized
134
+ """
135
+ if not self._initialized:
136
+ raise RuntimeError("GraphStore not initialized. Call initialize() first.")
137
+
138
+ if relation.id in self.relations:
139
+ raise ValueError(f"Relation with ID '{relation.id}' already exists")
140
+
141
+ # Validate entities exist
142
+ if relation.source_id not in self.entities:
143
+ raise ValueError(f"Source entity '{relation.source_id}' not found")
144
+ if relation.target_id not in self.entities:
145
+ raise ValueError(f"Target entity '{relation.target_id}' not found")
146
+
147
+ # Add to networkx graph
148
+ self.graph.add_edge(
149
+ relation.source_id,
150
+ relation.target_id,
151
+ key=relation.id,
152
+ relation=relation,
153
+ )
154
+
155
+ # Add to relation index
156
+ self.relations[relation.id] = relation
157
+
158
+ async def get_relation(self, relation_id: str) -> Optional[Relation]:
159
+ """
160
+ Get relation by ID
161
+
162
+ Args:
163
+ relation_id: Relation ID
164
+
165
+ Returns:
166
+ Relation if found, None otherwise
167
+ """
168
+ if not self._initialized:
169
+ return None
170
+
171
+ return self.relations.get(relation_id)
172
+
173
+ async def get_neighbors(
174
+ self,
175
+ entity_id: str,
176
+ relation_type: Optional[str] = None,
177
+ direction: str = "outgoing",
178
+ ) -> List[Entity]:
179
+ """
180
+ Get neighboring entities
181
+
182
+ Args:
183
+ entity_id: Entity ID to get neighbors for
184
+ relation_type: Optional filter by relation type
185
+ direction: "outgoing", "incoming", or "both"
186
+
187
+ Returns:
188
+ List of neighboring entities
189
+ """
190
+ if not self._initialized or entity_id not in self.graph:
191
+ return []
192
+
193
+ neighbors = []
194
+
195
+ # Get outgoing neighbors
196
+ if direction in ("outgoing", "both"):
197
+ for target_id in self.graph.successors(entity_id):
198
+ # Check relation type filter
199
+ if relation_type:
200
+ edge_data = self.graph.get_edge_data(entity_id, target_id)
201
+ if edge_data:
202
+ relation = edge_data.get("relation")
203
+ if relation and relation.relation_type == relation_type:
204
+ if target_id in self.entities:
205
+ neighbors.append(self.entities[target_id])
206
+ else:
207
+ if target_id in self.entities:
208
+ neighbors.append(self.entities[target_id])
209
+
210
+ # Get incoming neighbors
211
+ if direction in ("incoming", "both"):
212
+ for source_id in self.graph.predecessors(entity_id):
213
+ # Check relation type filter
214
+ if relation_type:
215
+ edge_data = self.graph.get_edge_data(source_id, entity_id)
216
+ if edge_data:
217
+ relation = edge_data.get("relation")
218
+ if relation and relation.relation_type == relation_type:
219
+ if source_id in self.entities:
220
+ neighbors.append(self.entities[source_id])
221
+ else:
222
+ if source_id in self.entities:
223
+ neighbors.append(self.entities[source_id])
224
+
225
+ return neighbors
226
+
227
+ async def get_all_entities(
228
+ self, entity_type: Optional[str] = None, limit: Optional[int] = None
229
+ ) -> List[Entity]:
230
+ """
231
+ Get all entities, optionally filtered by type
232
+
233
+ Args:
234
+ entity_type: Optional filter by entity type
235
+ limit: Optional limit on number of entities
236
+
237
+ Returns:
238
+ List of entities
239
+ """
240
+ if not self._initialized:
241
+ return []
242
+
243
+ entities = list(self.entities.values())
244
+
245
+ # Filter by entity type if specified
246
+ if entity_type:
247
+ entities = [e for e in entities if e.entity_type == entity_type]
248
+
249
+ # Apply limit if specified
250
+ if limit:
251
+ entities = entities[:limit]
252
+
253
+ return entities
254
+
255
+ # =========================================================================
256
+ # TIER 2 METHODS - Inherited from base class
257
+ # =========================================================================
258
+ # traverse(), find_paths(), subgraph_query(), execute_query()
259
+ # work automatically through default implementations!
260
+
261
+ # =========================================================================
262
+ # OPTIONAL: Override Tier 2 methods for optimization
263
+ # =========================================================================
264
+
265
+ async def vector_search(
266
+ self,
267
+ query_embedding: List[float],
268
+ entity_type: Optional[str] = None,
269
+ max_results: int = 10,
270
+ score_threshold: float = 0.0,
271
+ ) -> List[tuple]:
272
+ """
273
+ Optimized vector search for in-memory store
274
+
275
+ Performs brute-force cosine similarity over all entities with embeddings.
276
+
277
+ Args:
278
+ query_embedding: Query vector
279
+ entity_type: Optional filter by entity type
280
+ max_results: Maximum number of results
281
+ score_threshold: Minimum similarity score (0.0-1.0)
282
+
283
+ Returns:
284
+ List of (entity, similarity_score) tuples, sorted descending
285
+ """
286
+ if not self._initialized:
287
+ return []
288
+
289
+ if not query_embedding:
290
+ raise ValueError("Query embedding cannot be empty")
291
+
292
+ import numpy as np
293
+
294
+ query_vec = np.array(query_embedding, dtype=np.float32)
295
+ query_norm = np.linalg.norm(query_vec)
296
+
297
+ if query_norm == 0:
298
+ return []
299
+
300
+ scored_entities = []
301
+
302
+ for entity in self.entities.values():
303
+ # Filter by entity type if specified
304
+ if entity_type and entity.entity_type != entity_type:
305
+ continue
306
+
307
+ # Skip entities without embeddings
308
+ if not entity.embedding:
309
+ continue
310
+
311
+ # Compute cosine similarity
312
+ entity_vec = np.array(entity.embedding, dtype=np.float32)
313
+ entity_norm = np.linalg.norm(entity_vec)
314
+
315
+ if entity_norm == 0:
316
+ continue
317
+
318
+ # Cosine similarity
319
+ similarity = np.dot(query_vec, entity_vec) / (query_norm * entity_norm)
320
+ # Normalize to 0-1 range
321
+ similarity = (similarity + 1) / 2
322
+
323
+ # Filter by threshold
324
+ if similarity >= score_threshold:
325
+ scored_entities.append((entity, float(similarity)))
326
+
327
+ # Sort by score descending and return top results
328
+ scored_entities.sort(key=lambda x: x[1], reverse=True)
329
+ return scored_entities[:max_results]
330
+
331
+ async def text_search(
332
+ self,
333
+ query_text: str,
334
+ entity_type: Optional[str] = None,
335
+ max_results: int = 10,
336
+ score_threshold: float = 0.0,
337
+ method: str = "bm25",
338
+ ) -> List[tuple]:
339
+ """
340
+ Optimized text search for in-memory store
341
+
342
+ Performs text similarity search over entity properties using BM25, Jaccard,
343
+ cosine similarity, or Levenshtein distance.
344
+
345
+ Args:
346
+ query_text: Query text string
347
+ entity_type: Optional filter by entity type
348
+ max_results: Maximum number of results
349
+ score_threshold: Minimum similarity score (0.0-1.0)
350
+ method: Similarity method ("bm25", "jaccard", "cosine", "levenshtein")
351
+
352
+ Returns:
353
+ List of (entity, similarity_score) tuples, sorted descending
354
+ """
355
+ if not self._initialized:
356
+ return []
357
+
358
+ if not query_text:
359
+ return []
360
+
361
+ from aiecs.application.knowledge_graph.search.text_similarity import (
362
+ BM25Scorer,
363
+ jaccard_similarity_text,
364
+ cosine_similarity_text,
365
+ normalized_levenshtein_similarity,
366
+ )
367
+
368
+ # Get candidate entities
369
+ entities = list(self.entities.values())
370
+ if entity_type:
371
+ entities = [e for e in entities if e.entity_type == entity_type]
372
+
373
+ if not entities:
374
+ return []
375
+
376
+ scored_entities = []
377
+
378
+ # Extract text from entities (combine properties into searchable text)
379
+ entity_texts = []
380
+ for entity in entities:
381
+ # Combine all string properties into searchable text
382
+ text_parts = []
383
+ for key, value in entity.properties.items():
384
+ if isinstance(value, str):
385
+ text_parts.append(value)
386
+ elif isinstance(value, (list, tuple)):
387
+ text_parts.extend(str(v) for v in value if isinstance(v, str))
388
+ entity_text = " ".join(text_parts)
389
+ entity_texts.append((entity, entity_text))
390
+
391
+ if method == "bm25":
392
+ # Use BM25 scorer
393
+ corpus = [text for _, text in entity_texts]
394
+ scorer = BM25Scorer(corpus)
395
+ scores = scorer.score(query_text)
396
+
397
+ for (entity, _), score in zip(entity_texts, scores):
398
+ if score >= score_threshold:
399
+ scored_entities.append((entity, float(score)))
400
+
401
+ elif method == "jaccard":
402
+ for entity, text in entity_texts:
403
+ score = jaccard_similarity_text(query_text, text)
404
+ if score >= score_threshold:
405
+ scored_entities.append((entity, score))
406
+
407
+ elif method == "cosine":
408
+ for entity, text in entity_texts:
409
+ score = cosine_similarity_text(query_text, text)
410
+ if score >= score_threshold:
411
+ scored_entities.append((entity, score))
412
+
413
+ elif method == "levenshtein":
414
+ for entity, text in entity_texts:
415
+ score = normalized_levenshtein_similarity(query_text, text)
416
+ if score >= score_threshold:
417
+ scored_entities.append((entity, score))
418
+
419
+ else:
420
+ raise ValueError(
421
+ f"Unknown text search method: {method}. Use 'bm25', 'jaccard', 'cosine', or 'levenshtein'"
422
+ )
423
+
424
+ # Sort by score descending and return top results
425
+ scored_entities.sort(key=lambda x: x[1], reverse=True)
426
+ return scored_entities[:max_results]
427
+
428
+ async def find_paths(
429
+ self,
430
+ source_entity_id: str,
431
+ target_entity_id: str,
432
+ max_depth: int = 5,
433
+ max_paths: int = 10,
434
+ ) -> List:
435
+ """
436
+ Optimized path finding using networkx algorithms
437
+
438
+ Overrides default implementation to use networkx.all_simple_paths
439
+ for better performance.
440
+ """
441
+ from aiecs.domain.knowledge_graph.models.path import Path
442
+
443
+ if not self._initialized:
444
+ return []
445
+
446
+ if source_entity_id not in self.graph or target_entity_id not in self.graph:
447
+ return []
448
+
449
+ try:
450
+ # Use networkx's optimized path finding
451
+ paths = []
452
+ for node_path in nx.all_simple_paths(
453
+ self.graph,
454
+ source_entity_id,
455
+ target_entity_id,
456
+ cutoff=max_depth,
457
+ ):
458
+ # Convert node IDs to Entity and Relation objects
459
+ entities = [
460
+ self.entities[node_id] for node_id in node_path if node_id in self.entities
461
+ ]
462
+
463
+ # Get relations between consecutive nodes
464
+ edges = []
465
+ for i in range(len(node_path) - 1):
466
+ edge_data = self.graph.get_edge_data(node_path[i], node_path[i + 1])
467
+ if edge_data and "relation" in edge_data:
468
+ edges.append(edge_data["relation"])
469
+
470
+ if len(entities) == len(node_path):
471
+ paths.append(Path(nodes=entities, edges=edges))
472
+
473
+ if len(paths) >= max_paths:
474
+ break
475
+
476
+ return paths
477
+
478
+ except nx.NetworkXNoPath:
479
+ return []
480
+
481
+ # =========================================================================
482
+ # UTILITY METHODS
483
+ # =========================================================================
484
+
485
+ def get_stats(self) -> Dict[str, int]:
486
+ """
487
+ Get graph statistics
488
+
489
+ Returns:
490
+ Dictionary with node count, edge count, etc.
491
+ """
492
+ if not self._initialized:
493
+ return {"nodes": 0, "edges": 0, "entities": 0, "relations": 0}
494
+
495
+ return {
496
+ "nodes": self.graph.number_of_nodes(),
497
+ "edges": self.graph.number_of_edges(),
498
+ "entities": len(self.entities),
499
+ "relations": len(self.relations),
500
+ }
501
+
502
+ def clear(self) -> None:
503
+ """Clear all data from the graph"""
504
+ if self._initialized:
505
+ self.graph.clear()
506
+ self.entities.clear()
507
+ self.relations.clear()
508
+
509
+ def __str__(self) -> str:
510
+ stats = self.get_stats()
511
+ return f"InMemoryGraphStore(entities={stats['entities']}, relations={stats['relations']})"
512
+
513
+ def __repr__(self) -> str:
514
+ return self.__str__()