omnimancer-cli 0.1.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 (126) hide show
  1. omnimancer/__init__.py +42 -0
  2. omnimancer/__main__.py +9 -0
  3. omnimancer/cli/__init__.py +8 -0
  4. omnimancer/cli/agent_manager.py +826 -0
  5. omnimancer/cli/agent_wizard.py +944 -0
  6. omnimancer/cli/approval_formatter.py +734 -0
  7. omnimancer/cli/approval_integration.py +734 -0
  8. omnimancer/cli/approval_prompt.py +1286 -0
  9. omnimancer/cli/batch_approval_display.py +617 -0
  10. omnimancer/cli/batch_approval_filters.py +729 -0
  11. omnimancer/cli/batch_operation_monitor.py +775 -0
  12. omnimancer/cli/commands/performance_cmd.py +624 -0
  13. omnimancer/cli/commands.py +757 -0
  14. omnimancer/cli/completion_handler.py +281 -0
  15. omnimancer/cli/config_setup_wizard.py +783 -0
  16. omnimancer/cli/dynamic_commands.py +371 -0
  17. omnimancer/cli/handlers/__init__.py +18 -0
  18. omnimancer/cli/handlers/agent_handler.py +865 -0
  19. omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
  20. omnimancer/cli/handlers/custom_agent_handler.py +352 -0
  21. omnimancer/cli/handlers/permissions_handler.py +1609 -0
  22. omnimancer/cli/interface.py +6695 -0
  23. omnimancer/cli/performance_dashboard.py +612 -0
  24. omnimancer/core/__init__.py +34 -0
  25. omnimancer/core/agent/__init__.py +256 -0
  26. omnimancer/core/agent/agent_config.py +715 -0
  27. omnimancer/core/agent/agent_switcher.py +668 -0
  28. omnimancer/core/agent/approval_context.py +460 -0
  29. omnimancer/core/agent/approval_dialog.py +902 -0
  30. omnimancer/core/agent/approval_interface.py +628 -0
  31. omnimancer/core/agent/approval_manager.py +760 -0
  32. omnimancer/core/agent/cli_integration.py +470 -0
  33. omnimancer/core/agent/config.py +845 -0
  34. omnimancer/core/agent/custom_agent_integration.py +654 -0
  35. omnimancer/core/agent/diff_renderer.py +706 -0
  36. omnimancer/core/agent/file_content_display.py +503 -0
  37. omnimancer/core/agent/file_modification_workflow.py +658 -0
  38. omnimancer/core/agent/file_system_manager.py +1790 -0
  39. omnimancer/core/agent/input_handler.py +614 -0
  40. omnimancer/core/agent/metrics_collector.py +771 -0
  41. omnimancer/core/agent/optimization_engine.py +729 -0
  42. omnimancer/core/agent/performance_monitor.py +717 -0
  43. omnimancer/core/agent/persona.py +870 -0
  44. omnimancer/core/agent/persona_validator.py +672 -0
  45. omnimancer/core/agent/program_executor.py +748 -0
  46. omnimancer/core/agent/proposed_changes_integration.py +663 -0
  47. omnimancer/core/agent/read_before_write_errors.py +492 -0
  48. omnimancer/core/agent/read_before_write_ui.py +647 -0
  49. omnimancer/core/agent/rich_renderer.py +763 -0
  50. omnimancer/core/agent/status_config.py +238 -0
  51. omnimancer/core/agent/status_core.py +446 -0
  52. omnimancer/core/agent/status_integrated_engine.py +540 -0
  53. omnimancer/core/agent/status_manager.py +878 -0
  54. omnimancer/core/agent/status_ui_components.py +535 -0
  55. omnimancer/core/agent/template_applicator.py +548 -0
  56. omnimancer/core/agent/terminal_status_listener.py +394 -0
  57. omnimancer/core/agent/token_tracker.py +679 -0
  58. omnimancer/core/agent/types.py +60 -0
  59. omnimancer/core/agent/web_client.py +745 -0
  60. omnimancer/core/agent/workflow_orchestrator.py +826 -0
  61. omnimancer/core/agent_engine.py +1625 -0
  62. omnimancer/core/agent_mode_manager.py +706 -0
  63. omnimancer/core/agent_progress_ui.py +545 -0
  64. omnimancer/core/chat_manager.py +141 -0
  65. omnimancer/core/config_manager.py +2199 -0
  66. omnimancer/core/config_migration.py +772 -0
  67. omnimancer/core/config_provider.py +1974 -0
  68. omnimancer/core/config_security_validator.py +393 -0
  69. omnimancer/core/config_validator.py +768 -0
  70. omnimancer/core/conversation_manager.py +352 -0
  71. omnimancer/core/engine.py +787 -0
  72. omnimancer/core/enhanced_input.py +523 -0
  73. omnimancer/core/env_loader.py +83 -0
  74. omnimancer/core/fallback_manager.py +568 -0
  75. omnimancer/core/health_monitor.py +462 -0
  76. omnimancer/core/history_manager.py +462 -0
  77. omnimancer/core/mcp_integration_layer.py +878 -0
  78. omnimancer/core/models.py +1889 -0
  79. omnimancer/core/provider_capabilities.py +403 -0
  80. omnimancer/core/provider_initializer.py +450 -0
  81. omnimancer/core/provider_registry.py +432 -0
  82. omnimancer/core/security/__init__.py +16 -0
  83. omnimancer/core/security/approval_workflow.py +406 -0
  84. omnimancer/core/security/audit_logger.py +511 -0
  85. omnimancer/core/security/permission_controller.py +511 -0
  86. omnimancer/core/security/sandbox_manager.py +379 -0
  87. omnimancer/core/security/security_manager.py +530 -0
  88. omnimancer/core/setup_wizard.py +345 -0
  89. omnimancer/core/setup_wizard_core.py +449 -0
  90. omnimancer/core/setup_wizard_guide_generator.py +376 -0
  91. omnimancer/core/setup_wizard_provider_setup.py +454 -0
  92. omnimancer/core/setup_wizard_ui.py +317 -0
  93. omnimancer/core/setup_wizard_validation.py +371 -0
  94. omnimancer/core/signal_handler.py +174 -0
  95. omnimancer/mcp/__init__.py +11 -0
  96. omnimancer/mcp/client.py +725 -0
  97. omnimancer/mcp/manager.py +649 -0
  98. omnimancer/providers/__init__.py +24 -0
  99. omnimancer/providers/azure.py +608 -0
  100. omnimancer/providers/base.py +262 -0
  101. omnimancer/providers/bedrock.py +711 -0
  102. omnimancer/providers/claude.py +426 -0
  103. omnimancer/providers/claude_code.py +406 -0
  104. omnimancer/providers/cohere.py +412 -0
  105. omnimancer/providers/factory.py +988 -0
  106. omnimancer/providers/gemini.py +708 -0
  107. omnimancer/providers/mistral.py +554 -0
  108. omnimancer/providers/ollama.py +510 -0
  109. omnimancer/providers/openai.py +362 -0
  110. omnimancer/providers/openrouter.py +709 -0
  111. omnimancer/providers/perplexity.py +476 -0
  112. omnimancer/providers/vertex.py +617 -0
  113. omnimancer/providers/xai.py +484 -0
  114. omnimancer/ui/__init__.py +6 -0
  115. omnimancer/ui/cancellation_handler.py +235 -0
  116. omnimancer/ui/progress_indicator.py +318 -0
  117. omnimancer/utils/__init__.py +22 -0
  118. omnimancer/utils/error_handler.py +589 -0
  119. omnimancer/utils/errors.py +667 -0
  120. omnimancer/utils/retry.py +238 -0
  121. omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
  122. omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
  123. omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
  124. omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
  125. omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
  126. omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,235 @@
1
+ """
2
+ Cancellation handler for Omnimancer operations.
3
+
4
+ This module provides cancellation support for long-running operations
5
+ with user-friendly feedback and graceful operation termination.
6
+ """
7
+
8
+ import asyncio
9
+ import logging
10
+ from typing import Any, Callable, Optional
11
+
12
+ from rich.console import Console
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Global registry for active cancellation handler
17
+ _active_cancellation_handler: Optional["CancellationHandler"] = None
18
+
19
+
20
+ def get_active_cancellation_handler() -> Optional["CancellationHandler"]:
21
+ """Get the currently active cancellation handler."""
22
+ return _active_cancellation_handler
23
+
24
+
25
+ def set_active_cancellation_handler(handler: Optional["CancellationHandler"]):
26
+ """Set the currently active cancellation handler."""
27
+ global _active_cancellation_handler
28
+ _active_cancellation_handler = handler
29
+
30
+
31
+ class CancellationHandler:
32
+ """
33
+ Handles operation cancellation with user feedback.
34
+
35
+ This class provides a simple but effective cancellation system
36
+ that integrates with the existing signal handling infrastructure.
37
+ """
38
+
39
+ def __init__(self, console: Optional[Console] = None):
40
+ """
41
+ Initialize the cancellation handler.
42
+
43
+ Args:
44
+ console: Rich console instance for user feedback
45
+ """
46
+ self.console = console or Console()
47
+ self.active_operation: Optional[asyncio.Task] = None
48
+ self.is_listening = False
49
+ self.status_display = None
50
+ self.is_paused = False
51
+ logger.debug("CancellationHandler initialized")
52
+
53
+ async def start_cancellable_operation(
54
+ self,
55
+ operation: Callable,
56
+ status_message: str = "Processing...",
57
+ cancellation_message: str = "Operation cancelled by user",
58
+ signal_handler=None,
59
+ status_callback: Optional[Callable[[], str]] = None,
60
+ ) -> Any:
61
+ """
62
+ Start an operation with cancellation support.
63
+
64
+ This method wraps an operation to provide cancellation feedback
65
+ and integrates with the signal handler for Ctrl+C support.
66
+
67
+ Args:
68
+ operation: Async function to execute
69
+ status_message: Message to show during operation
70
+ cancellation_message: Message to show when cancelled
71
+ status_callback: Optional callback that returns current status
72
+
73
+ Returns:
74
+ Result of the operation
75
+
76
+ Raises:
77
+ asyncio.CancelledError: If operation was cancelled
78
+ """
79
+ logger.debug(f"Starting cancellable operation: {status_message}")
80
+
81
+ # Register this handler as active
82
+ set_active_cancellation_handler(self)
83
+
84
+ # Create the operation task
85
+ self.active_operation = asyncio.create_task(operation())
86
+ self.is_listening = True
87
+
88
+ # Register with signal handler if provided
89
+ if signal_handler:
90
+ signal_handler.register_operation(self.active_operation)
91
+
92
+ try:
93
+ # Show status with cancellation instructions
94
+ # Note: ESC key cancellation is not yet implemented, using Ctrl+C only
95
+ # If we have a status callback, use dynamic status
96
+ if status_callback:
97
+
98
+ async def update_status():
99
+ while not self.active_operation.done():
100
+ current_status = status_callback()
101
+ self.console.status(
102
+ f"[bold green]{current_status} (Press Ctrl+C to cancel)",
103
+ spinner="dots",
104
+ refresh=True,
105
+ )
106
+ await asyncio.sleep(0.1)
107
+
108
+ # Run status updates in parallel with operation
109
+ status_task = asyncio.create_task(update_status())
110
+ try:
111
+ result = await self.active_operation
112
+ finally:
113
+ status_task.cancel()
114
+ try:
115
+ await status_task
116
+ except asyncio.CancelledError:
117
+ pass
118
+ else:
119
+ # Use static status message
120
+ self.status_display = self.console.status(
121
+ f"[bold green]{status_message} (Press Ctrl+C to cancel)",
122
+ spinner="dots",
123
+ )
124
+ with self.status_display:
125
+ result = await self.active_operation
126
+
127
+ logger.debug("Cancellable operation completed successfully")
128
+ return result
129
+
130
+ except asyncio.CancelledError:
131
+ logger.info("Operation cancelled by user")
132
+ self.console.print(f"[yellow]⚠️ {cancellation_message}[/yellow]")
133
+ raise
134
+ finally:
135
+ self.is_listening = False
136
+ self.active_operation = None
137
+ self.status_display = None
138
+ self.is_paused = False
139
+ # Unregister this handler
140
+ set_active_cancellation_handler(None)
141
+
142
+ def is_operation_active(self) -> bool:
143
+ """
144
+ Check if an operation is currently active.
145
+
146
+ Returns:
147
+ True if an operation is running
148
+ """
149
+ return self.active_operation is not None and not self.active_operation.done()
150
+
151
+ def cancel_active_operation(self) -> bool:
152
+ """
153
+ Cancel the currently active operation.
154
+
155
+ Returns:
156
+ True if an operation was cancelled, False otherwise
157
+ """
158
+ if self.is_operation_active():
159
+ logger.info("Cancelling active operation")
160
+ self.active_operation.cancel()
161
+ return True
162
+ return False
163
+
164
+ def pause_status_display(self):
165
+ """
166
+ Pause the status display to allow for user interaction.
167
+
168
+ This stops the spinner temporarily while preserving the operation.
169
+ """
170
+ if self.status_display and not self.is_paused:
171
+ self.is_paused = True
172
+ try:
173
+ self.status_display.stop()
174
+ except:
175
+ pass
176
+ logger.debug("Status display paused for user interaction")
177
+
178
+ def resume_status_display(self):
179
+ """
180
+ Resume the status display after user interaction.
181
+ """
182
+ if self.status_display and self.is_paused and self.is_operation_active():
183
+ self.is_paused = False
184
+ try:
185
+ self.status_display.start()
186
+ except:
187
+ pass
188
+ logger.debug("Status display resumed after user interaction")
189
+
190
+
191
+ class EnhancedStatusDisplay:
192
+ """
193
+ Enhanced status display with better cancellation feedback.
194
+
195
+ Provides improved visual feedback for operations that can be cancelled.
196
+ """
197
+
198
+ def __init__(self, console: Console):
199
+ """
200
+ Initialize the enhanced status display.
201
+
202
+ Args:
203
+ console: Rich console instance
204
+ """
205
+ self.console = console
206
+
207
+ def show_thinking_with_cancel(self, message: str = "Thinking") -> None:
208
+ """
209
+ Show a thinking indicator with cancellation instructions.
210
+
211
+ Args:
212
+ message: Base message to display
213
+ """
214
+ enhanced_message = (
215
+ f"[bold green]{message}... (Press Ctrl+C to cancel)[/bold green]"
216
+ )
217
+ return self.console.status(enhanced_message, spinner="dots")
218
+
219
+ def show_cancellation_notice(self, message: str = "Operation cancelled") -> None:
220
+ """
221
+ Show a cancellation notice to the user.
222
+
223
+ Args:
224
+ message: Cancellation message to display
225
+ """
226
+ self.console.print(f"[yellow]⚠️ {message}[/yellow]")
227
+
228
+ def show_completion_notice(self, message: str = "Operation completed") -> None:
229
+ """
230
+ Show a completion notice to the user.
231
+
232
+ Args:
233
+ message: Completion message to display
234
+ """
235
+ self.console.print(f"[green]✅ {message}[/green]")
@@ -0,0 +1,318 @@
1
+ """
2
+ Progress indicator system for Omnimancer.
3
+
4
+ This module provides real-time progress indicators showing current operations
5
+ and tool usage during AI interactions.
6
+ """
7
+
8
+ import asyncio
9
+ import time
10
+ from dataclasses import dataclass, field
11
+ from enum import Enum
12
+ from typing import Dict, List, Optional
13
+
14
+ from rich.console import Console
15
+ from rich.live import Live
16
+ from rich.panel import Panel
17
+ from rich.table import Table
18
+
19
+
20
+ class OperationType(Enum):
21
+ """Types of operations that can be tracked."""
22
+
23
+ THINKING = "thinking"
24
+ READ = "read"
25
+ WRITE = "write"
26
+ BASH = "bash"
27
+ RESEARCH = "research"
28
+ GREP = "grep"
29
+ EDIT = "edit"
30
+ VALIDATE = "validate"
31
+ ANALYZE = "analyze"
32
+ GENERATE = "generate"
33
+ NETWORK = "network"
34
+ OTHER = "other"
35
+
36
+
37
+ @dataclass
38
+ class OperationInfo:
39
+ """Information about a current operation."""
40
+
41
+ operation_type: OperationType
42
+ description: str
43
+ start_time: float = field(default_factory=time.time)
44
+ progress: Optional[float] = None # 0.0 to 1.0
45
+ details: Optional[str] = None
46
+ status: str = "running" # "running", "completed", "failed"
47
+
48
+
49
+ class ProgressIndicator:
50
+ """
51
+ Real-time progress indicator for Omnimancer operations.
52
+
53
+ Shows current operations, tool usage, and progress information
54
+ in a live-updating display.
55
+ """
56
+
57
+ # Operation type icons and colors
58
+ OPERATION_ICONS = {
59
+ OperationType.THINKING: ("🤔", "yellow"),
60
+ OperationType.READ: ("📖", "blue"),
61
+ OperationType.WRITE: ("✍️", "green"),
62
+ OperationType.BASH: ("⚙️", "magenta"),
63
+ OperationType.RESEARCH: ("🔍", "cyan"),
64
+ OperationType.GREP: ("🔎", "blue"),
65
+ OperationType.EDIT: ("📝", "green"),
66
+ OperationType.VALIDATE: ("✅", "green"),
67
+ OperationType.ANALYZE: ("🔬", "purple"),
68
+ OperationType.GENERATE: ("🏗️", "orange"),
69
+ OperationType.NETWORK: ("🌐", "cyan"),
70
+ OperationType.OTHER: ("⚡", "white"),
71
+ }
72
+
73
+ def __init__(self, console: Console):
74
+ """
75
+ Initialize the progress indicator.
76
+
77
+ Args:
78
+ console: Rich Console instance
79
+ """
80
+ self.console = console
81
+ self.current_operations: Dict[str, OperationInfo] = {}
82
+ self.operation_history: List[OperationInfo] = []
83
+ self.live_display: Optional[Live] = None
84
+ self.display_task: Optional[asyncio.Task] = None
85
+ self.enabled = True
86
+ self.max_history = 5
87
+
88
+ def start_operation(
89
+ self,
90
+ operation_id: str,
91
+ operation_type: OperationType,
92
+ description: str,
93
+ details: Optional[str] = None,
94
+ ) -> None:
95
+ """
96
+ Start tracking a new operation.
97
+
98
+ Args:
99
+ operation_id: Unique identifier for the operation
100
+ operation_type: Type of operation
101
+ description: Human-readable description
102
+ details: Optional additional details
103
+ """
104
+ if not self.enabled:
105
+ return
106
+
107
+ operation = OperationInfo(
108
+ operation_type=operation_type,
109
+ description=description,
110
+ details=details,
111
+ )
112
+ self.current_operations[operation_id] = operation
113
+
114
+ # Start live display if this is the first operation
115
+ if len(self.current_operations) == 1 and self.live_display is None:
116
+ self.start_live_display()
117
+ else:
118
+ self._update_display()
119
+
120
+ def update_operation(
121
+ self,
122
+ operation_id: str,
123
+ progress: Optional[float] = None,
124
+ details: Optional[str] = None,
125
+ status: Optional[str] = None,
126
+ ) -> None:
127
+ """
128
+ Update an existing operation.
129
+
130
+ Args:
131
+ operation_id: Operation identifier
132
+ progress: Progress as float 0.0 to 1.0
133
+ details: Updated details
134
+ status: Updated status
135
+ """
136
+ if not self.enabled or operation_id not in self.current_operations:
137
+ return
138
+
139
+ operation = self.current_operations[operation_id]
140
+ if progress is not None:
141
+ operation.progress = progress
142
+ if details is not None:
143
+ operation.details = details
144
+ if status is not None:
145
+ operation.status = status
146
+
147
+ self._update_display()
148
+
149
+ def complete_operation(self, operation_id: str, status: str = "completed") -> None:
150
+ """
151
+ Complete an operation and move it to history.
152
+
153
+ Args:
154
+ operation_id: Operation identifier
155
+ status: Final status ("completed" or "failed")
156
+ """
157
+ if not self.enabled or operation_id not in self.current_operations:
158
+ return
159
+
160
+ operation = self.current_operations.pop(operation_id)
161
+ operation.status = status
162
+
163
+ # Add to history (keep only recent ones)
164
+ self.operation_history.append(operation)
165
+ if len(self.operation_history) > self.max_history:
166
+ self.operation_history.pop(0)
167
+
168
+ # Stop live display if no more operations
169
+ if len(self.current_operations) == 0:
170
+ self.stop_live_display()
171
+ else:
172
+ self._update_display()
173
+
174
+ def clear_all_operations(self) -> None:
175
+ """Clear all current operations."""
176
+ if not self.enabled:
177
+ return
178
+
179
+ # Move all current operations to history as completed
180
+ for operation_id, operation in self.current_operations.items():
181
+ operation.status = "completed"
182
+ self.operation_history.append(operation)
183
+
184
+ self.current_operations.clear()
185
+
186
+ # Trim history
187
+ if len(self.operation_history) > self.max_history:
188
+ self.operation_history = self.operation_history[-self.max_history :]
189
+
190
+ # Always stop live display when clearing all operations
191
+ self.stop_live_display()
192
+
193
+ def start_live_display(self) -> None:
194
+ """Start the live updating display."""
195
+ if not self.enabled or self.live_display is not None:
196
+ return
197
+
198
+ layout = self._create_layout()
199
+ self.live_display = Live(
200
+ layout,
201
+ console=self.console,
202
+ auto_refresh=False, # Disable auto-refresh to prevent runaway updates
203
+ refresh_per_second=2, # Limit refresh rate
204
+ )
205
+ self.live_display.start()
206
+
207
+ def stop_live_display(self) -> None:
208
+ """Stop the live updating display."""
209
+ if self.live_display:
210
+ self.live_display.stop()
211
+ self.live_display = None
212
+
213
+ def _create_layout(self) -> Panel:
214
+ """Create the display layout."""
215
+ # Create table for current operations
216
+ current_table = Table(show_header=False, box=None, padding=(0, 1))
217
+ current_table.add_column("", style="bold")
218
+ current_table.add_column("", style="dim")
219
+ current_table.add_column("", style="")
220
+
221
+ for operation_id, operation in self.current_operations.items():
222
+ icon, color = self.OPERATION_ICONS[operation.operation_type]
223
+ elapsed = time.time() - operation.start_time
224
+
225
+ # Format time
226
+ if elapsed < 60:
227
+ time_str = f"{elapsed:.1f}s"
228
+ else:
229
+ time_str = f"{elapsed/60:.1f}m"
230
+
231
+ # Progress indicator
232
+ if operation.progress is not None:
233
+ progress_str = f" ({operation.progress:.0%})"
234
+ else:
235
+ progress_str = ""
236
+
237
+ # Operation details
238
+ details_str = f" - {operation.details}" if operation.details else ""
239
+
240
+ current_table.add_row(
241
+ f"[{color}]{icon}[/{color}]",
242
+ f"[{color}]{operation.operation_type.value.title()}[/{color}]",
243
+ f"{operation.description}{progress_str}{details_str} [{time_str}]",
244
+ )
245
+
246
+ return Panel(
247
+ current_table,
248
+ title="🤖 Omnimancer Progress",
249
+ border_style="blue",
250
+ padding=(0, 1),
251
+ )
252
+
253
+ def _update_display(self) -> None:
254
+ """Update the live display."""
255
+ if self.live_display:
256
+ self.live_display.update(self._create_layout())
257
+
258
+ def enable(self) -> None:
259
+ """Enable progress tracking."""
260
+ self.enabled = True
261
+
262
+ def disable(self) -> None:
263
+ """Disable progress tracking."""
264
+ self.enabled = False
265
+ self.stop_live_display()
266
+
267
+ def show_simple_status(self, message: str) -> None:
268
+ """Show a simple status message without full progress tracking."""
269
+ if not self.enabled:
270
+ return
271
+
272
+ self.console.print(f"🤖 {message}", style="blue")
273
+
274
+
275
+ # Global progress indicator instance
276
+ _global_progress_indicator: Optional[ProgressIndicator] = None
277
+
278
+
279
+ def get_progress_indicator() -> Optional[ProgressIndicator]:
280
+ """Get the global progress indicator instance."""
281
+ return _global_progress_indicator
282
+
283
+
284
+ def set_progress_indicator(indicator: ProgressIndicator) -> None:
285
+ """Set the global progress indicator instance."""
286
+ global _global_progress_indicator
287
+ _global_progress_indicator = indicator
288
+
289
+
290
+ def start_operation(
291
+ operation_id: str,
292
+ operation_type: OperationType,
293
+ description: str,
294
+ details: Optional[str] = None,
295
+ ) -> None:
296
+ """Global function to start tracking an operation."""
297
+ indicator = get_progress_indicator()
298
+ if indicator:
299
+ indicator.start_operation(operation_id, operation_type, description, details)
300
+
301
+
302
+ def update_operation(
303
+ operation_id: str,
304
+ progress: Optional[float] = None,
305
+ details: Optional[str] = None,
306
+ status: Optional[str] = None,
307
+ ) -> None:
308
+ """Global function to update an operation."""
309
+ indicator = get_progress_indicator()
310
+ if indicator:
311
+ indicator.update_operation(operation_id, progress, details, status)
312
+
313
+
314
+ def complete_operation(operation_id: str, status: str = "completed") -> None:
315
+ """Global function to complete an operation."""
316
+ indicator = get_progress_indicator()
317
+ if indicator:
318
+ indicator.complete_operation(operation_id, status)
@@ -0,0 +1,22 @@
1
+ """
2
+ Utilities module for Omnimancer.
3
+
4
+ This module contains utility functions and classes for error handling,
5
+ retry logic, encryption, and other common functionality.
6
+ """
7
+
8
+ from .errors import (
9
+ AuthenticationError,
10
+ ConfigurationError,
11
+ OmnimancerError,
12
+ ProviderError,
13
+ RateLimitError,
14
+ )
15
+
16
+ __all__ = [
17
+ "OmnimancerError",
18
+ "ConfigurationError",
19
+ "ProviderError",
20
+ "AuthenticationError",
21
+ "RateLimitError",
22
+ ]