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,454 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Provider setup methods for the setup wizard.
|
|
3
|
+
|
|
4
|
+
This module contains all provider configuration and setup methods,
|
|
5
|
+
including provider selection, API key management, and model selection.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from typing import Any, Dict, Optional
|
|
9
|
+
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
from rich.prompt import Confirm, Prompt
|
|
12
|
+
from rich.table import Table
|
|
13
|
+
|
|
14
|
+
from .models import ProviderConfig
|
|
15
|
+
from .setup_wizard_ui import SetupWizardUI
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class SetupWizardProviderSetup:
|
|
19
|
+
"""Provider setup methods for the setup wizard."""
|
|
20
|
+
|
|
21
|
+
def __init__(self, console: Console, provider_info: Dict[str, Dict[str, Any]]):
|
|
22
|
+
"""
|
|
23
|
+
Initialize the provider setup component.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
console: Rich console instance
|
|
27
|
+
provider_info: Dictionary of provider information
|
|
28
|
+
"""
|
|
29
|
+
self.console = console
|
|
30
|
+
self.provider_info = provider_info
|
|
31
|
+
self.ui = SetupWizardUI(console, provider_info)
|
|
32
|
+
|
|
33
|
+
def select_provider(self) -> Optional[str]:
|
|
34
|
+
"""
|
|
35
|
+
Interactive provider selection with descriptions.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
Selected provider name or None if cancelled
|
|
39
|
+
"""
|
|
40
|
+
self.console.print("[bold]Available AI Providers:[/bold]\n")
|
|
41
|
+
|
|
42
|
+
# Create provider selection table
|
|
43
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
44
|
+
table.add_column("#", style="dim", width=3)
|
|
45
|
+
table.add_column("Provider", style="bold")
|
|
46
|
+
table.add_column("Description", style="dim")
|
|
47
|
+
table.add_column("Best For", style="green")
|
|
48
|
+
|
|
49
|
+
providers = list(self.provider_info.keys())
|
|
50
|
+
for i, provider_key in enumerate(providers, 1):
|
|
51
|
+
info = self.provider_info[provider_key]
|
|
52
|
+
strengths = ", ".join(info["strengths"][:2]) # Show first 2 strengths
|
|
53
|
+
table.add_row(str(i), info["name"], info["description"], strengths)
|
|
54
|
+
|
|
55
|
+
self.console.print(table)
|
|
56
|
+
self.console.print()
|
|
57
|
+
|
|
58
|
+
# Get user selection
|
|
59
|
+
while True:
|
|
60
|
+
try:
|
|
61
|
+
choice = Prompt.ask(
|
|
62
|
+
"Select a provider",
|
|
63
|
+
choices=[str(i) for i in range(1, len(providers) + 1)] + ["q"],
|
|
64
|
+
default="1",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
if choice.lower() == "q":
|
|
68
|
+
return None
|
|
69
|
+
|
|
70
|
+
provider_index = int(choice) - 1
|
|
71
|
+
selected_provider = providers[provider_index]
|
|
72
|
+
|
|
73
|
+
# Show detailed provider information
|
|
74
|
+
self.ui.show_provider_details(selected_provider)
|
|
75
|
+
|
|
76
|
+
if Confirm.ask(
|
|
77
|
+
f"Configure {self.provider_info[selected_provider]['name']}?"
|
|
78
|
+
):
|
|
79
|
+
return selected_provider
|
|
80
|
+
|
|
81
|
+
except (ValueError, IndexError):
|
|
82
|
+
self.console.print("[red]Invalid selection. Please try again.[/red]")
|
|
83
|
+
|
|
84
|
+
async def configure_provider(self, provider_name: str) -> Optional[ProviderConfig]:
|
|
85
|
+
"""
|
|
86
|
+
Configure a specific provider with validation.
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
provider_name: Name of the provider to configure
|
|
90
|
+
|
|
91
|
+
Returns:
|
|
92
|
+
Configured ProviderConfig or None if failed
|
|
93
|
+
"""
|
|
94
|
+
info = self.provider_info[provider_name]
|
|
95
|
+
|
|
96
|
+
self.console.print(f"\n[bold]Configuring {info['name']}[/bold]")
|
|
97
|
+
self.console.print(f"[dim]{info['setup_notes']}[/dim]")
|
|
98
|
+
self.console.print(f"[dim]Get your API key from: {info['api_key_url']}[/dim]\n")
|
|
99
|
+
|
|
100
|
+
# Get API key (if required)
|
|
101
|
+
api_key = None
|
|
102
|
+
if provider_name not in [
|
|
103
|
+
"ollama",
|
|
104
|
+
"claude-code",
|
|
105
|
+
]: # Ollama and Claude Code don't need API key
|
|
106
|
+
api_key = self._get_api_key(provider_name, info)
|
|
107
|
+
if not api_key:
|
|
108
|
+
return None
|
|
109
|
+
elif provider_name == "claude-code":
|
|
110
|
+
# Claude Code uses local authentication, set a placeholder
|
|
111
|
+
api_key = "local"
|
|
112
|
+
|
|
113
|
+
# Select model
|
|
114
|
+
model = self._select_model(provider_name, info)
|
|
115
|
+
if not model:
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
# Get additional settings
|
|
119
|
+
additional_settings = self._get_additional_settings(provider_name)
|
|
120
|
+
|
|
121
|
+
# Create provider config
|
|
122
|
+
config_data = {
|
|
123
|
+
"api_key": api_key,
|
|
124
|
+
"model": model,
|
|
125
|
+
**additional_settings,
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return ProviderConfig(**config_data)
|
|
129
|
+
|
|
130
|
+
def _get_api_key(self, provider_name: str, info: Dict[str, Any]) -> Optional[str]:
|
|
131
|
+
"""
|
|
132
|
+
Get and validate API key from user.
|
|
133
|
+
|
|
134
|
+
Args:
|
|
135
|
+
provider_name: Name of the provider
|
|
136
|
+
info: Provider information dictionary
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
Valid API key or None if cancelled
|
|
140
|
+
"""
|
|
141
|
+
while True:
|
|
142
|
+
api_key = Prompt.ask(f"Enter your {info['name']} API key", password=True)
|
|
143
|
+
|
|
144
|
+
if not api_key:
|
|
145
|
+
if not Confirm.ask("API key is required. Continue without it?"):
|
|
146
|
+
continue
|
|
147
|
+
return None
|
|
148
|
+
|
|
149
|
+
# Basic format validation
|
|
150
|
+
if info["api_key_prefix"] and not api_key.startswith(
|
|
151
|
+
info["api_key_prefix"]
|
|
152
|
+
):
|
|
153
|
+
self.console.print(
|
|
154
|
+
f"[yellow]⚠️ API key should start with '{info['api_key_prefix']}'[/yellow]"
|
|
155
|
+
)
|
|
156
|
+
if not Confirm.ask("Continue with this API key anyway?"):
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
return api_key
|
|
160
|
+
|
|
161
|
+
def _select_model(self, provider_name: str, info: Dict[str, Any]) -> Optional[str]:
|
|
162
|
+
"""
|
|
163
|
+
Select model for the provider.
|
|
164
|
+
|
|
165
|
+
Args:
|
|
166
|
+
provider_name: Name of the provider
|
|
167
|
+
info: Provider information dictionary
|
|
168
|
+
|
|
169
|
+
Returns:
|
|
170
|
+
Selected model name or None if cancelled
|
|
171
|
+
"""
|
|
172
|
+
models = info["models"]
|
|
173
|
+
|
|
174
|
+
# Allow custom model IDs for all providers
|
|
175
|
+
self.console.print(f"\n[bold]Model options for {info['name']}:[/bold]")
|
|
176
|
+
self.console.print("You can either:")
|
|
177
|
+
self.console.print(" 1. Select from common models")
|
|
178
|
+
self.console.print(" 2. Enter a custom model ID")
|
|
179
|
+
self.console.print()
|
|
180
|
+
|
|
181
|
+
choice = Prompt.ask("Choose option", choices=["1", "2"], default="1")
|
|
182
|
+
|
|
183
|
+
if choice == "2":
|
|
184
|
+
self.console.print(
|
|
185
|
+
f"\n[bold cyan]Custom Model ID Entry for {info['name']}:[/bold cyan]"
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
# Provider-specific examples
|
|
189
|
+
if provider_name == "bedrock":
|
|
190
|
+
self.console.print("Examples:")
|
|
191
|
+
self.console.print(
|
|
192
|
+
" • Model ID: [dim]anthropic.claude-opus-4-20250514-v1:0[/dim]"
|
|
193
|
+
)
|
|
194
|
+
self.console.print(
|
|
195
|
+
" • Inference Profile: [dim]us.anthropic.claude-opus-4-20250514-v1:0[/dim]"
|
|
196
|
+
)
|
|
197
|
+
self.console.print(
|
|
198
|
+
" • Foundation ARN: [dim]arn:aws:bedrock:us-west-2::foundation-model/meta.llama4-maverick-17b-instruct-v1:0[/dim]"
|
|
199
|
+
)
|
|
200
|
+
self.console.print(
|
|
201
|
+
" • Inference Profile ARN: [dim]arn:aws:bedrock:us-west-2::inference-profile/us.meta.llama4-maverick-17b-instruct-v1:0[/dim]"
|
|
202
|
+
)
|
|
203
|
+
elif provider_name == "openai":
|
|
204
|
+
self.console.print("Examples:")
|
|
205
|
+
self.console.print(" • [dim]gpt-4o[/dim]")
|
|
206
|
+
self.console.print(" • [dim]gpt-4o-mini[/dim]")
|
|
207
|
+
self.console.print(" • [dim]o1-preview[/dim]")
|
|
208
|
+
self.console.print(" • [dim]gpt-4-turbo[/dim]")
|
|
209
|
+
elif provider_name == "claude":
|
|
210
|
+
self.console.print("Examples:")
|
|
211
|
+
self.console.print(" • [dim]claude-sonnet-4-20250514[/dim]")
|
|
212
|
+
self.console.print(" • [dim]claude-opus-4-20250514[/dim]")
|
|
213
|
+
self.console.print(" • [dim]claude-3-5-sonnet-20241022[/dim]")
|
|
214
|
+
elif provider_name == "gemini":
|
|
215
|
+
self.console.print("Examples:")
|
|
216
|
+
self.console.print(" • [dim]gemini-1.5-pro[/dim]")
|
|
217
|
+
self.console.print(" • [dim]gemini-1.5-flash[/dim]")
|
|
218
|
+
self.console.print(" • [dim]gemini-2.0-flash-exp[/dim]")
|
|
219
|
+
elif provider_name == "openrouter":
|
|
220
|
+
self.console.print("Examples:")
|
|
221
|
+
self.console.print(" • [dim]anthropic/claude-3.5-sonnet[/dim]")
|
|
222
|
+
self.console.print(" • [dim]openai/gpt-4o[/dim]")
|
|
223
|
+
self.console.print(" • [dim]meta-llama/llama-3.1-70b-instruct[/dim]")
|
|
224
|
+
elif provider_name == "ollama":
|
|
225
|
+
self.console.print("Examples:")
|
|
226
|
+
self.console.print(" • [dim]llama3:8b[/dim]")
|
|
227
|
+
self.console.print(" • [dim]mistral:7b[/dim]")
|
|
228
|
+
self.console.print(" • [dim]codellama:13b[/dim]")
|
|
229
|
+
elif provider_name == "perplexity":
|
|
230
|
+
self.console.print("Examples:")
|
|
231
|
+
self.console.print(" • [dim]llama-3.1-sonar-large-128k-online[/dim]")
|
|
232
|
+
self.console.print(" • [dim]llama-3.1-sonar-small-128k-online[/dim]")
|
|
233
|
+
elif provider_name == "xai":
|
|
234
|
+
self.console.print("Examples:")
|
|
235
|
+
self.console.print(" • [dim]grok-beta[/dim]")
|
|
236
|
+
self.console.print(" • [dim]grok-vision-beta[/dim]")
|
|
237
|
+
elif provider_name == "mistral":
|
|
238
|
+
self.console.print("Examples:")
|
|
239
|
+
self.console.print(" • [dim]mistral-large-latest[/dim]")
|
|
240
|
+
self.console.print(" • [dim]mistral-small-latest[/dim]")
|
|
241
|
+
self.console.print(" • [dim]open-mistral-7b[/dim]")
|
|
242
|
+
elif provider_name == "cohere":
|
|
243
|
+
self.console.print("Examples:")
|
|
244
|
+
self.console.print(" • [dim]command-r[/dim]")
|
|
245
|
+
self.console.print(" • [dim]command-r-plus[/dim]")
|
|
246
|
+
self.console.print(" • [dim]command[/dim]")
|
|
247
|
+
elif provider_name == "azure":
|
|
248
|
+
self.console.print("Examples:")
|
|
249
|
+
self.console.print(" • [dim]gpt-4[/dim] (your deployment name)")
|
|
250
|
+
self.console.print(" • [dim]gpt-35-turbo[/dim] (your deployment name)")
|
|
251
|
+
self.console.print(
|
|
252
|
+
" • [dim]my-custom-model[/dim] (your deployment name)"
|
|
253
|
+
)
|
|
254
|
+
elif provider_name == "vertex":
|
|
255
|
+
self.console.print("Examples:")
|
|
256
|
+
self.console.print(" • [dim]gemini-1.5-pro[/dim]")
|
|
257
|
+
self.console.print(" • [dim]gemini-1.5-flash[/dim]")
|
|
258
|
+
self.console.print(" • [dim]gemini-pro[/dim]")
|
|
259
|
+
elif provider_name == "claude-code":
|
|
260
|
+
self.console.print("Examples:")
|
|
261
|
+
self.console.print(" • [dim]claude-code-sonnet[/dim]")
|
|
262
|
+
self.console.print(" • [dim]claude-code-opus[/dim]")
|
|
263
|
+
self.console.print(" • [dim]claude-code-haiku[/dim]")
|
|
264
|
+
|
|
265
|
+
self.console.print()
|
|
266
|
+
|
|
267
|
+
custom_model = Prompt.ask("Enter custom model ID")
|
|
268
|
+
if custom_model:
|
|
269
|
+
return custom_model
|
|
270
|
+
else:
|
|
271
|
+
self.console.print(
|
|
272
|
+
"[yellow]No model entered, falling back to common models...[/yellow]"
|
|
273
|
+
)
|
|
274
|
+
|
|
275
|
+
self.console.print(f"\n[bold]Common models for {info['name']}:[/bold]")
|
|
276
|
+
|
|
277
|
+
# Create model selection table
|
|
278
|
+
table = Table(show_header=True, header_style="bold magenta")
|
|
279
|
+
table.add_column("#", style="dim", width=3)
|
|
280
|
+
table.add_column("Model", style="bold")
|
|
281
|
+
table.add_column("Description", style="dim")
|
|
282
|
+
|
|
283
|
+
# Get model descriptions (simplified for now)
|
|
284
|
+
model_descriptions = {
|
|
285
|
+
"claude-3-5-sonnet-20241022": "Latest Claude model with enhanced capabilities",
|
|
286
|
+
"claude-3-haiku-20240307": "Fast and efficient Claude model",
|
|
287
|
+
"claude-3-opus-20240229": "Most capable Claude model",
|
|
288
|
+
"gpt-4o": "Latest GPT-4 with vision and tool use",
|
|
289
|
+
"gpt-4o-mini": "Efficient GPT-4 variant",
|
|
290
|
+
"gpt-4-turbo": "Enhanced GPT-4 with larger context",
|
|
291
|
+
"gemini-1.5-pro": "Advanced Gemini with large context",
|
|
292
|
+
"gemini-1.5-flash": "Fast Gemini variant",
|
|
293
|
+
"sonar-pro": "Advanced search-enabled model",
|
|
294
|
+
"grok-3": "Latest Grok model",
|
|
295
|
+
"mistral-small-3.1": "Efficient Mistral model",
|
|
296
|
+
"command-r": "Cohere's reasoning model",
|
|
297
|
+
"llama3.2": "Meta's latest Llama model",
|
|
298
|
+
# Bedrock specific models
|
|
299
|
+
"anthropic.claude-3-sonnet-20240229-v1:0": "Claude 3 Sonnet on Bedrock",
|
|
300
|
+
"anthropic.claude-3-haiku-20240307-v1:0": "Claude 3 Haiku on Bedrock",
|
|
301
|
+
"meta.llama3-1-8b-instruct-v1:0": "Llama 3.1 8B on Bedrock",
|
|
302
|
+
"arn:aws:bedrock:us-west-2::foundation-model/meta.llama4-maverick-17b-instruct-v1:0": "Meta Llama 4 Maverick (ARN)",
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
for i, model in enumerate(models, 1):
|
|
306
|
+
description = model_descriptions.get(model, "High-quality AI model")
|
|
307
|
+
table.add_row(str(i), model, description)
|
|
308
|
+
|
|
309
|
+
# Add custom option for non-Bedrock providers
|
|
310
|
+
if provider_name != "bedrock":
|
|
311
|
+
table.add_row(str(len(models) + 1), "[Custom]", "Enter custom model name")
|
|
312
|
+
|
|
313
|
+
self.console.print(table)
|
|
314
|
+
|
|
315
|
+
# Get user selection
|
|
316
|
+
while True:
|
|
317
|
+
try:
|
|
318
|
+
max_choice = len(models) + (1 if provider_name != "bedrock" else 0)
|
|
319
|
+
choice = Prompt.ask(
|
|
320
|
+
"Select a model",
|
|
321
|
+
choices=[str(i) for i in range(1, max_choice + 1)],
|
|
322
|
+
default="1",
|
|
323
|
+
)
|
|
324
|
+
|
|
325
|
+
choice_num = int(choice)
|
|
326
|
+
|
|
327
|
+
# Handle custom option for non-Bedrock providers
|
|
328
|
+
if provider_name != "bedrock" and choice_num == len(models) + 1:
|
|
329
|
+
custom_model = Prompt.ask("Enter custom model name")
|
|
330
|
+
if custom_model:
|
|
331
|
+
return custom_model
|
|
332
|
+
else:
|
|
333
|
+
continue
|
|
334
|
+
|
|
335
|
+
model_index = choice_num - 1
|
|
336
|
+
return models[model_index]
|
|
337
|
+
|
|
338
|
+
except (ValueError, IndexError):
|
|
339
|
+
self.console.print("[red]Invalid selection. Please try again.[/red]")
|
|
340
|
+
|
|
341
|
+
def _get_additional_settings(self, provider_name: str) -> Dict[str, Any]:
|
|
342
|
+
"""
|
|
343
|
+
Get additional provider-specific settings.
|
|
344
|
+
|
|
345
|
+
Args:
|
|
346
|
+
provider_name: Name of the provider
|
|
347
|
+
|
|
348
|
+
Returns:
|
|
349
|
+
Dictionary of additional settings
|
|
350
|
+
"""
|
|
351
|
+
settings = {}
|
|
352
|
+
|
|
353
|
+
# Common settings
|
|
354
|
+
if Confirm.ask("Configure advanced settings?", default=False):
|
|
355
|
+
# Temperature
|
|
356
|
+
temp_str = Prompt.ask("Temperature (0.0-1.0)", default="0.7")
|
|
357
|
+
try:
|
|
358
|
+
settings["temperature"] = float(temp_str)
|
|
359
|
+
except ValueError:
|
|
360
|
+
settings["temperature"] = 0.7
|
|
361
|
+
|
|
362
|
+
# Max tokens
|
|
363
|
+
tokens_str = Prompt.ask("Max tokens", default="4096")
|
|
364
|
+
try:
|
|
365
|
+
settings["max_tokens"] = int(tokens_str)
|
|
366
|
+
except ValueError:
|
|
367
|
+
settings["max_tokens"] = 4096
|
|
368
|
+
|
|
369
|
+
# Provider-specific settings
|
|
370
|
+
if provider_name == "ollama":
|
|
371
|
+
base_url = Prompt.ask("Ollama server URL", default="http://localhost:11434")
|
|
372
|
+
settings["base_url"] = base_url
|
|
373
|
+
elif provider_name == "bedrock":
|
|
374
|
+
# AWS region selection is required for Bedrock
|
|
375
|
+
regions = [
|
|
376
|
+
"us-east-1",
|
|
377
|
+
"us-west-2",
|
|
378
|
+
"eu-west-1",
|
|
379
|
+
"eu-central-1",
|
|
380
|
+
"ap-southeast-1",
|
|
381
|
+
"ap-northeast-1",
|
|
382
|
+
"ap-south-1",
|
|
383
|
+
]
|
|
384
|
+
|
|
385
|
+
self.console.print("\n[bold]Available AWS Regions:[/bold]")
|
|
386
|
+
for i, region in enumerate(regions, 1):
|
|
387
|
+
self.console.print(f" {i}. {region}")
|
|
388
|
+
|
|
389
|
+
while True:
|
|
390
|
+
region_choice = Prompt.ask(
|
|
391
|
+
f"Select AWS region [1-{len(regions)}]", default="1"
|
|
392
|
+
)
|
|
393
|
+
try:
|
|
394
|
+
region_idx = int(region_choice) - 1
|
|
395
|
+
if 0 <= region_idx < len(regions):
|
|
396
|
+
settings["aws_region"] = regions[region_idx]
|
|
397
|
+
break
|
|
398
|
+
else:
|
|
399
|
+
self.console.print(
|
|
400
|
+
"[red]Invalid selection. Please try again.[/red]"
|
|
401
|
+
)
|
|
402
|
+
except ValueError:
|
|
403
|
+
self.console.print("[red]Please enter a number.[/red]")
|
|
404
|
+
|
|
405
|
+
return settings
|
|
406
|
+
|
|
407
|
+
def save_configuration(
|
|
408
|
+
self,
|
|
409
|
+
provider_name: str,
|
|
410
|
+
provider_config: ProviderConfig,
|
|
411
|
+
config_manager,
|
|
412
|
+
) -> None:
|
|
413
|
+
"""
|
|
414
|
+
Save the configuration, adding the provider without overwriting existing ones.
|
|
415
|
+
|
|
416
|
+
Args:
|
|
417
|
+
provider_name: Name of the provider
|
|
418
|
+
provider_config: Provider configuration to save
|
|
419
|
+
config_manager: Configuration manager instance
|
|
420
|
+
"""
|
|
421
|
+
try:
|
|
422
|
+
# Check if this is the first provider being configured
|
|
423
|
+
config = config_manager.get_config()
|
|
424
|
+
is_first_provider = not config.providers
|
|
425
|
+
|
|
426
|
+
# Add or update the provider configuration
|
|
427
|
+
config_manager.set_provider_config(provider_name, provider_config)
|
|
428
|
+
|
|
429
|
+
# Set as default provider if it's the first one or if user confirms
|
|
430
|
+
if is_first_provider:
|
|
431
|
+
config_manager.set_default_provider(provider_name)
|
|
432
|
+
self.console.print(
|
|
433
|
+
f"[green]✅ {self.provider_info[provider_name]['name']} set as default provider![/green]"
|
|
434
|
+
)
|
|
435
|
+
else:
|
|
436
|
+
# Ask if user wants to set this as the default provider
|
|
437
|
+
if Confirm.ask(
|
|
438
|
+
f"Set {self.provider_info[provider_name]['name']} as your default provider?",
|
|
439
|
+
default=False,
|
|
440
|
+
):
|
|
441
|
+
config_manager.set_default_provider(provider_name)
|
|
442
|
+
self.console.print(
|
|
443
|
+
f"[green]✅ {self.provider_info[provider_name]['name']} set as default provider![/green]"
|
|
444
|
+
)
|
|
445
|
+
else:
|
|
446
|
+
self.console.print(
|
|
447
|
+
f"[green]✅ {self.provider_info[provider_name]['name']} added to your providers![/green]"
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
self.console.print("[green]✅ Configuration saved successfully![/green]")
|
|
451
|
+
|
|
452
|
+
except Exception as e:
|
|
453
|
+
self.console.print(f"[red]❌ Failed to save configuration: {e}[/red]")
|
|
454
|
+
raise
|