import { SyntheticEvent, useEffect, useRef, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { Route, Routes, useNavigate } from 'react-router-dom'; import userService from '../api/services/userService'; import Edit from '../assets/edit.svg'; import Link from '../assets/link-gray.svg'; import Monitoring from '../assets/monitoring.svg'; import Pin from '../assets/pin.svg'; import Trash from '../assets/red-trash.svg'; import Robot from '../assets/robot.svg'; import ThreeDots from '../assets/three-dots.svg'; import UnPin from '../assets/unpin.svg'; import ContextMenu, { MenuOption } from '../components/ContextMenu'; import Spinner from '../components/Spinner'; import { setConversation, updateConversationId, } from '../conversation/conversationSlice'; import ConfirmationModal from '../modals/ConfirmationModal'; import { ActiveState } from '../models/misc'; import { selectAgents, selectSelectedAgent, selectSharedAgents, selectToken, setAgents, setSelectedAgent, setSharedAgents, } from '../preferences/preferenceSlice'; import AgentLogs from './AgentLogs'; import NewAgent from './NewAgent'; import SharedAgent from './SharedAgent'; import { Agent } from './types'; export default function Agents() { return ( } /> } /> } /> } /> } /> ); } const sectionConfig = { user: { title: 'By me', description: 'Agents created or published by you', showNewAgentButton: true, emptyStateDescription: 'You don’t have any created agents yet', }, shared: { title: 'Shared with me', description: 'Agents imported by using a public link', showNewAgentButton: false, emptyStateDescription: 'No shared agents found', }, }; function AgentsList() { const dispatch = useDispatch(); const token = useSelector(selectToken); const agents = useSelector(selectAgents); const sharedAgents = useSelector(selectSharedAgents); const selectedAgent = useSelector(selectSelectedAgent); const [loadingUserAgents, setLoadingUserAgents] = useState(true); const [loadingSharedAgents, setLoadingSharedAgents] = useState(true); const getAgents = async () => { try { setLoadingUserAgents(true); const response = await userService.getAgents(token); if (!response.ok) throw new Error('Failed to fetch agents'); const data = await response.json(); dispatch(setAgents(data)); setLoadingUserAgents(false); } catch (error) { console.error('Error:', error); setLoadingUserAgents(false); } }; const getSharedAgents = async () => { try { setLoadingSharedAgents(true); const response = await userService.getSharedAgents(token); if (!response.ok) throw new Error('Failed to fetch shared agents'); const data = await response.json(); dispatch(setSharedAgents(data)); setLoadingSharedAgents(false); } catch (error) { console.error('Error:', error); setLoadingSharedAgents(false); } }; useEffect(() => { getAgents(); getSharedAgents(); dispatch(setConversation([])); dispatch( updateConversationId({ query: { conversationId: null }, }), ); if (selectedAgent) dispatch(setSelectedAgent(null)); }, [token]); return (

Agents

Discover and create custom versions of DocsGPT that combine instructions, extra knowledge, and any combination of skills

{/* Premade agents section */} {/*

Premade by DocsGPT

{Array.from({ length: 5 }, (_, index) => (
agent-logo

{}

{}

))}
*/} { dispatch(setAgents(updatedAgents)); }} loading={loadingUserAgents} section="user" /> { dispatch(setSharedAgents(updatedAgents)); }} loading={loadingSharedAgents} section="shared" />
); } function AgentSection({ agents, updateAgents, loading, section, }: { agents: Agent[]; updateAgents?: (agents: Agent[]) => void; loading: boolean; section: keyof typeof sectionConfig; }) { const navigate = useNavigate(); return (

{sectionConfig[section].title}

{sectionConfig[section].description}

{sectionConfig[section].showNewAgentButton && ( )}
{loading ? (
) : agents && agents.length > 0 ? (
{agents.map((agent, idx) => ( ))}
) : (

{sectionConfig[section].emptyStateDescription}

{sectionConfig[section].showNewAgentButton && ( )}
)}
); } function AgentCard({ agent, agents, updateAgents, section, }: { agent: Agent; agents: Agent[]; updateAgents?: (agents: Agent[]) => void; section: keyof typeof sectionConfig; }) { const navigate = useNavigate(); const dispatch = useDispatch(); const token = useSelector(selectToken); const [isMenuOpen, setIsMenuOpen] = useState(false); const [deleteConfirmation, setDeleteConfirmation] = useState('INACTIVE'); const menuRef = useRef(null); const togglePin = async () => { try { const response = await userService.togglePinAgent(agent.id ?? '', token); if (!response.ok) throw new Error('Failed to pin agent'); const updatedAgents = agents.map((prevAgent) => { if (prevAgent.id === agent.id) return { ...prevAgent, pinned: !prevAgent.pinned }; return prevAgent; }); updateAgents?.(updatedAgents); } catch (error) { console.error('Error:', error); } }; const handleHideSharedAgent = async () => { try { const response = await userService.removeSharedAgent( agent.id ?? '', token, ); if (!response.ok) throw new Error('Failed to hide shared agent'); const updatedAgents = agents.filter( (prevAgent) => prevAgent.id !== agent.id, ); updateAgents?.(updatedAgents); } catch (error) { console.error('Error:', error); } }; const menuOptionsConfig: Record = { user: [ { 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, }, ...(agent.status === 'published' ? [ { icon: agent.pinned ? UnPin : Pin, label: agent.pinned ? 'Unpin' : 'Pin agent', onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); }, variant: 'primary' as const, iconWidth: 18, iconHeight: 18, }, ] : []), { icon: Trash, label: 'Delete', onClick: (e: SyntheticEvent) => { e.stopPropagation(); setDeleteConfirmation('ACTIVE'); }, variant: 'danger', iconWidth: 13, iconHeight: 13, }, ], shared: [ { icon: Link, label: 'Open', onClick: (e: SyntheticEvent) => { e.stopPropagation(); navigate(`/agents/shared/${agent.shared_token}`); }, variant: 'primary', iconWidth: 12, iconHeight: 12, }, { icon: agent.pinned ? UnPin : Pin, label: agent.pinned ? 'Unpin' : 'Pin agent', onClick: (e: SyntheticEvent) => { e.stopPropagation(); togglePin(); }, variant: 'primary', iconWidth: 18, iconHeight: 18, }, { icon: Trash, label: 'Remove', onClick: (e: SyntheticEvent) => { e.stopPropagation(); handleHideSharedAgent(); }, variant: 'danger', iconWidth: 13, iconHeight: 13, }, ], }; const menuOptions = menuOptionsConfig[section] || []; const handleClick = () => { if (section === 'user') { if (agent.status === 'published') { dispatch(setSelectedAgent(agent)); navigate(`/`); } } if (section === 'shared') { navigate(`/agents/shared/${agent.shared_token}`); } }; 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(); dispatch(setAgents(agents.filter((prevAgent) => prevAgent.id !== data.id))); }; return (
{ e.stopPropagation(); handleClick(); }} >
{ e.stopPropagation(); setIsMenuOpen(true); }} className="absolute top-4 right-4 z-10 cursor-pointer" > {'use-agent'}
{`${agent.name}`} {agent.status === 'draft' && (

{`(Draft)`}

)}

{agent.name}

{agent.description}

{ handleDelete(agent.id || ''); setDeleteConfirmation('INACTIVE'); }} cancelLabel="Cancel" variant="danger" />
); }