kailash 0.1.5__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 (75) 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 +2 -0
  21. kailash/nodes/ai/a2a.py +714 -67
  22. kailash/nodes/ai/intelligent_agent_orchestrator.py +31 -37
  23. kailash/nodes/ai/iterative_llm_agent.py +1280 -0
  24. kailash/nodes/ai/llm_agent.py +324 -1
  25. kailash/nodes/ai/self_organizing.py +5 -6
  26. kailash/nodes/base.py +15 -2
  27. kailash/nodes/base_async.py +45 -0
  28. kailash/nodes/base_cycle_aware.py +374 -0
  29. kailash/nodes/base_with_acl.py +338 -0
  30. kailash/nodes/code/python.py +135 -27
  31. kailash/nodes/data/readers.py +16 -6
  32. kailash/nodes/data/writers.py +16 -6
  33. kailash/nodes/logic/__init__.py +8 -0
  34. kailash/nodes/logic/convergence.py +642 -0
  35. kailash/nodes/logic/loop.py +153 -0
  36. kailash/nodes/logic/operations.py +187 -27
  37. kailash/nodes/mixins/__init__.py +11 -0
  38. kailash/nodes/mixins/mcp.py +228 -0
  39. kailash/nodes/mixins.py +387 -0
  40. kailash/runtime/__init__.py +2 -1
  41. kailash/runtime/access_controlled.py +458 -0
  42. kailash/runtime/local.py +106 -33
  43. kailash/runtime/parallel_cyclic.py +529 -0
  44. kailash/sdk_exceptions.py +90 -5
  45. kailash/security.py +845 -0
  46. kailash/tracking/manager.py +38 -15
  47. kailash/tracking/models.py +1 -1
  48. kailash/tracking/storage/filesystem.py +30 -2
  49. kailash/utils/__init__.py +8 -0
  50. kailash/workflow/__init__.py +18 -0
  51. kailash/workflow/convergence.py +270 -0
  52. kailash/workflow/cycle_analyzer.py +768 -0
  53. kailash/workflow/cycle_builder.py +573 -0
  54. kailash/workflow/cycle_config.py +709 -0
  55. kailash/workflow/cycle_debugger.py +760 -0
  56. kailash/workflow/cycle_exceptions.py +601 -0
  57. kailash/workflow/cycle_profiler.py +671 -0
  58. kailash/workflow/cycle_state.py +338 -0
  59. kailash/workflow/cyclic_runner.py +985 -0
  60. kailash/workflow/graph.py +500 -39
  61. kailash/workflow/migration.py +768 -0
  62. kailash/workflow/safety.py +365 -0
  63. kailash/workflow/templates.py +744 -0
  64. kailash/workflow/validation.py +693 -0
  65. {kailash-0.1.5.dist-info → kailash-0.2.0.dist-info}/METADATA +256 -12
  66. kailash-0.2.0.dist-info/RECORD +125 -0
  67. kailash/nodes/mcp/__init__.py +0 -11
  68. kailash/nodes/mcp/client.py +0 -554
  69. kailash/nodes/mcp/resource.py +0 -682
  70. kailash/nodes/mcp/server.py +0 -577
  71. kailash-0.1.5.dist-info/RECORD +0 -88
  72. {kailash-0.1.5.dist-info → kailash-0.2.0.dist-info}/WHEEL +0 -0
  73. {kailash-0.1.5.dist-info → kailash-0.2.0.dist-info}/entry_points.txt +0 -0
  74. {kailash-0.1.5.dist-info → kailash-0.2.0.dist-info}/licenses/LICENSE +0 -0
  75. {kailash-0.1.5.dist-info → kailash-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,601 @@
1
+ """
2
+ Enhanced exception classes for cyclic workflow operations.
3
+
4
+ This module provides specialized exception classes with actionable error messages,
5
+ debugging context, and suggested solutions for cycle-related errors. These exceptions
6
+ replace generic errors with detailed diagnostics to improve developer experience.
7
+ """
8
+
9
+ import logging
10
+ from typing import Any, Dict, List, Optional
11
+
12
+ from kailash.sdk_exceptions import WorkflowException
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+
17
+ class CycleException(WorkflowException):
18
+ """
19
+ Base exception for all cycle-related errors.
20
+
21
+ This base class provides common functionality for cycle exceptions
22
+ including error codes, context information, and suggested solutions.
23
+ All cycle-specific exceptions inherit from this class.
24
+
25
+ Design Philosophy:
26
+ Provides actionable error messages with specific suggestions for
27
+ resolution. Each exception includes context about what went wrong,
28
+ why it happened, and how to fix it.
29
+
30
+ Upstream Dependencies:
31
+ - Inherits from WorkflowException for consistency
32
+ - Used throughout cycle builder and execution systems
33
+
34
+ Downstream Consumers:
35
+ - Developer error handling and debugging
36
+ - IDE error highlighting and suggestions
37
+ - Automated error reporting and analysis
38
+
39
+ Attributes:
40
+ error_code (str): Unique code for programmatic error handling
41
+ context (Dict[str, Any]): Additional context about the error
42
+ suggestions (List[str]): Actionable suggestions for resolution
43
+
44
+ Example:
45
+ >>> try:
46
+ ... # Some cycle operation
47
+ ... pass
48
+ ... except CycleException as e:
49
+ ... print(f"Error: {e}")
50
+ ... print(f"Code: {e.error_code}")
51
+ ... print(f"Suggestions: {e.suggestions}")
52
+ """
53
+
54
+ def __init__(
55
+ self,
56
+ message: str,
57
+ error_code: str = "CYCLE_ERROR",
58
+ context: Optional[Dict[str, Any]] = None,
59
+ suggestions: Optional[List[str]] = None,
60
+ documentation_url: Optional[str] = None
61
+ ):
62
+ """
63
+ Initialize cycle exception with enhanced error information.
64
+
65
+ Args:
66
+ message (str): Human-readable error description
67
+ error_code (str): Unique error code for programmatic handling
68
+ context (Dict[str, Any], optional): Additional error context
69
+ suggestions (List[str], optional): Actionable resolution suggestions
70
+ documentation_url (str, optional): URL to relevant documentation
71
+
72
+ Side Effects:
73
+ Logs error details for debugging and analysis
74
+ """
75
+ super().__init__(message)
76
+ self.error_code = error_code
77
+ self.context = context or {}
78
+ self.suggestions = suggestions or []
79
+ self.documentation_url = documentation_url
80
+
81
+ # Log error for debugging
82
+ logger.debug(f"CycleException raised: {error_code} - {message}")
83
+
84
+ def get_detailed_message(self) -> str:
85
+ """
86
+ Get detailed error message with context and suggestions.
87
+
88
+ Returns:
89
+ str: Comprehensive error message with all available information
90
+
91
+ Example:
92
+ >>> exception.get_detailed_message()
93
+ 'Error: Invalid cycle configuration
94
+ Code: CYCLE_CONFIG_001
95
+ Context: {"cycle_id": "test", "max_iterations": -5}
96
+ Suggestions:
97
+ • Set max_iterations to a positive value (recommended: 10-100)
98
+ • Add convergence_check for early termination
99
+ Documentation: https://docs.kailash.ai/cycles/configuration'
100
+ """
101
+ message_parts = [f"Error: {self.args[0]}"]
102
+
103
+ if self.error_code != "CYCLE_ERROR":
104
+ message_parts.append(f"Code: {self.error_code}")
105
+
106
+ if self.context:
107
+ context_str = ", ".join(f"{k}={v}" for k, v in self.context.items())
108
+ message_parts.append(f"Context: {context_str}")
109
+
110
+ if self.suggestions:
111
+ message_parts.append("Suggestions:")
112
+ for suggestion in self.suggestions:
113
+ message_parts.append(f"• {suggestion}")
114
+
115
+ if self.documentation_url:
116
+ message_parts.append(f"Documentation: {self.documentation_url}")
117
+
118
+ return "\n".join(message_parts)
119
+
120
+ def __str__(self) -> str:
121
+ """Return string representation with enhanced details."""
122
+ return self.get_detailed_message()
123
+
124
+
125
+ class CycleConfigurationError(CycleException):
126
+ """
127
+ Raised when cycle configuration is invalid or incomplete.
128
+
129
+ This exception provides specific guidance for cycle configuration issues,
130
+ including missing parameters, invalid values, and conflicting settings.
131
+ It helps developers quickly identify and fix configuration problems.
132
+
133
+ Common scenarios:
134
+ - Missing required parameters (max_iterations or convergence_check)
135
+ - Invalid parameter values (negative iterations, empty conditions)
136
+ - Unsafe expressions in convergence conditions
137
+ - Conflicting cycle settings
138
+
139
+ Example:
140
+ >>> raise CycleConfigurationError(
141
+ ... "Missing termination condition",
142
+ ... error_code="CYCLE_CONFIG_001",
143
+ ... context={"cycle_id": "test"},
144
+ ... suggestions=["Add max_iterations parameter", "Add convergence_check condition"]
145
+ ... )
146
+ """
147
+
148
+ def __init__(
149
+ self,
150
+ message: str,
151
+ cycle_id: Optional[str] = None,
152
+ invalid_params: Optional[Dict[str, Any]] = None,
153
+ **kwargs
154
+ ):
155
+ """
156
+ Initialize cycle configuration error.
157
+
158
+ Args:
159
+ message (str): Error description
160
+ cycle_id (str, optional): ID of the problematic cycle
161
+ invalid_params (Dict[str, Any], optional): Invalid parameter values
162
+ **kwargs: Additional arguments for base exception
163
+
164
+ Side Effects:
165
+ Automatically generates context and suggestions based on parameters
166
+ """
167
+ context = kwargs.get('context', {})
168
+ suggestions = kwargs.get('suggestions', [])
169
+
170
+ # Add cycle-specific context
171
+ if cycle_id:
172
+ context['cycle_id'] = cycle_id
173
+ if invalid_params:
174
+ context.update(invalid_params)
175
+
176
+ # Add common suggestions if none provided
177
+ if not suggestions:
178
+ suggestions = [
179
+ "Ensure at least one termination condition (max_iterations, convergence_check, or timeout)",
180
+ "Use positive values for numeric parameters",
181
+ "Avoid unsafe operations in convergence expressions",
182
+ "Check the CycleConfig documentation for valid parameter ranges"
183
+ ]
184
+
185
+ super().__init__(
186
+ message,
187
+ error_code=kwargs.get('error_code', 'CYCLE_CONFIG_001'),
188
+ context=context,
189
+ suggestions=suggestions,
190
+ documentation_url="https://docs.kailash.ai/cycles/configuration"
191
+ )
192
+
193
+
194
+ class CycleConnectionError(CycleException):
195
+ """
196
+ Raised when cycle connection creation fails.
197
+
198
+ This exception handles errors during cycle connection establishment,
199
+ including missing nodes, invalid mappings, and connection conflicts.
200
+ It provides specific guidance for fixing connection issues.
201
+
202
+ Common scenarios:
203
+ - Source or target nodes don't exist in workflow
204
+ - Invalid parameter mappings
205
+ - Conflicting cycle connections
206
+ - Missing required connection parameters
207
+
208
+ Example:
209
+ >>> raise CycleConnectionError(
210
+ ... "Source node 'processor' not found",
211
+ ... source_node="processor",
212
+ ... available_nodes=["reader", "writer"]
213
+ ... )
214
+ """
215
+
216
+ def __init__(
217
+ self,
218
+ message: str,
219
+ source_node: Optional[str] = None,
220
+ target_node: Optional[str] = None,
221
+ available_nodes: Optional[List[str]] = None,
222
+ mapping_errors: Optional[Dict[str, str]] = None,
223
+ **kwargs
224
+ ):
225
+ """
226
+ Initialize cycle connection error.
227
+
228
+ Args:
229
+ message (str): Error description
230
+ source_node (str, optional): Source node ID
231
+ target_node (str, optional): Target node ID
232
+ available_nodes (List[str], optional): Available node IDs
233
+ mapping_errors (Dict[str, str], optional): Parameter mapping errors
234
+ **kwargs: Additional arguments for base exception
235
+ """
236
+ context = kwargs.get('context', {})
237
+ suggestions = kwargs.get('suggestions', [])
238
+
239
+ # Add connection-specific context
240
+ if source_node:
241
+ context['source_node'] = source_node
242
+ if target_node:
243
+ context['target_node'] = target_node
244
+ if available_nodes:
245
+ context['available_nodes'] = available_nodes
246
+ if mapping_errors:
247
+ context['mapping_errors'] = mapping_errors
248
+
249
+ # Generate specific suggestions
250
+ if not suggestions:
251
+ suggestions = []
252
+ if available_nodes:
253
+ suggestions.append(f"Available nodes: {', '.join(available_nodes)}")
254
+ if source_node and available_nodes and source_node not in available_nodes:
255
+ suggestions.append(f"Add node '{source_node}' to workflow before connecting")
256
+ if mapping_errors:
257
+ suggestions.append("Check parameter mappings for typos and type compatibility")
258
+ suggestions.append("Verify node IDs match exactly (case-sensitive)")
259
+
260
+ super().__init__(
261
+ message,
262
+ error_code=kwargs.get('error_code', 'CYCLE_CONN_001'),
263
+ context=context,
264
+ suggestions=suggestions,
265
+ documentation_url="https://docs.kailash.ai/cycles/connections"
266
+ )
267
+
268
+
269
+ class CycleValidationError(CycleException):
270
+ """
271
+ Raised when cycle validation fails during workflow validation.
272
+
273
+ This exception handles validation errors for complete cycle configurations,
274
+ including cycle graph analysis, parameter compatibility, and safety checks.
275
+
276
+ Common scenarios:
277
+ - Circular dependencies without proper cycle marking
278
+ - Conflicting cycle parameters within groups
279
+ - Invalid nested cycle relationships
280
+ - Unsafe cycle configurations
281
+
282
+ Example:
283
+ >>> raise CycleValidationError(
284
+ ... "Conflicting max_iterations in cycle group",
285
+ ... cycle_group="optimization",
286
+ ... conflicting_values=[50, 100, 75]
287
+ ... )
288
+ """
289
+
290
+ def __init__(
291
+ self,
292
+ message: str,
293
+ cycle_group: Optional[str] = None,
294
+ validation_failures: Optional[List[str]] = None,
295
+ conflicting_values: Optional[List[Any]] = None,
296
+ **kwargs
297
+ ):
298
+ """
299
+ Initialize cycle validation error.
300
+
301
+ Args:
302
+ message (str): Error description
303
+ cycle_group (str, optional): Affected cycle group ID
304
+ validation_failures (List[str], optional): List of validation failures
305
+ conflicting_values (List[Any], optional): Conflicting parameter values
306
+ **kwargs: Additional arguments for base exception
307
+ """
308
+ context = kwargs.get('context', {})
309
+ suggestions = kwargs.get('suggestions', [])
310
+
311
+ # Add validation-specific context
312
+ if cycle_group:
313
+ context['cycle_group'] = cycle_group
314
+ if validation_failures:
315
+ context['validation_failures'] = validation_failures
316
+ if conflicting_values:
317
+ context['conflicting_values'] = conflicting_values
318
+
319
+ # Generate validation-specific suggestions
320
+ if not suggestions:
321
+ suggestions = [
322
+ "Review cycle configuration for consistency",
323
+ "Ensure all cycle edges use the same parameters",
324
+ "Check for proper cycle marking (cycle=True)",
325
+ "Validate nested cycle relationships"
326
+ ]
327
+ if conflicting_values:
328
+ suggestions.append("Use consistent parameter values across cycle group")
329
+
330
+ super().__init__(
331
+ message,
332
+ error_code=kwargs.get('error_code', 'CYCLE_VALID_001'),
333
+ context=context,
334
+ suggestions=suggestions,
335
+ documentation_url="https://docs.kailash.ai/cycles/validation"
336
+ )
337
+
338
+
339
+ class CycleExecutionError(CycleException):
340
+ """
341
+ Raised when cycle execution fails during runtime.
342
+
343
+ This exception handles runtime errors during cycle execution,
344
+ including convergence failures, timeout issues, and iteration problems.
345
+
346
+ Common scenarios:
347
+ - Cycle fails to converge within max_iterations
348
+ - Timeout exceeded during cycle execution
349
+ - Memory limit exceeded
350
+ - Node execution failures within cycles
351
+
352
+ Example:
353
+ >>> raise CycleExecutionError(
354
+ ... "Cycle timeout exceeded",
355
+ ... cycle_id="optimization",
356
+ ... current_iteration=50,
357
+ ... timeout_seconds=300
358
+ ... )
359
+ """
360
+
361
+ def __init__(
362
+ self,
363
+ message: str,
364
+ cycle_id: Optional[str] = None,
365
+ current_iteration: Optional[int] = None,
366
+ max_iterations: Optional[int] = None,
367
+ timeout_seconds: Optional[float] = None,
368
+ memory_usage_mb: Optional[int] = None,
369
+ **kwargs
370
+ ):
371
+ """
372
+ Initialize cycle execution error.
373
+
374
+ Args:
375
+ message (str): Error description
376
+ cycle_id (str, optional): ID of the failing cycle
377
+ current_iteration (int, optional): Current iteration count
378
+ max_iterations (int, optional): Maximum allowed iterations
379
+ timeout_seconds (float, optional): Timeout limit in seconds
380
+ memory_usage_mb (int, optional): Current memory usage
381
+ **kwargs: Additional arguments for base exception
382
+ """
383
+ context = kwargs.get('context', {})
384
+ suggestions = kwargs.get('suggestions', [])
385
+
386
+ # Add execution-specific context
387
+ if cycle_id:
388
+ context['cycle_id'] = cycle_id
389
+ if current_iteration is not None:
390
+ context['current_iteration'] = current_iteration
391
+ if max_iterations is not None:
392
+ context['max_iterations'] = max_iterations
393
+ if timeout_seconds is not None:
394
+ context['timeout_seconds'] = timeout_seconds
395
+ if memory_usage_mb is not None:
396
+ context['memory_usage_mb'] = memory_usage_mb
397
+
398
+ # Generate execution-specific suggestions
399
+ if not suggestions:
400
+ suggestions = []
401
+ if current_iteration and max_iterations and current_iteration >= max_iterations:
402
+ suggestions.extend([
403
+ "Increase max_iterations if more iterations are needed",
404
+ "Add or improve convergence_check for early termination",
405
+ "Review cycle logic for efficiency improvements"
406
+ ])
407
+ if timeout_seconds:
408
+ suggestions.extend([
409
+ "Increase timeout limit if legitimate long execution is expected",
410
+ "Optimize node processing for faster execution",
411
+ "Consider breaking into smaller cycles"
412
+ ])
413
+ if memory_usage_mb:
414
+ suggestions.extend([
415
+ "Increase memory_limit if more memory is needed",
416
+ "Optimize data handling to reduce memory usage",
417
+ "Consider streaming or chunked processing"
418
+ ])
419
+
420
+ super().__init__(
421
+ message,
422
+ error_code=kwargs.get('error_code', 'CYCLE_EXEC_001'),
423
+ context=context,
424
+ suggestions=suggestions,
425
+ documentation_url="https://docs.kailash.ai/cycles/execution"
426
+ )
427
+
428
+
429
+ class CycleConvergenceError(CycleException):
430
+ """
431
+ Raised when cycle convergence detection fails or behaves unexpectedly.
432
+
433
+ This exception handles convergence-related issues, including expression
434
+ evaluation errors, impossible convergence conditions, and convergence
435
+ detection failures.
436
+
437
+ Common scenarios:
438
+ - Convergence expression evaluation fails
439
+ - Convergence condition references undefined variables
440
+ - Convergence logic contradicts cycle behavior
441
+ - Premature or delayed convergence detection
442
+
443
+ Example:
444
+ >>> raise CycleConvergenceError(
445
+ ... "Convergence expression evaluation failed",
446
+ ... convergence_expression="undefined_var > 0.5",
447
+ ... available_variables=["value", "quality", "iteration"]
448
+ ... )
449
+ """
450
+
451
+ def __init__(
452
+ self,
453
+ message: str,
454
+ convergence_expression: Optional[str] = None,
455
+ evaluation_error: Optional[str] = None,
456
+ available_variables: Optional[List[str]] = None,
457
+ cycle_data: Optional[Dict[str, Any]] = None,
458
+ **kwargs
459
+ ):
460
+ """
461
+ Initialize cycle convergence error.
462
+
463
+ Args:
464
+ message (str): Error description
465
+ convergence_expression (str, optional): The problematic expression
466
+ evaluation_error (str, optional): Expression evaluation error details
467
+ available_variables (List[str], optional): Available variable names
468
+ cycle_data (Dict[str, Any], optional): Current cycle data
469
+ **kwargs: Additional arguments for base exception
470
+ """
471
+ context = kwargs.get('context', {})
472
+ suggestions = kwargs.get('suggestions', [])
473
+
474
+ # Add convergence-specific context
475
+ if convergence_expression:
476
+ context['convergence_expression'] = convergence_expression
477
+ if evaluation_error:
478
+ context['evaluation_error'] = evaluation_error
479
+ if available_variables:
480
+ context['available_variables'] = available_variables
481
+ if cycle_data:
482
+ context['cycle_data'] = {k: str(v)[:100] for k, v in cycle_data.items()} # Truncate for readability
483
+
484
+ # Generate convergence-specific suggestions
485
+ if not suggestions:
486
+ suggestions = [
487
+ "Check convergence expression syntax for typos",
488
+ "Ensure all referenced variables exist in cycle output",
489
+ "Use simple comparison operators (>, <, ==, >=, <=)",
490
+ "Avoid complex logic or function calls in expressions"
491
+ ]
492
+ if available_variables:
493
+ suggestions.append(f"Available variables: {', '.join(available_variables)}")
494
+ if convergence_expression and evaluation_error:
495
+ suggestions.append("Test convergence expression with sample data")
496
+
497
+ super().__init__(
498
+ message,
499
+ error_code=kwargs.get('error_code', 'CYCLE_CONV_001'),
500
+ context=context,
501
+ suggestions=suggestions,
502
+ documentation_url="https://docs.kailash.ai/cycles/convergence"
503
+ )
504
+
505
+
506
+ # Utility functions for enhanced error reporting
507
+ def create_configuration_error(
508
+ issue: str,
509
+ cycle_id: Optional[str] = None,
510
+ **invalid_params
511
+ ) -> CycleConfigurationError:
512
+ """
513
+ Create a standardized configuration error with common suggestions.
514
+
515
+ Args:
516
+ issue (str): Description of the configuration issue
517
+ cycle_id (str, optional): Cycle identifier
518
+ **invalid_params: Invalid parameter values
519
+
520
+ Returns:
521
+ CycleConfigurationError: Configured exception with context
522
+
523
+ Example:
524
+ >>> error = create_configuration_error(
525
+ ... "Invalid max_iterations value",
526
+ ... cycle_id="test",
527
+ ... max_iterations=-5
528
+ ... )
529
+ """
530
+ return CycleConfigurationError(
531
+ message=issue,
532
+ cycle_id=cycle_id,
533
+ invalid_params=invalid_params
534
+ )
535
+
536
+
537
+ def create_connection_error(
538
+ issue: str,
539
+ source_node: Optional[str] = None,
540
+ target_node: Optional[str] = None,
541
+ available_nodes: Optional[List[str]] = None
542
+ ) -> CycleConnectionError:
543
+ """
544
+ Create a standardized connection error with node context.
545
+
546
+ Args:
547
+ issue (str): Description of the connection issue
548
+ source_node (str, optional): Source node ID
549
+ target_node (str, optional): Target node ID
550
+ available_nodes (List[str], optional): Available node IDs
551
+
552
+ Returns:
553
+ CycleConnectionError: Configured exception with context
554
+
555
+ Example:
556
+ >>> error = create_connection_error(
557
+ ... "Node not found",
558
+ ... source_node="missing",
559
+ ... available_nodes=["node1", "node2"]
560
+ ... )
561
+ """
562
+ return CycleConnectionError(
563
+ message=issue,
564
+ source_node=source_node,
565
+ target_node=target_node,
566
+ available_nodes=available_nodes
567
+ )
568
+
569
+
570
+ def create_execution_error(
571
+ issue: str,
572
+ cycle_id: Optional[str] = None,
573
+ current_iteration: Optional[int] = None,
574
+ max_iterations: Optional[int] = None
575
+ ) -> CycleExecutionError:
576
+ """
577
+ Create a standardized execution error with runtime context.
578
+
579
+ Args:
580
+ issue (str): Description of the execution issue
581
+ cycle_id (str, optional): Cycle identifier
582
+ current_iteration (int, optional): Current iteration
583
+ max_iterations (int, optional): Maximum iterations
584
+
585
+ Returns:
586
+ CycleExecutionError: Configured exception with context
587
+
588
+ Example:
589
+ >>> error = create_execution_error(
590
+ ... "Max iterations exceeded",
591
+ ... cycle_id="optimization",
592
+ ... current_iteration=100,
593
+ ... max_iterations=100
594
+ ... )
595
+ """
596
+ return CycleExecutionError(
597
+ message=issue,
598
+ cycle_id=cycle_id,
599
+ current_iteration=current_iteration,
600
+ max_iterations=max_iterations
601
+ )