mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-07 08:26:10 +00:00
style: align agent wizard UI with existing product design patterns
- Replace indigo palette with blue (blue-500/600) to match MCP/agent pages - Remove all emojis from UI elements - Use Tremor TextInput + Button, Ant Design Form.Item with InfoCircleOutlined tooltips - Use Ant Design Switch instead of Checkbox for tool/skill toggles - Match label styling (text-sm font-medium text-gray-700) from create_mcp_server.tsx - Match modal pattern (width 900, header with border-b, 24px padding) - Use border-t border-gray-200 section dividers like MCP form - Use KeyOutlined, CopyOutlined, CheckCircleOutlined icons instead of emoji Co-authored-by: Ishaan Jaff <ishaan-jaff@users.noreply.github.com>
This commit is contained in:
parent
a13973b6cd
commit
bbd9f0f2e6
1 changed files with 161 additions and 240 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { Modal, Form, message, Select, Input, InputNumber, Switch, Checkbox } from "antd";
|
||||
import { Button } from "@tremor/react";
|
||||
import { Modal, Form, message, Select, Input, InputNumber, Tooltip, Switch } from "antd";
|
||||
import { Button, TextInput } from "@tremor/react";
|
||||
import { InfoCircleOutlined, CheckCircleOutlined, CopyOutlined, KeyOutlined } from "@ant-design/icons";
|
||||
import {
|
||||
createAgentCall,
|
||||
getAgentCreateMetadata,
|
||||
|
|
@ -9,11 +10,7 @@ import {
|
|||
} from "../networking";
|
||||
import { getDefaultFormValues, buildAgentDataFromForm } from "./agent_config";
|
||||
import { buildDynamicAgentData } from "./dynamic_agent_form_fields";
|
||||
import {
|
||||
CheckCircleIcon,
|
||||
ClipboardCopyIcon,
|
||||
InformationCircleIcon,
|
||||
} from "@heroicons/react/outline";
|
||||
import { CheckCircleIcon } from "@heroicons/react/outline";
|
||||
|
||||
const WIZARD_STEPS = [
|
||||
{ key: 1, label: "Configure" },
|
||||
|
|
@ -23,36 +20,11 @@ const WIZARD_STEPS = [
|
|||
];
|
||||
|
||||
const AVAILABLE_TOOLS = [
|
||||
{
|
||||
id: "web_search",
|
||||
name: "Web Search",
|
||||
description: "Search the internet for real-time info",
|
||||
icon: "🌐",
|
||||
},
|
||||
{
|
||||
id: "code_interpreter",
|
||||
name: "Code Interpreter",
|
||||
description: "Execute Python/JS code in a sandbox",
|
||||
icon: "</>"
|
||||
},
|
||||
{
|
||||
id: "http_request",
|
||||
name: "HTTP Request",
|
||||
description: "Make outbound API calls",
|
||||
icon: "⚡",
|
||||
},
|
||||
{
|
||||
id: "file_reader",
|
||||
name: "File Reader",
|
||||
description: "Read and parse uploaded files",
|
||||
icon: "📄",
|
||||
},
|
||||
{
|
||||
id: "database_query",
|
||||
name: "Database Query",
|
||||
description: "Run read-only SQL queries",
|
||||
icon: "🗃️",
|
||||
},
|
||||
{ id: "web_search", name: "Web Search", description: "Search the internet for real-time info" },
|
||||
{ id: "code_interpreter", name: "Code Interpreter", description: "Execute Python/JS code in a sandbox" },
|
||||
{ id: "http_request", name: "HTTP Request", description: "Make outbound API calls" },
|
||||
{ id: "file_reader", name: "File Reader", description: "Read and parse uploaded files" },
|
||||
{ id: "database_query", name: "Database Query", description: "Run read-only SQL queries" },
|
||||
];
|
||||
|
||||
const AVAILABLE_SKILLS = [
|
||||
|
|
@ -92,9 +64,9 @@ const StepIndicator: React.FC<{ currentStep: number }> = ({ currentStep }) => (
|
|||
<div
|
||||
className={`w-8 h-8 rounded-full flex items-center justify-center text-sm font-semibold transition-colors ${
|
||||
step.key < currentStep
|
||||
? "bg-indigo-600 text-white"
|
||||
? "bg-blue-600 text-white"
|
||||
: step.key === currentStep
|
||||
? "bg-indigo-600 text-white"
|
||||
? "bg-blue-600 text-white"
|
||||
: "bg-gray-200 text-gray-500"
|
||||
}`}
|
||||
>
|
||||
|
|
@ -107,7 +79,7 @@ const StepIndicator: React.FC<{ currentStep: number }> = ({ currentStep }) => (
|
|||
<span
|
||||
className={`text-xs mt-1 ${
|
||||
step.key === currentStep
|
||||
? "text-indigo-600 font-semibold"
|
||||
? "text-blue-600 font-semibold"
|
||||
: "text-gray-400"
|
||||
}`}
|
||||
>
|
||||
|
|
@ -117,7 +89,7 @@ const StepIndicator: React.FC<{ currentStep: number }> = ({ currentStep }) => (
|
|||
{idx < WIZARD_STEPS.length - 1 && (
|
||||
<div
|
||||
className={`w-16 h-0.5 mx-2 mb-5 ${
|
||||
step.key < currentStep ? "bg-indigo-600" : "bg-gray-200"
|
||||
step.key < currentStep ? "bg-blue-600" : "bg-gray-200"
|
||||
}`}
|
||||
/>
|
||||
)}
|
||||
|
|
@ -133,20 +105,17 @@ const ToolCard: React.FC<{
|
|||
}> = ({ tool, selected, onToggle }) => (
|
||||
<div
|
||||
onClick={onToggle}
|
||||
className={`flex items-center justify-between p-4 rounded-lg border-2 cursor-pointer transition-all ${
|
||||
className={`flex items-center justify-between p-4 rounded-lg border cursor-pointer transition-all ${
|
||||
selected
|
||||
? "border-indigo-500 bg-indigo-50"
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300 bg-white"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<span className="text-xl">{tool.icon}</span>
|
||||
<div>
|
||||
<div className="font-medium text-gray-900">{tool.name}</div>
|
||||
<div className="text-xs text-gray-500">{tool.description}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-sm font-medium text-gray-900">{tool.name}</div>
|
||||
<div className="text-xs text-gray-500">{tool.description}</div>
|
||||
</div>
|
||||
<Checkbox checked={selected} onChange={onToggle} />
|
||||
<Switch checked={selected} onChange={onToggle} size="small" />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
|
@ -157,15 +126,15 @@ const SkillCard: React.FC<{
|
|||
}> = ({ skill, selected, onToggle }) => (
|
||||
<div
|
||||
onClick={onToggle}
|
||||
className={`p-3 rounded-lg border-2 cursor-pointer transition-all ${
|
||||
className={`p-3 rounded-lg border cursor-pointer transition-all ${
|
||||
selected
|
||||
? "border-indigo-500 bg-indigo-50"
|
||||
? "border-blue-500 bg-blue-50"
|
||||
: "border-gray-200 hover:border-gray-300 bg-white"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center justify-between">
|
||||
<span className="text-sm font-medium text-gray-900">{skill.name}</span>
|
||||
<Checkbox checked={selected} onChange={onToggle} />
|
||||
<Switch checked={selected} onChange={onToggle} size="small" />
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 mt-1">{skill.description}</div>
|
||||
</div>
|
||||
|
|
@ -186,16 +155,13 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
const [agentType, setAgentType] = useState<string>("a2a");
|
||||
const [agentTypeMetadata, setAgentTypeMetadata] = useState<AgentCreateInfo[]>([]);
|
||||
|
||||
// Step 2 state
|
||||
const [maxIterations, setMaxIterations] = useState(10);
|
||||
const [selectedTools, setSelectedTools] = useState<string[]>([]);
|
||||
const [selectedSkills, setSelectedSkills] = useState<string[]>([]);
|
||||
|
||||
// Step 3 state
|
||||
const [keyOption, setKeyOption] = useState<"create" | "existing" | "skip">("create");
|
||||
const [keyName, setKeyName] = useState("new-agent-key");
|
||||
|
||||
// Step 4 state
|
||||
const [createdAgent, setCreatedAgent] = useState<CreatedAgentResult | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -238,17 +204,13 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
|
||||
const toggleTool = (toolId: string) => {
|
||||
setSelectedTools((prev) =>
|
||||
prev.includes(toolId)
|
||||
? prev.filter((t) => t !== toolId)
|
||||
: [...prev, toolId]
|
||||
prev.includes(toolId) ? prev.filter((t) => t !== toolId) : [...prev, toolId]
|
||||
);
|
||||
};
|
||||
|
||||
const toggleSkill = (skillId: string) => {
|
||||
setSelectedSkills((prev) =>
|
||||
prev.includes(skillId)
|
||||
? prev.filter((s) => s !== skillId)
|
||||
: [...prev, skillId]
|
||||
prev.includes(skillId) ? prev.filter((s) => s !== skillId) : [...prev, skillId]
|
||||
);
|
||||
};
|
||||
|
||||
|
|
@ -305,14 +267,12 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
agentData = buildDynamicAgentData(values, selectedAgentTypeInfo);
|
||||
}
|
||||
|
||||
// Attach capabilities metadata
|
||||
if (!agentData.litellm_params) {
|
||||
agentData.litellm_params = {};
|
||||
}
|
||||
agentData.litellm_params.max_iterations = maxIterations;
|
||||
agentData.litellm_params.tools = selectedTools;
|
||||
|
||||
// Merge selected skills into agent_card_params.skills
|
||||
const existingSkills = agentData.agent_card_params?.skills || [];
|
||||
const wizardSkills = selectedSkills.map((skillId) => {
|
||||
const skillDef = AVAILABLE_SKILLS.find((s) => s.id === skillId);
|
||||
|
|
@ -324,15 +284,11 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
};
|
||||
});
|
||||
if (agentData.agent_card_params) {
|
||||
agentData.agent_card_params.skills = [
|
||||
...existingSkills,
|
||||
...wizardSkills,
|
||||
];
|
||||
agentData.agent_card_params.skills = [...existingSkills, ...wizardSkills];
|
||||
}
|
||||
|
||||
const response = await createAgentCall(accessToken, agentData);
|
||||
|
||||
// Create key if requested
|
||||
let createdKeyName: string | undefined;
|
||||
let createdKeyValue: string | undefined;
|
||||
if (keyOption === "create" && keyName.trim()) {
|
||||
|
|
@ -379,16 +335,23 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
};
|
||||
|
||||
const renderStep1 = () => (
|
||||
<div className="space-y-5">
|
||||
<div className="grid grid-cols-1 gap-6">
|
||||
<Form.Item
|
||||
label={<span className="text-sm font-medium text-gray-700">Agent Type</span>}
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Agent Type
|
||||
<Tooltip title="Select the type of agent you want to create">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
required
|
||||
tooltip="Select the type of agent you want to create"
|
||||
>
|
||||
<Select
|
||||
value={agentType}
|
||||
onChange={handleAgentTypeChange}
|
||||
size="large"
|
||||
className="rounded-lg"
|
||||
style={{ width: "100%" }}
|
||||
optionLabelProp="label"
|
||||
>
|
||||
|
|
@ -407,17 +370,11 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
>
|
||||
<div className="flex items-center gap-3 py-1">
|
||||
{info.logo_url && (
|
||||
<img
|
||||
src={info.logo_url}
|
||||
alt={info.agent_type_display_name}
|
||||
className="w-5 h-5 object-contain"
|
||||
/>
|
||||
<img src={info.logo_url} alt={info.agent_type_display_name} className="w-5 h-5 object-contain" />
|
||||
)}
|
||||
<div>
|
||||
<div className="font-medium">{info.agent_type_display_name}</div>
|
||||
{info.description && (
|
||||
<div className="text-xs text-gray-500">{info.description}</div>
|
||||
)}
|
||||
{info.description && <div className="text-xs text-gray-500">{info.description}</div>}
|
||||
</div>
|
||||
</div>
|
||||
</Select.Option>
|
||||
|
|
@ -426,12 +383,21 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={<span className="text-sm font-medium text-gray-700">Agent Name</span>}
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Agent Name
|
||||
<Tooltip title="Unique identifier for the agent. Cannot contain spaces.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
name="agent_name"
|
||||
rules={[{ required: true, message: "Please enter a unique agent name" }]}
|
||||
tooltip="Unique identifier for the agent"
|
||||
>
|
||||
<Input size="large" placeholder="e.g., customer-support-agent" />
|
||||
<TextInput
|
||||
placeholder="e.g., customer-support-agent"
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
|
@ -439,7 +405,10 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
name="name"
|
||||
rules={[{ required: true, message: "Please enter a display name" }]}
|
||||
>
|
||||
<Input size="large" placeholder="e.g., Customer Support Agent" />
|
||||
<TextInput
|
||||
placeholder="e.g., Customer Support Agent"
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
|
|
@ -447,16 +416,28 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
name="description"
|
||||
rules={[{ required: true, message: "Please enter a description" }]}
|
||||
>
|
||||
<Input.TextArea rows={3} placeholder="Describe what this agent does..." />
|
||||
<TextInput
|
||||
placeholder="Brief description of what this agent does"
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={<span className="text-sm font-medium text-gray-700">URL</span>}
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
URL
|
||||
<Tooltip title="Base URL where the agent is hosted">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
}
|
||||
name="url"
|
||||
rules={[{ required: true, message: "Please enter the agent URL" }]}
|
||||
tooltip="Base URL where the agent is hosted"
|
||||
>
|
||||
<Input size="large" placeholder="http://localhost:9999/" />
|
||||
<TextInput
|
||||
placeholder="http://localhost:9999/"
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -466,13 +447,13 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
{/* Max Iterations */}
|
||||
<div>
|
||||
<div className="flex items-center justify-between mb-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-700">Max Iterations</span>
|
||||
<InformationCircleIcon className="w-4 h-4 text-gray-400" />
|
||||
</div>
|
||||
<span className="text-xs text-gray-500">
|
||||
How many reasoning loops before the agent stops
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Max Iterations
|
||||
<Tooltip title="How many reasoning loops before the agent stops. Lower values reduce cost; higher values allow more complex tasks.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">Range: 1–100</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center border border-gray-300 rounded-lg overflow-hidden">
|
||||
|
|
@ -507,7 +488,7 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
onClick={() => setMaxIterations(preset)}
|
||||
className={`px-3 py-1.5 rounded-lg text-sm font-medium transition-colors ${
|
||||
maxIterations === preset
|
||||
? "bg-indigo-600 text-white"
|
||||
? "bg-blue-600 text-white"
|
||||
: "bg-gray-100 text-gray-700 hover:bg-gray-200"
|
||||
}`}
|
||||
>
|
||||
|
|
@ -515,18 +496,17 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
</button>
|
||||
))}
|
||||
</div>
|
||||
<p className="text-xs text-gray-400 mt-1">
|
||||
Range: 1–100. Lower values reduce cost; higher values allow more complex tasks.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Tools */}
|
||||
<div>
|
||||
<div className="pt-6 border-t border-gray-200">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-700">Tools</span>
|
||||
<InformationCircleIcon className="w-4 h-4 text-gray-400" />
|
||||
</div>
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Tools
|
||||
<Tooltip title="Select which tools this agent is allowed to use during execution.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">{selectedTools.length} selected</span>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
|
|
@ -542,15 +522,15 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
</div>
|
||||
|
||||
{/* Skills */}
|
||||
<div>
|
||||
<div className="pt-6 border-t border-gray-200">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm font-medium text-gray-700">Skills</span>
|
||||
<InformationCircleIcon className="w-4 h-4 text-gray-400" />
|
||||
</div>
|
||||
<span className="text-xs text-gray-500">
|
||||
{selectedSkills.length} selected
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
Skills
|
||||
<Tooltip title="Select which skills this agent should have. Skills describe the agent's advertised capabilities.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<span className="text-xs text-gray-500">{selectedSkills.length} selected</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{AVAILABLE_SKILLS.map((skill) => (
|
||||
|
|
@ -571,61 +551,51 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="text-center mb-4">
|
||||
<span className="inline-flex items-center gap-2 bg-gray-100 rounded-full px-4 py-1.5 text-sm text-gray-700">
|
||||
🤖 {agentName}
|
||||
<span className="inline-flex items-center gap-2 px-2 py-1 bg-blue-50 text-blue-700 border border-blue-200 rounded-md text-sm font-medium">
|
||||
{agentName}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
{/* Create new key */}
|
||||
<div
|
||||
onClick={() => setKeyOption("create")}
|
||||
className={`p-5 rounded-xl border-2 cursor-pointer transition-all ${
|
||||
keyOption === "create"
|
||||
? "border-indigo-500 bg-indigo-50/30"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
className={`p-5 rounded-lg border cursor-pointer transition-all ${
|
||||
keyOption === "create" ? "border-blue-500 bg-blue-50" : "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
className={`w-5 h-5 rounded-full border-2 mt-0.5 flex items-center justify-center ${
|
||||
keyOption === "create" ? "border-indigo-600" : "border-gray-300"
|
||||
className={`w-5 h-5 rounded-full border-2 mt-0.5 flex items-center justify-center flex-shrink-0 ${
|
||||
keyOption === "create" ? "border-blue-600" : "border-gray-300"
|
||||
}`}
|
||||
>
|
||||
{keyOption === "create" && (
|
||||
<div className="w-2.5 h-2.5 rounded-full bg-indigo-600" />
|
||||
)}
|
||||
{keyOption === "create" && <div className="w-2.5 h-2.5 rounded-full bg-blue-600" />}
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-sm">🔑</span>
|
||||
<span className="font-semibold text-gray-900">
|
||||
Create a new key for this agent
|
||||
</span>
|
||||
<span className="text-xs bg-green-100 text-green-700 px-2 py-0.5 rounded-full font-medium">
|
||||
<KeyOutlined className="text-gray-500" />
|
||||
<span className="text-sm font-semibold text-gray-900">Create a new key for this agent</span>
|
||||
<span className="text-xs bg-green-50 text-green-700 border border-green-200 px-2 py-0.5 rounded-md font-medium">
|
||||
Recommended
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 ml-5">
|
||||
<p className="text-xs text-gray-500 ml-6">
|
||||
A dedicated key scoped to this agent. Recommended for production.
|
||||
</p>
|
||||
{keyOption === "create" && (
|
||||
<div className="mt-4 ml-5 space-y-3">
|
||||
<div className="mt-4 ml-6 space-y-3">
|
||||
<div>
|
||||
<label className="text-xs text-gray-600 font-medium">Key Name</label>
|
||||
<Input
|
||||
<TextInput
|
||||
value={keyName}
|
||||
onChange={(e) => setKeyName(e.target.value)}
|
||||
placeholder="new-agent-key"
|
||||
className="mt-1"
|
||||
className="mt-1 rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-xs text-gray-600 font-medium">Models</label>
|
||||
<Input
|
||||
value="All models (default)"
|
||||
disabled
|
||||
className="mt-1"
|
||||
/>
|
||||
<Input value="All models (default)" disabled className="mt-1 rounded-lg" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -636,28 +606,24 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
{/* Assign existing key */}
|
||||
<div
|
||||
onClick={() => setKeyOption("existing")}
|
||||
className={`p-5 rounded-xl border-2 cursor-pointer transition-all ${
|
||||
keyOption === "existing"
|
||||
? "border-indigo-500 bg-indigo-50/30"
|
||||
: "border-gray-200 hover:border-gray-300"
|
||||
className={`p-5 rounded-lg border cursor-pointer transition-all ${
|
||||
keyOption === "existing" ? "border-blue-500 bg-blue-50" : "border-gray-200 hover:border-gray-300"
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-start gap-3">
|
||||
<div
|
||||
className={`w-5 h-5 rounded-full border-2 mt-0.5 flex items-center justify-center ${
|
||||
keyOption === "existing" ? "border-indigo-600" : "border-gray-300"
|
||||
className={`w-5 h-5 rounded-full border-2 mt-0.5 flex items-center justify-center flex-shrink-0 ${
|
||||
keyOption === "existing" ? "border-blue-600" : "border-gray-300"
|
||||
}`}
|
||||
>
|
||||
{keyOption === "existing" && (
|
||||
<div className="w-2.5 h-2.5 rounded-full bg-indigo-600" />
|
||||
)}
|
||||
{keyOption === "existing" && <div className="w-2.5 h-2.5 rounded-full bg-blue-600" />}
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<span className="text-sm">🔍</span>
|
||||
<span className="font-semibold text-gray-900">Assign an existing key</span>
|
||||
<KeyOutlined className="text-gray-500" />
|
||||
<span className="text-sm font-semibold text-gray-900">Assign an existing key</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 ml-5">
|
||||
<p className="text-xs text-gray-500 ml-6">
|
||||
Link a key you've already created.
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -669,8 +635,8 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
<button
|
||||
type="button"
|
||||
onClick={() => setKeyOption("skip")}
|
||||
className={`text-sm underline ${
|
||||
keyOption === "skip" ? "text-indigo-600" : "text-gray-400 hover:text-gray-600"
|
||||
className={`text-sm underline bg-transparent border-none cursor-pointer ${
|
||||
keyOption === "skip" ? "text-blue-600" : "text-gray-400 hover:text-gray-600"
|
||||
}`}
|
||||
>
|
||||
Skip for now — I'll assign a key later
|
||||
|
|
@ -686,102 +652,70 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
return (
|
||||
<div className="text-center space-y-6">
|
||||
<div className="flex justify-center">
|
||||
<div className="w-16 h-16 rounded-full bg-green-100 flex items-center justify-center">
|
||||
<CheckCircleIcon className="w-10 h-10 text-green-600" />
|
||||
<div className="w-14 h-14 rounded-full bg-green-50 border border-green-200 flex items-center justify-center">
|
||||
<CheckCircleOutlined className="text-2xl text-green-600" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 className="text-xl font-bold text-gray-900">
|
||||
Agent created successfully!
|
||||
</h3>
|
||||
<p className="text-sm text-gray-500 mt-1">
|
||||
Your agent is configured and ready to use.
|
||||
</p>
|
||||
<h3 className="text-xl font-semibold text-gray-900">Agent created successfully!</h3>
|
||||
<p className="text-sm text-gray-500 mt-1">Your agent is configured and ready to use.</p>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-4 justify-center">
|
||||
<div className="flex gap-4 justify-center text-left">
|
||||
{/* Agent details */}
|
||||
<div className="bg-gray-50 rounded-xl p-5 text-left flex-1 max-w-[280px]">
|
||||
<p className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">
|
||||
Agent Details
|
||||
</p>
|
||||
<div className="bg-gray-50 border border-gray-200 rounded-lg p-5 flex-1 max-w-[280px]">
|
||||
<p className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">Agent Details</p>
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-sm">🤖</span>
|
||||
<span className="font-semibold text-gray-900">
|
||||
{createdAgent.agent_name}
|
||||
</span>
|
||||
</div>
|
||||
<p className="text-sm font-semibold text-gray-900">{createdAgent.agent_name}</p>
|
||||
{createdAgent.agent_type_display && (
|
||||
<div className="text-xs text-gray-500 flex items-center gap-1.5">
|
||||
<span className="w-2 h-2 rounded-full bg-gray-300" />
|
||||
<p className="text-xs text-gray-500 flex items-center gap-1.5">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-gray-400" />
|
||||
{createdAgent.agent_type_display}
|
||||
</div>
|
||||
</p>
|
||||
)}
|
||||
{createdAgent.url && (
|
||||
<div className="text-xs text-gray-500 flex items-center gap-1.5">
|
||||
<span>🌐</span>
|
||||
{createdAgent.url}
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">{createdAgent.url}</p>
|
||||
)}
|
||||
<div className="text-xs text-gray-500 flex items-center gap-1.5">
|
||||
<span>🔄</span>
|
||||
Max {createdAgent.max_iterations} iterations
|
||||
</div>
|
||||
<div className="text-xs text-gray-500 flex items-center gap-1.5">
|
||||
<span>🛠️</span>
|
||||
{createdAgent.tools_count} tools · {createdAgent.skills_count} skills
|
||||
</div>
|
||||
<p className="text-xs text-gray-500">Max {createdAgent.max_iterations} iterations</p>
|
||||
<p className="text-xs text-gray-500">
|
||||
{createdAgent.tools_count} tools, {createdAgent.skills_count} skills
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Key info */}
|
||||
{createdAgent.key_name && (
|
||||
<div className="bg-gray-50 rounded-xl p-5 text-left flex-1 max-w-[280px]">
|
||||
<p className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">
|
||||
🔑 API Key Assigned
|
||||
</p>
|
||||
<p className="font-semibold text-gray-900 text-sm">
|
||||
{createdAgent.key_name}
|
||||
</p>
|
||||
<div className="bg-gray-50 border border-gray-200 rounded-lg p-5 flex-1 max-w-[280px]">
|
||||
<p className="text-xs font-semibold text-gray-500 uppercase tracking-wide mb-3">API Key Assigned</p>
|
||||
<p className="text-sm font-semibold text-gray-900">{createdAgent.key_name}</p>
|
||||
{createdAgent.key_value && (
|
||||
<div className="mt-2 flex items-center gap-2 bg-white rounded-lg border border-gray-200 px-3 py-2">
|
||||
<code className="text-xs text-gray-600 truncate flex-1">
|
||||
<div className="mt-2 flex items-center gap-2 bg-white rounded-md border border-gray-200 px-3 py-2">
|
||||
<code className="text-xs text-gray-600 truncate flex-1 font-mono">
|
||||
{createdAgent.key_value.substring(0, 12)}..
|
||||
{createdAgent.key_value.substring(
|
||||
createdAgent.key_value.length - 4
|
||||
)}
|
||||
{createdAgent.key_value.substring(createdAgent.key_value.length - 4)}
|
||||
</code>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => copyToClipboard(createdAgent.key_value!)}
|
||||
className="text-gray-400 hover:text-gray-600"
|
||||
>
|
||||
<ClipboardCopyIcon className="w-4 h-4" />
|
||||
</button>
|
||||
<Tooltip title="Copy to clipboard">
|
||||
<CopyOutlined
|
||||
onClick={() => copyToClipboard(createdAgent.key_value!)}
|
||||
className="cursor-pointer text-gray-400 hover:text-blue-500"
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-green-600 mt-2 flex items-center gap-1">
|
||||
<span className="w-1.5 h-1.5 rounded-full bg-green-500" />
|
||||
Active & ready
|
||||
Active & ready
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-3 justify-center pt-2">
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={handleClose}
|
||||
>
|
||||
<Button variant="secondary" onClick={handleClose}>
|
||||
View All Agents
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
className="bg-red-500 hover:bg-red-600 text-white border-red-500"
|
||||
onClick={handleClose}
|
||||
>
|
||||
<Button variant="primary" onClick={handleClose}>
|
||||
Go to Virtual Keys
|
||||
</Button>
|
||||
</div>
|
||||
|
|
@ -791,35 +725,25 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
|
||||
const getStepContent = () => {
|
||||
switch (currentStep) {
|
||||
case 1:
|
||||
return renderStep1();
|
||||
case 2:
|
||||
return renderStep2();
|
||||
case 3:
|
||||
return renderStep3();
|
||||
case 4:
|
||||
return renderStep4();
|
||||
default:
|
||||
return null;
|
||||
case 1: return renderStep1();
|
||||
case 2: return renderStep2();
|
||||
case 3: return renderStep3();
|
||||
case 4: return renderStep4();
|
||||
default: return null;
|
||||
}
|
||||
};
|
||||
|
||||
const getNextButtonText = () => {
|
||||
if (currentStep === 3) return isSubmitting ? "Creating..." : "Create Agent";
|
||||
return "Next";
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={
|
||||
<div className="pb-2 border-b border-gray-100">
|
||||
<div className="flex items-center pb-4 border-b border-gray-100" style={{ gap: 12 }}>
|
||||
<h2 className="text-xl font-semibold text-gray-900">Add New Agent</h2>
|
||||
</div>
|
||||
}
|
||||
open={visible}
|
||||
onCancel={handleClose}
|
||||
footer={null}
|
||||
width={720}
|
||||
width={900}
|
||||
className="top-8"
|
||||
styles={{
|
||||
body: { padding: "24px", maxHeight: "70vh", overflowY: "auto" },
|
||||
|
|
@ -827,34 +751,31 @@ const AddAgentWizard: React.FC<AddAgentWizardProps> = ({
|
|||
}}
|
||||
destroyOnClose
|
||||
>
|
||||
<div className="mt-4">
|
||||
<div className="mt-6">
|
||||
<StepIndicator currentStep={currentStep} />
|
||||
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
initialValues={getDefaultFormValues()}
|
||||
className="space-y-4"
|
||||
className="space-y-6"
|
||||
>
|
||||
{getStepContent()}
|
||||
</Form>
|
||||
|
||||
{/* Footer buttons */}
|
||||
{currentStep < 4 && (
|
||||
<div className="flex items-center justify-between pt-6 border-t border-gray-100 mt-6">
|
||||
<div>
|
||||
{currentStep > 1 && (
|
||||
<Button variant="secondary" onClick={handleBack}>
|
||||
← Back
|
||||
<Button variant="light" onClick={handleBack}>
|
||||
Back
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleNext}
|
||||
loading={isSubmitting}
|
||||
>
|
||||
{getNextButtonText()} {currentStep < 3 ? "›" : ""}
|
||||
<Button variant="primary" onClick={handleNext} loading={isSubmitting}>
|
||||
{currentStep === 3
|
||||
? isSubmitting ? "Creating..." : "Create Agent"
|
||||
: "Next"}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue