feat(agent): in-drawer history tab and denser session layout (AGUI-2)

- Drawer tabs 当前/历史: searchable run list (status/source/time filters,
  cursor auto-load), opens runs inside the drawer, keeps scroll and filters,
  remembers the last tab; 在页面打开 is secondary
- Ended runs: append to resume, or 用同目标新建 with 先看方案再执行 toggle
- Session page: 88ch conversation column, turns grouped with one timestamp,
  tool cards collapse to one line, 3+ activities fold; steps/subagents/budget
  moved to a right rail (collapsible overview bar on narrow screens and in
  the drawer), long model reports fold behind 展开全文
- Smoke covers the drawer history flow

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
rootandClaude Opus 5.5 committed 2026-09-29 15:17:37 +08:00
1 parent ac478673bc
commit 20b63db254
14 files changed
+1234 -349

No files matched your search

+17 -8
View File
@@ -1,35 +1,44 @@
import type { AgentRunStatus } from "@umt/contracts";
import { ArrowLeft } from "lucide-react";
import { useState } from "react";
import { Link, useParams } from "react-router";
import { agentMockEnabled, useAgentRun } from "~/api/agent.ts";
import { AgentRunPanel } from "~/components/agent/agent-run-panel.tsx";
import { AgentSessionList } from "~/components/agent/agent-session-list.tsx";
import { splitContextGoal } from "~/components/agent/agent-store.ts";
import { PageHeader } from "~/components/console/page-header.tsx";
import { Button } from "~/components/ui/button.tsx";
// 会话页:左栏会话列表(xl 以上)· 中间会话列(统一最大宽度,输入区固定在底部)· 右侧栏状态/步骤/预算(lg 以上;
// 更窄时换成会话列顶部的可折叠概况条)。
export default function AgentRunPage() {
const { runId = "" } = useParams();
const run = useAgentRun(runId);
const mock = agentMockEnabled();
const [status, setStatus] = useState<"" | AgentRunStatus>("");
const suffix = mock ? "?mock=1" : "";
return (
<>
<PageHeader
title="Agent 会话"
description={run.data ? <span className="line-clamp-2 break-words">{run.data.run.goal}</span> : "加载中…"}
description={
run.data ? (
<span className="line-clamp-2 break-words" title={run.data.run.goal}>
{splitContextGoal(run.data.run.goal).text}
</span>
) : (
"加载中…"
)
}
actions={
<Button asChild variant="ghost" size="sm">
<Link to={`/console/agent${mock ? "?mock=1" : ""}`}>
<Link to={`/console/agent${suffix}`}>
<ArrowLeft />
全部会话
</Link>
</Button>
}
/>
<div className="grid grid-cols-1 gap-4 lg:grid-cols-[minmax(0,17rem)_minmax(0,1fr)]">
<aside className="pg-slab hidden rounded-xl p-3 lg:block lg:h-[calc(100dvh-13rem)] lg:overflow-hidden">
<AgentSessionList activeId={runId} status={status} onStatusChange={setStatus} className="h-full" />
<div className="grid grid-cols-1 gap-4 xl:grid-cols-[minmax(0,16rem)_minmax(0,1fr)]">
<aside className="pg-slab hidden rounded-xl p-3 xl:block xl:h-[calc(100dvh-13rem)] xl:overflow-hidden">
<AgentSessionList activeId={runId} hrefFor={(id) => `/console/agent/${id}${suffix}`} className="h-full" />
</aside>
<div className="pg-slab flex h-[calc(100dvh-11rem)] min-h-[32rem] flex-col rounded-xl p-3 md:p-4 lg:h-[calc(100dvh-13rem)]">
<AgentRunPanel key={runId} runId={runId} className="flex-1" />