kailash 0.1.4__py3-none-any.whl → 0.2.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 (83) hide show
  1. kailash/__init__.py +1 -1
  2. kailash/access_control.py +740 -0
  3. kailash/api/__main__.py +6 -0
  4. kailash/api/auth.py +668 -0
  5. kailash/api/custom_nodes.py +285 -0
  6. kailash/api/custom_nodes_secure.py +377 -0
  7. kailash/api/database.py +620 -0
  8. kailash/api/studio.py +915 -0
  9. kailash/api/studio_secure.py +893 -0
  10. kailash/mcp/__init__.py +53 -0
  11. kailash/mcp/__main__.py +13 -0
  12. kailash/mcp/ai_registry_server.py +712 -0
  13. kailash/mcp/client.py +447 -0
  14. kailash/mcp/client_new.py +334 -0
  15. kailash/mcp/server.py +293 -0
  16. kailash/mcp/server_new.py +336 -0
  17. kailash/mcp/servers/__init__.py +12 -0
  18. kailash/mcp/servers/ai_registry.py +289 -0
  19. kailash/nodes/__init__.py +4 -2
  20. kailash/nodes/ai/__init__.py +38 -0
  21. kailash/nodes/ai/a2a.py +1790 -0
  22. kailash/nodes/ai/agents.py +116 -2
  23. kailash/nodes/ai/ai_providers.py +206 -8
  24. kailash/nodes/ai/intelligent_agent_orchestrator.py +2108 -0
  25. kailash/nodes/ai/iterative_llm_agent.py +1280 -0
  26. kailash/nodes/ai/llm_agent.py +324 -1
  27. kailash/nodes/ai/self_organizing.py +1623 -0
  28. kailash/nodes/api/http.py +106 -25
  29. kailash/nodes/api/rest.py +116 -21
  30. kailash/nodes/base.py +15 -2
  31. kailash/nodes/base_async.py +45 -0
  32. kailash/nodes/base_cycle_aware.py +374 -0
  33. kailash/nodes/base_with_acl.py +338 -0
  34. kailash/nodes/code/python.py +135 -27
  35. kailash/nodes/data/readers.py +116 -53
  36. kailash/nodes/data/writers.py +16 -6
  37. kailash/nodes/logic/__init__.py +8 -0
  38. kailash/nodes/logic/async_operations.py +48 -9
  39. kailash/nodes/logic/convergence.py +642 -0
  40. kailash/nodes/logic/loop.py +153 -0
  41. kailash/nodes/logic/operations.py +212 -27
  42. kailash/nodes/logic/workflow.py +26 -18
  43. kailash/nodes/mixins/__init__.py +11 -0
  44. kailash/nodes/mixins/mcp.py +228 -0
  45. kailash/nodes/mixins.py +387 -0
  46. kailash/nodes/transform/__init__.py +8 -1
  47. kailash/nodes/transform/processors.py +119 -4
  48. kailash/runtime/__init__.py +2 -1
  49. kailash/runtime/access_controlled.py +458 -0
  50. kailash/runtime/local.py +106 -33
  51. kailash/runtime/parallel_cyclic.py +529 -0
  52. kailash/sdk_exceptions.py +90 -5
  53. kailash/security.py +845 -0
  54. kailash/tracking/manager.py +38 -15
  55. kailash/tracking/models.py +1 -1
  56. kailash/tracking/storage/filesystem.py +30 -2
  57. kailash/utils/__init__.py +8 -0
  58. kailash/workflow/__init__.py +18 -0
  59. kailash/workflow/convergence.py +270 -0
  60. kailash/workflow/cycle_analyzer.py +768 -0
  61. kailash/workflow/cycle_builder.py +573 -0
  62. kailash/workflow/cycle_config.py +709 -0
  63. kailash/workflow/cycle_debugger.py +760 -0
  64. kailash/workflow/cycle_exceptions.py +601 -0
  65. kailash/workflow/cycle_profiler.py +671 -0
  66. kailash/workflow/cycle_state.py +338 -0
  67. kailash/workflow/cyclic_runner.py +985 -0
  68. kailash/workflow/graph.py +500 -39
  69. kailash/workflow/migration.py +768 -0
  70. kailash/workflow/safety.py +365 -0
  71. kailash/workflow/templates.py +744 -0
  72. kailash/workflow/validation.py +693 -0
  73. {kailash-0.1.4.dist-info → kailash-0.2.0.dist-info}/METADATA +446 -13
  74. kailash-0.2.0.dist-info/RECORD +125 -0
  75. kailash/nodes/mcp/__init__.py +0 -11
  76. kailash/nodes/mcp/client.py +0 -554
  77. kailash/nodes/mcp/resource.py +0 -682
  78. kailash/nodes/mcp/server.py +0 -577
  79. kailash-0.1.4.dist-info/RECORD +0 -85
  80. {kailash-0.1.4.dist-info → kailash-0.2.0.dist-info}/WHEEL +0 -0
  81. {kailash-0.1.4.dist-info → kailash-0.2.0.dist-info}/entry_points.txt +0 -0
  82. {kailash-0.1.4.dist-info → kailash-0.2.0.dist-info}/licenses/LICENSE +0 -0
  83. {kailash-0.1.4.dist-info → kailash-0.2.0.dist-info}/top_level.txt +0 -0
kailash/nodes/api/http.py CHANGED
@@ -57,33 +57,114 @@ class HTTPResponse(BaseModel):
57
57
 
58
58
  @register_node()
59
59
  class HTTPRequestNode(Node):
60
- """Enhanced node for making HTTP requests to external APIs.
61
-
62
- This node provides a flexible interface for making HTTP requests with support for:
63
- * All common HTTP methods (GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS)
64
- * Multiple authentication methods (Bearer, Basic, API Key, OAuth2)
65
- * JSON, form, and multipart request bodies
66
- * Custom headers and query parameters
67
- * Response parsing (JSON, text, binary)
68
- * Error handling and retries with recovery suggestions
69
- * Rate limiting support
70
- * Request/response logging
71
-
72
- Design Purpose:
73
- * Enable workflow integration with external HTTP APIs
74
- * Provide a consistent interface for HTTP operations
75
- * Support common authentication patterns
76
- * Handle response parsing and error handling
77
- * Offer enterprise-grade features like rate limiting
78
-
79
- Upstream Usage:
80
- * Workflow: Creates and configures node for API integration
81
- * Specialized API nodes: May extend this node for specific APIs
60
+ """
61
+ Enhanced node for making HTTP requests to external APIs.
62
+
63
+ This node provides a comprehensive HTTP client with enterprise-grade features for
64
+ integrating external APIs into Kailash workflows. It supports all common HTTP
65
+ operations with built-in authentication, error handling, and response parsing,
66
+ making it the foundation for API integration in the SDK.
67
+
68
+ Design Philosophy:
69
+ The HTTPRequestNode embodies the principle of "API integration made simple."
70
+ It abstracts the complexity of HTTP operations behind a clean interface while
71
+ providing advanced features when needed. The design prioritizes flexibility,
72
+ reliability, and ease of use, supporting everything from simple REST calls
73
+ to complex authentication flows and multipart uploads.
74
+
75
+ Upstream Dependencies:
76
+ - Workflow orchestrators configuring API endpoints
77
+ - Authentication nodes providing credentials
78
+ - Configuration systems supplying API settings
79
+ - Data transformation nodes preparing request payloads
80
+ - Rate limiting controllers managing API quotas
82
81
 
83
82
  Downstream Consumers:
84
- * Data processing nodes: Consume API response data
85
- * Decision nodes: Route workflow based on API responses
86
- * Custom nodes: Process API-specific data formats
83
+ - Data processing nodes consuming API responses
84
+ - Decision nodes routing based on HTTP status
85
+ - Error handling nodes managing failures
86
+ - Caching nodes storing API results
87
+ - Analytics nodes tracking API usage
88
+
89
+ Configuration:
90
+ The node supports extensive configuration options:
91
+ - URL with template variable support
92
+ - All standard HTTP methods
93
+ - Custom headers and query parameters
94
+ - Multiple body formats (JSON, form, multipart)
95
+ - Authentication methods (Bearer, Basic, API Key, OAuth2)
96
+ - Timeout and retry settings
97
+ - Response format preferences
98
+
99
+ Implementation Details:
100
+ - Uses requests library for synchronous operations
101
+ - Automatic response format detection based on Content-Type
102
+ - Built-in JSON parsing with error handling
103
+ - Support for binary responses (files, images)
104
+ - Connection pooling for performance
105
+ - Comprehensive error messages with recovery hints
106
+ - Optional request/response logging
107
+ - Metrics collection for monitoring
108
+
109
+ Error Handling:
110
+ - Connection errors with retry suggestions
111
+ - Timeout handling with configurable limits
112
+ - HTTP error status codes with detailed messages
113
+ - JSON parsing errors with fallback to text
114
+ - Authentication failures with setup guidance
115
+ - Rate limit detection and backoff
116
+
117
+ Side Effects:
118
+ - Makes external HTTP requests
119
+ - May consume API rate limits
120
+ - Logs requests/responses when enabled
121
+ - Updates internal metrics
122
+ - May modify external resources (POST/PUT/DELETE)
123
+
124
+ Examples:
125
+ >>> # Simple GET request
126
+ >>> node = HTTPRequestNode()
127
+ >>> result = node.run(
128
+ ... url="https://api.example.com/users",
129
+ ... method="GET",
130
+ ... headers={"Accept": "application/json"}
131
+ ... )
132
+ >>> assert result["status_code"] == 200
133
+ >>> assert isinstance(result["content"], dict)
134
+ >>>
135
+ >>> # POST request with JSON body
136
+ >>> result = node.run(
137
+ ... url="https://api.example.com/users",
138
+ ... method="POST",
139
+ ... json_data={"name": "John", "email": "john@example.com"},
140
+ ... headers={"Authorization": "Bearer token123"}
141
+ ... )
142
+ >>> assert result["status_code"] in [200, 201]
143
+ >>> assert result["headers"]["content-type"].startswith("application/json")
144
+ >>>
145
+ >>> # Form data submission
146
+ >>> result = node.run(
147
+ ... url="https://api.example.com/form",
148
+ ... method="POST",
149
+ ... data={"field1": "value1", "field2": "value2"},
150
+ ... headers={"Content-Type": "application/x-www-form-urlencoded"}
151
+ ... )
152
+ >>>
153
+ >>> # File upload with multipart
154
+ >>> result = node.run(
155
+ ... url="https://api.example.com/upload",
156
+ ... method="POST",
157
+ ... files={"file": ("data.csv", b"col1,col2\\n1,2", "text/csv")},
158
+ ... data={"description": "Sample data"}
159
+ ... )
160
+ >>>
161
+ >>> # Error handling example
162
+ >>> result = node.run(
163
+ ... url="https://api.example.com/protected",
164
+ ... method="GET"
165
+ ... )
166
+ >>> if result["status_code"] == 401:
167
+ ... print("Authentication required")
87
168
  """
88
169
 
89
170
  def __init__(self, **kwargs):
kailash/nodes/api/rest.py CHANGED
@@ -20,29 +20,124 @@ from kailash.sdk_exceptions import NodeExecutionError, NodeValidationError
20
20
 
21
21
  @register_node()
22
22
  class RESTClientNode(Node):
23
- """Node for interacting with REST APIs.
24
-
25
- This node provides a higher-level interface for interacting with REST APIs,
26
- with built-in support for:
27
- * Resource-based operations (e.g., GET /users/{id})
28
- * Common REST patterns (list, get, create, update, delete)
29
- * Pagination handling
30
- * Response schema validation
31
- * Error response handling
32
-
33
- Design Purpose:
34
- * Simplify REST API integration in workflows
35
- * Provide consistent interfaces for common REST operations
36
- * Support standard REST conventions and patterns
37
- * Handle common REST-specific error cases
38
-
39
- Upstream Usage:
40
- * Workflow: Creates and configures for specific REST APIs
41
- * API integration workflows: Uses for external service integration
23
+ """
24
+ Node for interacting with REST APIs using resource-oriented patterns.
25
+
26
+ This node provides a higher-level abstraction over HTTP operations, specifically
27
+ designed for REST APIs. It understands REST conventions and provides convenient
28
+ methods for resource-based operations, making it easier to integrate RESTful
29
+ services into Kailash workflows.
30
+
31
+ Design Philosophy:
32
+ The RESTClientNode embraces REST principles and conventions, providing an
33
+ intuitive interface for resource manipulation. It abstracts common patterns
34
+ like path parameter substitution, pagination, and error handling while
35
+ maintaining flexibility for API-specific requirements. The design promotes
36
+ clean, maintainable API integration code.
37
+
38
+ Upstream Dependencies:
39
+ - Workflow orchestrators defining API endpoints
40
+ - Configuration nodes providing API credentials
41
+ - Data transformation nodes preparing resources
42
+ - Authentication nodes managing tokens
43
+ - Schema validation nodes defining expected formats
42
44
 
43
45
  Downstream Consumers:
44
- * Data processing nodes: Consume API response data
45
- * Custom nodes: Process API-specific data formats
46
+ - Data processing nodes working with API responses
47
+ - Pagination handlers managing result sets
48
+ - Error recovery nodes handling failures
49
+ - Caching nodes storing resource data
50
+ - Analytics nodes tracking API usage patterns
51
+
52
+ Configuration:
53
+ The node supports REST-specific configuration:
54
+ - Base URL for API endpoints
55
+ - Resource paths with parameter placeholders
56
+ - Default headers and authentication
57
+ - API versioning strategies
58
+ - Pagination parameters
59
+ - Response format expectations
60
+
61
+ Implementation Details:
62
+ - Built on HTTPRequestNode for core functionality
63
+ - Automatic URL construction from base + resource
64
+ - Path parameter substitution (e.g., /users/{id})
65
+ - Query parameter handling with encoding
66
+ - Standard REST method mapping
67
+ - Response format negotiation
68
+ - Error response parsing for API-specific errors
69
+ - Link header parsing for pagination
70
+
71
+ Error Handling:
72
+ - 404 errors for missing resources
73
+ - 422 validation errors with field details
74
+ - 401/403 authentication/authorization errors
75
+ - Rate limiting (429) with retry headers
76
+ - 5xx server errors with backoff
77
+ - Network failures with retry logic
78
+ - Malformed response handling
79
+
80
+ Side Effects:
81
+ - Performs HTTP requests to external APIs
82
+ - May modify remote resources (POST/PUT/DELETE)
83
+ - Consumes API rate limits
84
+ - May trigger webhooks or notifications
85
+ - Updates internal request metrics
86
+
87
+ Examples:
88
+ >>> # Initialize REST client
89
+ >>> client = RESTClientNode()
90
+ >>>
91
+ >>> # Get a single resource
92
+ >>> result = client.run(
93
+ ... base_url="https://api.example.com/v1",
94
+ ... resource="users/{id}",
95
+ ... method="GET",
96
+ ... path_params={"id": 123},
97
+ ... headers={"Authorization": "Bearer token"}
98
+ ... )
99
+ >>> assert result["status_code"] == 200
100
+ >>> user = result["content"]
101
+ >>> assert user["id"] == 123
102
+ >>>
103
+ >>> # List resources with pagination
104
+ >>> result = client.run(
105
+ ... base_url="https://api.example.com/v1",
106
+ ... resource="products",
107
+ ... method="GET",
108
+ ... query_params={"page": 1, "per_page": 20, "category": "electronics"}
109
+ ... )
110
+ >>> assert len(result["content"]) <= 20
111
+ >>>
112
+ >>> # Create a new resource
113
+ >>> result = client.run(
114
+ ... base_url="https://api.example.com/v1",
115
+ ... resource="posts",
116
+ ... method="POST",
117
+ ... data={"title": "New Post", "content": "Post content"},
118
+ ... headers={"Content-Type": "application/json"}
119
+ ... )
120
+ >>> assert result["status_code"] == 201
121
+ >>> assert "id" in result["content"]
122
+ >>>
123
+ >>> # Update a resource
124
+ >>> result = client.run(
125
+ ... base_url="https://api.example.com/v1",
126
+ ... resource="users/{id}",
127
+ ... method="PATCH",
128
+ ... path_params={"id": 123},
129
+ ... data={"email": "newemail@example.com"}
130
+ ... )
131
+ >>> assert result["status_code"] == 200
132
+ >>>
133
+ >>> # Delete a resource
134
+ >>> result = client.run(
135
+ ... base_url="https://api.example.com/v1",
136
+ ... resource="comments/{id}",
137
+ ... method="DELETE",
138
+ ... path_params={"id": 456}
139
+ ... )
140
+ >>> assert result["status_code"] in [200, 204]
46
141
  """
47
142
 
48
143
  def __init__(self, **kwargs):
kailash/nodes/base.py CHANGED
@@ -60,7 +60,8 @@ class NodeMetadata(BaseModel):
60
60
  version: str = Field("1.0.0", description="Node version")
61
61
  author: str = Field("", description="Node author")
62
62
  created_at: datetime = Field(
63
- default_factory=datetime.utcnow, description="Node creation date"
63
+ default_factory=lambda: datetime.now(timezone.utc),
64
+ description="Node creation date",
64
65
  )
65
66
  tags: Set[str] = Field(default_factory=set, description="Node tags")
66
67
 
@@ -185,7 +186,19 @@ class Node(ABC):
185
186
  ),
186
187
  )
187
188
  self.logger = logging.getLogger(f"kailash.nodes.{self.id}")
188
- self.config = kwargs
189
+
190
+ # Filter out internal fields from config
191
+ internal_fields = {
192
+ "id",
193
+ "name",
194
+ "description",
195
+ "version",
196
+ "author",
197
+ "tags",
198
+ "metadata",
199
+ }
200
+ self.config = {k: v for k, v in kwargs.items() if k not in internal_fields}
201
+
189
202
  self._validate_config()
190
203
  except ValidationError as e:
191
204
  raise NodeConfigurationError(f"Invalid node metadata: {e}") from e
@@ -45,6 +45,51 @@ class AsyncNode(Node):
45
45
  - TaskManager: Tracks node execution status
46
46
  """
47
47
 
48
+ def execute(self, **runtime_inputs) -> Dict[str, Any]:
49
+ """Execute the node synchronously by running async code in a new event loop.
50
+
51
+ This override allows AsyncNode to work with synchronous runtimes like LocalRuntime.
52
+ It creates a new event loop to run the async code if needed.
53
+
54
+ Args:
55
+ **runtime_inputs: Runtime inputs for node execution
56
+
57
+ Returns:
58
+ Dictionary of validated outputs
59
+
60
+ Raises:
61
+ NodeValidationError: If inputs or outputs are invalid
62
+ NodeExecutionError: If execution fails
63
+ """
64
+ import asyncio
65
+ import sys
66
+
67
+ # Check if we're already in an event loop
68
+ try:
69
+ asyncio.get_running_loop()
70
+ # We're in an event loop - this is problematic for sync execution
71
+ # Try to use nest_asyncio if available
72
+ try:
73
+ import nest_asyncio
74
+
75
+ nest_asyncio.apply()
76
+ return asyncio.run(self.execute_async(**runtime_inputs))
77
+ except ImportError:
78
+ # Fall back to running in a thread pool
79
+ import concurrent.futures
80
+
81
+ with concurrent.futures.ThreadPoolExecutor() as executor:
82
+ future = executor.submit(
83
+ asyncio.run, self.execute_async(**runtime_inputs)
84
+ )
85
+ return future.result()
86
+ except RuntimeError:
87
+ # No event loop running, we can create one
88
+ if sys.platform == "win32":
89
+ # Windows requires special handling
90
+ asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
91
+ return asyncio.run(self.execute_async(**runtime_inputs))
92
+
48
93
  async def async_run(self, **kwargs) -> Dict[str, Any]:
49
94
  """Asynchronous execution method for the node.
50
95