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,362 @@
1
+ """
2
+ OpenAI provider implementation for Omnimancer.
3
+
4
+ This module provides the OpenAI API provider implementation using OpenAI's API.
5
+ """
6
+
7
+ from datetime import datetime
8
+ from typing import Dict, List
9
+
10
+ import httpx
11
+
12
+ from ..core.models import ChatContext, ChatResponse, ModelInfo
13
+ from ..utils.errors import (
14
+ AuthenticationError,
15
+ ModelNotFoundError,
16
+ NetworkError,
17
+ ProviderError,
18
+ RateLimitError,
19
+ )
20
+ from .base import BaseProvider
21
+
22
+
23
+ class OpenAIProvider(BaseProvider):
24
+ """
25
+ OpenAI API provider implementation using OpenAI's API.
26
+ """
27
+
28
+ BASE_URL = "https://api.openai.com/v1"
29
+
30
+ def __init__(self, api_key: str, model: str = "", **kwargs):
31
+ """
32
+ Initialize OpenAI provider.
33
+
34
+ Args:
35
+ api_key: OpenAI API key
36
+ model: OpenAI model to use (e.g., 'gpt-4', 'gpt-4o', 'gpt-3.5-turbo')
37
+ **kwargs: Additional configuration
38
+ """
39
+ super().__init__(api_key, model or "gpt-4", **kwargs)
40
+ self.max_tokens = kwargs.get("max_tokens", 4096)
41
+ self.temperature = kwargs.get("temperature", 0.7)
42
+
43
+ async def send_message(self, message: str, context: ChatContext) -> ChatResponse:
44
+ """
45
+ Send a message to OpenAI API.
46
+
47
+ Args:
48
+ message: User message
49
+ context: Conversation context
50
+
51
+ Returns:
52
+ ChatResponse with OpenAI's reply
53
+ """
54
+ try:
55
+ # Prepare messages for OpenAI API
56
+ messages = self._prepare_messages(message, context)
57
+
58
+ # Make API request
59
+ async with httpx.AsyncClient() as client:
60
+ response = await client.post(
61
+ f"{self.BASE_URL}/chat/completions",
62
+ headers={
63
+ "Content-Type": "application/json",
64
+ "Authorization": f"Bearer {self.api_key}",
65
+ },
66
+ json={
67
+ "model": self.model,
68
+ "messages": messages,
69
+ "max_tokens": self.max_tokens,
70
+ "temperature": self.temperature,
71
+ },
72
+ timeout=30.0,
73
+ )
74
+
75
+ # Handle response
76
+ return self._handle_response(response)
77
+
78
+ except httpx.TimeoutException:
79
+ raise NetworkError("Request to OpenAI API timed out")
80
+ except httpx.RequestError as e:
81
+ raise NetworkError(f"Network error: {e}")
82
+ except Exception as e:
83
+ raise ProviderError(f"Unexpected error: {e}")
84
+
85
+ async def validate_credentials(self) -> bool:
86
+ """
87
+ Validate OpenAI API credentials by making a test request.
88
+
89
+ Returns:
90
+ True if credentials are valid
91
+ """
92
+ try:
93
+ async with httpx.AsyncClient() as client:
94
+ response = await client.post(
95
+ f"{self.BASE_URL}/chat/completions",
96
+ headers={
97
+ "Content-Type": "application/json",
98
+ "Authorization": f"Bearer {self.api_key}",
99
+ },
100
+ json={
101
+ "model": self.model,
102
+ "messages": [{"role": "user", "content": "Hi"}],
103
+ "max_tokens": 10,
104
+ },
105
+ timeout=10.0,
106
+ )
107
+
108
+ return response.status_code == 200
109
+
110
+ except Exception:
111
+ return False
112
+
113
+ def _prepare_messages(
114
+ self, message: str, context: ChatContext
115
+ ) -> List[Dict[str, str]]:
116
+ """
117
+ Prepare messages for OpenAI API format.
118
+
119
+ Args:
120
+ message: Current user message
121
+ context: Conversation context
122
+
123
+ Returns:
124
+ List of messages formatted for OpenAI API
125
+ """
126
+ messages = []
127
+
128
+ # Add context messages
129
+ for msg in context.messages:
130
+ messages.append({"role": msg.role.value, "content": msg.content})
131
+
132
+ # Add current message
133
+ messages.append({"role": "user", "content": message})
134
+
135
+ return messages
136
+
137
+ def _handle_response(self, response: httpx.Response) -> ChatResponse:
138
+ """
139
+ Handle OpenAI API response.
140
+
141
+ Args:
142
+ response: HTTP response from OpenAI API
143
+
144
+ Returns:
145
+ ChatResponse object
146
+
147
+ Raises:
148
+ Various provider errors based on response status
149
+ """
150
+ if response.status_code == 200:
151
+ data = response.json()
152
+ choices = data.get("choices", [])
153
+
154
+ if choices and len(choices) > 0:
155
+ message = choices[0].get("message", {})
156
+ content = message.get("content", "")
157
+ usage = data.get("usage", {})
158
+
159
+ return ChatResponse(
160
+ content=content,
161
+ model_used=self.model,
162
+ tokens_used=usage.get("total_tokens", 0),
163
+ timestamp=datetime.now(),
164
+ )
165
+ else:
166
+ raise ProviderError("Empty response from OpenAI API")
167
+
168
+ elif response.status_code == 401:
169
+ raise AuthenticationError("Invalid OpenAI API key")
170
+ elif response.status_code == 429:
171
+ raise RateLimitError("OpenAI API rate limit exceeded")
172
+ elif response.status_code == 404:
173
+ raise ModelNotFoundError(f"OpenAI model '{self.model}' not found")
174
+ else:
175
+ try:
176
+ error_data = response.json()
177
+ error_msg = error_data.get("error", {}).get("message", "Unknown error")
178
+ except:
179
+ error_msg = f"HTTP {response.status_code}"
180
+
181
+ raise ProviderError(f"OpenAI API error: {error_msg}")
182
+
183
+ def get_model_info(self) -> ModelInfo:
184
+ """
185
+ Get information about the current OpenAI model.
186
+ """
187
+ model_configs = {
188
+ "gpt-4": {
189
+ "description": "GPT-4 - Most capable model",
190
+ "max_tokens": 8192,
191
+ "cost_per_token": 0.00003,
192
+ },
193
+ "gpt-4-turbo": {
194
+ "description": "GPT-4 Turbo - Enhanced performance",
195
+ "max_tokens": 128000,
196
+ "cost_per_token": 0.00001,
197
+ },
198
+ "gpt-3.5-turbo": {
199
+ "description": "GPT-3.5 Turbo - Fast and efficient",
200
+ "max_tokens": 4096,
201
+ "cost_per_token": 0.000002,
202
+ },
203
+ "gpt-3.5-turbo-16k": {
204
+ "description": "GPT-3.5 Turbo with 16K context",
205
+ "max_tokens": 16384,
206
+ "cost_per_token": 0.000004,
207
+ },
208
+ }
209
+
210
+ config = model_configs.get(
211
+ self.model,
212
+ {
213
+ "description": f"OpenAI model {self.model}",
214
+ "max_tokens": 4096,
215
+ "cost_per_token": 0.00002,
216
+ },
217
+ )
218
+
219
+ return ModelInfo(
220
+ name=self.model,
221
+ provider="openai",
222
+ description=config["description"],
223
+ max_tokens=config["max_tokens"],
224
+ cost_per_token=config["cost_per_token"],
225
+ available=True,
226
+ supports_tools=self.supports_tools(),
227
+ supports_multimodal=self.supports_multimodal(),
228
+ latest_version=self.model == "gpt-4-turbo",
229
+ )
230
+
231
+ def _get_static_models(self) -> List[ModelInfo]:
232
+ """
233
+ Get static list of available OpenAI models.
234
+ """
235
+ return [
236
+ ModelInfo(
237
+ name="gpt-4",
238
+ provider="openai",
239
+ description="GPT-4 - Most capable model",
240
+ max_tokens=8192,
241
+ cost_per_token=0.00003,
242
+ available=True,
243
+ supports_tools=True,
244
+ supports_multimodal=False,
245
+ ),
246
+ ModelInfo(
247
+ name="gpt-4-turbo",
248
+ provider="openai",
249
+ description="GPT-4 Turbo - Enhanced performance",
250
+ max_tokens=128000,
251
+ cost_per_token=0.00001,
252
+ available=True,
253
+ supports_tools=True,
254
+ supports_multimodal=True,
255
+ latest_version=True,
256
+ ),
257
+ ModelInfo(
258
+ name="gpt-3.5-turbo",
259
+ provider="openai",
260
+ description="GPT-3.5 Turbo - Fast and efficient",
261
+ max_tokens=4096,
262
+ cost_per_token=0.000002,
263
+ available=True,
264
+ supports_tools=True,
265
+ supports_multimodal=False,
266
+ ),
267
+ ModelInfo(
268
+ name="gpt-3.5-turbo-16k",
269
+ provider="openai",
270
+ description="GPT-3.5 Turbo with 16K context",
271
+ max_tokens=16384,
272
+ cost_per_token=0.000004,
273
+ available=True,
274
+ supports_tools=True,
275
+ supports_multimodal=False,
276
+ ),
277
+ ]
278
+
279
+ def supports_tools(self) -> bool:
280
+ """
281
+ Check if OpenAI provider supports tool calling.
282
+
283
+ Returns:
284
+ True - OpenAI supports function calling/tools
285
+ """
286
+ return True
287
+
288
+ def supports_multimodal(self) -> bool:
289
+ """
290
+ Check if OpenAI provider supports multimodal inputs.
291
+
292
+ Returns:
293
+ True for GPT-4 models that support vision, False for others
294
+ """
295
+ # GPT-4 models with vision support
296
+ vision_models = ["gpt-4-vision-preview", "gpt-4-turbo", "gpt-4o"]
297
+ return any(model in self.model for model in vision_models)
298
+
299
+ async def fetch_live_models(self) -> List[ModelInfo]:
300
+ """
301
+ Fetch live model list from OpenAI API.
302
+
303
+ Returns:
304
+ List of ModelInfo objects from OpenAI API
305
+ """
306
+ try:
307
+ headers = {
308
+ "Authorization": f"Bearer {self.api_key}",
309
+ "Content-Type": "application/json",
310
+ }
311
+
312
+ async with httpx.AsyncClient() as client:
313
+ response = await client.get(
314
+ f"{self.BASE_URL}/models", headers=headers, timeout=30.0
315
+ )
316
+ response.raise_for_status()
317
+
318
+ data = response.json()
319
+ models = []
320
+
321
+ # Filter and convert to ModelInfo objects
322
+ for model_data in data.get("data", []):
323
+ model_id = model_data.get("id", "")
324
+
325
+ # Filter for chat models (exclude fine-tuned and other model types)
326
+ if any(prefix in model_id for prefix in ["gpt-3.5", "gpt-4"]):
327
+ # Determine model capabilities
328
+ supports_tools = (
329
+ "gpt-3.5-turbo" in model_id or "gpt-4" in model_id
330
+ )
331
+ supports_multimodal = any(
332
+ vision in model_id
333
+ for vision in ["gpt-4-turbo", "gpt-4o", "vision"]
334
+ )
335
+
336
+ # Estimate max tokens based on model
337
+ max_tokens = 4096 # default
338
+ if "gpt-4-turbo" in model_id or "gpt-4o" in model_id:
339
+ max_tokens = 128000
340
+ elif "gpt-4" in model_id:
341
+ max_tokens = 8192
342
+ elif "gpt-3.5-turbo" in model_id:
343
+ max_tokens = 16384
344
+
345
+ models.append(
346
+ ModelInfo(
347
+ name=model_id,
348
+ provider="openai",
349
+ description=f"OpenAI {model_id}",
350
+ max_tokens=max_tokens,
351
+ cost_per_token=0.00001, # Approximate
352
+ available=True,
353
+ supports_tools=supports_tools,
354
+ supports_multimodal=supports_multimodal,
355
+ )
356
+ )
357
+
358
+ return models
359
+
360
+ except Exception:
361
+ # Fall back to static model list if API call fails
362
+ return self.get_available_models()