kailash 0.4.2__py3-none-any.whl → 0.6.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 +1 -1
- kailash/client/__init__.py +12 -0
- kailash/client/enhanced_client.py +306 -0
- kailash/core/actors/__init__.py +16 -0
- kailash/core/actors/connection_actor.py +566 -0
- kailash/core/actors/supervisor.py +364 -0
- kailash/edge/__init__.py +16 -0
- kailash/edge/compliance.py +834 -0
- kailash/edge/discovery.py +659 -0
- kailash/edge/location.py +582 -0
- kailash/gateway/__init__.py +33 -0
- kailash/gateway/api.py +289 -0
- kailash/gateway/enhanced_gateway.py +357 -0
- kailash/gateway/resource_resolver.py +217 -0
- kailash/gateway/security.py +227 -0
- kailash/middleware/auth/models.py +2 -2
- kailash/middleware/database/base_models.py +1 -7
- kailash/middleware/database/repositories.py +3 -1
- kailash/middleware/gateway/__init__.py +22 -0
- kailash/middleware/gateway/checkpoint_manager.py +398 -0
- kailash/middleware/gateway/deduplicator.py +382 -0
- kailash/middleware/gateway/durable_gateway.py +417 -0
- kailash/middleware/gateway/durable_request.py +498 -0
- kailash/middleware/gateway/event_store.py +459 -0
- kailash/nodes/admin/audit_log.py +364 -6
- kailash/nodes/admin/permission_check.py +817 -33
- kailash/nodes/admin/role_management.py +1242 -108
- kailash/nodes/admin/schema_manager.py +438 -0
- kailash/nodes/admin/user_management.py +1209 -681
- kailash/nodes/api/http.py +95 -71
- kailash/nodes/base.py +281 -164
- kailash/nodes/base_async.py +30 -31
- kailash/nodes/code/__init__.py +8 -1
- kailash/nodes/code/async_python.py +1035 -0
- kailash/nodes/code/python.py +1 -0
- kailash/nodes/data/async_sql.py +12 -25
- kailash/nodes/data/sql.py +20 -11
- kailash/nodes/data/workflow_connection_pool.py +643 -0
- kailash/nodes/rag/__init__.py +1 -4
- kailash/resources/__init__.py +40 -0
- kailash/resources/factory.py +533 -0
- kailash/resources/health.py +319 -0
- kailash/resources/reference.py +288 -0
- kailash/resources/registry.py +392 -0
- kailash/runtime/async_local.py +711 -302
- kailash/testing/__init__.py +34 -0
- kailash/testing/async_test_case.py +353 -0
- kailash/testing/async_utils.py +345 -0
- kailash/testing/fixtures.py +458 -0
- kailash/testing/mock_registry.py +495 -0
- kailash/utils/resource_manager.py +420 -0
- kailash/workflow/__init__.py +8 -0
- kailash/workflow/async_builder.py +621 -0
- kailash/workflow/async_patterns.py +766 -0
- kailash/workflow/builder.py +93 -10
- kailash/workflow/cyclic_runner.py +111 -41
- kailash/workflow/graph.py +7 -2
- kailash/workflow/resilience.py +11 -1
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/METADATA +12 -7
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/RECORD +64 -28
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/WHEEL +0 -0
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/entry_points.txt +0 -0
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.4.2.dist-info → kailash-0.6.0.dist-info}/top_level.txt +0 -0
kailash/__init__.py
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
"""Enhanced client SDK for Kailash Gateway.
|
2
|
+
|
3
|
+
This module provides Python client for interacting with the Enhanced Gateway API.
|
4
|
+
"""
|
5
|
+
|
6
|
+
from .enhanced_client import KailashClient, SyncKailashClient, WorkflowResult
|
7
|
+
|
8
|
+
__all__ = [
|
9
|
+
"KailashClient",
|
10
|
+
"SyncKailashClient",
|
11
|
+
"WorkflowResult",
|
12
|
+
]
|
@@ -0,0 +1,306 @@
|
|
1
|
+
"""Enhanced client for interacting with Kailash gateway.
|
2
|
+
|
3
|
+
This module provides async and sync clients for the Enhanced Gateway API
|
4
|
+
with support for resource references and convenient helper methods.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import asyncio
|
8
|
+
import json
|
9
|
+
import logging
|
10
|
+
from dataclasses import dataclass
|
11
|
+
from typing import Any, Dict, List, Optional, Union
|
12
|
+
|
13
|
+
import aiohttp
|
14
|
+
|
15
|
+
from ..gateway.resource_resolver import ResourceReference
|
16
|
+
|
17
|
+
logger = logging.getLogger(__name__)
|
18
|
+
|
19
|
+
|
20
|
+
@dataclass
|
21
|
+
class WorkflowResult:
|
22
|
+
"""Result from workflow execution."""
|
23
|
+
|
24
|
+
request_id: str
|
25
|
+
workflow_id: str
|
26
|
+
status: str
|
27
|
+
result: Optional[Any] = None
|
28
|
+
error: Optional[str] = None
|
29
|
+
execution_time: Optional[float] = None
|
30
|
+
|
31
|
+
@property
|
32
|
+
def is_success(self) -> bool:
|
33
|
+
return self.status == "completed"
|
34
|
+
|
35
|
+
@property
|
36
|
+
def is_failed(self) -> bool:
|
37
|
+
return self.status == "failed"
|
38
|
+
|
39
|
+
@property
|
40
|
+
def is_running(self) -> bool:
|
41
|
+
return self.status in ["pending", "running"]
|
42
|
+
|
43
|
+
|
44
|
+
class KailashClient:
|
45
|
+
"""Enhanced client for interacting with Kailash gateway."""
|
46
|
+
|
47
|
+
def __init__(self, base_url: str, api_key: Optional[str] = None, timeout: int = 30):
|
48
|
+
self.base_url = base_url.rstrip("/")
|
49
|
+
self.api_key = api_key
|
50
|
+
self.timeout = timeout
|
51
|
+
self._session: Optional[aiohttp.ClientSession] = None
|
52
|
+
|
53
|
+
async def __aenter__(self):
|
54
|
+
"""Async context manager entry."""
|
55
|
+
await self._ensure_session()
|
56
|
+
return self
|
57
|
+
|
58
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
59
|
+
"""Async context manager exit."""
|
60
|
+
await self.close()
|
61
|
+
|
62
|
+
async def _ensure_session(self):
|
63
|
+
"""Ensure HTTP session exists."""
|
64
|
+
if not self._session:
|
65
|
+
headers = {}
|
66
|
+
if self.api_key:
|
67
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
68
|
+
|
69
|
+
timeout = aiohttp.ClientTimeout(total=self.timeout)
|
70
|
+
self._session = aiohttp.ClientSession(headers=headers, timeout=timeout)
|
71
|
+
|
72
|
+
async def close(self):
|
73
|
+
"""Close HTTP session."""
|
74
|
+
if self._session:
|
75
|
+
await self._session.close()
|
76
|
+
self._session = None
|
77
|
+
|
78
|
+
async def execute_workflow(
|
79
|
+
self,
|
80
|
+
workflow_id: str,
|
81
|
+
inputs: Dict[str, Any],
|
82
|
+
resources: Optional[Dict[str, Any]] = None,
|
83
|
+
context: Optional[Dict[str, Any]] = None,
|
84
|
+
wait: bool = True,
|
85
|
+
poll_interval: float = 1.0,
|
86
|
+
max_wait: float = 300.0,
|
87
|
+
) -> WorkflowResult:
|
88
|
+
"""Execute workflow with resource support."""
|
89
|
+
await self._ensure_session()
|
90
|
+
|
91
|
+
# Prepare request
|
92
|
+
request_data = {
|
93
|
+
"inputs": inputs,
|
94
|
+
"resources": resources or {},
|
95
|
+
"context": context or {},
|
96
|
+
}
|
97
|
+
|
98
|
+
# Execute workflow
|
99
|
+
async with self._session.post(
|
100
|
+
f"{self.base_url}/api/v1/workflows/{workflow_id}/execute", json=request_data
|
101
|
+
) as response:
|
102
|
+
response.raise_for_status()
|
103
|
+
result_data = await response.json()
|
104
|
+
|
105
|
+
result = WorkflowResult(**result_data)
|
106
|
+
|
107
|
+
# Wait for completion if requested
|
108
|
+
if wait and result.is_running:
|
109
|
+
result = await self.wait_for_completion(
|
110
|
+
workflow_id,
|
111
|
+
result.request_id,
|
112
|
+
poll_interval=poll_interval,
|
113
|
+
max_wait=max_wait,
|
114
|
+
)
|
115
|
+
|
116
|
+
return result
|
117
|
+
|
118
|
+
async def wait_for_completion(
|
119
|
+
self,
|
120
|
+
workflow_id: str,
|
121
|
+
request_id: str,
|
122
|
+
poll_interval: float = 1.0,
|
123
|
+
max_wait: float = 300.0,
|
124
|
+
) -> WorkflowResult:
|
125
|
+
"""Wait for workflow completion."""
|
126
|
+
await self._ensure_session()
|
127
|
+
|
128
|
+
elapsed = 0.0
|
129
|
+
while elapsed < max_wait:
|
130
|
+
# Get status
|
131
|
+
result = await self.get_workflow_status(workflow_id, request_id)
|
132
|
+
|
133
|
+
if not result.is_running:
|
134
|
+
return result
|
135
|
+
|
136
|
+
# Wait before next poll
|
137
|
+
await asyncio.sleep(poll_interval)
|
138
|
+
elapsed += poll_interval
|
139
|
+
|
140
|
+
# Timeout
|
141
|
+
raise TimeoutError(f"Workflow did not complete within {max_wait} seconds")
|
142
|
+
|
143
|
+
async def get_workflow_status(
|
144
|
+
self, workflow_id: str, request_id: str
|
145
|
+
) -> WorkflowResult:
|
146
|
+
"""Get workflow execution status."""
|
147
|
+
await self._ensure_session()
|
148
|
+
|
149
|
+
async with self._session.get(
|
150
|
+
f"{self.base_url}/api/v1/workflows/{workflow_id}/status/{request_id}"
|
151
|
+
) as response:
|
152
|
+
response.raise_for_status()
|
153
|
+
result_data = await response.json()
|
154
|
+
|
155
|
+
return WorkflowResult(**result_data)
|
156
|
+
|
157
|
+
async def list_workflows(self) -> Dict[str, Any]:
|
158
|
+
"""List available workflows."""
|
159
|
+
await self._ensure_session()
|
160
|
+
|
161
|
+
async with self._session.get(f"{self.base_url}/api/v1/workflows") as response:
|
162
|
+
response.raise_for_status()
|
163
|
+
return await response.json()
|
164
|
+
|
165
|
+
async def get_workflow_details(self, workflow_id: str) -> Dict[str, Any]:
|
166
|
+
"""Get details of a specific workflow."""
|
167
|
+
await self._ensure_session()
|
168
|
+
|
169
|
+
async with self._session.get(
|
170
|
+
f"{self.base_url}/api/v1/workflows/{workflow_id}"
|
171
|
+
) as response:
|
172
|
+
response.raise_for_status()
|
173
|
+
return await response.json()
|
174
|
+
|
175
|
+
async def health_check(self) -> Dict[str, Any]:
|
176
|
+
"""Check gateway health."""
|
177
|
+
await self._ensure_session()
|
178
|
+
|
179
|
+
async with self._session.get(f"{self.base_url}/api/v1/health") as response:
|
180
|
+
response.raise_for_status()
|
181
|
+
return await response.json()
|
182
|
+
|
183
|
+
async def list_resources(self) -> List[str]:
|
184
|
+
"""List available resources."""
|
185
|
+
await self._ensure_session()
|
186
|
+
|
187
|
+
async with self._session.get(f"{self.base_url}/api/v1/resources") as response:
|
188
|
+
response.raise_for_status()
|
189
|
+
return await response.json()
|
190
|
+
|
191
|
+
# Resource reference helpers
|
192
|
+
def ref(self, resource_name: str) -> str:
|
193
|
+
"""Create reference to registered resource."""
|
194
|
+
return f"@{resource_name}"
|
195
|
+
|
196
|
+
def database(
|
197
|
+
self,
|
198
|
+
host: str,
|
199
|
+
database: str,
|
200
|
+
port: int = 5432,
|
201
|
+
credentials_ref: Optional[str] = None,
|
202
|
+
**kwargs,
|
203
|
+
) -> Dict[str, Any]:
|
204
|
+
"""Create database resource reference."""
|
205
|
+
config = {"host": host, "port": port, "database": database, **kwargs}
|
206
|
+
|
207
|
+
return {
|
208
|
+
"type": "database",
|
209
|
+
"config": config,
|
210
|
+
"credentials_ref": credentials_ref,
|
211
|
+
}
|
212
|
+
|
213
|
+
def http_client(
|
214
|
+
self,
|
215
|
+
base_url: Optional[str] = None,
|
216
|
+
headers: Optional[Dict[str, str]] = None,
|
217
|
+
credentials_ref: Optional[str] = None,
|
218
|
+
**kwargs,
|
219
|
+
) -> Dict[str, Any]:
|
220
|
+
"""Create HTTP client resource reference."""
|
221
|
+
config = {**kwargs}
|
222
|
+
if base_url:
|
223
|
+
config["base_url"] = base_url
|
224
|
+
if headers:
|
225
|
+
config["headers"] = headers
|
226
|
+
|
227
|
+
return {
|
228
|
+
"type": "http_client",
|
229
|
+
"config": config,
|
230
|
+
"credentials_ref": credentials_ref,
|
231
|
+
}
|
232
|
+
|
233
|
+
def cache(
|
234
|
+
self,
|
235
|
+
host: str = "localhost",
|
236
|
+
port: int = 6379,
|
237
|
+
credentials_ref: Optional[str] = None,
|
238
|
+
**kwargs,
|
239
|
+
) -> Dict[str, Any]:
|
240
|
+
"""Create cache resource reference."""
|
241
|
+
config = {"host": host, "port": port, **kwargs}
|
242
|
+
|
243
|
+
return {"type": "cache", "config": config, "credentials_ref": credentials_ref}
|
244
|
+
|
245
|
+
|
246
|
+
# Synchronous wrapper for convenience
|
247
|
+
class SyncKailashClient:
|
248
|
+
"""Synchronous wrapper for KailashClient."""
|
249
|
+
|
250
|
+
def __init__(self, base_url: str, api_key: Optional[str] = None):
|
251
|
+
self.async_client = KailashClient(base_url, api_key)
|
252
|
+
|
253
|
+
def execute_workflow(
|
254
|
+
self, workflow_id: str, inputs: Dict[str, Any], **kwargs
|
255
|
+
) -> WorkflowResult:
|
256
|
+
"""Execute workflow synchronously."""
|
257
|
+
loop = asyncio.new_event_loop()
|
258
|
+
asyncio.set_event_loop(loop)
|
259
|
+
try:
|
260
|
+
return loop.run_until_complete(
|
261
|
+
self.async_client.execute_workflow(workflow_id, inputs, **kwargs)
|
262
|
+
)
|
263
|
+
finally:
|
264
|
+
loop.close()
|
265
|
+
|
266
|
+
def list_workflows(self) -> Dict[str, Any]:
|
267
|
+
"""List workflows synchronously."""
|
268
|
+
loop = asyncio.new_event_loop()
|
269
|
+
asyncio.set_event_loop(loop)
|
270
|
+
try:
|
271
|
+
return loop.run_until_complete(self.async_client.list_workflows())
|
272
|
+
finally:
|
273
|
+
loop.close()
|
274
|
+
|
275
|
+
def get_workflow_details(self, workflow_id: str) -> Dict[str, Any]:
|
276
|
+
"""Get workflow details synchronously."""
|
277
|
+
loop = asyncio.new_event_loop()
|
278
|
+
asyncio.set_event_loop(loop)
|
279
|
+
try:
|
280
|
+
return loop.run_until_complete(
|
281
|
+
self.async_client.get_workflow_details(workflow_id)
|
282
|
+
)
|
283
|
+
finally:
|
284
|
+
loop.close()
|
285
|
+
|
286
|
+
def health_check(self) -> Dict[str, Any]:
|
287
|
+
"""Check health synchronously."""
|
288
|
+
loop = asyncio.new_event_loop()
|
289
|
+
asyncio.set_event_loop(loop)
|
290
|
+
try:
|
291
|
+
return loop.run_until_complete(self.async_client.health_check())
|
292
|
+
finally:
|
293
|
+
loop.close()
|
294
|
+
|
295
|
+
def list_resources(self) -> List[str]:
|
296
|
+
"""List resources synchronously."""
|
297
|
+
loop = asyncio.new_event_loop()
|
298
|
+
asyncio.set_event_loop(loop)
|
299
|
+
try:
|
300
|
+
return loop.run_until_complete(self.async_client.list_resources())
|
301
|
+
finally:
|
302
|
+
loop.close()
|
303
|
+
|
304
|
+
# Delegate resource helpers
|
305
|
+
def __getattr__(self, name):
|
306
|
+
return getattr(self.async_client, name)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
"""Actor-based components for Kailash SDK.
|
2
|
+
|
3
|
+
This module provides actor-based patterns for improved fault tolerance
|
4
|
+
and isolation in distributed systems.
|
5
|
+
"""
|
6
|
+
|
7
|
+
from .connection_actor import ActorConnection, ConnectionActor, ConnectionState
|
8
|
+
from .supervisor import ActorSupervisor, SupervisionStrategy
|
9
|
+
|
10
|
+
__all__ = [
|
11
|
+
"ActorConnection",
|
12
|
+
"ConnectionState",
|
13
|
+
"ConnectionActor",
|
14
|
+
"ActorSupervisor",
|
15
|
+
"SupervisionStrategy",
|
16
|
+
]
|