'use client'
import { Button } from '@/components/ui/button'
import { AgentSelector } from '@/components/playground/Sidebar/AgentSelector'
import useChatActions from '@/hooks/useChatActions'
import { usePlaygroundStore } from '@/store'
import { motion, AnimatePresence } from 'framer-motion'
import { useState, useEffect } from 'react'
import Icon from '@/components/ui/icon'
import { getProviderIcon } from '@/lib/modelProvider'
import Sessions from './Sessions'
import { isValidUrl } from '@/lib/utils'
import { toast } from 'sonner'
import { useQueryState } from 'nuqs'
import { truncateText } from '@/lib/utils'
import { Skeleton } from '@/components/ui/skeleton'
const ENDPOINT_PLACEHOLDER = 'NO ENDPOINT ADDED'
const SidebarHeader = () => (
Agent UI
)
const NewChatButton = ({
disabled,
onClick
}: {
disabled: boolean
onClick: () => void
}) => (
)
const ModelDisplay = ({ model }: { model: string }) => (
{(() => {
const icon = getProviderIcon(model)
return icon ? : null
})()}
{model}
)
const Endpoint = () => {
const {
selectedEndpoint,
isEndpointActive,
setSelectedEndpoint,
setAgents,
setSessionsData,
setMessages
} = usePlaygroundStore()
const { initializePlayground } = useChatActions()
const [isEditing, setIsEditing] = useState(false)
const [endpointValue, setEndpointValue] = useState('')
const [isMounted, setIsMounted] = useState(false)
const [isHovering, setIsHovering] = useState(false)
const [isRotating, setIsRotating] = useState(false)
const [, setAgentId] = useQueryState('agent')
const [, setSessionId] = useQueryState('session')
useEffect(() => {
setEndpointValue(selectedEndpoint)
setIsMounted(true)
}, [selectedEndpoint])
const getStatusColor = (isActive: boolean) =>
isActive ? 'bg-positive' : 'bg-destructive'
const handleSave = async () => {
if (!isValidUrl(endpointValue)) {
toast.error('Please enter a valid URL')
return
}
const cleanEndpoint = endpointValue.replace(/\/$/, '').trim()
setSelectedEndpoint(cleanEndpoint)
setAgentId(null)
setSessionId(null)
setIsEditing(false)
setIsHovering(false)
setAgents([])
setSessionsData([])
setMessages([])
}
const handleCancel = () => {
setEndpointValue(selectedEndpoint)
setIsEditing(false)
setIsHovering(false)
}
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key === 'Enter') {
handleSave()
} else if (e.key === 'Escape') {
handleCancel()
}
}
const handleRefresh = async () => {
setIsRotating(true)
await initializePlayground()
setTimeout(() => setIsRotating(false), 500)
}
return (
Endpoint
{isEditing ? (
setEndpointValue(e.target.value)}
onKeyDown={handleKeyDown}
className="flex h-9 w-full items-center text-ellipsis rounded-xl border border-primary/15 bg-accent p-3 text-xs font-medium text-muted"
autoFocus
/>
) : (
setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
onClick={() => setIsEditing(true)}
transition={{ type: 'spring', stiffness: 400, damping: 10 }}
>
{isHovering ? (
EDIT ENDPOINT
) : (
{isMounted
? truncateText(selectedEndpoint, 21) ||
ENDPOINT_PLACEHOLDER
: 'http://localhost:7777'}
)}
)}
)
}
const Sidebar = () => {
const [isCollapsed, setIsCollapsed] = useState(false)
const { clearChat, focusChatInput, initializePlayground } = useChatActions()
const {
messages,
selectedEndpoint,
isEndpointActive,
selectedModel,
hydrated,
isEndpointLoading
} = usePlaygroundStore()
const [isMounted, setIsMounted] = useState(false)
const [agentId] = useQueryState('agent')
useEffect(() => {
setIsMounted(true)
if (hydrated) initializePlayground()
}, [selectedEndpoint, initializePlayground, hydrated])
const handleNewChat = () => {
clearChat()
focusChatInput()
}
return (
setIsCollapsed(!isCollapsed)}
className="absolute right-2 top-2 z-10 p-1"
aria-label={isCollapsed ? 'Expand sidebar' : 'Collapse sidebar'}
type="button"
whileTap={{ scale: 0.95 }}
>
{isMounted && (
<>
{isEndpointActive && (
<>
Agent
{isEndpointLoading ? (
{Array.from({ length: 2 }).map((_, index) => (
))}
) : (
<>
{selectedModel && agentId && (
)}
>
)}
>
)}
>
)}
)
}
export default Sidebar