mirror of https://github.com/kortix-ai/suna.git
improve agent config ui
This commit is contained in:
parent
76eef5081c
commit
df29b41a2f
|
@ -2,32 +2,23 @@
|
||||||
|
|
||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
import { useParams, useRouter } from 'next/navigation';
|
import { useParams, useRouter } from 'next/navigation';
|
||||||
import { Loader2, Save, Eye, Check, Wrench, Server, BookOpen, Workflow, Zap } from 'lucide-react';
|
import { Loader2, Save, Eye } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
|
||||||
import { Badge } from '@/components/ui/badge';
|
|
||||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
|
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
import { Dialog, DialogContent } from '@/components/ui/dialog';
|
|
||||||
import { useUpdateAgent } from '@/hooks/react-query/agents/use-agents';
|
import { useUpdateAgent } from '@/hooks/react-query/agents/use-agents';
|
||||||
import { useCreateAgentVersion, useActivateAgentVersion } from '@/hooks/react-query/agents/use-agent-versions';
|
import { useCreateAgentVersion, useActivateAgentVersion } from '@/hooks/react-query/agents/use-agent-versions';
|
||||||
import { AgentMCPConfiguration } from '../../../../../components/agents/agent-mcp-configuration';
|
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { AgentToolsConfiguration } from '../../../../../components/agents/agent-tools-configuration';
|
|
||||||
import { AgentPreview } from '../../../../../components/agents/agent-preview';
|
|
||||||
import { getAgentAvatar } from '../../../../../lib/utils/get-agent-style';
|
import { getAgentAvatar } from '../../../../../lib/utils/get-agent-style';
|
||||||
import { EditableText } from '@/components/ui/editable';
|
import { AgentPreview } from '../../../../../components/agents/agent-preview';
|
||||||
import { ExpandableMarkdownEditor } from '@/components/ui/expandable-markdown-editor';
|
|
||||||
import { StylePicker } from '../../../../../components/agents/style-picker';
|
|
||||||
import { AgentBuilderChat } from '../../../../../components/agents/agent-builder-chat';
|
|
||||||
import { AgentTriggersConfiguration } from '@/components/agents/triggers/agent-triggers-configuration';
|
|
||||||
import { AgentKnowledgeBaseManager } from '@/components/agents/knowledge-base/agent-knowledge-base-manager';
|
|
||||||
import { AgentWorkflowsConfiguration } from '@/components/agents/workflows/agent-workflows-configuration';
|
|
||||||
import { AgentVersionSwitcher } from '@/components/agents/agent-version-switcher';
|
import { AgentVersionSwitcher } from '@/components/agents/agent-version-switcher';
|
||||||
import { CreateVersionButton } from '@/components/agents/create-version-button';
|
import { CreateVersionButton } from '@/components/agents/create-version-button';
|
||||||
import { useAgentVersionData } from '../../../../../hooks/use-agent-version-data';
|
import { useAgentVersionData } from '../../../../../hooks/use-agent-version-data';
|
||||||
import { useAgentVersionStore } from '../../../../../lib/stores/agent-version-store';
|
import { useAgentVersionStore } from '../../../../../lib/stores/agent-version-store';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
import { AgentHeader, VersionAlert, AgentBuilderTab, ConfigurationTab } from '@/components/agents/config';
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -46,18 +37,13 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const agentId = params.agentId as string;
|
const agentId = params.agentId as string;
|
||||||
|
|
||||||
// Use modular hooks
|
|
||||||
const { agent, versionData, isViewingOldVersion, isLoading, error } = useAgentVersionData({ agentId });
|
const { agent, versionData, isViewingOldVersion, isLoading, error } = useAgentVersionData({ agentId });
|
||||||
|
|
||||||
// Debug logging
|
|
||||||
console.log('[Agent Config] Loading state:', { isLoading, error, agentId });
|
|
||||||
const { hasUnsavedChanges, setHasUnsavedChanges } = useAgentVersionStore();
|
const { hasUnsavedChanges, setHasUnsavedChanges } = useAgentVersionStore();
|
||||||
|
|
||||||
const updateAgentMutation = useUpdateAgent();
|
const updateAgentMutation = useUpdateAgent();
|
||||||
const createVersionMutation = useCreateAgentVersion();
|
const createVersionMutation = useCreateAgentVersion();
|
||||||
const activateVersionMutation = useActivateAgentVersion();
|
const activateVersionMutation = useActivateAgentVersion();
|
||||||
|
|
||||||
// State management
|
|
||||||
const [formData, setFormData] = useState<FormData>({
|
const [formData, setFormData] = useState<FormData>({
|
||||||
name: '',
|
name: '',
|
||||||
description: '',
|
description: '',
|
||||||
|
@ -73,30 +59,18 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
const [originalData, setOriginalData] = useState<FormData>(formData);
|
const [originalData, setOriginalData] = useState<FormData>(formData);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
|
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
|
||||||
const [isComparisonOpen, setIsComparisonOpen] = useState(false);
|
|
||||||
const [activeTab, setActiveTab] = useState('agent-builder');
|
const [activeTab, setActiveTab] = useState('agent-builder');
|
||||||
|
|
||||||
// Initialize form data from agent/version data
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!agent) return;
|
if (!agent) return;
|
||||||
|
|
||||||
console.log('[Agent Config] Agent data:', agent);
|
|
||||||
console.log('[Agent Config] Version data:', versionData);
|
|
||||||
|
|
||||||
// Determine the source of configuration data
|
|
||||||
let configSource = agent;
|
let configSource = agent;
|
||||||
|
|
||||||
// If we have explicit version data (from URL param), use it
|
|
||||||
if (versionData) {
|
if (versionData) {
|
||||||
configSource = versionData;
|
configSource = versionData;
|
||||||
}
|
}
|
||||||
// If no URL param but agent has current_version data, use that
|
|
||||||
else if (agent.current_version) {
|
else if (agent.current_version) {
|
||||||
configSource = agent.current_version;
|
configSource = agent.current_version;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[Agent Config] Config source:', configSource);
|
|
||||||
|
|
||||||
const initialData: FormData = {
|
const initialData: FormData = {
|
||||||
name: agent.name || '',
|
name: agent.name || '',
|
||||||
description: agent.description || '',
|
description: agent.description || '',
|
||||||
|
@ -190,19 +164,16 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
}));
|
}));
|
||||||
}, [isViewingOldVersion]);
|
}, [isViewingOldVersion]);
|
||||||
|
|
||||||
// Version activation handler
|
|
||||||
const handleActivateVersion = useCallback(async (versionId: string) => {
|
const handleActivateVersion = useCallback(async (versionId: string) => {
|
||||||
try {
|
try {
|
||||||
await activateVersionMutation.mutateAsync({ agentId, versionId });
|
await activateVersionMutation.mutateAsync({ agentId, versionId });
|
||||||
toast.success('Version activated successfully');
|
toast.success('Version activated successfully');
|
||||||
// Refresh page without version param
|
|
||||||
router.push(`/agents/config/${agentId}`);
|
router.push(`/agents/config/${agentId}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast.error('Failed to activate version');
|
toast.error('Failed to activate version');
|
||||||
}
|
}
|
||||||
}, [agentId, activateVersionMutation, router]);
|
}, [agentId, activateVersionMutation, router]);
|
||||||
|
|
||||||
// Auto-switch to configuration tab when viewing old versions
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isViewingOldVersion && activeTab === 'agent-builder') {
|
if (isViewingOldVersion && activeTab === 'agent-builder') {
|
||||||
setActiveTab('configuration');
|
setActiveTab('configuration');
|
||||||
|
@ -212,7 +183,7 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen">
|
<div className="flex items-center justify-center h-screen">
|
||||||
<Alert variant="destructive">
|
<Alert variant="destructive" className="max-w-md">
|
||||||
<AlertDescription>
|
<AlertDescription>
|
||||||
{error.message || 'Failed to load agent configuration'}
|
{error.message || 'Failed to load agent configuration'}
|
||||||
</AlertDescription>
|
</AlertDescription>
|
||||||
|
@ -224,7 +195,10 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen">
|
<div className="flex items-center justify-center h-screen">
|
||||||
<Loader2 className="h-8 w-8 animate-spin" />
|
<div className="flex flex-col items-center gap-3">
|
||||||
|
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
|
||||||
|
<p className="text-sm text-muted-foreground">Loading agent configuration...</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -232,14 +206,13 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
if (!agent) {
|
if (!agent) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center h-screen">
|
<div className="flex items-center justify-center h-screen">
|
||||||
<Alert>
|
<Alert className="max-w-md">
|
||||||
<AlertDescription>Agent not found</AlertDescription>
|
<AlertDescription>Agent not found</AlertDescription>
|
||||||
</Alert>
|
</Alert>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use version data when viewing old version, otherwise use form data
|
|
||||||
const displayData = isViewingOldVersion && versionData ? {
|
const displayData = isViewingOldVersion && versionData ? {
|
||||||
name: agent?.name || '',
|
name: agent?.name || '',
|
||||||
description: agent?.description || '',
|
description: agent?.description || '',
|
||||||
|
@ -263,12 +236,14 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="h-screen flex flex-col">
|
<div className="h-screen flex flex-col bg-background">
|
||||||
<div className="flex-1 flex overflow-hidden">
|
<div className="flex-1 flex overflow-hidden">
|
||||||
<div className="hidden md:flex w-full h-full">
|
<div className="hidden md:flex w-full h-full">
|
||||||
<div className="w-1/2 border-r bg-background h-full flex flex-col">
|
<div className="w-1/2 border-r border-border/40 bg-background h-full flex flex-col">
|
||||||
<div className="h-full flex flex-col">
|
<div className="h-full flex flex-col">
|
||||||
<div className="flex justify-between items-center mb-4 p-4 border-b">
|
<div className="flex-shrink-0 bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||||
|
<div className="p-4">
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<AgentVersionSwitcher
|
<AgentVersionSwitcher
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
|
@ -300,225 +275,70 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
size="sm"
|
size="sm"
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
disabled={isSaving}
|
disabled={isSaving}
|
||||||
|
className="bg-primary hover:bg-primary/90 text-primary-foreground"
|
||||||
>
|
>
|
||||||
{isSaving ? (
|
{isSaving ? (
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-3 w-3 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<Save className="h-4 w-4" />
|
<Save className="h-3 w-3" />
|
||||||
)}
|
)}
|
||||||
Save Changes
|
Save
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-1 flex flex-col overflow-hidden -mt-4">
|
|
||||||
<div className="flex-shrink-0 space-y-6 px-4 mt-2">
|
|
||||||
{isViewingOldVersion && (
|
{isViewingOldVersion && (
|
||||||
<Alert className="mb-4">
|
<VersionAlert
|
||||||
<Eye className="h-4 w-4" />
|
versionData={versionData}
|
||||||
<div className="flex items-center justify-between w-full">
|
isActivating={activateVersionMutation.isPending}
|
||||||
<AlertDescription>
|
onActivateVersion={handleActivateVersion}
|
||||||
You are viewing a read-only version. To make changes, please activate this version or switch back to the current version.
|
|
||||||
</AlertDescription>
|
|
||||||
<div className="ml-4 flex items-center gap-2">
|
|
||||||
{versionData && (
|
|
||||||
<Badge className="text-xs">
|
|
||||||
{versionData.version_name}
|
|
||||||
</Badge>
|
|
||||||
)}
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => versionData && handleActivateVersion(versionData.version_id)}
|
|
||||||
disabled={activateVersionMutation.isPending}
|
|
||||||
>
|
|
||||||
{activateVersionMutation.isPending ? (
|
|
||||||
<Loader2 className="h-3 w-3 animate-spin mr-1" />
|
|
||||||
) : (
|
|
||||||
<Check className="h-3 w-3" />
|
|
||||||
)}
|
|
||||||
Set as Current
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Alert>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex flex-col flex-1 overflow-hidden">
|
|
||||||
<div className="flex-shrink-0 space-y-4 px-4 py-2">
|
|
||||||
<div className="flex items-center justify-between">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<StylePicker
|
|
||||||
currentEmoji={currentStyle.avatar}
|
|
||||||
currentColor={currentStyle.color}
|
|
||||||
onStyleChange={handleStyleChange}
|
|
||||||
agentId={agentId}
|
|
||||||
>
|
|
||||||
<div className="h-10 w-10 rounded-xl flex items-center justify-center gap-2" style={{ backgroundColor: currentStyle.color }}>
|
|
||||||
<div className="text-lg font-medium">{currentStyle.avatar}</div>
|
|
||||||
</div>
|
|
||||||
</StylePicker>
|
|
||||||
<EditableText
|
|
||||||
value={displayData.name}
|
|
||||||
onSave={(value) => handleFieldChange('name', value)}
|
|
||||||
className="text-md font-semibold bg-transparent"
|
|
||||||
placeholder="Click to add agent name..."
|
|
||||||
disabled={isViewingOldVersion}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
)}
|
||||||
<TabsList className="grid grid-cols-2">
|
<AgentHeader
|
||||||
<TabsTrigger
|
|
||||||
value="agent-builder"
|
|
||||||
disabled={isViewingOldVersion}
|
|
||||||
className={isViewingOldVersion ? "opacity-50 cursor-not-allowed" : ""}
|
|
||||||
>
|
|
||||||
Agent Builder
|
|
||||||
</TabsTrigger>
|
|
||||||
<TabsTrigger value="configuration">Configuration</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<TabsContent value="agent-builder" className="flex-1 h-0 px-4">
|
|
||||||
{isViewingOldVersion ? (
|
|
||||||
<div className="flex items-center justify-center h-full">
|
|
||||||
<div className="text-center space-y-4 max-w-md">
|
|
||||||
<div className="text-6xl">🔒</div>
|
|
||||||
<div>
|
|
||||||
<h3 className="text-lg font-semibold text-muted-foreground">Agent Builder Disabled</h3>
|
|
||||||
<p className="text-sm text-muted-foreground mt-2">
|
|
||||||
The Agent Builder is only available for the current version.
|
|
||||||
To use the Agent Builder, please activate this version first.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<AgentBuilderChat
|
|
||||||
agentId={agentId}
|
agentId={agentId}
|
||||||
formData={displayData}
|
displayData={displayData}
|
||||||
handleFieldChange={handleFieldChange}
|
|
||||||
handleStyleChange={handleStyleChange}
|
|
||||||
currentStyle={currentStyle}
|
currentStyle={currentStyle}
|
||||||
|
activeTab={activeTab}
|
||||||
|
isViewingOldVersion={isViewingOldVersion}
|
||||||
|
onFieldChange={handleFieldChange}
|
||||||
|
onStyleChange={handleStyleChange}
|
||||||
|
onTabChange={setActiveTab}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 overflow-hidden">
|
||||||
|
<Tabs value={activeTab} onValueChange={setActiveTab} className="flex flex-col h-full">
|
||||||
|
<TabsContent value="agent-builder" className="flex-1 h-0 m-0">
|
||||||
|
<AgentBuilderTab
|
||||||
|
agentId={agentId}
|
||||||
|
displayData={displayData}
|
||||||
|
currentStyle={currentStyle}
|
||||||
|
isViewingOldVersion={isViewingOldVersion}
|
||||||
|
onFieldChange={handleFieldChange}
|
||||||
|
onStyleChange={handleStyleChange}
|
||||||
/>
|
/>
|
||||||
)}
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
{activeTab === 'configuration' && (
|
<TabsContent value="configuration" className="flex-1 h-0 m-0 overflow-y-auto">
|
||||||
<div className='px-4'>
|
<ConfigurationTab
|
||||||
<ExpandableMarkdownEditor
|
agentId={agentId}
|
||||||
value={displayData.system_prompt}
|
displayData={displayData}
|
||||||
onSave={(value) => handleFieldChange('system_prompt', value)}
|
versionData={versionData}
|
||||||
placeholder="Click to set system instructions..."
|
isViewingOldVersion={isViewingOldVersion}
|
||||||
title="System Instructions"
|
onFieldChange={handleFieldChange}
|
||||||
disabled={isViewingOldVersion}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<TabsContent value="configuration" className="flex-1 h-0 overflow-y-auto px-4">
|
|
||||||
<Accordion type="single" collapsible defaultValue="system" className='space-y-2'>
|
|
||||||
<AccordionItem className='border rounded-xl px-4' value="tools">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<div className='bg-muted rounded-full h-8 w-8 flex items-center justify-center'>
|
|
||||||
<Wrench className='h-4 w-4' />
|
|
||||||
</div>
|
|
||||||
Tools
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
<AgentToolsConfiguration
|
|
||||||
tools={displayData.agentpress_tools}
|
|
||||||
onToolsChange={(tools) => handleFieldChange('agentpress_tools', tools)}
|
|
||||||
/>
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem className='border rounded-xl px-4' value="integrations">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<div className='bg-muted rounded-full h-8 w-8 flex items-center justify-center'>
|
|
||||||
<Server className='h-4 w-4' />
|
|
||||||
</div>
|
|
||||||
Integrations
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
<AgentMCPConfiguration
|
|
||||||
configuredMCPs={displayData.configured_mcps}
|
|
||||||
customMCPs={displayData.custom_mcps}
|
|
||||||
onMCPChange={handleMCPChange}
|
onMCPChange={handleMCPChange}
|
||||||
agentId={agentId}
|
|
||||||
versionData={{
|
|
||||||
configured_mcps: displayData.configured_mcps,
|
|
||||||
custom_mcps: displayData.custom_mcps,
|
|
||||||
system_prompt: displayData.system_prompt,
|
|
||||||
agentpress_tools: displayData.agentpress_tools
|
|
||||||
}}
|
|
||||||
saveMode="callback"
|
|
||||||
versionId={versionData?.version_id}
|
|
||||||
/>
|
/>
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem className='border rounded-xl px-4' value="knowledge">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<div className='bg-muted rounded-full h-8 w-8 flex items-center justify-center'>
|
|
||||||
<BookOpen className='h-4 w-4' />
|
|
||||||
</div>
|
|
||||||
Knowledge Base
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
<AgentKnowledgeBaseManager
|
|
||||||
agentId={agentId}
|
|
||||||
agentName={displayData.name || 'Agent'}
|
|
||||||
/>
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem className='border rounded-xl px-4' value="workflows">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<div className='bg-muted rounded-full h-8 w-8 flex items-center justify-center'>
|
|
||||||
<Workflow className='h-4 w-4' />
|
|
||||||
</div>
|
|
||||||
Workflows
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
<AgentWorkflowsConfiguration
|
|
||||||
agentId={agentId}
|
|
||||||
agentName={displayData.name || 'Agent'}
|
|
||||||
/>
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
|
|
||||||
<AccordionItem className='border rounded-xl px-4' value="triggers">
|
|
||||||
<AccordionTrigger>
|
|
||||||
<div className='flex items-center gap-2'>
|
|
||||||
<div className='bg-muted rounded-full h-8 w-8 flex items-center justify-center'>
|
|
||||||
<Zap className='h-4 w-4' />
|
|
||||||
</div>
|
|
||||||
Triggers
|
|
||||||
</div>
|
|
||||||
</AccordionTrigger>
|
|
||||||
<AccordionContent>
|
|
||||||
<AgentTriggersConfiguration agentId={agentId} />
|
|
||||||
</AccordionContent>
|
|
||||||
</AccordionItem>
|
|
||||||
</Accordion>
|
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-1/2 overflow-y-auto">
|
<div className="w-1/2 bg-muted/30 overflow-y-auto">
|
||||||
|
<div className="h-full">
|
||||||
{previewAgent && <AgentPreview agent={previewAgent} />}
|
{previewAgent && <AgentPreview agent={previewAgent} />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="md:hidden flex flex-col h-full w-full">
|
<div className="md:hidden flex flex-col h-full w-full">
|
||||||
<div className="flex-1 overflow-y-auto p-4">
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
|
@ -527,17 +347,17 @@ export default function AgentConfigurationPageRefactored() {
|
||||||
<Drawer open={isPreviewOpen} onOpenChange={setIsPreviewOpen}>
|
<Drawer open={isPreviewOpen} onOpenChange={setIsPreviewOpen}>
|
||||||
<DrawerTrigger asChild>
|
<DrawerTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
className="fixed bottom-4 right-4 rounded-full shadow-lg"
|
className="fixed bottom-6 right-6 rounded-full shadow-lg h-14 w-14 bg-primary hover:bg-primary/90"
|
||||||
size="icon"
|
size="icon"
|
||||||
>
|
>
|
||||||
<Eye className="h-4 w-4" />
|
<Eye className="h-5 w-5" />
|
||||||
</Button>
|
</Button>
|
||||||
</DrawerTrigger>
|
</DrawerTrigger>
|
||||||
<DrawerContent>
|
<DrawerContent className="h-[85vh]">
|
||||||
<DrawerHeader>
|
<DrawerHeader className="border-b">
|
||||||
<DrawerTitle>Agent Preview</DrawerTitle>
|
<DrawerTitle>Agent Preview</DrawerTitle>
|
||||||
</DrawerHeader>
|
</DrawerHeader>
|
||||||
<div className="flex-1 overflow-y-auto px-4 pb-4">
|
<div className="flex-1 overflow-y-auto p-4">
|
||||||
{previewAgent && <AgentPreview agent={previewAgent} />}
|
{previewAgent && <AgentPreview agent={previewAgent} />}
|
||||||
</div>
|
</div>
|
||||||
</DrawerContent>
|
</DrawerContent>
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { AgentBuilderChat } from '../agent-builder-chat';
|
||||||
|
|
||||||
|
interface AgentBuilderTabProps {
|
||||||
|
agentId: string;
|
||||||
|
displayData: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
system_prompt: string;
|
||||||
|
agentpress_tools: any;
|
||||||
|
configured_mcps: any[];
|
||||||
|
custom_mcps: any[];
|
||||||
|
is_default: boolean;
|
||||||
|
avatar: string;
|
||||||
|
avatar_color: string;
|
||||||
|
};
|
||||||
|
currentStyle: {
|
||||||
|
avatar: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
isViewingOldVersion: boolean;
|
||||||
|
onFieldChange: (field: string, value: any) => void;
|
||||||
|
onStyleChange: (emoji: string, color: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AgentBuilderTab({
|
||||||
|
agentId,
|
||||||
|
displayData,
|
||||||
|
currentStyle,
|
||||||
|
isViewingOldVersion,
|
||||||
|
onFieldChange,
|
||||||
|
onStyleChange,
|
||||||
|
}: AgentBuilderTabProps) {
|
||||||
|
if (isViewingOldVersion) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-center h-full">
|
||||||
|
<div className="text-center space-y-3 max-w-md px-6">
|
||||||
|
<div className="text-4xl opacity-50">🔒</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-base font-semibold text-foreground mb-1">Builder Unavailable</h3>
|
||||||
|
<p className="text-sm text-muted-foreground">
|
||||||
|
Only available for the current version. Please activate this version first.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="px-4 h-full">
|
||||||
|
<AgentBuilderChat
|
||||||
|
agentId={agentId}
|
||||||
|
formData={displayData}
|
||||||
|
handleFieldChange={onFieldChange}
|
||||||
|
handleStyleChange={onStyleChange}
|
||||||
|
currentStyle={currentStyle}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Sparkles, Settings } from 'lucide-react';
|
||||||
|
import { Tabs, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
||||||
|
import { EditableText } from '@/components/ui/editable';
|
||||||
|
import { StylePicker } from '../style-picker';
|
||||||
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
|
interface AgentHeaderProps {
|
||||||
|
agentId: string;
|
||||||
|
displayData: {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
};
|
||||||
|
currentStyle: {
|
||||||
|
avatar: string;
|
||||||
|
color: string;
|
||||||
|
};
|
||||||
|
activeTab: string;
|
||||||
|
isViewingOldVersion: boolean;
|
||||||
|
onFieldChange: (field: string, value: any) => void;
|
||||||
|
onStyleChange: (emoji: string, color: string) => void;
|
||||||
|
onTabChange: (value: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function AgentHeader({
|
||||||
|
agentId,
|
||||||
|
displayData,
|
||||||
|
currentStyle,
|
||||||
|
activeTab,
|
||||||
|
isViewingOldVersion,
|
||||||
|
onFieldChange,
|
||||||
|
onStyleChange,
|
||||||
|
onTabChange,
|
||||||
|
}: AgentHeaderProps) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<StylePicker
|
||||||
|
currentEmoji={currentStyle.avatar}
|
||||||
|
currentColor={currentStyle.color}
|
||||||
|
onStyleChange={onStyleChange}
|
||||||
|
agentId={agentId}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="h-9 w-9 rounded-lg flex items-center justify-center shadow-sm ring-1 ring-black/5 hover:ring-black/10 transition-all duration-200 cursor-pointer"
|
||||||
|
style={{ backgroundColor: currentStyle.color }}
|
||||||
|
>
|
||||||
|
<div className="text-lg font-medium">{currentStyle.avatar}</div>
|
||||||
|
</div>
|
||||||
|
</StylePicker>
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<EditableText
|
||||||
|
value={displayData.name}
|
||||||
|
onSave={(value) => onFieldChange('name', value)}
|
||||||
|
className="text-lg font-semibold bg-transparent text-foreground placeholder:text-muted-foreground"
|
||||||
|
placeholder="Agent name..."
|
||||||
|
disabled={isViewingOldVersion}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Tabs value={activeTab} onValueChange={onTabChange}>
|
||||||
|
<TabsList className="grid grid-cols-2 bg-muted/50 h-9">
|
||||||
|
<TabsTrigger
|
||||||
|
value="agent-builder"
|
||||||
|
disabled={isViewingOldVersion}
|
||||||
|
className={cn(
|
||||||
|
"flex items-center gap-2 text-sm data-[state=active]:bg-background data-[state=active]:shadow-sm",
|
||||||
|
isViewingOldVersion && "opacity-50 cursor-not-allowed"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<Sparkles className="h-3 w-3" />
|
||||||
|
Prompt to Build
|
||||||
|
</TabsTrigger>
|
||||||
|
<TabsTrigger
|
||||||
|
value="configuration"
|
||||||
|
className="flex items-center gap-2 text-sm data-[state=active]:bg-background data-[state=active]:shadow-sm"
|
||||||
|
>
|
||||||
|
<Settings className="h-3 w-3" />
|
||||||
|
Manual Config
|
||||||
|
</TabsTrigger>
|
||||||
|
</TabsList>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,197 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Settings, Wrench, Server, BookOpen, Workflow, Zap } from 'lucide-react';
|
||||||
|
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||||
|
import { ExpandableMarkdownEditor } from '@/components/ui/expandable-markdown-editor';
|
||||||
|
import { AgentToolsConfiguration } from '../agent-tools-configuration';
|
||||||
|
import { AgentMCPConfiguration } from '../agent-mcp-configuration';
|
||||||
|
import { AgentKnowledgeBaseManager } from '../knowledge-base/agent-knowledge-base-manager';
|
||||||
|
import { AgentWorkflowsConfiguration } from '../workflows/agent-workflows-configuration';
|
||||||
|
import { AgentTriggersConfiguration } from '../triggers/agent-triggers-configuration';
|
||||||
|
|
||||||
|
interface ConfigurationTabProps {
|
||||||
|
agentId: string;
|
||||||
|
displayData: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
system_prompt: string;
|
||||||
|
agentpress_tools: any;
|
||||||
|
configured_mcps: any[];
|
||||||
|
custom_mcps: any[];
|
||||||
|
is_default: boolean;
|
||||||
|
avatar: string;
|
||||||
|
avatar_color: string;
|
||||||
|
};
|
||||||
|
versionData?: {
|
||||||
|
version_id: string;
|
||||||
|
configured_mcps: any[];
|
||||||
|
custom_mcps: any[];
|
||||||
|
system_prompt: string;
|
||||||
|
agentpress_tools: any;
|
||||||
|
};
|
||||||
|
isViewingOldVersion: boolean;
|
||||||
|
onFieldChange: (field: string, value: any) => void;
|
||||||
|
onMCPChange: (updates: { configured_mcps: any[]; custom_mcps: any[] }) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ConfigurationTab({
|
||||||
|
agentId,
|
||||||
|
displayData,
|
||||||
|
versionData,
|
||||||
|
isViewingOldVersion,
|
||||||
|
onFieldChange,
|
||||||
|
onMCPChange,
|
||||||
|
}: ConfigurationTabProps) {
|
||||||
|
return (
|
||||||
|
<div className="p-4">
|
||||||
|
<Accordion type="single" collapsible defaultValue="system" className="space-y-2">
|
||||||
|
<AccordionItem
|
||||||
|
value="system"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<Settings className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">System Prompt</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Define agent behavior and goals</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<ExpandableMarkdownEditor
|
||||||
|
value={displayData.system_prompt}
|
||||||
|
onSave={(value) => onFieldChange('system_prompt', value)}
|
||||||
|
placeholder="Click to set system instructions..."
|
||||||
|
title="System Instructions"
|
||||||
|
disabled={isViewingOldVersion}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
value="tools"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<Wrench className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">Default Tools</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Configure default agentpress tools</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<AgentToolsConfiguration
|
||||||
|
tools={displayData.agentpress_tools}
|
||||||
|
onToolsChange={(tools) => onFieldChange('agentpress_tools', tools)}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
value="integrations"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<Server className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">Integrations</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Connect external services via MCPs</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<AgentMCPConfiguration
|
||||||
|
configuredMCPs={displayData.configured_mcps}
|
||||||
|
customMCPs={displayData.custom_mcps}
|
||||||
|
onMCPChange={onMCPChange}
|
||||||
|
agentId={agentId}
|
||||||
|
versionData={{
|
||||||
|
configured_mcps: displayData.configured_mcps,
|
||||||
|
custom_mcps: displayData.custom_mcps,
|
||||||
|
system_prompt: displayData.system_prompt,
|
||||||
|
agentpress_tools: displayData.agentpress_tools
|
||||||
|
}}
|
||||||
|
saveMode="callback"
|
||||||
|
versionId={versionData?.version_id}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
value="knowledge"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<BookOpen className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">Knowledge Base</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Upload and manage knowledge for the agent</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<AgentKnowledgeBaseManager
|
||||||
|
agentId={agentId}
|
||||||
|
agentName={displayData.name || 'Agent'}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
value="workflows"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<Workflow className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">Workflows</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Automate complex processes</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<AgentWorkflowsConfiguration
|
||||||
|
agentId={agentId}
|
||||||
|
agentName={displayData.name || 'Agent'}
|
||||||
|
/>
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
|
||||||
|
<AccordionItem
|
||||||
|
value="triggers"
|
||||||
|
className="rounded-xl hover:bg-muted/30 border transition-colors duration-200"
|
||||||
|
>
|
||||||
|
<AccordionTrigger className="hover:no-underline py-4 px-4 [&[data-state=open]]:pb-3">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="bg-muted rounded-lg h-9 w-9 flex items-center justify-center">
|
||||||
|
<Zap className="h-4 w-4" />
|
||||||
|
</div>
|
||||||
|
<div className="text-left">
|
||||||
|
<h4 className="font-medium text-sm text-gray-900 dark:text-gray-100">Triggers</h4>
|
||||||
|
<p className="text-xs text-gray-500 dark:text-gray-400">Set up automated agent runs</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionTrigger>
|
||||||
|
<AccordionContent className="px-4 pb-4">
|
||||||
|
<AgentTriggersConfiguration agentId={agentId} />
|
||||||
|
</AccordionContent>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
export { AgentHeader } from './agent-header';
|
||||||
|
export { VersionAlert } from './version-alert';
|
||||||
|
export { AgentBuilderTab } from './agent-builder-tab';
|
||||||
|
export { ConfigurationTab } from './configuration-tab';
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Eye, Check, Loader2, Info } from 'lucide-react';
|
||||||
|
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Button } from '@/components/ui/button';
|
||||||
|
|
||||||
|
interface VersionAlertProps {
|
||||||
|
versionData?: {
|
||||||
|
version_id: string;
|
||||||
|
version_name: string;
|
||||||
|
};
|
||||||
|
isActivating: boolean;
|
||||||
|
onActivateVersion: (versionId: string) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function VersionAlert({
|
||||||
|
versionData,
|
||||||
|
isActivating,
|
||||||
|
onActivateVersion,
|
||||||
|
}: VersionAlertProps) {
|
||||||
|
if (!versionData) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="mb-4 w-full bg-primary/5 border shadow-xs border-primary/10 p-2 rounded-xl">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<AlertDescription className="text-primary text-sm flex items-center gap-2 flex-1">
|
||||||
|
<Info className="h-4 w-4 text-primary" />
|
||||||
|
<span>You are viewing a read-only version of the agent</span>
|
||||||
|
</AlertDescription>
|
||||||
|
<Button variant="outline" size="sm" onClick={() => onActivateVersion(versionData.version_id)}>
|
||||||
|
Activate
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
Loading…
Reference in New Issue