import type { AgentRunStatus } from "@umt/contracts"; import { Bot, FlaskConical } from "lucide-react"; import { useState } from "react"; import { useNavigate } from "react-router"; import { toast } from "sonner"; import { type AgentRunView, agentMockEnabled, RUN_STATUS_LABEL, useAgentRuns, useCreateAgentRun } from "~/api/agent.ts"; import { RunStatusBadge } from "~/components/agent/agent-conversation.tsx"; import { GoalComposer } from "~/components/agent/agent-run-panel.tsx"; import { type DataColumn, DataTable } from "~/components/console/data-table.tsx"; import { FilterBar, FilterSelect } from "~/components/console/filter-bar.tsx"; import { PageHeader } from "~/components/console/page-header.tsx"; import { Button } from "~/components/ui/button.tsx"; import { relTime } from "~/components/workbench/release-fields.ts"; import { errorMessage } from "~/lib/api.ts"; const COLUMNS: DataColumn[] = [ { key: "goal", header: "目标", cell: (r) => (

{r.goal}

{r.summary ?

{r.summary}

: null}
), }, { key: "status", header: "状态", cell: (r) => }, { key: "mode", header: "模式", hideBelow: "md", cell: (r) => ((r.mode ?? r.scope.mode) === "plan_only" ? "只要方案" : "执行"), }, { key: "tools", header: "工具调用", hideBelow: "md", align: "right", cell: (r) => r.toolCallCount }, { key: "at", header: "开始", hideBelow: "sm", cell: (r) => {relTime(r.createdAt)}, }, ]; export default function AgentPage() { const [status, setStatus] = useState(""); const runs = useAgentRuns((status || undefined) as AgentRunStatus | undefined); const create = useCreateAgentRun(); const navigate = useNavigate(); const mock = agentMockEnabled(); const rows = runs.data?.pages.flatMap((p) => p.items); return ( <> {mock ? (
演示模式:会话是本地假数据,不连后端,不会产生任何动作。
) : null}
create.mutate( { goal, mode }, { onSuccess: (run) => navigate(`/console/agent/${run.id}${mock ? "?mock=1" : ""}`), onError: (e) => toast.error(errorMessage(e)), }, ) } />
setStatus("") : undefined}> ({ value, label }))} /> r.id} loading={runs.isPending} error={runs.error} onRetry={() => void runs.refetch()} empty={{ icon: Bot, title: "还没有会话", description: "例如:“把某部电影的 1080p 收进来”,或在任意页面右上角打开 Agent 侧栏。", }} onRowClick={(r) => navigate(`/console/agent/${r.id}${mock ? "?mock=1" : ""}`)} hasMore={runs.hasNextPage} onLoadMore={() => void runs.fetchNextPage()} loadingMore={runs.isFetchingNextPage} /> ); }