Skip to content

ZER-404 W1: 三栏只读会话工作台骨架 - #30

Closed
ZeroPointSix wants to merge 5 commits into
mainfrom
cursor/zer-404-w1-session-workbench-d873
Closed

ZER-404 W1: 三栏只读会话工作台骨架#30
ZeroPointSix wants to merge 5 commits into
mainfrom
cursor/zer-404-w1-session-workbench-d873

Conversation

@ZeroPointSix

Copy link
Copy Markdown
Owner

Summary

/sessions/sessions/:id 从 ProTable 运维表形态替换为 Factory/Cursor 风格的三栏只读会话工作台(W1 骨架,无后端依赖)。

改动点

  • 新增 SessionWorkbenchPage 作为 /sessions/sessions/:id 的统一入口
  • 新增三栏组件:
    • SessionSidebar — Ant Design X Conversations 按 Agent 分组展示会话,支持搜索/状态/平台筛选,数据来自现有 GET /api/v1/sessions
    • SessionMainPanel — 顶部状态条 + W4 Transcript 占位区 + 底部固定「🔒 只读观测」条
    • SessionInspector — 元数据 / 告警 / 事件 Tab(Descriptions + Alert + Timeline,自原 SessionDetailPage 迁移)
  • 引入 @ant-design/x@1.0.5(兼容现有 antd 5.x)
  • 移除 SessionsPage / SessionDetailPage 及 ProTable 列表路径
  • 总览页 OverviewPage 仍保留 compact SessionTable(最近 8 条),点击「查看」进入工作台

只读边界

  • 无发送框、插话、Stop/Cancel、模型/参数修改、权限审批
  • 底部固定只读语义条;SSE 连接态沿用 Admin 顶栏指示(本页不重复建连)

本地验证

cd web
pnpm install
pnpm lint && pnpm test && pnpm build
pnpm dev
  1. 登录 Admin Console,进入「会话」菜单
  2. 确认三栏布局(左列表 / 中主区 / 右 Inspector)
  3. 左栏搜索、状态/平台筛选与会话切换
  4. /sessions 有数据时自动选中最新会话并跳转 /sessions/:id
  5. 右栏 Tab 切换元数据、告警、事件
  6. 确认页面无可写入口

未完成项(后续包)

  • W2:冷启动历史、permalink、状态映射
  • W3:Transcript 数据层
  • W4:中栏活动流渲染(当前为占位)
  • W5 / W6

Review Contract

Goal

把 Admin /sessions 主路径从 ProTable 运维表改为只读三栏会话工作台,让用户进站即可按 Agent 浏览与观测会话,并守住只读硬边界。

Non-goals

  • 不新增后端写接口或 SSE 协议变更
  • 不实现 Transcript/活动流真实渲染(W4)
  • 不改造总览页 compact 表格(非本包范围)
  • 不实现 permalink/冷启动历史(W2)

Accepted Residual Risks

  • /sessions 无选中 ID 时会自动跳转到最新会话,深链到列表根路径的行为与旧版不同;可接受,因 W1 目标是工作台心智。
  • Ant Design X 1.x 与 antd 5 配套,未来升级 antd 6 需同步升级 @ant-design/x
  • 窄屏下三栏堆叠,侧栏列表高度受限;可接受,W1 以桌面观测为主。

Acceptance Criteria

  • /sessions/sessions/:id 进入三栏工作台,非 ProTable
  • 左栏列出会话(现有 API),支持搜索/筛选
  • 中栏有顶部状态条 + 内容占位 + 底部只读条
  • 右栏有元数据/告警/事件 Tab
  • 页面无可写入口
  • pnpm lint / pnpm test / pnpm build 通过
  • 进站心智为「看 Agent 会话的地方」(标题/副标题/三栏布局)

Follow-ups

  • W2–W6 按 Linear ZER-404 分包推进
  • 视需要为工作台补 E2E 截图测试或 Storybook
  • antd 6 升级时评估 @ant-design/x 2.x 迁移
Open in Web Open in Cursor 

Replace ProTable sessions list and detail pages with a read-only
three-column SessionWorkbenchPage using Ant Design X Conversations for
the sidebar, status bar + transcript placeholder in the main panel,
and metadata/alerts/events tabs in the inspector.

Co-authored-by: ZeroPointSix <ZeroPointSix@users.noreply.github.com>
@linear-code

linear-code Bot commented Aug 12, 2026

Copy link
Copy Markdown

ZER-404

- 左栏新增 New chat 禁用占位(会话创建 W6 开放)
- 中栏状态条补齐 Profile / workdir 字段
- 底部只读条内嵌 SSE 连接态:新增 StreamStatusContext,复用 AdminLayout 同一 SSE,不新建连接
- 新增 useMediaQuery,≤1100px 左右栏折叠为 Drawer,390 下顶栏不溢出
- 版本号 0.2.3 → 0.3.0
- 重新构建并提交 web/app.js 与 web/styles.css 产物
@ZeroPointSix

Copy link
Copy Markdown
Owner Author

追加提交 311fe5a:补齐 ZER-668 验收缺口(独立沙箱验证通过)

在独立 Daytona 沙箱(zer-668-workbench)对本分支做了逐条验收核对,发现 4 处与 ZER-668 验收标准的缺口并已修复推送:

改动

  • 左栏新增 New chat 禁用占位(范围表要求,会话创建 W6 才开放)
  • 中栏状态条补齐字段:Agent / Profile / 模型 / 状态 / workdir / 会话链接(原缺 Profile、workdir)
  • 底部只读条内嵌 SSE 连接态:新增 StreamStatusContext,由 AdminLayout 下发既有 useSessionStream 状态,不新建第二条 SSE(沿用 2026-08-06 调研结论)
  • 窄屏 ≤1100px 左右栏折叠为 Drawer:新增 useMediaQuery,状态条提供列表/详情开关按钮,390 下 scrollWidth === innerWidth 无横向溢出;选中会话后 Drawer 自动收起并跳转
  • 版本号 0.2.3 → 0.3.0;web/app.js / web/styles.css 产物已重新构建提交

独立验证证据(mock API + Chromium 实测,非仅 lint)

  • pnpm lint(tsc)/ pnpm test(26 通过)/ pnpm build 全绿
  • 桌面 1440:三栏 grid、按 Agent 分组(2 组 3 会话)、搜索/状态/平台筛选、New chat 禁用、状态条字段齐全、底栏「🔒 只读观测 + 实时连接」、主区 0 个输入框、无 Stop/Cancel/发送类按钮
  • 深链冷启动直达 error 会话:Inspector 告警 Tab 徽标 2,完整承接 last_errorprofile_config_errors;事件 Tab 时间线正常
  • 移动 390:单栏、无内联侧栏、Drawer 开合与选中跳转正常、顶栏无溢出
  • 截图已附在 Linear ZER-668 附件(4 张)

说明

  • SessionTable.tsx 保留仅服务总览页 compact 最近 8 条(按 2026-08-12 决策),/sessions 路由引用已全部移除
  • 本提交后 CI 重跑,绿后可转 Ready

@ZeroPointSix
ZeroPointSix marked this pull request as ready for review August 12, 2026 06:42
@ZeroPointSix

Copy link
Copy Markdown
Owner Author

Review:ZER-404 W1 三栏只读会话工作台

过了一遍 PR 描述、4 个 commit、18 个改动文件、CI 结果以及相关源文件(SessionWorkbenchPage / SessionSidebar / SessionMainPanel / SessionInspector / useSessionStream / lib/session.ts)。

方向和拆包认可。 SessionsPage + SessionDetailPage 收敛成统一的 SessionWorkbenchPage 很干净,Inspector 完整承接了原详情页的元数据 / 告警 / 时间线;StreamStatusContext 复用 AdminLayout 既有 SSE 而不新建第二条连接的处理尤其到位。Review Contract 里 Goal / Non-goals / Accepted Residual Risks 的写法也很规范。

CI:validate ✅ / verify ✅。

以下是建议合并前回一轮的问题。


🔴 需要确认

1. 事件 Tab 可能被 SSE 静默清空后不再恢复

useSessionStream.onmessage 中,只要 parseSessionEventPayload 返回 null(心跳帧、缺 sequence 字段、任何非标准帧),就会执行:

queryClient.setQueriesData<SessionTimelineItem[]>(
  { queryKey: ['sessionTimeline'] },
  [],
)

所有会话的 timeline 缓存清成空数组,然后依赖 invalidateQueries(['session']) 重拉来间接 re-seed。

SessionWorkbenchPage 的 re-seed effect 依赖的是 sessionQuery.data引用变化

useEffect(() => {
  if (!sessionQuery.data) return;
  queryClient.setQueryData<SessionTimelineItem[]>(
    ['sessionTimeline', sessionId],
    (current = []) => (current.length ? current : initialTimeline(sessionQuery.data!)),
  );
}, [queryClient, sessionId, sessionQuery.data]);

如果重拉回来的快照内容没有变化,React Query 的 structural sharing 会返回同一个对象引用 → effect 不重跑 → 事件 Tab 停在「暂无事件」,直到用户切走再切回会话。

旧的 SessionDetailPage 是「进来看一眼就走」,这个空窗不明显;新工作台是常驻页面,暴露面被显著放大。

建议二选一:

  • seed 逻辑改为读 queryClient.getQueryData 判空后主动补,不依赖 data 引用变化;
  • 或让解析失败时只对心跳帧静默 return,不做全量 wipe。

2. sortSessions 用字符串比较时间

return [...sessions].sort((a, b) =>
  String(b.updated_at || b.created_at).localeCompare(
    String(a.updated_at || a.created_at),
  ),
);

只要后端同时出现 2026-08-12T06:43:22Z2026-08-12T14:43:22+08:00 两种写法,排序结果就是错的。

关键在于:这个函数原本只喂 ProTable 展示,本 PR 之后它被提升成了路由决策依据 —— /sessions 自动选中「最新会话」直接依赖它。排错了就是进站默认打开一条旧会话,用户很难察觉。风险等级已经变了,建议换成 Date.parse() 数值比较。


🟡 建议改

3. 构建产物入库

web/app.js / web/styles.css 直接提交到仓库,后 3 个 commit 都在手工 rebuild。迟早会出现「改了 src 忘了 build」的漂移。建议 CI 补一步:

pnpm build && git diff --exit-code web/app.js web/styles.css

4. .workbench-status-workdir 是死 CSS

样式里定义了 .workbench-status-workdir { max-width: 180px }(640 断点下 100%),但 SessionMainPanel 渲染 workdir 的那段 JSX 没有挂这个 className:

<Typography.Text type="secondary">
  目录 <Typography.Text code>{session.workdir || '-'}</Typography.Text>
</Typography.Text>

实际效果是长 workdir 不会被截断,会把状态条撑开。

5. New chat 的禁用提示不可达

<Button disabled title="会话创建将在后续版本开放"> —— disabled 按钮在多数浏览器不触发原生 title tooltip,屏幕阅读器也读不到。包一层 antd Tooltip 即可。

6. 只读边界目前是「软」的

底部 🔒 条是纯文案,只读性靠「没画入口」保证。Review Contract 写的是「守住只读硬边界」,措辞与实现之间有落差。W1 骨架阶段可以接受,但建议要么对齐措辞,要么用下面第 7 条的断言测试把它固化。

7. 新增约 1400 行 UI,0 个测试文件

18 个改动文件里没有任何 .test.ts(x)。验收完全依赖沙箱手工核对 + 4 张截图 —— 过程很扎实,但不可回归。建议至少补两块低成本的:

  • SessionSidebar 的搜索 / 状态 / 平台筛选(纯逻辑,好测)
  • 一条「只读断言」测试:渲染工作台后断言查不到发送框、Stop/Cancel 类按钮

这样第 6 点的「硬边界」才真正有机制保障,W4 接入活动流时也不会不小心把写入口带进来。


🟢 小问题

  • SessionInspectoralertItems 用了 .filter(Boolean),但 TS 没有收窄类型,导致渲染时还要 item ? ... : null 二次判空。换成类型谓词 (x): x is AlertItem => Boolean(x) 可以去掉冗余分支。
  • sessionTitle()thread.slice(0, 12),同平台下前缀相同的 thread 在左栏会显示成完全一样的标题。功能上没问题(key 用的是 session_id),只影响可辨识度。
  • @ant-design/x 锁了精确版本 1.0.5,仓库其他依赖都是 ^。如果是刻意 pin(antd 5 配套),建议留一句说明。
  • SessionTable 已重命名为 RecentSessionsTable,但 CSS 选择器仍是 .session-table,命名未同步。

结论

Approve with comments 的量级:没有阻断性缺陷,CI 全绿,只读边界在 UI 层守住了,W1 验收标准基本达成。

但第 1 条(timeline 被清空)和第 2 条(时间字符串排序)都是会在生产里静默出错、且很难从截图验收中发现的问题,建议这一轮先修掉;第 3、7 条可以放进 W2。

@ZeroPointSix ZeroPointSix left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Context fact card

Target

  • Repository:ZeroPointSix/openab-plus
  • PR:#30 ZER-404 W1: 三栏只读会话工作台骨架
  • Reviewed head:4d94cb98a966c9d50987897baf1a346bcd97be61
  • Target branch:main
  • 当前 maina03d9de5dd1853bf9efcce6e999374d8f2ab09ef
  • 目标:确认 W1 工作台改造是否可合并,以及上一轮 review 修复是否完整

Verified facts

  • 最新 4d94cb9 已正确处理上一轮两个主要问题:
    • SSE 诊断帧不再清空全部 sessionTimeline 缓存;cursor_reset / stream error 只触发 session 数据重拉,和后端 SSE 事件名一致。
    • sortSessions 已改为 Date.parse() 数值排序,并新增跨时区测试。
  • 同一提交还补了 workdir ellipsis、New chat Tooltip、AlertItem 类型收窄;这些修改方向都没问题。
  • 生成产物漂移目前已经由 .github/workflows/admin-web.ymlpnpm build + git diff --exit-code -- web/index.html web/app.js web/styles.css 覆盖,上一轮对此的担心可以关闭。

CI / validation

  • 当前 head 4d94cb9 能看到的 check 只有 Review Contract / validate,结果为成功。
  • Admin Web 最近一次成功属于旧 head(例如 0f331c7),不是当前 4d94cb9。因此不能把旧的 lint / test / build / embedded assets 结果当成当前 head 的最终 CI 证据。
  • 我尝试在独立本地执行环境重新 clone/rerun,但该环境当前无法解析 github.com(DNS),所以本次没有额外声称“本地重跑通过”。

阻断问题

1. 当前 PR 已与 main 冲突,必须先 rebase

当前 main 已在本 PR 建立后前进到 a03d9de(合入 #28),而本 PR 的 merge base 仍是 b177f5b。当前比较结果:

  • PR:ahead 5 commits
  • PR:behind main 39 commits
  • GitHub:mergeable = false
  • GitHub:mergeable_state = dirty
  • PR 已有 needs-rebase 标签

所以当前状态不能合并。并且不是纯机械 rebase:main 在这 39 个 commit 中也修改了 web/src/pages/SessionDetailPage.tsxweb/src/components/SessionTable.tsxweb/src/types.ts 和生成的 web/app.js;而本 PR 正好删除/重命名/替换这些文件,需要人工保留双方语义。

2. rebase 时必须保住 #28 已进入 main 的 session metadata,否则会功能回退

当前 mainSessionSnapshot 已新增:

reasoning_effort?: string;
metadata_source?: 'acp' | 'configured';

而当前 mainSessionDetailPage 已把它们展示为:

  • Thinkingsession.reasoning_effort
  • 元数据来源 → ACP 运行时 / 配置值 / 未报告

本 PR 的 SessionInspector 是“承接原 SessionDetailPage”的替代实现,但 reviewed head 4d94cb9types.ts 和 Inspector 仍基于旧 base,没有这两个字段,也没有对应展示。

rebase 解决冲突时不能简单选择 PR 一侧。 请把 reasoning_effort / metadata_source 保留进最终 SessionSnapshot,并把 Thinking / 元数据来源 迁移到新的 Inspector(至少保证当前 main 已有的信息不因工作台替换而消失)。RecentSessionsTable 与当前 main 的 SessionTable 之间的细小展示差异也建议顺手按当前 main 取新语义。

3. rebase 后需要当前 head 的新一轮 Admin Web CI

解决冲突并更新 head 后,请确认新的 Admin Web workflow 在新 SHA上跑完:type-check、vitest、profile schema smoke、build、generated assets diff、Gateway embedding 全部通过。当前旧 SHA 的绿灯不足以覆盖 rebase 后结果。

非阻断建议

  • Tooltip > span > disabled Button 已解决鼠标 hover 提示,但 wrapper 本身没有 tabIndex / 可访问描述;键盘用户仍较难发现“为什么禁用”。W1 可不阻断,后续可补。
  • 工作台新增 UI 仍缺直接的组件/只读边界回归测试;这可以按 PR 里的 W2/E2E follow-up 处理,不要求本轮为了它扩大范围。

Review 结论

当前暂不建议合并。 主体设计和上一轮代码修复我认可;现在真正需要处理的是:

  1. rebase 到当前 main 并解决冲突;
  2. 保留 #28 已进入 main 的 reasoning_effort / metadata_source 展示能力;
  3. 在 rebased head 上重新拿到完整 Admin Web CI 绿灯。

这三项完成后,我预期 W1 本身可以进入可合并状态。

ZeroPointSix added a commit that referenced this pull request Aug 13, 2026
Resolve the diverged #36 and #37 integration trees by retaining the current #39 tree, which contains the complete #30-#35 integration plus #38. The second parent preserves the exact #36/#41 head for ancestry and auditability without reintroducing its incomplete duplicate workbench implementation.
@ZeroPointSix

Copy link
Copy Markdown
Owner Author

已由 #46 的干净 ZER-404 W1–W5 只读工作台整合替代。#46 从最新 main 按依赖顺序重建,保留本 PR 的有效能力并补齐跨包冲突、活动流接线、恢复链与最新回归修复;原分支保留供历史追溯。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants