diff --git a/src/interface/web/app/agents/page.tsx b/src/interface/web/app/agents/page.tsx index 800dcb16..3a7ce172 100644 --- a/src/interface/web/app/agents/page.tsx +++ b/src/interface/web/app/agents/page.tsx @@ -35,8 +35,10 @@ import { DotsThreeVertical, Pencil, Trash, + ArrowRight, + ArrowLeft, } from "@phosphor-icons/react"; -import { set, z } from "zod"; +import { set, z, ZodError } from "zod"; import { Card, CardContent, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"; import { Dialog, @@ -245,12 +247,18 @@ function AgentCard(props: AgentCardProps) { let agentsApiUrl = `/api/agents`; let method = props.editCard ? "PATCH" : "POST"; + let valuesToSend: any = values; + + if (props.editCard) { + valuesToSend = { ...values, slug: props.data.slug }; + } + fetch(agentsApiUrl, { method: method, headers: { "Content-Type": "application/json", }, - body: JSON.stringify(values), + body: JSON.stringify(valuesToSend), }) .then((response) => { if (response.status === 200) { @@ -537,9 +545,36 @@ function AgentModificationForm(props: AgentModificationFormProps) { const [progressValue, setProgressValue] = useState(0); const [uploadedFiles, setUploadedFiles] = useState([]); const [allFileOptions, setAllFileOptions] = useState([]); + const [currentStep, setCurrentStep] = useState(0); const [showSubscribeDialog, setShowSubscribeDialog] = useState(true); + const privacyOptions = ["public", "private", "protected"]; + + const basicFields = [ + { name: "name", label: "Name" }, + { name: "persona", label: "Personality" }, + ]; + + const advancedFields = [ + { name: "files", label: "Knowledge Base" }, + { name: "input_tools", label: "Input Tools" }, + { name: "output_modes", label: "Output Modes" }, + ]; + + const customizationFields = [ + { name: "color", label: "Color" }, + { name: "icon", label: "Icon" }, + { name: "chat_model", label: "Chat Model" }, + { name: "privacy_level", label: "Privacy Level" }, + ]; + + const formGroups = [ + { fields: basicFields, label: "Basic Settings" }, + { fields: customizationFields, label: "Customization & Access" }, + { fields: advancedFields, label: "Advanced Settings" }, + ]; + const fileInputRef = useRef(null); useEffect(() => { @@ -563,7 +598,9 @@ function AgentModificationForm(props: AgentModificationFormProps) { const currentFiles = props.form.getValues("files") || []; const fileOptions = props.filesOptions || []; const concatenatedFiles = [...currentFiles, ...fileOptions]; - setAllFileOptions((prev) => [...prev, ...concatenatedFiles]); + const fullAllFileOptions = [...allFileOptions, ...concatenatedFiles]; + const dedupedAllFileOptions = Array.from(new Set(fullAllFileOptions)); + setAllFileOptions(dedupedAllFileOptions); }, []); useEffect(() => { @@ -614,6 +651,25 @@ function AgentModificationForm(props: AgentModificationFormProps) { uploadFiles(event.target.files); } + const handleNext = (event: React.MouseEvent) => { + event.preventDefault(); + if (currentStep < formGroups.length - 1) { + setCurrentStep(currentStep + 1); + } + }; + + const handlePrevious = (event: React.MouseEvent) => { + event.preventDefault(); + if (currentStep > 0) { + setCurrentStep(currentStep - 1); + } + }; + + const handleSubmit = (values: any) => { + props.onSubmit(values); + setIsSaving(true); + }; + const handleAgentFileChange = (files: string[]) => { for (const file of files) { const currentFiles = props.form.getValues("files") || []; @@ -624,7 +680,30 @@ function AgentModificationForm(props: AgentModificationFormProps) { } }; - const privacyOptions = ["public", "private", "protected"]; + const areRequiredFieldsCompletedForCurrentStep = (formGroup: { + fields: { name: string }[]; + }) => { + try { + EditAgentSchema.parse(props.form.getValues()); + return true; + } catch (error) { + const errors: { [key: string]: string } = (error as ZodError).errors.reduce( + (acc: any, curr: any) => { + acc[curr.path[0]] = curr.message; + return acc; + }, + {}, + ); + + for (const field of formGroup.fields) { + if (errors[field.name]) { + return false; + } + } + + return true; + } + }; if (!props.isSubscribed && showSubscribeDialog) { return ( @@ -658,471 +737,570 @@ function AgentModificationForm(props: AgentModificationFormProps) { ); } - return ( -
- { - props.onSubmit(values); - setIsSaving(true); - })} - className="space-y-6" - > - ( - - Name - - What should this agent be called? Pick something descriptive & - memorable. - - - - - - - )} - /> - - ( - - Personality - - What is the personality, thought process, or tuning of this agent? - Get creative; this is how you can influence the agent constitution. - - -