kailash 0.3.1__py3-none-any.whl → 0.4.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 (146) hide show
  1. kailash/__init__.py +33 -1
  2. kailash/access_control/__init__.py +129 -0
  3. kailash/access_control/managers.py +461 -0
  4. kailash/access_control/rule_evaluators.py +467 -0
  5. kailash/access_control_abac.py +825 -0
  6. kailash/config/__init__.py +27 -0
  7. kailash/config/database_config.py +359 -0
  8. kailash/database/__init__.py +28 -0
  9. kailash/database/execution_pipeline.py +499 -0
  10. kailash/middleware/__init__.py +306 -0
  11. kailash/middleware/auth/__init__.py +33 -0
  12. kailash/middleware/auth/access_control.py +436 -0
  13. kailash/middleware/auth/auth_manager.py +422 -0
  14. kailash/middleware/auth/jwt_auth.py +477 -0
  15. kailash/middleware/auth/kailash_jwt_auth.py +616 -0
  16. kailash/middleware/communication/__init__.py +37 -0
  17. kailash/middleware/communication/ai_chat.py +989 -0
  18. kailash/middleware/communication/api_gateway.py +802 -0
  19. kailash/middleware/communication/events.py +470 -0
  20. kailash/middleware/communication/realtime.py +710 -0
  21. kailash/middleware/core/__init__.py +21 -0
  22. kailash/middleware/core/agent_ui.py +890 -0
  23. kailash/middleware/core/schema.py +643 -0
  24. kailash/middleware/core/workflows.py +396 -0
  25. kailash/middleware/database/__init__.py +63 -0
  26. kailash/middleware/database/base.py +113 -0
  27. kailash/middleware/database/base_models.py +525 -0
  28. kailash/middleware/database/enums.py +106 -0
  29. kailash/middleware/database/migrations.py +12 -0
  30. kailash/{api/database.py → middleware/database/models.py} +183 -291
  31. kailash/middleware/database/repositories.py +685 -0
  32. kailash/middleware/database/session_manager.py +19 -0
  33. kailash/middleware/mcp/__init__.py +38 -0
  34. kailash/middleware/mcp/client_integration.py +585 -0
  35. kailash/middleware/mcp/enhanced_server.py +576 -0
  36. kailash/nodes/__init__.py +25 -3
  37. kailash/nodes/admin/__init__.py +35 -0
  38. kailash/nodes/admin/audit_log.py +794 -0
  39. kailash/nodes/admin/permission_check.py +864 -0
  40. kailash/nodes/admin/role_management.py +823 -0
  41. kailash/nodes/admin/security_event.py +1519 -0
  42. kailash/nodes/admin/user_management.py +944 -0
  43. kailash/nodes/ai/a2a.py +24 -7
  44. kailash/nodes/ai/ai_providers.py +1 -0
  45. kailash/nodes/ai/embedding_generator.py +11 -11
  46. kailash/nodes/ai/intelligent_agent_orchestrator.py +99 -11
  47. kailash/nodes/ai/llm_agent.py +407 -2
  48. kailash/nodes/ai/self_organizing.py +85 -10
  49. kailash/nodes/api/auth.py +287 -6
  50. kailash/nodes/api/rest.py +151 -0
  51. kailash/nodes/auth/__init__.py +17 -0
  52. kailash/nodes/auth/directory_integration.py +1228 -0
  53. kailash/nodes/auth/enterprise_auth_provider.py +1328 -0
  54. kailash/nodes/auth/mfa.py +2338 -0
  55. kailash/nodes/auth/risk_assessment.py +872 -0
  56. kailash/nodes/auth/session_management.py +1093 -0
  57. kailash/nodes/auth/sso.py +1040 -0
  58. kailash/nodes/base.py +344 -13
  59. kailash/nodes/base_cycle_aware.py +4 -2
  60. kailash/nodes/base_with_acl.py +1 -1
  61. kailash/nodes/code/python.py +293 -12
  62. kailash/nodes/compliance/__init__.py +9 -0
  63. kailash/nodes/compliance/data_retention.py +1888 -0
  64. kailash/nodes/compliance/gdpr.py +2004 -0
  65. kailash/nodes/data/__init__.py +22 -2
  66. kailash/nodes/data/async_connection.py +469 -0
  67. kailash/nodes/data/async_sql.py +757 -0
  68. kailash/nodes/data/async_vector.py +598 -0
  69. kailash/nodes/data/readers.py +767 -0
  70. kailash/nodes/data/retrieval.py +360 -1
  71. kailash/nodes/data/sharepoint_graph.py +397 -21
  72. kailash/nodes/data/sql.py +94 -5
  73. kailash/nodes/data/streaming.py +68 -8
  74. kailash/nodes/data/vector_db.py +54 -4
  75. kailash/nodes/enterprise/__init__.py +13 -0
  76. kailash/nodes/enterprise/batch_processor.py +741 -0
  77. kailash/nodes/enterprise/data_lineage.py +497 -0
  78. kailash/nodes/logic/convergence.py +31 -9
  79. kailash/nodes/logic/operations.py +14 -3
  80. kailash/nodes/mixins/__init__.py +8 -0
  81. kailash/nodes/mixins/event_emitter.py +201 -0
  82. kailash/nodes/mixins/mcp.py +9 -4
  83. kailash/nodes/mixins/security.py +165 -0
  84. kailash/nodes/monitoring/__init__.py +7 -0
  85. kailash/nodes/monitoring/performance_benchmark.py +2497 -0
  86. kailash/nodes/rag/__init__.py +284 -0
  87. kailash/nodes/rag/advanced.py +1615 -0
  88. kailash/nodes/rag/agentic.py +773 -0
  89. kailash/nodes/rag/conversational.py +999 -0
  90. kailash/nodes/rag/evaluation.py +875 -0
  91. kailash/nodes/rag/federated.py +1188 -0
  92. kailash/nodes/rag/graph.py +721 -0
  93. kailash/nodes/rag/multimodal.py +671 -0
  94. kailash/nodes/rag/optimized.py +933 -0
  95. kailash/nodes/rag/privacy.py +1059 -0
  96. kailash/nodes/rag/query_processing.py +1335 -0
  97. kailash/nodes/rag/realtime.py +764 -0
  98. kailash/nodes/rag/registry.py +547 -0
  99. kailash/nodes/rag/router.py +837 -0
  100. kailash/nodes/rag/similarity.py +1854 -0
  101. kailash/nodes/rag/strategies.py +566 -0
  102. kailash/nodes/rag/workflows.py +575 -0
  103. kailash/nodes/security/__init__.py +19 -0
  104. kailash/nodes/security/abac_evaluator.py +1411 -0
  105. kailash/nodes/security/audit_log.py +91 -0
  106. kailash/nodes/security/behavior_analysis.py +1893 -0
  107. kailash/nodes/security/credential_manager.py +401 -0
  108. kailash/nodes/security/rotating_credentials.py +760 -0
  109. kailash/nodes/security/security_event.py +132 -0
  110. kailash/nodes/security/threat_detection.py +1103 -0
  111. kailash/nodes/testing/__init__.py +9 -0
  112. kailash/nodes/testing/credential_testing.py +499 -0
  113. kailash/nodes/transform/__init__.py +10 -2
  114. kailash/nodes/transform/chunkers.py +592 -1
  115. kailash/nodes/transform/processors.py +484 -14
  116. kailash/nodes/validation.py +321 -0
  117. kailash/runtime/access_controlled.py +1 -1
  118. kailash/runtime/async_local.py +41 -7
  119. kailash/runtime/docker.py +1 -1
  120. kailash/runtime/local.py +474 -55
  121. kailash/runtime/parallel.py +1 -1
  122. kailash/runtime/parallel_cyclic.py +1 -1
  123. kailash/runtime/testing.py +210 -2
  124. kailash/utils/migrations/__init__.py +25 -0
  125. kailash/utils/migrations/generator.py +433 -0
  126. kailash/utils/migrations/models.py +231 -0
  127. kailash/utils/migrations/runner.py +489 -0
  128. kailash/utils/secure_logging.py +342 -0
  129. kailash/workflow/__init__.py +16 -0
  130. kailash/workflow/cyclic_runner.py +3 -4
  131. kailash/workflow/graph.py +70 -2
  132. kailash/workflow/resilience.py +249 -0
  133. kailash/workflow/templates.py +726 -0
  134. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/METADATA +253 -20
  135. kailash-0.4.0.dist-info/RECORD +223 -0
  136. kailash/api/__init__.py +0 -17
  137. kailash/api/__main__.py +0 -6
  138. kailash/api/studio_secure.py +0 -893
  139. kailash/mcp/__main__.py +0 -13
  140. kailash/mcp/server_new.py +0 -336
  141. kailash/mcp/servers/__init__.py +0 -12
  142. kailash-0.3.1.dist-info/RECORD +0 -136
  143. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/WHEEL +0 -0
  144. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/entry_points.txt +0 -0
  145. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/licenses/LICENSE +0 -0
  146. {kailash-0.3.1.dist-info → kailash-0.4.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,321 @@
1
+ """Node validation framework with context-aware error suggestions.
2
+
3
+ This module provides validation utilities that enhance error messages with
4
+ helpful suggestions, code examples, and documentation links.
5
+ """
6
+
7
+ import inspect
8
+ import re
9
+ from dataclasses import dataclass
10
+ from typing import Any, Callable, Dict, List, Optional, Type
11
+
12
+ from kailash.nodes.base import Node, NodeParameter
13
+
14
+
15
+ @dataclass
16
+ class ValidationSuggestion:
17
+ """Suggestion for fixing a validation error."""
18
+
19
+ message: str
20
+ code_example: Optional[str] = None
21
+ doc_link: Optional[str] = None
22
+ alternative_nodes: Optional[List[str]] = None
23
+
24
+
25
+ class NodeValidator:
26
+ """Enhanced node validation with helpful error messages."""
27
+
28
+ # Common parameter mistakes and their fixes
29
+ PARAMETER_PATTERNS = {
30
+ # PythonCodeNode common mistakes
31
+ r"return\s+(?!.*\{.*result.*\})": ValidationSuggestion(
32
+ message="PythonCodeNode must return data wrapped in {'result': ...}",
33
+ code_example='return {"result": your_data} # Not: return your_data',
34
+ doc_link="sdk-users/developer/07-troubleshooting.md#pythoncodenode-output",
35
+ ),
36
+ # File path mistakes
37
+ r"^(?!/).*\.(csv|json|txt)$": ValidationSuggestion(
38
+ message="File paths should be absolute, not relative",
39
+ code_example='file_path="/data/inputs/file.csv" # Not: file_path="file.csv"',
40
+ doc_link="sdk-users/developer/QUICK_REFERENCE.md#file-paths",
41
+ ),
42
+ # Node naming mistakes
43
+ r"Node$": ValidationSuggestion(
44
+ message="Node names should describe their purpose, not end with 'Node'",
45
+ code_example='workflow.add_node("read_data", CSVReaderNode) # Not: "csv_reader_node"',
46
+ alternative_nodes=[
47
+ "Consider using descriptive names like 'load_config', 'process_data', 'save_results'"
48
+ ],
49
+ ),
50
+ # SQL injection risks
51
+ r"f['\"].*SELECT.*\{": ValidationSuggestion(
52
+ message="Avoid f-strings in SQL queries - use parameterized queries",
53
+ code_example='query="SELECT * FROM users WHERE id = %s", params=[user_id]',
54
+ doc_link="sdk-users/security/sql-best-practices.md",
55
+ ),
56
+ # Missing required fields
57
+ r"TypeError.*missing.*required": ValidationSuggestion(
58
+ message="Required parameter missing",
59
+ code_example="Check node documentation for required parameters",
60
+ doc_link="sdk-users/nodes/comprehensive-node-catalog.md",
61
+ ),
62
+ }
63
+
64
+ # Node-specific validations
65
+ NODE_VALIDATIONS: Dict[str, List[Callable]] = {
66
+ "PythonCodeNode": [
67
+ lambda config: "code" in config or "func" in config,
68
+ lambda config: not (
69
+ config.get("code", "").strip().startswith("import ")
70
+ and len(config.get("code", "").split("\n")) == 1
71
+ ),
72
+ ],
73
+ "SQLDatabaseNode": [
74
+ lambda config: "query" in config or "queries" in config,
75
+ lambda config: not re.search(
76
+ r"DROP|DELETE|TRUNCATE", config.get("query", ""), re.I
77
+ )
78
+ or config.get("allow_destructive", False),
79
+ ],
80
+ "HTTPRequestNode": [
81
+ lambda config: "url" in config,
82
+ lambda config: config.get("url", "").startswith(("http://", "https://")),
83
+ ],
84
+ }
85
+
86
+ # Alternative node suggestions
87
+ ALTERNATIVE_NODES = {
88
+ "csv_processing": ["CSVReaderNode", "PandasNode", "DataTransformerNode"],
89
+ "api_calls": ["HTTPRequestNode", "RESTClientNode", "GraphQLClientNode"],
90
+ "data_storage": ["SQLDatabaseNode", "VectorDatabaseNode", "JSONWriterNode"],
91
+ "llm_tasks": ["LLMAgentNode", "A2AAgentNode", "MCPAgentNode"],
92
+ "authentication": ["OAuth2Node", "CredentialManagerNode", "BasicAuthNode"],
93
+ }
94
+
95
+ @classmethod
96
+ def validate_node_config(
97
+ cls,
98
+ node_type: str,
99
+ config: Dict[str, Any],
100
+ node_instance: Optional[Node] = None,
101
+ ) -> List[ValidationSuggestion]:
102
+ """Validate node configuration and return suggestions."""
103
+ suggestions = []
104
+
105
+ # Check node-specific validations
106
+ if node_type in cls.NODE_VALIDATIONS:
107
+ for validation in cls.NODE_VALIDATIONS[node_type]:
108
+ try:
109
+ if not validation(config):
110
+ suggestions.append(cls._get_node_suggestion(node_type, config))
111
+ except Exception:
112
+ pass
113
+
114
+ # Check parameter patterns
115
+ config_str = str(config)
116
+ for pattern, suggestion in cls.PARAMETER_PATTERNS.items():
117
+ if re.search(pattern, config_str):
118
+ suggestions.append(suggestion)
119
+
120
+ # Check for common type mismatches
121
+ if node_instance:
122
+ suggestions.extend(cls._validate_parameter_types(node_instance, config))
123
+
124
+ return suggestions
125
+
126
+ @classmethod
127
+ def _validate_parameter_types(
128
+ cls, node: Node, config: Dict[str, Any]
129
+ ) -> List[ValidationSuggestion]:
130
+ """Validate parameter types match expected types."""
131
+ suggestions = []
132
+
133
+ try:
134
+ params = node.get_parameters()
135
+ for param_name, param_def in params.items():
136
+ if param_name in config:
137
+ value = config[param_name]
138
+ expected_type = param_def.type
139
+
140
+ # Type checking
141
+ if expected_type and not cls._check_type(value, expected_type):
142
+ suggestions.append(
143
+ ValidationSuggestion(
144
+ message=f"Parameter '{param_name}' expects {expected_type.__name__}, got {type(value).__name__}",
145
+ code_example=f"{param_name}={cls._get_type_example(expected_type)}",
146
+ doc_link=f"sdk-users/nodes/{node.__class__.__name__.lower()}.md",
147
+ )
148
+ )
149
+ except Exception:
150
+ pass
151
+
152
+ return suggestions
153
+
154
+ @classmethod
155
+ def _check_type(cls, value: Any, expected_type: Type) -> bool:
156
+ """Check if value matches expected type."""
157
+ # Handle Optional types
158
+ if hasattr(expected_type, "__origin__"):
159
+ if expected_type.__origin__ is type(Optional):
160
+ if value is None:
161
+ return True
162
+ expected_type = expected_type.__args__[0]
163
+
164
+ # Direct type check
165
+ return isinstance(value, expected_type)
166
+
167
+ @classmethod
168
+ def _get_type_example(cls, type_hint: Type) -> str:
169
+ """Get example value for a type."""
170
+ examples = {
171
+ str: '"example_string"',
172
+ int: "42",
173
+ float: "3.14",
174
+ bool: "True",
175
+ list: '["item1", "item2"]',
176
+ dict: '{"key": "value"}',
177
+ }
178
+ return examples.get(type_hint, f"<{type_hint.__name__} value>")
179
+
180
+ @classmethod
181
+ def _get_node_suggestion(
182
+ cls, node_type: str, config: Dict[str, Any]
183
+ ) -> ValidationSuggestion:
184
+ """Get node-specific suggestion."""
185
+ suggestions_map = {
186
+ "PythonCodeNode": ValidationSuggestion(
187
+ message="PythonCodeNode requires 'code' or use .from_function()",
188
+ code_example="""
189
+ # Option 1: Inline code
190
+ PythonCodeNode(code='return {"result": data}')
191
+
192
+ # Option 2: From function (recommended)
193
+ def process(data):
194
+ return {"result": data}
195
+ PythonCodeNode.from_function("processor", process)
196
+ """,
197
+ alternative_nodes=["DataTransformerNode", "FilterNode", "MapNode"],
198
+ ),
199
+ "SQLDatabaseNode": ValidationSuggestion(
200
+ message="SQLDatabaseNode requires 'query' parameter",
201
+ code_example='SQLDatabaseNode(query="SELECT * FROM table", connection_string="...")',
202
+ alternative_nodes=["AsyncSQLDatabaseNode", "VectorDatabaseNode"],
203
+ ),
204
+ "HTTPRequestNode": ValidationSuggestion(
205
+ message="HTTPRequestNode requires valid 'url' parameter",
206
+ code_example='HTTPRequestNode(url="https://api.example.com/data", method="GET")',
207
+ alternative_nodes=[
208
+ "RESTClientNode",
209
+ "GraphQLClientNode",
210
+ "WebhookNode",
211
+ ],
212
+ ),
213
+ }
214
+ return suggestions_map.get(
215
+ node_type,
216
+ ValidationSuggestion(message=f"Invalid configuration for {node_type}"),
217
+ )
218
+
219
+ @classmethod
220
+ def suggest_alternative_nodes(cls, use_case: str) -> List[str]:
221
+ """Suggest alternative nodes for a use case."""
222
+ # Fuzzy match use case
223
+ for key, nodes in cls.ALTERNATIVE_NODES.items():
224
+ if key in use_case.lower() or use_case.lower() in key:
225
+ return nodes
226
+ return []
227
+
228
+ @classmethod
229
+ def format_error_with_suggestions(
230
+ cls,
231
+ error: Exception,
232
+ node_type: str,
233
+ config: Dict[str, Any],
234
+ context: Optional[Dict[str, Any]] = None,
235
+ ) -> str:
236
+ """Format error message with helpful suggestions."""
237
+ suggestions = cls.validate_node_config(node_type, config)
238
+
239
+ # Build formatted error message
240
+ lines = [f"❌ Error in {node_type}: {str(error)}", ""]
241
+
242
+ if suggestions:
243
+ lines.append("💡 Suggestions:")
244
+ for i, suggestion in enumerate(suggestions, 1):
245
+ lines.append(f"\n{i}. {suggestion.message}")
246
+
247
+ if suggestion.code_example:
248
+ lines.append(f"\n Example:\n {suggestion.code_example}")
249
+
250
+ if suggestion.alternative_nodes:
251
+ lines.append(
252
+ f"\n Alternative nodes: {', '.join(suggestion.alternative_nodes)}"
253
+ )
254
+
255
+ if suggestion.doc_link:
256
+ lines.append(f"\n 📚 Documentation: {suggestion.doc_link}")
257
+
258
+ # Add context if provided
259
+ if context:
260
+ lines.extend(
261
+ [
262
+ "",
263
+ "📋 Context:",
264
+ f" Workflow: {context.get('workflow_name', 'Unknown')}",
265
+ f" Node ID: {context.get('node_id', 'Unknown')}",
266
+ f" Previous Node: {context.get('previous_node', 'None')}",
267
+ ]
268
+ )
269
+
270
+ # Add generic help
271
+ lines.extend(
272
+ [
273
+ "",
274
+ "🔗 Resources:",
275
+ " - Node Catalog: sdk-users/nodes/comprehensive-node-catalog.md",
276
+ " - Quick Reference: sdk-users/developer/QUICK_REFERENCE.md",
277
+ " - Troubleshooting: sdk-users/developer/07-troubleshooting.md",
278
+ ]
279
+ )
280
+
281
+ return "\n".join(lines)
282
+
283
+
284
+ def validate_node_decorator(node_class: Type[Node]) -> Type[Node]:
285
+ """Decorator to add validation to node classes."""
286
+
287
+ original_init = node_class.__init__
288
+ original_run = node_class.run
289
+
290
+ def new_init(self, *args, **kwargs):
291
+ """Enhanced init with validation."""
292
+ try:
293
+ original_init(self, *args, **kwargs)
294
+ except Exception as e:
295
+ # Enhance error with suggestions
296
+ error_msg = NodeValidator.format_error_with_suggestions(
297
+ e, node_class.__name__, kwargs, {"node_id": kwargs.get("id", "unknown")}
298
+ )
299
+ raise type(e)(error_msg) from e
300
+
301
+ def new_run(self, **inputs):
302
+ """Enhanced run with validation."""
303
+ try:
304
+ return original_run(self, **inputs)
305
+ except Exception as e:
306
+ # Enhance error with runtime context
307
+ error_msg = NodeValidator.format_error_with_suggestions(
308
+ e,
309
+ node_class.__name__,
310
+ inputs,
311
+ {
312
+ "node_id": getattr(self, "id", "unknown"),
313
+ "inputs": list(inputs.keys()),
314
+ },
315
+ )
316
+ raise type(e)(error_msg) from e
317
+
318
+ node_class.__init__ = new_init
319
+ node_class.run = new_run
320
+
321
+ return node_class
@@ -239,7 +239,7 @@ class AccessControlledRuntime:
239
239
  return {}
240
240
 
241
241
  # Execute the original node
242
- result = self._original_node.run(**inputs)
242
+ result = self._original_node.execute(**inputs)
243
243
 
244
244
  # Check output read permission
245
245
  output_decision = runtime.acm.check_node_access(
@@ -1,5 +1,9 @@
1
1
  """Asynchronous local runtime engine for executing workflows.
2
2
 
3
+ DEPRECATED: This module is deprecated. The LocalRuntime in local.py now provides
4
+ unified async/sync execution capabilities. For backward compatibility, this module
5
+ exports LocalRuntime as AsyncLocalRuntime.
6
+
3
7
  This module provides an asynchronous execution engine for Kailash workflows,
4
8
  particularly useful for workflows with I/O-bound nodes such as API calls,
5
9
  database queries, or LLM interactions.
@@ -11,7 +15,6 @@ from typing import Any
11
15
 
12
16
  import networkx as nx
13
17
 
14
- from kailash.nodes.base_async import AsyncNode
15
18
  from kailash.sdk_exceptions import (
16
19
  RuntimeExecutionError,
17
20
  WorkflowExecutionError,
@@ -83,8 +86,8 @@ class AsyncLocalRuntime:
83
86
  run_id = None
84
87
 
85
88
  try:
86
- # Validate workflow
87
- workflow.validate()
89
+ # Validate workflow with runtime parameters (Session 061)
90
+ workflow.validate(runtime_parameters=parameters)
88
91
 
89
92
  # Initialize tracking
90
93
  if task_manager:
@@ -222,12 +225,13 @@ class AsyncLocalRuntime:
222
225
  # Execute node - check if it supports async execution
223
226
  start_time = datetime.now(UTC)
224
227
 
225
- if isinstance(node_instance, AsyncNode):
226
- # Use async execution
228
+ if hasattr(node_instance, "execute_async"):
229
+ # Use async execution if available
227
230
  outputs = await node_instance.execute_async(**inputs)
228
231
  else:
229
- # Fall back to synchronous execution
230
- outputs = node_instance.run(**inputs)
232
+ # Fall back to synchronous execution using execute()
233
+ # This ensures proper validation and error handling
234
+ outputs = node_instance.execute(**inputs)
231
235
 
232
236
  execution_time = (datetime.now(UTC) - start_time).total_seconds()
233
237
 
@@ -352,3 +356,33 @@ class AsyncLocalRuntime:
352
356
  # For now, stop if the failed node has dependents
353
357
  # Future: implement configurable error handling policies
354
358
  return has_dependents
359
+
360
+
361
+ # Backward compatibility: Use the unified LocalRuntime
362
+ from kailash.runtime.local import LocalRuntime # noqa: E402
363
+
364
+ # Export LocalRuntime as AsyncLocalRuntime for backward compatibility
365
+ # AsyncLocalRuntime = LocalRuntime # Commented out to avoid redefinition warning
366
+
367
+
368
+ # For better backward compatibility, create a wrapper that sets enable_async=True by default
369
+ class AsyncLocalRuntimeCompat(LocalRuntime):
370
+ """Backward compatibility wrapper for AsyncLocalRuntime.
371
+
372
+ This wrapper automatically enables async execution and provides the same
373
+ interface as the original AsyncLocalRuntime.
374
+ """
375
+
376
+ def __init__(self, debug: bool = False, max_concurrency: int = 10, **kwargs):
377
+ """Initialize with async enabled by default."""
378
+ super().__init__(
379
+ debug=debug, enable_async=True, max_concurrency=max_concurrency, **kwargs
380
+ )
381
+
382
+ async def execute(self, *args, **kwargs):
383
+ """Async execute method for full backward compatibility."""
384
+ return await self.execute_async(*args, **kwargs)
385
+
386
+
387
+ # Use the compatibility wrapper as the main export
388
+ # AsyncLocalRuntime = AsyncLocalRuntimeCompat # Commented out to avoid redefinition warning - class definition at top takes precedence
kailash/runtime/docker.py CHANGED
@@ -201,7 +201,7 @@ def main():
201
201
  # Execute node
202
202
  logger.info(f"Executing node with inputs: {list(runtime_inputs.keys())}")
203
203
  try:
204
- result = node.run(**runtime_inputs)
204
+ result = node.execute(**runtime_inputs)
205
205
  logger.info("Node execution completed successfully")
206
206
  except Exception as e:
207
207
  logger.error(f"Node execution failed: {e}")