feat: agents route replacing chatbots

- Removed API Keys tab from SettingsBar and adjusted tab layout.
- Improved styling for tab scrolling buttons and gradient indicators.
- Introduced AgentDetailsModal for displaying agent access details.
- Updated Analytics component to fetch agent data and handle analytics for selected agent.
- Refactored Logs component to accept agentId as a prop for filtering logs.
- Enhanced type definitions for InputProps to include textSize.
- Cleaned up unused imports and optimized component structure across various files.
This commit is contained in:
Siddhant Rai
2025-04-11 17:24:22 +05:30
parent 94c7bba168
commit fa1f9d7009
29 changed files with 2001 additions and 579 deletions

View File

@@ -0,0 +1,32 @@
import { useNavigate, useParams } from 'react-router-dom';
import ArrowLeft from '../assets/arrow-left.svg';
import Analytics from '../settings/Analytics';
import Logs from '../settings/Logs';
export default function AgentLogs() {
const navigate = useNavigate();
const { agentId } = useParams();
return (
<div className="p-4 md:p-12">
<div className="flex items-center gap-3 px-4">
<button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
onClick={() => navigate('/agents')}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<p className="mt-px text-sm font-semibold text-eerie-black dark:text-bright-gray">
Back to all agents
</p>
</div>
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
<h1 className="m-0 text-[40px] font-bold text-[#212121] dark:text-white">
Agent Logs
</h1>
</div>
<Analytics agentId={agentId} />
<Logs agentId={agentId} tableHeader="Agent endpoint logs" />
</div>
);
}

View File

@@ -0,0 +1,501 @@
import React, { useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { useNavigate, useParams } from 'react-router-dom';
import userService from '../api/services/userService';
import ArrowLeft from '../assets/arrow-left.svg';
import SourceIcon from '../assets/source.svg';
import Dropdown from '../components/Dropdown';
import MultiSelectPopup, { OptionType } from '../components/MultiSelectPopup';
import { ActiveState, Doc } from '../models/misc';
import { selectSourceDocs, selectToken } from '../preferences/preferenceSlice';
import { UserToolType } from '../settings/types';
import { Agent } from './types';
import ConfirmationModal from '../modals/ConfirmationModal';
import AgentDetailsModal from '../modals/AgentDetailsModal';
const embeddingsName =
import.meta.env.VITE_EMBEDDINGS_NAME ||
'huggingface_sentence-transformers/all-mpnet-base-v2';
export default function NewAgent({ mode }: { mode: 'new' | 'edit' | 'draft' }) {
const navigate = useNavigate();
const { agentId } = useParams();
const token = useSelector(selectToken);
const sourceDocs = useSelector(selectSourceDocs);
const [effectiveMode, setEffectiveMode] = useState(mode);
const [agent, setAgent] = useState<Agent>({
id: agentId || '',
name: '',
description: '',
image: '',
source: '',
chunks: '',
retriever: '',
prompt_id: '',
tools: [],
agent_type: '',
status: '',
});
const [prompts, setPrompts] = useState<
{ name: string; id: string; type: string }[]
>([]);
const [userTools, setUserTools] = useState<OptionType[]>([]);
const [isSourcePopupOpen, setIsSourcePopupOpen] = useState(false);
const [isToolsPopupOpen, setIsToolsPopupOpen] = useState(false);
const [selectedSourceIds, setSelectedSourceIds] = useState<
Set<string | number>
>(new Set());
const [selectedToolIds, setSelectedToolIds] = useState<Set<string | number>>(
new Set(),
);
const [deleteConfirmation, setDeleteConfirmation] =
useState<ActiveState>('INACTIVE');
const [agentDetails, setAgentDetails] = useState<ActiveState>('INACTIVE');
const sourceAnchorButtonRef = useRef<HTMLButtonElement>(null);
const toolAnchorButtonRef = useRef<HTMLButtonElement>(null);
const modeConfig = {
new: {
heading: 'New Agent',
buttonText: 'Create Agent',
showDelete: false,
showSaveDraft: true,
showLogs: false,
showAccessDetails: false,
},
edit: {
heading: 'Edit Agent',
buttonText: 'Save Changes',
showDelete: true,
showSaveDraft: false,
showLogs: true,
showAccessDetails: true,
},
draft: {
heading: 'New Agent (Draft)',
buttonText: 'Publish Draft',
showDelete: true,
showSaveDraft: true,
showLogs: false,
showAccessDetails: false,
},
};
const chunks = ['0', '2', '4', '6', '8', '10'];
const agentTypes = [
{ label: 'Classic', value: 'classic' },
{ label: 'ReAct', value: 'react' },
];
const isPublishable = () => {
return (
agent.name &&
agent.description &&
(agent.source || agent.retriever) &&
agent.chunks &&
agent.prompt_id &&
agent.agent_type
);
};
const handleCancel = () => navigate('/agents');
const handleDelete = async (agentId: string) => {
const response = await userService.deleteAgent(agentId, token);
if (!response.ok) throw new Error('Failed to delete agent');
navigate('/agents');
};
const handleSaveDraft = async () => {
const response =
effectiveMode === 'new'
? await userService.createAgent({ ...agent, status: 'draft' }, token)
: await userService.updateAgent(
agent.id || '',
{ ...agent, status: 'draft' },
token,
);
if (!response.ok) throw new Error('Failed to create agent draft');
const data = await response.json();
if (effectiveMode === 'new') {
setEffectiveMode('draft');
setAgent((prev) => ({ ...prev, id: data.id }));
}
};
const handlePublish = async () => {
const response =
effectiveMode === 'new'
? await userService.createAgent(
{ ...agent, status: 'published' },
token,
)
: await userService.updateAgent(
agent.id || '',
{ ...agent, status: 'published' },
token,
);
if (!response.ok) throw new Error('Failed to publish agent');
const data = await response.json();
if (data.key) setAgent((prev) => ({ ...prev, key: data.key }));
if (effectiveMode === 'new') setAgentDetails('ACTIVE');
};
useEffect(() => {
const getTools = async () => {
const response = await userService.getUserTools(token);
if (!response.ok) throw new Error('Failed to fetch tools');
const data = await response.json();
const tools: OptionType[] = data.tools.map((tool: UserToolType) => ({
id: tool.id,
label: tool.displayName,
icon: `/toolIcons/tool_${tool.name}.svg`,
}));
setUserTools(tools);
};
const getPrompts = async () => {
const response = await userService.getPrompts(token);
if (!response.ok) {
throw new Error('Failed to fetch prompts');
}
const data = await response.json();
setPrompts(data);
};
getTools();
getPrompts();
}, [token]);
useEffect(() => {
if ((mode === 'edit' || mode === 'draft') && agentId) {
const getAgent = async () => {
const response = await userService.getAgent(agentId, token);
if (!response.ok) {
navigate('/agents');
throw new Error('Failed to fetch agent');
}
const data = await response.json();
if (data.source) setSelectedSourceIds(new Set([data.source]));
else if (data.retriever)
setSelectedSourceIds(new Set([data.retriever]));
if (data.tools) setSelectedToolIds(new Set(data.tools));
if (data.status === 'draft') setEffectiveMode('draft');
setAgent(data);
};
getAgent();
}
}, [agentId, mode, token]);
useEffect(() => {
const selectedSource = Array.from(selectedSourceIds).map((id) =>
sourceDocs?.find(
(source) =>
source.id === id || source.retriever === id || source.name === id,
),
);
if (selectedSource[0]?.model === embeddingsName) {
if (selectedSource[0] && 'id' in selectedSource[0]) {
setAgent((prev) => ({
...prev,
source: selectedSource[0]?.id || 'default',
retriever: '',
}));
} else
setAgent((prev) => ({
...prev,
source: '',
retriever: selectedSource[0]?.retriever || 'classic',
}));
}
}, [selectedSourceIds]);
useEffect(() => {
const selectedTool = Array.from(selectedToolIds).map((id) =>
userTools.find((tool) => tool.id === id),
);
setAgent((prev) => ({
...prev,
tools: selectedTool
.map((tool) => tool?.id)
.filter((id): id is string => typeof id === 'string'),
}));
}, [selectedToolIds]);
return (
<div className="p-4 md:p-12">
<div className="flex items-center gap-3 px-4">
<button
className="rounded-full border p-3 text-sm text-gray-400 dark:border-0 dark:bg-[#28292D] dark:text-gray-500 dark:hover:bg-[#2E2F34]"
onClick={() => navigate('/agents')}
>
<img src={ArrowLeft} alt="left-arrow" className="h-3 w-3" />
</button>
<p className="mt-px text-sm font-semibold text-eerie-black dark:text-bright-gray">
Back to all agents
</p>
</div>
<div className="mt-5 flex w-full flex-wrap items-center justify-between gap-2 px-4">
<h1 className="m-0 text-[40px] font-bold text-[#212121] dark:text-white">
{modeConfig[effectiveMode].heading}
</h1>
<div className="flex flex-wrap items-center gap-1">
<button
className="mr-4 rounded-3xl py-2 text-sm font-medium text-purple-30 dark:bg-transparent dark:text-light-gray"
onClick={handleCancel}
>
Cancel
</button>
{modeConfig[effectiveMode].showDelete && agent.id && (
<button
className="group flex items-center gap-2 rounded-3xl border border-solid border-red-2000 px-5 py-2 text-sm font-medium text-red-2000 transition-colors hover:bg-red-2000 hover:text-white"
onClick={() => setDeleteConfirmation('ACTIVE')}
>
<span className="block h-4 w-4 bg-[url('/src/assets/red-trash.svg')] bg-contain bg-center bg-no-repeat transition-all group-hover:bg-[url('/src/assets/white-trash.svg')]" />
Delete
</button>
)}
{modeConfig[effectiveMode].showSaveDraft && (
<button
className="hover:bg-vi</button>olets-are-blue rounded-3xl border border-solid border-violets-are-blue px-5 py-2 text-sm font-medium text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
onClick={handleSaveDraft}
>
Save Draft
</button>
)}
{modeConfig[effectiveMode].showAccessDetails && (
<button
className="hover:bg-vi</button>olets-are-blue rounded-3xl border border-solid border-violets-are-blue px-5 py-2 text-sm font-medium text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
onClick={() => navigate(`/agents/logs/${agent.id}`)}
>
Logs
</button>
)}
{modeConfig[effectiveMode].showAccessDetails && (
<button
className="hover:bg-vi</button>olets-are-blue rounded-3xl border border-solid border-violets-are-blue px-5 py-2 text-sm font-medium text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white"
onClick={() => setAgentDetails('ACTIVE')}
>
Access Details
</button>
)}
<button
disabled={!isPublishable()}
className={`${!isPublishable() && 'cursor-not-allowed opacity-30'} rounded-3xl bg-purple-30 px-5 py-2 text-sm font-medium text-white hover:bg-violets-are-blue`}
onClick={handlePublish}
>
Publish
</button>
</div>
</div>
<div className="mt-5 flex w-full grid-cols-5 flex-col gap-10 min-[1024px]:grid min-[1024px]:gap-5">
<div className="col-span-2 flex flex-col gap-5">
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Meta</h2>
<input
className="mt-3 w-full rounded-3xl border border-silver bg-white px-5 py-3 text-sm text-jet outline-none placeholder:text-gray-400 dark:border-[#7E7E7E] dark:bg-[#222327] dark:text-bright-gray placeholder:dark:text-silver"
type="text"
value={agent.name}
placeholder="Agent name"
onChange={(e) => setAgent({ ...agent, name: e.target.value })}
/>
<textarea
className="mt-3 h-32 w-full rounded-3xl border border-silver bg-white px-5 py-4 text-sm text-jet outline-none placeholder:text-gray-400 dark:border-[#7E7E7E] dark:bg-[#222327] dark:text-bright-gray placeholder:dark:text-silver"
placeholder="Describe your agent"
value={agent.description}
onChange={(e) =>
setAgent({ ...agent, description: e.target.value })
}
/>
</div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Source</h2>
<div className="mt-3">
<div className="flex flex-wrap items-center gap-1">
<button
ref={sourceAnchorButtonRef}
onClick={() => setIsSourcePopupOpen(!isSourcePopupOpen)}
className="w-full truncate rounded-3xl border border-silver bg-white px-5 py-3 text-left text-sm text-gray-400 dark:border-[#7E7E7E] dark:bg-[#222327] dark:text-silver"
>
{selectedSourceIds.size > 0
? Array.from(selectedSourceIds)
.map(
(id) =>
sourceDocs?.find(
(source) =>
source.id === id ||
source.name === id ||
source.retriever === id,
)?.name,
)
.filter(Boolean)
.join(', ')
: 'Select source'}
</button>
<MultiSelectPopup
isOpen={isSourcePopupOpen}
onClose={() => setIsSourcePopupOpen(false)}
anchorRef={sourceAnchorButtonRef}
options={
sourceDocs?.map((doc: Doc) => ({
id: doc.id || doc.retriever || doc.name,
label: doc.name,
icon: SourceIcon,
})) || []
}
selectedIds={selectedSourceIds}
onSelectionChange={(newSelectedIds: Set<string | number>) => {
setSelectedSourceIds(newSelectedIds);
setIsSourcePopupOpen(false);
}}
title="Select Source"
searchPlaceholder="Search sources..."
noOptionsMessage="No source available"
singleSelect={true}
/>
</div>
<div className="mt-3">
<Dropdown
options={chunks}
selectedValue={agent.chunks ? agent.chunks : null}
onSelect={(value: string) =>
setAgent({ ...agent, chunks: value })
}
size="w-full"
rounded="3xl"
buttonDarkBackgroundColor="[#222327]"
border="border"
darkBorderColor="[#7E7E7E]"
placeholder="Chunks per query"
placeholderTextColor="gray-400"
darkPlaceholderTextColor="silver"
contentSize="text-sm"
/>
</div>
</div>
</div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Prompt</h2>
<div className="mt-3 flex flex-wrap items-center gap-1">
<div className="min-w-20 flex-grow basis-full sm:basis-0">
<Dropdown
options={prompts.map((prompt) => ({
label: prompt.name,
value: prompt.id,
}))}
selectedValue={
agent.prompt_id
? prompts.filter(
(prompt) => prompt.id === agent.prompt_id,
)[0].name || null
: null
}
onSelect={(option: { label: string; value: string }) =>
setAgent({ ...agent, prompt_id: option.value })
}
size="w-full"
rounded="3xl"
buttonDarkBackgroundColor="[#222327]"
border="border"
darkBorderColor="[#7E7E7E]"
placeholder="Select a prompt"
placeholderTextColor="gray-400"
darkPlaceholderTextColor="silver"
contentSize="text-sm"
/>
</div>
<button className="w-20 flex-shrink-0 basis-full rounded-3xl border-2 border-solid border-violets-are-blue px-5 py-[11px] text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white sm:basis-auto">
Add
</button>
</div>
</div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Tools</h2>
<div className="mt-3 flex flex-wrap items-center gap-1">
<button
ref={toolAnchorButtonRef}
onClick={() => setIsToolsPopupOpen(!isToolsPopupOpen)}
className="w-full truncate rounded-3xl border border-silver bg-white px-5 py-3 text-left text-sm text-gray-400 dark:border-[#7E7E7E] dark:bg-[#222327] dark:text-silver"
>
{selectedToolIds.size > 0
? Array.from(selectedToolIds)
.map(
(id) => userTools.find((tool) => tool.id === id)?.label,
)
.filter(Boolean)
.join(', ')
: 'Select tools'}
</button>
<MultiSelectPopup
isOpen={isToolsPopupOpen}
onClose={() => setIsToolsPopupOpen(false)}
anchorRef={toolAnchorButtonRef}
options={userTools}
selectedIds={selectedToolIds}
onSelectionChange={(newSelectedIds: Set<string | number>) =>
setSelectedToolIds(newSelectedIds)
}
title="Select Tools"
searchPlaceholder="Search tools..."
noOptionsMessage="No tools available"
/>
</div>
</div>
<div className="rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Agent type</h2>
<div className="mt-3">
<Dropdown
options={agentTypes}
selectedValue={
agent.agent_type
? agentTypes.find((type) => type.value === agent.agent_type)
?.label || null
: null
}
onSelect={(option: { label: string; value: string }) =>
setAgent({ ...agent, agent_type: option.value })
}
size="w-full"
rounded="3xl"
buttonDarkBackgroundColor="[#222327]"
border="border"
darkBorderColor="[#7E7E7E]"
placeholder="Select type"
placeholderTextColor="gray-400"
darkPlaceholderTextColor="silver"
contentSize="text-sm"
/>
</div>
</div>
</div>
<div className="col-span-3 flex flex-col gap-3 rounded-[30px] bg-[#F6F6F6] px-6 py-3 dark:bg-[#383838] dark:text-[#E0E0E0]">
<h2 className="text-lg font-semibold">Preview</h2>
<AgentPreview />
</div>
</div>
<ConfirmationModal
message="Are you sure you want to delete this agent?"
modalState={deleteConfirmation}
setModalState={setDeleteConfirmation}
submitLabel="Delete"
handleSubmit={() => {
handleDelete(agent.id || '');
setDeleteConfirmation('INACTIVE');
}}
cancelLabel="Cancel"
variant="danger"
/>
<AgentDetailsModal
agent={agent}
mode={effectiveMode}
modalState={agentDetails}
setModalState={setAgentDetails}
/>
</div>
);
}
function AgentPreview() {
return (
<div className="h-full w-full rounded-[30px] border border-[#F6F6F6] bg-white dark:border-[#7E7E7E] dark:bg-[#222327] max-[1024px]:min-h-[48rem]"></div>
);
}

View File

@@ -0,0 +1,230 @@
import React, { SyntheticEvent, useEffect, useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { Route, Routes, useNavigate } from 'react-router-dom';
import userService from '../api/services/userService';
import Copy from '../assets/copy-linear.svg';
import Edit from '../assets/edit.svg';
import Monitoring from '../assets/monitoring.svg';
import Trash from '../assets/red-trash.svg';
import Robot from '../assets/robot.svg';
import ThreeDots from '../assets/three-dots.svg';
import ContextMenu, { MenuOption } from '../components/ContextMenu';
import ConfirmationModal from '../modals/ConfirmationModal';
import { ActiveState } from '../models/misc';
import { selectToken } from '../preferences/preferenceSlice';
import AgentLogs from './AgentLogs';
import NewAgent from './NewAgent';
import { Agent } from './types';
export default function Agents() {
return (
<Routes>
<Route path="/" element={<AgentsList />} />
<Route path="/new" element={<NewAgent mode="new" />} />
<Route path="/edit/:agentId" element={<NewAgent mode="edit" />} />
<Route path="/logs/:agentId" element={<AgentLogs />} />
</Routes>
);
}
function AgentsList() {
const navigate = useNavigate();
const token = useSelector(selectToken);
const [userAgents, setUserAgents] = useState<Agent[]>([]);
useEffect(() => {
const getAgents = async () => {
const response = await userService.getAgents(token);
if (!response.ok) throw new Error('Failed to fetch agents');
const data = await response.json();
setUserAgents(data);
};
getAgents();
}, [token]);
return (
<div className="p-4 md:p-12">
<h1 className="mb-0 text-[40px] font-bold text-[#212121] dark:text-[#E0E0E0]">
Agents
</h1>
<p className="mt-5 text-[15px] text-[#71717A] dark:text-[#949494]">
Discover and create custom versions of DocsGPT that combine
instructions, extra knowledge, and any combination of skills.
</p>
{/* <div className="mt-6">
<h2 className="text-[18px] font-semibold text-[#18181B] dark:text-[#E0E0E0]">
Premade by DocsGPT
</h2>
<div className="mt-4 flex w-full flex-wrap gap-4">
{Array.from({ length: 5 }, (_, index) => (
<div
key={index}
className="relative flex h-44 w-48 flex-col justify-between rounded-[1.2rem] bg-[#F6F6F6] px-6 py-5 dark:bg-[#383838]"
>
<button onClick={() => {}} className="absolute right-4 top-4">
<img
src={Copy}
alt={'use-agent'}
className="h-[19px] w-[19px]"
/>
</button>
<div className="w-full">
<div className="flex w-full items-center px-1">
<img
src={Robot}
alt="agent-logo"
className="h-7 w-7 rounded-full"
/>
</div>
<div className="mt-2">
<p
title={''}
className="truncate px-1 text-[13px] font-semibold capitalize leading-relaxed text-raisin-black-light dark:text-bright-gray"
>
{}
</p>
<p className="mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed text-old-silver dark:text-sonic-silver-light">
{}
</p>
</div>
</div>
<div className="absolute bottom-4 right-4"></div>
</div>
))}
</div>
</div> */}
<div className="mt-8 flex flex-col gap-4">
<div className="flex w-full items-center justify-between">
<h2 className="text-[18px] font-semibold text-[#18181B] dark:text-[#E0E0E0]">
Created by You
</h2>
<button
className="rounded-full bg-purple-30 px-4 py-2 text-sm text-white hover:bg-violets-are-blue"
onClick={() => navigate('/agents/new')}
>
New Agent
</button>
</div>
<div className="flex w-full flex-wrap gap-4">
{userAgents.map((agent, idx) => (
<AgentCard key={idx} agent={agent} setUserAgents={setUserAgents} />
))}
</div>
</div>
</div>
);
}
function AgentCard({
agent,
setUserAgents,
}: {
agent: Agent;
setUserAgents: React.Dispatch<React.SetStateAction<Agent[]>>;
}) {
const navigate = useNavigate();
const token = useSelector(selectToken);
const menuRef = useRef<HTMLDivElement>(null);
const [isMenuOpen, setIsMenuOpen] = useState<boolean>(false);
const [deleteConfirmation, setDeleteConfirmation] =
useState<ActiveState>('INACTIVE');
const menuOptions: MenuOption[] = [
{
icon: Monitoring,
label: 'Logs',
onClick: (e: SyntheticEvent) => {
e.stopPropagation();
navigate(`/agents/logs/${agent.id}`);
},
variant: 'primary',
iconWidth: 14,
iconHeight: 14,
},
{
icon: Edit,
label: 'Edit',
onClick: (e: SyntheticEvent) => {
e.stopPropagation();
navigate(`/agents/edit/${agent.id}`);
},
variant: 'primary',
iconWidth: 14,
iconHeight: 14,
},
{
icon: Trash,
label: 'Delete',
onClick: () => setDeleteConfirmation('ACTIVE'),
variant: 'danger',
iconWidth: 12,
iconHeight: 12,
},
];
const handleDelete = async (agentId: string) => {
const response = await userService.deleteAgent(agentId, token);
if (!response.ok) throw new Error('Failed to delete agent');
const data = await response.json();
setUserAgents((prevAgents) =>
prevAgents.filter((prevAgent) => prevAgent.id !== data.id),
);
};
return (
<div className="relative flex h-44 w-48 flex-col justify-between rounded-[1.2rem] bg-[#F6F6F6] px-6 py-5 dark:bg-[#383838]">
<div
ref={menuRef}
onClick={() => {
setIsMenuOpen(true);
}}
className="absolute right-4 top-4 cursor-pointer"
>
<img src={ThreeDots} alt={'use-agent'} className="h-[19px] w-[19px]" />
<ContextMenu
isOpen={isMenuOpen}
setIsOpen={setIsMenuOpen}
options={menuOptions}
anchorRef={menuRef}
position="top-right"
offset={{ x: 0, y: 0 }}
/>
</div>
<div className="w-full">
<div className="flex w-full items-center gap-1 px-1">
<img
src={agent.image ?? Robot}
alt={`${agent.name}`}
className="h-7 w-7 rounded-full"
/>
{agent.status === 'draft' && (
<p className="text-xs text-black opacity-50 dark:text-[#E0E0E0]">{`(Draft)`}</p>
)}
</div>
<div className="mt-2">
<p
title={agent.name}
className="truncate px-1 text-[13px] font-semibold capitalize leading-relaxed text-[#020617] dark:text-[#E0E0E0]"
>
{agent.name}
</p>
<p className="mt-1 h-20 overflow-auto px-1 text-[12px] leading-relaxed text-[#64748B] dark:text-sonic-silver-light">
{agent.description}
</p>
</div>
</div>
<ConfirmationModal
message="Are you sure you want to delete this agent?"
modalState={deleteConfirmation}
setModalState={setDeleteConfirmation}
submitLabel="Delete"
handleSubmit={() => {
handleDelete(agent.id || '');
setDeleteConfirmation('INACTIVE');
}}
cancelLabel="Cancel"
variant="danger"
/>
</div>
);
}

View File

@@ -0,0 +1,14 @@
export type Agent = {
id?: string;
name: string;
description: string;
image: string;
source: string;
chunks: string;
retriever: string;
prompt_id: string;
tools: string[];
agent_type: string;
status: string;
key?: string;
};