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,432 @@
1
+ """
2
+ Provider registry for comprehensive model catalog management.
3
+
4
+ This module provides a centralized registry for managing AI providers
5
+ and their model catalogs with enhanced information.
6
+ """
7
+
8
+ import logging
9
+ from datetime import datetime
10
+ from typing import Any, Dict, List, Optional, Type
11
+
12
+ from ..providers.base import BaseProvider
13
+ from ..utils.errors import ConfigurationError
14
+ from .models import EnhancedModelInfo
15
+
16
+ logger = logging.getLogger(__name__)
17
+
18
+
19
+ class ProviderRegistry:
20
+ """Enhanced provider registry with comprehensive model catalog."""
21
+
22
+ def __init__(self):
23
+ """Initialize the provider registry."""
24
+ self.providers: Dict[str, Type[BaseProvider]] = {}
25
+ self.model_catalog: Dict[str, List[EnhancedModelInfo]] = {}
26
+ self.last_update: Optional[datetime] = None
27
+ self._provider_instances: Dict[str, BaseProvider] = {}
28
+
29
+ def register_provider(self, name: str, provider_class: Type[BaseProvider]) -> None:
30
+ """
31
+ Register a provider with the registry.
32
+
33
+ Args:
34
+ name: Provider name (e.g., "claude", "openai")
35
+ provider_class: Provider class to register
36
+ """
37
+ logger.info(f"Registering provider: {name}")
38
+ self.providers[name] = provider_class
39
+
40
+ # Initialize empty model catalog for this provider
41
+ if name not in self.model_catalog:
42
+ self.model_catalog[name] = []
43
+
44
+ def unregister_provider(self, name: str) -> bool:
45
+ """
46
+ Unregister a provider from the registry.
47
+
48
+ Args:
49
+ name: Provider name to unregister
50
+
51
+ Returns:
52
+ True if provider was unregistered, False if not found
53
+ """
54
+ if name in self.providers:
55
+ logger.info(f"Unregistering provider: {name}")
56
+ del self.providers[name]
57
+
58
+ # Clean up model catalog and instances
59
+ if name in self.model_catalog:
60
+ del self.model_catalog[name]
61
+ if name in self._provider_instances:
62
+ del self._provider_instances[name]
63
+
64
+ return True
65
+ return False
66
+
67
+ def get_registered_providers(self) -> List[str]:
68
+ """
69
+ Get list of registered provider names.
70
+
71
+ Returns:
72
+ List of provider names
73
+ """
74
+ return list(self.providers.keys())
75
+
76
+ def is_provider_registered(self, name: str) -> bool:
77
+ """
78
+ Check if a provider is registered.
79
+
80
+ Args:
81
+ name: Provider name
82
+
83
+ Returns:
84
+ True if provider is registered
85
+ """
86
+ return name in self.providers
87
+
88
+ def get_provider_class(self, name: str) -> Type[BaseProvider]:
89
+ """
90
+ Get provider class by name.
91
+
92
+ Args:
93
+ name: Provider name
94
+
95
+ Returns:
96
+ Provider class
97
+
98
+ Raises:
99
+ ConfigurationError: If provider is not registered
100
+ """
101
+ if name not in self.providers:
102
+ raise ConfigurationError(f"Provider '{name}' is not registered")
103
+ return self.providers[name]
104
+
105
+ def get_all_models_with_details(
106
+ self,
107
+ ) -> Dict[str, List[EnhancedModelInfo]]:
108
+ """
109
+ Get comprehensive model catalog with all details.
110
+
111
+ Returns:
112
+ Dictionary mapping provider names to their enhanced model lists
113
+ """
114
+ return self.model_catalog.copy()
115
+
116
+ def get_models_for_provider(self, provider_name: str) -> List[EnhancedModelInfo]:
117
+ """
118
+ Get models for a specific provider.
119
+
120
+ Args:
121
+ provider_name: Name of the provider
122
+
123
+ Returns:
124
+ List of enhanced model info for the provider
125
+ """
126
+ return self.model_catalog.get(provider_name, [])
127
+
128
+ def update_provider_models(
129
+ self, provider_name: str, models: List[EnhancedModelInfo]
130
+ ) -> None:
131
+ """
132
+ Update model catalog for a specific provider.
133
+
134
+ Args:
135
+ provider_name: Name of the provider
136
+ models: List of enhanced model info
137
+ """
138
+ logger.info(
139
+ f"Updating model catalog for provider: {provider_name} ({len(models)} models)"
140
+ )
141
+ self.model_catalog[provider_name] = models
142
+ self.last_update = datetime.now()
143
+
144
+ def get_models_by_capability(
145
+ self, capability: str
146
+ ) -> Dict[str, List[EnhancedModelInfo]]:
147
+ """
148
+ Get models filtered by capability (tools, multimodal, etc.).
149
+
150
+ Args:
151
+ capability: Capability to filter by ('tools', 'multimodal', 'latest', 'free')
152
+
153
+ Returns:
154
+ Dictionary mapping provider names to filtered models
155
+ """
156
+ filtered_models = {}
157
+
158
+ for provider_name, models in self.model_catalog.items():
159
+ if capability == "tools":
160
+ filtered = [m for m in models if m.supports_tools]
161
+ elif capability == "multimodal":
162
+ filtered = [m for m in models if m.supports_multimodal]
163
+ elif capability == "latest":
164
+ filtered = [m for m in models if m.latest_version]
165
+ elif capability == "free":
166
+ filtered = [m for m in models if m.is_free]
167
+ elif capability == "available":
168
+ filtered = [m for m in models if m.available and not m.deprecated]
169
+ else:
170
+ filtered = models
171
+
172
+ if filtered:
173
+ filtered_models[provider_name] = filtered
174
+
175
+ return filtered_models
176
+
177
+ def get_models_by_pricing(
178
+ self, max_cost_per_million: float
179
+ ) -> Dict[str, List[EnhancedModelInfo]]:
180
+ """
181
+ Get models filtered by maximum cost per million tokens.
182
+
183
+ Args:
184
+ max_cost_per_million: Maximum average cost per million tokens
185
+
186
+ Returns:
187
+ Dictionary mapping provider names to models within budget
188
+ """
189
+ filtered_models = {}
190
+
191
+ for provider_name, models in self.model_catalog.items():
192
+ budget_models = []
193
+ for model in models:
194
+ if model.is_free:
195
+ budget_models.append(model)
196
+ else:
197
+ avg_cost = (
198
+ model.cost_per_million_input + model.cost_per_million_output
199
+ ) / 2
200
+ if avg_cost <= max_cost_per_million:
201
+ budget_models.append(model)
202
+
203
+ if budget_models:
204
+ filtered_models[provider_name] = budget_models
205
+
206
+ return filtered_models
207
+
208
+ def get_models_by_performance(
209
+ self, min_swe_score: float
210
+ ) -> Dict[str, List[EnhancedModelInfo]]:
211
+ """
212
+ Get models filtered by minimum SWE score.
213
+
214
+ Args:
215
+ min_swe_score: Minimum SWE score (0-100)
216
+
217
+ Returns:
218
+ Dictionary mapping provider names to high-performance models
219
+ """
220
+ filtered_models = {}
221
+
222
+ for provider_name, models in self.model_catalog.items():
223
+ high_perf_models = [
224
+ m
225
+ for m in models
226
+ if m.swe_score is not None and m.swe_score >= min_swe_score
227
+ ]
228
+
229
+ if high_perf_models:
230
+ filtered_models[provider_name] = high_perf_models
231
+
232
+ return filtered_models
233
+
234
+ def search_models(self, query: str) -> Dict[str, List[EnhancedModelInfo]]:
235
+ """
236
+ Search models by name or description.
237
+
238
+ Args:
239
+ query: Search query string
240
+
241
+ Returns:
242
+ Dictionary mapping provider names to matching models
243
+ """
244
+ query_lower = query.lower()
245
+ matching_models = {}
246
+
247
+ for provider_name, models in self.model_catalog.items():
248
+ matches = [
249
+ m
250
+ for m in models
251
+ if query_lower in m.name.lower() or query_lower in m.description.lower()
252
+ ]
253
+
254
+ if matches:
255
+ matching_models[provider_name] = matches
256
+
257
+ return matching_models
258
+
259
+ def get_model_by_name(
260
+ self, provider_name: str, model_name: str
261
+ ) -> Optional[EnhancedModelInfo]:
262
+ """
263
+ Get a specific model by provider and name.
264
+
265
+ Args:
266
+ provider_name: Name of the provider
267
+ model_name: Name of the model
268
+
269
+ Returns:
270
+ Enhanced model info if found, None otherwise
271
+ """
272
+ models = self.model_catalog.get(provider_name, [])
273
+ for model in models:
274
+ if model.name == model_name:
275
+ return model
276
+ return None
277
+
278
+ def get_latest_models(self) -> Dict[str, List[EnhancedModelInfo]]:
279
+ """
280
+ Get the latest models from all providers.
281
+
282
+ Returns:
283
+ Dictionary mapping provider names to their latest models
284
+ """
285
+ return self.get_models_by_capability("latest")
286
+
287
+ def get_free_models(self) -> Dict[str, List[EnhancedModelInfo]]:
288
+ """
289
+ Get all free models from all providers.
290
+
291
+ Returns:
292
+ Dictionary mapping provider names to their free models
293
+ """
294
+ return self.get_models_by_capability("free")
295
+
296
+ def get_tool_capable_models(self) -> Dict[str, List[EnhancedModelInfo]]:
297
+ """
298
+ Get all models that support tool calling.
299
+
300
+ Returns:
301
+ Dictionary mapping provider names to their tool-capable models
302
+ """
303
+ return self.get_models_by_capability("tools")
304
+
305
+ def get_multimodal_models(self) -> Dict[str, List[EnhancedModelInfo]]:
306
+ """
307
+ Get all models that support multimodal inputs.
308
+
309
+ Returns:
310
+ Dictionary mapping provider names to their multimodal models
311
+ """
312
+ return self.get_models_by_capability("multimodal")
313
+
314
+ def get_catalog_stats(self) -> Dict[str, Any]:
315
+ """
316
+ Get statistics about the model catalog.
317
+
318
+ Returns:
319
+ Dictionary with catalog statistics
320
+ """
321
+ total_models = sum(len(models) for models in self.model_catalog.values())
322
+ total_providers = len(self.providers)
323
+
324
+ # Count models by capability
325
+ tool_models = sum(
326
+ len(models) for models in self.get_tool_capable_models().values()
327
+ )
328
+ multimodal_models = sum(
329
+ len(models) for models in self.get_multimodal_models().values()
330
+ )
331
+ free_models = sum(len(models) for models in self.get_free_models().values())
332
+ latest_models = sum(len(models) for models in self.get_latest_models().values())
333
+
334
+ # Count models by performance tier
335
+ high_perf = sum(
336
+ len(models) for models in self.get_models_by_performance(60.0).values()
337
+ )
338
+ mid_perf = (
339
+ sum(len(models) for models in self.get_models_by_performance(40.0).values())
340
+ - high_perf
341
+ )
342
+
343
+ return {
344
+ "total_providers": total_providers,
345
+ "total_models": total_models,
346
+ "tool_capable_models": tool_models,
347
+ "multimodal_models": multimodal_models,
348
+ "free_models": free_models,
349
+ "latest_models": latest_models,
350
+ "high_performance_models": high_perf,
351
+ "mid_performance_models": mid_perf,
352
+ "last_update": self.last_update,
353
+ "providers": list(self.providers.keys()),
354
+ }
355
+
356
+ def validate_catalog(self) -> List[str]:
357
+ """
358
+ Validate the model catalog and return any issues found.
359
+
360
+ Returns:
361
+ List of validation error messages
362
+ """
363
+ errors = []
364
+
365
+ for provider_name, models in self.model_catalog.items():
366
+ if provider_name not in self.providers:
367
+ errors.append(
368
+ f"Models exist for unregistered provider: {provider_name}"
369
+ )
370
+ continue
371
+
372
+ for model in models:
373
+ # Validate model data
374
+ if not model.validate_pricing():
375
+ errors.append(f"Invalid pricing for {provider_name}:{model.name}")
376
+
377
+ if not model.validate_swe_score():
378
+ errors.append(f"Invalid SWE score for {provider_name}:{model.name}")
379
+
380
+ # Check for duplicate models
381
+ duplicates = [m for m in models if m.name == model.name]
382
+ if len(duplicates) > 1:
383
+ errors.append(
384
+ f"Duplicate model {model.name} in provider {provider_name}"
385
+ )
386
+
387
+ return errors
388
+
389
+ def clear_catalog(self) -> None:
390
+ """Clear all model catalog data."""
391
+ logger.info("Clearing model catalog")
392
+ self.model_catalog.clear()
393
+ self.last_update = None
394
+
395
+ def get_provider_summary(self, provider_name: str) -> Dict[str, Any]:
396
+ """
397
+ Get summary information for a specific provider.
398
+
399
+ Args:
400
+ provider_name: Name of the provider
401
+
402
+ Returns:
403
+ Dictionary with provider summary
404
+ """
405
+ if provider_name not in self.providers:
406
+ return {"error": f"Provider {provider_name} not registered"}
407
+
408
+ models = self.model_catalog.get(provider_name, [])
409
+
410
+ return {
411
+ "name": provider_name,
412
+ "registered": True,
413
+ "total_models": len(models),
414
+ "available_models": len(
415
+ [m for m in models if m.available and not m.deprecated]
416
+ ),
417
+ "tool_capable_models": len([m for m in models if m.supports_tools]),
418
+ "multimodal_models": len([m for m in models if m.supports_multimodal]),
419
+ "free_models": len([m for m in models if m.is_free]),
420
+ "latest_models": len([m for m in models if m.latest_version]),
421
+ "deprecated_models": len([m for m in models if m.deprecated]),
422
+ "models": [m.name for m in models if m.available and not m.deprecated],
423
+ }
424
+
425
+ def __str__(self) -> str:
426
+ """String representation of the registry."""
427
+ stats = self.get_catalog_stats()
428
+ return f"ProviderRegistry({stats['total_providers']} providers, {stats['total_models']} models)"
429
+
430
+ def __repr__(self) -> str:
431
+ """Detailed string representation of the registry."""
432
+ return f"ProviderRegistry(providers={list(self.providers.keys())}, last_update={self.last_update})"
@@ -0,0 +1,16 @@
1
+ """Security framework for Omnimancer agents."""
2
+
3
+ from .approval_workflow import ApprovalWorkflow
4
+ from .audit_logger import AuditLogger
5
+ from .permission_controller import PermissionController, PermissionOperation
6
+ from .sandbox_manager import SandboxManager
7
+ from .security_manager import SecurityManager
8
+
9
+ __all__ = [
10
+ "SecurityManager",
11
+ "PermissionController",
12
+ "PermissionOperation",
13
+ "SandboxManager",
14
+ "ApprovalWorkflow",
15
+ "AuditLogger",
16
+ ]