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 { 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 { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert';
|
||||
import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerTrigger } from '@/components/ui/drawer';
|
||||
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 { useCreateAgentVersion, useActivateAgentVersion } from '@/hooks/react-query/agents/use-agent-versions';
|
||||
import { AgentMCPConfiguration } from '../../../../../components/agents/agent-mcp-configuration';
|
||||
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 { EditableText } from '@/components/ui/editable';
|
||||
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 { AgentPreview } from '../../../../../components/agents/agent-preview';
|
||||
import { AgentVersionSwitcher } from '@/components/agents/agent-version-switcher';
|
||||
import { CreateVersionButton } from '@/components/agents/create-version-button';
|
||||
import { useAgentVersionData } from '../../../../../hooks/use-agent-version-data';
|
||||
import { useAgentVersionStore } from '../../../../../lib/stores/agent-version-store';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
import { AgentHeader, VersionAlert, AgentBuilderTab, ConfigurationTab } from '@/components/agents/config';
|
||||
|
||||
interface FormData {
|
||||
name: string;
|
||||
|
@ -46,18 +37,13 @@ export default function AgentConfigurationPageRefactored() {
|
|||
const router = useRouter();
|
||||
const agentId = params.agentId as string;
|
||||
|
||||
// Use modular hooks
|
||||
const { agent, versionData, isViewingOldVersion, isLoading, error } = useAgentVersionData({ agentId });
|
||||
|
||||
// Debug logging
|
||||
console.log('[Agent Config] Loading state:', { isLoading, error, agentId });
|
||||
const { hasUnsavedChanges, setHasUnsavedChanges } = useAgentVersionStore();
|
||||
|
||||
const updateAgentMutation = useUpdateAgent();
|
||||
const createVersionMutation = useCreateAgentVersion();
|
||||
const activateVersionMutation = useActivateAgentVersion();
|
||||
|
||||
// State management
|
||||
const [formData, setFormData] = useState<FormData>({
|
||||
name: '',
|
||||
description: '',
|
||||
|
@ -73,30 +59,18 @@ export default function AgentConfigurationPageRefactored() {
|
|||
const [originalData, setOriginalData] = useState<FormData>(formData);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [isPreviewOpen, setIsPreviewOpen] = useState(false);
|
||||
const [isComparisonOpen, setIsComparisonOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState('agent-builder');
|
||||
|
||||
// Initialize form data from agent/version data
|
||||
useEffect(() => {
|
||||
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;
|
||||
|
||||
// If we have explicit version data (from URL param), use it
|
||||
if (versionData) {
|
||||
configSource = versionData;
|
||||
}
|
||||
// If no URL param but agent has current_version data, use that
|
||||
else if (agent.current_version) {
|
||||
configSource = agent.current_version;
|
||||
}
|
||||
|
||||
console.log('[Agent Config] Config source:', configSource);
|
||||
|
||||
const initialData: FormData = {
|
||||
name: agent.name || '',
|
||||
description: agent.description || '',
|
||||
|
@ -190,19 +164,16 @@ export default function AgentConfigurationPageRefactored() {
|
|||
}));
|
||||
}, [isViewingOldVersion]);
|
||||
|
||||
// Version activation handler
|
||||
const handleActivateVersion = useCallback(async (versionId: string) => {
|
||||
try {
|
||||
await activateVersionMutation.mutateAsync({ agentId, versionId });
|
||||
toast.success('Version activated successfully');
|
||||
// Refresh page without version param
|
||||
router.push(`/agents/config/${agentId}`);
|
||||
} catch (error) {
|
||||
toast.error('Failed to activate version');
|
||||
}
|
||||
}, [agentId, activateVersionMutation, router]);
|
||||
|
||||
// Auto-switch to configuration tab when viewing old versions
|
||||
useEffect(() => {
|
||||
if (isViewingOldVersion && activeTab === 'agent-builder') {
|
||||
setActiveTab('configuration');
|
||||
|
@ -212,7 +183,7 @@ export default function AgentConfigurationPageRefactored() {
|
|||
if (error) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen">
|
||||
<Alert variant="destructive">
|
||||
<Alert variant="destructive" className="max-w-md">
|
||||
<AlertDescription>
|
||||
{error.message || 'Failed to load agent configuration'}
|
||||
</AlertDescription>
|
||||
|
@ -224,7 +195,10 @@ export default function AgentConfigurationPageRefactored() {
|
|||
if (isLoading) {
|
||||
return (
|
||||
<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>
|
||||
);
|
||||
}
|
||||
|
@ -232,14 +206,13 @@ export default function AgentConfigurationPageRefactored() {
|
|||
if (!agent) {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen">
|
||||
<Alert>
|
||||
<Alert className="max-w-md">
|
||||
<AlertDescription>Agent not found</AlertDescription>
|
||||
</Alert>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
// Use version data when viewing old version, otherwise use form data
|
||||
const displayData = isViewingOldVersion && versionData ? {
|
||||
name: agent?.name || '',
|
||||
description: agent?.description || '',
|
||||
|
@ -263,12 +236,14 @@ export default function AgentConfigurationPageRefactored() {
|
|||
};
|
||||
|
||||
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="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="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">
|
||||
<AgentVersionSwitcher
|
||||
agentId={agentId}
|
||||
|
@ -300,225 +275,70 @@ export default function AgentConfigurationPageRefactored() {
|
|||
size="sm"
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="bg-primary hover:bg-primary/90 text-primary-foreground"
|
||||
>
|
||||
{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>
|
||||
)}
|
||||
</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 && (
|
||||
<Alert className="mb-4">
|
||||
<Eye className="h-4 w-4" />
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<AlertDescription>
|
||||
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}
|
||||
<VersionAlert
|
||||
versionData={versionData}
|
||||
isActivating={activateVersionMutation.isPending}
|
||||
onActivateVersion={handleActivateVersion}
|
||||
/>
|
||||
</div>
|
||||
<TabsList className="grid grid-cols-2">
|
||||
<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
|
||||
)}
|
||||
<AgentHeader
|
||||
agentId={agentId}
|
||||
formData={displayData}
|
||||
handleFieldChange={handleFieldChange}
|
||||
handleStyleChange={handleStyleChange}
|
||||
displayData={displayData}
|
||||
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>
|
||||
{activeTab === 'configuration' && (
|
||||
<div className='px-4'>
|
||||
<ExpandableMarkdownEditor
|
||||
value={displayData.system_prompt}
|
||||
onSave={(value) => handleFieldChange('system_prompt', value)}
|
||||
placeholder="Click to set system instructions..."
|
||||
title="System Instructions"
|
||||
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}
|
||||
<TabsContent value="configuration" className="flex-1 h-0 m-0 overflow-y-auto">
|
||||
<ConfigurationTab
|
||||
agentId={agentId}
|
||||
displayData={displayData}
|
||||
versionData={versionData}
|
||||
isViewingOldVersion={isViewingOldVersion}
|
||||
onFieldChange={handleFieldChange}
|
||||
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>
|
||||
</Tabs>
|
||||
</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} />}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="md:hidden flex flex-col h-full w-full">
|
||||
<div className="flex-1 overflow-y-auto p-4">
|
||||
|
@ -527,17 +347,17 @@ export default function AgentConfigurationPageRefactored() {
|
|||
<Drawer open={isPreviewOpen} onOpenChange={setIsPreviewOpen}>
|
||||
<DrawerTrigger asChild>
|
||||
<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"
|
||||
>
|
||||
<Eye className="h-4 w-4" />
|
||||
<Eye className="h-5 w-5" />
|
||||
</Button>
|
||||
</DrawerTrigger>
|
||||
<DrawerContent>
|
||||
<DrawerHeader>
|
||||
<DrawerContent className="h-[85vh]">
|
||||
<DrawerHeader className="border-b">
|
||||
<DrawerTitle>Agent Preview</DrawerTitle>
|
||||
</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} />}
|
||||
</div>
|
||||
</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