kailash 0.3.0__py3-none-any.whl → 0.3.2__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.
- kailash/access_control.py +40 -39
- kailash/api/auth.py +26 -32
- kailash/api/custom_nodes.py +29 -29
- kailash/api/custom_nodes_secure.py +35 -35
- kailash/api/database.py +17 -17
- kailash/api/gateway.py +19 -19
- kailash/api/mcp_integration.py +24 -23
- kailash/api/studio.py +45 -45
- kailash/api/workflow_api.py +8 -8
- kailash/cli/commands.py +5 -8
- kailash/manifest.py +42 -42
- kailash/mcp/__init__.py +1 -1
- kailash/mcp/ai_registry_server.py +20 -20
- kailash/mcp/client.py +9 -11
- kailash/mcp/client_new.py +10 -10
- kailash/mcp/server.py +1 -2
- kailash/mcp/server_enhanced.py +449 -0
- kailash/mcp/servers/ai_registry.py +6 -6
- kailash/mcp/utils/__init__.py +31 -0
- kailash/mcp/utils/cache.py +267 -0
- kailash/mcp/utils/config.py +263 -0
- kailash/mcp/utils/formatters.py +293 -0
- kailash/mcp/utils/metrics.py +418 -0
- kailash/nodes/ai/agents.py +9 -9
- kailash/nodes/ai/ai_providers.py +33 -34
- kailash/nodes/ai/embedding_generator.py +31 -32
- kailash/nodes/ai/intelligent_agent_orchestrator.py +62 -66
- kailash/nodes/ai/iterative_llm_agent.py +48 -48
- kailash/nodes/ai/llm_agent.py +32 -33
- kailash/nodes/ai/models.py +13 -13
- kailash/nodes/ai/self_organizing.py +44 -44
- kailash/nodes/api/auth.py +11 -11
- kailash/nodes/api/graphql.py +13 -13
- kailash/nodes/api/http.py +19 -19
- kailash/nodes/api/monitoring.py +20 -20
- kailash/nodes/api/rate_limiting.py +9 -13
- kailash/nodes/api/rest.py +29 -29
- kailash/nodes/api/security.py +44 -47
- kailash/nodes/base.py +21 -23
- kailash/nodes/base_async.py +7 -7
- kailash/nodes/base_cycle_aware.py +12 -12
- kailash/nodes/base_with_acl.py +5 -5
- kailash/nodes/code/python.py +66 -57
- kailash/nodes/data/directory.py +6 -6
- kailash/nodes/data/event_generation.py +10 -10
- kailash/nodes/data/file_discovery.py +28 -31
- kailash/nodes/data/readers.py +8 -8
- kailash/nodes/data/retrieval.py +10 -10
- kailash/nodes/data/sharepoint_graph.py +17 -17
- kailash/nodes/data/sources.py +5 -5
- kailash/nodes/data/sql.py +13 -13
- kailash/nodes/data/streaming.py +25 -25
- kailash/nodes/data/vector_db.py +22 -22
- kailash/nodes/data/writers.py +7 -7
- kailash/nodes/logic/async_operations.py +17 -17
- kailash/nodes/logic/convergence.py +11 -11
- kailash/nodes/logic/loop.py +4 -4
- kailash/nodes/logic/operations.py +11 -11
- kailash/nodes/logic/workflow.py +8 -9
- kailash/nodes/mixins/mcp.py +17 -17
- kailash/nodes/mixins.py +8 -10
- kailash/nodes/transform/chunkers.py +3 -3
- kailash/nodes/transform/formatters.py +7 -7
- kailash/nodes/transform/processors.py +10 -10
- kailash/runtime/access_controlled.py +18 -18
- kailash/runtime/async_local.py +17 -19
- kailash/runtime/docker.py +20 -22
- kailash/runtime/local.py +16 -16
- kailash/runtime/parallel.py +23 -23
- kailash/runtime/parallel_cyclic.py +27 -27
- kailash/runtime/runner.py +6 -6
- kailash/runtime/testing.py +20 -20
- kailash/sdk_exceptions.py +0 -58
- kailash/security.py +14 -26
- kailash/tracking/manager.py +38 -38
- kailash/tracking/metrics_collector.py +15 -14
- kailash/tracking/models.py +53 -53
- kailash/tracking/storage/base.py +7 -17
- kailash/tracking/storage/database.py +22 -23
- kailash/tracking/storage/filesystem.py +38 -40
- kailash/utils/export.py +21 -21
- kailash/utils/templates.py +2 -3
- kailash/visualization/api.py +30 -34
- kailash/visualization/dashboard.py +17 -17
- kailash/visualization/performance.py +16 -16
- kailash/visualization/reports.py +25 -27
- kailash/workflow/builder.py +8 -8
- kailash/workflow/convergence.py +13 -12
- kailash/workflow/cycle_analyzer.py +30 -32
- kailash/workflow/cycle_builder.py +12 -12
- kailash/workflow/cycle_config.py +16 -15
- kailash/workflow/cycle_debugger.py +40 -40
- kailash/workflow/cycle_exceptions.py +29 -29
- kailash/workflow/cycle_profiler.py +21 -21
- kailash/workflow/cycle_state.py +20 -22
- kailash/workflow/cyclic_runner.py +44 -44
- kailash/workflow/graph.py +40 -40
- kailash/workflow/mermaid_visualizer.py +9 -11
- kailash/workflow/migration.py +22 -22
- kailash/workflow/mock_registry.py +6 -6
- kailash/workflow/runner.py +9 -9
- kailash/workflow/safety.py +12 -13
- kailash/workflow/state.py +8 -11
- kailash/workflow/templates.py +19 -19
- kailash/workflow/validation.py +14 -14
- kailash/workflow/visualization.py +22 -22
- {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/METADATA +53 -5
- kailash-0.3.2.dist-info/RECORD +136 -0
- kailash-0.3.0.dist-info/RECORD +0 -130
- {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/WHEEL +0 -0
- {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/entry_points.txt +0 -0
- {kailash-0.3.0.dist-info → kailash-0.3.2.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.3.0.dist-info → kailash-0.3.2.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
|
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:
|
59
|
-
suggestions:
|
60
|
-
documentation_url:
|
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:
|
152
|
-
invalid_params:
|
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:
|
220
|
-
target_node:
|
221
|
-
available_nodes:
|
222
|
-
mapping_errors:
|
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:
|
298
|
-
validation_failures:
|
299
|
-
conflicting_values:
|
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:
|
369
|
-
current_iteration:
|
370
|
-
max_iterations:
|
371
|
-
timeout_seconds:
|
372
|
-
memory_usage_mb:
|
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:
|
469
|
-
evaluation_error:
|
470
|
-
available_variables:
|
471
|
-
cycle_data:
|
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:
|
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:
|
554
|
-
target_node:
|
555
|
-
available_nodes:
|
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:
|
587
|
-
current_iteration:
|
588
|
-
max_iterations:
|
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
|
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:
|
87
|
-
cpu_stats:
|
88
|
-
convergence_stats:
|
89
|
-
bottlenecks:
|
90
|
-
optimization_opportunities:
|
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) ->
|
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:
|
145
|
-
self.performance_history:
|
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:
|
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:
|
342
|
-
) ->
|
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) ->
|
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:
|
564
|
-
) ->
|
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:
|
586
|
-
) ->
|
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) ->
|
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) ->
|
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) ->
|
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) ->
|
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"}
|
kailash/workflow/cycle_state.py
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
import logging
|
4
4
|
import time
|
5
|
-
from datetime import
|
6
|
-
from typing import Any
|
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:
|
23
|
-
self.metadata:
|
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:
|
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:
|
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(
|
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) ->
|
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) ->
|
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 = "") ->
|
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) ->
|
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) ->
|
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:
|
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:
|
268
|
-
self.active_cycles:
|
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) ->
|
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) ->
|
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) ->
|
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:
|
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
|
103
|
-
from typing import Any,
|
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:
|
131
|
-
self.execution_order:
|
132
|
-
self.metadata:
|
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:
|
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:
|
152
|
-
task_manager:
|
153
|
-
run_id:
|
154
|
-
) ->
|
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:
|
226
|
+
parameters: dict[str, Any] | None,
|
227
227
|
run_id: str,
|
228
|
-
task_manager:
|
229
|
-
) ->
|
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:
|
268
|
-
cycle_groups:
|
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:
|
333
|
-
) ->
|
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:
|
381
|
-
) ->
|
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(
|
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(
|
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(
|
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(
|
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:
|
607
|
-
cycle_edges:
|
608
|
-
previous_iteration_results:
|
609
|
-
task_manager:
|
610
|
-
iteration:
|
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(
|
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(
|
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(
|
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:
|
835
|
-
self.cycle_groups:
|
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:
|
841
|
-
entry_nodes:
|
842
|
-
exit_nodes:
|
843
|
-
edges:
|
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:
|
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:
|
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:
|
939
|
-
entry_nodes:
|
940
|
-
exit_nodes:
|
941
|
-
edges:
|
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) ->
|
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:
|