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.
- omnimancer/__init__.py +42 -0
- omnimancer/__main__.py +9 -0
- omnimancer/cli/__init__.py +8 -0
- omnimancer/cli/agent_manager.py +826 -0
- omnimancer/cli/agent_wizard.py +944 -0
- omnimancer/cli/approval_formatter.py +734 -0
- omnimancer/cli/approval_integration.py +734 -0
- omnimancer/cli/approval_prompt.py +1286 -0
- omnimancer/cli/batch_approval_display.py +617 -0
- omnimancer/cli/batch_approval_filters.py +729 -0
- omnimancer/cli/batch_operation_monitor.py +775 -0
- omnimancer/cli/commands/performance_cmd.py +624 -0
- omnimancer/cli/commands.py +757 -0
- omnimancer/cli/completion_handler.py +281 -0
- omnimancer/cli/config_setup_wizard.py +783 -0
- omnimancer/cli/dynamic_commands.py +371 -0
- omnimancer/cli/handlers/__init__.py +18 -0
- omnimancer/cli/handlers/agent_handler.py +865 -0
- omnimancer/cli/handlers/agent_persona_handler.py +1048 -0
- omnimancer/cli/handlers/custom_agent_handler.py +352 -0
- omnimancer/cli/handlers/permissions_handler.py +1609 -0
- omnimancer/cli/interface.py +6695 -0
- omnimancer/cli/performance_dashboard.py +612 -0
- omnimancer/core/__init__.py +34 -0
- omnimancer/core/agent/__init__.py +256 -0
- omnimancer/core/agent/agent_config.py +715 -0
- omnimancer/core/agent/agent_switcher.py +668 -0
- omnimancer/core/agent/approval_context.py +460 -0
- omnimancer/core/agent/approval_dialog.py +902 -0
- omnimancer/core/agent/approval_interface.py +628 -0
- omnimancer/core/agent/approval_manager.py +760 -0
- omnimancer/core/agent/cli_integration.py +470 -0
- omnimancer/core/agent/config.py +845 -0
- omnimancer/core/agent/custom_agent_integration.py +654 -0
- omnimancer/core/agent/diff_renderer.py +706 -0
- omnimancer/core/agent/file_content_display.py +503 -0
- omnimancer/core/agent/file_modification_workflow.py +658 -0
- omnimancer/core/agent/file_system_manager.py +1790 -0
- omnimancer/core/agent/input_handler.py +614 -0
- omnimancer/core/agent/metrics_collector.py +771 -0
- omnimancer/core/agent/optimization_engine.py +729 -0
- omnimancer/core/agent/performance_monitor.py +717 -0
- omnimancer/core/agent/persona.py +870 -0
- omnimancer/core/agent/persona_validator.py +672 -0
- omnimancer/core/agent/program_executor.py +748 -0
- omnimancer/core/agent/proposed_changes_integration.py +663 -0
- omnimancer/core/agent/read_before_write_errors.py +492 -0
- omnimancer/core/agent/read_before_write_ui.py +647 -0
- omnimancer/core/agent/rich_renderer.py +763 -0
- omnimancer/core/agent/status_config.py +238 -0
- omnimancer/core/agent/status_core.py +446 -0
- omnimancer/core/agent/status_integrated_engine.py +540 -0
- omnimancer/core/agent/status_manager.py +878 -0
- omnimancer/core/agent/status_ui_components.py +535 -0
- omnimancer/core/agent/template_applicator.py +548 -0
- omnimancer/core/agent/terminal_status_listener.py +394 -0
- omnimancer/core/agent/token_tracker.py +679 -0
- omnimancer/core/agent/types.py +60 -0
- omnimancer/core/agent/web_client.py +745 -0
- omnimancer/core/agent/workflow_orchestrator.py +826 -0
- omnimancer/core/agent_engine.py +1625 -0
- omnimancer/core/agent_mode_manager.py +706 -0
- omnimancer/core/agent_progress_ui.py +545 -0
- omnimancer/core/chat_manager.py +141 -0
- omnimancer/core/config_manager.py +2199 -0
- omnimancer/core/config_migration.py +772 -0
- omnimancer/core/config_provider.py +1974 -0
- omnimancer/core/config_security_validator.py +393 -0
- omnimancer/core/config_validator.py +768 -0
- omnimancer/core/conversation_manager.py +352 -0
- omnimancer/core/engine.py +787 -0
- omnimancer/core/enhanced_input.py +523 -0
- omnimancer/core/env_loader.py +83 -0
- omnimancer/core/fallback_manager.py +568 -0
- omnimancer/core/health_monitor.py +462 -0
- omnimancer/core/history_manager.py +462 -0
- omnimancer/core/mcp_integration_layer.py +878 -0
- omnimancer/core/models.py +1889 -0
- omnimancer/core/provider_capabilities.py +403 -0
- omnimancer/core/provider_initializer.py +450 -0
- omnimancer/core/provider_registry.py +432 -0
- omnimancer/core/security/__init__.py +16 -0
- omnimancer/core/security/approval_workflow.py +406 -0
- omnimancer/core/security/audit_logger.py +511 -0
- omnimancer/core/security/permission_controller.py +511 -0
- omnimancer/core/security/sandbox_manager.py +379 -0
- omnimancer/core/security/security_manager.py +530 -0
- omnimancer/core/setup_wizard.py +345 -0
- omnimancer/core/setup_wizard_core.py +449 -0
- omnimancer/core/setup_wizard_guide_generator.py +376 -0
- omnimancer/core/setup_wizard_provider_setup.py +454 -0
- omnimancer/core/setup_wizard_ui.py +317 -0
- omnimancer/core/setup_wizard_validation.py +371 -0
- omnimancer/core/signal_handler.py +174 -0
- omnimancer/mcp/__init__.py +11 -0
- omnimancer/mcp/client.py +725 -0
- omnimancer/mcp/manager.py +649 -0
- omnimancer/providers/__init__.py +24 -0
- omnimancer/providers/azure.py +608 -0
- omnimancer/providers/base.py +262 -0
- omnimancer/providers/bedrock.py +711 -0
- omnimancer/providers/claude.py +426 -0
- omnimancer/providers/claude_code.py +406 -0
- omnimancer/providers/cohere.py +412 -0
- omnimancer/providers/factory.py +988 -0
- omnimancer/providers/gemini.py +708 -0
- omnimancer/providers/mistral.py +554 -0
- omnimancer/providers/ollama.py +510 -0
- omnimancer/providers/openai.py +362 -0
- omnimancer/providers/openrouter.py +709 -0
- omnimancer/providers/perplexity.py +476 -0
- omnimancer/providers/vertex.py +617 -0
- omnimancer/providers/xai.py +484 -0
- omnimancer/ui/__init__.py +6 -0
- omnimancer/ui/cancellation_handler.py +235 -0
- omnimancer/ui/progress_indicator.py +318 -0
- omnimancer/utils/__init__.py +22 -0
- omnimancer/utils/error_handler.py +589 -0
- omnimancer/utils/errors.py +667 -0
- omnimancer/utils/retry.py +238 -0
- omnimancer_cli-0.1.0.dist-info/METADATA +413 -0
- omnimancer_cli-0.1.0.dist-info/RECORD +126 -0
- omnimancer_cli-0.1.0.dist-info/WHEEL +5 -0
- omnimancer_cli-0.1.0.dist-info/entry_points.txt +4 -0
- omnimancer_cli-0.1.0.dist-info/licenses/LICENSE +21 -0
- omnimancer_cli-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base provider interface for Omnimancer.
|
|
3
|
+
|
|
4
|
+
This module defines the abstract base class that all AI providers must implement
|
|
5
|
+
to ensure consistent behavior across different AI services.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from abc import ABC, abstractmethod
|
|
9
|
+
from typing import Dict, List
|
|
10
|
+
|
|
11
|
+
from ..core.models import ChatContext, ChatResponse, ModelInfo, ToolDefinition
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class BaseProvider(ABC):
|
|
15
|
+
"""
|
|
16
|
+
Abstract base class for AI providers.
|
|
17
|
+
|
|
18
|
+
All AI provider implementations must inherit from this class and implement
|
|
19
|
+
the required abstract methods to ensure consistent behavior.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, api_key: str, model: str, **kwargs):
|
|
23
|
+
"""
|
|
24
|
+
Initialize the provider.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
api_key: API key for authentication
|
|
28
|
+
model: Model name to use
|
|
29
|
+
**kwargs: Additional provider-specific configuration
|
|
30
|
+
"""
|
|
31
|
+
self.api_key = api_key
|
|
32
|
+
self.model = model
|
|
33
|
+
self.config = kwargs
|
|
34
|
+
|
|
35
|
+
@abstractmethod
|
|
36
|
+
async def send_message(self, message: str, context: ChatContext) -> ChatResponse:
|
|
37
|
+
"""
|
|
38
|
+
Send a message to the AI provider and get a response.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
message: The user's message
|
|
42
|
+
context: Current conversation context
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
ChatResponse with the AI's reply
|
|
46
|
+
|
|
47
|
+
Raises:
|
|
48
|
+
ProviderError: If the API call fails
|
|
49
|
+
AuthenticationError: If authentication fails
|
|
50
|
+
RateLimitError: If rate limits are exceeded
|
|
51
|
+
"""
|
|
52
|
+
pass
|
|
53
|
+
|
|
54
|
+
@abstractmethod
|
|
55
|
+
async def validate_credentials(self) -> bool:
|
|
56
|
+
"""
|
|
57
|
+
Validate that the API credentials are working.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
True if credentials are valid, False otherwise
|
|
61
|
+
"""
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
@abstractmethod
|
|
65
|
+
def get_model_info(self) -> ModelInfo:
|
|
66
|
+
"""
|
|
67
|
+
Get information about the current model.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
ModelInfo object with model details
|
|
71
|
+
"""
|
|
72
|
+
pass
|
|
73
|
+
|
|
74
|
+
def get_available_models(self) -> List[ModelInfo]:
|
|
75
|
+
"""
|
|
76
|
+
Get list of available models for this provider.
|
|
77
|
+
Uses catalog models if available, otherwise returns static models.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
List of ModelInfo objects for available models
|
|
81
|
+
"""
|
|
82
|
+
# Check if we have catalog models (updated from API)
|
|
83
|
+
if hasattr(self, "_catalog_models") and self._catalog_models:
|
|
84
|
+
# Convert EnhancedModelInfo to ModelInfo if needed
|
|
85
|
+
result = []
|
|
86
|
+
for model in self._catalog_models:
|
|
87
|
+
if hasattr(model, "to_model_info"):
|
|
88
|
+
result.append(model.to_model_info())
|
|
89
|
+
else:
|
|
90
|
+
result.append(model)
|
|
91
|
+
return result
|
|
92
|
+
|
|
93
|
+
# Otherwise, use the provider's static models
|
|
94
|
+
return self._get_static_models()
|
|
95
|
+
|
|
96
|
+
def _get_static_models(self) -> List[ModelInfo]:
|
|
97
|
+
"""
|
|
98
|
+
Get static list of models (when catalog is not available).
|
|
99
|
+
Subclasses should override this to return their default models.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
List of ModelInfo objects for available models
|
|
103
|
+
"""
|
|
104
|
+
# Default implementation returns empty list
|
|
105
|
+
# Subclasses should override this method
|
|
106
|
+
return []
|
|
107
|
+
|
|
108
|
+
async def fetch_live_models(self) -> List[ModelInfo]:
|
|
109
|
+
"""
|
|
110
|
+
Fetch live model list from provider API.
|
|
111
|
+
|
|
112
|
+
This method should be implemented by providers that support
|
|
113
|
+
real-time model discovery via their APIs.
|
|
114
|
+
|
|
115
|
+
Returns:
|
|
116
|
+
List of ModelInfo objects from API, or empty list if not supported
|
|
117
|
+
"""
|
|
118
|
+
# Default implementation returns static models
|
|
119
|
+
return self.get_available_models()
|
|
120
|
+
|
|
121
|
+
async def fetch_enhanced_models(self) -> List["EnhancedModelInfo"]:
|
|
122
|
+
"""
|
|
123
|
+
Fetch enhanced model information from provider API.
|
|
124
|
+
|
|
125
|
+
This method fetches detailed model information including pricing,
|
|
126
|
+
capabilities, and performance metrics when available.
|
|
127
|
+
|
|
128
|
+
Returns:
|
|
129
|
+
List of EnhancedModelInfo objects with detailed model information
|
|
130
|
+
"""
|
|
131
|
+
from ..core.models import EnhancedModelInfo
|
|
132
|
+
|
|
133
|
+
# Try to get live models first
|
|
134
|
+
models = await self.fetch_live_models()
|
|
135
|
+
|
|
136
|
+
# Convert to enhanced model info
|
|
137
|
+
enhanced_models = []
|
|
138
|
+
for model in models:
|
|
139
|
+
if isinstance(model, EnhancedModelInfo):
|
|
140
|
+
enhanced_models.append(model)
|
|
141
|
+
else:
|
|
142
|
+
# Convert basic ModelInfo to EnhancedModelInfo
|
|
143
|
+
enhanced = EnhancedModelInfo.from_model_info(model)
|
|
144
|
+
enhanced_models.append(enhanced)
|
|
145
|
+
|
|
146
|
+
return enhanced_models
|
|
147
|
+
|
|
148
|
+
@abstractmethod
|
|
149
|
+
def supports_tools(self) -> bool:
|
|
150
|
+
"""
|
|
151
|
+
Check if this provider supports tool calling.
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
True if tool calling is supported, False otherwise
|
|
155
|
+
"""
|
|
156
|
+
pass
|
|
157
|
+
|
|
158
|
+
@abstractmethod
|
|
159
|
+
def supports_multimodal(self) -> bool:
|
|
160
|
+
"""
|
|
161
|
+
Check if this provider supports multimodal inputs (images, audio, etc.).
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
True if multimodal inputs are supported, False otherwise
|
|
165
|
+
"""
|
|
166
|
+
pass
|
|
167
|
+
|
|
168
|
+
async def send_message_with_tools(
|
|
169
|
+
self,
|
|
170
|
+
message: str,
|
|
171
|
+
context: ChatContext,
|
|
172
|
+
available_tools: List[ToolDefinition],
|
|
173
|
+
) -> ChatResponse:
|
|
174
|
+
"""
|
|
175
|
+
Send a message with available tools for the AI to use.
|
|
176
|
+
|
|
177
|
+
This method should be overridden by providers that support tool calling.
|
|
178
|
+
Default implementation falls back to regular message sending.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
message: The user's message
|
|
182
|
+
context: Current conversation context
|
|
183
|
+
available_tools: List of tools available for the AI to use
|
|
184
|
+
|
|
185
|
+
Returns:
|
|
186
|
+
ChatResponse with the AI's reply and any tool calls
|
|
187
|
+
|
|
188
|
+
Raises:
|
|
189
|
+
ProviderError: If the API call fails
|
|
190
|
+
AuthenticationError: If authentication fails
|
|
191
|
+
RateLimitError: If rate limits are exceeded
|
|
192
|
+
"""
|
|
193
|
+
# Default implementation for providers that don't support tools
|
|
194
|
+
if not self.supports_tools():
|
|
195
|
+
return await self.send_message(message, context)
|
|
196
|
+
|
|
197
|
+
# This should be overridden by tool-supporting providers
|
|
198
|
+
raise NotImplementedError(
|
|
199
|
+
f"{self.__class__.__name__} supports tools but hasn't implemented send_message_with_tools"
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
def get_provider_name(self) -> str:
|
|
203
|
+
"""
|
|
204
|
+
Get the name of this provider.
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
Provider name (e.g., "claude", "openai")
|
|
208
|
+
"""
|
|
209
|
+
return self.__class__.__name__.lower().replace("provider", "")
|
|
210
|
+
|
|
211
|
+
def supports_streaming(self) -> bool:
|
|
212
|
+
"""
|
|
213
|
+
Check if this provider supports streaming responses.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
True if streaming is supported, False otherwise
|
|
217
|
+
"""
|
|
218
|
+
return False
|
|
219
|
+
|
|
220
|
+
def get_max_tokens(self) -> int:
|
|
221
|
+
"""
|
|
222
|
+
Get the maximum number of tokens supported by the current model.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Maximum token count
|
|
226
|
+
"""
|
|
227
|
+
model_info = self.get_model_info()
|
|
228
|
+
return model_info.max_tokens
|
|
229
|
+
|
|
230
|
+
def estimate_cost(self, input_tokens: int, output_tokens: int) -> float:
|
|
231
|
+
"""
|
|
232
|
+
Estimate the cost of a request based on token usage.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
input_tokens: Number of input tokens
|
|
236
|
+
output_tokens: Number of output tokens
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
Estimated cost in USD
|
|
240
|
+
"""
|
|
241
|
+
model_info = self.get_model_info()
|
|
242
|
+
return (input_tokens + output_tokens) * model_info.cost_per_token
|
|
243
|
+
|
|
244
|
+
def prepare_context(self, context: ChatContext) -> List[Dict[str, str]]:
|
|
245
|
+
"""
|
|
246
|
+
Prepare conversation context for API call.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
context: Current conversation context
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
List of message dictionaries formatted for the API
|
|
253
|
+
"""
|
|
254
|
+
return context.get_context_for_api()
|
|
255
|
+
|
|
256
|
+
def __str__(self) -> str:
|
|
257
|
+
"""String representation of the provider."""
|
|
258
|
+
return f"{self.get_provider_name()}:{self.model}"
|
|
259
|
+
|
|
260
|
+
def __repr__(self) -> str:
|
|
261
|
+
"""Detailed string representation of the provider."""
|
|
262
|
+
return f"{self.__class__.__name__}(model='{self.model}')"
|