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,410 @@
1
+ """
2
+ Lazy Loading Support for Graph Storage
3
+
4
+ Provides lazy loading of entities and relations to reduce memory usage
5
+ and improve performance when working with large graphs.
6
+ """
7
+
8
+ import logging
9
+ from typing import Optional, List, Dict, Any, AsyncIterator
10
+ from dataclasses import dataclass, field
11
+
12
+ from aiecs.domain.knowledge_graph.models.entity import Entity
13
+ from aiecs.domain.knowledge_graph.models.relation import Relation
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+
18
+ @dataclass
19
+ class LazyEntity:
20
+ """
21
+ Lazy-loaded entity wrapper
22
+
23
+ Only loads full entity data when accessed, reducing memory usage.
24
+
25
+ Example:
26
+ ```python
27
+ lazy_entity = LazyEntity(id="person_1", store=store)
28
+
29
+ # Entity not loaded yet
30
+ print(lazy_entity.id) # Just ID, no DB query
31
+
32
+ # Load full entity when needed
33
+ entity = await lazy_entity.load()
34
+ print(entity.properties["name"]) # DB query executed
35
+ ```
36
+ """
37
+
38
+ id: str
39
+ entity_type: Optional[str] = None
40
+ _store: Any = None
41
+ _loaded_entity: Optional[Entity] = field(default=None, init=False, repr=False)
42
+ _is_loaded: bool = field(default=False, init=False, repr=False)
43
+
44
+ async def load(self, force: bool = False) -> Optional[Entity]:
45
+ """
46
+ Load the full entity from storage
47
+
48
+ Args:
49
+ force: Force reload even if already loaded
50
+
51
+ Returns:
52
+ Full Entity object or None if not found
53
+ """
54
+ if not force and self._is_loaded:
55
+ return self._loaded_entity
56
+
57
+ if not self._store:
58
+ raise RuntimeError("No store provided for lazy loading")
59
+
60
+ self._loaded_entity = await self._store.get_entity(self.id)
61
+ self._is_loaded = True
62
+ return self._loaded_entity
63
+
64
+ async def get(self, property_name: str, default: Any = None) -> Any:
65
+ """
66
+ Get a specific property (loads entity if needed)
67
+
68
+ Args:
69
+ property_name: Property to retrieve
70
+ default: Default value if property not found
71
+
72
+ Returns:
73
+ Property value or default
74
+ """
75
+ entity = await self.load()
76
+ if not entity:
77
+ return default
78
+ return entity.properties.get(property_name, default)
79
+
80
+ def is_loaded(self) -> bool:
81
+ """Check if entity has been loaded"""
82
+ return self._is_loaded
83
+
84
+ def to_dict(self) -> Dict[str, Any]:
85
+ """Convert to dictionary (only includes loaded data)"""
86
+ result = {"id": self.id}
87
+ if self.entity_type:
88
+ result["entity_type"] = self.entity_type
89
+ if self._is_loaded and self._loaded_entity:
90
+ result["properties"] = self._loaded_entity.properties
91
+ return result
92
+
93
+
94
+ @dataclass
95
+ class LazyRelation:
96
+ """
97
+ Lazy-loaded relation wrapper
98
+
99
+ Only loads full relation data when accessed.
100
+ """
101
+
102
+ id: str
103
+ source_id: str
104
+ target_id: str
105
+ relation_type: Optional[str] = None
106
+ _store: Any = None
107
+ _loaded_relation: Optional[Relation] = field(default=None, init=False, repr=False)
108
+ _is_loaded: bool = field(default=False, init=False, repr=False)
109
+
110
+ async def load(self, force: bool = False) -> Optional[Relation]:
111
+ """Load the full relation from storage"""
112
+ if not force and self._is_loaded:
113
+ return self._loaded_relation
114
+
115
+ if not self._store:
116
+ raise RuntimeError("No store provided for lazy loading")
117
+
118
+ self._loaded_relation = await self._store.get_relation(self.id)
119
+ self._is_loaded = True
120
+ return self._loaded_relation
121
+
122
+ async def get_source(self) -> Optional[Entity]:
123
+ """Get source entity (lazy loaded)"""
124
+ if not self._store:
125
+ return None
126
+ return await self._store.get_entity(self.source_id)
127
+
128
+ async def get_target(self) -> Optional[Entity]:
129
+ """Get target entity (lazy loaded)"""
130
+ if not self._store:
131
+ return None
132
+ return await self._store.get_entity(self.target_id)
133
+
134
+ def is_loaded(self) -> bool:
135
+ """Check if relation has been loaded"""
136
+ return self._is_loaded
137
+
138
+
139
+ class LazyLoadingMixin:
140
+ """
141
+ Mixin providing lazy loading capabilities for graph stores
142
+
143
+ Enables deferred loading of entities and relations to reduce memory usage.
144
+
145
+ Example:
146
+ ```python
147
+ class MyGraphStore(GraphStore, LazyLoadingMixin):
148
+ pass
149
+
150
+ store = MyGraphStore()
151
+
152
+ # Get lazy entities (no DB queries yet)
153
+ lazy_entities = await store.get_lazy_entities(entity_type="Person")
154
+
155
+ # Load specific entities as needed
156
+ for lazy_entity in lazy_entities[:10]:
157
+ entity = await lazy_entity.load()
158
+ print(entity.properties["name"])
159
+ ```
160
+ """
161
+
162
+ async def get_lazy_entity(self, entity_id: str) -> LazyEntity:
163
+ """
164
+ Get a lazy-loaded entity wrapper
165
+
166
+ Args:
167
+ entity_id: Entity ID
168
+
169
+ Returns:
170
+ LazyEntity wrapper (not yet loaded from DB)
171
+ """
172
+ return LazyEntity(id=entity_id, _store=self)
173
+
174
+ async def get_lazy_entities(
175
+ self, entity_type: Optional[str] = None, limit: Optional[int] = None
176
+ ) -> List[LazyEntity]:
177
+ """
178
+ Get lazy-loaded entity wrappers
179
+
180
+ Only fetches IDs and types, not full entity data.
181
+
182
+ Args:
183
+ entity_type: Filter by entity type
184
+ limit: Maximum number of entities
185
+
186
+ Returns:
187
+ List of LazyEntity wrappers
188
+ """
189
+ # Get lightweight entity list (IDs only)
190
+ entities = await self._get_entity_ids(entity_type=entity_type, limit=limit)
191
+
192
+ return [LazyEntity(id=eid, entity_type=etype, _store=self) for eid, etype in entities]
193
+
194
+ async def _get_entity_ids(
195
+ self, entity_type: Optional[str] = None, limit: Optional[int] = None
196
+ ) -> List[tuple[str, str]]:
197
+ """
198
+ Get entity IDs and types only (efficient query)
199
+
200
+ Backends should override this for better performance.
201
+
202
+ Returns:
203
+ List of (entity_id, entity_type) tuples
204
+ """
205
+ # Default implementation - load full entities (inefficient)
206
+ entities = await self.get_all_entities(entity_type=entity_type, limit=limit)
207
+ return [(e.id, e.entity_type) for e in entities]
208
+
209
+ async def get_lazy_neighbors(
210
+ self,
211
+ entity_id: str,
212
+ relation_type: Optional[str] = None,
213
+ direction: str = "outgoing",
214
+ ) -> List[LazyEntity]:
215
+ """
216
+ Get lazy-loaded neighbor entities
217
+
218
+ Args:
219
+ entity_id: Source entity ID
220
+ relation_type: Filter by relation type
221
+ direction: "outgoing", "incoming", or "both"
222
+
223
+ Returns:
224
+ List of LazyEntity wrappers for neighbors
225
+ """
226
+ # Get neighbor IDs without loading full entities
227
+ neighbor_ids = await self._get_neighbor_ids(
228
+ entity_id=entity_id,
229
+ relation_type=relation_type,
230
+ direction=direction,
231
+ )
232
+
233
+ return [LazyEntity(id=nid, _store=self) for nid in neighbor_ids]
234
+
235
+ async def _get_neighbor_ids(
236
+ self,
237
+ entity_id: str,
238
+ relation_type: Optional[str] = None,
239
+ direction: str = "outgoing",
240
+ ) -> List[str]:
241
+ """
242
+ Get neighbor entity IDs only (efficient query)
243
+
244
+ Backends should override this for better performance.
245
+ """
246
+ # Default implementation - load full neighbors
247
+ neighbors = await self.get_neighbors(
248
+ entity_id=entity_id,
249
+ relation_type=relation_type,
250
+ direction=direction,
251
+ )
252
+ return [n.id for n in neighbors]
253
+
254
+
255
+ class EntityBatchLoader:
256
+ """
257
+ Batch loader for efficient loading of multiple entities
258
+
259
+ Collects entity IDs and loads them in batches to reduce DB queries.
260
+ Implements the DataLoader pattern for GraphQL-like efficiency.
261
+
262
+ Example:
263
+ ```python
264
+ loader = EntityBatchLoader(store, batch_size=100)
265
+
266
+ # Queue entities for loading
267
+ e1_future = loader.load("entity_1")
268
+ e2_future = loader.load("entity_2")
269
+ # ... queue many more
270
+
271
+ # Load all queued entities in batch
272
+ await loader.dispatch()
273
+
274
+ # Get results
275
+ entity1 = await e1_future
276
+ entity2 = await e2_future
277
+ ```
278
+ """
279
+
280
+ def __init__(self, store: Any, batch_size: int = 100):
281
+ """
282
+ Initialize batch loader
283
+
284
+ Args:
285
+ store: Graph store instance
286
+ batch_size: Maximum batch size
287
+ """
288
+ self.store = store
289
+ self.batch_size = batch_size
290
+ self._queue: List[str] = []
291
+ self._cache: Dict[str, Optional[Entity]] = {}
292
+ self._futures: Dict[str, Any] = {}
293
+
294
+ async def load(self, entity_id: str) -> Optional[Entity]:
295
+ """
296
+ Load an entity (batched)
297
+
298
+ Args:
299
+ entity_id: Entity ID to load
300
+
301
+ Returns:
302
+ Entity or None if not found
303
+ """
304
+ # Check cache
305
+ if entity_id in self._cache:
306
+ return self._cache[entity_id]
307
+
308
+ # Queue for batch loading
309
+ if entity_id not in self._queue:
310
+ self._queue.append(entity_id)
311
+
312
+ # Dispatch if batch is full
313
+ if len(self._queue) >= self.batch_size:
314
+ await self.dispatch()
315
+
316
+ return self._cache.get(entity_id)
317
+
318
+ async def dispatch(self) -> None:
319
+ """
320
+ Dispatch all queued loads
321
+
322
+ Loads all queued entities in batch and updates cache.
323
+ """
324
+ if not self._queue:
325
+ return
326
+
327
+ # Get unique IDs
328
+ entity_ids = list(set(self._queue))
329
+ self._queue.clear()
330
+
331
+ # Batch load
332
+ entities = await self._batch_fetch_entities(entity_ids)
333
+
334
+ # Update cache
335
+ entity_map = {e.id: e for e in entities}
336
+ for eid in entity_ids:
337
+ self._cache[eid] = entity_map.get(eid)
338
+
339
+ async def _batch_fetch_entities(self, entity_ids: List[str]) -> List[Entity]:
340
+ """
341
+ Fetch multiple entities efficiently
342
+
343
+ Backends should optimize this for batch retrieval.
344
+ """
345
+ entities = []
346
+ for eid in entity_ids:
347
+ entity = await self.store.get_entity(eid)
348
+ if entity:
349
+ entities.append(entity)
350
+ return entities
351
+
352
+ def clear_cache(self) -> None:
353
+ """Clear the entity cache"""
354
+ self._cache.clear()
355
+
356
+
357
+ async def lazy_traverse(
358
+ store: Any, start_entity_id: str, max_depth: int = 3, batch_size: int = 100
359
+ ) -> AsyncIterator[LazyEntity]:
360
+ """
361
+ Lazy graph traversal with batch loading
362
+
363
+ Traverses the graph lazily, yielding entities as they're discovered
364
+ without loading the entire subgraph into memory.
365
+
366
+ Args:
367
+ store: Graph store instance
368
+ start_entity_id: Starting entity ID
369
+ max_depth: Maximum traversal depth
370
+ batch_size: Batch size for loading
371
+
372
+ Yields:
373
+ LazyEntity instances as graph is traversed
374
+
375
+ Example:
376
+ ```python
377
+ async for lazy_entity in lazy_traverse(store, "person_1", max_depth=3):
378
+ entity = await lazy_entity.load()
379
+ print(f"Found: {entity.id}")
380
+ ```
381
+ """
382
+ visited = set()
383
+ # loader = EntityBatchLoader(store, batch_size=batch_size) # Reserved for
384
+ # future use
385
+
386
+ # BFS traversal
387
+ current_level = [start_entity_id]
388
+ depth = 0
389
+
390
+ while current_level and depth <= max_depth:
391
+ next_level = []
392
+
393
+ for entity_id in current_level:
394
+ if entity_id in visited:
395
+ continue
396
+
397
+ visited.add(entity_id)
398
+
399
+ # Yield lazy entity
400
+ lazy_entity = LazyEntity(id=entity_id, _store=store)
401
+ yield lazy_entity
402
+
403
+ # Get neighbors for next level
404
+ neighbors = await store.get_neighbors(entity_id, direction="outgoing")
405
+ for neighbor in neighbors:
406
+ if neighbor.id not in visited:
407
+ next_level.append(neighbor.id)
408
+
409
+ current_level = next_level
410
+ depth += 1