kailash 0.4.0__py3-none-any.whl → 0.4.2__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 +3 -4
- kailash/middleware/__init__.py +4 -2
- kailash/middleware/auth/__init__.py +55 -12
- kailash/middleware/auth/exceptions.py +80 -0
- kailash/middleware/auth/jwt_auth.py +265 -123
- kailash/middleware/auth/models.py +137 -0
- kailash/middleware/auth/utils.py +257 -0
- kailash/middleware/communication/api_gateway.py +49 -7
- kailash/middleware/core/agent_ui.py +108 -1
- kailash/middleware/mcp/enhanced_server.py +2 -2
- kailash/nodes/__init__.py +2 -0
- kailash/nodes/admin/__init__.py +9 -2
- kailash/nodes/admin/audit_log.py +1 -1
- kailash/nodes/admin/security_event.py +7 -3
- kailash/nodes/ai/ai_providers.py +247 -40
- kailash/nodes/ai/llm_agent.py +29 -3
- kailash/nodes/ai/vision_utils.py +148 -0
- kailash/nodes/alerts/__init__.py +26 -0
- kailash/nodes/alerts/base.py +234 -0
- kailash/nodes/alerts/discord.py +499 -0
- kailash/nodes/code/python.py +18 -0
- kailash/nodes/data/streaming.py +8 -8
- kailash/nodes/security/audit_log.py +48 -36
- kailash/nodes/security/security_event.py +73 -72
- kailash/security.py +1 -1
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/METADATA +4 -1
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/RECORD +31 -25
- kailash/middleware/auth/kailash_jwt_auth.py +0 -616
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/WHEEL +0 -0
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/entry_points.txt +0 -0
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/licenses/LICENSE +0 -0
- {kailash-0.4.0.dist-info → kailash-0.4.2.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,234 @@
|
|
1
|
+
"""Base alert node class for the Kailash SDK.
|
2
|
+
|
3
|
+
This module provides the foundation for all alert and notification nodes in the system.
|
4
|
+
It defines common parameters, severity levels, and formatting utilities that are shared
|
5
|
+
across different alert implementations.
|
6
|
+
|
7
|
+
The alert system is designed to provide:
|
8
|
+
- Consistent interface across different notification channels
|
9
|
+
- Severity-based formatting and colors
|
10
|
+
- Structured context data support
|
11
|
+
- Easy extensibility for new alert types
|
12
|
+
"""
|
13
|
+
|
14
|
+
from abc import abstractmethod
|
15
|
+
from enum import Enum
|
16
|
+
from typing import Any
|
17
|
+
|
18
|
+
from kailash.nodes.base import Node, NodeParameter
|
19
|
+
|
20
|
+
|
21
|
+
class AlertSeverity(str, Enum):
|
22
|
+
"""Standard alert severity levels with associated colors."""
|
23
|
+
|
24
|
+
SUCCESS = "success"
|
25
|
+
WARNING = "warning"
|
26
|
+
ERROR = "error"
|
27
|
+
CRITICAL = "critical"
|
28
|
+
INFO = "info"
|
29
|
+
|
30
|
+
def get_color(self) -> int:
|
31
|
+
"""Get the color code for this severity level (Discord/Slack compatible)."""
|
32
|
+
colors = {
|
33
|
+
AlertSeverity.SUCCESS: 0x28A745, # Green
|
34
|
+
AlertSeverity.WARNING: 0xFFC107, # Yellow/Amber
|
35
|
+
AlertSeverity.ERROR: 0xDC3545, # Red
|
36
|
+
AlertSeverity.CRITICAL: 0x8B0000, # Dark Red
|
37
|
+
AlertSeverity.INFO: 0x007BFF, # Blue
|
38
|
+
}
|
39
|
+
return colors.get(self, 0x808080) # Default to gray
|
40
|
+
|
41
|
+
|
42
|
+
class AlertNode(Node):
|
43
|
+
"""
|
44
|
+
Base class for all alert and notification nodes in the Kailash SDK.
|
45
|
+
|
46
|
+
This abstract base class provides common functionality for sending alerts
|
47
|
+
through various channels (Discord, Slack, email, webhooks, etc.). It defines
|
48
|
+
standard parameters that all alert nodes should support and provides utilities
|
49
|
+
for formatting messages consistently.
|
50
|
+
|
51
|
+
Design Philosophy:
|
52
|
+
Alert nodes should provide a simple, consistent interface for sending
|
53
|
+
notifications while allowing channel-specific features when needed.
|
54
|
+
The base class handles common concerns like severity levels, titles,
|
55
|
+
and context data, while subclasses implement channel-specific logic.
|
56
|
+
|
57
|
+
Common Parameters:
|
58
|
+
- alert_type: Severity level (success, warning, error, critical, info)
|
59
|
+
- title: Alert title/subject
|
60
|
+
- message: Main alert message body
|
61
|
+
- context: Additional structured data
|
62
|
+
|
63
|
+
Subclasses must implement:
|
64
|
+
- get_channel_parameters(): Define channel-specific parameters
|
65
|
+
- send_alert(): Implement the actual alert sending logic
|
66
|
+
"""
|
67
|
+
|
68
|
+
category = "alerts"
|
69
|
+
|
70
|
+
def get_parameters(self) -> dict[str, NodeParameter]:
|
71
|
+
"""Define common parameters for all alert nodes.
|
72
|
+
|
73
|
+
Returns:
|
74
|
+
Dictionary of common alert parameters merged with channel-specific ones
|
75
|
+
"""
|
76
|
+
common_params = {
|
77
|
+
"alert_type": NodeParameter(
|
78
|
+
name="alert_type",
|
79
|
+
type=str,
|
80
|
+
required=False,
|
81
|
+
default="info",
|
82
|
+
description="Alert severity level: success, warning, error, critical, info",
|
83
|
+
),
|
84
|
+
"title": NodeParameter(
|
85
|
+
name="title",
|
86
|
+
type=str,
|
87
|
+
required=True,
|
88
|
+
description="Alert title or subject",
|
89
|
+
),
|
90
|
+
"message": NodeParameter(
|
91
|
+
name="message",
|
92
|
+
type=str,
|
93
|
+
required=False,
|
94
|
+
default="",
|
95
|
+
description="Main alert message body",
|
96
|
+
),
|
97
|
+
"context": NodeParameter(
|
98
|
+
name="context",
|
99
|
+
type=dict,
|
100
|
+
required=False,
|
101
|
+
default={},
|
102
|
+
description="Additional context data to include in the alert",
|
103
|
+
),
|
104
|
+
}
|
105
|
+
|
106
|
+
# Merge with channel-specific parameters
|
107
|
+
channel_params = self.get_channel_parameters()
|
108
|
+
return {**common_params, **channel_params}
|
109
|
+
|
110
|
+
@abstractmethod
|
111
|
+
def get_channel_parameters(self) -> dict[str, NodeParameter]:
|
112
|
+
"""Define channel-specific parameters.
|
113
|
+
|
114
|
+
Subclasses must implement this to add their specific parameters
|
115
|
+
like webhook URLs, authentication tokens, formatting options, etc.
|
116
|
+
|
117
|
+
Returns:
|
118
|
+
Dictionary of channel-specific parameters
|
119
|
+
"""
|
120
|
+
pass
|
121
|
+
|
122
|
+
def validate_alert_type(self, alert_type: str) -> AlertSeverity:
|
123
|
+
"""Validate and normalize the alert type.
|
124
|
+
|
125
|
+
Args:
|
126
|
+
alert_type: String representation of alert severity
|
127
|
+
|
128
|
+
Returns:
|
129
|
+
Normalized AlertSeverity enum value
|
130
|
+
|
131
|
+
Raises:
|
132
|
+
ValueError: If alert_type is not valid
|
133
|
+
"""
|
134
|
+
try:
|
135
|
+
return AlertSeverity(alert_type.lower())
|
136
|
+
except ValueError:
|
137
|
+
valid_types = [s.value for s in AlertSeverity]
|
138
|
+
raise ValueError(
|
139
|
+
f"Invalid alert_type '{alert_type}'. Must be one of: {', '.join(valid_types)}"
|
140
|
+
)
|
141
|
+
|
142
|
+
def format_context(self, context: dict[str, Any]) -> str:
|
143
|
+
"""Format context dictionary for display.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
context: Dictionary of context data
|
147
|
+
|
148
|
+
Returns:
|
149
|
+
Formatted string representation of context
|
150
|
+
"""
|
151
|
+
if not context:
|
152
|
+
return ""
|
153
|
+
|
154
|
+
lines = []
|
155
|
+
for key, value in context.items():
|
156
|
+
# Handle nested dictionaries and lists
|
157
|
+
if isinstance(value, (dict, list)):
|
158
|
+
import json
|
159
|
+
|
160
|
+
value_str = json.dumps(value) # No indent for single-line format
|
161
|
+
else:
|
162
|
+
value_str = str(value)
|
163
|
+
|
164
|
+
lines.append(f"**{key}**: {value_str}")
|
165
|
+
|
166
|
+
return "\n".join(lines)
|
167
|
+
|
168
|
+
def run(self, **kwargs) -> dict[str, Any]:
|
169
|
+
"""Execute the alert node.
|
170
|
+
|
171
|
+
This method validates common parameters, normalizes the alert type,
|
172
|
+
and delegates to the subclass's send_alert method.
|
173
|
+
|
174
|
+
Args:
|
175
|
+
**kwargs: Alert parameters including common and channel-specific ones
|
176
|
+
|
177
|
+
Returns:
|
178
|
+
Dictionary with alert execution results
|
179
|
+
"""
|
180
|
+
# Validate and normalize alert type
|
181
|
+
alert_type_str = kwargs.get("alert_type", "info")
|
182
|
+
alert_severity = self.validate_alert_type(alert_type_str)
|
183
|
+
|
184
|
+
# Extract common parameters
|
185
|
+
title = kwargs["title"]
|
186
|
+
message = kwargs.get("message", "")
|
187
|
+
context = kwargs.get("context", {})
|
188
|
+
|
189
|
+
# Extract channel-specific parameters only
|
190
|
+
channel_params = {
|
191
|
+
k: v
|
192
|
+
for k, v in kwargs.items()
|
193
|
+
if k not in ["alert_type", "title", "message", "context"]
|
194
|
+
}
|
195
|
+
|
196
|
+
# Call subclass implementation
|
197
|
+
result = self.send_alert(
|
198
|
+
severity=alert_severity,
|
199
|
+
title=title,
|
200
|
+
message=message,
|
201
|
+
context=context,
|
202
|
+
**channel_params, # Pass only channel-specific params
|
203
|
+
)
|
204
|
+
|
205
|
+
# Add standard metadata to result
|
206
|
+
result["alert_type"] = alert_severity.value
|
207
|
+
result["title"] = title
|
208
|
+
|
209
|
+
return result
|
210
|
+
|
211
|
+
@abstractmethod
|
212
|
+
def send_alert(
|
213
|
+
self,
|
214
|
+
severity: AlertSeverity,
|
215
|
+
title: str,
|
216
|
+
message: str,
|
217
|
+
context: dict[str, Any],
|
218
|
+
**kwargs,
|
219
|
+
) -> dict[str, Any]:
|
220
|
+
"""Send the alert through the specific channel.
|
221
|
+
|
222
|
+
Subclasses must implement this method to handle the actual alert delivery.
|
223
|
+
|
224
|
+
Args:
|
225
|
+
severity: Normalized alert severity
|
226
|
+
title: Alert title
|
227
|
+
message: Alert message body
|
228
|
+
context: Additional context data
|
229
|
+
**kwargs: Channel-specific parameters
|
230
|
+
|
231
|
+
Returns:
|
232
|
+
Dictionary with channel-specific response data
|
233
|
+
"""
|
234
|
+
pass
|