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.
Files changed (69) hide show
  1. kailash/__init__.py +31 -0
  2. kailash/__main__.py +11 -0
  3. kailash/cli/__init__.py +5 -0
  4. kailash/cli/commands.py +563 -0
  5. kailash/manifest.py +778 -0
  6. kailash/nodes/__init__.py +23 -0
  7. kailash/nodes/ai/__init__.py +26 -0
  8. kailash/nodes/ai/agents.py +417 -0
  9. kailash/nodes/ai/models.py +488 -0
  10. kailash/nodes/api/__init__.py +52 -0
  11. kailash/nodes/api/auth.py +567 -0
  12. kailash/nodes/api/graphql.py +480 -0
  13. kailash/nodes/api/http.py +598 -0
  14. kailash/nodes/api/rate_limiting.py +572 -0
  15. kailash/nodes/api/rest.py +665 -0
  16. kailash/nodes/base.py +1032 -0
  17. kailash/nodes/base_async.py +128 -0
  18. kailash/nodes/code/__init__.py +32 -0
  19. kailash/nodes/code/python.py +1021 -0
  20. kailash/nodes/data/__init__.py +125 -0
  21. kailash/nodes/data/readers.py +496 -0
  22. kailash/nodes/data/sharepoint_graph.py +623 -0
  23. kailash/nodes/data/sql.py +380 -0
  24. kailash/nodes/data/streaming.py +1168 -0
  25. kailash/nodes/data/vector_db.py +964 -0
  26. kailash/nodes/data/writers.py +529 -0
  27. kailash/nodes/logic/__init__.py +6 -0
  28. kailash/nodes/logic/async_operations.py +702 -0
  29. kailash/nodes/logic/operations.py +551 -0
  30. kailash/nodes/transform/__init__.py +5 -0
  31. kailash/nodes/transform/processors.py +379 -0
  32. kailash/runtime/__init__.py +6 -0
  33. kailash/runtime/async_local.py +356 -0
  34. kailash/runtime/docker.py +697 -0
  35. kailash/runtime/local.py +434 -0
  36. kailash/runtime/parallel.py +557 -0
  37. kailash/runtime/runner.py +110 -0
  38. kailash/runtime/testing.py +347 -0
  39. kailash/sdk_exceptions.py +307 -0
  40. kailash/tracking/__init__.py +7 -0
  41. kailash/tracking/manager.py +885 -0
  42. kailash/tracking/metrics_collector.py +342 -0
  43. kailash/tracking/models.py +535 -0
  44. kailash/tracking/storage/__init__.py +0 -0
  45. kailash/tracking/storage/base.py +113 -0
  46. kailash/tracking/storage/database.py +619 -0
  47. kailash/tracking/storage/filesystem.py +543 -0
  48. kailash/utils/__init__.py +0 -0
  49. kailash/utils/export.py +924 -0
  50. kailash/utils/templates.py +680 -0
  51. kailash/visualization/__init__.py +62 -0
  52. kailash/visualization/api.py +732 -0
  53. kailash/visualization/dashboard.py +951 -0
  54. kailash/visualization/performance.py +808 -0
  55. kailash/visualization/reports.py +1471 -0
  56. kailash/workflow/__init__.py +15 -0
  57. kailash/workflow/builder.py +245 -0
  58. kailash/workflow/graph.py +827 -0
  59. kailash/workflow/mermaid_visualizer.py +628 -0
  60. kailash/workflow/mock_registry.py +63 -0
  61. kailash/workflow/runner.py +302 -0
  62. kailash/workflow/state.py +238 -0
  63. kailash/workflow/visualization.py +588 -0
  64. kailash-0.1.0.dist-info/METADATA +710 -0
  65. kailash-0.1.0.dist-info/RECORD +69 -0
  66. kailash-0.1.0.dist-info/WHEEL +5 -0
  67. kailash-0.1.0.dist-info/entry_points.txt +2 -0
  68. kailash-0.1.0.dist-info/licenses/LICENSE +21 -0
  69. 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