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.
- aiecs/__init__.py +72 -0
- aiecs/__main__.py +41 -0
- aiecs/aiecs_client.py +469 -0
- aiecs/application/__init__.py +10 -0
- aiecs/application/executors/__init__.py +10 -0
- aiecs/application/executors/operation_executor.py +363 -0
- aiecs/application/knowledge_graph/__init__.py +7 -0
- aiecs/application/knowledge_graph/builder/__init__.py +37 -0
- aiecs/application/knowledge_graph/builder/document_builder.py +375 -0
- aiecs/application/knowledge_graph/builder/graph_builder.py +356 -0
- aiecs/application/knowledge_graph/builder/schema_mapping.py +531 -0
- aiecs/application/knowledge_graph/builder/structured_pipeline.py +443 -0
- aiecs/application/knowledge_graph/builder/text_chunker.py +319 -0
- aiecs/application/knowledge_graph/extractors/__init__.py +27 -0
- aiecs/application/knowledge_graph/extractors/base.py +100 -0
- aiecs/application/knowledge_graph/extractors/llm_entity_extractor.py +327 -0
- aiecs/application/knowledge_graph/extractors/llm_relation_extractor.py +349 -0
- aiecs/application/knowledge_graph/extractors/ner_entity_extractor.py +244 -0
- aiecs/application/knowledge_graph/fusion/__init__.py +23 -0
- aiecs/application/knowledge_graph/fusion/entity_deduplicator.py +387 -0
- aiecs/application/knowledge_graph/fusion/entity_linker.py +343 -0
- aiecs/application/knowledge_graph/fusion/knowledge_fusion.py +580 -0
- aiecs/application/knowledge_graph/fusion/relation_deduplicator.py +189 -0
- aiecs/application/knowledge_graph/pattern_matching/__init__.py +21 -0
- aiecs/application/knowledge_graph/pattern_matching/pattern_matcher.py +344 -0
- aiecs/application/knowledge_graph/pattern_matching/query_executor.py +378 -0
- aiecs/application/knowledge_graph/profiling/__init__.py +12 -0
- aiecs/application/knowledge_graph/profiling/query_plan_visualizer.py +199 -0
- aiecs/application/knowledge_graph/profiling/query_profiler.py +223 -0
- aiecs/application/knowledge_graph/reasoning/__init__.py +27 -0
- aiecs/application/knowledge_graph/reasoning/evidence_synthesis.py +347 -0
- aiecs/application/knowledge_graph/reasoning/inference_engine.py +504 -0
- aiecs/application/knowledge_graph/reasoning/logic_form_parser.py +167 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/__init__.py +79 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_builder.py +513 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_nodes.py +630 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/ast_validator.py +654 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/error_handler.py +477 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/parser.py +390 -0
- aiecs/application/knowledge_graph/reasoning/logic_parser/query_context.py +217 -0
- aiecs/application/knowledge_graph/reasoning/logic_query_integration.py +169 -0
- aiecs/application/knowledge_graph/reasoning/query_planner.py +872 -0
- aiecs/application/knowledge_graph/reasoning/reasoning_engine.py +554 -0
- aiecs/application/knowledge_graph/retrieval/__init__.py +19 -0
- aiecs/application/knowledge_graph/retrieval/retrieval_strategies.py +596 -0
- aiecs/application/knowledge_graph/search/__init__.py +59 -0
- aiecs/application/knowledge_graph/search/hybrid_search.py +423 -0
- aiecs/application/knowledge_graph/search/reranker.py +295 -0
- aiecs/application/knowledge_graph/search/reranker_strategies.py +553 -0
- aiecs/application/knowledge_graph/search/text_similarity.py +398 -0
- aiecs/application/knowledge_graph/traversal/__init__.py +15 -0
- aiecs/application/knowledge_graph/traversal/enhanced_traversal.py +329 -0
- aiecs/application/knowledge_graph/traversal/path_scorer.py +269 -0
- aiecs/application/knowledge_graph/validators/__init__.py +13 -0
- aiecs/application/knowledge_graph/validators/relation_validator.py +189 -0
- aiecs/application/knowledge_graph/visualization/__init__.py +11 -0
- aiecs/application/knowledge_graph/visualization/graph_visualizer.py +321 -0
- aiecs/common/__init__.py +9 -0
- aiecs/common/knowledge_graph/__init__.py +17 -0
- aiecs/common/knowledge_graph/runnable.py +484 -0
- aiecs/config/__init__.py +16 -0
- aiecs/config/config.py +498 -0
- aiecs/config/graph_config.py +137 -0
- aiecs/config/registry.py +23 -0
- aiecs/core/__init__.py +46 -0
- aiecs/core/interface/__init__.py +34 -0
- aiecs/core/interface/execution_interface.py +152 -0
- aiecs/core/interface/storage_interface.py +171 -0
- aiecs/domain/__init__.py +289 -0
- aiecs/domain/agent/__init__.py +189 -0
- aiecs/domain/agent/base_agent.py +697 -0
- aiecs/domain/agent/exceptions.py +103 -0
- aiecs/domain/agent/graph_aware_mixin.py +559 -0
- aiecs/domain/agent/hybrid_agent.py +490 -0
- aiecs/domain/agent/integration/__init__.py +26 -0
- aiecs/domain/agent/integration/context_compressor.py +222 -0
- aiecs/domain/agent/integration/context_engine_adapter.py +252 -0
- aiecs/domain/agent/integration/retry_policy.py +219 -0
- aiecs/domain/agent/integration/role_config.py +213 -0
- aiecs/domain/agent/knowledge_aware_agent.py +646 -0
- aiecs/domain/agent/lifecycle.py +296 -0
- aiecs/domain/agent/llm_agent.py +300 -0
- aiecs/domain/agent/memory/__init__.py +12 -0
- aiecs/domain/agent/memory/conversation.py +197 -0
- aiecs/domain/agent/migration/__init__.py +14 -0
- aiecs/domain/agent/migration/conversion.py +160 -0
- aiecs/domain/agent/migration/legacy_wrapper.py +90 -0
- aiecs/domain/agent/models.py +317 -0
- aiecs/domain/agent/observability.py +407 -0
- aiecs/domain/agent/persistence.py +289 -0
- aiecs/domain/agent/prompts/__init__.py +29 -0
- aiecs/domain/agent/prompts/builder.py +161 -0
- aiecs/domain/agent/prompts/formatters.py +189 -0
- aiecs/domain/agent/prompts/template.py +255 -0
- aiecs/domain/agent/registry.py +260 -0
- aiecs/domain/agent/tool_agent.py +257 -0
- aiecs/domain/agent/tools/__init__.py +12 -0
- aiecs/domain/agent/tools/schema_generator.py +221 -0
- aiecs/domain/community/__init__.py +155 -0
- aiecs/domain/community/agent_adapter.py +477 -0
- aiecs/domain/community/analytics.py +481 -0
- aiecs/domain/community/collaborative_workflow.py +642 -0
- aiecs/domain/community/communication_hub.py +645 -0
- aiecs/domain/community/community_builder.py +320 -0
- aiecs/domain/community/community_integration.py +800 -0
- aiecs/domain/community/community_manager.py +813 -0
- aiecs/domain/community/decision_engine.py +879 -0
- aiecs/domain/community/exceptions.py +225 -0
- aiecs/domain/community/models/__init__.py +33 -0
- aiecs/domain/community/models/community_models.py +268 -0
- aiecs/domain/community/resource_manager.py +457 -0
- aiecs/domain/community/shared_context_manager.py +603 -0
- aiecs/domain/context/__init__.py +58 -0
- aiecs/domain/context/context_engine.py +989 -0
- aiecs/domain/context/conversation_models.py +354 -0
- aiecs/domain/context/graph_memory.py +467 -0
- aiecs/domain/execution/__init__.py +12 -0
- aiecs/domain/execution/model.py +57 -0
- aiecs/domain/knowledge_graph/__init__.py +19 -0
- aiecs/domain/knowledge_graph/models/__init__.py +52 -0
- aiecs/domain/knowledge_graph/models/entity.py +130 -0
- aiecs/domain/knowledge_graph/models/evidence.py +194 -0
- aiecs/domain/knowledge_graph/models/inference_rule.py +186 -0
- aiecs/domain/knowledge_graph/models/path.py +179 -0
- aiecs/domain/knowledge_graph/models/path_pattern.py +173 -0
- aiecs/domain/knowledge_graph/models/query.py +272 -0
- aiecs/domain/knowledge_graph/models/query_plan.py +187 -0
- aiecs/domain/knowledge_graph/models/relation.py +136 -0
- aiecs/domain/knowledge_graph/schema/__init__.py +23 -0
- aiecs/domain/knowledge_graph/schema/entity_type.py +135 -0
- aiecs/domain/knowledge_graph/schema/graph_schema.py +271 -0
- aiecs/domain/knowledge_graph/schema/property_schema.py +155 -0
- aiecs/domain/knowledge_graph/schema/relation_type.py +171 -0
- aiecs/domain/knowledge_graph/schema/schema_manager.py +496 -0
- aiecs/domain/knowledge_graph/schema/type_enums.py +205 -0
- aiecs/domain/task/__init__.py +13 -0
- aiecs/domain/task/dsl_processor.py +613 -0
- aiecs/domain/task/model.py +62 -0
- aiecs/domain/task/task_context.py +268 -0
- aiecs/infrastructure/__init__.py +24 -0
- aiecs/infrastructure/graph_storage/__init__.py +11 -0
- aiecs/infrastructure/graph_storage/base.py +601 -0
- aiecs/infrastructure/graph_storage/batch_operations.py +449 -0
- aiecs/infrastructure/graph_storage/cache.py +429 -0
- aiecs/infrastructure/graph_storage/distributed.py +226 -0
- aiecs/infrastructure/graph_storage/error_handling.py +390 -0
- aiecs/infrastructure/graph_storage/graceful_degradation.py +306 -0
- aiecs/infrastructure/graph_storage/health_checks.py +378 -0
- aiecs/infrastructure/graph_storage/in_memory.py +514 -0
- aiecs/infrastructure/graph_storage/index_optimization.py +483 -0
- aiecs/infrastructure/graph_storage/lazy_loading.py +410 -0
- aiecs/infrastructure/graph_storage/metrics.py +357 -0
- aiecs/infrastructure/graph_storage/migration.py +413 -0
- aiecs/infrastructure/graph_storage/pagination.py +471 -0
- aiecs/infrastructure/graph_storage/performance_monitoring.py +466 -0
- aiecs/infrastructure/graph_storage/postgres.py +871 -0
- aiecs/infrastructure/graph_storage/query_optimizer.py +635 -0
- aiecs/infrastructure/graph_storage/schema_cache.py +290 -0
- aiecs/infrastructure/graph_storage/sqlite.py +623 -0
- aiecs/infrastructure/graph_storage/streaming.py +495 -0
- aiecs/infrastructure/messaging/__init__.py +13 -0
- aiecs/infrastructure/messaging/celery_task_manager.py +383 -0
- aiecs/infrastructure/messaging/websocket_manager.py +298 -0
- aiecs/infrastructure/monitoring/__init__.py +34 -0
- aiecs/infrastructure/monitoring/executor_metrics.py +174 -0
- aiecs/infrastructure/monitoring/global_metrics_manager.py +213 -0
- aiecs/infrastructure/monitoring/structured_logger.py +48 -0
- aiecs/infrastructure/monitoring/tracing_manager.py +410 -0
- aiecs/infrastructure/persistence/__init__.py +24 -0
- aiecs/infrastructure/persistence/context_engine_client.py +187 -0
- aiecs/infrastructure/persistence/database_manager.py +333 -0
- aiecs/infrastructure/persistence/file_storage.py +754 -0
- aiecs/infrastructure/persistence/redis_client.py +220 -0
- aiecs/llm/__init__.py +86 -0
- aiecs/llm/callbacks/__init__.py +11 -0
- aiecs/llm/callbacks/custom_callbacks.py +264 -0
- aiecs/llm/client_factory.py +420 -0
- aiecs/llm/clients/__init__.py +33 -0
- aiecs/llm/clients/base_client.py +193 -0
- aiecs/llm/clients/googleai_client.py +181 -0
- aiecs/llm/clients/openai_client.py +131 -0
- aiecs/llm/clients/vertex_client.py +437 -0
- aiecs/llm/clients/xai_client.py +184 -0
- aiecs/llm/config/__init__.py +51 -0
- aiecs/llm/config/config_loader.py +275 -0
- aiecs/llm/config/config_validator.py +236 -0
- aiecs/llm/config/model_config.py +151 -0
- aiecs/llm/utils/__init__.py +10 -0
- aiecs/llm/utils/validate_config.py +91 -0
- aiecs/main.py +363 -0
- aiecs/scripts/__init__.py +3 -0
- aiecs/scripts/aid/VERSION_MANAGEMENT.md +97 -0
- aiecs/scripts/aid/__init__.py +19 -0
- aiecs/scripts/aid/version_manager.py +215 -0
- aiecs/scripts/dependance_check/DEPENDENCY_SYSTEM_SUMMARY.md +242 -0
- aiecs/scripts/dependance_check/README_DEPENDENCY_CHECKER.md +310 -0
- aiecs/scripts/dependance_check/__init__.py +17 -0
- aiecs/scripts/dependance_check/dependency_checker.py +938 -0
- aiecs/scripts/dependance_check/dependency_fixer.py +391 -0
- aiecs/scripts/dependance_check/download_nlp_data.py +396 -0
- aiecs/scripts/dependance_check/quick_dependency_check.py +270 -0
- aiecs/scripts/dependance_check/setup_nlp_data.sh +217 -0
- aiecs/scripts/dependance_patch/__init__.py +7 -0
- aiecs/scripts/dependance_patch/fix_weasel/README_WEASEL_PATCH.md +126 -0
- aiecs/scripts/dependance_patch/fix_weasel/__init__.py +11 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.py +128 -0
- aiecs/scripts/dependance_patch/fix_weasel/fix_weasel_validator.sh +82 -0
- aiecs/scripts/dependance_patch/fix_weasel/patch_weasel_library.sh +188 -0
- aiecs/scripts/dependance_patch/fix_weasel/run_weasel_patch.sh +41 -0
- aiecs/scripts/tools_develop/README.md +449 -0
- aiecs/scripts/tools_develop/TOOL_AUTO_DISCOVERY.md +234 -0
- aiecs/scripts/tools_develop/__init__.py +21 -0
- aiecs/scripts/tools_develop/check_type_annotations.py +259 -0
- aiecs/scripts/tools_develop/validate_tool_schemas.py +422 -0
- aiecs/scripts/tools_develop/verify_tools.py +356 -0
- aiecs/tasks/__init__.py +1 -0
- aiecs/tasks/worker.py +172 -0
- aiecs/tools/__init__.py +299 -0
- aiecs/tools/apisource/__init__.py +99 -0
- aiecs/tools/apisource/intelligence/__init__.py +19 -0
- aiecs/tools/apisource/intelligence/data_fusion.py +381 -0
- aiecs/tools/apisource/intelligence/query_analyzer.py +413 -0
- aiecs/tools/apisource/intelligence/search_enhancer.py +388 -0
- aiecs/tools/apisource/monitoring/__init__.py +9 -0
- aiecs/tools/apisource/monitoring/metrics.py +303 -0
- aiecs/tools/apisource/providers/__init__.py +115 -0
- aiecs/tools/apisource/providers/base.py +664 -0
- aiecs/tools/apisource/providers/census.py +401 -0
- aiecs/tools/apisource/providers/fred.py +564 -0
- aiecs/tools/apisource/providers/newsapi.py +412 -0
- aiecs/tools/apisource/providers/worldbank.py +357 -0
- aiecs/tools/apisource/reliability/__init__.py +12 -0
- aiecs/tools/apisource/reliability/error_handler.py +375 -0
- aiecs/tools/apisource/reliability/fallback_strategy.py +391 -0
- aiecs/tools/apisource/tool.py +850 -0
- aiecs/tools/apisource/utils/__init__.py +9 -0
- aiecs/tools/apisource/utils/validators.py +338 -0
- aiecs/tools/base_tool.py +201 -0
- aiecs/tools/docs/__init__.py +121 -0
- aiecs/tools/docs/ai_document_orchestrator.py +599 -0
- aiecs/tools/docs/ai_document_writer_orchestrator.py +2403 -0
- aiecs/tools/docs/content_insertion_tool.py +1333 -0
- aiecs/tools/docs/document_creator_tool.py +1317 -0
- aiecs/tools/docs/document_layout_tool.py +1166 -0
- aiecs/tools/docs/document_parser_tool.py +994 -0
- aiecs/tools/docs/document_writer_tool.py +1818 -0
- aiecs/tools/knowledge_graph/__init__.py +17 -0
- aiecs/tools/knowledge_graph/graph_reasoning_tool.py +734 -0
- aiecs/tools/knowledge_graph/graph_search_tool.py +923 -0
- aiecs/tools/knowledge_graph/kg_builder_tool.py +476 -0
- aiecs/tools/langchain_adapter.py +542 -0
- aiecs/tools/schema_generator.py +275 -0
- aiecs/tools/search_tool/__init__.py +100 -0
- aiecs/tools/search_tool/analyzers.py +589 -0
- aiecs/tools/search_tool/cache.py +260 -0
- aiecs/tools/search_tool/constants.py +128 -0
- aiecs/tools/search_tool/context.py +216 -0
- aiecs/tools/search_tool/core.py +749 -0
- aiecs/tools/search_tool/deduplicator.py +123 -0
- aiecs/tools/search_tool/error_handler.py +271 -0
- aiecs/tools/search_tool/metrics.py +371 -0
- aiecs/tools/search_tool/rate_limiter.py +178 -0
- aiecs/tools/search_tool/schemas.py +277 -0
- aiecs/tools/statistics/__init__.py +80 -0
- aiecs/tools/statistics/ai_data_analysis_orchestrator.py +643 -0
- aiecs/tools/statistics/ai_insight_generator_tool.py +505 -0
- aiecs/tools/statistics/ai_report_orchestrator_tool.py +694 -0
- aiecs/tools/statistics/data_loader_tool.py +564 -0
- aiecs/tools/statistics/data_profiler_tool.py +658 -0
- aiecs/tools/statistics/data_transformer_tool.py +573 -0
- aiecs/tools/statistics/data_visualizer_tool.py +495 -0
- aiecs/tools/statistics/model_trainer_tool.py +487 -0
- aiecs/tools/statistics/statistical_analyzer_tool.py +459 -0
- aiecs/tools/task_tools/__init__.py +86 -0
- aiecs/tools/task_tools/chart_tool.py +732 -0
- aiecs/tools/task_tools/classfire_tool.py +922 -0
- aiecs/tools/task_tools/image_tool.py +447 -0
- aiecs/tools/task_tools/office_tool.py +684 -0
- aiecs/tools/task_tools/pandas_tool.py +635 -0
- aiecs/tools/task_tools/report_tool.py +635 -0
- aiecs/tools/task_tools/research_tool.py +392 -0
- aiecs/tools/task_tools/scraper_tool.py +715 -0
- aiecs/tools/task_tools/stats_tool.py +688 -0
- aiecs/tools/temp_file_manager.py +130 -0
- aiecs/tools/tool_executor/__init__.py +37 -0
- aiecs/tools/tool_executor/tool_executor.py +881 -0
- aiecs/utils/LLM_output_structor.py +445 -0
- aiecs/utils/__init__.py +34 -0
- aiecs/utils/base_callback.py +47 -0
- aiecs/utils/cache_provider.py +695 -0
- aiecs/utils/execution_utils.py +184 -0
- aiecs/utils/logging.py +1 -0
- aiecs/utils/prompt_loader.py +14 -0
- aiecs/utils/token_usage_repository.py +323 -0
- aiecs/ws/__init__.py +0 -0
- aiecs/ws/socket_server.py +52 -0
- aiecs-1.5.1.dist-info/METADATA +608 -0
- aiecs-1.5.1.dist-info/RECORD +302 -0
- aiecs-1.5.1.dist-info/WHEEL +5 -0
- aiecs-1.5.1.dist-info/entry_points.txt +10 -0
- aiecs-1.5.1.dist-info/licenses/LICENSE +225 -0
- aiecs-1.5.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
PathPattern Domain Model
|
|
3
|
+
|
|
4
|
+
Represents a pattern for graph traversal specifications.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import List, Optional, Set
|
|
8
|
+
from pydantic import BaseModel, Field
|
|
9
|
+
from enum import Enum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class TraversalDirection(str, Enum):
|
|
13
|
+
"""Direction for graph traversal"""
|
|
14
|
+
|
|
15
|
+
OUTGOING = "outgoing"
|
|
16
|
+
INCOMING = "incoming"
|
|
17
|
+
BOTH = "both"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class PathPattern(BaseModel):
|
|
21
|
+
"""
|
|
22
|
+
Path Pattern for Graph Traversal
|
|
23
|
+
|
|
24
|
+
Specifies constraints and preferences for graph traversal operations.
|
|
25
|
+
Used to control how the graph is explored and which paths are valid.
|
|
26
|
+
|
|
27
|
+
Attributes:
|
|
28
|
+
relation_types: Optional list of allowed relation types
|
|
29
|
+
entity_types: Optional list of allowed entity types
|
|
30
|
+
direction: Traversal direction (outgoing, incoming, both)
|
|
31
|
+
max_depth: Maximum path length
|
|
32
|
+
allow_cycles: Whether to allow revisiting nodes
|
|
33
|
+
required_relation_sequence: Optional sequence of relation types that must be followed
|
|
34
|
+
|
|
35
|
+
Example:
|
|
36
|
+
```python
|
|
37
|
+
# Find paths following WORKS_FOR -> LOCATED_IN pattern
|
|
38
|
+
pattern = PathPattern(
|
|
39
|
+
relation_types=["WORKS_FOR", "LOCATED_IN"],
|
|
40
|
+
required_relation_sequence=["WORKS_FOR", "LOCATED_IN"],
|
|
41
|
+
max_depth=2,
|
|
42
|
+
allow_cycles=False
|
|
43
|
+
)
|
|
44
|
+
```
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
relation_types: Optional[List[str]] = Field(
|
|
48
|
+
default=None,
|
|
49
|
+
description="Optional list of allowed relation types (None = all types allowed)",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
entity_types: Optional[List[str]] = Field(
|
|
53
|
+
default=None,
|
|
54
|
+
description="Optional list of allowed entity types (None = all types allowed)",
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
direction: TraversalDirection = Field(
|
|
58
|
+
default=TraversalDirection.OUTGOING,
|
|
59
|
+
description="Direction for traversal",
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
max_depth: int = Field(
|
|
63
|
+
default=3,
|
|
64
|
+
ge=1,
|
|
65
|
+
le=10,
|
|
66
|
+
description="Maximum path length (number of hops)",
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
allow_cycles: bool = Field(
|
|
70
|
+
default=False, description="Whether to allow revisiting nodes (cycles)"
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
required_relation_sequence: Optional[List[str]] = Field(
|
|
74
|
+
default=None,
|
|
75
|
+
description="Optional sequence of relation types that must be followed in order",
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
min_path_length: int = Field(default=1, ge=1, description="Minimum path length to return")
|
|
79
|
+
|
|
80
|
+
excluded_entity_ids: Set[str] = Field(
|
|
81
|
+
default_factory=set,
|
|
82
|
+
description="Set of entity IDs to exclude from traversal",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
def is_relation_allowed(self, relation_type: str, depth: int = 0) -> bool:
|
|
86
|
+
"""
|
|
87
|
+
Check if a relation type is allowed at the current depth
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
relation_type: Relation type to check
|
|
91
|
+
depth: Current depth in the traversal (0-indexed)
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
True if the relation is allowed
|
|
95
|
+
"""
|
|
96
|
+
# Check required sequence if specified
|
|
97
|
+
if self.required_relation_sequence:
|
|
98
|
+
if depth >= len(self.required_relation_sequence):
|
|
99
|
+
return False
|
|
100
|
+
return relation_type == self.required_relation_sequence[depth]
|
|
101
|
+
|
|
102
|
+
# Check allowed types if specified
|
|
103
|
+
if self.relation_types:
|
|
104
|
+
return relation_type in self.relation_types
|
|
105
|
+
|
|
106
|
+
# All types allowed if no constraints
|
|
107
|
+
return True
|
|
108
|
+
|
|
109
|
+
def is_entity_allowed(self, entity_id: str, entity_type: str) -> bool:
|
|
110
|
+
"""
|
|
111
|
+
Check if an entity is allowed in the path
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
entity_id: Entity ID to check
|
|
115
|
+
entity_type: Entity type to check
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
True if the entity is allowed
|
|
119
|
+
"""
|
|
120
|
+
# Check excluded entities
|
|
121
|
+
if entity_id in self.excluded_entity_ids:
|
|
122
|
+
return False
|
|
123
|
+
|
|
124
|
+
# Check allowed types if specified
|
|
125
|
+
if self.entity_types:
|
|
126
|
+
return entity_type in self.entity_types
|
|
127
|
+
|
|
128
|
+
# All entities allowed if no constraints
|
|
129
|
+
return True
|
|
130
|
+
|
|
131
|
+
def is_valid_path_length(self, length: int) -> bool:
|
|
132
|
+
"""
|
|
133
|
+
Check if a path length is valid according to the pattern
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
length: Path length to check
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
True if the length is valid
|
|
140
|
+
"""
|
|
141
|
+
return self.min_path_length <= length <= self.max_depth
|
|
142
|
+
|
|
143
|
+
def should_continue_traversal(self, depth: int) -> bool:
|
|
144
|
+
"""
|
|
145
|
+
Check if traversal should continue at the current depth
|
|
146
|
+
|
|
147
|
+
Args:
|
|
148
|
+
depth: Current depth in the traversal
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
True if traversal should continue
|
|
152
|
+
"""
|
|
153
|
+
return depth < self.max_depth
|
|
154
|
+
|
|
155
|
+
class Config:
|
|
156
|
+
use_enum_values = True
|
|
157
|
+
|
|
158
|
+
def __str__(self) -> str:
|
|
159
|
+
parts = [f"depth={self.max_depth}"]
|
|
160
|
+
|
|
161
|
+
if self.relation_types:
|
|
162
|
+
parts.append(f"relations={','.join(self.relation_types)}")
|
|
163
|
+
|
|
164
|
+
if self.entity_types:
|
|
165
|
+
parts.append(f"entities={','.join(self.entity_types)}")
|
|
166
|
+
|
|
167
|
+
if self.required_relation_sequence:
|
|
168
|
+
parts.append(f"sequence={' -> '.join(self.required_relation_sequence)}")
|
|
169
|
+
|
|
170
|
+
if self.allow_cycles:
|
|
171
|
+
parts.append("allow_cycles")
|
|
172
|
+
|
|
173
|
+
return f"PathPattern({', '.join(parts)})"
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Query Domain Models
|
|
3
|
+
|
|
4
|
+
Models for specifying graph queries and their results.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, List, Optional, Dict
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
from aiecs.domain.knowledge_graph.models.entity import Entity
|
|
11
|
+
from aiecs.domain.knowledge_graph.models.relation import Relation
|
|
12
|
+
from aiecs.domain.knowledge_graph.models.path import Path
|
|
13
|
+
from aiecs.domain.knowledge_graph.models.path_pattern import PathPattern
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class QueryType(str, Enum):
|
|
17
|
+
"""Types of graph queries"""
|
|
18
|
+
|
|
19
|
+
ENTITY_LOOKUP = "entity_lookup"
|
|
20
|
+
VECTOR_SEARCH = "vector_search"
|
|
21
|
+
TRAVERSAL = "traversal"
|
|
22
|
+
PATH_FINDING = "path_finding"
|
|
23
|
+
SUBGRAPH = "subgraph"
|
|
24
|
+
CUSTOM = "custom"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class GraphQuery(BaseModel):
|
|
28
|
+
"""
|
|
29
|
+
Graph Query Specification
|
|
30
|
+
|
|
31
|
+
Specifies a query to execute against the knowledge graph.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
query_type: Type of query to execute
|
|
35
|
+
entity_id: Entity ID for entity lookup queries
|
|
36
|
+
entity_type: Filter by entity type
|
|
37
|
+
relation_type: Filter by relation type
|
|
38
|
+
embedding: Query embedding for vector search
|
|
39
|
+
properties: Property constraints for filtering
|
|
40
|
+
max_results: Maximum number of results to return
|
|
41
|
+
max_depth: Maximum traversal depth for path queries
|
|
42
|
+
score_threshold: Minimum score threshold for results
|
|
43
|
+
|
|
44
|
+
Example:
|
|
45
|
+
```python
|
|
46
|
+
# Vector search query
|
|
47
|
+
query = GraphQuery(
|
|
48
|
+
query_type=QueryType.VECTOR_SEARCH,
|
|
49
|
+
embedding=[0.1, 0.2, ...],
|
|
50
|
+
entity_type="Document",
|
|
51
|
+
max_results=10,
|
|
52
|
+
score_threshold=0.7
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Traversal query
|
|
56
|
+
query = GraphQuery(
|
|
57
|
+
query_type=QueryType.TRAVERSAL,
|
|
58
|
+
entity_id="person_001",
|
|
59
|
+
relation_type="KNOWS",
|
|
60
|
+
max_depth=3
|
|
61
|
+
)
|
|
62
|
+
```
|
|
63
|
+
"""
|
|
64
|
+
|
|
65
|
+
query_type: QueryType = Field(..., description="Type of query to execute")
|
|
66
|
+
|
|
67
|
+
# Entity lookup
|
|
68
|
+
entity_id: Optional[str] = Field(
|
|
69
|
+
default=None, description="Entity ID for entity lookup queries"
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Filtering
|
|
73
|
+
entity_type: Optional[str] = Field(default=None, description="Filter results by entity type")
|
|
74
|
+
|
|
75
|
+
relation_type: Optional[str] = Field(
|
|
76
|
+
default=None, description="Filter by relation type (for traversal)"
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
# Vector search
|
|
80
|
+
embedding: Optional[List[float]] = Field(
|
|
81
|
+
default=None, description="Query embedding for vector search"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Property constraints
|
|
85
|
+
properties: Dict[str, Any] = Field(
|
|
86
|
+
default_factory=dict, description="Property constraints for filtering"
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# Result constraints
|
|
90
|
+
max_results: int = Field(default=10, ge=1, description="Maximum number of results to return")
|
|
91
|
+
|
|
92
|
+
max_depth: int = Field(
|
|
93
|
+
default=3,
|
|
94
|
+
ge=1,
|
|
95
|
+
le=10,
|
|
96
|
+
description="Maximum traversal depth for path queries",
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
score_threshold: float = Field(
|
|
100
|
+
default=0.0,
|
|
101
|
+
ge=0.0,
|
|
102
|
+
le=1.0,
|
|
103
|
+
description="Minimum score threshold for results",
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
# Source/target constraints for path finding
|
|
107
|
+
source_entity_id: Optional[str] = Field(
|
|
108
|
+
default=None, description="Source entity ID for path finding"
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
target_entity_id: Optional[str] = Field(
|
|
112
|
+
default=None, description="Target entity ID for path finding"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Custom query parameters
|
|
116
|
+
custom_params: Dict[str, Any] = Field(
|
|
117
|
+
default_factory=dict, description="Additional custom query parameters"
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
# Custom pattern matching (Task 3.3)
|
|
121
|
+
pattern: Optional[PathPattern] = Field(
|
|
122
|
+
default=None,
|
|
123
|
+
description="Graph pattern for custom pattern matching queries",
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
patterns: Optional[List[PathPattern]] = Field(
|
|
127
|
+
default=None,
|
|
128
|
+
description="Multiple graph patterns for complex pattern matching",
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
optional_patterns: Optional[List[PathPattern]] = Field(
|
|
132
|
+
default=None, description="Optional patterns that may or may not match"
|
|
133
|
+
)
|
|
134
|
+
|
|
135
|
+
projection: Optional[List[str]] = Field(
|
|
136
|
+
default=None,
|
|
137
|
+
description="Fields to project in results (e.g., ['id', 'name', 'properties.age'])",
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
aggregations: Optional[Dict[str, str]] = Field(
|
|
141
|
+
default=None,
|
|
142
|
+
description="Aggregations to apply (e.g., {'count': 'COUNT', 'avg_age': 'AVG(properties.age)'})",
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
group_by: Optional[List[str]] = Field(
|
|
146
|
+
default=None, description="Fields to group by for aggregations"
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
class Config:
|
|
150
|
+
use_enum_values = True
|
|
151
|
+
|
|
152
|
+
def __str__(self) -> str:
|
|
153
|
+
parts = [f"GraphQuery(type={self.query_type})"]
|
|
154
|
+
if self.entity_id:
|
|
155
|
+
parts.append(f"entity_id={self.entity_id}")
|
|
156
|
+
if self.entity_type:
|
|
157
|
+
parts.append(f"entity_type={self.entity_type}")
|
|
158
|
+
if self.relation_type:
|
|
159
|
+
parts.append(f"relation_type={self.relation_type}")
|
|
160
|
+
return " ".join(parts)
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
class GraphResult(BaseModel):
|
|
164
|
+
"""
|
|
165
|
+
Graph Query Result
|
|
166
|
+
|
|
167
|
+
Contains the results of a graph query execution.
|
|
168
|
+
|
|
169
|
+
Attributes:
|
|
170
|
+
query: The original query that was executed
|
|
171
|
+
entities: List of entity results
|
|
172
|
+
relations: List of relation results (for traversal/subgraph queries)
|
|
173
|
+
paths: List of path results (for path-finding queries)
|
|
174
|
+
scores: Scores for each result (parallel to entities)
|
|
175
|
+
total_count: Total number of matching results (before max_results limit)
|
|
176
|
+
execution_time_ms: Query execution time in milliseconds
|
|
177
|
+
|
|
178
|
+
Example:
|
|
179
|
+
```python
|
|
180
|
+
result = GraphResult(
|
|
181
|
+
query=query,
|
|
182
|
+
entities=[entity1, entity2],
|
|
183
|
+
scores=[0.95, 0.87],
|
|
184
|
+
total_count=2,
|
|
185
|
+
execution_time_ms=15.3
|
|
186
|
+
)
|
|
187
|
+
```
|
|
188
|
+
"""
|
|
189
|
+
|
|
190
|
+
query: GraphQuery = Field(..., description="The original query that was executed")
|
|
191
|
+
|
|
192
|
+
entities: List[Entity] = Field(default_factory=list, description="List of entity results")
|
|
193
|
+
|
|
194
|
+
relations: List[Relation] = Field(
|
|
195
|
+
default_factory=list,
|
|
196
|
+
description="List of relation results (for graph queries)",
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
paths: List[Path] = Field(
|
|
200
|
+
default_factory=list,
|
|
201
|
+
description="List of path results (for path-finding)",
|
|
202
|
+
)
|
|
203
|
+
|
|
204
|
+
scores: List[float] = Field(default_factory=list, description="Scores for each entity result")
|
|
205
|
+
|
|
206
|
+
total_count: int = Field(default=0, ge=0, description="Total matching results (before limit)")
|
|
207
|
+
|
|
208
|
+
execution_time_ms: Optional[float] = Field(
|
|
209
|
+
default=None,
|
|
210
|
+
ge=0.0,
|
|
211
|
+
description="Query execution time in milliseconds",
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
class Config:
|
|
215
|
+
arbitrary_types_allowed = True
|
|
216
|
+
|
|
217
|
+
@property
|
|
218
|
+
def has_results(self) -> bool:
|
|
219
|
+
"""Check if result contains any data"""
|
|
220
|
+
return len(self.entities) > 0 or len(self.paths) > 0
|
|
221
|
+
|
|
222
|
+
@property
|
|
223
|
+
def entity_count(self) -> int:
|
|
224
|
+
"""Get number of entities in result"""
|
|
225
|
+
return len(self.entities)
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def path_count(self) -> int:
|
|
229
|
+
"""Get number of paths in result"""
|
|
230
|
+
return len(self.paths)
|
|
231
|
+
|
|
232
|
+
def get_top_entities(self, n: int = 5) -> List[Entity]:
|
|
233
|
+
"""
|
|
234
|
+
Get top N entities by score
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
n: Number of entities to return
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Top N entities
|
|
241
|
+
"""
|
|
242
|
+
if not self.scores:
|
|
243
|
+
return self.entities[:n]
|
|
244
|
+
|
|
245
|
+
# Sort by score (descending)
|
|
246
|
+
scored_entities = list(zip(self.entities, self.scores))
|
|
247
|
+
scored_entities.sort(key=lambda x: x[1], reverse=True)
|
|
248
|
+
return [entity for entity, _ in scored_entities[:n]]
|
|
249
|
+
|
|
250
|
+
def get_entity_ids(self) -> List[str]:
|
|
251
|
+
"""
|
|
252
|
+
Get list of all entity IDs in result
|
|
253
|
+
|
|
254
|
+
Returns:
|
|
255
|
+
List of entity IDs
|
|
256
|
+
"""
|
|
257
|
+
return [entity.id for entity in self.entities]
|
|
258
|
+
|
|
259
|
+
def __str__(self) -> str:
|
|
260
|
+
parts = [f"GraphResult(entities={self.entity_count}, paths={self.path_count})"]
|
|
261
|
+
if self.execution_time_ms:
|
|
262
|
+
parts.append(f"time={self.execution_time_ms:.2f}ms")
|
|
263
|
+
return " ".join(parts)
|
|
264
|
+
|
|
265
|
+
def __repr__(self) -> str:
|
|
266
|
+
return (
|
|
267
|
+
f"GraphResult("
|
|
268
|
+
f"entities={self.entity_count}, "
|
|
269
|
+
f"relations={len(self.relations)}, "
|
|
270
|
+
f"paths={self.path_count}, "
|
|
271
|
+
f"total_count={self.total_count})"
|
|
272
|
+
)
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Query Plan Domain Models
|
|
3
|
+
|
|
4
|
+
Models for query planning, decomposition, and optimization.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from typing import Any, List, Dict, Set
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from pydantic import BaseModel, Field
|
|
10
|
+
from aiecs.domain.knowledge_graph.models.query import GraphQuery
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class QueryOperation(str, Enum):
|
|
14
|
+
"""Types of query operations"""
|
|
15
|
+
|
|
16
|
+
ENTITY_LOOKUP = "entity_lookup"
|
|
17
|
+
VECTOR_SEARCH = "vector_search"
|
|
18
|
+
TRAVERSAL = "traversal"
|
|
19
|
+
FILTER = "filter"
|
|
20
|
+
JOIN = "join"
|
|
21
|
+
AGGREGATE = "aggregate"
|
|
22
|
+
RANK = "rank"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class QueryStep(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
A single step in a query execution plan
|
|
28
|
+
|
|
29
|
+
Represents one operation in a multi-step query plan.
|
|
30
|
+
|
|
31
|
+
Attributes:
|
|
32
|
+
step_id: Unique identifier for this step
|
|
33
|
+
operation: Type of operation to perform
|
|
34
|
+
query: Graph query specification for this step
|
|
35
|
+
depends_on: List of step IDs that must complete before this step
|
|
36
|
+
description: Human-readable description of what this step does
|
|
37
|
+
estimated_cost: Estimated computational cost (0-1, higher = more expensive)
|
|
38
|
+
|
|
39
|
+
Example:
|
|
40
|
+
```python
|
|
41
|
+
step = QueryStep(
|
|
42
|
+
step_id="step_1",
|
|
43
|
+
operation=QueryOperation.VECTOR_SEARCH,
|
|
44
|
+
query=GraphQuery(
|
|
45
|
+
query_type=QueryType.VECTOR_SEARCH,
|
|
46
|
+
embedding=[0.1, 0.2, ...],
|
|
47
|
+
max_results=10
|
|
48
|
+
),
|
|
49
|
+
description="Find semantically similar entities"
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
step_id: str = Field(..., description="Unique identifier for this step")
|
|
55
|
+
|
|
56
|
+
operation: QueryOperation = Field(..., description="Type of operation to perform")
|
|
57
|
+
|
|
58
|
+
query: GraphQuery = Field(..., description="Graph query specification for this step")
|
|
59
|
+
|
|
60
|
+
depends_on: List[str] = Field(
|
|
61
|
+
default_factory=list,
|
|
62
|
+
description="List of step IDs that must complete before this step",
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
description: str = Field(..., description="Human-readable description of what this step does")
|
|
66
|
+
|
|
67
|
+
estimated_cost: float = Field(
|
|
68
|
+
default=0.5,
|
|
69
|
+
ge=0.0,
|
|
70
|
+
le=1.0,
|
|
71
|
+
description="Estimated computational cost (0-1, higher = more expensive)",
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
metadata: Dict[str, Any] = Field(
|
|
75
|
+
default_factory=dict, description="Additional metadata for this step"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class QueryPlan(BaseModel):
|
|
80
|
+
"""
|
|
81
|
+
Query Execution Plan
|
|
82
|
+
|
|
83
|
+
Represents a structured plan for executing a complex query as a series of steps.
|
|
84
|
+
|
|
85
|
+
Attributes:
|
|
86
|
+
plan_id: Unique identifier for this plan
|
|
87
|
+
original_query: The original natural language or complex query
|
|
88
|
+
steps: List of query steps to execute in order
|
|
89
|
+
total_estimated_cost: Total estimated cost of executing this plan
|
|
90
|
+
optimized: Whether this plan has been optimized
|
|
91
|
+
explanation: Human-readable explanation of the plan
|
|
92
|
+
|
|
93
|
+
Example:
|
|
94
|
+
```python
|
|
95
|
+
plan = QueryPlan(
|
|
96
|
+
plan_id="plan_001",
|
|
97
|
+
original_query="Who works at companies that Alice knows people at?",
|
|
98
|
+
steps=[
|
|
99
|
+
QueryStep(step_id="step_1", ...), # Find Alice
|
|
100
|
+
QueryStep(step_id="step_2", ...), # Find people Alice knows
|
|
101
|
+
QueryStep(step_id="step_3", ...) # Find their companies
|
|
102
|
+
],
|
|
103
|
+
explanation="Multi-hop query to find companies through social connections"
|
|
104
|
+
)
|
|
105
|
+
```
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
plan_id: str = Field(..., description="Unique identifier for this plan")
|
|
109
|
+
|
|
110
|
+
original_query: str = Field(..., description="The original natural language or complex query")
|
|
111
|
+
|
|
112
|
+
steps: List[QueryStep] = Field(..., description="List of query steps to execute in order")
|
|
113
|
+
|
|
114
|
+
total_estimated_cost: float = Field(
|
|
115
|
+
default=0.0, description="Total estimated cost of executing this plan"
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
optimized: bool = Field(default=False, description="Whether this plan has been optimized")
|
|
119
|
+
|
|
120
|
+
explanation: str = Field(default="", description="Human-readable explanation of the plan")
|
|
121
|
+
|
|
122
|
+
metadata: Dict[str, Any] = Field(
|
|
123
|
+
default_factory=dict, description="Additional metadata for this plan"
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
def calculate_total_cost(self) -> float:
|
|
127
|
+
"""Calculate total estimated cost from all steps"""
|
|
128
|
+
return sum(step.estimated_cost for step in self.steps)
|
|
129
|
+
|
|
130
|
+
def get_executable_steps(self, completed_step_ids: set[str]) -> List[QueryStep]:
|
|
131
|
+
"""
|
|
132
|
+
Get steps that can be executed given completed steps
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
completed_step_ids: Set of step IDs that have been completed
|
|
136
|
+
|
|
137
|
+
Returns:
|
|
138
|
+
List of steps whose dependencies are all satisfied
|
|
139
|
+
"""
|
|
140
|
+
executable = []
|
|
141
|
+
for step in self.steps:
|
|
142
|
+
if step.step_id in completed_step_ids:
|
|
143
|
+
continue
|
|
144
|
+
if all(dep in completed_step_ids for dep in step.depends_on):
|
|
145
|
+
executable.append(step)
|
|
146
|
+
return executable
|
|
147
|
+
|
|
148
|
+
def get_execution_order(self) -> List[List[str]]:
|
|
149
|
+
"""
|
|
150
|
+
Get optimal execution order for steps
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
List of lists, where each inner list contains step IDs that can run in parallel
|
|
154
|
+
|
|
155
|
+
Example:
|
|
156
|
+
[[step_1], [step_2, step_3], [step_4]]
|
|
157
|
+
- step_1 runs first
|
|
158
|
+
- step_2 and step_3 can run in parallel after step_1
|
|
159
|
+
- step_4 runs after both step_2 and step_3 complete
|
|
160
|
+
"""
|
|
161
|
+
completed: Set[str] = set()
|
|
162
|
+
execution_order: List[List[str]] = []
|
|
163
|
+
|
|
164
|
+
while len(completed) < len(self.steps):
|
|
165
|
+
# Get all steps that can run now
|
|
166
|
+
current_batch = []
|
|
167
|
+
for step in self.steps:
|
|
168
|
+
if step.step_id not in completed:
|
|
169
|
+
if all(dep in completed for dep in step.depends_on):
|
|
170
|
+
current_batch.append(step.step_id)
|
|
171
|
+
|
|
172
|
+
if not current_batch:
|
|
173
|
+
# Should not happen if dependencies are valid
|
|
174
|
+
break
|
|
175
|
+
|
|
176
|
+
execution_order.append(current_batch)
|
|
177
|
+
completed.update(current_batch)
|
|
178
|
+
|
|
179
|
+
return execution_order
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class OptimizationStrategy(str, Enum):
|
|
183
|
+
"""Query optimization strategies"""
|
|
184
|
+
|
|
185
|
+
MINIMIZE_COST = "minimize_cost" # Reorder to minimize total cost
|
|
186
|
+
MINIMIZE_LATENCY = "minimize_latency" # Maximize parallelization
|
|
187
|
+
BALANCED = "balanced" # Balance cost and latency
|