kailash 0.2.2__py3-none-any.whl → 0.3.1__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 (117) hide show
  1. kailash/__init__.py +1 -1
  2. kailash/access_control.py +40 -39
  3. kailash/api/auth.py +26 -32
  4. kailash/api/custom_nodes.py +29 -29
  5. kailash/api/custom_nodes_secure.py +35 -35
  6. kailash/api/database.py +17 -17
  7. kailash/api/gateway.py +19 -19
  8. kailash/api/mcp_integration.py +24 -23
  9. kailash/api/studio.py +45 -45
  10. kailash/api/workflow_api.py +8 -8
  11. kailash/cli/commands.py +5 -8
  12. kailash/manifest.py +42 -42
  13. kailash/mcp/__init__.py +1 -1
  14. kailash/mcp/ai_registry_server.py +20 -20
  15. kailash/mcp/client.py +9 -11
  16. kailash/mcp/client_new.py +10 -10
  17. kailash/mcp/server.py +1 -2
  18. kailash/mcp/server_enhanced.py +449 -0
  19. kailash/mcp/servers/ai_registry.py +6 -6
  20. kailash/mcp/utils/__init__.py +31 -0
  21. kailash/mcp/utils/cache.py +267 -0
  22. kailash/mcp/utils/config.py +263 -0
  23. kailash/mcp/utils/formatters.py +293 -0
  24. kailash/mcp/utils/metrics.py +418 -0
  25. kailash/nodes/ai/agents.py +9 -9
  26. kailash/nodes/ai/ai_providers.py +33 -34
  27. kailash/nodes/ai/embedding_generator.py +31 -32
  28. kailash/nodes/ai/intelligent_agent_orchestrator.py +62 -66
  29. kailash/nodes/ai/iterative_llm_agent.py +48 -48
  30. kailash/nodes/ai/llm_agent.py +32 -33
  31. kailash/nodes/ai/models.py +13 -13
  32. kailash/nodes/ai/self_organizing.py +44 -44
  33. kailash/nodes/api/__init__.py +5 -0
  34. kailash/nodes/api/auth.py +11 -11
  35. kailash/nodes/api/graphql.py +13 -13
  36. kailash/nodes/api/http.py +19 -19
  37. kailash/nodes/api/monitoring.py +463 -0
  38. kailash/nodes/api/rate_limiting.py +9 -13
  39. kailash/nodes/api/rest.py +29 -29
  40. kailash/nodes/api/security.py +819 -0
  41. kailash/nodes/base.py +24 -26
  42. kailash/nodes/base_async.py +7 -7
  43. kailash/nodes/base_cycle_aware.py +12 -12
  44. kailash/nodes/base_with_acl.py +5 -5
  45. kailash/nodes/code/python.py +56 -55
  46. kailash/nodes/data/__init__.py +6 -0
  47. kailash/nodes/data/directory.py +6 -6
  48. kailash/nodes/data/event_generation.py +297 -0
  49. kailash/nodes/data/file_discovery.py +598 -0
  50. kailash/nodes/data/readers.py +8 -8
  51. kailash/nodes/data/retrieval.py +10 -10
  52. kailash/nodes/data/sharepoint_graph.py +17 -17
  53. kailash/nodes/data/sources.py +5 -5
  54. kailash/nodes/data/sql.py +13 -13
  55. kailash/nodes/data/streaming.py +25 -25
  56. kailash/nodes/data/vector_db.py +22 -22
  57. kailash/nodes/data/writers.py +7 -7
  58. kailash/nodes/logic/async_operations.py +17 -17
  59. kailash/nodes/logic/convergence.py +11 -11
  60. kailash/nodes/logic/loop.py +4 -4
  61. kailash/nodes/logic/operations.py +11 -11
  62. kailash/nodes/logic/workflow.py +8 -9
  63. kailash/nodes/mixins/mcp.py +17 -17
  64. kailash/nodes/mixins.py +8 -10
  65. kailash/nodes/transform/chunkers.py +3 -3
  66. kailash/nodes/transform/formatters.py +7 -7
  67. kailash/nodes/transform/processors.py +11 -11
  68. kailash/runtime/access_controlled.py +18 -18
  69. kailash/runtime/async_local.py +18 -20
  70. kailash/runtime/docker.py +24 -26
  71. kailash/runtime/local.py +55 -31
  72. kailash/runtime/parallel.py +25 -25
  73. kailash/runtime/parallel_cyclic.py +29 -29
  74. kailash/runtime/runner.py +6 -6
  75. kailash/runtime/testing.py +22 -22
  76. kailash/sdk_exceptions.py +0 -58
  77. kailash/security.py +14 -26
  78. kailash/tracking/manager.py +38 -38
  79. kailash/tracking/metrics_collector.py +15 -14
  80. kailash/tracking/models.py +53 -53
  81. kailash/tracking/storage/base.py +7 -17
  82. kailash/tracking/storage/database.py +22 -23
  83. kailash/tracking/storage/filesystem.py +38 -40
  84. kailash/utils/export.py +21 -21
  85. kailash/utils/templates.py +8 -9
  86. kailash/visualization/api.py +30 -34
  87. kailash/visualization/dashboard.py +17 -17
  88. kailash/visualization/performance.py +32 -19
  89. kailash/visualization/reports.py +30 -28
  90. kailash/workflow/builder.py +8 -8
  91. kailash/workflow/convergence.py +13 -12
  92. kailash/workflow/cycle_analyzer.py +38 -33
  93. kailash/workflow/cycle_builder.py +12 -12
  94. kailash/workflow/cycle_config.py +16 -15
  95. kailash/workflow/cycle_debugger.py +40 -40
  96. kailash/workflow/cycle_exceptions.py +29 -29
  97. kailash/workflow/cycle_profiler.py +21 -21
  98. kailash/workflow/cycle_state.py +20 -22
  99. kailash/workflow/cyclic_runner.py +45 -45
  100. kailash/workflow/graph.py +57 -45
  101. kailash/workflow/mermaid_visualizer.py +9 -11
  102. kailash/workflow/migration.py +22 -22
  103. kailash/workflow/mock_registry.py +6 -6
  104. kailash/workflow/runner.py +9 -9
  105. kailash/workflow/safety.py +12 -13
  106. kailash/workflow/state.py +8 -11
  107. kailash/workflow/templates.py +19 -19
  108. kailash/workflow/validation.py +14 -14
  109. kailash/workflow/visualization.py +32 -24
  110. kailash-0.3.1.dist-info/METADATA +476 -0
  111. kailash-0.3.1.dist-info/RECORD +136 -0
  112. kailash-0.2.2.dist-info/METADATA +0 -121
  113. kailash-0.2.2.dist-info/RECORD +0 -126
  114. {kailash-0.2.2.dist-info → kailash-0.3.1.dist-info}/WHEEL +0 -0
  115. {kailash-0.2.2.dist-info → kailash-0.3.1.dist-info}/entry_points.txt +0 -0
  116. {kailash-0.2.2.dist-info → kailash-0.3.1.dist-info}/licenses/LICENSE +0 -0
  117. {kailash-0.2.2.dist-info → kailash-0.3.1.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  """Document retrieval nodes for finding relevant content using various similarity methods."""
2
2
 
3
- from typing import Any, Dict, List
3
+ from typing import Any
4
4
 
5
5
  from kailash.nodes.base import Node, NodeParameter, register_node
6
6
 
@@ -9,7 +9,7 @@ from kailash.nodes.base import Node, NodeParameter, register_node
9
9
  class RelevanceScorerNode(Node):
10
10
  """Scores chunk relevance using various similarity methods including embeddings similarity."""
11
11
 
12
- def get_parameters(self) -> Dict[str, NodeParameter]:
12
+ def get_parameters(self) -> dict[str, NodeParameter]:
13
13
  return {
14
14
  "chunks": NodeParameter(
15
15
  name="chunks",
@@ -45,7 +45,7 @@ class RelevanceScorerNode(Node):
45
45
  ),
46
46
  }
47
47
 
48
- def run(self, **kwargs) -> Dict[str, Any]:
48
+ def run(self, **kwargs) -> dict[str, Any]:
49
49
  chunks = kwargs.get("chunks", [])
50
50
  query_embeddings = kwargs.get("query_embedding", [])
51
51
  chunk_embeddings = kwargs.get("chunk_embeddings", [])
@@ -98,8 +98,8 @@ class RelevanceScorerNode(Node):
98
98
  return {"relevant_chunks": top_chunks}
99
99
 
100
100
  def _cosine_similarity_scoring(
101
- self, chunks: List[Dict], query_embeddings: List, chunk_embeddings: List
102
- ) -> List[Dict]:
101
+ self, chunks: list[dict], query_embeddings: list, chunk_embeddings: list
102
+ ) -> list[dict]:
103
103
  """Score chunks using cosine similarity."""
104
104
  # Extract actual embedding vectors from the embedding objects
105
105
  # EmbeddingGeneratorNode returns embeddings in format: {"embedding": [...], "text": "...", "dimensions": X}
@@ -131,7 +131,7 @@ class RelevanceScorerNode(Node):
131
131
  return 0.5
132
132
 
133
133
  try:
134
- dot_product = sum(x * y for x, y in zip(a, b))
134
+ dot_product = sum(x * y for x, y in zip(a, b, strict=False))
135
135
  norm_a = sum(x * x for x in a) ** 0.5
136
136
  norm_b = sum(x * x for x in b) ** 0.5
137
137
  return dot_product / (norm_a * norm_b) if norm_a * norm_b > 0 else 0
@@ -162,16 +162,16 @@ class RelevanceScorerNode(Node):
162
162
  return scored_chunks
163
163
 
164
164
  def _bm25_scoring(
165
- self, chunks: List[Dict], query_embeddings: List, chunk_embeddings: List
166
- ) -> List[Dict]:
165
+ self, chunks: list[dict], query_embeddings: list, chunk_embeddings: list
166
+ ) -> list[dict]:
167
167
  """Score chunks using BM25 algorithm (future implementation)."""
168
168
  # TODO: Implement BM25 scoring
169
169
  # For now, return chunks with default scores
170
170
  return [{**chunk, "relevance_score": 0.5} for chunk in chunks]
171
171
 
172
172
  def _tfidf_scoring(
173
- self, chunks: List[Dict], query_embeddings: List, chunk_embeddings: List
174
- ) -> List[Dict]:
173
+ self, chunks: list[dict], query_embeddings: list, chunk_embeddings: list
174
+ ) -> list[dict]:
175
175
  """Score chunks using TF-IDF similarity (future implementation)."""
176
176
  # TODO: Implement TF-IDF scoring
177
177
  # For now, return chunks with default scores
@@ -23,7 +23,7 @@ Downstream consumers:
23
23
 
24
24
  import os
25
25
  from pathlib import Path
26
- from typing import Any, Dict, List, Optional
26
+ from typing import Any
27
27
 
28
28
  import requests
29
29
 
@@ -79,7 +79,7 @@ class SharePointGraphReader(Node):
79
79
  author="Kailash SDK",
80
80
  )
81
81
 
82
- def get_parameters(self) -> Dict[str, NodeParameter]:
82
+ def get_parameters(self) -> dict[str, NodeParameter]:
83
83
  """Define input parameters for SharePoint Graph operations."""
84
84
  return {
85
85
  "tenant_id": NodeParameter(
@@ -149,7 +149,7 @@ class SharePointGraphReader(Node):
149
149
 
150
150
  def _authenticate(
151
151
  self, tenant_id: str, client_id: str, client_secret: str
152
- ) -> Dict[str, Any]:
152
+ ) -> dict[str, Any]:
153
153
  """Authenticate with Microsoft Graph API using MSAL.
154
154
 
155
155
  Returns dict with token and headers for stateless operation.
@@ -184,7 +184,7 @@ class SharePointGraphReader(Node):
184
184
  },
185
185
  }
186
186
 
187
- def _get_site_data(self, site_url: str, headers: Dict[str, str]) -> Dict[str, Any]:
187
+ def _get_site_data(self, site_url: str, headers: dict[str, str]) -> dict[str, Any]:
188
188
  """Get SharePoint site data from Graph API."""
189
189
  # Convert SharePoint URL to Graph API site ID format
190
190
  site_id = site_url.replace("https://", "").replace(
@@ -201,8 +201,8 @@ class SharePointGraphReader(Node):
201
201
  )
202
202
 
203
203
  def _list_libraries(
204
- self, site_id: str, headers: Dict[str, str]
205
- ) -> List[Dict[str, Any]]:
204
+ self, site_id: str, headers: dict[str, str]
205
+ ) -> list[dict[str, Any]]:
206
206
  """List all document libraries in the site."""
207
207
  drives_url = f"https://graph.microsoft.com/v1.0/sites/{site_id}/drives"
208
208
  response = requests.get(drives_url, headers=headers)
@@ -215,8 +215,8 @@ class SharePointGraphReader(Node):
215
215
  )
216
216
 
217
217
  def _get_drive_id(
218
- self, site_id: str, library_name: str, headers: Dict[str, str]
219
- ) -> Optional[str]:
218
+ self, site_id: str, library_name: str, headers: dict[str, str]
219
+ ) -> str | None:
220
220
  """Get the drive ID for a specific library."""
221
221
  libraries = self._list_libraries(site_id, headers)
222
222
  for lib in libraries:
@@ -225,8 +225,8 @@ class SharePointGraphReader(Node):
225
225
  return None
226
226
 
227
227
  def _list_files(
228
- self, site_id: str, library_name: str, folder_path: str, headers: Dict[str, str]
229
- ) -> Dict[str, Any]:
228
+ self, site_id: str, library_name: str, folder_path: str, headers: dict[str, str]
229
+ ) -> dict[str, Any]:
230
230
  """List files in a specific library and folder."""
231
231
  drive_id = self._get_drive_id(site_id, library_name, headers)
232
232
  if not drive_id:
@@ -289,8 +289,8 @@ class SharePointGraphReader(Node):
289
289
  file_name: str,
290
290
  folder_path: str,
291
291
  local_path: str,
292
- headers: Dict[str, str],
293
- ) -> Dict[str, Any]:
292
+ headers: dict[str, str],
293
+ ) -> dict[str, Any]:
294
294
  """Download a file from SharePoint."""
295
295
  drive_id = self._get_drive_id(site_id, library_name, headers)
296
296
  if not drive_id:
@@ -344,8 +344,8 @@ class SharePointGraphReader(Node):
344
344
  )
345
345
 
346
346
  def _search_files(
347
- self, site_id: str, library_name: str, query: str, headers: Dict[str, str]
348
- ) -> Dict[str, Any]:
347
+ self, site_id: str, library_name: str, query: str, headers: dict[str, str]
348
+ ) -> dict[str, Any]:
349
349
  """Search for files in a library."""
350
350
  drive_id = self._get_drive_id(site_id, library_name, headers)
351
351
  if not drive_id:
@@ -383,7 +383,7 @@ class SharePointGraphReader(Node):
383
383
  f"Search failed: {response.status_code} - {response.text}"
384
384
  )
385
385
 
386
- def run(self, **kwargs) -> Dict[str, Any]:
386
+ def run(self, **kwargs) -> dict[str, Any]:
387
387
  """Execute SharePoint Graph operation.
388
388
 
389
389
  This method is stateless and returns JSON-serializable results
@@ -494,7 +494,7 @@ class SharePointGraphWriter(Node):
494
494
  author="Kailash SDK",
495
495
  )
496
496
 
497
- def get_parameters(self) -> Dict[str, NodeParameter]:
497
+ def get_parameters(self) -> dict[str, NodeParameter]:
498
498
  """Define input parameters for SharePoint upload operations."""
499
499
  return {
500
500
  "tenant_id": NodeParameter(
@@ -549,7 +549,7 @@ class SharePointGraphWriter(Node):
549
549
  ),
550
550
  }
551
551
 
552
- def run(self, **kwargs) -> Dict[str, Any]:
552
+ def run(self, **kwargs) -> dict[str, Any]:
553
553
  """Execute SharePoint upload operation."""
554
554
  # Validate required parameters
555
555
  tenant_id = kwargs.get("tenant_id")
@@ -1,6 +1,6 @@
1
1
  """Data source nodes for providing input data to workflows."""
2
2
 
3
- from typing import Any, Dict
3
+ from typing import Any
4
4
 
5
5
  from kailash.nodes.base import Node, NodeParameter, register_node
6
6
 
@@ -9,7 +9,7 @@ from kailash.nodes.base import Node, NodeParameter, register_node
9
9
  class DocumentSourceNode(Node):
10
10
  """Provides sample documents for hierarchical RAG processing."""
11
11
 
12
- def get_parameters(self) -> Dict[str, NodeParameter]:
12
+ def get_parameters(self) -> dict[str, NodeParameter]:
13
13
  return {
14
14
  "sample_documents": NodeParameter(
15
15
  name="sample_documents",
@@ -20,7 +20,7 @@ class DocumentSourceNode(Node):
20
20
  )
21
21
  }
22
22
 
23
- def run(self, **kwargs) -> Dict[str, Any]:
23
+ def run(self, **kwargs) -> dict[str, Any]:
24
24
  # Sample documents for demonstration
25
25
  documents = [
26
26
  {
@@ -48,7 +48,7 @@ class DocumentSourceNode(Node):
48
48
  class QuerySourceNode(Node):
49
49
  """Provides sample queries for RAG processing."""
50
50
 
51
- def get_parameters(self) -> Dict[str, NodeParameter]:
51
+ def get_parameters(self) -> dict[str, NodeParameter]:
52
52
  return {
53
53
  "query": NodeParameter(
54
54
  name="query",
@@ -59,7 +59,7 @@ class QuerySourceNode(Node):
59
59
  )
60
60
  }
61
61
 
62
- def run(self, **kwargs) -> Dict[str, Any]:
62
+ def run(self, **kwargs) -> dict[str, Any]:
63
63
  query = kwargs.get("query", "What are the main types of machine learning?")
64
64
  print(f"Debug QuerySource: providing query='{query}'")
65
65
  return {"query": query}
kailash/nodes/data/sql.py CHANGED
@@ -16,7 +16,7 @@ import os
16
16
  import threading
17
17
  import time
18
18
  from datetime import datetime
19
- from typing import Any, Dict, List, Optional, Tuple
19
+ from typing import Any, Optional
20
20
 
21
21
  import yaml
22
22
  from sqlalchemy import create_engine, text
@@ -38,7 +38,7 @@ class SQLDatabaseNode(Node):
38
38
  self.config_path = project_config_path
39
39
  self.config = self._load_project_config()
40
40
 
41
- def _load_project_config(self) -> Dict[str, Any]:
41
+ def _load_project_config(self) -> dict[str, Any]:
42
42
  """Load project configuration from YAML file."""
43
43
  if not os.path.exists(self.config_path):
44
44
  raise NodeExecutionError(
@@ -46,7 +46,7 @@ class SQLDatabaseNode(Node):
46
46
  )
47
47
 
48
48
  try:
49
- with open(self.config_path, "r") as f:
49
+ with open(self.config_path) as f:
50
50
  config = yaml.safe_load(f)
51
51
  return config or {}
52
52
  except yaml.YAMLError as e:
@@ -56,7 +56,7 @@ class SQLDatabaseNode(Node):
56
56
 
57
57
  def get_database_config(
58
58
  self, connection_name: str
59
- ) -> Tuple[str, Dict[str, Any]]:
59
+ ) -> tuple[str, dict[str, Any]]:
60
60
  """Get database configuration by connection name.
61
61
 
62
62
  Args:
@@ -185,8 +185,8 @@ class SQLDatabaseNode(Node):
185
185
  """
186
186
 
187
187
  # Class-level shared resources for connection pooling
188
- _shared_pools: Dict[Tuple[str, frozenset], Any] = {}
189
- _pool_metrics: Dict[Tuple[str, frozenset], Dict[str, Any]] = {}
188
+ _shared_pools: dict[tuple[str, frozenset], Any] = {}
189
+ _pool_metrics: dict[tuple[str, frozenset], dict[str, Any]] = {}
190
190
  _pool_lock = threading.Lock()
191
191
  _config_manager: Optional["SQLDatabaseNode._DatabaseConfigManager"] = None
192
192
 
@@ -252,7 +252,7 @@ class SQLDatabaseNode(Node):
252
252
  # Call parent constructor
253
253
  super().__init__(**kwargs)
254
254
 
255
- def get_parameters(self) -> Dict[str, NodeParameter]:
255
+ def get_parameters(self) -> dict[str, NodeParameter]:
256
256
  """Define input parameters for SQL execution.
257
257
 
258
258
  Configuration parameters (provided to constructor):
@@ -334,7 +334,7 @@ class SQLDatabaseNode(Node):
334
334
 
335
335
  return self._shared_pools[cache_key]
336
336
 
337
- def run(self, **kwargs) -> Dict[str, Any]:
337
+ def run(self, **kwargs) -> dict[str, Any]:
338
338
  """Execute SQL query using shared connection pool.
339
339
 
340
340
  Args:
@@ -458,7 +458,7 @@ class SQLDatabaseNode(Node):
458
458
  }
459
459
 
460
460
  @classmethod
461
- def get_pool_status(cls) -> Dict[str, Any]:
461
+ def get_pool_status(cls) -> dict[str, Any]:
462
462
  """Get status of all shared connection pools."""
463
463
  with cls._pool_lock:
464
464
  status = {}
@@ -736,7 +736,7 @@ class SQLDatabaseNode(Node):
736
736
 
737
737
  return sanitized
738
738
 
739
- def _convert_to_named_parameters(self, query: str, parameters: List) -> tuple:
739
+ def _convert_to_named_parameters(self, query: str, parameters: list) -> tuple:
740
740
  """Convert positional parameters to named parameters for SQLAlchemy 2.0.
741
741
 
742
742
  Args:
@@ -790,8 +790,8 @@ class SQLDatabaseNode(Node):
790
790
  return modified_query, param_dict
791
791
 
792
792
  def _format_results(
793
- self, rows: List, columns: List[str], result_format: str
794
- ) -> List[Any]:
793
+ self, rows: list, columns: list[str], result_format: str
794
+ ) -> list[Any]:
795
795
  """Format query results according to specified format.
796
796
 
797
797
  Args:
@@ -820,4 +820,4 @@ class SQLDatabaseNode(Node):
820
820
  self.logger.warning(
821
821
  f"Unknown result_format '{result_format}', defaulting to 'dict'"
822
822
  )
823
- return [dict(zip(columns, row)) for row in rows]
823
+ return [dict(zip(columns, row, strict=False)) for row in rows]
@@ -44,7 +44,7 @@ Example:
44
44
  """
45
45
 
46
46
  import time
47
- from typing import Any, Dict, List
47
+ from typing import Any
48
48
 
49
49
  from kailash.nodes.base import Node, NodeMetadata, NodeParameter, register_node
50
50
  from kailash.sdk_exceptions import NodeConfigurationError, NodeExecutionError
@@ -148,7 +148,7 @@ class KafkaConsumerNode(Node):
148
148
  self._consumer = None
149
149
  self._topic = None
150
150
 
151
- def get_parameters(self) -> Dict[str, NodeParameter]:
151
+ def get_parameters(self) -> dict[str, NodeParameter]:
152
152
  """Define parameters for the Kafka consumer node."""
153
153
  return {
154
154
  "bootstrap_servers": NodeParameter(
@@ -206,7 +206,7 @@ class KafkaConsumerNode(Node):
206
206
  ),
207
207
  }
208
208
 
209
- def configure(self, config: Dict[str, Any]) -> None:
209
+ def configure(self, config: dict[str, Any]) -> None:
210
210
  """Configure the Kafka consumer.
211
211
 
212
212
  Creates and configures the Kafka consumer with the specified
@@ -241,7 +241,7 @@ class KafkaConsumerNode(Node):
241
241
  self._consumer = f"kafka_consumer_{self.config['group_id']}"
242
242
  self._topic = self.config["topic"]
243
243
 
244
- def run(self, **kwargs) -> Dict[str, Any]:
244
+ def run(self, **kwargs) -> dict[str, Any]:
245
245
  """Consume messages from Kafka.
246
246
 
247
247
  Implementation of the abstract run method from the base Node class.
@@ -254,7 +254,7 @@ class KafkaConsumerNode(Node):
254
254
  """
255
255
  return self.execute(kwargs)
256
256
 
257
- def execute(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
257
+ def execute(self, inputs: dict[str, Any]) -> dict[str, Any]:
258
258
  """Consume messages from Kafka.
259
259
 
260
260
  Polls for messages up to the specified limit or timeout.
@@ -286,7 +286,7 @@ class KafkaConsumerNode(Node):
286
286
  except Exception as e:
287
287
  raise NodeExecutionError(f"Failed to consume messages: {str(e)}")
288
288
 
289
- def _consume_messages(self, max_messages: int, timeout_ms: int) -> List[Dict]:
289
+ def _consume_messages(self, max_messages: int, timeout_ms: int) -> list[dict]:
290
290
  """Consume messages from Kafka.
291
291
 
292
292
  This is a placeholder for actual message consumption logic.
@@ -420,7 +420,7 @@ class StreamPublisherNode(Node):
420
420
  self._publisher = None
421
421
  self._protocol = None
422
422
 
423
- def get_parameters(self) -> Dict[str, NodeParameter]:
423
+ def get_parameters(self) -> dict[str, NodeParameter]:
424
424
  """Define parameters for the stream publisher node."""
425
425
  return {
426
426
  "protocol": NodeParameter(
@@ -465,7 +465,7 @@ class StreamPublisherNode(Node):
465
465
  ),
466
466
  }
467
467
 
468
- def configure(self, config: Dict[str, Any]) -> None:
468
+ def configure(self, config: dict[str, Any]) -> None:
469
469
  """Configure the stream publisher.
470
470
 
471
471
  Creates the appropriate publisher based on the protocol.
@@ -499,7 +499,7 @@ class StreamPublisherNode(Node):
499
499
  # Placeholder for actual publisher creation
500
500
  self._publisher = f"{self._protocol}_publisher"
501
501
 
502
- def run(self, **kwargs) -> Dict[str, Any]:
502
+ def run(self, **kwargs) -> dict[str, Any]:
503
503
  """Publish messages to the streaming platform.
504
504
 
505
505
  Implementation of the abstract run method from the base Node class.
@@ -512,7 +512,7 @@ class StreamPublisherNode(Node):
512
512
  """
513
513
  return self.execute(kwargs)
514
514
 
515
- def execute(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
515
+ def execute(self, inputs: dict[str, Any]) -> dict[str, Any]:
516
516
  """Publish messages to the streaming platform.
517
517
 
518
518
  Args:
@@ -541,7 +541,7 @@ class StreamPublisherNode(Node):
541
541
  except Exception as e:
542
542
  raise NodeExecutionError(f"Failed to publish messages: {str(e)}")
543
543
 
544
- def _publish_messages(self, messages: List[Dict], headers: Dict) -> Dict[str, Any]:
544
+ def _publish_messages(self, messages: list[dict], headers: dict) -> dict[str, Any]:
545
545
  """Publish messages to the stream.
546
546
 
547
547
  This is a placeholder for actual publishing logic.
@@ -683,7 +683,7 @@ class WebSocketNode(Node):
683
683
  self._connected = False
684
684
  self._message_queue = []
685
685
 
686
- def get_parameters(self) -> Dict[str, NodeParameter]:
686
+ def get_parameters(self) -> dict[str, NodeParameter]:
687
687
  """Get the parameters for this node.
688
688
 
689
689
  Returns:
@@ -750,7 +750,7 @@ class WebSocketNode(Node):
750
750
  ),
751
751
  }
752
752
 
753
- def configure(self, config: Dict[str, Any]) -> None:
753
+ def configure(self, config: dict[str, Any]) -> None:
754
754
  """Configure the WebSocket connection.
755
755
 
756
756
  Validates the URL and prepares connection parameters.
@@ -770,7 +770,7 @@ class WebSocketNode(Node):
770
770
  if not url.startswith(("ws://", "wss://")):
771
771
  raise NodeConfigurationError("URL must start with ws:// or wss://")
772
772
 
773
- def run(self, **kwargs) -> Dict[str, Any]:
773
+ def run(self, **kwargs) -> dict[str, Any]:
774
774
  """Run the WebSocket node.
775
775
 
776
776
  This method fulfills the abstract run method requirement from the base Node class.
@@ -786,7 +786,7 @@ class WebSocketNode(Node):
786
786
  """
787
787
  return self.execute(kwargs)
788
788
 
789
- def execute(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
789
+ def execute(self, inputs: dict[str, Any]) -> dict[str, Any]:
790
790
  """Execute WebSocket operations.
791
791
 
792
792
  Performs the requested action (connect, send, receive, disconnect).
@@ -816,7 +816,7 @@ class WebSocketNode(Node):
816
816
  except Exception as e:
817
817
  raise NodeExecutionError(f"WebSocket operation failed: {str(e)}")
818
818
 
819
- def _connect(self) -> Dict[str, Any]:
819
+ def _connect(self) -> dict[str, Any]:
820
820
  """Connect to the WebSocket server.
821
821
 
822
822
  Returns:
@@ -832,7 +832,7 @@ class WebSocketNode(Node):
832
832
  "metadata": {"timestamp": time.time()},
833
833
  }
834
834
 
835
- def _send_message(self, message: Any) -> Dict[str, Any]:
835
+ def _send_message(self, message: Any) -> dict[str, Any]:
836
836
  """Send a message through the WebSocket.
837
837
 
838
838
  Args:
@@ -851,7 +851,7 @@ class WebSocketNode(Node):
851
851
  "metadata": {"timestamp": time.time()},
852
852
  }
853
853
 
854
- def _receive_messages(self, timeout: float) -> Dict[str, Any]:
854
+ def _receive_messages(self, timeout: float) -> dict[str, Any]:
855
855
  """Receive messages from the WebSocket.
856
856
 
857
857
  Args:
@@ -877,7 +877,7 @@ class WebSocketNode(Node):
877
877
  "metadata": {"count": len(messages), "timeout": timeout},
878
878
  }
879
879
 
880
- def _disconnect(self) -> Dict[str, Any]:
880
+ def _disconnect(self) -> dict[str, Any]:
881
881
  """Disconnect from the WebSocket server.
882
882
 
883
883
  Returns:
@@ -994,7 +994,7 @@ class EventStreamNode(Node):
994
994
  self._connected = False
995
995
  self._last_event_id = None
996
996
 
997
- def get_parameters(self) -> Dict[str, NodeParameter]:
997
+ def get_parameters(self) -> dict[str, NodeParameter]:
998
998
  """Get the parameters for this node.
999
999
 
1000
1000
  Returns:
@@ -1048,7 +1048,7 @@ class EventStreamNode(Node):
1048
1048
  ),
1049
1049
  }
1050
1050
 
1051
- def run(self, **kwargs) -> Dict[str, Any]:
1051
+ def run(self, **kwargs) -> dict[str, Any]:
1052
1052
  """Run the EventStream node.
1053
1053
 
1054
1054
  This method fulfills the abstract run method requirement from the base Node class.
@@ -1064,7 +1064,7 @@ class EventStreamNode(Node):
1064
1064
  """
1065
1065
  return self.execute(kwargs)
1066
1066
 
1067
- def execute(self, inputs: Dict[str, Any]) -> Dict[str, Any]:
1067
+ def execute(self, inputs: dict[str, Any]) -> dict[str, Any]:
1068
1068
  """Execute EventStream operations.
1069
1069
 
1070
1070
  Args:
@@ -1090,7 +1090,7 @@ class EventStreamNode(Node):
1090
1090
  except Exception as e:
1091
1091
  raise NodeExecutionError(f"EventStream operation failed: {str(e)}")
1092
1092
 
1093
- def _start_stream(self) -> Dict[str, Any]:
1093
+ def _start_stream(self) -> dict[str, Any]:
1094
1094
  """Start the event stream connection.
1095
1095
 
1096
1096
  Returns:
@@ -1106,7 +1106,7 @@ class EventStreamNode(Node):
1106
1106
  "metadata": {"timestamp": time.time()},
1107
1107
  }
1108
1108
 
1109
- def _stop_stream(self) -> Dict[str, Any]:
1109
+ def _stop_stream(self) -> dict[str, Any]:
1110
1110
  """Stop the event stream connection.
1111
1111
 
1112
1112
  Returns:
@@ -1124,7 +1124,7 @@ class EventStreamNode(Node):
1124
1124
  },
1125
1125
  }
1126
1126
 
1127
- def _receive_events(self, max_events: int) -> Dict[str, Any]:
1127
+ def _receive_events(self, max_events: int) -> dict[str, Any]:
1128
1128
  """Receive events from the stream.
1129
1129
 
1130
1130
  Args: