kailash 0.3.0__py3-none-any.whl → 0.3.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 (114) hide show
  1. kailash/__init__.py +1 -1
  2. kailash/access_control.py +40 -39
  3. kailash/api/auth.py +26 -32
  4. kailash/api/custom_nodes.py +29 -29
  5. kailash/api/custom_nodes_secure.py +35 -35
  6. kailash/api/database.py +17 -17
  7. kailash/api/gateway.py +19 -19
  8. kailash/api/mcp_integration.py +24 -23
  9. kailash/api/studio.py +45 -45
  10. kailash/api/workflow_api.py +8 -8
  11. kailash/cli/commands.py +5 -8
  12. kailash/manifest.py +42 -42
  13. kailash/mcp/__init__.py +1 -1
  14. kailash/mcp/ai_registry_server.py +20 -20
  15. kailash/mcp/client.py +9 -11
  16. kailash/mcp/client_new.py +10 -10
  17. kailash/mcp/server.py +1 -2
  18. kailash/mcp/server_enhanced.py +449 -0
  19. kailash/mcp/servers/ai_registry.py +6 -6
  20. kailash/mcp/utils/__init__.py +31 -0
  21. kailash/mcp/utils/cache.py +267 -0
  22. kailash/mcp/utils/config.py +263 -0
  23. kailash/mcp/utils/formatters.py +293 -0
  24. kailash/mcp/utils/metrics.py +418 -0
  25. kailash/nodes/ai/agents.py +9 -9
  26. kailash/nodes/ai/ai_providers.py +33 -34
  27. kailash/nodes/ai/embedding_generator.py +31 -32
  28. kailash/nodes/ai/intelligent_agent_orchestrator.py +62 -66
  29. kailash/nodes/ai/iterative_llm_agent.py +48 -48
  30. kailash/nodes/ai/llm_agent.py +32 -33
  31. kailash/nodes/ai/models.py +13 -13
  32. kailash/nodes/ai/self_organizing.py +44 -44
  33. kailash/nodes/api/auth.py +11 -11
  34. kailash/nodes/api/graphql.py +13 -13
  35. kailash/nodes/api/http.py +19 -19
  36. kailash/nodes/api/monitoring.py +20 -20
  37. kailash/nodes/api/rate_limiting.py +9 -13
  38. kailash/nodes/api/rest.py +29 -29
  39. kailash/nodes/api/security.py +44 -47
  40. kailash/nodes/base.py +21 -23
  41. kailash/nodes/base_async.py +7 -7
  42. kailash/nodes/base_cycle_aware.py +12 -12
  43. kailash/nodes/base_with_acl.py +5 -5
  44. kailash/nodes/code/python.py +56 -55
  45. kailash/nodes/data/directory.py +6 -6
  46. kailash/nodes/data/event_generation.py +10 -10
  47. kailash/nodes/data/file_discovery.py +28 -31
  48. kailash/nodes/data/readers.py +8 -8
  49. kailash/nodes/data/retrieval.py +10 -10
  50. kailash/nodes/data/sharepoint_graph.py +17 -17
  51. kailash/nodes/data/sources.py +5 -5
  52. kailash/nodes/data/sql.py +13 -13
  53. kailash/nodes/data/streaming.py +25 -25
  54. kailash/nodes/data/vector_db.py +22 -22
  55. kailash/nodes/data/writers.py +7 -7
  56. kailash/nodes/logic/async_operations.py +17 -17
  57. kailash/nodes/logic/convergence.py +11 -11
  58. kailash/nodes/logic/loop.py +4 -4
  59. kailash/nodes/logic/operations.py +11 -11
  60. kailash/nodes/logic/workflow.py +8 -9
  61. kailash/nodes/mixins/mcp.py +17 -17
  62. kailash/nodes/mixins.py +8 -10
  63. kailash/nodes/transform/chunkers.py +3 -3
  64. kailash/nodes/transform/formatters.py +7 -7
  65. kailash/nodes/transform/processors.py +10 -10
  66. kailash/runtime/access_controlled.py +18 -18
  67. kailash/runtime/async_local.py +17 -19
  68. kailash/runtime/docker.py +20 -22
  69. kailash/runtime/local.py +16 -16
  70. kailash/runtime/parallel.py +23 -23
  71. kailash/runtime/parallel_cyclic.py +27 -27
  72. kailash/runtime/runner.py +6 -6
  73. kailash/runtime/testing.py +20 -20
  74. kailash/sdk_exceptions.py +0 -58
  75. kailash/security.py +14 -26
  76. kailash/tracking/manager.py +38 -38
  77. kailash/tracking/metrics_collector.py +15 -14
  78. kailash/tracking/models.py +53 -53
  79. kailash/tracking/storage/base.py +7 -17
  80. kailash/tracking/storage/database.py +22 -23
  81. kailash/tracking/storage/filesystem.py +38 -40
  82. kailash/utils/export.py +21 -21
  83. kailash/utils/templates.py +2 -3
  84. kailash/visualization/api.py +30 -34
  85. kailash/visualization/dashboard.py +17 -17
  86. kailash/visualization/performance.py +16 -16
  87. kailash/visualization/reports.py +25 -27
  88. kailash/workflow/builder.py +8 -8
  89. kailash/workflow/convergence.py +13 -12
  90. kailash/workflow/cycle_analyzer.py +30 -32
  91. kailash/workflow/cycle_builder.py +12 -12
  92. kailash/workflow/cycle_config.py +16 -15
  93. kailash/workflow/cycle_debugger.py +40 -40
  94. kailash/workflow/cycle_exceptions.py +29 -29
  95. kailash/workflow/cycle_profiler.py +21 -21
  96. kailash/workflow/cycle_state.py +20 -22
  97. kailash/workflow/cyclic_runner.py +44 -44
  98. kailash/workflow/graph.py +40 -40
  99. kailash/workflow/mermaid_visualizer.py +9 -11
  100. kailash/workflow/migration.py +22 -22
  101. kailash/workflow/mock_registry.py +6 -6
  102. kailash/workflow/runner.py +9 -9
  103. kailash/workflow/safety.py +12 -13
  104. kailash/workflow/state.py +8 -11
  105. kailash/workflow/templates.py +19 -19
  106. kailash/workflow/validation.py +14 -14
  107. kailash/workflow/visualization.py +22 -22
  108. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/METADATA +53 -5
  109. kailash-0.3.1.dist-info/RECORD +136 -0
  110. kailash-0.3.0.dist-info/RECORD +0 -130
  111. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/WHEEL +0 -0
  112. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/entry_points.txt +0 -0
  113. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/licenses/LICENSE +0 -0
  114. {kailash-0.3.0.dist-info → kailash-0.3.1.dist-info}/top_level.txt +0 -0
@@ -7,7 +7,7 @@ replace generic errors with detailed diagnostics to improve developer experience
7
7
  """
8
8
 
9
9
  import logging
10
- from typing import Any, Dict, List, Optional
10
+ from typing import Any
11
11
 
12
12
  from kailash.sdk_exceptions import WorkflowException
13
13
 
@@ -55,9 +55,9 @@ class CycleException(WorkflowException):
55
55
  self,
56
56
  message: str,
57
57
  error_code: str = "CYCLE_ERROR",
58
- context: Optional[Dict[str, Any]] = None,
59
- suggestions: Optional[List[str]] = None,
60
- documentation_url: Optional[str] = None,
58
+ context: dict[str, Any] | None = None,
59
+ suggestions: list[str] | None = None,
60
+ documentation_url: str | None = None,
61
61
  ):
62
62
  """
63
63
  Initialize cycle exception with enhanced error information.
@@ -148,8 +148,8 @@ class CycleConfigurationError(CycleException):
148
148
  def __init__(
149
149
  self,
150
150
  message: str,
151
- cycle_id: Optional[str] = None,
152
- invalid_params: Optional[Dict[str, Any]] = None,
151
+ cycle_id: str | None = None,
152
+ invalid_params: dict[str, Any] | None = None,
153
153
  **kwargs,
154
154
  ):
155
155
  """
@@ -216,10 +216,10 @@ class CycleConnectionError(CycleException):
216
216
  def __init__(
217
217
  self,
218
218
  message: str,
219
- source_node: Optional[str] = None,
220
- target_node: Optional[str] = None,
221
- available_nodes: Optional[List[str]] = None,
222
- mapping_errors: Optional[Dict[str, str]] = None,
219
+ source_node: str | None = None,
220
+ target_node: str | None = None,
221
+ available_nodes: list[str] | None = None,
222
+ mapping_errors: dict[str, str] | None = None,
223
223
  **kwargs,
224
224
  ):
225
225
  """
@@ -294,9 +294,9 @@ class CycleValidationError(CycleException):
294
294
  def __init__(
295
295
  self,
296
296
  message: str,
297
- cycle_group: Optional[str] = None,
298
- validation_failures: Optional[List[str]] = None,
299
- conflicting_values: Optional[List[Any]] = None,
297
+ cycle_group: str | None = None,
298
+ validation_failures: list[str] | None = None,
299
+ conflicting_values: list[Any] | None = None,
300
300
  **kwargs,
301
301
  ):
302
302
  """
@@ -365,11 +365,11 @@ class CycleExecutionError(CycleException):
365
365
  def __init__(
366
366
  self,
367
367
  message: str,
368
- cycle_id: Optional[str] = None,
369
- current_iteration: Optional[int] = None,
370
- max_iterations: Optional[int] = None,
371
- timeout_seconds: Optional[float] = None,
372
- memory_usage_mb: Optional[int] = None,
368
+ cycle_id: str | None = None,
369
+ current_iteration: int | None = None,
370
+ max_iterations: int | None = None,
371
+ timeout_seconds: float | None = None,
372
+ memory_usage_mb: int | None = None,
373
373
  **kwargs,
374
374
  ):
375
375
  """
@@ -465,10 +465,10 @@ class CycleConvergenceError(CycleException):
465
465
  def __init__(
466
466
  self,
467
467
  message: str,
468
- convergence_expression: Optional[str] = None,
469
- evaluation_error: Optional[str] = None,
470
- available_variables: Optional[List[str]] = None,
471
- cycle_data: Optional[Dict[str, Any]] = None,
468
+ convergence_expression: str | None = None,
469
+ evaluation_error: str | None = None,
470
+ available_variables: list[str] | None = None,
471
+ cycle_data: dict[str, Any] | None = None,
472
472
  **kwargs,
473
473
  ):
474
474
  """
@@ -523,7 +523,7 @@ class CycleConvergenceError(CycleException):
523
523
 
524
524
  # Utility functions for enhanced error reporting
525
525
  def create_configuration_error(
526
- issue: str, cycle_id: Optional[str] = None, **invalid_params
526
+ issue: str, cycle_id: str | None = None, **invalid_params
527
527
  ) -> CycleConfigurationError:
528
528
  """
529
529
  Create a standardized configuration error with common suggestions.
@@ -550,9 +550,9 @@ def create_configuration_error(
550
550
 
551
551
  def create_connection_error(
552
552
  issue: str,
553
- source_node: Optional[str] = None,
554
- target_node: Optional[str] = None,
555
- available_nodes: Optional[List[str]] = None,
553
+ source_node: str | None = None,
554
+ target_node: str | None = None,
555
+ available_nodes: list[str] | None = None,
556
556
  ) -> CycleConnectionError:
557
557
  """
558
558
  Create a standardized connection error with node context.
@@ -583,9 +583,9 @@ def create_connection_error(
583
583
 
584
584
  def create_execution_error(
585
585
  issue: str,
586
- cycle_id: Optional[str] = None,
587
- current_iteration: Optional[int] = None,
588
- max_iterations: Optional[int] = None,
586
+ cycle_id: str | None = None,
587
+ current_iteration: int | None = None,
588
+ max_iterations: int | None = None,
589
589
  ) -> CycleExecutionError:
590
590
  """
591
591
  Create a standardized execution error with runtime context.
@@ -45,7 +45,7 @@ import logging
45
45
  import statistics
46
46
  from dataclasses import dataclass, field
47
47
  from datetime import datetime
48
- from typing import Any, Dict, List, Optional, Tuple
48
+ from typing import Any
49
49
 
50
50
  from kailash.workflow.cycle_debugger import CycleExecutionTrace
51
51
 
@@ -83,13 +83,13 @@ class PerformanceMetrics:
83
83
  min_iteration_time: float = float("inf")
84
84
  max_iteration_time: float = 0.0
85
85
  iteration_time_stddev: float = 0.0
86
- memory_stats: Dict[str, float] = field(default_factory=dict)
87
- cpu_stats: Dict[str, float] = field(default_factory=dict)
88
- convergence_stats: Dict[str, Any] = field(default_factory=dict)
89
- bottlenecks: List[str] = field(default_factory=list)
90
- optimization_opportunities: List[str] = field(default_factory=list)
86
+ memory_stats: dict[str, float] = field(default_factory=dict)
87
+ cpu_stats: dict[str, float] = field(default_factory=dict)
88
+ convergence_stats: dict[str, Any] = field(default_factory=dict)
89
+ bottlenecks: list[str] = field(default_factory=list)
90
+ optimization_opportunities: list[str] = field(default_factory=list)
91
91
 
92
- def to_dict(self) -> Dict[str, Any]:
92
+ def to_dict(self) -> dict[str, Any]:
93
93
  """Convert metrics to dictionary for serialization.
94
94
 
95
95
  Returns:
@@ -141,8 +141,8 @@ class CycleProfiler:
141
141
  enable_advanced_metrics: Whether to enable advanced statistical analysis.
142
142
  """
143
143
  self.enable_advanced_metrics = enable_advanced_metrics
144
- self.traces: List[CycleExecutionTrace] = []
145
- self.performance_history: List[PerformanceMetrics] = []
144
+ self.traces: list[CycleExecutionTrace] = []
145
+ self.performance_history: list[PerformanceMetrics] = []
146
146
 
147
147
  def add_trace(self, trace: CycleExecutionTrace):
148
148
  """
@@ -260,7 +260,7 @@ class CycleProfiler:
260
260
 
261
261
  return metrics
262
262
 
263
- def compare_cycles(self, cycle_ids: List[str]) -> Dict[str, Any]:
263
+ def compare_cycles(self, cycle_ids: list[str]) -> dict[str, Any]:
264
264
  """
265
265
  Compare performance across multiple specific cycles.
266
266
 
@@ -338,8 +338,8 @@ class CycleProfiler:
338
338
  return comparison
339
339
 
340
340
  def get_optimization_recommendations(
341
- self, trace: Optional[CycleExecutionTrace] = None
342
- ) -> List[Dict[str, Any]]:
341
+ self, trace: CycleExecutionTrace | None = None
342
+ ) -> list[dict[str, Any]]:
343
343
  """
344
344
  Generate detailed optimization recommendations.
345
345
 
@@ -459,7 +459,7 @@ class CycleProfiler:
459
459
 
460
460
  return recommendations
461
461
 
462
- def generate_performance_report(self) -> Dict[str, Any]:
462
+ def generate_performance_report(self) -> dict[str, Any]:
463
463
  """
464
464
  Generate comprehensive performance report.
465
465
 
@@ -560,8 +560,8 @@ class CycleProfiler:
560
560
  logger.info(f"Exported profiling data to {filepath} in {format} format")
561
561
 
562
562
  def _analyze_convergence_performance(
563
- self, convergence_data: List[float]
564
- ) -> Dict[str, Any]:
563
+ self, convergence_data: list[float]
564
+ ) -> dict[str, Any]:
565
565
  """Analyze convergence performance characteristics."""
566
566
  if not convergence_data:
567
567
  return {}
@@ -582,8 +582,8 @@ class CycleProfiler:
582
582
  }
583
583
 
584
584
  def _analyze_convergence_pattern(
585
- self, convergence_trend: List[Tuple[int, Optional[float]]]
586
- ) -> Dict[str, Any]:
585
+ self, convergence_trend: list[tuple[int, float | None]]
586
+ ) -> dict[str, Any]:
587
587
  """Analyze convergence pattern for stability."""
588
588
  valid_points = [value for _, value in convergence_trend if value is not None]
589
589
 
@@ -608,7 +608,7 @@ class CycleProfiler:
608
608
  "reason": "high_volatility" if unstable else "stable",
609
609
  }
610
610
 
611
- def _identify_bottlenecks(self, metrics: PerformanceMetrics) -> List[str]:
611
+ def _identify_bottlenecks(self, metrics: PerformanceMetrics) -> list[str]:
612
612
  """Identify performance bottlenecks from metrics."""
613
613
  bottlenecks = []
614
614
 
@@ -636,7 +636,7 @@ class CycleProfiler:
636
636
 
637
637
  return bottlenecks
638
638
 
639
- def _identify_optimizations(self, metrics: PerformanceMetrics) -> List[str]:
639
+ def _identify_optimizations(self, metrics: PerformanceMetrics) -> list[str]:
640
640
  """Identify optimization opportunities."""
641
641
  optimizations = []
642
642
 
@@ -697,7 +697,7 @@ class CycleProfiler:
697
697
 
698
698
  return statistics.mean(score_components) if score_components else 0.5
699
699
 
700
- def _analyze_performance_trends(self) -> Dict[str, Any]:
700
+ def _analyze_performance_trends(self) -> dict[str, Any]:
701
701
  """Analyze performance trends over time."""
702
702
  if len(self.performance_history) < 2:
703
703
  return {"trend": "insufficient_data"}
@@ -720,7 +720,7 @@ class CycleProfiler:
720
720
  "performance_history_length": len(self.performance_history),
721
721
  }
722
722
 
723
- def _get_cycle_comparisons(self) -> Dict[str, Any]:
723
+ def _get_cycle_comparisons(self) -> dict[str, Any]:
724
724
  """Get comparative analysis across all cycles."""
725
725
  if len(self.traces) < 2:
726
726
  return {"comparison": "insufficient_data"}
@@ -2,8 +2,8 @@
2
2
 
3
3
  import logging
4
4
  import time
5
- from datetime import datetime, timezone
6
- from typing import Any, Dict, List, Optional
5
+ from datetime import UTC, datetime
6
+ from typing import Any
7
7
 
8
8
  logger = logging.getLogger(__name__)
9
9
 
@@ -19,11 +19,11 @@ class CycleState:
19
19
  """
20
20
  self.cycle_id = cycle_id
21
21
  self.iteration = 0
22
- self.history: List[Dict[str, Any]] = []
23
- self.metadata: Dict[str, Any] = {}
22
+ self.history: list[dict[str, Any]] = []
23
+ self.metadata: dict[str, Any] = {}
24
24
  self.start_time = time.time()
25
25
  self.last_update_time = self.start_time
26
- self.node_states: Dict[str, Any] = {} # Per-node state storage
26
+ self.node_states: dict[str, Any] = {} # Per-node state storage
27
27
 
28
28
  @property
29
29
  def elapsed_time(self) -> float:
@@ -35,7 +35,7 @@ class CycleState:
35
35
  """Get time since last iteration."""
36
36
  return time.time() - self.last_update_time
37
37
 
38
- def update(self, results: Dict[str, Any], iteration: Optional[int] = None) -> None:
38
+ def update(self, results: dict[str, Any], iteration: int | None = None) -> None:
39
39
  """Update state with iteration results.
40
40
 
41
41
  Args:
@@ -51,7 +51,7 @@ class CycleState:
51
51
  history_entry = {
52
52
  "iteration": self.iteration,
53
53
  "results": results,
54
- "timestamp": datetime.now(timezone.utc).isoformat(),
54
+ "timestamp": datetime.now(UTC).isoformat(),
55
55
  "elapsed_time": self.elapsed_time,
56
56
  "iteration_time": self.iteration_time,
57
57
  }
@@ -90,7 +90,7 @@ class CycleState:
90
90
  """
91
91
  self.node_states[node_id] = state
92
92
 
93
- def get_convergence_context(self) -> Dict[str, Any]:
93
+ def get_convergence_context(self) -> dict[str, Any]:
94
94
  """Get context for convergence evaluation.
95
95
 
96
96
  Returns:
@@ -110,7 +110,7 @@ class CycleState:
110
110
 
111
111
  return context
112
112
 
113
- def calculate_trend(self) -> Dict[str, Any]:
113
+ def calculate_trend(self) -> dict[str, Any]:
114
114
  """Calculate trends from iteration history.
115
115
 
116
116
  Returns:
@@ -159,7 +159,7 @@ class CycleState:
159
159
 
160
160
  return trends
161
161
 
162
- def _extract_numeric_keys(self, obj: Any, prefix: str = "") -> List[str]:
162
+ def _extract_numeric_keys(self, obj: Any, prefix: str = "") -> list[str]:
163
163
  """Extract all numeric value keys from nested dict."""
164
164
  keys = []
165
165
 
@@ -186,7 +186,7 @@ class CycleState:
186
186
 
187
187
  return value
188
188
 
189
- def get_summary(self) -> Dict[str, Any]:
189
+ def get_summary(self) -> dict[str, Any]:
190
190
  """Get summary of cycle execution.
191
191
 
192
192
  Returns:
@@ -196,9 +196,7 @@ class CycleState:
196
196
  "cycle_id": self.cycle_id,
197
197
  "iterations": self.iteration,
198
198
  "elapsed_time": self.elapsed_time,
199
- "start_time": datetime.fromtimestamp(
200
- self.start_time, timezone.utc
201
- ).isoformat(),
199
+ "start_time": datetime.fromtimestamp(self.start_time, UTC).isoformat(),
202
200
  "history_length": len(self.history),
203
201
  }
204
202
 
@@ -223,7 +221,7 @@ class CycleState:
223
221
 
224
222
  return summary
225
223
 
226
- def to_dict(self) -> Dict[str, Any]:
224
+ def to_dict(self) -> dict[str, Any]:
227
225
  """Serialize state to dictionary.
228
226
 
229
227
  Returns:
@@ -240,7 +238,7 @@ class CycleState:
240
238
  }
241
239
 
242
240
  @classmethod
243
- def from_dict(cls, data: Dict[str, Any]) -> "CycleState":
241
+ def from_dict(cls, data: dict[str, Any]) -> "CycleState":
244
242
  """Create CycleState from dictionary.
245
243
 
246
244
  Args:
@@ -264,8 +262,8 @@ class CycleStateManager:
264
262
 
265
263
  def __init__(self):
266
264
  """Initialize cycle state manager."""
267
- self.states: Dict[str, CycleState] = {}
268
- self.active_cycles: List[str] = []
265
+ self.states: dict[str, CycleState] = {}
266
+ self.active_cycles: list[str] = []
269
267
 
270
268
  def get_or_create_state(self, cycle_id: str) -> CycleState:
271
269
  """Get existing state or create new one.
@@ -291,7 +289,7 @@ class CycleStateManager:
291
289
  self.active_cycles.append(cycle_id)
292
290
  logger.debug(f"Pushed cycle: {cycle_id}, stack: {self.active_cycles}")
293
291
 
294
- def pop_cycle(self) -> Optional[str]:
292
+ def pop_cycle(self) -> str | None:
295
293
  """Pop cycle from active stack.
296
294
 
297
295
  Returns:
@@ -303,7 +301,7 @@ class CycleStateManager:
303
301
  return cycle_id
304
302
  return None
305
303
 
306
- def get_active_cycle(self) -> Optional[str]:
304
+ def get_active_cycle(self) -> str | None:
307
305
  """Get currently active cycle ID.
308
306
 
309
307
  Returns:
@@ -311,7 +309,7 @@ class CycleStateManager:
311
309
  """
312
310
  return self.active_cycles[-1] if self.active_cycles else None
313
311
 
314
- def get_all_summaries(self) -> Dict[str, Dict[str, Any]]:
312
+ def get_all_summaries(self) -> dict[str, dict[str, Any]]:
315
313
  """Get summaries for all cycles.
316
314
 
317
315
  Returns:
@@ -321,7 +319,7 @@ class CycleStateManager:
321
319
  cycle_id: state.get_summary() for cycle_id, state in self.states.items()
322
320
  }
323
321
 
324
- def clear(self, cycle_id: Optional[str] = None) -> None:
322
+ def clear(self, cycle_id: str | None = None) -> None:
325
323
  """Clear cycle state(s).
326
324
 
327
325
  Args:
@@ -99,8 +99,8 @@ See Also:
99
99
  """
100
100
 
101
101
  import logging
102
- from datetime import datetime, timezone
103
- from typing import Any, Dict, List, Optional, Set, Tuple
102
+ from datetime import UTC, datetime
103
+ from typing import Any, Optional
104
104
 
105
105
  import networkx as nx
106
106
 
@@ -127,15 +127,15 @@ class WorkflowState:
127
127
  run_id: Unique execution run ID
128
128
  """
129
129
  self.run_id = run_id
130
- self.node_outputs: Dict[str, Any] = {}
131
- self.execution_order: List[str] = []
132
- self.metadata: Dict[str, Any] = {}
130
+ self.node_outputs: dict[str, Any] = {}
131
+ self.execution_order: list[str] = []
132
+ self.metadata: dict[str, Any] = {}
133
133
 
134
134
 
135
135
  class CyclicWorkflowExecutor:
136
136
  """Execution engine supporting cyclic workflows with fixed parameter propagation."""
137
137
 
138
- def __init__(self, safety_manager: Optional[CycleSafetyManager] = None):
138
+ def __init__(self, safety_manager: CycleSafetyManager | None = None):
139
139
  """Initialize cyclic workflow executor.
140
140
 
141
141
  Args:
@@ -148,10 +148,10 @@ class CyclicWorkflowExecutor:
148
148
  def execute(
149
149
  self,
150
150
  workflow: Workflow,
151
- parameters: Optional[Dict[str, Any]] = None,
152
- task_manager: Optional[TaskManager] = None,
153
- run_id: Optional[str] = None,
154
- ) -> Tuple[Dict[str, Any], str]:
151
+ parameters: dict[str, Any] | None = None,
152
+ task_manager: TaskManager | None = None,
153
+ run_id: str | None = None,
154
+ ) -> tuple[dict[str, Any], str]:
155
155
  """Execute workflow with cycle support.
156
156
 
157
157
  Args:
@@ -223,10 +223,10 @@ class CyclicWorkflowExecutor:
223
223
  def _execute_with_cycles(
224
224
  self,
225
225
  workflow: Workflow,
226
- parameters: Optional[Dict[str, Any]],
226
+ parameters: dict[str, Any] | None,
227
227
  run_id: str,
228
- task_manager: Optional[TaskManager] = None,
229
- ) -> Dict[str, Any]:
228
+ task_manager: TaskManager | None = None,
229
+ ) -> dict[str, Any]:
230
230
  """Execute workflow with cycle handling.
231
231
 
232
232
  Args:
@@ -264,8 +264,8 @@ class CyclicWorkflowExecutor:
264
264
  def _create_execution_plan(
265
265
  self,
266
266
  workflow: Workflow,
267
- dag_edges: List[Tuple],
268
- cycle_groups: Dict[str, List[Tuple]],
267
+ dag_edges: list[tuple],
268
+ cycle_groups: dict[str, list[tuple]],
269
269
  ) -> "ExecutionPlan":
270
270
  """Create execution plan handling cycles.
271
271
 
@@ -329,8 +329,8 @@ class CyclicWorkflowExecutor:
329
329
  workflow: Workflow,
330
330
  plan: "ExecutionPlan",
331
331
  state: WorkflowState,
332
- task_manager: Optional[TaskManager] = None,
333
- ) -> Dict[str, Any]:
332
+ task_manager: TaskManager | None = None,
333
+ ) -> dict[str, Any]:
334
334
  """Execute the workflow plan.
335
335
 
336
336
  Args:
@@ -377,8 +377,8 @@ class CyclicWorkflowExecutor:
377
377
  workflow: Workflow,
378
378
  cycle_group: "CycleGroup",
379
379
  state: WorkflowState,
380
- task_manager: Optional[TaskManager] = None,
381
- ) -> Dict[str, Any]:
380
+ task_manager: TaskManager | None = None,
381
+ ) -> dict[str, Any]:
382
382
  """Execute a cycle group with proper parameter propagation.
383
383
 
384
384
  Args:
@@ -432,7 +432,7 @@ class CyclicWorkflowExecutor:
432
432
  run_id=state.run_id,
433
433
  node_id=f"cycle_group_{cycle_id}",
434
434
  node_type="CycleGroup",
435
- started_at=datetime.now(timezone.utc),
435
+ started_at=datetime.now(UTC),
436
436
  metadata={
437
437
  "cycle_id": cycle_id,
438
438
  "max_iterations": cycle_config.get("max_iterations"),
@@ -463,7 +463,7 @@ class CyclicWorkflowExecutor:
463
463
  run_id=state.run_id,
464
464
  node_id=f"cycle_{cycle_id}_iteration_{loop_count}",
465
465
  node_type="CycleIteration",
466
- started_at=datetime.now(timezone.utc),
466
+ started_at=datetime.now(UTC),
467
467
  metadata={
468
468
  "cycle_id": cycle_id,
469
469
  "iteration": loop_count,
@@ -552,7 +552,7 @@ class CyclicWorkflowExecutor:
552
552
  task_manager.update_task_status(
553
553
  iteration_task_id,
554
554
  TaskStatus.COMPLETED,
555
- ended_at=datetime.now(timezone.utc),
555
+ ended_at=datetime.now(UTC),
556
556
  result=iteration_results,
557
557
  metadata={
558
558
  "converged": (
@@ -579,7 +579,7 @@ class CyclicWorkflowExecutor:
579
579
  task_manager.update_task_status(
580
580
  cycle_task_id,
581
581
  TaskStatus.COMPLETED,
582
- ended_at=datetime.now(timezone.utc),
582
+ ended_at=datetime.now(UTC),
583
583
  result=results,
584
584
  metadata={
585
585
  "total_iterations": loop_count,
@@ -603,11 +603,11 @@ class CyclicWorkflowExecutor:
603
603
  workflow: Workflow,
604
604
  node_id: str,
605
605
  state: WorkflowState,
606
- cycle_state: Optional[CycleState] = None,
607
- cycle_edges: Optional[List[Tuple]] = None,
608
- previous_iteration_results: Optional[Dict[str, Any]] = None,
609
- task_manager: Optional[TaskManager] = None,
610
- iteration: Optional[int] = None,
606
+ cycle_state: CycleState | None = None,
607
+ cycle_edges: list[tuple] | None = None,
608
+ previous_iteration_results: dict[str, Any] | None = None,
609
+ task_manager: TaskManager | None = None,
610
+ iteration: int | None = None,
611
611
  ) -> Any:
612
612
  """Execute a single node with proper parameter handling for cycles.
613
613
 
@@ -757,7 +757,7 @@ class CyclicWorkflowExecutor:
757
757
  run_id=state.run_id,
758
758
  node_id=task_node_id,
759
759
  node_type=node.__class__.__name__,
760
- started_at=datetime.now(timezone.utc),
760
+ started_at=datetime.now(UTC),
761
761
  metadata=task_metadata,
762
762
  )
763
763
  if task:
@@ -794,7 +794,7 @@ class CyclicWorkflowExecutor:
794
794
  task.task_id,
795
795
  TaskStatus.COMPLETED,
796
796
  result=result,
797
- ended_at=datetime.now(timezone.utc),
797
+ ended_at=datetime.now(UTC),
798
798
  metadata={"execution_time": performance_metrics.duration},
799
799
  )
800
800
 
@@ -811,7 +811,7 @@ class CyclicWorkflowExecutor:
811
811
  task.task_id,
812
812
  TaskStatus.FAILED,
813
813
  error=str(e),
814
- ended_at=datetime.now(timezone.utc),
814
+ ended_at=datetime.now(UTC),
815
815
  )
816
816
  except Exception as update_error:
817
817
  logger.warning(
@@ -831,16 +831,16 @@ class ExecutionPlan:
831
831
 
832
832
  def __init__(self):
833
833
  """Initialize execution plan."""
834
- self.stages: List["ExecutionStage"] = []
835
- self.cycle_groups: Dict[str, "CycleGroup"] = {}
834
+ self.stages: list["ExecutionStage"] = []
835
+ self.cycle_groups: dict[str, "CycleGroup"] = {}
836
836
 
837
837
  def add_cycle_group(
838
838
  self,
839
839
  cycle_id: str,
840
- nodes: Set[str],
841
- entry_nodes: Set[str],
842
- exit_nodes: Set[str],
843
- edges: List[Tuple],
840
+ nodes: set[str],
841
+ entry_nodes: set[str],
842
+ exit_nodes: set[str],
843
+ edges: list[tuple],
844
844
  ) -> None:
845
845
  """Add a cycle group to the plan.
846
846
 
@@ -859,7 +859,7 @@ class ExecutionPlan:
859
859
  edges=edges,
860
860
  )
861
861
 
862
- def build_stages(self, topo_order: List[str], dag_graph: nx.DiGraph) -> None:
862
+ def build_stages(self, topo_order: list[str], dag_graph: nx.DiGraph) -> None:
863
863
  """Build execution stages.
864
864
 
865
865
  Args:
@@ -914,7 +914,7 @@ class ExecutionStage:
914
914
  def __init__(
915
915
  self,
916
916
  is_cycle: bool,
917
- nodes: Optional[List[str]] = None,
917
+ nodes: list[str] | None = None,
918
918
  cycle_group: Optional["CycleGroup"] = None,
919
919
  ):
920
920
  """Initialize execution stage.
@@ -935,10 +935,10 @@ class CycleGroup:
935
935
  def __init__(
936
936
  self,
937
937
  cycle_id: str,
938
- nodes: Set[str],
939
- entry_nodes: Set[str],
940
- exit_nodes: Set[str],
941
- edges: List[Tuple],
938
+ nodes: set[str],
939
+ entry_nodes: set[str],
940
+ exit_nodes: set[str],
941
+ edges: list[tuple],
942
942
  ):
943
943
  """Initialize cycle group.
944
944
 
@@ -955,7 +955,7 @@ class CycleGroup:
955
955
  self.exit_nodes = exit_nodes
956
956
  self.edges = edges
957
957
 
958
- def get_execution_order(self, full_graph: nx.DiGraph) -> List[str]:
958
+ def get_execution_order(self, full_graph: nx.DiGraph) -> list[str]:
959
959
  """Get execution order for nodes in cycle.
960
960
 
961
961
  Args: