kailash 0.8.3__py3-none-any.whl → 0.8.5__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 (84) hide show
  1. kailash/__init__.py +1 -7
  2. kailash/cli/__init__.py +11 -1
  3. kailash/cli/validation_audit.py +570 -0
  4. kailash/core/actors/supervisor.py +1 -1
  5. kailash/core/resilience/circuit_breaker.py +71 -1
  6. kailash/core/resilience/health_monitor.py +172 -0
  7. kailash/edge/compliance.py +33 -0
  8. kailash/edge/consistency.py +609 -0
  9. kailash/edge/coordination/__init__.py +30 -0
  10. kailash/edge/coordination/global_ordering.py +355 -0
  11. kailash/edge/coordination/leader_election.py +217 -0
  12. kailash/edge/coordination/partition_detector.py +296 -0
  13. kailash/edge/coordination/raft.py +485 -0
  14. kailash/edge/discovery.py +63 -1
  15. kailash/edge/migration/__init__.py +19 -0
  16. kailash/edge/migration/edge_migrator.py +832 -0
  17. kailash/edge/monitoring/__init__.py +21 -0
  18. kailash/edge/monitoring/edge_monitor.py +736 -0
  19. kailash/edge/prediction/__init__.py +10 -0
  20. kailash/edge/prediction/predictive_warmer.py +591 -0
  21. kailash/edge/resource/__init__.py +102 -0
  22. kailash/edge/resource/cloud_integration.py +796 -0
  23. kailash/edge/resource/cost_optimizer.py +949 -0
  24. kailash/edge/resource/docker_integration.py +919 -0
  25. kailash/edge/resource/kubernetes_integration.py +893 -0
  26. kailash/edge/resource/platform_integration.py +913 -0
  27. kailash/edge/resource/predictive_scaler.py +959 -0
  28. kailash/edge/resource/resource_analyzer.py +824 -0
  29. kailash/edge/resource/resource_pools.py +610 -0
  30. kailash/integrations/dataflow_edge.py +261 -0
  31. kailash/mcp_server/registry_integration.py +1 -1
  32. kailash/monitoring/__init__.py +18 -0
  33. kailash/monitoring/alerts.py +646 -0
  34. kailash/monitoring/metrics.py +677 -0
  35. kailash/nodes/__init__.py +2 -0
  36. kailash/nodes/ai/__init__.py +17 -0
  37. kailash/nodes/ai/a2a.py +1914 -43
  38. kailash/nodes/ai/a2a_backup.py +1807 -0
  39. kailash/nodes/ai/hybrid_search.py +972 -0
  40. kailash/nodes/ai/semantic_memory.py +558 -0
  41. kailash/nodes/ai/streaming_analytics.py +947 -0
  42. kailash/nodes/base.py +545 -0
  43. kailash/nodes/edge/__init__.py +36 -0
  44. kailash/nodes/edge/base.py +240 -0
  45. kailash/nodes/edge/cloud_node.py +710 -0
  46. kailash/nodes/edge/coordination.py +239 -0
  47. kailash/nodes/edge/docker_node.py +825 -0
  48. kailash/nodes/edge/edge_data.py +582 -0
  49. kailash/nodes/edge/edge_migration_node.py +392 -0
  50. kailash/nodes/edge/edge_monitoring_node.py +421 -0
  51. kailash/nodes/edge/edge_state.py +673 -0
  52. kailash/nodes/edge/edge_warming_node.py +393 -0
  53. kailash/nodes/edge/kubernetes_node.py +652 -0
  54. kailash/nodes/edge/platform_node.py +766 -0
  55. kailash/nodes/edge/resource_analyzer_node.py +378 -0
  56. kailash/nodes/edge/resource_optimizer_node.py +501 -0
  57. kailash/nodes/edge/resource_scaler_node.py +397 -0
  58. kailash/nodes/ports.py +676 -0
  59. kailash/runtime/local.py +344 -1
  60. kailash/runtime/validation/__init__.py +20 -0
  61. kailash/runtime/validation/connection_context.py +119 -0
  62. kailash/runtime/validation/enhanced_error_formatter.py +202 -0
  63. kailash/runtime/validation/error_categorizer.py +164 -0
  64. kailash/runtime/validation/metrics.py +380 -0
  65. kailash/runtime/validation/performance.py +615 -0
  66. kailash/runtime/validation/suggestion_engine.py +212 -0
  67. kailash/testing/fixtures.py +2 -2
  68. kailash/workflow/builder.py +234 -8
  69. kailash/workflow/contracts.py +418 -0
  70. kailash/workflow/edge_infrastructure.py +369 -0
  71. kailash/workflow/migration.py +3 -3
  72. kailash/workflow/type_inference.py +669 -0
  73. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/METADATA +44 -27
  74. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/RECORD +78 -28
  75. kailash/nexus/__init__.py +0 -21
  76. kailash/nexus/cli/__init__.py +0 -5
  77. kailash/nexus/cli/__main__.py +0 -6
  78. kailash/nexus/cli/main.py +0 -176
  79. kailash/nexus/factory.py +0 -413
  80. kailash/nexus/gateway.py +0 -545
  81. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/WHEEL +0 -0
  82. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/entry_points.txt +0 -0
  83. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/licenses/LICENSE +0 -0
  84. {kailash-0.8.3.dist-info → kailash-0.8.5.dist-info}/top_level.txt +0 -0
kailash/nexus/gateway.py DELETED
@@ -1,545 +0,0 @@
1
- """Nexus Gateway - Main orchestration hub for multi-channel communication."""
2
-
3
- import asyncio
4
- import logging
5
- import signal
6
- import sys
7
- from dataclasses import dataclass, field
8
- from typing import Any, Callable, Dict, List, Optional, Union
9
-
10
- from ..channels.api_channel import APIChannel
11
- from ..channels.base import Channel, ChannelConfig, ChannelStatus, ChannelType
12
- from ..channels.cli_channel import CLIChannel
13
- from ..channels.event_router import EventRoute, EventRouter, RoutingRule
14
- from ..channels.mcp_channel import MCPChannel
15
- from ..channels.session import SessionManager
16
- from ..workflow import Workflow
17
-
18
- logger = logging.getLogger(__name__)
19
-
20
-
21
- @dataclass
22
- class NexusConfig:
23
- """Configuration for Nexus Gateway."""
24
-
25
- # Basic settings
26
- name: str = "kailash-nexus"
27
- description: str = "Multi-channel workflow orchestration gateway"
28
- version: str = "1.0.0"
29
-
30
- # Channel configuration
31
- enable_api: bool = True
32
- enable_cli: bool = True
33
- enable_mcp: bool = True
34
-
35
- # API channel settings
36
- api_host: str = "localhost"
37
- api_port: int = 8000
38
- api_cors_origins: List[str] = field(default_factory=lambda: ["*"])
39
-
40
- # CLI channel settings
41
- cli_interactive: bool = False
42
- cli_prompt_template: str = "nexus> "
43
-
44
- # MCP channel settings
45
- mcp_host: str = "localhost"
46
- mcp_port: int = 3001
47
- mcp_server_name: str = "kailash-nexus-mcp"
48
-
49
- # Session management
50
- session_timeout: int = 3600 # 1 hour
51
- session_cleanup_interval: int = 300 # 5 minutes
52
-
53
- # Event routing
54
- enable_event_routing: bool = True
55
- event_queue_size: int = 10000
56
-
57
- # Advanced settings
58
- enable_health_monitoring: bool = True
59
- health_check_interval: int = 30
60
- graceful_shutdown_timeout: int = 30
61
-
62
-
63
- class NexusGateway:
64
- """Main orchestration hub for the Kailash Nexus framework.
65
-
66
- The Nexus Gateway provides a unified interface for managing multiple
67
- communication channels (API, CLI, MCP) with shared session management
68
- and cross-channel event routing.
69
- """
70
-
71
- def __init__(self, config: Optional[NexusConfig] = None):
72
- """Initialize Nexus Gateway.
73
-
74
- Args:
75
- config: Optional configuration, uses defaults if not provided
76
- """
77
- self.config = config or NexusConfig()
78
-
79
- # Core components
80
- self.session_manager = SessionManager(
81
- default_timeout=self.config.session_timeout,
82
- cleanup_interval=self.config.session_cleanup_interval,
83
- )
84
- self.event_router = EventRouter(session_manager=self.session_manager)
85
-
86
- # Channels
87
- self._channels: Dict[str, Channel] = {}
88
- self._workflows: Dict[str, Workflow] = {}
89
-
90
- # Runtime state
91
- self._running = False
92
- self._startup_tasks: List[asyncio.Task] = []
93
- self._health_task: Optional[asyncio.Task] = None
94
- self._shutdown_event = asyncio.Event()
95
-
96
- # Initialize channels based on configuration
97
- self._initialize_channels()
98
-
99
- logger.info(f"Nexus Gateway initialized: {self.config.name}")
100
-
101
- def _initialize_channels(self) -> None:
102
- """Initialize channels based on configuration."""
103
-
104
- # API Channel
105
- if self.config.enable_api:
106
- api_config = ChannelConfig(
107
- name="api",
108
- channel_type=ChannelType.API,
109
- host=self.config.api_host,
110
- port=self.config.api_port,
111
- enable_event_routing=self.config.enable_event_routing,
112
- extra_config={
113
- "title": f"{self.config.name} API",
114
- "description": f"API interface for {self.config.description}",
115
- "cors_origins": self.config.api_cors_origins,
116
- "enable_durability": True,
117
- "enable_resource_management": True,
118
- "enable_async_execution": True,
119
- "enable_health_checks": True,
120
- },
121
- )
122
- self._channels["api"] = APIChannel(api_config)
123
-
124
- # CLI Channel
125
- if self.config.enable_cli:
126
- cli_config = ChannelConfig(
127
- name="cli",
128
- channel_type=ChannelType.CLI,
129
- host=self.config.api_host, # CLI doesn't use network host
130
- enable_event_routing=self.config.enable_event_routing,
131
- extra_config={
132
- "interactive_mode": self.config.cli_interactive,
133
- "prompt_template": self.config.cli_prompt_template,
134
- },
135
- )
136
- self._channels["cli"] = CLIChannel(cli_config)
137
-
138
- # MCP Channel
139
- if self.config.enable_mcp:
140
- mcp_config = ChannelConfig(
141
- name="mcp",
142
- channel_type=ChannelType.MCP,
143
- host=self.config.mcp_host,
144
- port=self.config.mcp_port,
145
- enable_event_routing=self.config.enable_event_routing,
146
- extra_config={
147
- "server_name": self.config.mcp_server_name,
148
- "description": f"MCP interface for {self.config.description}",
149
- },
150
- )
151
- self._channels["mcp"] = MCPChannel(mcp_config)
152
-
153
- async def start(self) -> None:
154
- """Start the Nexus Gateway and all enabled channels."""
155
- if self._running:
156
- logger.warning("Nexus Gateway is already running")
157
- return
158
-
159
- try:
160
- logger.info(f"Starting Nexus Gateway: {self.config.name}")
161
-
162
- # Start session manager
163
- await self.session_manager.start()
164
-
165
- # Start event router
166
- await self.event_router.start()
167
-
168
- # Register channels with event router
169
- for channel in self._channels.values():
170
- self.event_router.register_channel(channel)
171
-
172
- # Start all channels
173
- channel_tasks = []
174
- for channel_name, channel in self._channels.items():
175
- logger.info(f"Starting {channel_name} channel...")
176
- task = asyncio.create_task(channel.start())
177
- task.set_name(f"start_{channel_name}")
178
- channel_tasks.append(task)
179
-
180
- # Wait for all channels to start
181
- await asyncio.gather(*channel_tasks, return_exceptions=True)
182
-
183
- # Verify channel startup
184
- failed_channels = []
185
- for channel_name, channel in self._channels.items():
186
- if channel.status != ChannelStatus.RUNNING:
187
- failed_channels.append(channel_name)
188
- logger.error(
189
- f"Failed to start {channel_name} channel: {channel.status}"
190
- )
191
-
192
- if failed_channels:
193
- raise RuntimeError(f"Failed to start channels: {failed_channels}")
194
-
195
- # Start health monitoring if enabled
196
- if self.config.enable_health_monitoring:
197
- self._health_task = asyncio.create_task(self._health_monitoring_loop())
198
-
199
- # Setup signal handlers for graceful shutdown
200
- self._setup_signal_handlers()
201
-
202
- self._running = True
203
-
204
- logger.info(
205
- f"Nexus Gateway started successfully with {len(self._channels)} channels"
206
- )
207
-
208
- # Register shared workflows with all channels
209
- await self._register_workflows()
210
-
211
- except Exception as e:
212
- logger.error(f"Failed to start Nexus Gateway: {e}")
213
- await self.stop() # Cleanup on failure
214
- raise
215
-
216
- async def stop(self) -> None:
217
- """Stop the Nexus Gateway and all channels."""
218
- if not self._running:
219
- return
220
-
221
- try:
222
- logger.info("Stopping Nexus Gateway...")
223
- self._running = False
224
- self._shutdown_event.set()
225
-
226
- # Stop health monitoring
227
- if self._health_task and not self._health_task.done():
228
- self._health_task.cancel()
229
- try:
230
- await self._health_task
231
- except asyncio.CancelledError:
232
- pass
233
-
234
- # Stop all channels
235
- channel_tasks = []
236
- for channel_name, channel in self._channels.items():
237
- logger.info(f"Stopping {channel_name} channel...")
238
- task = asyncio.create_task(channel.stop())
239
- task.set_name(f"stop_{channel_name}")
240
- channel_tasks.append(task)
241
-
242
- # Wait for channels to stop (with timeout)
243
- try:
244
- await asyncio.wait_for(
245
- asyncio.gather(*channel_tasks, return_exceptions=True),
246
- timeout=self.config.graceful_shutdown_timeout,
247
- )
248
- except asyncio.TimeoutError:
249
- logger.warning("Channel shutdown timed out")
250
-
251
- # Stop event router
252
- await self.event_router.stop()
253
-
254
- # Stop session manager
255
- await self.session_manager.stop()
256
-
257
- logger.info("Nexus Gateway stopped")
258
-
259
- except Exception as e:
260
- logger.error(f"Error stopping Nexus Gateway: {e}")
261
-
262
- def register_workflow(
263
- self, name: str, workflow: Workflow, channels: Optional[List[str]] = None
264
- ) -> None:
265
- """Register a workflow with specified channels.
266
-
267
- Args:
268
- name: Workflow name
269
- workflow: Workflow instance
270
- channels: List of channel names to register with (all channels if None)
271
- """
272
- self._workflows[name] = workflow
273
-
274
- # Register with specified channels (or all channels if none specified)
275
- target_channels = channels or list(self._channels.keys())
276
-
277
- for channel_name in target_channels:
278
- if channel_name in self._channels:
279
- channel = self._channels[channel_name]
280
-
281
- # Register based on channel type
282
- if isinstance(channel, APIChannel):
283
- channel.register_workflow(name, workflow)
284
- elif isinstance(channel, MCPChannel):
285
- channel.register_workflow(name, workflow)
286
- # CLI channel uses workflows through routing
287
-
288
- logger.info(f"Registered workflow '{name}' with {channel_name} channel")
289
-
290
- def proxy_workflow(
291
- self,
292
- name: str,
293
- proxy_url: str,
294
- channels: Optional[List[str]] = None,
295
- health_check: Optional[str] = None,
296
- ) -> None:
297
- """Register a proxied workflow with specified channels.
298
-
299
- Args:
300
- name: Workflow name
301
- proxy_url: URL to proxy requests to
302
- channels: List of channel names to register with
303
- health_check: Optional health check endpoint
304
- """
305
- target_channels = channels or [
306
- "api"
307
- ] # Default to API only for proxied workflows
308
-
309
- for channel_name in target_channels:
310
- if channel_name in self._channels and isinstance(
311
- self._channels[channel_name], APIChannel
312
- ):
313
- channel = self._channels[channel_name]
314
- channel.proxy_workflow(name, proxy_url, health_check)
315
- logger.info(
316
- f"Registered proxied workflow '{name}' with {channel_name} channel"
317
- )
318
-
319
- async def _register_workflows(self) -> None:
320
- """Register all stored workflows with appropriate channels."""
321
- for name, workflow in self._workflows.items():
322
- self.register_workflow(name, workflow)
323
-
324
- def get_channel(self, name: str) -> Optional[Channel]:
325
- """Get a channel by name.
326
-
327
- Args:
328
- name: Channel name
329
-
330
- Returns:
331
- Channel instance or None if not found
332
- """
333
- return self._channels.get(name)
334
-
335
- def list_channels(self) -> Dict[str, Dict[str, Any]]:
336
- """List all channels and their status.
337
-
338
- Returns:
339
- Dictionary of channel information
340
- """
341
- channels_info = {}
342
-
343
- for name, channel in self._channels.items():
344
- channels_info[name] = {
345
- "name": name,
346
- "type": channel.channel_type.value,
347
- "status": channel.status.value,
348
- "config": {
349
- "host": channel.config.host,
350
- "port": channel.config.port,
351
- "enabled": channel.config.enabled,
352
- },
353
- }
354
-
355
- return channels_info
356
-
357
- def list_workflows(self) -> Dict[str, Dict[str, Any]]:
358
- """List all registered workflows.
359
-
360
- Returns:
361
- Dictionary of workflow information
362
- """
363
- workflows_info = {}
364
-
365
- for name, workflow in self._workflows.items():
366
- workflows_info[name] = {"name": name, "available_on": []}
367
-
368
- # Check which channels have this workflow
369
- for channel_name, channel in self._channels.items():
370
- if (
371
- isinstance(channel, APIChannel)
372
- and name in channel.workflow_server.workflows
373
- ):
374
- workflows_info[name]["available_on"].append(channel_name)
375
- elif (
376
- isinstance(channel, MCPChannel)
377
- and name in channel._workflow_registry
378
- ):
379
- workflows_info[name]["available_on"].append(channel_name)
380
-
381
- return workflows_info
382
-
383
- async def health_check(self) -> Dict[str, Any]:
384
- """Perform comprehensive health check.
385
-
386
- Returns:
387
- Health check results
388
- """
389
- overall_healthy = True
390
- checks = {}
391
-
392
- # Check session manager
393
- try:
394
- session_stats = self.session_manager.get_stats()
395
- checks["session_manager"] = {
396
- "healthy": True,
397
- "total_sessions": session_stats["total_sessions"],
398
- "active_sessions": session_stats["active_sessions"],
399
- }
400
- except Exception as e:
401
- checks["session_manager"] = {"healthy": False, "error": str(e)}
402
- overall_healthy = False
403
-
404
- # Check event router
405
- try:
406
- router_health = await self.event_router.health_check()
407
- checks["event_router"] = router_health
408
- if not router_health["healthy"]:
409
- overall_healthy = False
410
- except Exception as e:
411
- checks["event_router"] = {"healthy": False, "error": str(e)}
412
- overall_healthy = False
413
-
414
- # Check all channels
415
- channel_checks = {}
416
- for name, channel in self._channels.items():
417
- try:
418
- channel_health = await channel.health_check()
419
- channel_checks[name] = channel_health
420
- if not channel_health["healthy"]:
421
- overall_healthy = False
422
- except Exception as e:
423
- channel_checks[name] = {"healthy": False, "error": str(e)}
424
- overall_healthy = False
425
-
426
- checks["channels"] = channel_checks
427
-
428
- return {
429
- "healthy": overall_healthy,
430
- "nexus_running": self._running,
431
- "channels_count": len(self._channels),
432
- "workflows_count": len(self._workflows),
433
- "checks": checks,
434
- "channels": list(self._channels.keys()),
435
- "config": {
436
- "name": self.config.name,
437
- "version": self.config.version,
438
- "enable_api": self.config.enable_api,
439
- "enable_cli": self.config.enable_cli,
440
- "enable_mcp": self.config.enable_mcp,
441
- },
442
- }
443
-
444
- async def get_stats(self) -> Dict[str, Any]:
445
- """Get comprehensive Nexus Gateway statistics.
446
-
447
- Returns:
448
- Statistics dictionary
449
- """
450
- stats = {
451
- "nexus": {
452
- "name": self.config.name,
453
- "version": self.config.version,
454
- "running": self._running,
455
- "channels_enabled": len(self._channels),
456
- "workflows_registered": len(self._workflows),
457
- },
458
- "session_manager": self.session_manager.get_stats(),
459
- "event_router": self.event_router.get_stats(),
460
- "channels": {},
461
- }
462
-
463
- # Get channel-specific stats
464
- for name, channel in self._channels.items():
465
- try:
466
- channel_status = await channel.get_status()
467
- stats["channels"][name] = channel_status
468
- except Exception as e:
469
- stats["channels"][name] = {"error": str(e)}
470
-
471
- return stats
472
-
473
- async def _health_monitoring_loop(self) -> None:
474
- """Background health monitoring loop."""
475
- while self._running:
476
- try:
477
- await asyncio.sleep(self.config.health_check_interval)
478
-
479
- if not self._running:
480
- break
481
-
482
- # Perform health check
483
- health = await self.health_check()
484
-
485
- if not health["healthy"]:
486
- logger.warning("Nexus Gateway health check failed")
487
- logger.debug(f"Health check details: {health}")
488
-
489
- # Check for unhealthy channels
490
- for channel_name, channel_health in health["checks"][
491
- "channels"
492
- ].items():
493
- if not channel_health.get("healthy", False):
494
- logger.warning(
495
- f"Channel {channel_name} is unhealthy: {channel_health}"
496
- )
497
-
498
- except asyncio.CancelledError:
499
- break
500
- except Exception as e:
501
- logger.error(f"Error in health monitoring: {e}")
502
-
503
- def _setup_signal_handlers(self) -> None:
504
- """Setup signal handlers for graceful shutdown."""
505
- if sys.platform != "win32":
506
- # Unix-style signal handling
507
- loop = asyncio.get_event_loop()
508
-
509
- def signal_handler():
510
- logger.info("Received shutdown signal")
511
- asyncio.create_task(self.stop())
512
-
513
- loop.add_signal_handler(signal.SIGINT, signal_handler)
514
- loop.add_signal_handler(signal.SIGTERM, signal_handler)
515
-
516
- async def run_forever(self) -> None:
517
- """Run the Nexus Gateway until shutdown signal."""
518
- if not self._running:
519
- await self.start()
520
-
521
- try:
522
- logger.info("Nexus Gateway is running. Press Ctrl+C to stop.")
523
- await self._shutdown_event.wait()
524
- except KeyboardInterrupt:
525
- logger.info("Received keyboard interrupt")
526
- finally:
527
- await self.stop()
528
-
529
- def __enter__(self):
530
- """Context manager entry."""
531
- return self
532
-
533
- async def __aenter__(self):
534
- """Async context manager entry."""
535
- await self.start()
536
- return self
537
-
538
- def __exit__(self, exc_type, exc_val, exc_tb):
539
- """Context manager exit."""
540
- # Note: This is synchronous, for async context use __aexit__
541
- pass
542
-
543
- async def __aexit__(self, exc_type, exc_val, exc_tb):
544
- """Async context manager exit."""
545
- await self.stop()