kailash 0.1.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.
- kailash/__init__.py +31 -0
- kailash/__main__.py +11 -0
- kailash/cli/__init__.py +5 -0
- kailash/cli/commands.py +563 -0
- kailash/manifest.py +778 -0
- kailash/nodes/__init__.py +23 -0
- kailash/nodes/ai/__init__.py +26 -0
- kailash/nodes/ai/agents.py +417 -0
- kailash/nodes/ai/models.py +488 -0
- kailash/nodes/api/__init__.py +52 -0
- kailash/nodes/api/auth.py +567 -0
- kailash/nodes/api/graphql.py +480 -0
- kailash/nodes/api/http.py +598 -0
- kailash/nodes/api/rate_limiting.py +572 -0
- kailash/nodes/api/rest.py +665 -0
- kailash/nodes/base.py +1032 -0
- kailash/nodes/base_async.py +128 -0
- kailash/nodes/code/__init__.py +32 -0
- kailash/nodes/code/python.py +1021 -0
- kailash/nodes/data/__init__.py +125 -0
- kailash/nodes/data/readers.py +496 -0
- kailash/nodes/data/sharepoint_graph.py +623 -0
- kailash/nodes/data/sql.py +380 -0
- kailash/nodes/data/streaming.py +1168 -0
- kailash/nodes/data/vector_db.py +964 -0
- kailash/nodes/data/writers.py +529 -0
- kailash/nodes/logic/__init__.py +6 -0
- kailash/nodes/logic/async_operations.py +702 -0
- kailash/nodes/logic/operations.py +551 -0
- kailash/nodes/transform/__init__.py +5 -0
- kailash/nodes/transform/processors.py +379 -0
- kailash/runtime/__init__.py +6 -0
- kailash/runtime/async_local.py +356 -0
- kailash/runtime/docker.py +697 -0
- kailash/runtime/local.py +434 -0
- kailash/runtime/parallel.py +557 -0
- kailash/runtime/runner.py +110 -0
- kailash/runtime/testing.py +347 -0
- kailash/sdk_exceptions.py +307 -0
- kailash/tracking/__init__.py +7 -0
- kailash/tracking/manager.py +885 -0
- kailash/tracking/metrics_collector.py +342 -0
- kailash/tracking/models.py +535 -0
- kailash/tracking/storage/__init__.py +0 -0
- kailash/tracking/storage/base.py +113 -0
- kailash/tracking/storage/database.py +619 -0
- kailash/tracking/storage/filesystem.py +543 -0
- kailash/utils/__init__.py +0 -0
- kailash/utils/export.py +924 -0
- kailash/utils/templates.py +680 -0
- kailash/visualization/__init__.py +62 -0
- kailash/visualization/api.py +732 -0
- kailash/visualization/dashboard.py +951 -0
- kailash/visualization/performance.py +808 -0
- kailash/visualization/reports.py +1471 -0
- kailash/workflow/__init__.py +15 -0
- kailash/workflow/builder.py +245 -0
- kailash/workflow/graph.py +827 -0
- kailash/workflow/mermaid_visualizer.py +628 -0
- kailash/workflow/mock_registry.py +63 -0
- kailash/workflow/runner.py +302 -0
- kailash/workflow/state.py +238 -0
- kailash/workflow/visualization.py +588 -0
- kailash-0.1.0.dist-info/METADATA +710 -0
- kailash-0.1.0.dist-info/RECORD +69 -0
- kailash-0.1.0.dist-info/WHEEL +5 -0
- kailash-0.1.0.dist-info/entry_points.txt +2 -0
- kailash-0.1.0.dist-info/licenses/LICENSE +21 -0
- kailash-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
"""Workflow system for the Kailash SDK."""
|
2
|
+
|
3
|
+
from kailash.workflow.builder import WorkflowBuilder
|
4
|
+
from kailash.workflow.graph import Connection, NodeInstance, Workflow
|
5
|
+
from kailash.workflow.mermaid_visualizer import MermaidVisualizer
|
6
|
+
from kailash.workflow.visualization import WorkflowVisualizer
|
7
|
+
|
8
|
+
__all__ = [
|
9
|
+
"Workflow",
|
10
|
+
"NodeInstance",
|
11
|
+
"Connection",
|
12
|
+
"WorkflowVisualizer",
|
13
|
+
"MermaidVisualizer",
|
14
|
+
"WorkflowBuilder",
|
15
|
+
]
|
@@ -0,0 +1,245 @@
|
|
1
|
+
"""Workflow builder implementation for the Kailash SDK."""
|
2
|
+
|
3
|
+
import logging
|
4
|
+
import uuid
|
5
|
+
from typing import Any, Dict, List, Optional
|
6
|
+
|
7
|
+
from kailash.sdk_exceptions import ConnectionError, WorkflowValidationError
|
8
|
+
from kailash.workflow.graph import Workflow
|
9
|
+
|
10
|
+
logger = logging.getLogger(__name__)
|
11
|
+
|
12
|
+
|
13
|
+
class WorkflowBuilder:
|
14
|
+
"""Builder pattern for creating Workflow instances."""
|
15
|
+
|
16
|
+
def __init__(self):
|
17
|
+
"""Initialize an empty workflow builder."""
|
18
|
+
self.nodes: Dict[str, Dict[str, Any]] = {}
|
19
|
+
self.connections: List[Dict[str, str]] = []
|
20
|
+
self._metadata: Dict[str, Any] = {}
|
21
|
+
|
22
|
+
def add_node(
|
23
|
+
self,
|
24
|
+
node_type: str,
|
25
|
+
node_id: Optional[str] = None,
|
26
|
+
config: Optional[Dict[str, Any]] = None,
|
27
|
+
) -> str:
|
28
|
+
"""
|
29
|
+
Add a node to the workflow.
|
30
|
+
|
31
|
+
Args:
|
32
|
+
node_type: Node type name
|
33
|
+
node_id: Unique identifier for this node (auto-generated if not provided)
|
34
|
+
config: Configuration for the node
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
Node ID (useful for method chaining)
|
38
|
+
|
39
|
+
Raises:
|
40
|
+
WorkflowValidationError: If node_id is already used
|
41
|
+
"""
|
42
|
+
# Generate ID if not provided
|
43
|
+
if node_id is None:
|
44
|
+
node_id = f"node_{uuid.uuid4().hex[:8]}"
|
45
|
+
|
46
|
+
if node_id in self.nodes:
|
47
|
+
raise WorkflowValidationError(
|
48
|
+
f"Node ID '{node_id}' already exists in workflow"
|
49
|
+
)
|
50
|
+
|
51
|
+
self.nodes[node_id] = {"type": node_type, "config": config or {}}
|
52
|
+
|
53
|
+
logger.info(f"Added node '{node_id}' of type '{node_type}'")
|
54
|
+
return node_id
|
55
|
+
|
56
|
+
def add_connection(
|
57
|
+
self, from_node: str, from_output: str, to_node: str, to_input: str
|
58
|
+
) -> None:
|
59
|
+
"""
|
60
|
+
Connect two nodes in the workflow.
|
61
|
+
|
62
|
+
Args:
|
63
|
+
from_node: Source node ID
|
64
|
+
from_output: Output field from source
|
65
|
+
to_node: Target node ID
|
66
|
+
to_input: Input field on target
|
67
|
+
|
68
|
+
Raises:
|
69
|
+
WorkflowValidationError: If nodes don't exist
|
70
|
+
ConnectionError: If connection is invalid
|
71
|
+
"""
|
72
|
+
if from_node not in self.nodes:
|
73
|
+
raise WorkflowValidationError(
|
74
|
+
f"Source node '{from_node}' not found in workflow"
|
75
|
+
)
|
76
|
+
if to_node not in self.nodes:
|
77
|
+
raise WorkflowValidationError(
|
78
|
+
f"Target node '{to_node}' not found in workflow"
|
79
|
+
)
|
80
|
+
|
81
|
+
# Self-connection check
|
82
|
+
if from_node == to_node:
|
83
|
+
raise ConnectionError(f"Cannot connect node '{from_node}' to itself")
|
84
|
+
|
85
|
+
# Add connection to list
|
86
|
+
connection = {
|
87
|
+
"from_node": from_node,
|
88
|
+
"from_output": from_output,
|
89
|
+
"to_node": to_node,
|
90
|
+
"to_input": to_input,
|
91
|
+
}
|
92
|
+
self.connections.append(connection)
|
93
|
+
|
94
|
+
logger.info(f"Connected '{from_node}.{from_output}' to '{to_node}.{to_input}'")
|
95
|
+
|
96
|
+
def set_metadata(self, **kwargs) -> "WorkflowBuilder":
|
97
|
+
"""
|
98
|
+
Set workflow metadata.
|
99
|
+
|
100
|
+
Args:
|
101
|
+
**kwargs: Metadata key-value pairs
|
102
|
+
|
103
|
+
Returns:
|
104
|
+
Self for chaining
|
105
|
+
"""
|
106
|
+
self._metadata.update(kwargs)
|
107
|
+
return self
|
108
|
+
|
109
|
+
def build(self, workflow_id: Optional[str] = None, **kwargs) -> Workflow:
|
110
|
+
"""
|
111
|
+
Build and return a Workflow instance.
|
112
|
+
|
113
|
+
Args:
|
114
|
+
workflow_id: Workflow identifier (auto-generated if not provided)
|
115
|
+
**kwargs: Additional metadata (name, description, version, etc.)
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
Configured Workflow instance
|
119
|
+
|
120
|
+
Raises:
|
121
|
+
WorkflowValidationError: If workflow building fails
|
122
|
+
"""
|
123
|
+
# Generate ID if not provided
|
124
|
+
if workflow_id is None:
|
125
|
+
workflow_id = str(uuid.uuid4())
|
126
|
+
|
127
|
+
# Prepare metadata
|
128
|
+
metadata = self._metadata.copy()
|
129
|
+
metadata.update(kwargs)
|
130
|
+
if "name" not in metadata:
|
131
|
+
metadata["name"] = f"Workflow-{workflow_id[:8]}"
|
132
|
+
|
133
|
+
# Get basic workflow properties
|
134
|
+
name = metadata.pop("name")
|
135
|
+
description = metadata.pop("description", "")
|
136
|
+
version = metadata.pop("version", "1.0.0")
|
137
|
+
author = metadata.pop("author", "")
|
138
|
+
|
139
|
+
# Create workflow
|
140
|
+
workflow = Workflow(
|
141
|
+
workflow_id=workflow_id,
|
142
|
+
name=name,
|
143
|
+
description=description,
|
144
|
+
version=version,
|
145
|
+
author=author,
|
146
|
+
metadata=metadata,
|
147
|
+
)
|
148
|
+
|
149
|
+
# Add nodes to workflow
|
150
|
+
for node_id, node_info in self.nodes.items():
|
151
|
+
try:
|
152
|
+
node_type = node_info["type"]
|
153
|
+
node_config = node_info.get("config", {})
|
154
|
+
|
155
|
+
# Add the node to workflow
|
156
|
+
workflow._add_node_internal(node_id, node_type, node_config)
|
157
|
+
except Exception as e:
|
158
|
+
raise WorkflowValidationError(
|
159
|
+
f"Failed to add node '{node_id}' to workflow: {e}"
|
160
|
+
) from e
|
161
|
+
|
162
|
+
# Add connections to workflow
|
163
|
+
for conn in self.connections:
|
164
|
+
try:
|
165
|
+
from_node = conn["from_node"]
|
166
|
+
from_output = conn["from_output"]
|
167
|
+
to_node = conn["to_node"]
|
168
|
+
to_input = conn["to_input"]
|
169
|
+
|
170
|
+
# Add the connection to workflow
|
171
|
+
workflow._add_edge_internal(from_node, from_output, to_node, to_input)
|
172
|
+
except Exception as e:
|
173
|
+
raise WorkflowValidationError(
|
174
|
+
f"Failed to connect '{from_node}' to '{to_node}': {e}"
|
175
|
+
) from e
|
176
|
+
|
177
|
+
logger.info(
|
178
|
+
f"Built workflow '{workflow_id}' with "
|
179
|
+
f"{len(self.nodes)} nodes and {len(self.connections)} connections"
|
180
|
+
)
|
181
|
+
return workflow
|
182
|
+
|
183
|
+
def clear(self) -> "WorkflowBuilder":
|
184
|
+
"""
|
185
|
+
Clear builder state.
|
186
|
+
|
187
|
+
Returns:
|
188
|
+
Self for chaining
|
189
|
+
"""
|
190
|
+
self.nodes = {}
|
191
|
+
self.connections = []
|
192
|
+
self._metadata = {}
|
193
|
+
return self
|
194
|
+
|
195
|
+
@classmethod
|
196
|
+
def from_dict(cls, config: Dict[str, Any]) -> "WorkflowBuilder":
|
197
|
+
"""
|
198
|
+
Create builder from dictionary configuration.
|
199
|
+
|
200
|
+
Args:
|
201
|
+
config: Dictionary with workflow configuration
|
202
|
+
|
203
|
+
Returns:
|
204
|
+
Configured WorkflowBuilder instance
|
205
|
+
|
206
|
+
Raises:
|
207
|
+
WorkflowValidationError: If configuration is invalid
|
208
|
+
"""
|
209
|
+
builder = cls()
|
210
|
+
|
211
|
+
# Extract metadata
|
212
|
+
for key, value in config.items():
|
213
|
+
if key not in ["nodes", "connections"]:
|
214
|
+
builder._metadata[key] = value
|
215
|
+
|
216
|
+
# Add nodes
|
217
|
+
for node_config in config.get("nodes", []):
|
218
|
+
node_id = node_config.get("id")
|
219
|
+
node_type = node_config.get("type")
|
220
|
+
node_params = node_config.get("config", {})
|
221
|
+
|
222
|
+
if not node_id:
|
223
|
+
raise WorkflowValidationError("Node ID is required")
|
224
|
+
if not node_type:
|
225
|
+
raise WorkflowValidationError(
|
226
|
+
f"Node type is required for node '{node_id}'"
|
227
|
+
)
|
228
|
+
|
229
|
+
builder.add_node(node_type, node_id, node_params)
|
230
|
+
|
231
|
+
# Add connections
|
232
|
+
for conn in config.get("connections", []):
|
233
|
+
from_node = conn.get("from_node")
|
234
|
+
from_output = conn.get("from_output")
|
235
|
+
to_node = conn.get("to_node")
|
236
|
+
to_input = conn.get("to_input")
|
237
|
+
|
238
|
+
if not all([from_node, from_output, to_node, to_input]):
|
239
|
+
raise WorkflowValidationError(
|
240
|
+
f"Invalid connection: missing required fields. Connection data: {conn}"
|
241
|
+
)
|
242
|
+
|
243
|
+
builder.add_connection(from_node, from_output, to_node, to_input)
|
244
|
+
|
245
|
+
return builder
|