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,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
+ }