"use client"; export const dynamic = "force-dynamic"; import { useMemo, useState } from "react"; import Link from "next/link"; import { useParams, useRouter } from "next/navigation"; import { SignInButton, SignedIn, SignedOut, useAuth } from "@/auth/clerk"; import { ApiError } from "@/api/mutator"; import { type getAgentApiV1AgentsAgentIdGetResponse, useDeleteAgentApiV1AgentsAgentIdDelete, useGetAgentApiV1AgentsAgentIdGet, } from "@/api/generated/agents/agents"; import { type listActivityApiV1ActivityGetResponse, useListActivityApiV1ActivityGet, } from "@/api/generated/activity/activity"; import { type listBoardsApiV1BoardsGetResponse, useListBoardsApiV1BoardsGet, } from "@/api/generated/boards/boards"; import type { ActivityEventRead, AgentRead, BoardRead } from "@/api/generated/model"; import { StatusPill } from "@/components/atoms/StatusPill"; import { DashboardSidebar } from "@/components/organisms/DashboardSidebar"; import { DashboardShell } from "@/components/templates/DashboardShell"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; const parseTimestamp = (value?: string | null) => { if (!value) return null; const hasTz = /[zZ]|[+-]\d\d:\d\d$/.test(value); const normalized = hasTz ? value : `${value}Z`; const date = new Date(normalized); if (Number.isNaN(date.getTime())) return null; return date; }; const formatTimestamp = (value?: string | null) => { const date = parseTimestamp(value); if (!date) return "—"; return date.toLocaleString(undefined, { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", }); }; const formatRelative = (value?: string | null) => { const date = parseTimestamp(value); if (!date) return "—"; const diff = Date.now() - date.getTime(); const minutes = Math.round(diff / 60000); if (minutes < 1) return "Just now"; if (minutes < 60) return `${minutes}m ago`; const hours = Math.round(minutes / 60); if (hours < 24) return `${hours}h ago`; const days = Math.round(hours / 24); return `${days}d ago`; }; export default function AgentDetailPage() { const { isSignedIn } = useAuth(); const router = useRouter(); const params = useParams(); const agentIdParam = params?.agentId; const agentId = Array.isArray(agentIdParam) ? agentIdParam[0] : agentIdParam; const [deleteOpen, setDeleteOpen] = useState(false); const [deleteError, setDeleteError] = useState(null); const agentQuery = useGetAgentApiV1AgentsAgentIdGet< getAgentApiV1AgentsAgentIdGetResponse, ApiError >(agentId ?? "", { query: { enabled: Boolean(isSignedIn && agentId), refetchInterval: 30_000, refetchOnMount: "always", retry: false, }, }); const activityQuery = useListActivityApiV1ActivityGet< listActivityApiV1ActivityGetResponse, ApiError >( { limit: 200 }, { query: { enabled: Boolean(isSignedIn), refetchInterval: 30_000, retry: false, }, }, ); const boardsQuery = useListBoardsApiV1BoardsGet< listBoardsApiV1BoardsGetResponse, ApiError >(undefined, { query: { enabled: Boolean(isSignedIn), refetchInterval: 60_000, refetchOnMount: "always", retry: false, }, }); const agent: AgentRead | null = agentQuery.data?.status === 200 ? agentQuery.data.data : null; const events: ActivityEventRead[] = activityQuery.data?.status === 200 ? activityQuery.data.data.items ?? [] : []; const boards: BoardRead[] = boardsQuery.data?.status === 200 ? boardsQuery.data.data.items ?? [] : []; const agentEvents = useMemo(() => { if (!agent) return []; return events.filter((event) => event.agent_id === agent.id); }, [events, agent]); const linkedBoard = !agent?.board_id || agent?.is_gateway_main ? null : boards.find((board) => board.id === agent.board_id) ?? null; const deleteMutation = useDeleteAgentApiV1AgentsAgentIdDelete({ mutation: { onSuccess: () => { setDeleteOpen(false); router.push("/agents"); }, onError: (err) => { setDeleteError(err.message || "Something went wrong."); }, }, }); const isLoading = agentQuery.isLoading || activityQuery.isLoading || boardsQuery.isLoading; const error = agentQuery.error?.message ?? activityQuery.error?.message ?? boardsQuery.error?.message ?? null; const isDeleting = deleteMutation.isPending; const agentStatus = agent?.status ?? "unknown"; const handleDelete = () => { if (!agentId || !isSignedIn) return; setDeleteError(null); deleteMutation.mutate({ agentId }); }; return (

Sign in to view agents.

Agents

{agent?.name ?? "Agent"}

Review agent health, session binding, and recent activity.

{agent ? ( Edit ) : null} {agent ? ( ) : null}
{error ? (
{error}
) : null} {isLoading ? (
Loading agent details…
) : agent ? (

Overview

{agent.name}

Agent ID

{agent.id}

Session key

{agent.openclaw_session_id ?? "—"}

Board

{agent.is_gateway_main ? (

Gateway main (no board)

) : linkedBoard ? ( {linkedBoard.name} ) : (

)}

Last seen

{formatRelative(agent.last_seen_at)}

{formatTimestamp(agent.last_seen_at)}

Updated

{formatTimestamp(agent.updated_at)}

Created

{formatTimestamp(agent.created_at)}

Health

Heartbeat window {formatRelative(agent.last_seen_at)}
Session binding {agent.openclaw_session_id ? "Bound" : "Unbound"}
Status {agentStatus}

Activity

{agentEvents.length} events

{agentEvents.length === 0 ? (
No activity yet for this agent.
) : ( agentEvents.map((event) => (

{event.message ?? event.event_type}

{formatTimestamp(event.created_at)}

)) )}
) : (
Agent not found.
)}
Delete agent This will remove {agent?.name}. This action cannot be undone. {deleteError ? (
{deleteError}
) : null}
); }