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,613 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
from typing import Dict, List, Any, Callable
|
|
5
|
+
from aiecs.domain.execution.model import TaskStepResult, TaskStatus, ErrorCode
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DSLProcessor:
|
|
11
|
+
"""
|
|
12
|
+
Specialized DSL (Domain Specific Language) parsing and execution processor
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
def __init__(self, tracer=None):
|
|
16
|
+
self.tracer = tracer
|
|
17
|
+
# Update supported condition patterns with stricter matching
|
|
18
|
+
self.supported_conditions = [
|
|
19
|
+
r"intent\.includes\('([^']+)'\)",
|
|
20
|
+
r"context\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)",
|
|
21
|
+
r"input\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)",
|
|
22
|
+
r"result\[(\d+)\]\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)",
|
|
23
|
+
]
|
|
24
|
+
# Condition check priority order
|
|
25
|
+
self.condition_check_order = [
|
|
26
|
+
"AND", # Logical AND operation
|
|
27
|
+
"OR", # Logical OR operation
|
|
28
|
+
"intent.includes", # Intent inclusion check
|
|
29
|
+
"context", # Context check
|
|
30
|
+
"input", # Input check
|
|
31
|
+
"result", # Result check
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
def evaluate_condition(
|
|
35
|
+
self,
|
|
36
|
+
condition: str,
|
|
37
|
+
intent_categories: List[str],
|
|
38
|
+
context: Dict[str, Any] = None,
|
|
39
|
+
input_data: Dict[str, Any] = None,
|
|
40
|
+
results: List[TaskStepResult] = None,
|
|
41
|
+
) -> bool:
|
|
42
|
+
"""
|
|
43
|
+
Evaluate condition expression, supporting multiple condition types
|
|
44
|
+
Following optimized check order: AND -> OR -> intent.includes -> context -> input -> result
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
# 1. Compound condition: support AND (highest priority)
|
|
48
|
+
if " AND " in condition:
|
|
49
|
+
parts = condition.split(" AND ")
|
|
50
|
+
return all(
|
|
51
|
+
self.evaluate_condition(
|
|
52
|
+
part.strip(),
|
|
53
|
+
intent_categories,
|
|
54
|
+
context,
|
|
55
|
+
input_data,
|
|
56
|
+
results,
|
|
57
|
+
)
|
|
58
|
+
for part in parts
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# 2. Compound condition: support OR (second priority)
|
|
62
|
+
if " OR " in condition:
|
|
63
|
+
parts = condition.split(" OR ")
|
|
64
|
+
return any(
|
|
65
|
+
self.evaluate_condition(
|
|
66
|
+
part.strip(),
|
|
67
|
+
intent_categories,
|
|
68
|
+
context,
|
|
69
|
+
input_data,
|
|
70
|
+
results,
|
|
71
|
+
)
|
|
72
|
+
for part in parts
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# 3. Intent condition: intent.includes('category')
|
|
76
|
+
match = re.fullmatch(r"intent\.includes\('([^']+)'\)", condition)
|
|
77
|
+
if match:
|
|
78
|
+
category = match.group(1)
|
|
79
|
+
return category in intent_categories
|
|
80
|
+
|
|
81
|
+
# 4. Context condition: context.field == value
|
|
82
|
+
match = re.fullmatch(r"context\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
|
|
83
|
+
if match and context:
|
|
84
|
+
field, operator, value = match.groups()
|
|
85
|
+
return self._evaluate_comparison(
|
|
86
|
+
context.get(field), operator, self._parse_value(value)
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
# 5. Input condition: input.field == value
|
|
90
|
+
match = re.fullmatch(r"input\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
|
|
91
|
+
if match and input_data:
|
|
92
|
+
field, operator, value = match.groups()
|
|
93
|
+
return self._evaluate_comparison(
|
|
94
|
+
input_data.get(field), operator, self._parse_value(value)
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
# 6. Result condition: result[0].field == value
|
|
98
|
+
match = re.fullmatch(r"result\[(\d+)\]\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
|
|
99
|
+
if match and results:
|
|
100
|
+
index, field, operator, value = match.groups()
|
|
101
|
+
index = int(index)
|
|
102
|
+
if index < len(results) and results[index].result:
|
|
103
|
+
result_value = (
|
|
104
|
+
results[index].result.get(field)
|
|
105
|
+
if isinstance(results[index].result, dict)
|
|
106
|
+
else None
|
|
107
|
+
)
|
|
108
|
+
return self._evaluate_comparison(
|
|
109
|
+
result_value, operator, self._parse_value(value)
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
raise ValueError(f"Unsupported condition format: {condition}")
|
|
113
|
+
|
|
114
|
+
except Exception as e:
|
|
115
|
+
logger.error(f"Failed to evaluate condition '{condition}': {e}")
|
|
116
|
+
raise ValueError(f"Failed to evaluate condition '{condition}': {e}")
|
|
117
|
+
|
|
118
|
+
def _evaluate_comparison(self, left_value: Any, operator: str, right_value: Any) -> bool:
|
|
119
|
+
"""Evaluate comparison operation"""
|
|
120
|
+
try:
|
|
121
|
+
if operator == "==":
|
|
122
|
+
return left_value == right_value
|
|
123
|
+
elif operator == "!=":
|
|
124
|
+
return left_value != right_value
|
|
125
|
+
elif operator == ">":
|
|
126
|
+
return left_value > right_value
|
|
127
|
+
elif operator == "<":
|
|
128
|
+
return left_value < right_value
|
|
129
|
+
elif operator == ">=":
|
|
130
|
+
return left_value >= right_value
|
|
131
|
+
elif operator == "<=":
|
|
132
|
+
return left_value <= right_value
|
|
133
|
+
else:
|
|
134
|
+
raise ValueError(f"Unsupported operator: {operator}")
|
|
135
|
+
except TypeError:
|
|
136
|
+
# Return False when types don't match
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
def _parse_value(self, value_str: str) -> Any:
|
|
140
|
+
"""Parse value string to appropriate type"""
|
|
141
|
+
value_str = value_str.strip()
|
|
142
|
+
|
|
143
|
+
# String value
|
|
144
|
+
if value_str.startswith('"') and value_str.endswith('"'):
|
|
145
|
+
return value_str[1:-1]
|
|
146
|
+
if value_str.startswith("'") and value_str.endswith("'"):
|
|
147
|
+
return value_str[1:-1]
|
|
148
|
+
|
|
149
|
+
# Boolean value
|
|
150
|
+
if value_str.lower() == "true":
|
|
151
|
+
return True
|
|
152
|
+
if value_str.lower() == "false":
|
|
153
|
+
return False
|
|
154
|
+
|
|
155
|
+
# Numeric value
|
|
156
|
+
try:
|
|
157
|
+
if "." in value_str:
|
|
158
|
+
return float(value_str)
|
|
159
|
+
else:
|
|
160
|
+
return int(value_str)
|
|
161
|
+
except ValueError:
|
|
162
|
+
pass
|
|
163
|
+
|
|
164
|
+
# Default return string
|
|
165
|
+
return value_str
|
|
166
|
+
|
|
167
|
+
def validate_condition_syntax(self, condition: str) -> bool:
|
|
168
|
+
"""Validate condition syntax validity"""
|
|
169
|
+
if not condition or not isinstance(condition, str):
|
|
170
|
+
return False
|
|
171
|
+
|
|
172
|
+
condition = condition.strip()
|
|
173
|
+
if not condition:
|
|
174
|
+
return False
|
|
175
|
+
|
|
176
|
+
# Check if matches any supported condition pattern
|
|
177
|
+
for pattern in self.supported_conditions:
|
|
178
|
+
if re.fullmatch(pattern, condition):
|
|
179
|
+
return True
|
|
180
|
+
|
|
181
|
+
# Check compound conditions
|
|
182
|
+
if " AND " in condition or " OR " in condition:
|
|
183
|
+
return True
|
|
184
|
+
|
|
185
|
+
return False
|
|
186
|
+
|
|
187
|
+
async def execute_dsl_step(
|
|
188
|
+
self,
|
|
189
|
+
step: Dict,
|
|
190
|
+
intent_categories: List[str],
|
|
191
|
+
input_data: Dict,
|
|
192
|
+
context: Dict,
|
|
193
|
+
execute_single_task: Callable,
|
|
194
|
+
execute_batch_task: Callable,
|
|
195
|
+
results: List[TaskStepResult] = None,
|
|
196
|
+
) -> TaskStepResult:
|
|
197
|
+
"""
|
|
198
|
+
Execute DSL step based on step type (if, parallel, task, sequence)
|
|
199
|
+
"""
|
|
200
|
+
span = self.tracer.start_span("execute_dsl_step") if self.tracer else None
|
|
201
|
+
if span:
|
|
202
|
+
span.set_tag("step", json.dumps(step))
|
|
203
|
+
|
|
204
|
+
try:
|
|
205
|
+
if "if" in step:
|
|
206
|
+
return await self._handle_if_step(
|
|
207
|
+
step,
|
|
208
|
+
intent_categories,
|
|
209
|
+
input_data,
|
|
210
|
+
context,
|
|
211
|
+
execute_single_task,
|
|
212
|
+
execute_batch_task,
|
|
213
|
+
span,
|
|
214
|
+
results,
|
|
215
|
+
)
|
|
216
|
+
elif "parallel" in step:
|
|
217
|
+
return await self._handle_parallel_step(
|
|
218
|
+
step, input_data, context, execute_batch_task, span
|
|
219
|
+
)
|
|
220
|
+
elif "sequence" in step:
|
|
221
|
+
return await self._handle_sequence_step(
|
|
222
|
+
step,
|
|
223
|
+
intent_categories,
|
|
224
|
+
input_data,
|
|
225
|
+
context,
|
|
226
|
+
execute_single_task,
|
|
227
|
+
execute_batch_task,
|
|
228
|
+
span,
|
|
229
|
+
results,
|
|
230
|
+
)
|
|
231
|
+
elif "task" in step:
|
|
232
|
+
return await self._handle_task_step(
|
|
233
|
+
step, input_data, context, execute_single_task, span
|
|
234
|
+
)
|
|
235
|
+
elif "loop" in step:
|
|
236
|
+
return await self._handle_loop_step(
|
|
237
|
+
step,
|
|
238
|
+
intent_categories,
|
|
239
|
+
input_data,
|
|
240
|
+
context,
|
|
241
|
+
execute_single_task,
|
|
242
|
+
execute_batch_task,
|
|
243
|
+
span,
|
|
244
|
+
results,
|
|
245
|
+
)
|
|
246
|
+
else:
|
|
247
|
+
if span:
|
|
248
|
+
span.set_tag("error", True)
|
|
249
|
+
span.log_kv({"error_message": "Invalid DSL step"})
|
|
250
|
+
return TaskStepResult(
|
|
251
|
+
step="unknown",
|
|
252
|
+
result=None,
|
|
253
|
+
completed=False,
|
|
254
|
+
message="Invalid DSL step",
|
|
255
|
+
status=TaskStatus.FAILED.value,
|
|
256
|
+
error_code=ErrorCode.EXECUTION_ERROR.value,
|
|
257
|
+
error_message="Unknown DSL step type",
|
|
258
|
+
)
|
|
259
|
+
finally:
|
|
260
|
+
if span:
|
|
261
|
+
span.finish()
|
|
262
|
+
|
|
263
|
+
async def _handle_if_step(
|
|
264
|
+
self,
|
|
265
|
+
step: Dict,
|
|
266
|
+
intent_categories: List[str],
|
|
267
|
+
input_data: Dict,
|
|
268
|
+
context: Dict,
|
|
269
|
+
execute_single_task: Callable,
|
|
270
|
+
execute_batch_task: Callable,
|
|
271
|
+
span=None,
|
|
272
|
+
results: List[TaskStepResult] = None,
|
|
273
|
+
) -> TaskStepResult:
|
|
274
|
+
"""Handle conditional 'if' step"""
|
|
275
|
+
condition = step["if"]
|
|
276
|
+
then_steps = step["then"]
|
|
277
|
+
else_steps = step.get("else", [])
|
|
278
|
+
|
|
279
|
+
if span:
|
|
280
|
+
span.set_tag("condition", condition)
|
|
281
|
+
|
|
282
|
+
try:
|
|
283
|
+
condition_result = self.evaluate_condition(
|
|
284
|
+
condition, intent_categories, context, input_data, results
|
|
285
|
+
)
|
|
286
|
+
|
|
287
|
+
if condition_result:
|
|
288
|
+
if span:
|
|
289
|
+
span.log_kv({"condition_result": "true"})
|
|
290
|
+
|
|
291
|
+
step_results = []
|
|
292
|
+
for sub_step in then_steps:
|
|
293
|
+
result = await self.execute_dsl_step(
|
|
294
|
+
sub_step,
|
|
295
|
+
intent_categories,
|
|
296
|
+
input_data,
|
|
297
|
+
context,
|
|
298
|
+
execute_single_task,
|
|
299
|
+
execute_batch_task,
|
|
300
|
+
results,
|
|
301
|
+
)
|
|
302
|
+
step_results.append(result)
|
|
303
|
+
if results is not None:
|
|
304
|
+
results.append(result)
|
|
305
|
+
|
|
306
|
+
return TaskStepResult(
|
|
307
|
+
step=f"if_{condition}",
|
|
308
|
+
result=[r.dict() for r in step_results],
|
|
309
|
+
completed=all(r.completed for r in step_results),
|
|
310
|
+
message=f"Condition '{condition}' evaluated to true",
|
|
311
|
+
status=(
|
|
312
|
+
TaskStatus.COMPLETED.value
|
|
313
|
+
if all(r.status == TaskStatus.COMPLETED.value for r in step_results)
|
|
314
|
+
else TaskStatus.FAILED.value
|
|
315
|
+
),
|
|
316
|
+
)
|
|
317
|
+
else:
|
|
318
|
+
if span:
|
|
319
|
+
span.log_kv({"condition_result": "false"})
|
|
320
|
+
|
|
321
|
+
if else_steps:
|
|
322
|
+
step_results = []
|
|
323
|
+
for sub_step in else_steps:
|
|
324
|
+
result = await self.execute_dsl_step(
|
|
325
|
+
sub_step,
|
|
326
|
+
intent_categories,
|
|
327
|
+
input_data,
|
|
328
|
+
context,
|
|
329
|
+
execute_single_task,
|
|
330
|
+
execute_batch_task,
|
|
331
|
+
results,
|
|
332
|
+
)
|
|
333
|
+
step_results.append(result)
|
|
334
|
+
if results is not None:
|
|
335
|
+
results.append(result)
|
|
336
|
+
|
|
337
|
+
return TaskStepResult(
|
|
338
|
+
step=f"if_{condition}_else",
|
|
339
|
+
result=[r.dict() for r in step_results],
|
|
340
|
+
completed=all(r.completed for r in step_results),
|
|
341
|
+
message=f"Condition '{condition}' evaluated to false, executed else branch",
|
|
342
|
+
status=(
|
|
343
|
+
TaskStatus.COMPLETED.value
|
|
344
|
+
if all(r.status == TaskStatus.COMPLETED.value for r in step_results)
|
|
345
|
+
else TaskStatus.FAILED.value
|
|
346
|
+
),
|
|
347
|
+
)
|
|
348
|
+
else:
|
|
349
|
+
return TaskStepResult(
|
|
350
|
+
step=f"if_{condition}",
|
|
351
|
+
result=None,
|
|
352
|
+
completed=True,
|
|
353
|
+
message=f"Condition '{condition}' evaluated to false, skipping",
|
|
354
|
+
status=TaskStatus.COMPLETED.value,
|
|
355
|
+
)
|
|
356
|
+
except Exception as e:
|
|
357
|
+
if span:
|
|
358
|
+
span.set_tag("error", True)
|
|
359
|
+
span.log_kv({"error_message": str(e)})
|
|
360
|
+
return TaskStepResult(
|
|
361
|
+
step=f"if_{condition}",
|
|
362
|
+
result=None,
|
|
363
|
+
completed=False,
|
|
364
|
+
message="Failed to evaluate condition",
|
|
365
|
+
status=TaskStatus.FAILED.value,
|
|
366
|
+
error_code=ErrorCode.DSL_EVALUATION_ERROR.value,
|
|
367
|
+
error_message=str(e),
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
async def _handle_parallel_step(
|
|
371
|
+
self,
|
|
372
|
+
step: Dict,
|
|
373
|
+
input_data: Dict,
|
|
374
|
+
context: Dict,
|
|
375
|
+
execute_batch_task: Callable,
|
|
376
|
+
span=None,
|
|
377
|
+
) -> TaskStepResult:
|
|
378
|
+
"""Handle parallel task execution"""
|
|
379
|
+
task_names = step["parallel"]
|
|
380
|
+
if span:
|
|
381
|
+
span.set_tag("parallel_tasks", task_names)
|
|
382
|
+
|
|
383
|
+
batch_tasks = [{"category": "process", "task": task_name} for task_name in task_names]
|
|
384
|
+
batch_results = await execute_batch_task(batch_tasks, input_data, context)
|
|
385
|
+
|
|
386
|
+
return TaskStepResult(
|
|
387
|
+
step=f"parallel_{'_'.join(task_names)}",
|
|
388
|
+
result=[r.dict() for r in batch_results],
|
|
389
|
+
completed=all(r.completed for r in batch_results),
|
|
390
|
+
message=f"Completed parallel execution of {len(task_names)} tasks",
|
|
391
|
+
status=(
|
|
392
|
+
TaskStatus.COMPLETED.value
|
|
393
|
+
if all(r.status == TaskStatus.COMPLETED.value for r in batch_results)
|
|
394
|
+
else TaskStatus.FAILED.value
|
|
395
|
+
),
|
|
396
|
+
)
|
|
397
|
+
|
|
398
|
+
async def _handle_sequence_step(
|
|
399
|
+
self,
|
|
400
|
+
step: Dict,
|
|
401
|
+
intent_categories: List[str],
|
|
402
|
+
input_data: Dict,
|
|
403
|
+
context: Dict,
|
|
404
|
+
execute_single_task: Callable,
|
|
405
|
+
execute_batch_task: Callable,
|
|
406
|
+
span=None,
|
|
407
|
+
results: List[TaskStepResult] = None,
|
|
408
|
+
) -> TaskStepResult:
|
|
409
|
+
"""Handle sequential execution steps"""
|
|
410
|
+
sequence_steps = step["sequence"]
|
|
411
|
+
if span:
|
|
412
|
+
span.set_tag("sequence_length", len(sequence_steps))
|
|
413
|
+
|
|
414
|
+
step_results = []
|
|
415
|
+
for i, sub_step in enumerate(sequence_steps):
|
|
416
|
+
result = await self.execute_dsl_step(
|
|
417
|
+
sub_step,
|
|
418
|
+
intent_categories,
|
|
419
|
+
input_data,
|
|
420
|
+
context,
|
|
421
|
+
execute_single_task,
|
|
422
|
+
execute_batch_task,
|
|
423
|
+
results,
|
|
424
|
+
)
|
|
425
|
+
step_results.append(result)
|
|
426
|
+
if results is not None:
|
|
427
|
+
results.append(result)
|
|
428
|
+
|
|
429
|
+
# If step fails and stop_on_failure is set, stop execution
|
|
430
|
+
if not result.completed and step.get("stop_on_failure", False):
|
|
431
|
+
break
|
|
432
|
+
|
|
433
|
+
return TaskStepResult(
|
|
434
|
+
step=f"sequence_{len(sequence_steps)}_steps",
|
|
435
|
+
result=[r.dict() for r in step_results],
|
|
436
|
+
completed=all(r.completed for r in step_results),
|
|
437
|
+
message=f"Completed sequence execution of {len(step_results)} steps",
|
|
438
|
+
status=(
|
|
439
|
+
TaskStatus.COMPLETED.value
|
|
440
|
+
if all(r.status == TaskStatus.COMPLETED.value for r in step_results)
|
|
441
|
+
else TaskStatus.FAILED.value
|
|
442
|
+
),
|
|
443
|
+
)
|
|
444
|
+
|
|
445
|
+
async def _handle_task_step(
|
|
446
|
+
self,
|
|
447
|
+
step: Dict,
|
|
448
|
+
input_data: Dict,
|
|
449
|
+
context: Dict,
|
|
450
|
+
execute_single_task: Callable,
|
|
451
|
+
span=None,
|
|
452
|
+
) -> TaskStepResult:
|
|
453
|
+
"""Handle single task execution"""
|
|
454
|
+
task_name = step["task"]
|
|
455
|
+
task_params = step.get("params", {})
|
|
456
|
+
|
|
457
|
+
if span:
|
|
458
|
+
span.set_tag("task_name", task_name)
|
|
459
|
+
|
|
460
|
+
try:
|
|
461
|
+
# Merge task parameters and input data
|
|
462
|
+
merged_input = {**input_data, **task_params}
|
|
463
|
+
result = await execute_single_task(task_name, merged_input, context)
|
|
464
|
+
|
|
465
|
+
if isinstance(result, dict) and "step" in result:
|
|
466
|
+
return TaskStepResult(**result)
|
|
467
|
+
else:
|
|
468
|
+
return TaskStepResult(
|
|
469
|
+
step=f"task_{task_name}",
|
|
470
|
+
result=result,
|
|
471
|
+
completed=True,
|
|
472
|
+
message=f"Completed task {task_name}",
|
|
473
|
+
status=TaskStatus.COMPLETED.value,
|
|
474
|
+
)
|
|
475
|
+
except Exception as e:
|
|
476
|
+
if span:
|
|
477
|
+
span.set_tag("error", True)
|
|
478
|
+
span.log_kv({"error_message": str(e)})
|
|
479
|
+
return TaskStepResult(
|
|
480
|
+
step=f"task_{task_name}",
|
|
481
|
+
result=None,
|
|
482
|
+
completed=False,
|
|
483
|
+
message=f"Failed to execute task {task_name}",
|
|
484
|
+
status=TaskStatus.FAILED.value,
|
|
485
|
+
error_code=ErrorCode.EXECUTION_ERROR.value,
|
|
486
|
+
error_message=str(e),
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
async def _handle_loop_step(
|
|
490
|
+
self,
|
|
491
|
+
step: Dict,
|
|
492
|
+
intent_categories: List[str],
|
|
493
|
+
input_data: Dict,
|
|
494
|
+
context: Dict,
|
|
495
|
+
execute_single_task: Callable,
|
|
496
|
+
execute_batch_task: Callable,
|
|
497
|
+
span=None,
|
|
498
|
+
results: List[TaskStepResult] = None,
|
|
499
|
+
) -> TaskStepResult:
|
|
500
|
+
"""Handle loop step"""
|
|
501
|
+
loop_config = step["loop"]
|
|
502
|
+
loop_steps = loop_config["steps"]
|
|
503
|
+
condition = loop_config.get("while")
|
|
504
|
+
max_iterations = loop_config.get("max_iterations", 10)
|
|
505
|
+
|
|
506
|
+
if span:
|
|
507
|
+
span.set_tag("loop_condition", condition)
|
|
508
|
+
span.set_tag("max_iterations", max_iterations)
|
|
509
|
+
|
|
510
|
+
iteration_results = []
|
|
511
|
+
iteration = 0
|
|
512
|
+
|
|
513
|
+
while iteration < max_iterations:
|
|
514
|
+
# Check loop condition
|
|
515
|
+
if condition and not self.evaluate_condition(
|
|
516
|
+
condition, intent_categories, context, input_data, results
|
|
517
|
+
):
|
|
518
|
+
break
|
|
519
|
+
|
|
520
|
+
# Execute loop body
|
|
521
|
+
iteration_step_results = []
|
|
522
|
+
for sub_step in loop_steps:
|
|
523
|
+
result = await self.execute_dsl_step(
|
|
524
|
+
sub_step,
|
|
525
|
+
intent_categories,
|
|
526
|
+
input_data,
|
|
527
|
+
context,
|
|
528
|
+
execute_single_task,
|
|
529
|
+
execute_batch_task,
|
|
530
|
+
results,
|
|
531
|
+
)
|
|
532
|
+
iteration_step_results.append(result)
|
|
533
|
+
if results is not None:
|
|
534
|
+
results.append(result)
|
|
535
|
+
|
|
536
|
+
iteration_results.append(iteration_step_results)
|
|
537
|
+
iteration += 1
|
|
538
|
+
|
|
539
|
+
# If no condition, execute only once
|
|
540
|
+
if not condition:
|
|
541
|
+
break
|
|
542
|
+
|
|
543
|
+
return TaskStepResult(
|
|
544
|
+
step=f"loop_{iteration}_iterations",
|
|
545
|
+
result=[
|
|
546
|
+
{"iteration": i, "results": [r.dict() for r in iter_results]}
|
|
547
|
+
for i, iter_results in enumerate(iteration_results)
|
|
548
|
+
],
|
|
549
|
+
completed=True,
|
|
550
|
+
message=f"Completed loop with {iteration} iterations",
|
|
551
|
+
status=TaskStatus.COMPLETED.value,
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
def validate_dsl_step(self, step: Dict) -> List[str]:
|
|
555
|
+
"""Validate DSL step format"""
|
|
556
|
+
errors = []
|
|
557
|
+
|
|
558
|
+
if not isinstance(step, dict):
|
|
559
|
+
errors.append("Step must be a dictionary")
|
|
560
|
+
return errors
|
|
561
|
+
|
|
562
|
+
step_types = ["if", "parallel", "sequence", "task", "loop"]
|
|
563
|
+
found_types = [t for t in step_types if t in step]
|
|
564
|
+
|
|
565
|
+
if len(found_types) == 0:
|
|
566
|
+
errors.append(f"Step must contain one of: {step_types}")
|
|
567
|
+
elif len(found_types) > 1:
|
|
568
|
+
errors.append(f"Step can only contain one type, found: {found_types}")
|
|
569
|
+
|
|
570
|
+
# Validate specific step types
|
|
571
|
+
if "if" in step:
|
|
572
|
+
if "then" not in step:
|
|
573
|
+
errors.append("'if' step must have 'then' clause")
|
|
574
|
+
|
|
575
|
+
if "parallel" in step:
|
|
576
|
+
if not isinstance(step["parallel"], list):
|
|
577
|
+
errors.append("'parallel' must be a list of task names")
|
|
578
|
+
|
|
579
|
+
if "sequence" in step:
|
|
580
|
+
if not isinstance(step["sequence"], list):
|
|
581
|
+
errors.append("'sequence' must be a list of steps")
|
|
582
|
+
|
|
583
|
+
if "loop" in step:
|
|
584
|
+
loop_config = step["loop"]
|
|
585
|
+
if not isinstance(loop_config, dict):
|
|
586
|
+
errors.append("'loop' must be a dictionary")
|
|
587
|
+
elif "steps" not in loop_config:
|
|
588
|
+
errors.append("'loop' must have 'steps' field")
|
|
589
|
+
|
|
590
|
+
return errors
|
|
591
|
+
|
|
592
|
+
def get_supported_features(self) -> Dict[str, Any]:
|
|
593
|
+
"""Get supported DSL features"""
|
|
594
|
+
return {
|
|
595
|
+
"step_types": ["if", "parallel", "sequence", "task", "loop"],
|
|
596
|
+
"condition_types": [
|
|
597
|
+
"intent.includes('category')",
|
|
598
|
+
"context.field == value",
|
|
599
|
+
"input.field == value",
|
|
600
|
+
"result[index].field == value",
|
|
601
|
+
],
|
|
602
|
+
"operators": ["==", "!=", ">", "<", ">=", "<="],
|
|
603
|
+
"logical_operators": ["AND", "OR"],
|
|
604
|
+
"supported_value_types": ["string", "number", "boolean", "null"],
|
|
605
|
+
"condition_check_order": self.condition_check_order,
|
|
606
|
+
"regex_matching": "fullmatch (exact matching)",
|
|
607
|
+
"improvements": [
|
|
608
|
+
"Use re.fullmatch instead of re.match for stricter matching",
|
|
609
|
+
"Optimize condition check order: AND -> OR -> intent.includes -> context -> input -> result",
|
|
610
|
+
"Enhance value parsing robustness, support null values",
|
|
611
|
+
"Add condition syntax validation method",
|
|
612
|
+
],
|
|
613
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class TaskContext:
|
|
6
|
+
"""Task context model"""
|
|
7
|
+
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
user_id: str,
|
|
11
|
+
task_id: str,
|
|
12
|
+
session_id: Optional[str] = None,
|
|
13
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
14
|
+
):
|
|
15
|
+
self.user_id = user_id
|
|
16
|
+
self.task_id = task_id
|
|
17
|
+
self.session_id = session_id
|
|
18
|
+
self.metadata = metadata or {}
|
|
19
|
+
self.created_at = datetime.now()
|
|
20
|
+
self.variables = {} # Variable storage during task execution
|
|
21
|
+
|
|
22
|
+
def set_variable(self, key: str, value: Any):
|
|
23
|
+
"""Set task variable"""
|
|
24
|
+
self.variables[key] = value
|
|
25
|
+
|
|
26
|
+
def get_variable(self, key: str, default: Any = None) -> Any:
|
|
27
|
+
"""Get task variable"""
|
|
28
|
+
return self.variables.get(key, default)
|
|
29
|
+
|
|
30
|
+
def dict(self) -> Dict[str, Any]:
|
|
31
|
+
return {
|
|
32
|
+
"user_id": self.user_id,
|
|
33
|
+
"task_id": self.task_id,
|
|
34
|
+
"session_id": self.session_id,
|
|
35
|
+
"metadata": self.metadata,
|
|
36
|
+
"created_at": self.created_at.isoformat(),
|
|
37
|
+
"variables": self.variables,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class DSLStep:
|
|
42
|
+
"""DSL step model"""
|
|
43
|
+
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
step_type: str,
|
|
47
|
+
condition: Optional[str] = None,
|
|
48
|
+
description: str = "",
|
|
49
|
+
params: Optional[Dict[str, Any]] = None,
|
|
50
|
+
):
|
|
51
|
+
self.step_type = step_type
|
|
52
|
+
self.condition = condition
|
|
53
|
+
self.description = description
|
|
54
|
+
self.params = params or {}
|
|
55
|
+
|
|
56
|
+
def dict(self) -> Dict[str, Any]:
|
|
57
|
+
return {
|
|
58
|
+
"step_type": self.step_type,
|
|
59
|
+
"condition": self.condition,
|
|
60
|
+
"description": self.description,
|
|
61
|
+
"params": self.params,
|
|
62
|
+
}
|