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,601 @@
1
+ """
2
+ Graph Store Base Interface
3
+
4
+ Two-tier abstract interface for graph storage backends:
5
+ - Tier 1 (Basic): Must implement - core CRUD operations
6
+ - Tier 2 (Advanced): Has defaults, can optimize - complex queries
7
+
8
+ This design allows minimal adapters (Tier 1 only) to work immediately,
9
+ while backends can optimize Tier 2 methods for better performance.
10
+ """
11
+
12
+ from abc import ABC, abstractmethod
13
+ from typing import List, Optional, Set
14
+ from collections import deque
15
+
16
+ from aiecs.domain.knowledge_graph.models.entity import Entity
17
+ from aiecs.domain.knowledge_graph.models.relation import Relation
18
+ from aiecs.domain.knowledge_graph.models.path import Path
19
+ from aiecs.domain.knowledge_graph.models.query import (
20
+ GraphQuery,
21
+ GraphResult,
22
+ QueryType,
23
+ )
24
+
25
+
26
+ class GraphStore(ABC):
27
+ """
28
+ Abstract Graph Storage Interface
29
+
30
+ Two-tier design:
31
+
32
+ **Tier 1 - Basic Interface (MUST IMPLEMENT)**:
33
+ - add_entity() - Add entity to graph
34
+ - get_entity() - Get entity by ID
35
+ - add_relation() - Add relation to graph
36
+ - get_relation() - Get relation by ID
37
+ - get_neighbors() - Get neighboring entities
38
+ - initialize() - Initialize storage
39
+ - close() - Close storage connection
40
+
41
+ **Tier 2 - Advanced Interface (HAS DEFAULTS, CAN OPTIMIZE)**:
42
+ - traverse() - Multi-hop graph traversal
43
+ - find_paths() - Find paths between entities
44
+ - subgraph_query() - Extract subgraph
45
+ - vector_search() - Semantic vector search
46
+ - execute_query() - Execute GraphQuery
47
+
48
+ Implementations only need to provide Tier 1 methods. Tier 2 methods
49
+ have default implementations using Tier 1, but can be overridden for
50
+ performance optimization (e.g., using SQL recursive CTEs, Cypher queries).
51
+
52
+ Example:
53
+ ```python
54
+ # Minimal implementation (Tier 1 only)
55
+ class CustomGraphStore(GraphStore):
56
+ async def add_entity(self, entity: Entity) -> None:
57
+ # Your implementation
58
+ pass
59
+
60
+ # ... implement other Tier 1 methods
61
+ # Tier 2 methods work automatically!
62
+
63
+ # Optimized implementation (override Tier 2)
64
+ class OptimizedGraphStore(CustomGraphStore):
65
+ async def traverse(self, ...):
66
+ # Use database-specific optimization
67
+ pass
68
+ ```
69
+ """
70
+
71
+ # =========================================================================
72
+ # TIER 1: BASIC INTERFACE - MUST IMPLEMENT
73
+ # =========================================================================
74
+
75
+ @abstractmethod
76
+ async def initialize(self) -> None:
77
+ """
78
+ Initialize the graph storage backend
79
+
80
+ Called once before using the store. Use this to:
81
+ - Create database connections
82
+ - Initialize data structures
83
+ - Create tables/indexes
84
+ """
85
+
86
+ @abstractmethod
87
+ async def close(self) -> None:
88
+ """
89
+ Close the graph storage backend and cleanup resources
90
+
91
+ Called when shutting down. Use this to:
92
+ - Close database connections
93
+ - Flush pending writes
94
+ - Cleanup resources
95
+ """
96
+
97
+ @abstractmethod
98
+ async def add_entity(self, entity: Entity) -> None:
99
+ """
100
+ Add an entity to the graph
101
+
102
+ Args:
103
+ entity: Entity to add
104
+
105
+ Raises:
106
+ ValueError: If entity with same ID already exists
107
+ """
108
+
109
+ @abstractmethod
110
+ async def get_entity(self, entity_id: str) -> Optional[Entity]:
111
+ """
112
+ Get an entity by ID
113
+
114
+ Args:
115
+ entity_id: Entity ID to retrieve
116
+
117
+ Returns:
118
+ Entity if found, None otherwise
119
+ """
120
+
121
+ @abstractmethod
122
+ async def add_relation(self, relation: Relation) -> None:
123
+ """
124
+ Add a relation to the graph
125
+
126
+ Args:
127
+ relation: Relation to add
128
+
129
+ Raises:
130
+ ValueError: If relation with same ID already exists
131
+ ValueError: If source or target entity doesn't exist
132
+ """
133
+
134
+ @abstractmethod
135
+ async def get_relation(self, relation_id: str) -> Optional[Relation]:
136
+ """
137
+ Get a relation by ID
138
+
139
+ Args:
140
+ relation_id: Relation ID to retrieve
141
+
142
+ Returns:
143
+ Relation if found, None otherwise
144
+ """
145
+
146
+ @abstractmethod
147
+ async def get_neighbors(
148
+ self,
149
+ entity_id: str,
150
+ relation_type: Optional[str] = None,
151
+ direction: str = "outgoing",
152
+ ) -> List[Entity]:
153
+ """
154
+ Get neighboring entities connected by relations
155
+
156
+ Args:
157
+ entity_id: ID of entity to get neighbors for
158
+ relation_type: Optional filter by relation type
159
+ direction: "outgoing", "incoming", or "both"
160
+
161
+ Returns:
162
+ List of neighboring entities
163
+ """
164
+
165
+ # =========================================================================
166
+ # TIER 2: ADVANCED INTERFACE - HAS DEFAULTS (Template Method Pattern)
167
+ # =========================================================================
168
+
169
+ async def traverse(
170
+ self,
171
+ start_entity_id: str,
172
+ relation_type: Optional[str] = None,
173
+ max_depth: int = 3,
174
+ max_results: int = 100,
175
+ ) -> List[Path]:
176
+ """
177
+ Traverse the graph starting from an entity (BFS traversal)
178
+
179
+ **DEFAULT IMPLEMENTATION**: Uses get_neighbors() in BFS pattern.
180
+ Override for better performance (e.g., recursive CTEs in SQL).
181
+
182
+ Args:
183
+ start_entity_id: Starting entity ID
184
+ relation_type: Optional filter by relation type
185
+ max_depth: Maximum traversal depth
186
+ max_results: Maximum number of paths to return
187
+
188
+ Returns:
189
+ List of paths found during traversal
190
+ """
191
+ return await self._default_traverse_bfs(
192
+ start_entity_id, relation_type, max_depth, max_results
193
+ )
194
+
195
+ async def find_paths(
196
+ self,
197
+ source_entity_id: str,
198
+ target_entity_id: str,
199
+ max_depth: int = 5,
200
+ max_paths: int = 10,
201
+ ) -> List[Path]:
202
+ """
203
+ Find paths between two entities
204
+
205
+ **DEFAULT IMPLEMENTATION**: Uses traverse() with early stopping.
206
+ Override for better performance (e.g., bidirectional search).
207
+
208
+ Args:
209
+ source_entity_id: Source entity ID
210
+ target_entity_id: Target entity ID
211
+ max_depth: Maximum path length
212
+ max_paths: Maximum number of paths to return
213
+
214
+ Returns:
215
+ List of paths between source and target
216
+ """
217
+ return await self._default_find_paths(
218
+ source_entity_id, target_entity_id, max_depth, max_paths
219
+ )
220
+
221
+ async def subgraph_query(
222
+ self, entity_ids: List[str], include_relations: bool = True
223
+ ) -> tuple[List[Entity], List[Relation]]:
224
+ """
225
+ Extract a subgraph containing specified entities
226
+
227
+ **DEFAULT IMPLEMENTATION**: Uses get_entity() and get_neighbors().
228
+ Override for better performance (e.g., single JOIN query).
229
+
230
+ Args:
231
+ entity_ids: List of entity IDs to include
232
+ include_relations: Whether to include relations between entities
233
+
234
+ Returns:
235
+ Tuple of (entities, relations)
236
+ """
237
+ return await self._default_subgraph_query(entity_ids, include_relations)
238
+
239
+ async def vector_search(
240
+ self,
241
+ query_embedding: List[float],
242
+ entity_type: Optional[str] = None,
243
+ max_results: int = 10,
244
+ score_threshold: float = 0.0,
245
+ ) -> List[tuple[Entity, float]]:
246
+ """
247
+ Semantic vector search over entities
248
+
249
+ **DEFAULT IMPLEMENTATION**: Brute-force cosine similarity.
250
+ Override for better performance (e.g., pgvector, FAISS, ANN indexes).
251
+
252
+ Args:
253
+ query_embedding: Query vector embedding
254
+ entity_type: Optional filter by entity type
255
+ max_results: Maximum number of results
256
+ score_threshold: Minimum similarity score (0.0-1.0)
257
+
258
+ Returns:
259
+ List of (entity, score) tuples, sorted by score descending
260
+ """
261
+ return await self._default_vector_search(
262
+ query_embedding, entity_type, max_results, score_threshold
263
+ )
264
+
265
+ async def text_search(
266
+ self,
267
+ query_text: str,
268
+ entity_type: Optional[str] = None,
269
+ max_results: int = 10,
270
+ score_threshold: float = 0.0,
271
+ method: str = "bm25",
272
+ ) -> List[tuple[Entity, float]]:
273
+ """
274
+ Text-based search over entities using text similarity
275
+
276
+ **DEFAULT IMPLEMENTATION**: Uses text similarity utilities (BM25, Jaccard, etc.).
277
+ Override for better performance (e.g., full-text search indexes).
278
+
279
+ Args:
280
+ query_text: Query text string
281
+ entity_type: Optional filter by entity type
282
+ max_results: Maximum number of results
283
+ score_threshold: Minimum similarity score (0.0-1.0)
284
+ method: Similarity method ("bm25", "jaccard", "cosine", "levenshtein")
285
+
286
+ Returns:
287
+ List of (entity, score) tuples, sorted by score descending
288
+ """
289
+ return await self._default_text_search(
290
+ query_text, entity_type, max_results, score_threshold, method
291
+ )
292
+
293
+ async def execute_query(self, query: GraphQuery) -> GraphResult:
294
+ """
295
+ Execute a graph query
296
+
297
+ **DEFAULT IMPLEMENTATION**: Routes to appropriate methods based on query type.
298
+ Override for custom query execution logic.
299
+
300
+ Args:
301
+ query: Graph query to execute
302
+
303
+ Returns:
304
+ Query results
305
+ """
306
+ return await self._default_execute_query(query)
307
+
308
+ # =========================================================================
309
+ # DEFAULT IMPLEMENTATIONS (Template Methods)
310
+ # =========================================================================
311
+
312
+ async def _default_traverse_bfs(
313
+ self,
314
+ start_entity_id: str,
315
+ relation_type: Optional[str],
316
+ max_depth: int,
317
+ max_results: int,
318
+ ) -> List[Path]:
319
+ """
320
+ Default BFS traversal implementation using get_neighbors()
321
+
322
+ This provides a working traversal that any Tier 1 implementation gets for free.
323
+ Backends can override traverse() with optimized versions.
324
+ """
325
+ start_entity = await self.get_entity(start_entity_id)
326
+ if start_entity is None:
327
+ return []
328
+
329
+ paths: List[Path] = []
330
+ visited: Set[str] = set()
331
+ queue: deque = deque([(start_entity, [])]) # (entity, edges_path)
332
+
333
+ while queue and len(paths) < max_results:
334
+ current_entity, edges_path = queue.popleft()
335
+ current_depth = len(edges_path)
336
+
337
+ if current_entity.id in visited:
338
+ continue
339
+ visited.add(current_entity.id)
340
+
341
+ # Create path for this node
342
+ if current_depth > 0: # Don't add single-node paths
343
+ nodes_path = [start_entity]
344
+ for edge in edges_path:
345
+ target_entity = await self.get_entity(edge.target_id)
346
+ if target_entity:
347
+ nodes_path.append(target_entity)
348
+
349
+ if len(nodes_path) == len(edges_path) + 1:
350
+ paths.append(Path(nodes=nodes_path, edges=edges_path))
351
+
352
+ # Explore neighbors if not at max depth
353
+ if current_depth < max_depth:
354
+ neighbors = await self.get_neighbors(
355
+ current_entity.id,
356
+ relation_type=relation_type,
357
+ direction="outgoing",
358
+ )
359
+
360
+ for neighbor in neighbors:
361
+ if neighbor.id not in visited:
362
+ # Find the relation connecting them
363
+ # (In a real implementation, get_neighbors should return relations too)
364
+ # For now, create a placeholder relation
365
+ edge = Relation(
366
+ id=f"rel_{current_entity.id}_{neighbor.id}",
367
+ relation_type=relation_type or "CONNECTED_TO",
368
+ source_id=current_entity.id,
369
+ target_id=neighbor.id,
370
+ )
371
+ queue.append((neighbor, edges_path + [edge]))
372
+
373
+ return paths
374
+
375
+ async def _default_find_paths(
376
+ self,
377
+ source_entity_id: str,
378
+ target_entity_id: str,
379
+ max_depth: int,
380
+ max_paths: int,
381
+ ) -> List[Path]:
382
+ """
383
+ Default path finding using BFS with target check
384
+ """
385
+ all_paths = await self.traverse(
386
+ source_entity_id,
387
+ max_depth=max_depth,
388
+ max_results=max_paths * 10, # Get more, filter later
389
+ )
390
+
391
+ # Filter paths that end at target
392
+ target_paths = [path for path in all_paths if path.end_entity.id == target_entity_id]
393
+
394
+ return target_paths[:max_paths]
395
+
396
+ async def _default_subgraph_query(
397
+ self, entity_ids: List[str], include_relations: bool
398
+ ) -> tuple[List[Entity], List[Relation]]:
399
+ """
400
+ Default subgraph extraction
401
+ """
402
+ entities = []
403
+ relations = []
404
+
405
+ # Fetch all entities
406
+ for entity_id in entity_ids:
407
+ entity = await self.get_entity(entity_id)
408
+ if entity:
409
+ entities.append(entity)
410
+
411
+ # Fetch relations between entities (if requested)
412
+ if include_relations:
413
+ entity_id_set = set(entity_ids)
414
+ for entity_id in entity_ids:
415
+ neighbors = await self.get_neighbors(entity_id, direction="outgoing")
416
+ for neighbor in neighbors:
417
+ if neighbor.id in entity_id_set:
418
+ # Fetch the relation (simplified - needs proper
419
+ # implementation)
420
+ rel = Relation(
421
+ id=f"rel_{entity_id}_{neighbor.id}",
422
+ relation_type="CONNECTED_TO",
423
+ source_id=entity_id,
424
+ target_id=neighbor.id,
425
+ )
426
+ relations.append(rel)
427
+
428
+ return entities, relations
429
+
430
+ async def _default_vector_search(
431
+ self,
432
+ query_embedding: List[float],
433
+ entity_type: Optional[str],
434
+ max_results: int,
435
+ score_threshold: float,
436
+ ) -> List[tuple[Entity, float]]:
437
+ """
438
+ Default brute-force vector search using cosine similarity
439
+
440
+ This is slow but works. Backends should override with ANN indexes.
441
+ """
442
+ # Note: This requires iterating all entities - needs proper implementation
443
+ # In a real store, you'd have a method to get all entities or use an index
444
+ # For now, return empty results
445
+ # TODO: Implement when we have entity enumeration capability
446
+ return []
447
+
448
+ async def _default_text_search(
449
+ self,
450
+ query_text: str,
451
+ entity_type: Optional[str],
452
+ max_results: int,
453
+ score_threshold: float,
454
+ method: str,
455
+ ) -> List[tuple[Entity, float]]:
456
+ """
457
+ Default text search using text similarity utilities
458
+
459
+ This implementation requires get_all_entities() or similar method.
460
+ Backends should override for better performance (e.g., full-text indexes).
461
+ """
462
+ # Try to get all entities - check if store has get_all_entities method
463
+ if hasattr(self, "get_all_entities"):
464
+ entities = await self.get_all_entities(entity_type=entity_type)
465
+ else:
466
+ # Fallback: return empty if no way to enumerate entities
467
+ return []
468
+
469
+ if not query_text:
470
+ return []
471
+
472
+ from aiecs.application.knowledge_graph.search.text_similarity import (
473
+ BM25Scorer,
474
+ jaccard_similarity_text,
475
+ cosine_similarity_text,
476
+ normalized_levenshtein_similarity,
477
+ )
478
+
479
+ scored_entities = []
480
+
481
+ # Extract text from entities (combine properties into searchable text)
482
+ entity_texts = []
483
+ for entity in entities:
484
+ # Combine all string properties into searchable text
485
+ text_parts = []
486
+ for key, value in entity.properties.items():
487
+ if isinstance(value, str):
488
+ text_parts.append(value)
489
+ elif isinstance(value, (list, tuple)):
490
+ text_parts.extend(str(v) for v in value if isinstance(v, str))
491
+ entity_text = " ".join(text_parts)
492
+ entity_texts.append((entity, entity_text))
493
+
494
+ if method == "bm25":
495
+ # Use BM25 scorer
496
+ corpus = [text for _, text in entity_texts]
497
+ scorer = BM25Scorer(corpus)
498
+ scores = scorer.score(query_text)
499
+
500
+ for (entity, _), score in zip(entity_texts, scores):
501
+ if score >= score_threshold:
502
+ scored_entities.append((entity, float(score)))
503
+
504
+ elif method == "jaccard":
505
+ for entity, text in entity_texts:
506
+ score = jaccard_similarity_text(query_text, text)
507
+ if score >= score_threshold:
508
+ scored_entities.append((entity, score))
509
+
510
+ elif method == "cosine":
511
+ for entity, text in entity_texts:
512
+ score = cosine_similarity_text(query_text, text)
513
+ if score >= score_threshold:
514
+ scored_entities.append((entity, score))
515
+
516
+ elif method == "levenshtein":
517
+ for entity, text in entity_texts:
518
+ score = normalized_levenshtein_similarity(query_text, text)
519
+ if score >= score_threshold:
520
+ scored_entities.append((entity, score))
521
+
522
+ else:
523
+ raise ValueError(
524
+ f"Unknown text search method: {method}. Use 'bm25', 'jaccard', 'cosine', or 'levenshtein'"
525
+ )
526
+
527
+ # Sort by score descending and return top results
528
+ scored_entities.sort(key=lambda x: x[1], reverse=True)
529
+ return scored_entities[:max_results]
530
+
531
+ async def _default_execute_query(self, query: GraphQuery) -> GraphResult:
532
+ """
533
+ Default query execution router
534
+ """
535
+ import time
536
+
537
+ start_time = time.time()
538
+
539
+ if query.query_type == QueryType.ENTITY_LOOKUP:
540
+ entity = await self.get_entity(query.entity_id) if query.entity_id else None
541
+ entities = [entity] if entity else []
542
+
543
+ elif query.query_type == QueryType.VECTOR_SEARCH:
544
+ if query.embedding:
545
+ results = await self.vector_search(
546
+ query.embedding,
547
+ query.entity_type,
548
+ query.max_results,
549
+ query.score_threshold,
550
+ )
551
+ entities = [entity for entity, score in results]
552
+ else:
553
+ entities = []
554
+
555
+ elif query.query_type == QueryType.TRAVERSAL:
556
+ if query.entity_id:
557
+ paths = await self.traverse(
558
+ query.entity_id,
559
+ query.relation_type,
560
+ query.max_depth,
561
+ query.max_results,
562
+ )
563
+ # Extract unique entities from paths
564
+ entity_ids_seen = set()
565
+ entities = []
566
+ for path in paths:
567
+ for entity in path.nodes:
568
+ if entity.id not in entity_ids_seen:
569
+ entities.append(entity)
570
+ entity_ids_seen.add(entity.id)
571
+ else:
572
+ entities = []
573
+ paths = []
574
+
575
+ elif query.query_type == QueryType.PATH_FINDING:
576
+ if query.source_entity_id and query.target_entity_id:
577
+ paths = await self.find_paths(
578
+ query.source_entity_id,
579
+ query.target_entity_id,
580
+ query.max_depth,
581
+ query.max_results,
582
+ )
583
+ entities = []
584
+ else:
585
+ paths = []
586
+ entities = []
587
+
588
+ else:
589
+ entities = []
590
+ paths = []
591
+
592
+ execution_time_ms = (time.time() - start_time) * 1000
593
+
594
+ return GraphResult(
595
+ query=query,
596
+ entities=entities[: query.max_results],
597
+ paths=paths[: query.max_results] if "paths" in locals() else [],
598
+ scores=[],
599
+ total_count=len(entities),
600
+ execution_time_ms=execution_time_ms,
601
+ )