aiecs 1.0.0__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.

Potentially problematic release.


This version of aiecs might be problematic. Click here for more details.

Files changed (90) hide show
  1. aiecs/__init__.py +75 -0
  2. aiecs/__main__.py +41 -0
  3. aiecs/aiecs_client.py +295 -0
  4. aiecs/application/__init__.py +10 -0
  5. aiecs/application/executors/__init__.py +10 -0
  6. aiecs/application/executors/operation_executor.py +341 -0
  7. aiecs/config/__init__.py +15 -0
  8. aiecs/config/config.py +117 -0
  9. aiecs/config/registry.py +19 -0
  10. aiecs/core/__init__.py +46 -0
  11. aiecs/core/interface/__init__.py +34 -0
  12. aiecs/core/interface/execution_interface.py +150 -0
  13. aiecs/core/interface/storage_interface.py +214 -0
  14. aiecs/domain/__init__.py +20 -0
  15. aiecs/domain/context/__init__.py +28 -0
  16. aiecs/domain/context/content_engine.py +982 -0
  17. aiecs/domain/context/conversation_models.py +306 -0
  18. aiecs/domain/execution/__init__.py +12 -0
  19. aiecs/domain/execution/model.py +49 -0
  20. aiecs/domain/task/__init__.py +13 -0
  21. aiecs/domain/task/dsl_processor.py +460 -0
  22. aiecs/domain/task/model.py +50 -0
  23. aiecs/domain/task/task_context.py +257 -0
  24. aiecs/infrastructure/__init__.py +26 -0
  25. aiecs/infrastructure/messaging/__init__.py +13 -0
  26. aiecs/infrastructure/messaging/celery_task_manager.py +341 -0
  27. aiecs/infrastructure/messaging/websocket_manager.py +289 -0
  28. aiecs/infrastructure/monitoring/__init__.py +12 -0
  29. aiecs/infrastructure/monitoring/executor_metrics.py +138 -0
  30. aiecs/infrastructure/monitoring/structured_logger.py +50 -0
  31. aiecs/infrastructure/monitoring/tracing_manager.py +376 -0
  32. aiecs/infrastructure/persistence/__init__.py +12 -0
  33. aiecs/infrastructure/persistence/database_manager.py +286 -0
  34. aiecs/infrastructure/persistence/file_storage.py +671 -0
  35. aiecs/infrastructure/persistence/redis_client.py +162 -0
  36. aiecs/llm/__init__.py +54 -0
  37. aiecs/llm/base_client.py +99 -0
  38. aiecs/llm/client_factory.py +339 -0
  39. aiecs/llm/custom_callbacks.py +228 -0
  40. aiecs/llm/openai_client.py +125 -0
  41. aiecs/llm/vertex_client.py +186 -0
  42. aiecs/llm/xai_client.py +184 -0
  43. aiecs/main.py +351 -0
  44. aiecs/scripts/DEPENDENCY_SYSTEM_SUMMARY.md +241 -0
  45. aiecs/scripts/README_DEPENDENCY_CHECKER.md +309 -0
  46. aiecs/scripts/README_WEASEL_PATCH.md +126 -0
  47. aiecs/scripts/__init__.py +3 -0
  48. aiecs/scripts/dependency_checker.py +825 -0
  49. aiecs/scripts/dependency_fixer.py +348 -0
  50. aiecs/scripts/download_nlp_data.py +348 -0
  51. aiecs/scripts/fix_weasel_validator.py +121 -0
  52. aiecs/scripts/fix_weasel_validator.sh +82 -0
  53. aiecs/scripts/patch_weasel_library.sh +188 -0
  54. aiecs/scripts/quick_dependency_check.py +269 -0
  55. aiecs/scripts/run_weasel_patch.sh +41 -0
  56. aiecs/scripts/setup_nlp_data.sh +217 -0
  57. aiecs/tasks/__init__.py +2 -0
  58. aiecs/tasks/worker.py +111 -0
  59. aiecs/tools/__init__.py +196 -0
  60. aiecs/tools/base_tool.py +202 -0
  61. aiecs/tools/langchain_adapter.py +361 -0
  62. aiecs/tools/task_tools/__init__.py +82 -0
  63. aiecs/tools/task_tools/chart_tool.py +704 -0
  64. aiecs/tools/task_tools/classfire_tool.py +901 -0
  65. aiecs/tools/task_tools/image_tool.py +397 -0
  66. aiecs/tools/task_tools/office_tool.py +600 -0
  67. aiecs/tools/task_tools/pandas_tool.py +565 -0
  68. aiecs/tools/task_tools/report_tool.py +499 -0
  69. aiecs/tools/task_tools/research_tool.py +363 -0
  70. aiecs/tools/task_tools/scraper_tool.py +548 -0
  71. aiecs/tools/task_tools/search_api.py +7 -0
  72. aiecs/tools/task_tools/stats_tool.py +513 -0
  73. aiecs/tools/temp_file_manager.py +126 -0
  74. aiecs/tools/tool_executor/__init__.py +35 -0
  75. aiecs/tools/tool_executor/tool_executor.py +518 -0
  76. aiecs/utils/LLM_output_structor.py +409 -0
  77. aiecs/utils/__init__.py +23 -0
  78. aiecs/utils/base_callback.py +50 -0
  79. aiecs/utils/execution_utils.py +158 -0
  80. aiecs/utils/logging.py +1 -0
  81. aiecs/utils/prompt_loader.py +13 -0
  82. aiecs/utils/token_usage_repository.py +279 -0
  83. aiecs/ws/__init__.py +0 -0
  84. aiecs/ws/socket_server.py +41 -0
  85. aiecs-1.0.0.dist-info/METADATA +610 -0
  86. aiecs-1.0.0.dist-info/RECORD +90 -0
  87. aiecs-1.0.0.dist-info/WHEEL +5 -0
  88. aiecs-1.0.0.dist-info/entry_points.txt +7 -0
  89. aiecs-1.0.0.dist-info/licenses/LICENSE +225 -0
  90. aiecs-1.0.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,460 @@
1
+ import re
2
+ import json
3
+ import logging
4
+ import asyncio
5
+ from typing import Dict, List, Any, Optional, Callable
6
+ from aiecs.domain.execution.model import TaskStepResult, TaskStatus, ErrorCode
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ class DSLProcessor:
12
+ """
13
+ Specialized DSL (Domain Specific Language) parsing and execution processor
14
+ """
15
+
16
+ def __init__(self, tracer=None):
17
+ self.tracer = tracer
18
+ # Update supported condition patterns with stricter matching
19
+ self.supported_conditions = [
20
+ r"intent\.includes\('([^']+)'\)",
21
+ r"context\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)",
22
+ r"input\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)",
23
+ r"result\[(\d+)\]\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)"
24
+ ]
25
+ # Condition check priority order
26
+ self.condition_check_order = [
27
+ "AND", # Logical AND operation
28
+ "OR", # Logical OR operation
29
+ "intent.includes", # Intent inclusion check
30
+ "context", # Context check
31
+ "input", # Input check
32
+ "result" # Result check
33
+ ]
34
+
35
+ def evaluate_condition(self, condition: str, intent_categories: List[str],
36
+ context: Dict[str, Any] = None, input_data: Dict[str, Any] = None,
37
+ results: List[TaskStepResult] = None) -> bool:
38
+ """
39
+ Evaluate condition expression, supporting multiple condition types
40
+ Following optimized check order: AND -> OR -> intent.includes -> context -> input -> result
41
+ """
42
+ try:
43
+ # 1. Compound condition: support AND (highest priority)
44
+ if " AND " in condition:
45
+ parts = condition.split(" AND ")
46
+ return all(self.evaluate_condition(part.strip(), intent_categories, context, input_data, results) for part in parts)
47
+
48
+ # 2. Compound condition: support OR (second priority)
49
+ if " OR " in condition:
50
+ parts = condition.split(" OR ")
51
+ return any(self.evaluate_condition(part.strip(), intent_categories, context, input_data, results) for part in parts)
52
+
53
+ # 3. Intent condition: intent.includes('category')
54
+ match = re.fullmatch(r"intent\.includes\('([^']+)'\)", condition)
55
+ if match:
56
+ category = match.group(1)
57
+ return category in intent_categories
58
+
59
+ # 4. Context condition: context.field == value
60
+ match = re.fullmatch(r"context\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
61
+ if match and context:
62
+ field, operator, value = match.groups()
63
+ return self._evaluate_comparison(context.get(field), operator, self._parse_value(value))
64
+
65
+ # 5. Input condition: input.field == value
66
+ match = re.fullmatch(r"input\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
67
+ if match and input_data:
68
+ field, operator, value = match.groups()
69
+ return self._evaluate_comparison(input_data.get(field), operator, self._parse_value(value))
70
+
71
+ # 6. Result condition: result[0].field == value
72
+ match = re.fullmatch(r"result\[(\d+)\]\.(\w+)\s*(==|!=|>|<|>=|<=)\s*(.+)", condition)
73
+ if match and results:
74
+ index, field, operator, value = match.groups()
75
+ index = int(index)
76
+ if index < len(results) and results[index].result:
77
+ result_value = results[index].result.get(field) if isinstance(results[index].result, dict) else None
78
+ return self._evaluate_comparison(result_value, operator, self._parse_value(value))
79
+
80
+ raise ValueError(f"Unsupported condition format: {condition}")
81
+
82
+ except Exception as e:
83
+ logger.error(f"Failed to evaluate condition '{condition}': {e}")
84
+ raise ValueError(f"Failed to evaluate condition '{condition}': {e}")
85
+
86
+ def _evaluate_comparison(self, left_value: Any, operator: str, right_value: Any) -> bool:
87
+ """Evaluate comparison operation"""
88
+ try:
89
+ if operator == "==":
90
+ return left_value == right_value
91
+ elif operator == "!=":
92
+ return left_value != right_value
93
+ elif operator == ">":
94
+ return left_value > right_value
95
+ elif operator == "<":
96
+ return left_value < right_value
97
+ elif operator == ">=":
98
+ return left_value >= right_value
99
+ elif operator == "<=":
100
+ return left_value <= right_value
101
+ else:
102
+ raise ValueError(f"Unsupported operator: {operator}")
103
+ except TypeError:
104
+ # Return False when types don't match
105
+ return False
106
+
107
+ def _parse_value(self, value_str: str) -> Any:
108
+ """Parse value string to appropriate type"""
109
+ value_str = value_str.strip()
110
+
111
+ # String value
112
+ if value_str.startswith('"') and value_str.endswith('"'):
113
+ return value_str[1:-1]
114
+ if value_str.startswith("'") and value_str.endswith("'"):
115
+ return value_str[1:-1]
116
+
117
+ # Boolean value
118
+ if value_str.lower() == "true":
119
+ return True
120
+ if value_str.lower() == "false":
121
+ return False
122
+
123
+ # Numeric value
124
+ try:
125
+ if "." in value_str:
126
+ return float(value_str)
127
+ else:
128
+ return int(value_str)
129
+ except ValueError:
130
+ pass
131
+
132
+ # Default return string
133
+ return value_str
134
+
135
+ def validate_condition_syntax(self, condition: str) -> bool:
136
+ """Validate condition syntax validity"""
137
+ if not condition or not isinstance(condition, str):
138
+ return False
139
+
140
+ condition = condition.strip()
141
+ if not condition:
142
+ return False
143
+
144
+ # Check if matches any supported condition pattern
145
+ for pattern in self.supported_conditions:
146
+ if re.fullmatch(pattern, condition):
147
+ return True
148
+
149
+ # Check compound conditions
150
+ if " AND " in condition or " OR " in condition:
151
+ return True
152
+
153
+ return False
154
+
155
+ async def execute_dsl_step(self, step: Dict, intent_categories: List[str], input_data: Dict,
156
+ context: Dict, execute_single_task: Callable, execute_batch_task: Callable,
157
+ results: List[TaskStepResult] = None) -> TaskStepResult:
158
+ """
159
+ Execute DSL step based on step type (if, parallel, task, sequence)
160
+ """
161
+ span = self.tracer.start_span("execute_dsl_step") if self.tracer else None
162
+ if span:
163
+ span.set_tag("step", json.dumps(step))
164
+
165
+ try:
166
+ if "if" in step:
167
+ return await self._handle_if_step(step, intent_categories, input_data, context,
168
+ execute_single_task, execute_batch_task, span, results)
169
+ elif "parallel" in step:
170
+ return await self._handle_parallel_step(step, input_data, context, execute_batch_task, span)
171
+ elif "sequence" in step:
172
+ return await self._handle_sequence_step(step, intent_categories, input_data, context,
173
+ execute_single_task, execute_batch_task, span, results)
174
+ elif "task" in step:
175
+ return await self._handle_task_step(step, input_data, context, execute_single_task, span)
176
+ elif "loop" in step:
177
+ return await self._handle_loop_step(step, intent_categories, input_data, context,
178
+ execute_single_task, execute_batch_task, span, results)
179
+ else:
180
+ if span:
181
+ span.set_tag("error", True)
182
+ span.log_kv({"error_message": "Invalid DSL step"})
183
+ return TaskStepResult(
184
+ step="unknown",
185
+ result=None,
186
+ completed=False,
187
+ message="Invalid DSL step",
188
+ status=TaskStatus.FAILED.value,
189
+ error_code=ErrorCode.EXECUTION_ERROR.value,
190
+ error_message="Unknown DSL step type"
191
+ )
192
+ finally:
193
+ if span:
194
+ span.finish()
195
+
196
+ async def _handle_if_step(self, step: Dict, intent_categories: List[str], input_data: Dict,
197
+ context: Dict, execute_single_task: Callable, execute_batch_task: Callable,
198
+ span=None, results: List[TaskStepResult] = None) -> TaskStepResult:
199
+ """Handle conditional 'if' step"""
200
+ condition = step["if"]
201
+ then_steps = step["then"]
202
+ else_steps = step.get("else", [])
203
+
204
+ if span:
205
+ span.set_tag("condition", condition)
206
+
207
+ try:
208
+ condition_result = self.evaluate_condition(condition, intent_categories, context, input_data, results)
209
+
210
+ if condition_result:
211
+ if span:
212
+ span.log_kv({"condition_result": "true"})
213
+
214
+ step_results = []
215
+ for sub_step in then_steps:
216
+ result = await self.execute_dsl_step(sub_step, intent_categories, input_data, context,
217
+ execute_single_task, execute_batch_task, results)
218
+ step_results.append(result)
219
+ if results is not None:
220
+ results.append(result)
221
+
222
+ return TaskStepResult(
223
+ step=f"if_{condition}",
224
+ result=[r.dict() for r in step_results],
225
+ completed=all(r.completed for r in step_results),
226
+ message=f"Condition '{condition}' evaluated to true",
227
+ status=TaskStatus.COMPLETED.value if all(r.status == TaskStatus.COMPLETED.value for r in step_results) else TaskStatus.FAILED.value
228
+ )
229
+ else:
230
+ if span:
231
+ span.log_kv({"condition_result": "false"})
232
+
233
+ if else_steps:
234
+ step_results = []
235
+ for sub_step in else_steps:
236
+ result = await self.execute_dsl_step(sub_step, intent_categories, input_data, context,
237
+ execute_single_task, execute_batch_task, results)
238
+ step_results.append(result)
239
+ if results is not None:
240
+ results.append(result)
241
+
242
+ return TaskStepResult(
243
+ step=f"if_{condition}_else",
244
+ result=[r.dict() for r in step_results],
245
+ completed=all(r.completed for r in step_results),
246
+ message=f"Condition '{condition}' evaluated to false, executed else branch",
247
+ status=TaskStatus.COMPLETED.value if all(r.status == TaskStatus.COMPLETED.value for r in step_results) else TaskStatus.FAILED.value
248
+ )
249
+ else:
250
+ return TaskStepResult(
251
+ step=f"if_{condition}",
252
+ result=None,
253
+ completed=True,
254
+ message=f"Condition '{condition}' evaluated to false, skipping",
255
+ status=TaskStatus.COMPLETED.value
256
+ )
257
+ except Exception as e:
258
+ if span:
259
+ span.set_tag("error", True)
260
+ span.log_kv({"error_message": str(e)})
261
+ return TaskStepResult(
262
+ step=f"if_{condition}",
263
+ result=None,
264
+ completed=False,
265
+ message="Failed to evaluate condition",
266
+ status=TaskStatus.FAILED.value,
267
+ error_code=ErrorCode.DSL_EVALUATION_ERROR.value,
268
+ error_message=str(e)
269
+ )
270
+
271
+ async def _handle_parallel_step(self, step: Dict, input_data: Dict, context: Dict,
272
+ execute_batch_task: Callable, span=None) -> TaskStepResult:
273
+ """Handle parallel task execution"""
274
+ task_names = step["parallel"]
275
+ if span:
276
+ span.set_tag("parallel_tasks", task_names)
277
+
278
+ batch_tasks = [{"category": "process", "task": task_name} for task_name in task_names]
279
+ batch_results = await execute_batch_task(batch_tasks, input_data, context)
280
+
281
+ return TaskStepResult(
282
+ step=f"parallel_{'_'.join(task_names)}",
283
+ result=[r.dict() for r in batch_results],
284
+ completed=all(r.completed for r in batch_results),
285
+ message=f"Completed parallel execution of {len(task_names)} tasks",
286
+ status=TaskStatus.COMPLETED.value if all(r.status == TaskStatus.COMPLETED.value for r in batch_results) else TaskStatus.FAILED.value
287
+ )
288
+
289
+ async def _handle_sequence_step(self, step: Dict, intent_categories: List[str], input_data: Dict,
290
+ context: Dict, execute_single_task: Callable, execute_batch_task: Callable,
291
+ span=None, results: List[TaskStepResult] = None) -> TaskStepResult:
292
+ """Handle sequential execution steps"""
293
+ sequence_steps = step["sequence"]
294
+ if span:
295
+ span.set_tag("sequence_length", len(sequence_steps))
296
+
297
+ step_results = []
298
+ for i, sub_step in enumerate(sequence_steps):
299
+ result = await self.execute_dsl_step(sub_step, intent_categories, input_data, context,
300
+ execute_single_task, execute_batch_task, results)
301
+ step_results.append(result)
302
+ if results is not None:
303
+ results.append(result)
304
+
305
+ # If step fails and stop_on_failure is set, stop execution
306
+ if not result.completed and step.get("stop_on_failure", False):
307
+ break
308
+
309
+ return TaskStepResult(
310
+ step=f"sequence_{len(sequence_steps)}_steps",
311
+ result=[r.dict() for r in step_results],
312
+ completed=all(r.completed for r in step_results),
313
+ message=f"Completed sequence execution of {len(step_results)} steps",
314
+ status=TaskStatus.COMPLETED.value if all(r.status == TaskStatus.COMPLETED.value for r in step_results) else TaskStatus.FAILED.value
315
+ )
316
+
317
+ async def _handle_task_step(self, step: Dict, input_data: Dict, context: Dict,
318
+ execute_single_task: Callable, span=None) -> TaskStepResult:
319
+ """Handle single task execution"""
320
+ task_name = step["task"]
321
+ task_params = step.get("params", {})
322
+
323
+ if span:
324
+ span.set_tag("task_name", task_name)
325
+
326
+ try:
327
+ # Merge task parameters and input data
328
+ merged_input = {**input_data, **task_params}
329
+ result = await execute_single_task(task_name, merged_input, context)
330
+
331
+ if isinstance(result, dict) and "step" in result:
332
+ return TaskStepResult(**result)
333
+ else:
334
+ return TaskStepResult(
335
+ step=f"task_{task_name}",
336
+ result=result,
337
+ completed=True,
338
+ message=f"Completed task {task_name}",
339
+ status=TaskStatus.COMPLETED.value
340
+ )
341
+ except Exception as e:
342
+ if span:
343
+ span.set_tag("error", True)
344
+ span.log_kv({"error_message": str(e)})
345
+ return TaskStepResult(
346
+ step=f"task_{task_name}",
347
+ result=None,
348
+ completed=False,
349
+ message=f"Failed to execute task {task_name}",
350
+ status=TaskStatus.FAILED.value,
351
+ error_code=ErrorCode.EXECUTION_ERROR.value,
352
+ error_message=str(e)
353
+ )
354
+
355
+ async def _handle_loop_step(self, step: Dict, intent_categories: List[str], input_data: Dict,
356
+ context: Dict, execute_single_task: Callable, execute_batch_task: Callable,
357
+ span=None, results: List[TaskStepResult] = None) -> TaskStepResult:
358
+ """Handle loop step"""
359
+ loop_config = step["loop"]
360
+ loop_steps = loop_config["steps"]
361
+ condition = loop_config.get("while")
362
+ max_iterations = loop_config.get("max_iterations", 10)
363
+
364
+ if span:
365
+ span.set_tag("loop_condition", condition)
366
+ span.set_tag("max_iterations", max_iterations)
367
+
368
+ iteration_results = []
369
+ iteration = 0
370
+
371
+ while iteration < max_iterations:
372
+ # Check loop condition
373
+ if condition and not self.evaluate_condition(condition, intent_categories, context, input_data, results):
374
+ break
375
+
376
+ # Execute loop body
377
+ iteration_step_results = []
378
+ for sub_step in loop_steps:
379
+ result = await self.execute_dsl_step(sub_step, intent_categories, input_data, context,
380
+ execute_single_task, execute_batch_task, results)
381
+ iteration_step_results.append(result)
382
+ if results is not None:
383
+ results.append(result)
384
+
385
+ iteration_results.append(iteration_step_results)
386
+ iteration += 1
387
+
388
+ # If no condition, execute only once
389
+ if not condition:
390
+ break
391
+
392
+ return TaskStepResult(
393
+ step=f"loop_{iteration}_iterations",
394
+ result=[{"iteration": i, "results": [r.dict() for r in iter_results]}
395
+ for i, iter_results in enumerate(iteration_results)],
396
+ completed=True,
397
+ message=f"Completed loop with {iteration} iterations",
398
+ status=TaskStatus.COMPLETED.value
399
+ )
400
+
401
+ def validate_dsl_step(self, step: Dict) -> List[str]:
402
+ """Validate DSL step format"""
403
+ errors = []
404
+
405
+ if not isinstance(step, dict):
406
+ errors.append("Step must be a dictionary")
407
+ return errors
408
+
409
+ step_types = ["if", "parallel", "sequence", "task", "loop"]
410
+ found_types = [t for t in step_types if t in step]
411
+
412
+ if len(found_types) == 0:
413
+ errors.append(f"Step must contain one of: {step_types}")
414
+ elif len(found_types) > 1:
415
+ errors.append(f"Step can only contain one type, found: {found_types}")
416
+
417
+ # Validate specific step types
418
+ if "if" in step:
419
+ if "then" not in step:
420
+ errors.append("'if' step must have 'then' clause")
421
+
422
+ if "parallel" in step:
423
+ if not isinstance(step["parallel"], list):
424
+ errors.append("'parallel' must be a list of task names")
425
+
426
+ if "sequence" in step:
427
+ if not isinstance(step["sequence"], list):
428
+ errors.append("'sequence' must be a list of steps")
429
+
430
+ if "loop" in step:
431
+ loop_config = step["loop"]
432
+ if not isinstance(loop_config, dict):
433
+ errors.append("'loop' must be a dictionary")
434
+ elif "steps" not in loop_config:
435
+ errors.append("'loop' must have 'steps' field")
436
+
437
+ return errors
438
+
439
+ def get_supported_features(self) -> Dict[str, Any]:
440
+ """Get supported DSL features"""
441
+ return {
442
+ "step_types": ["if", "parallel", "sequence", "task", "loop"],
443
+ "condition_types": [
444
+ "intent.includes('category')",
445
+ "context.field == value",
446
+ "input.field == value",
447
+ "result[index].field == value"
448
+ ],
449
+ "operators": ["==", "!=", ">", "<", ">=", "<="],
450
+ "logical_operators": ["AND", "OR"],
451
+ "supported_value_types": ["string", "number", "boolean", "null"],
452
+ "condition_check_order": self.condition_check_order,
453
+ "regex_matching": "fullmatch (exact matching)",
454
+ "improvements": [
455
+ "Use re.fullmatch instead of re.match for stricter matching",
456
+ "Optimize condition check order: AND -> OR -> intent.includes -> context -> input -> result",
457
+ "Enhance value parsing robustness, support null values",
458
+ "Add condition syntax validation method"
459
+ ]
460
+ }
@@ -0,0 +1,50 @@
1
+ from typing import Any, Dict, List, Optional
2
+ from datetime import datetime
3
+
4
+
5
+ class TaskContext:
6
+ """Task context model"""
7
+ def __init__(self, user_id: str, task_id: str, session_id: Optional[str] = None,
8
+ metadata: Optional[Dict[str, Any]] = None):
9
+ self.user_id = user_id
10
+ self.task_id = task_id
11
+ self.session_id = session_id
12
+ self.metadata = metadata or {}
13
+ self.created_at = datetime.now()
14
+ self.variables = {} # Variable storage during task execution
15
+
16
+ def set_variable(self, key: str, value: Any):
17
+ """Set task variable"""
18
+ self.variables[key] = value
19
+
20
+ def get_variable(self, key: str, default: Any = None) -> Any:
21
+ """Get task variable"""
22
+ return self.variables.get(key, default)
23
+
24
+ def dict(self) -> Dict[str, Any]:
25
+ return {
26
+ "user_id": self.user_id,
27
+ "task_id": self.task_id,
28
+ "session_id": self.session_id,
29
+ "metadata": self.metadata,
30
+ "created_at": self.created_at.isoformat(),
31
+ "variables": self.variables
32
+ }
33
+
34
+
35
+ class DSLStep:
36
+ """DSL step model"""
37
+ def __init__(self, step_type: str, condition: Optional[str] = None,
38
+ description: str = "", params: Optional[Dict[str, Any]] = None):
39
+ self.step_type = step_type
40
+ self.condition = condition
41
+ self.description = description
42
+ self.params = params or {}
43
+
44
+ def dict(self) -> Dict[str, Any]:
45
+ return {
46
+ "step_type": self.step_type,
47
+ "condition": self.condition,
48
+ "description": self.description,
49
+ "params": self.params
50
+ }