156 lines
6.4 KiB
TypeScript
156 lines
6.4 KiB
TypeScript
import { mdiArrowLeft, mdiRobotOutline } from '@mdi/js';
|
|
import Head from 'next/head';
|
|
import Link from 'next/link';
|
|
import React, { ReactElement } from 'react';
|
|
import { Form, Formik } from 'formik';
|
|
|
|
import AgentFormSections from '../../components/Agents/AgentFormSections';
|
|
import BaseIcon from '../../components/BaseIcon';
|
|
import SectionMain from '../../components/SectionMain';
|
|
import { getPageTitle } from '../../config';
|
|
import LayoutAuthenticated from '../../layouts/Authenticated';
|
|
import { create } from '../../stores/agents/agentsSlice';
|
|
import { useAppDispatch } from '../../stores/hooks';
|
|
import { useRouter } from 'next/router';
|
|
|
|
const actionButtonClassName =
|
|
'inline-flex items-center justify-center rounded-[8px] border px-4 py-2 text-sm font-medium';
|
|
|
|
const initialValues = {
|
|
description: '',
|
|
is_active: true,
|
|
is_default: false,
|
|
max_output_tokens: '',
|
|
metadata_json: '',
|
|
model: '',
|
|
name: '',
|
|
system_prompt: '',
|
|
temperature: '',
|
|
};
|
|
|
|
function getPreviewName(values: typeof initialValues) {
|
|
if (values.name) {
|
|
return values.name;
|
|
}
|
|
|
|
return 'Untitled agent';
|
|
}
|
|
|
|
const AgentsNew = () => {
|
|
const router = useRouter();
|
|
const dispatch = useAppDispatch();
|
|
|
|
const handleSubmit = async (data: typeof initialValues) => {
|
|
await dispatch(create(data));
|
|
await router.push('/agents/agents-list');
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>{getPageTitle('New agent')}</title>
|
|
</Head>
|
|
<SectionMain>
|
|
<Formik initialValues={initialValues} onSubmit={(values) => handleSubmit(values)}>
|
|
{({ isSubmitting, setFieldValue, values }) => {
|
|
const previewName = getPreviewName(values);
|
|
|
|
return (
|
|
<Form>
|
|
<div className="flex w-full flex-col gap-5">
|
|
<div className="rounded-[12px] border border-slate-200 bg-white px-6 py-6">
|
|
<Link
|
|
className="inline-flex items-center gap-2 text-[12px] font-medium text-slate-500"
|
|
href="/agents/agents-list"
|
|
>
|
|
<BaseIcon path={mdiArrowLeft} size={14} />
|
|
Back to agents
|
|
</Link>
|
|
<p className="mt-4 text-[11px] font-medium uppercase tracking-[0.28em] text-slate-400">
|
|
Agent
|
|
</p>
|
|
<h1 className="mt-3 text-[2rem] font-semibold tracking-[-0.04em] text-slate-900">
|
|
Create a reusable assistant profile.
|
|
</h1>
|
|
<p className="mt-3 max-w-2xl text-sm leading-6 text-slate-500">
|
|
Define how this agent should behave, what model it should use, and whether it belongs in the default workspace lineup.
|
|
</p>
|
|
</div>
|
|
|
|
<div className="grid gap-5 2xl:grid-cols-[minmax(0,1fr)_320px]">
|
|
<div className="space-y-5">
|
|
<AgentFormSections setFieldValue={setFieldValue} values={values} />
|
|
</div>
|
|
|
|
<div className="space-y-5">
|
|
<div className="rounded-[12px] border border-slate-200 bg-white px-5 py-5">
|
|
<div className="flex items-start gap-3">
|
|
<div className="inline-flex h-11 w-11 items-center justify-center rounded-[10px] border border-slate-200 bg-slate-50 text-slate-700">
|
|
<BaseIcon path={mdiRobotOutline} size={20} />
|
|
</div>
|
|
<div className="min-w-0">
|
|
<p className="truncate text-[16px] font-semibold text-slate-900">
|
|
{previewName}
|
|
</p>
|
|
<p className="mt-1 text-[13px] text-slate-500">
|
|
{values.model || 'No model selected yet'}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div className="mt-4 flex flex-wrap gap-2">
|
|
<span
|
|
className={`inline-flex items-center rounded-[999px] px-2.5 py-1 text-[11px] font-medium ${
|
|
values.is_active
|
|
? 'bg-emerald-50 text-emerald-700'
|
|
: 'bg-slate-100 text-slate-600'
|
|
}`}
|
|
>
|
|
{values.is_active ? 'Active' : 'Inactive'}
|
|
</span>
|
|
<span className="inline-flex items-center rounded-[999px] bg-slate-100 px-2.5 py-1 text-[11px] font-medium text-slate-700">
|
|
{values.is_default ? 'Default preset' : 'Custom preset'}
|
|
</span>
|
|
</div>
|
|
<p className="mt-4 text-[13px] leading-6 text-slate-500">
|
|
{values.description || 'Add a short description so people understand when to use this agent.'}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="rounded-[12px] border border-slate-200 bg-white px-5 py-5">
|
|
<p className="text-[11px] font-medium uppercase tracking-[0.28em] text-slate-400">
|
|
Actions
|
|
</p>
|
|
<div className="mt-4 flex flex-wrap gap-2">
|
|
<Link
|
|
className={`${actionButtonClassName} border-slate-200 bg-white text-slate-700`}
|
|
href="/agents/agents-list"
|
|
>
|
|
Cancel
|
|
</Link>
|
|
<button
|
|
className={`${actionButtonClassName} border-slate-900 bg-slate-900 text-white`}
|
|
disabled={isSubmitting}
|
|
type="submit"
|
|
>
|
|
{isSubmitting ? 'Creating…' : 'Create agent'}
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Form>
|
|
);
|
|
}}
|
|
</Formik>
|
|
</SectionMain>
|
|
</>
|
|
);
|
|
};
|
|
|
|
AgentsNew.getLayout = function getLayout(page: ReactElement) {
|
|
return <LayoutAuthenticated permission="CREATE_AGENTS">{page}</LayoutAuthenticated>;
|
|
};
|
|
|
|
export default AgentsNew;
|