"use client"; export const dynamic = "force-dynamic"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { type listBoardsApiV1BoardsGetResponse, useListBoardsApiV1BoardsGet, } from "@/api/generated/boards/boards"; import { useCreateAgentApiV1AgentsPost } from "@/api/generated/agents/agents"; import type { BoardRead } from "@/api/generated/model"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import SearchableSelect, { type SearchableSelectOption, } from "@/components/ui/searchable-select"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { DEFAULT_IDENTITY_PROFILE, DEFAULT_SOUL_TEMPLATE, } from "@/lib/agent-templates"; type IdentityProfile = { role: string; communication_style: string; emoji: string; }; const EMOJI_OPTIONS = [ { value: ":gear:", label: "Gear", glyph: "βš™οΈ" }, { value: ":sparkles:", label: "Sparkles", glyph: "✨" }, { value: ":rocket:", label: "Rocket", glyph: "πŸš€" }, { value: ":megaphone:", label: "Megaphone", glyph: "πŸ“£" }, { value: ":chart_with_upwards_trend:", label: "Growth", glyph: "πŸ“ˆ" }, { value: ":bulb:", label: "Idea", glyph: "πŸ’‘" }, { value: ":wrench:", label: "Builder", glyph: "πŸ”§" }, { value: ":shield:", label: "Shield", glyph: "πŸ›‘οΈ" }, { value: ":memo:", label: "Notes", glyph: "πŸ“" }, { value: ":brain:", label: "Brain", glyph: "🧠" }, ]; const HEARTBEAT_TARGET_OPTIONS: SearchableSelectOption[] = [ { value: "none", label: "None (no outbound message)" }, { value: "last", label: "Last channel" }, ]; const getBoardOptions = (boards: BoardRead[]): SearchableSelectOption[] => boards.map((board) => ({ value: board.id, label: board.name, })); const normalizeIdentityProfile = ( profile: IdentityProfile ): IdentityProfile | null => { const normalized: IdentityProfile = { role: profile.role.trim(), communication_style: profile.communication_style.trim(), emoji: profile.emoji.trim(), }; const hasValue = Object.values(normalized).some((value) => value.length > 0); return hasValue ? normalized : null; }; export default function NewAgentPage() { const router = useRouter(); const { isSignedIn } = useAuth(); const [name, setName] = useState(""); const [boardId, setBoardId] = useState(""); const [heartbeatEvery, setHeartbeatEvery] = useState("10m"); const [heartbeatTarget, setHeartbeatTarget] = useState("none"); const [identityProfile, setIdentityProfile] = useState({ ...DEFAULT_IDENTITY_PROFILE, }); const [soulTemplate, setSoulTemplate] = useState(DEFAULT_SOUL_TEMPLATE); const [error, setError] = useState(null); const boardsQuery = useListBoardsApiV1BoardsGet< listBoardsApiV1BoardsGetResponse, ApiError >(undefined, { query: { enabled: Boolean(isSignedIn), refetchOnMount: "always", }, }); const createAgentMutation = useCreateAgentApiV1AgentsPost({ mutation: { onSuccess: (result) => { if (result.status === 200) { router.push(`/agents/${result.data.id}`); } }, onError: (err) => { setError(err.message || "Something went wrong."); }, }, }); const boards = boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : []; const displayBoardId = boardId || boards[0]?.id || ""; const isLoading = boardsQuery.isLoading || createAgentMutation.isPending; const errorMessage = error ?? boardsQuery.error?.message ?? null; const handleSubmit = (event: React.FormEvent) => { event.preventDefault(); if (!isSignedIn) return; const trimmed = name.trim(); if (!trimmed) { setError("Agent name is required."); return; } const resolvedBoardId = displayBoardId; if (!resolvedBoardId) { setError("Select a board before creating an agent."); return; } setError(null); createAgentMutation.mutate({ data: { name: trimmed, board_id: resolvedBoardId, heartbeat_config: { every: heartbeatEvery.trim() || "10m", target: heartbeatTarget, }, identity_profile: normalizeIdentityProfile(identityProfile) as unknown as Record< string, unknown > | null, soul_template: soulTemplate.trim() || null, }, }); }; return (

Sign in to create an agent.

Create agent

Agents start in provisioning until they check in.

Basic configuration

setName(event.target.value)} placeholder="e.g. Deploy bot" disabled={isLoading} />
setIdentityProfile((current) => ({ ...current, role: event.target.value, })) } placeholder="e.g. Founder, Social Media Manager" disabled={isLoading} />
{boards.length === 0 ? (

Create a board before adding agents.

) : null}

Personality & behavior

setIdentityProfile((current) => ({ ...current, communication_style: event.target.value, })) } disabled={isLoading} />