"use client" import { ArrowsDownUp, CaretCircleDown, CircleNotch, Sparkle } from "@phosphor-icons/react"; import { Button } from "@/components/ui/button"; import { Sidebar, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarMenu, SidebarMenuButton, SidebarMenuItem } from "@/components/ui/sidebar"; import { Textarea } from "@/components/ui/textarea"; import { ModelSelector } from "@/app/common/modelSelector"; import { FilesMenu } from "../allConversations/allConversations"; import { AgentConfigurationOptions } from "@/app/agents/page"; import useSWR from "swr"; import { mutate } from "swr"; import { Sheet, SheetContent } from "@/components/ui/sheet"; import { AgentData } from "../agentCard/agentCard"; import { useEffect, useState } from "react"; import { getIconForSlashCommand, getIconFromIconName } from "@/app/common/iconUtils"; import { Label } from "@/components/ui/label"; import { Checkbox } from "@/components/ui/checkbox"; import { Tooltip, TooltipTrigger } from "@/components/ui/tooltip"; import { TooltipContent } from "@radix-ui/react-tooltip"; import { useAuthenticatedData } from "@/app/common/auth"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; interface ChatSideBarProps { conversationId: string; isOpen: boolean; isMobileWidth?: boolean; onOpenChange: (open: boolean) => void; } const fetcher = (url: string) => fetch(url).then((res) => res.json()); export function ChatSidebar({ ...props }: ChatSideBarProps) { if (props.isMobileWidth) { return ( ); } return (
); } function ChatSidebarInternal({ ...props }: ChatSideBarProps) { const [isEditable, setIsEditable] = useState(false); const { data: agentConfigurationOptions, error: agentConfigurationOptionsError } = useSWR("/api/agents/options", fetcher); const { data: agentData, isLoading: agentDataLoading, error: agentDataError } = useSWR(`/api/agents/conversation?conversation_id=${props.conversationId}`, fetcher); const { data: authenticatedData, error: authenticationError, isLoading: authenticationLoading, } = useAuthenticatedData(); const [customPrompt, setCustomPrompt] = useState(""); const [selectedModel, setSelectedModel] = useState(); const [inputTools, setInputTools] = useState(); const [outputModes, setOutputModes] = useState(); const [hasModified, setHasModified] = useState(false); const [isDefaultAgent, setIsDefaultAgent] = useState(agentData?.slug.toLowerCase() === "khoj" ? true : false); const [isSaving, setIsSaving] = useState(false); function setupAgentData() { if (agentData) { setInputTools(agentData.input_tools); if (agentData.input_tools === undefined || agentData.input_tools.length === 0) { setInputTools(agentConfigurationOptions?.input_tools ? Object.keys(agentConfigurationOptions.input_tools) : []); } setOutputModes(agentData.output_modes); if (agentData.output_modes === undefined || agentData.output_modes.length === 0) { setOutputModes(agentConfigurationOptions?.output_modes ? Object.keys(agentConfigurationOptions.output_modes) : []); } if (agentData.name.toLowerCase() === "khoj" || agentData.is_hidden === true) { setIsEditable(true); } if (agentData.slug.toLowerCase() === "khoj") { setSelectedModel(undefined); setCustomPrompt(undefined); setIsDefaultAgent(true); } else { setIsDefaultAgent(false); setCustomPrompt(agentData.persona); setSelectedModel(agentData.chat_model); } } } useEffect(() => { setupAgentData(); }, [agentData]); function isValueChecked(value: string, existingSelections: string[]): boolean { return existingSelections.includes(value); } function handleCheckToggle(value: string, existingSelections: string[]): string[] { setHasModified(true); if (existingSelections.includes(value)) { return existingSelections.filter((v) => v !== value); } return [...existingSelections, value]; } function handleCustomPromptChange(value: string) { setCustomPrompt(value); setHasModified(true); } function handleSave() { if (hasModified) { if (!isDefaultAgent && agentData?.is_hidden === false) { alert("This agent is not a hidden agent. It cannot be modified from this interface."); return; } let mode = "PATCH"; if (isDefaultAgent) { mode = "POST"; } const data = { persona: customPrompt, chat_model: selectedModel, input_tools: inputTools, output_modes: outputModes, ...(isDefaultAgent ? {} : { slug: agentData?.slug }) }; setIsSaving(true); const url = !isDefaultAgent ? `/api/agents/hidden` : `/api/agents/hidden?conversation_id=${props.conversationId}`; // There are four scenarios here. // 1. If the agent is a default agent, then we need to create a new agent just to associate with this conversation. // 2. If the agent is not a default agent, then we need to update the existing hidden agent. This will be associated using the `slug` field. // 3. If the agent is a "proper" agent and not a hidden agent, then it cannot be updated from this API. // 4. The API is being called before the new conversation has been provisioned. This is currently not supported. fetch(url, { method: mode, headers: { "Content-Type": "application/json" }, body: JSON.stringify(data) }) .then((res) => { setIsSaving(false); res.json() }) .then((data) => { mutate(`/api/agents/conversation?conversation_id=${props.conversationId}`); setHasModified(false); }) .catch((error) => { console.error("Error:", error); setIsSaving(false); }); } } function handleReset() { setupAgentData(); setHasModified(false); } function handleModelSelect(model: string, userModification: boolean = true) { setSelectedModel(model); if (userModification) { setHasModified(true); } } return ( { agentData && !isEditable ? ( ) : (
{getIconFromIconName("lightbulb", "orange")} Chat Options
) }
{ agentData && agentData.has_files ? (
Using custom knowledge base
) : null }
Instructions