Files
UHD_Media_Tool/apps/web/app/components/agent/agent-drawer.tsx
T
rootandClaude Opus 5.5 7103bc8f7c feat(web): W3-3 site workbench, sources/feeds/snapshots, downloads with business timeline, organization records and agent sessions
- sites + /sites/:siteId: organized view with snapshot-first release list, inventory overlay,
  candidate reasons, volatile-field recheck, stale marking that keeps existing data, live search,
  unified download entry; origin view placeholder (M2)
- sources: feed CRUD/enable/fetch/reset, cursor/health/gap hints; per-site snapshot history
- tasks: download tasks with pause/resume (threshold pause cannot be bypassed), plans,
  cache volume thresholds and cleanup, business timeline (observation → plan → download →
  organization → agent/engine)
- organize: record list/detail with file-level results, manual organize with dryRun preview
- agent: session list/page and layout drawer with context prefix; streaming events,
  tool cards, rejection alerts, compaction, budget meters, model text vs server report;
  mock switch (?mock=1) until W2-D endpoints land

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-09-27 20:52:32 +08:00

96 lines
3.6 KiB
TypeScript

import { Bot, ExternalLink, Plus } from "lucide-react";
import { Link } from "react-router";
import { toast } from "sonner";
import { useCreateAgentRun } from "~/api/agent.ts";
import { Button } from "~/components/ui/button.tsx";
import { Sheet, SheetContent, SheetDescription, SheetHeader, SheetTitle } from "~/components/ui/sheet.tsx";
import { errorMessage } from "~/lib/api.ts";
import { AgentRunPanel, GoalComposer } from "./agent-run-panel.tsx";
import {
contextPrefix,
openAgentDrawer,
setAgentDrawerOpen,
setAgentDrawerRun,
useAgentDrawer,
} from "./agent-store.ts";
/**
* Agent 侧栏抽屉:任意页面可打开,带当前页面上下文(entityId 等)作为 goal 前缀。
* 挂载:在 console layout 里渲染一次 <AgentDrawer />;顶栏放 <AgentDrawerTrigger />。
* 页面内打开:import { openAgentDrawer } from "~/components/agent/agent-store.ts"。
*/
export function AgentDrawer() {
const { open, context, runId } = useAgentDrawer();
const create = useCreateAgentRun();
const prefix = contextPrefix(context);
return (
<Sheet open={open} onOpenChange={setAgentDrawerOpen}>
<SheetContent side="right" className="w-full gap-0 p-0 sm:max-w-lg">
<SheetHeader className="border-b border-[var(--shell-border)] px-5 py-4 pr-14">
<SheetTitle className="flex items-center gap-2 text-lead">
<Bot className="h-4 w-4" />
Agent
</SheetTitle>
<SheetDescription className="break-words">
{context?.label ? `当前对象:${context.label}` : "交代目标,Agent 在授权范围内边执行边汇报。"}
</SheetDescription>
</SheetHeader>
<div className="min-h-0 flex-1 overflow-y-auto px-5 py-4">
{runId ? (
<AgentRunPanel runId={runId} compact />
) : (
<GoalComposer
key={`${context?.entityId ?? ""}${context?.releaseId ?? ""}${context?.goal ?? ""}`}
compact
prefix={prefix || undefined}
defaultGoal={context?.goal ?? ""}
pending={create.isPending}
onSubmit={(goal, mode) =>
create.mutate(
{ goal: `${prefix}${goal}`, mode },
{
onSuccess: (run) => setAgentDrawerRun(run.id),
onError: (e) => toast.error(errorMessage(e)),
},
)
}
/>
)}
</div>
<div className="flex flex-wrap items-center justify-end gap-2 border-t border-[var(--shell-border)] px-5 py-3">
{runId ? (
<>
<Button variant="ghost" size="sm" onClick={() => openAgentDrawer(context)}>
<Plus />
新目标
</Button>
<Button asChild variant="outline" size="sm">
<Link to={`/console/agent/${runId}`} onClick={() => setAgentDrawerOpen(false)}>
<ExternalLink />
在会话页打开
</Link>
</Button>
</>
) : (
<Button asChild variant="ghost" size="sm">
<Link to="/console/agent" onClick={() => setAgentDrawerOpen(false)}>
全部会话
</Link>
</Button>
)}
</div>
</SheetContent>
</Sheet>
);
}
/** 顶栏按钮:打开抽屉(不带上下文;页面内按钮用 openAgentDrawer 传上下文) */
export function AgentDrawerTrigger() {
return (
<Button variant="ghost" size="icon-sm" aria-label="打开 Agent" title="Agent" onClick={() => openAgentDrawer(null)}>
<Bot />
</Button>
);
}