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,944 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Agent Creation Wizard for Omnimancer.
|
|
3
|
+
|
|
4
|
+
Interactive CLI wizard that guides users through creating custom agent
|
|
5
|
+
configurations step-by-step with validation and real-time feedback.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import List, Optional, Set
|
|
10
|
+
|
|
11
|
+
from rich.align import Align
|
|
12
|
+
from rich.box import ROUNDED
|
|
13
|
+
from rich.console import Console
|
|
14
|
+
from rich.panel import Panel
|
|
15
|
+
from rich.prompt import Confirm, FloatPrompt, IntPrompt, Prompt
|
|
16
|
+
from rich.table import Table
|
|
17
|
+
from rich.text import Text
|
|
18
|
+
|
|
19
|
+
from ..core.agent.agent_config import (
|
|
20
|
+
AgentRepository,
|
|
21
|
+
AgentTool,
|
|
22
|
+
BehaviorRules,
|
|
23
|
+
ContextParameters,
|
|
24
|
+
CustomAgentConfig,
|
|
25
|
+
CustomAgentStatus,
|
|
26
|
+
CustomAgentValidator,
|
|
27
|
+
ModelSettings,
|
|
28
|
+
)
|
|
29
|
+
from ..core.agent.config import ProviderType
|
|
30
|
+
from ..core.agent.persona import PersonaCapability, PersonaCategory
|
|
31
|
+
from ..core.models import ConfigTemplateManager
|
|
32
|
+
|
|
33
|
+
logger = logging.getLogger(__name__)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class AgentCreationWizard:
|
|
37
|
+
"""Interactive wizard for creating custom agents."""
|
|
38
|
+
|
|
39
|
+
def __init__(
|
|
40
|
+
self,
|
|
41
|
+
console: Optional[Console] = None,
|
|
42
|
+
template_manager: Optional[ConfigTemplateManager] = None,
|
|
43
|
+
repository: Optional[AgentRepository] = None,
|
|
44
|
+
):
|
|
45
|
+
"""
|
|
46
|
+
Initialize the agent creation wizard.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
console: Rich console for output
|
|
50
|
+
template_manager: Configuration template manager
|
|
51
|
+
repository: Agent repository for storage
|
|
52
|
+
"""
|
|
53
|
+
self.console = console or Console()
|
|
54
|
+
self.template_manager = template_manager or ConfigTemplateManager()
|
|
55
|
+
self.repository = repository or AgentRepository()
|
|
56
|
+
self.validator = CustomAgentValidator()
|
|
57
|
+
|
|
58
|
+
# Wizard state
|
|
59
|
+
self.current_config: Optional[CustomAgentConfig] = None
|
|
60
|
+
self.step_history: List[str] = []
|
|
61
|
+
|
|
62
|
+
async def run_wizard(
|
|
63
|
+
self, base_config: Optional[CustomAgentConfig] = None
|
|
64
|
+
) -> Optional[CustomAgentConfig]:
|
|
65
|
+
"""
|
|
66
|
+
Run the complete agent creation wizard.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
base_config: Optional base configuration to start with
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Created agent configuration or None if cancelled
|
|
73
|
+
"""
|
|
74
|
+
try:
|
|
75
|
+
self._show_welcome()
|
|
76
|
+
|
|
77
|
+
# Initialize with base config or create new
|
|
78
|
+
self.current_config = base_config or CustomAgentConfig()
|
|
79
|
+
|
|
80
|
+
# Run wizard steps
|
|
81
|
+
if not await self._step_basic_info():
|
|
82
|
+
return None
|
|
83
|
+
|
|
84
|
+
if not await self._step_select_template():
|
|
85
|
+
return None
|
|
86
|
+
|
|
87
|
+
if not await self._step_model_settings():
|
|
88
|
+
return None
|
|
89
|
+
|
|
90
|
+
if not await self._step_tools_capabilities():
|
|
91
|
+
return None
|
|
92
|
+
|
|
93
|
+
if not await self._step_context_parameters():
|
|
94
|
+
return None
|
|
95
|
+
|
|
96
|
+
if not await self._step_behavior_rules():
|
|
97
|
+
return None
|
|
98
|
+
|
|
99
|
+
if not await self._step_review_and_save():
|
|
100
|
+
return None
|
|
101
|
+
|
|
102
|
+
return self.current_config
|
|
103
|
+
|
|
104
|
+
except KeyboardInterrupt:
|
|
105
|
+
self.console.print("\\n[yellow]Wizard cancelled by user.[/yellow]")
|
|
106
|
+
return None
|
|
107
|
+
except Exception as e:
|
|
108
|
+
self.console.print(f"\\n[red]Wizard error: {e}[/red]")
|
|
109
|
+
logger.error(f"Agent creation wizard error: {e}", exc_info=True)
|
|
110
|
+
return None
|
|
111
|
+
|
|
112
|
+
def _show_welcome(self):
|
|
113
|
+
"""Show welcome message and instructions."""
|
|
114
|
+
welcome_text = Text.assemble(
|
|
115
|
+
"Welcome to the ",
|
|
116
|
+
("Agent Creation Wizard", "bold cyan"),
|
|
117
|
+
"!\\n\\n",
|
|
118
|
+
"This wizard will guide you through creating a custom agent configuration.\\n",
|
|
119
|
+
"You can press ",
|
|
120
|
+
("Ctrl+C", "bold"),
|
|
121
|
+
" at any time to cancel.\\n\\n",
|
|
122
|
+
"Let's get started! 🚀",
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
panel = Panel(
|
|
126
|
+
Align.center(welcome_text),
|
|
127
|
+
title="🤖 Custom Agent Creator",
|
|
128
|
+
box=ROUNDED,
|
|
129
|
+
padding=(1, 2),
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
self.console.print(panel)
|
|
133
|
+
self.console.print()
|
|
134
|
+
|
|
135
|
+
async def _step_basic_info(self) -> bool:
|
|
136
|
+
"""Step 1: Collect basic agent information."""
|
|
137
|
+
self.console.rule("📝 Step 1: Basic Information")
|
|
138
|
+
|
|
139
|
+
# Agent name
|
|
140
|
+
while True:
|
|
141
|
+
name = Prompt.ask(
|
|
142
|
+
"Enter a name for your agent",
|
|
143
|
+
default=(
|
|
144
|
+
self.current_config.name
|
|
145
|
+
if self.current_config.name != "Untitled Agent"
|
|
146
|
+
else ""
|
|
147
|
+
),
|
|
148
|
+
).strip()
|
|
149
|
+
|
|
150
|
+
if not name:
|
|
151
|
+
self.console.print("[red]Agent name cannot be empty.[/red]")
|
|
152
|
+
continue
|
|
153
|
+
|
|
154
|
+
if len(name) > 100:
|
|
155
|
+
self.console.print(
|
|
156
|
+
"[red]Agent name too long (max 100 characters).[/red]"
|
|
157
|
+
)
|
|
158
|
+
continue
|
|
159
|
+
|
|
160
|
+
# Check for name conflicts
|
|
161
|
+
existing = self.repository.get_by_name(name)
|
|
162
|
+
if existing:
|
|
163
|
+
self.console.print(
|
|
164
|
+
f"[yellow]An agent named '{name}' already exists.[/yellow]"
|
|
165
|
+
)
|
|
166
|
+
if not Confirm.ask(
|
|
167
|
+
"Do you want to use a different name?", default=True
|
|
168
|
+
):
|
|
169
|
+
continue
|
|
170
|
+
|
|
171
|
+
self.current_config.name = name
|
|
172
|
+
break
|
|
173
|
+
|
|
174
|
+
# Description
|
|
175
|
+
description = Prompt.ask(
|
|
176
|
+
"Enter a description for your agent (optional)",
|
|
177
|
+
default=self.current_config.description,
|
|
178
|
+
).strip()
|
|
179
|
+
|
|
180
|
+
if len(description) > 500:
|
|
181
|
+
self.console.print(
|
|
182
|
+
"[yellow]Description truncated to 500 characters.[/yellow]"
|
|
183
|
+
)
|
|
184
|
+
description = description[:500]
|
|
185
|
+
|
|
186
|
+
self.current_config.description = description
|
|
187
|
+
|
|
188
|
+
# Category
|
|
189
|
+
self.console.print("\\nSelect a category for your agent:")
|
|
190
|
+
categories = list(PersonaCategory)
|
|
191
|
+
for i, category in enumerate(categories, 1):
|
|
192
|
+
self.console.print(f" {i}. {category.value.title()}")
|
|
193
|
+
|
|
194
|
+
while True:
|
|
195
|
+
try:
|
|
196
|
+
choice = IntPrompt.ask(
|
|
197
|
+
"Category",
|
|
198
|
+
default=categories.index(self.current_config.category) + 1,
|
|
199
|
+
show_default=True,
|
|
200
|
+
)
|
|
201
|
+
if 1 <= choice <= len(categories):
|
|
202
|
+
self.current_config.category = categories[choice - 1]
|
|
203
|
+
break
|
|
204
|
+
else:
|
|
205
|
+
self.console.print(
|
|
206
|
+
f"[red]Please enter a number between 1 and {len(categories)}.[/red]"
|
|
207
|
+
)
|
|
208
|
+
except (ValueError, EOFError):
|
|
209
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
210
|
+
|
|
211
|
+
self.step_history.append("basic_info")
|
|
212
|
+
return True
|
|
213
|
+
|
|
214
|
+
async def _step_select_template(self) -> bool:
|
|
215
|
+
"""Step 2: Select base template (optional)."""
|
|
216
|
+
self.console.rule("🎯 Step 2: Base Template")
|
|
217
|
+
|
|
218
|
+
self.console.print(
|
|
219
|
+
"You can base your agent on an existing template for easier setup."
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
use_template = Confirm.ask(
|
|
223
|
+
"Would you like to use a base template?", default=False
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
if not use_template:
|
|
227
|
+
self.current_config.base_template_id = None
|
|
228
|
+
self.step_history.append("template_skipped")
|
|
229
|
+
return True
|
|
230
|
+
|
|
231
|
+
# Get available templates
|
|
232
|
+
try:
|
|
233
|
+
templates = self.template_manager.list_templates()
|
|
234
|
+
|
|
235
|
+
if not templates:
|
|
236
|
+
self.console.print(
|
|
237
|
+
"[yellow]No templates available. Continuing without template.[/yellow]"
|
|
238
|
+
)
|
|
239
|
+
self.current_config.base_template_id = None
|
|
240
|
+
self.step_history.append("no_templates")
|
|
241
|
+
return True
|
|
242
|
+
|
|
243
|
+
self.console.print("\\nAvailable templates:")
|
|
244
|
+
for i, template in enumerate(templates, 1):
|
|
245
|
+
description = template.description[:60] + (
|
|
246
|
+
"..." if len(template.description) > 60 else ""
|
|
247
|
+
)
|
|
248
|
+
self.console.print(f" {i}. {template.name} - {description}")
|
|
249
|
+
|
|
250
|
+
while True:
|
|
251
|
+
try:
|
|
252
|
+
choice = IntPrompt.ask(
|
|
253
|
+
"Select template (0 for none)",
|
|
254
|
+
default=0,
|
|
255
|
+
show_default=True,
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
if choice == 0:
|
|
259
|
+
self.current_config.base_template_id = None
|
|
260
|
+
break
|
|
261
|
+
elif 1 <= choice <= len(templates):
|
|
262
|
+
selected_template = templates[choice - 1]
|
|
263
|
+
self.current_config.base_template_id = selected_template.id
|
|
264
|
+
|
|
265
|
+
# Inherit from template
|
|
266
|
+
self.current_config.inherit_from_template(self.template_manager)
|
|
267
|
+
|
|
268
|
+
self.console.print(
|
|
269
|
+
f"[green]Selected template: {selected_template.name}[/green]"
|
|
270
|
+
)
|
|
271
|
+
break
|
|
272
|
+
else:
|
|
273
|
+
self.console.print(
|
|
274
|
+
f"[red]Please enter a number between 0 and {len(templates)}.[/red]"
|
|
275
|
+
)
|
|
276
|
+
except (ValueError, EOFError):
|
|
277
|
+
self.console.print(
|
|
278
|
+
"[red]Invalid input. Please enter a number.[/red]"
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
except Exception as e:
|
|
282
|
+
self.console.print(f"[red]Error loading templates: {e}[/red]")
|
|
283
|
+
self.current_config.base_template_id = None
|
|
284
|
+
|
|
285
|
+
self.step_history.append("template_selected")
|
|
286
|
+
return True
|
|
287
|
+
|
|
288
|
+
async def _step_model_settings(self) -> bool:
|
|
289
|
+
"""Step 3: Configure model settings."""
|
|
290
|
+
self.console.rule("🧠 Step 3: Model Configuration")
|
|
291
|
+
|
|
292
|
+
current_settings = self.current_config.model_settings
|
|
293
|
+
|
|
294
|
+
# Provider selection
|
|
295
|
+
self.console.print("\\nSelect AI provider:")
|
|
296
|
+
providers = list(ProviderType)
|
|
297
|
+
for i, provider in enumerate(providers, 1):
|
|
298
|
+
self.console.print(f" {i}. {provider.value}")
|
|
299
|
+
|
|
300
|
+
while True:
|
|
301
|
+
try:
|
|
302
|
+
choice = IntPrompt.ask(
|
|
303
|
+
"Provider",
|
|
304
|
+
default=providers.index(current_settings.provider_type) + 1,
|
|
305
|
+
show_default=True,
|
|
306
|
+
)
|
|
307
|
+
if 1 <= choice <= len(providers):
|
|
308
|
+
provider_type = providers[choice - 1]
|
|
309
|
+
break
|
|
310
|
+
else:
|
|
311
|
+
self.console.print(
|
|
312
|
+
f"[red]Please enter a number between 1 and {len(providers)}.[/red]"
|
|
313
|
+
)
|
|
314
|
+
except (ValueError, EOFError):
|
|
315
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
316
|
+
|
|
317
|
+
# Model name
|
|
318
|
+
model_suggestions = self._get_model_suggestions(provider_type)
|
|
319
|
+
if model_suggestions:
|
|
320
|
+
self.console.print(f"\\nSuggested models for {provider_type.value}:")
|
|
321
|
+
for suggestion in model_suggestions[:5]: # Show top 5
|
|
322
|
+
self.console.print(f" • {suggestion}")
|
|
323
|
+
|
|
324
|
+
model_name = Prompt.ask(
|
|
325
|
+
"Model name", default=current_settings.model_name
|
|
326
|
+
).strip()
|
|
327
|
+
|
|
328
|
+
if not model_name:
|
|
329
|
+
model_name = self._get_default_model(provider_type)
|
|
330
|
+
self.console.print(f"[yellow]Using default model: {model_name}[/yellow]")
|
|
331
|
+
|
|
332
|
+
# Temperature
|
|
333
|
+
while True:
|
|
334
|
+
try:
|
|
335
|
+
temperature = FloatPrompt.ask(
|
|
336
|
+
"Temperature (0.0 = deterministic, 2.0 = very creative)",
|
|
337
|
+
default=current_settings.temperature,
|
|
338
|
+
show_default=True,
|
|
339
|
+
)
|
|
340
|
+
if 0.0 <= temperature <= 2.0:
|
|
341
|
+
break
|
|
342
|
+
else:
|
|
343
|
+
self.console.print(
|
|
344
|
+
"[red]Temperature must be between 0.0 and 2.0.[/red]"
|
|
345
|
+
)
|
|
346
|
+
except (ValueError, EOFError):
|
|
347
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
348
|
+
|
|
349
|
+
# Max tokens (optional)
|
|
350
|
+
max_tokens = None
|
|
351
|
+
if Confirm.ask("Set maximum response length?", default=False):
|
|
352
|
+
while True:
|
|
353
|
+
try:
|
|
354
|
+
max_tokens = IntPrompt.ask(
|
|
355
|
+
"Maximum tokens",
|
|
356
|
+
default=current_settings.max_tokens or 4096,
|
|
357
|
+
show_default=True,
|
|
358
|
+
)
|
|
359
|
+
if max_tokens > 0:
|
|
360
|
+
break
|
|
361
|
+
else:
|
|
362
|
+
self.console.print(
|
|
363
|
+
"[red]Maximum tokens must be positive.[/red]"
|
|
364
|
+
)
|
|
365
|
+
except (ValueError, EOFError):
|
|
366
|
+
self.console.print(
|
|
367
|
+
"[red]Invalid input. Please enter a number.[/red]"
|
|
368
|
+
)
|
|
369
|
+
|
|
370
|
+
# Update model settings
|
|
371
|
+
self.current_config.model_settings = ModelSettings(
|
|
372
|
+
provider_type=provider_type,
|
|
373
|
+
model_name=model_name,
|
|
374
|
+
temperature=temperature,
|
|
375
|
+
max_tokens=max_tokens,
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
self.step_history.append("model_configured")
|
|
379
|
+
return True
|
|
380
|
+
|
|
381
|
+
async def _step_tools_capabilities(self) -> bool:
|
|
382
|
+
"""Step 4: Select tools and capabilities."""
|
|
383
|
+
self.console.rule("🔧 Step 4: Tools and Capabilities")
|
|
384
|
+
|
|
385
|
+
# Tools selection
|
|
386
|
+
self.console.print("\\nSelect tools to enable for your agent:")
|
|
387
|
+
all_tools = list(AgentTool)
|
|
388
|
+
current_tools = self.current_config.enabled_tools
|
|
389
|
+
|
|
390
|
+
tool_table = Table(show_header=True, header_style="bold magenta")
|
|
391
|
+
tool_table.add_column("Tool", style="cyan")
|
|
392
|
+
tool_table.add_column("Description", style="white")
|
|
393
|
+
tool_table.add_column("Enabled", style="green")
|
|
394
|
+
|
|
395
|
+
tool_descriptions = {
|
|
396
|
+
AgentTool.FILE_OPERATIONS: "Read, write, and manage files",
|
|
397
|
+
AgentTool.PROGRAM_EXECUTOR: "Execute system commands and programs",
|
|
398
|
+
AgentTool.WEB_CLIENT: "Make web requests and browse content",
|
|
399
|
+
AgentTool.MCP_TOOLS: "Model Context Protocol integration",
|
|
400
|
+
AgentTool.SEARCH: "Search capabilities and information retrieval",
|
|
401
|
+
AgentTool.CODE_ANALYSIS: "Analyze and understand code structure",
|
|
402
|
+
AgentTool.SYSTEM_INFO: "Access system information and diagnostics",
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
for tool in all_tools:
|
|
406
|
+
description = tool_descriptions.get(tool, "Advanced tool functionality")
|
|
407
|
+
enabled = "✅" if tool in current_tools else "❌"
|
|
408
|
+
tool_table.add_row(
|
|
409
|
+
tool.value.replace("_", " ").title(), description, enabled
|
|
410
|
+
)
|
|
411
|
+
|
|
412
|
+
self.console.print(tool_table)
|
|
413
|
+
|
|
414
|
+
# Interactive tool selection
|
|
415
|
+
selected_tools = set(current_tools)
|
|
416
|
+
|
|
417
|
+
while True:
|
|
418
|
+
self.console.print("\\nTool selection:")
|
|
419
|
+
self.console.print("1. Toggle individual tools")
|
|
420
|
+
self.console.print("2. Select preset configuration")
|
|
421
|
+
self.console.print("3. Continue with current selection")
|
|
422
|
+
|
|
423
|
+
choice = Prompt.ask("Choose option", choices=["1", "2", "3"], default="3")
|
|
424
|
+
|
|
425
|
+
if choice == "1":
|
|
426
|
+
selected_tools = await self._interactive_tool_selection(
|
|
427
|
+
all_tools, selected_tools
|
|
428
|
+
)
|
|
429
|
+
elif choice == "2":
|
|
430
|
+
selected_tools = await self._preset_tool_selection()
|
|
431
|
+
else:
|
|
432
|
+
break
|
|
433
|
+
|
|
434
|
+
self.current_config.enabled_tools = selected_tools
|
|
435
|
+
|
|
436
|
+
# Capabilities selection
|
|
437
|
+
self.console.print("\\nSelect capabilities for your agent:")
|
|
438
|
+
all_capabilities = list(PersonaCapability)
|
|
439
|
+
current_capabilities = self.current_config.capabilities
|
|
440
|
+
|
|
441
|
+
# Smart capability suggestions based on selected tools
|
|
442
|
+
suggested_capabilities = self._suggest_capabilities_for_tools(selected_tools)
|
|
443
|
+
|
|
444
|
+
if suggested_capabilities:
|
|
445
|
+
self.console.print(
|
|
446
|
+
"\\n[cyan]Suggested capabilities based on selected tools:[/cyan]"
|
|
447
|
+
)
|
|
448
|
+
for cap in suggested_capabilities:
|
|
449
|
+
self.console.print(f" • {cap.value.replace('_', ' ').title()}")
|
|
450
|
+
|
|
451
|
+
if Confirm.ask("Use suggested capabilities?", default=True):
|
|
452
|
+
self.current_config.capabilities = suggested_capabilities
|
|
453
|
+
else:
|
|
454
|
+
self.current_config.capabilities = (
|
|
455
|
+
await self._interactive_capability_selection(
|
|
456
|
+
all_capabilities, current_capabilities
|
|
457
|
+
)
|
|
458
|
+
)
|
|
459
|
+
else:
|
|
460
|
+
self.current_config.capabilities = (
|
|
461
|
+
await self._interactive_capability_selection(
|
|
462
|
+
all_capabilities, current_capabilities
|
|
463
|
+
)
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
self.step_history.append("tools_capabilities_configured")
|
|
467
|
+
return True
|
|
468
|
+
|
|
469
|
+
async def _step_context_parameters(self) -> bool:
|
|
470
|
+
"""Step 5: Configure context and behavior parameters."""
|
|
471
|
+
self.console.rule("💭 Step 5: Context Configuration")
|
|
472
|
+
|
|
473
|
+
current_params = self.current_config.context_parameters
|
|
474
|
+
|
|
475
|
+
# System prompt
|
|
476
|
+
self.console.print("\\nConfigure the system prompt for your agent:")
|
|
477
|
+
self.console.print("This defines the agent's personality and behavior.")
|
|
478
|
+
|
|
479
|
+
current_prompt = current_params.system_prompt
|
|
480
|
+
if current_prompt:
|
|
481
|
+
self.console.print(f"\\nCurrent prompt preview:")
|
|
482
|
+
preview = current_prompt[:200] + (
|
|
483
|
+
"..." if len(current_prompt) > 200 else ""
|
|
484
|
+
)
|
|
485
|
+
self.console.print(Panel(preview, box=ROUNDED))
|
|
486
|
+
|
|
487
|
+
if Confirm.ask("Edit system prompt?", default=bool(current_prompt)):
|
|
488
|
+
# For simplicity, use basic input. In a full implementation,
|
|
489
|
+
# this could open an editor or provide multi-line input
|
|
490
|
+
system_prompt = Prompt.ask("System prompt", default=current_prompt).strip()
|
|
491
|
+
else:
|
|
492
|
+
system_prompt = current_prompt
|
|
493
|
+
|
|
494
|
+
# Context window size
|
|
495
|
+
context_size = IntPrompt.ask(
|
|
496
|
+
"Context window size (tokens)",
|
|
497
|
+
default=current_params.context_window_size,
|
|
498
|
+
show_default=True,
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
if context_size < 1000:
|
|
502
|
+
self.console.print(
|
|
503
|
+
"[yellow]Warning: Very small context window may limit functionality.[/yellow]"
|
|
504
|
+
)
|
|
505
|
+
|
|
506
|
+
# Memory settings
|
|
507
|
+
conversation_memory = Confirm.ask(
|
|
508
|
+
"Enable conversation memory?",
|
|
509
|
+
default=current_params.conversation_memory,
|
|
510
|
+
)
|
|
511
|
+
|
|
512
|
+
memory_limit = current_params.memory_limit
|
|
513
|
+
if conversation_memory:
|
|
514
|
+
memory_limit = IntPrompt.ask(
|
|
515
|
+
"Memory limit (number of messages to remember)",
|
|
516
|
+
default=current_params.memory_limit,
|
|
517
|
+
show_default=True,
|
|
518
|
+
)
|
|
519
|
+
|
|
520
|
+
# Response format
|
|
521
|
+
self.console.print("\\nResponse format options:")
|
|
522
|
+
self.console.print("1. Default - Natural conversational responses")
|
|
523
|
+
self.console.print("2. JSON - Structured JSON responses")
|
|
524
|
+
self.console.print("3. Markdown - Markdown-formatted responses")
|
|
525
|
+
|
|
526
|
+
format_choices = ["default", "json", "markdown"]
|
|
527
|
+
format_choice = Prompt.ask(
|
|
528
|
+
"Response format", choices=["1", "2", "3"], default="1"
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
response_format = format_choices[int(format_choice) - 1]
|
|
532
|
+
|
|
533
|
+
# Update context parameters
|
|
534
|
+
self.current_config.context_parameters = ContextParameters(
|
|
535
|
+
system_prompt=system_prompt,
|
|
536
|
+
context_window_size=context_size,
|
|
537
|
+
conversation_memory=conversation_memory,
|
|
538
|
+
memory_limit=memory_limit,
|
|
539
|
+
response_format=response_format,
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
self.step_history.append("context_configured")
|
|
543
|
+
return True
|
|
544
|
+
|
|
545
|
+
async def _step_behavior_rules(self) -> bool:
|
|
546
|
+
"""Step 6: Configure behavior rules and constraints."""
|
|
547
|
+
self.console.rule("⚙️ Step 6: Behavior Rules")
|
|
548
|
+
|
|
549
|
+
current_rules = self.current_config.behavior_rules
|
|
550
|
+
|
|
551
|
+
# Safety level
|
|
552
|
+
self.console.print("\\nSelect safety level:")
|
|
553
|
+
self.console.print("1. Strict - Maximum safety, conservative behavior")
|
|
554
|
+
self.console.print("2. Standard - Balanced safety and functionality")
|
|
555
|
+
self.console.print("3. Permissive - Minimal restrictions, maximum freedom")
|
|
556
|
+
|
|
557
|
+
safety_levels = ["strict", "standard", "permissive"]
|
|
558
|
+
safety_choice = Prompt.ask("Safety level", choices=["1", "2", "3"], default="2")
|
|
559
|
+
safety_level = safety_levels[int(safety_choice) - 1]
|
|
560
|
+
|
|
561
|
+
# Reasoning style
|
|
562
|
+
self.console.print("\\nSelect reasoning style:")
|
|
563
|
+
self.console.print("1. Concise - Brief, to-the-point responses")
|
|
564
|
+
self.console.print("2. Balanced - Moderate detail level")
|
|
565
|
+
self.console.print("3. Verbose - Detailed explanations")
|
|
566
|
+
self.console.print("4. Step-by-step - Explicit reasoning process")
|
|
567
|
+
|
|
568
|
+
reasoning_styles = ["concise", "balanced", "verbose", "step_by_step"]
|
|
569
|
+
reasoning_choice = Prompt.ask(
|
|
570
|
+
"Reasoning style", choices=["1", "2", "3", "4"], default="2"
|
|
571
|
+
)
|
|
572
|
+
reasoning_style = reasoning_styles[int(reasoning_choice) - 1]
|
|
573
|
+
|
|
574
|
+
# Creativity level
|
|
575
|
+
self.console.print("\\nSelect creativity level:")
|
|
576
|
+
self.console.print("1. Low - Conservative, predictable responses")
|
|
577
|
+
self.console.print("2. Medium - Balanced creativity")
|
|
578
|
+
self.console.print("3. High - Creative, exploratory responses")
|
|
579
|
+
|
|
580
|
+
creativity_levels = ["low", "medium", "high"]
|
|
581
|
+
creativity_choice = Prompt.ask(
|
|
582
|
+
"Creativity level", choices=["1", "2", "3"], default="2"
|
|
583
|
+
)
|
|
584
|
+
creativity_level = creativity_levels[int(creativity_choice) - 1]
|
|
585
|
+
|
|
586
|
+
# Confirmation requirements
|
|
587
|
+
require_confirmation = []
|
|
588
|
+
|
|
589
|
+
self.console.print("\\nConfigure operations that require user confirmation:")
|
|
590
|
+
confirmation_options = [
|
|
591
|
+
("file_delete", "File deletion operations"),
|
|
592
|
+
("system_commands", "System command execution"),
|
|
593
|
+
("web_requests", "External web requests"),
|
|
594
|
+
("code_execution", "Code execution"),
|
|
595
|
+
("data_modification", "Data modification operations"),
|
|
596
|
+
]
|
|
597
|
+
|
|
598
|
+
for option, description in confirmation_options:
|
|
599
|
+
if Confirm.ask(
|
|
600
|
+
f"Require confirmation for {description}?",
|
|
601
|
+
default=option in current_rules.require_confirmation_for,
|
|
602
|
+
):
|
|
603
|
+
require_confirmation.append(option)
|
|
604
|
+
|
|
605
|
+
# Update behavior rules
|
|
606
|
+
self.current_config.behavior_rules = BehaviorRules(
|
|
607
|
+
require_confirmation_for=require_confirmation,
|
|
608
|
+
reasoning_style=reasoning_style,
|
|
609
|
+
creativity_level=creativity_level,
|
|
610
|
+
safety_level=safety_level,
|
|
611
|
+
custom_restrictions=current_rules.custom_restrictions, # Keep existing custom restrictions
|
|
612
|
+
)
|
|
613
|
+
|
|
614
|
+
self.step_history.append("behavior_configured")
|
|
615
|
+
return True
|
|
616
|
+
|
|
617
|
+
async def _step_review_and_save(self) -> bool:
|
|
618
|
+
"""Step 7: Review configuration and save."""
|
|
619
|
+
self.console.rule("📋 Step 7: Review and Save")
|
|
620
|
+
|
|
621
|
+
# Show configuration summary
|
|
622
|
+
self._show_configuration_summary()
|
|
623
|
+
|
|
624
|
+
# Validation
|
|
625
|
+
try:
|
|
626
|
+
self.validator.validate_config(self.current_config)
|
|
627
|
+
self.console.print("[green]✅ Configuration is valid![/green]")
|
|
628
|
+
except ValueError as e:
|
|
629
|
+
self.console.print(f"[red]❌ Configuration validation failed: {e}[/red]")
|
|
630
|
+
if not Confirm.ask("Continue anyway?", default=False):
|
|
631
|
+
return False
|
|
632
|
+
|
|
633
|
+
# Final confirmation
|
|
634
|
+
if not Confirm.ask("\\nSave this agent configuration?", default=True):
|
|
635
|
+
return False
|
|
636
|
+
|
|
637
|
+
# Save the configuration
|
|
638
|
+
try:
|
|
639
|
+
self.current_config.status = CustomAgentStatus.ACTIVE
|
|
640
|
+
saved_config = self.repository.create(self.current_config)
|
|
641
|
+
|
|
642
|
+
self.console.print(
|
|
643
|
+
f"\\n[green]✅ Agent '{saved_config.name}' created successfully![/green]"
|
|
644
|
+
)
|
|
645
|
+
self.console.print(f"[cyan]Agent ID: {saved_config.id}[/cyan]")
|
|
646
|
+
|
|
647
|
+
return True
|
|
648
|
+
|
|
649
|
+
except Exception as e:
|
|
650
|
+
self.console.print(f"[red]❌ Failed to save agent: {e}[/red]")
|
|
651
|
+
return False
|
|
652
|
+
|
|
653
|
+
def _show_configuration_summary(self):
|
|
654
|
+
"""Display a summary of the current configuration."""
|
|
655
|
+
config = self.current_config
|
|
656
|
+
|
|
657
|
+
# Basic info
|
|
658
|
+
basic_table = Table(show_header=False, box=None)
|
|
659
|
+
basic_table.add_column("Field", style="cyan")
|
|
660
|
+
basic_table.add_column("Value", style="white")
|
|
661
|
+
|
|
662
|
+
basic_table.add_row("Name", config.name)
|
|
663
|
+
basic_table.add_row("Description", config.description or "[dim]None[/dim]")
|
|
664
|
+
basic_table.add_row("Category", config.category.value.title())
|
|
665
|
+
basic_table.add_row(
|
|
666
|
+
"Base Template", config.base_template_id or "[dim]None[/dim]"
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
self.console.print(Panel(basic_table, title="Basic Information", box=ROUNDED))
|
|
670
|
+
|
|
671
|
+
# Model settings
|
|
672
|
+
model_table = Table(show_header=False, box=None)
|
|
673
|
+
model_table.add_column("Field", style="cyan")
|
|
674
|
+
model_table.add_column("Value", style="white")
|
|
675
|
+
|
|
676
|
+
model_table.add_row("Provider", config.model_settings.provider_type.value)
|
|
677
|
+
model_table.add_row("Model", config.model_settings.model_name)
|
|
678
|
+
model_table.add_row("Temperature", str(config.model_settings.temperature))
|
|
679
|
+
model_table.add_row(
|
|
680
|
+
"Max Tokens",
|
|
681
|
+
(
|
|
682
|
+
str(config.model_settings.max_tokens)
|
|
683
|
+
if config.model_settings.max_tokens
|
|
684
|
+
else "[dim]Unlimited[/dim]"
|
|
685
|
+
),
|
|
686
|
+
)
|
|
687
|
+
|
|
688
|
+
self.console.print(Panel(model_table, title="Model Configuration", box=ROUNDED))
|
|
689
|
+
|
|
690
|
+
# Tools and capabilities
|
|
691
|
+
tools_text = ", ".join(
|
|
692
|
+
[tool.value.replace("_", " ").title() for tool in config.enabled_tools]
|
|
693
|
+
)
|
|
694
|
+
caps_text = ", ".join(
|
|
695
|
+
[cap.value.replace("_", " ").title() for cap in config.capabilities]
|
|
696
|
+
)
|
|
697
|
+
|
|
698
|
+
tools_table = Table(show_header=False, box=None)
|
|
699
|
+
tools_table.add_column("Field", style="cyan")
|
|
700
|
+
tools_table.add_column("Value", style="white")
|
|
701
|
+
|
|
702
|
+
tools_table.add_row("Tools", tools_text or "[dim]None[/dim]")
|
|
703
|
+
tools_table.add_row("Capabilities", caps_text or "[dim]None[/dim]")
|
|
704
|
+
|
|
705
|
+
self.console.print(
|
|
706
|
+
Panel(tools_table, title="Tools and Capabilities", box=ROUNDED)
|
|
707
|
+
)
|
|
708
|
+
|
|
709
|
+
async def _interactive_tool_selection(
|
|
710
|
+
self, all_tools: List[AgentTool], current_selection: Set[AgentTool]
|
|
711
|
+
) -> Set[AgentTool]:
|
|
712
|
+
"""Interactive tool selection interface."""
|
|
713
|
+
selected = set(current_selection)
|
|
714
|
+
|
|
715
|
+
while True:
|
|
716
|
+
self.console.print("\\nCurrent tool selection:")
|
|
717
|
+
for i, tool in enumerate(all_tools, 1):
|
|
718
|
+
status = "✅" if tool in selected else "❌"
|
|
719
|
+
self.console.print(
|
|
720
|
+
f" {i}. {status} {tool.value.replace('_', ' ').title()}"
|
|
721
|
+
)
|
|
722
|
+
|
|
723
|
+
self.console.print(f"\\n {len(all_tools) + 1}. Done")
|
|
724
|
+
|
|
725
|
+
try:
|
|
726
|
+
choice = IntPrompt.ask(
|
|
727
|
+
"Toggle tool (enter number)",
|
|
728
|
+
default=len(all_tools) + 1,
|
|
729
|
+
show_default=False,
|
|
730
|
+
)
|
|
731
|
+
|
|
732
|
+
if choice == len(all_tools) + 1:
|
|
733
|
+
break
|
|
734
|
+
elif 1 <= choice <= len(all_tools):
|
|
735
|
+
tool = all_tools[choice - 1]
|
|
736
|
+
if tool in selected:
|
|
737
|
+
selected.remove(tool)
|
|
738
|
+
else:
|
|
739
|
+
selected.add(tool)
|
|
740
|
+
else:
|
|
741
|
+
self.console.print(
|
|
742
|
+
f"[red]Please enter a number between 1 and {len(all_tools) + 1}.[/red]"
|
|
743
|
+
)
|
|
744
|
+
except (ValueError, EOFError):
|
|
745
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
746
|
+
|
|
747
|
+
return selected
|
|
748
|
+
|
|
749
|
+
async def _preset_tool_selection(self) -> Set[AgentTool]:
|
|
750
|
+
"""Tool selection from presets."""
|
|
751
|
+
presets = {
|
|
752
|
+
"minimal": {AgentTool.FILE_OPERATIONS},
|
|
753
|
+
"standard": {
|
|
754
|
+
AgentTool.FILE_OPERATIONS,
|
|
755
|
+
AgentTool.PROGRAM_EXECUTOR,
|
|
756
|
+
AgentTool.SYSTEM_INFO,
|
|
757
|
+
},
|
|
758
|
+
"web_enabled": {
|
|
759
|
+
AgentTool.FILE_OPERATIONS,
|
|
760
|
+
AgentTool.PROGRAM_EXECUTOR,
|
|
761
|
+
AgentTool.WEB_CLIENT,
|
|
762
|
+
AgentTool.SEARCH,
|
|
763
|
+
},
|
|
764
|
+
"full_featured": set(AgentTool),
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
self.console.print("\\nTool presets:")
|
|
768
|
+
preset_names = list(presets.keys())
|
|
769
|
+
for i, name in enumerate(preset_names, 1):
|
|
770
|
+
tool_list = ", ".join(
|
|
771
|
+
[t.value.replace("_", " ").title() for t in presets[name]]
|
|
772
|
+
)
|
|
773
|
+
self.console.print(f" {i}. {name.title()}: {tool_list}")
|
|
774
|
+
|
|
775
|
+
while True:
|
|
776
|
+
try:
|
|
777
|
+
choice = IntPrompt.ask(
|
|
778
|
+
"Select preset", default=2, show_default=True # Standard
|
|
779
|
+
)
|
|
780
|
+
if 1 <= choice <= len(preset_names):
|
|
781
|
+
return presets[preset_names[choice - 1]]
|
|
782
|
+
else:
|
|
783
|
+
self.console.print(
|
|
784
|
+
f"[red]Please enter a number between 1 and {len(preset_names)}.[/red]"
|
|
785
|
+
)
|
|
786
|
+
except (ValueError, EOFError):
|
|
787
|
+
self.console.print("[red]Invalid input. Please enter a number.[/red]")
|
|
788
|
+
|
|
789
|
+
async def _interactive_capability_selection(
|
|
790
|
+
self,
|
|
791
|
+
all_capabilities: List[PersonaCapability],
|
|
792
|
+
current_selection: Set[PersonaCapability],
|
|
793
|
+
) -> Set[PersonaCapability]:
|
|
794
|
+
"""Interactive capability selection interface."""
|
|
795
|
+
# Group capabilities for easier selection
|
|
796
|
+
capability_groups = {
|
|
797
|
+
"Core": [
|
|
798
|
+
PersonaCapability.GENERAL_PURPOSE,
|
|
799
|
+
PersonaCapability.REASONING,
|
|
800
|
+
PersonaCapability.ANALYSIS,
|
|
801
|
+
],
|
|
802
|
+
"Development": [
|
|
803
|
+
PersonaCapability.CODE_GENERATION,
|
|
804
|
+
PersonaCapability.FILE_OPERATIONS,
|
|
805
|
+
PersonaCapability.TOOL_CALLING,
|
|
806
|
+
],
|
|
807
|
+
"Research": [
|
|
808
|
+
PersonaCapability.RESEARCH,
|
|
809
|
+
PersonaCapability.WEB_SEARCH,
|
|
810
|
+
PersonaCapability.LARGE_CONTEXT,
|
|
811
|
+
],
|
|
812
|
+
"Creative": [
|
|
813
|
+
PersonaCapability.CREATIVE_WRITING,
|
|
814
|
+
PersonaCapability.HIGH_TEMPERATURE,
|
|
815
|
+
],
|
|
816
|
+
"Performance": [
|
|
817
|
+
PersonaCapability.FAST_RESPONSE,
|
|
818
|
+
PersonaCapability.COST_EFFICIENT,
|
|
819
|
+
PersonaCapability.BALANCED,
|
|
820
|
+
],
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
selected = set(current_selection)
|
|
824
|
+
|
|
825
|
+
# Show grouped capabilities
|
|
826
|
+
for group_name, group_caps in capability_groups.items():
|
|
827
|
+
self.console.print(f"\\n[bold]{group_name} Capabilities:[/bold]")
|
|
828
|
+
for cap in group_caps:
|
|
829
|
+
if cap in all_capabilities:
|
|
830
|
+
status = "✅" if cap in selected else "❌"
|
|
831
|
+
self.console.print(
|
|
832
|
+
f" {status} {cap.value.replace('_', ' ').title()}"
|
|
833
|
+
)
|
|
834
|
+
|
|
835
|
+
# Simple yes/no for each group
|
|
836
|
+
for group_name, group_caps in capability_groups.items():
|
|
837
|
+
available_caps = [cap for cap in group_caps if cap in all_capabilities]
|
|
838
|
+
if not available_caps:
|
|
839
|
+
continue
|
|
840
|
+
|
|
841
|
+
current_count = len([cap for cap in available_caps if cap in selected])
|
|
842
|
+
|
|
843
|
+
if Confirm.ask(
|
|
844
|
+
f"\\nEnable {group_name.lower()} capabilities? (currently {current_count}/{len(available_caps)})",
|
|
845
|
+
default=current_count > 0,
|
|
846
|
+
):
|
|
847
|
+
selected.update(available_caps)
|
|
848
|
+
else:
|
|
849
|
+
selected.difference_update(available_caps)
|
|
850
|
+
|
|
851
|
+
return selected
|
|
852
|
+
|
|
853
|
+
def _suggest_capabilities_for_tools(
|
|
854
|
+
self, tools: Set[AgentTool]
|
|
855
|
+
) -> Set[PersonaCapability]:
|
|
856
|
+
"""Suggest capabilities based on selected tools."""
|
|
857
|
+
suggestions = {PersonaCapability.GENERAL_PURPOSE}
|
|
858
|
+
|
|
859
|
+
if AgentTool.FILE_OPERATIONS in tools:
|
|
860
|
+
suggestions.add(PersonaCapability.FILE_OPERATIONS)
|
|
861
|
+
suggestions.add(PersonaCapability.CODE_GENERATION)
|
|
862
|
+
|
|
863
|
+
if AgentTool.WEB_CLIENT in tools or AgentTool.SEARCH in tools:
|
|
864
|
+
suggestions.add(PersonaCapability.WEB_SEARCH)
|
|
865
|
+
suggestions.add(PersonaCapability.RESEARCH)
|
|
866
|
+
|
|
867
|
+
if AgentTool.PROGRAM_EXECUTOR in tools:
|
|
868
|
+
suggestions.add(PersonaCapability.TOOL_CALLING)
|
|
869
|
+
|
|
870
|
+
if AgentTool.CODE_ANALYSIS in tools:
|
|
871
|
+
suggestions.add(PersonaCapability.ANALYSIS)
|
|
872
|
+
suggestions.add(PersonaCapability.REASONING)
|
|
873
|
+
|
|
874
|
+
return suggestions
|
|
875
|
+
|
|
876
|
+
def _get_model_suggestions(self, provider_type: ProviderType) -> List[str]:
|
|
877
|
+
"""Get model suggestions for a provider."""
|
|
878
|
+
suggestions = {
|
|
879
|
+
ProviderType.ANTHROPIC: [
|
|
880
|
+
"claude-3-opus-20240229",
|
|
881
|
+
"claude-3-sonnet-20240229",
|
|
882
|
+
"claude-3-haiku-20240307",
|
|
883
|
+
],
|
|
884
|
+
ProviderType.OPENAI: [
|
|
885
|
+
"gpt-4",
|
|
886
|
+
"gpt-4-turbo",
|
|
887
|
+
"gpt-3.5-turbo",
|
|
888
|
+
"gpt-4o",
|
|
889
|
+
],
|
|
890
|
+
ProviderType.GOOGLE: [
|
|
891
|
+
"gemini-pro",
|
|
892
|
+
"gemini-pro-vision",
|
|
893
|
+
"gemini-1.5-pro",
|
|
894
|
+
],
|
|
895
|
+
ProviderType.MISTRAL: [
|
|
896
|
+
"mistral-large",
|
|
897
|
+
"mistral-medium",
|
|
898
|
+
"mistral-small",
|
|
899
|
+
],
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
return suggestions.get(provider_type, [])
|
|
903
|
+
|
|
904
|
+
def _get_default_model(self, provider_type: ProviderType) -> str:
|
|
905
|
+
"""Get default model for a provider."""
|
|
906
|
+
defaults = {
|
|
907
|
+
ProviderType.ANTHROPIC: "claude-3-haiku-20240307",
|
|
908
|
+
ProviderType.OPENAI: "gpt-3.5-turbo",
|
|
909
|
+
ProviderType.GOOGLE: "gemini-pro",
|
|
910
|
+
ProviderType.MISTRAL: "mistral-medium",
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
return defaults.get(provider_type, "default-model")
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
# Utility functions for easy integration
|
|
917
|
+
|
|
918
|
+
|
|
919
|
+
async def create_agent_wizard(
|
|
920
|
+
console: Optional[Console] = None,
|
|
921
|
+
) -> AgentCreationWizard:
|
|
922
|
+
"""Create and initialize an agent creation wizard."""
|
|
923
|
+
return AgentCreationWizard(console=console)
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
async def quick_agent_creation(
|
|
927
|
+
name: str,
|
|
928
|
+
provider: str = "anthropic",
|
|
929
|
+
model: str = "claude-3-haiku-20240307",
|
|
930
|
+
) -> Optional[CustomAgentConfig]:
|
|
931
|
+
"""Quick agent creation with minimal configuration."""
|
|
932
|
+
try:
|
|
933
|
+
provider_type = ProviderType(provider.lower())
|
|
934
|
+
except ValueError:
|
|
935
|
+
provider_type = ProviderType.ANTHROPIC
|
|
936
|
+
|
|
937
|
+
config = CustomAgentConfig(
|
|
938
|
+
name=name,
|
|
939
|
+
model_settings=ModelSettings(provider_type=provider_type, model_name=model),
|
|
940
|
+
status=CustomAgentStatus.ACTIVE,
|
|
941
|
+
)
|
|
942
|
+
|
|
943
|
+
repository = AgentRepository()
|
|
944
|
+
return repository.create(config)
|