Files
beaver_project/app-instance/frontend/office-ui.md
steven_li 29dfd14aa6 ```
feat(agent): 添加对持久化子智能体的支持并增强委派管理

添加了持久化子智能体的完整生命周期管理功能,包括创建、更新、删除和查询API接口。
新增了子智能体的JSON-RPC通信协议支持,实现了远程调用和任务管理功能。

同时增强了委派管理器的功能:
- 添加了对本地委派、插件委派和本地回退的开关控制
- 实现了持久化子智能体任务的自动检测和本地执行保护
- 增加了对不同委派类型的权限验证机制

修改了智能体注册表以支持插件智能体的条件性包含,并更新了工具注册逻辑以支持可选工具。

BREAKING CHANGE: 委派管理器的构造函数签名已更改,添加了新的控制参数。
```
2026-03-27 10:15:35 +08:00

47 KiB
Raw Blame History

Office UI Guide

本文件用于记录 office UI 相关的想法、讨论结论、约束和后续修正。

目标:

  • 作为实现前的持续设计指南
  • 作为后续页面开发时的范围边界
  • 作为每次对话补充和纠偏的记录落点

约定:

  • 后续在对话中凡是对 office UI 的想法有新增、修正、否定、细化,都继续更新本文件
  • 这里记录的是当前共识,不代表已经完成实现

当前结论

office UI 不是传统意义上的“任务管理页”,更适合定义为:

一个面向长耗时、多 agent、多阶段任务的“运行态可视化总览页”。

当前开发阶段补充:

  • 优先目标已切换为“稳定可用、稳定可演示”
  • 当前阶段不再继续追求更复杂的像素美术细节
  • 当前冻结项:
    • 四区地图结构
    • 当前家具资源方案
    • 当前角色资源方案
  • 当前优先确保:
    • /office/[taskId] 真实可用
    • 角色状态有基础差异
    • 构建、测试、类型检查稳定

它借鉴 Star-Office-UI 的核心概念:

  • 用办公室空间隐喻表达 agent 状态
  • 让主 agent 和 sub-agent 的工作状态可视化
  • 让用户快速感知“谁在做什么、是否卡住、任务进展到哪里”

但它不应直接替代现有结构化任务管理界面。

产品定位

建议定位:

  • office UI = 总览层 / 态势层 / 趣味化运行时观察台

不建议定位:

  • 唯一的任务管理入口
  • 唯一的故障诊断入口
  • 唯一的任务事实来源

原因:

  • 办公室隐喻适合表达“状态”和“分工”
  • 不适合单独承载依赖关系、失败原因、产物细节、真实阻塞点

核心设计思想

1. session、task、office 是三层关系

当前方向:

  • session 用于维护长期对话上下文
  • 用户在 session 中发起“让主 agent 干 XXX”即创建一个 task
  • office 是这个 task 的运行态可视化现场

当前共识:

  • 一个 session 可以包含多个 task
  • 一个 task 对应一个临时 office
  • task 结束后office 解散,不作为长期容器保留

补充约束:

  • office 解散指“退出活跃运行态视图”
  • 不等于删除该 task 的历史事实
  • task 完成后,仍应保留最小可回看的摘要、结果和产物入口

预期收益:

  • 对话上下文和任务执行上下文分离
  • office UI 可以只关注“当前这次任务在发生什么”
  • 避免把整个 session 的历史信息都带进办公室画布

2. 办公室负责概览,不负责全部事实

办公室画布适合承载:

  • 主 agent / sub-agent 在线状态
  • 当前任务归属
  • 工作区域映射
  • 简化的进度感知
  • 团队分工
  • 当前办公室成员名单

办公室画布不应单独承载:

  • 全量日志
  • 复杂筛选
  • 深层错误排查
  • 完整产物浏览
  • 精确任务编排

结论:

  • 画布负责“扫一眼看懂”
  • 结构化面板负责“点进去看清”

3. 趣味性可以有,但不能压过可读性

允许:

  • 空间化布局
  • 角色位置变化
  • 轻量动效
  • 有辨识度的视觉氛围

不建议:

  • 过多持续动画
  • 复杂装饰导致信息遮挡
  • 仅为可爱而牺牲状态辨识度

页面建议结构

建议采用混合布局,而不是纯画布页。

A. 办公室画布区

用于展示:

  • 主 agent
  • sub-agent
  • 当前状态分布
  • 所属任务或阶段
  • 简化状态气泡

可能的空间分区示例:

  • 接待区:待命 / 排队
  • 工位区:执行中 / 处理中
  • 会议区:同步 / 协作
  • 研究区:检索 / 分析
  • 故障区:异常 / 阻塞
  • 完成区:已完成 / 待汇总

注意:

  • 分区必须和真实状态枚举稳定映射
  • 不能靠“视觉猜测”表达状态

B. 任务看板区

用于展示当前办公室里的任务拆分情况,例如:

  • 待开始
  • 进行中
  • 已完成
  • 阻塞

要求:

  • 看板是结构化事实,不是装饰物
  • 每个任务卡应至少显示标题、负责人、状态、阶段、更新时间

C. 进度区

可以有进度条,但要非常克制。

原则:

  • 只有在后端有真实阶段数据时才显示百分比进度
  • 如果没有可靠进度,只显示“阶段进度”而不是伪百分比

可以接受:

  • 3 / 7 子任务完成
  • 当前阶段:资料检索
  • 已完成:需求分析 -> 分工 -> 编码中

不建议:

  • 没有依据的 78%
  • 基于耗时猜测的 ETA

D. 分工区

用于展示:

  • 谁负责什么
  • 主 agent 当前委派给了哪些 sub-agent
  • 各 agent 当前所属阶段

E. 办公室成员名单

用于展示:

  • 当前 task 参与成员
  • 角色类型
  • 当前状态
  • 最近更新时间

当前明确的产品判断

支持的判断

  • 这个方向有价值
  • 比纯日志或纯表格更适合“长耗时任务”的态势感知
  • 对多 agent 协作特别有帮助
  • 与 task 生命周期绑定是合理的
  • 如果做得好,既能提高清晰度,也能提高使用乐趣

反对的判断

  • 不应把它做成唯一任务管理页
  • 不应让办公室隐喻替代真实任务数据
  • 不应为了像素办公室效果而牺牲后台控制台的可操作性
  • 不应直接照搬 Star-Office-UI 整套产品结构

关键风险

1. 隐喻过强,事实过弱

风险:

  • 用户知道“谁在忙”,但不知道“为什么慢”

控制方式:

  • 必须有结构化任务卡、状态、阶段、更新时间、负责人

2. 进度条失真

风险:

  • 进度看起来很满,但实际任务没有可靠里程碑

控制方式:

  • 没有真实进度数据就不用百分比

3. 页面职责过载

风险:

  • 一个页面同时做总览、诊断、管理、配置,最后都做不强

控制方式:

  • 明确 office UI 首先是总览页
  • 诊断和深度操作应下钻到详细面板

4. 代码移植成本被低估

风险:

  • Star-Office-UI 是完整产品,不是简单组件
  • 直接搬代码的成本和适配复杂度可能高于重写

控制方式:

  • 优先借鉴概念、布局语言和交互隐喻
  • 代码层面只选择性复用可拆分部分

5. 资产许可风险

风险:

  • 原项目代码和美术资产许可范围不同

控制方式:

  • 直接复用图像和素材前,必须再次核对许可
  • 有商用可能时,应准备自有素材方案 (暂时不商用)

实现原则

实现时建议遵守:

  • 先做信息架构,再做美术包装
  • 先做静态结构,再接实时数据
  • 先保证状态映射准确,再增加趣味动效
  • 先让用户看懂,再让页面有趣

与现有前端的关系

当前前端已经存在:

  • 聊天工作台
  • 执行过程展示
  • 定时任务管理
  • 智能体管理

因此 office UI 更像新增一个:

  • 运行态总览页
  • 或者 task 级运行态页面

而不是替换这些已有页面。

适配现有数据结构的信息架构

当前前端已具备的关键数据:

  • sessionId
  • sessions
  • processRuns
  • processEvents
  • processArtifacts
  • selectedRunId
  • run 的 parent_run_id 父子关系

现有数据模型说明:

  • session 适合作为 task 的发起上下文,不适合直接等同办公室
  • ProcessRun 更适合作为 task / 子任务 的基础执行实体
  • ProcessRun 是最适合作为“任务实体”的基础对象
  • ProcessEvent 是状态变化和过程流
  • ProcessArtifact 是阶段产物和结果输出
  • parent_run_id 可以推导主 agent 与 sub-agent 的委派关系

结论:

  • office UI 第一版应围绕 task -> run tree -> event/artifact 构建
  • session 只用于找到当前 task 的来源上下文
  • 不要第一版就引入全新任务模型,除非现有结构明显不够

页面级信息架构

建议采用四层结构。

1. 办公室切换层

位置:

  • 页面顶部或左侧一级导航区

作用:

  • 切换不同 task 对应的办公室
  • 展示当前办公室的摘要状态

建议展示字段:

  • 办公室名称
  • 对应 task 标题
  • 最近活跃时间
  • 运行中 agent 数
  • 阻塞 / 错误数

数据来源建议:

  • 当前 session 中可查看的 task 列表
  • 当前 task 下筛选后的 processRuns

2. 办公室画布层

位置:

  • 页面主视觉中心

作用:

  • 用空间化方式展示当前 task 内主 agent / sub-agent 的实时分布

画布中的基本对象建议:

  • 办公室房间 / 分区
  • agent 角色卡
  • 当前任务气泡
  • 简化状态标识
  • 高风险提醒标识

数据映射建议:

  • 一个 agent run 对应一个画布中的“办公人员状态实例”
  • 同一 agent 多个并发 run 时,需要有明确合并策略

第一版建议合并策略:

  • 只显示每个 agent 最近一个活跃 run
  • 若存在 running / waiting,优先显示活跃 run
  • 已完成 run 不长期占据画布主位

3. 结构化事实层

位置:

  • 画布右侧栏或下方主面板

作用:

  • 承载不能只靠视觉隐喻表达的真实任务信息

建议包含 4 个模块:

  • 任务看板
  • 进度区
  • 分工区
  • 成员名单

4. 下钻详情层

位置:

  • 抽屉、侧边详情面板或弹层

作用:

  • 用户点击画布中的 agent、任务卡或异常标识后查看详情

建议展示:

  • 当前 run 摘要
  • 最近事件
  • 当前状态
  • 产物列表
  • 失败原因
  • 上下游关系

元素归位规则

本节用于明确什么应该放在办公室画布,什么不应该。

应该放在办公室画布里的元素

适合放入画布的前提:

  • 用户需要扫一眼快速理解
  • 信息可以被抽象成状态、位置、分工、风险
  • 不依赖长文本解释

具体包括:

  • 主 agent
  • sub-agent
  • agent 当前状态
  • agent 当前负责的任务短标题
  • 所在阶段的标签
  • 阻塞 / 错误告警标记
  • 办公室内的功能分区
  • 简化进度感,例如“阶段 2/4”或“3 个子任务进行中”
  • 当前在线成员总览

这些信息适合视觉化,因为:

  • 强调态势而不是细节
  • 适合空间映射
  • 能快速建立“工作现场感”

不应该直接放在办公室画布里的元素

以下内容不适合直接塞进画布主体:

  • 全量事件流
  • 全量日志文本
  • 复杂任务依赖图
  • 多条件筛选器
  • 大量操作按钮
  • 大段失败堆栈
  • 完整 artifact 内容
  • 大量表格字段
  • 精确排程配置

原因:

  • 会破坏扫视效率
  • 会让画布从“总览层”退化成“信息垃圾堆”
  • 视觉隐喻会被结构化细节打散

结论:

  • 画布里只保留高信号、低文本密度的信息
  • 深度信息必须进入结构化面板或详情抽屉

现有数据到页面模块的映射建议

办公室

建议实体:

  • office = current task

需要的基础字段:

  • task 标题
  • task 创建时间
  • 最近活跃时间
  • 所属 sessionId

如果 task 当前没有独立名称:

  • 第一版可以显示为主 run 标题或默认编号

办公人员

建议实体:

  • office member = actor

主要来源:

  • processRuns.actor_id
  • processRuns.actor_name
  • processRuns.actor_type

注意:

  • 成员名单应按 actor 聚合,而不是按 run 平铺
  • 否则一个 agent 多次执行会在名单中重复出现

任务卡

建议实体:

  • task card = root run 或独立 run

第一版推荐:

  • 一个 office 绑定一个主 task
  • root run 作为该 task 的主执行单元
  • member runs 视为子任务 / 分工项

依据:

  • 现有 parent_run_id 已足够支撑这种树状关系
  • 现有聊天页中的 team group 逻辑已经在这么做

建议字段:

  • title
  • status
  • actor_name
  • started_at
  • finished_at
  • summary
  • 子任务数量
  • 最近更新时间

进度

当前数据模型下,最安全的进度表达方式:

  • 按子任务完成数计算
  • 按状态分布计算
  • 按阶段标签计算

当前不安全的进度表达方式:

  • 伪百分比
  • 纯时间推算 ETA

第一版建议的进度来源优先级:

  1. metadata 中显式阶段信息
  2. member runs 的完成数量
  3. run status 分布

分工

建议实体:

  • assignment = root run -> member runs

展示方式:

  • 主 agent
  • 子 agent 列表
  • 每个子 agent 的当前标题 / 阶段 / 状态

适合来源:

  • parent_run_id
  • actor_name
  • title
  • status

详情抽屉

建议实体:

  • detail drawer = selected run

主要来源:

  • selectedRunId
  • 对应 run 的 events
  • 对应 run 的 artifacts

这层应承接:

  • 任务摘要
  • 最近事件时间线
  • 产物列表
  • 失败信息

第一版页面布局建议

推荐布局:

顶部

  • task office 切换器
  • 当前办公室摘要
  • 总体状态统计

中部左侧

  • 办公室画布

中部右侧

  • 任务看板
  • 进度区
  • 分工区

底部或右侧抽屉

  • 成员名单
  • 任务详情
  • 事件与产物

这样的好处:

  • 左边负责“看态势”
  • 右边负责“看事实”
  • 抽屉负责“看细节”

第一版强约束

为了避免首版失控,建议强约束如下:

  • 一个 task 对应一个办公室
  • office 生命周期跟随 tasktask 结束后 office 解散
  • 画布只展示 agent 和简化任务态势,不展示全量任务文字
  • 任务看板只展示 root run 及其子任务摘要
  • 进度不用伪百分比
  • 详情只对单个 run 下钻
  • 不在首版加入自由拖拽装修系统
  • 不在首版复刻像素资产编辑系统

当前建议的数据派生逻辑

建议在前端增加一层 office view model而不是直接把 store 数据原样灌进 UI。

建议派生对象:

  • OfficeView
  • OfficeMemberView
  • OfficeTaskView
  • OfficeAssignmentView
  • OfficeAlertView

建议派生过程:

  1. 先识别当前 task 的 root run
  2. 收集该 root run 及其子树中的 runs / events / artifacts
  3. runsparent_run_id 组织成树
  4. actor_id 聚合成员状态
  5. 从状态和 metadata 推导画布分区
  6. 将异常和阻塞单独提取为 alert

这样做的好处:

  • 避免页面组件直接承担复杂归并逻辑
  • 便于后续替换视觉方案而不动数据组织

当前 task 的推荐判定规则:

  • 用户在 session 中发起一次主请求,即创建一个主 task
  • 主 agent 开始执行,到主 agent 向用户给出最终回复为止,视为该 task 生命周期
  • 该期间产生的 root run 及其子 runs 构成一个 office
  • task 结束后office 从活跃列表移除,但 task 摘要不应丢失

Task 识别规则

这一节用于把“什么算一个 task”说清楚否则 office UI 很容易做成不稳定状态机。

task 定义

建议定义:

  • task = 用户在 session 中发起的一次主请求所触发的完整执行周期

起点:

  • 主 agent 接收到该次用户请求
  • 对应 root run 被创建

终点:

  • 主 agent 针对该次请求输出最终用户可见回复
  • 对应 root run 进入终态:done / error / cancelled

一个 task 内可以包含:

  • 主 agent 自身执行
  • sub-agent 委派
  • MCP 调用
  • 中间产物
  • 中间进展事件

一个 task 不应跨越:

  • 多次独立用户请求
  • 不同 session
  • 已结束后再次重新触发的新一轮执行

第一版 task 主键建议

首选:

  • taskId = root run_id

原因:

  • 当前数据里最稳定的执行主键就是 run_id
  • parent_run_id 已能自然形成 task 树
  • 前端不需要首版额外等后端提供新 ID

第一版 task 归属规则

推荐规则:

  1. 找到 parent_run_id = null 的主 run
  2. 将该 run 及其所有子孙 runs 视为一个 task
  3. 该 task 的 office 生命周期跟随 root run 生命周期

边界情况:

  • 如果一个用户请求触发多个并列 root run第一版必须选一个明确策略

第一版推荐策略:

  • 默认一个用户请求只允许一个主 root run
  • 如果出现多个并列 root run先按时间拆成多个 task
  • 不在首版支持“一个 task 多个 root run 合并”

task 状态映射建议

建议 task 状态从 root run 派生:

  • waiting -> 待启动
  • queued -> 排队中
  • running -> 进行中
  • done -> 已完成
  • error -> 失败
  • cancelled -> 已取消

补充派生状态:

  • blocked:仅当存在明确阻塞信号时额外推导,不要乱推

task 标题生成建议

优先级:

  1. root run.title
  2. 用户该轮请求的首句摘要
  3. 默认标题,例如 Task 2026-03-24 14:32

要求:

  • 标题应短
  • 可用于列表和 office 顶部摘要
  • 不依赖长文本解析

路由与入口建议

这一节用于明确 office UI 在当前前端中的落点。

页面关系

建议关系:

  • session page 负责对话
  • office page 负责展示某个 task 的运行态

两者是关联页面,不是同页双模式。

路由建议

第一版推荐:

  • 列表页:/office
  • 详情页:/office/[taskId]

路由职责:

  • /office
    • 查看活跃 office 列表
    • 查看最近结束 task 摘要
    • 支持从 session 跳转过来的当前 task 高亮
  • /office/[taskId]
    • 查看某个 task 的办公室画布
    • 查看对应结构化面板和详情抽屉

入口建议

首选入口:

  • 聊天页在主 agent 开始执行后,出现“查看任务现场”入口
  • 点击后跳转 /office/[taskId]

辅助入口:

  • 顶部导航新增 Office
  • 进入 /office 查看当前活跃任务与最近任务

不建议的入口方式:

  • 强制把用户从聊天页自动跳走
  • 每次任务启动都弹窗打断对话

与现有导航的关系

建议:

  • 顶部导航增加 Office
  • 但不要把 Office 放成比 对话 更中心的一级任务入口

原因:

  • 主工作流仍然是对话发起任务
  • office UI 是运行态观察层,不是主输入层

首版页面线框

本节提供实现时可直接参考的结构。

/office 列表页

建议结构:

  • 顶部标题区
  • 活跃 office 列表
  • 最近结束 task 列表
  • 过滤栏:全部 / 进行中 / 失败 / 最近完成

每个卡片建议包含:

  • task 标题
  • 来源 session 标识
  • 主 agent 名称
  • 当前状态
  • 最近活跃时间
  • sub-agent 数量
  • 错误 / 告警数
  • “进入办公室”按钮

页面目标:

  • 让用户快速找到正在跑的 task
  • 让用户快速回看最近结束的 task

/office/[taskId] 详情页

建议结构:

  • 顶部摘要条
  • 主画布区
  • 右侧事实面板
  • 底部或侧边详情抽屉

顶部摘要条

建议包含:

  • task 标题
  • task 状态
  • 来源 session 入口
  • 创建时间 / 运行时长
  • 返回对话按钮

主画布区

建议包含:

  • 办公室背景分区
  • 主 agent 卡
  • sub-agent 卡
  • 状态气泡
  • 简化分工连线或区域归属

右侧事实面板

建议包含 4 个模块:

  • 任务看板
  • 当前进度
  • 分工面板
  • 成员名单

底部或侧边详情抽屉

点击对象后展示:

  • run 摘要
  • 最近事件
  • 产物列表
  • 错误信息

首版组件清单

建议先拆成以下组件,而不是把整个页面写成单文件。

页面级组件

  • OfficeListPage
  • OfficeDetailPage

数据组装层

  • buildOfficeView(taskId, storeState)
  • buildOfficeTaskList(sessionId?, storeState)

列表页组件

  • OfficeTaskCard
  • OfficeTaskStatusBadge
  • OfficeTaskFilterBar

详情页组件

  • OfficeHeader
  • OfficeCanvas
  • OfficeZones
  • OfficeAgentCard
  • OfficeTaskBoard
  • OfficeProgressPanel
  • OfficeAssignmentPanel
  • OfficeRosterPanel
  • OfficeDetailDrawer

公共派生组件

  • TaskDuration
  • TaskStageBadge
  • AgentStateDot
  • OfficeAlertPill

首版交互原则

列表页

  • 单击卡片进入 office 详情
  • 已结束 task 默认折叠到“最近任务”区
  • 活跃 task 永远优先展示在上方

详情页

  • 点击 agent 卡,打开对应 run 详情
  • 点击任务卡,定位到对应分工或详情
  • 点击 session 入口,返回聊天页对应会话

任务结束时

  • 如果用户正在 office 详情页内,不强制跳走
  • 页面显示“任务已完成,办公室已解散”
  • 保留摘要和结果查看能力
  • 从活跃状态切换为历史状态

当前实现建议

如果按现有代码结构推进,推荐顺序:

  1. 先新增 /office/office/[taskId] 路由骨架
  2. 先做 OfficeView 派生函数
  3. 先接真实 processRuns / processEvents / processArtifacts
  4. 再做静态办公室画布
  5. 最后补动效和视觉包装

这样可以避免先做出一套漂亮但没有稳定数据归属的空画布。

OfficeView 类型设计

这一节定义首版前端建议使用的 view model目的是隔离原始 store 数据和页面 UI。

顶层对象

type OfficeTaskStatus =
  | 'queued'
  | 'running'
  | 'waiting'
  | 'done'
  | 'error'
  | 'cancelled'
  | 'blocked';

type OfficeZoneId =
  | 'reception'
  | 'workspace'
  | 'collab'
  | 'research'
  | 'alert'
  | 'done';

interface OfficeView {
  officeId: string;
  taskId: string;
  sessionId: string | null;
  title: string;
  status: OfficeTaskStatus;
  createdAt: string;
  updatedAt: string;
  finishedAt: string | null;
  durationMs: number | null;
  sourceSessionLabel: string;
  rootRunId: string;
  rootActorName: string;
  currentStageLabel: string | null;
  progress: OfficeProgressView;
  stats: OfficeStatsView;
  alerts: OfficeAlertView[];
  zones: OfficeZoneView[];
  members: OfficeMemberView[];
  tasks: OfficeTaskView[];
  assignments: OfficeAssignmentView[];
  detailRunIds: string[];
}

说明:

  • officeIdtaskId 第一版可以相同,均使用 rootRunId
  • status 以 root run 为主,再允许前端推导 blocked
  • detailRunIds 用于详情抽屉的可选对象列表

进度对象

interface OfficeProgressView {
  mode: 'stage' | 'ratio' | 'status';
  label: string;
  value: number | null;
  max: number | null;
  stageLabel: string | null;
}

约束:

  • value/max 只在有可靠分子分母时填写
  • 没有可靠比值时只显示 stageLabel

统计对象

interface OfficeStatsView {
  totalRuns: number;
  activeRuns: number;
  doneRuns: number;
  errorRuns: number;
  cancelledRuns: number;
  memberCount: number;
  artifactCount: number;
}

分区对象

interface OfficeZoneView {
  id: OfficeZoneId;
  label: string;
  memberIds: string[];
  taskIds: string[];
  tone: 'neutral' | 'info' | 'warn' | 'danger' | 'success';
}

成员对象

interface OfficeMemberView {
  memberId: string;
  actorId: string;
  actorName: string;
  actorType: 'agent' | 'mcp' | 'system';
  status: OfficeTaskStatus;
  zoneId: OfficeZoneId;
  currentRunId: string;
  currentTitle: string;
  stageLabel: string | null;
  summary: string | null;
  startedAt: string | null;
  updatedAt: string | null;
  finishedAt: string | null;
  childRunIds: string[];
  artifactCount: number;
  isPrimary: boolean;
}

设计原则:

  • member 是按 actor 聚合,不是简单复制 run
  • currentRunId 指向该 actor 当前最值得展示的 run

任务对象

interface OfficeTaskView {
  taskId: string;
  runId: string;
  parentRunId: string | null;
  actorId: string;
  actorName: string;
  actorType: 'agent' | 'mcp' | 'system';
  title: string;
  status: OfficeTaskStatus;
  stageLabel: string | null;
  summary: string | null;
  startedAt: string;
  updatedAt: string;
  finishedAt: string | null;
  childTaskIds: string[];
  artifactCount: number;
  errorText: string | null;
  isRoot: boolean;
}

说明:

  • OfficeTaskView 面向任务看板
  • taskId 第一版可直接等于 runId

分工对象

interface OfficeAssignmentView {
  ownerRunId: string;
  ownerActorName: string;
  assigneeRunIds: string[];
  assigneeActorNames: string[];
  label: string;
}

告警对象

interface OfficeAlertView {
  id: string;
  level: 'info' | 'warn' | 'error';
  title: string;
  description: string | null;
  runId: string | null;
  actorId: string | null;
  createdAt: string;
}

buildOfficeView 派生规则

这一节定义如何从现有 store 数据推导 OfficeView

输入

建议输入:

interface BuildOfficeViewInput {
  taskId: string;
  sessions: Session[];
  processRuns: ProcessRun[];
  processEvents: ProcessEvent[];
  processArtifacts: ProcessArtifact[];
}

第一步:定位 root run

规则:

  • taskId 第一版默认等于 rootRunId
  • processRuns 中找到 run_id === taskId 的 run
  • 若找不到则返回 null

失败处理:

  • 详情页展示 “任务不存在或已失效”

第二步:收集 task 子树

规则:

  • 从 root run 出发
  • 递归收集所有 parent_run_id === 当前 run_id 的子孙 runs
  • 形成当前 task 的完整 run tree

派生结果:

  • taskRuns
  • taskRunIds

第三步:收集 events / artifacts

规则:

  • taskEvents = processEvents.filter(event => taskRunIds.has(event.run_id))
  • taskArtifacts = processArtifacts.filter(artifact => taskRunIds.has(artifact.run_id))

第四步:派生 task 更新时间

优先级:

  1. taskEvents 中最新 created_at
  2. taskArtifacts 中最新 created_at
  3. root run.finished_at
  4. root run.started_at

第五步:派生 task 状态

规则:

  • 默认直接取 root run.status
  • 只有在存在明确阻塞信号时才提升为 blocked

第一版阻塞信号建议:

  • root run.status 为 waiting
  • 且在一段阈值时间内没有新的 progress / artifact / status 更新

注意:

  • blocked 是前端推导态,不是后端事实态
  • 第一版如果证据不足,可以先不启用 blocked

第六步:派生阶段标签

优先级建议:

  1. rootRun.metadata.stage_label
  2. 最近一个相关 event 的 metadata.stage_label
  3. 基于状态的回退文案,例如“执行中”“等待中”“已完成”

第一版要求:

  • 没有可靠阶段字段就显示空,不要硬猜复杂阶段

第七步:派生成员列表

规则:

  • actor_id 分组 taskRuns
  • 每组选择“当前展示 run”

当前展示 run 选择优先级:

  1. running
  2. waiting
  3. queued
  4. 最近更新的非终态 run
  5. 最近完成的终态 run

然后派生:

  • status
  • zoneId
  • currentTitle
  • artifactCount
  • childRunIds

第八步:派生任务看板

规则:

  • 将 taskRuns 全量转为 OfficeTaskView
  • 保留树形关系 parentRunId -> childTaskIds
  • root run 置 isRoot = true

排序建议:

  1. isRoot
  2. 非终态优先
  3. 最近更新时间倒序

第九步:派生分工关系

规则:

  • 对每个有子 run 的 run 生成一条 OfficeAssignmentView
  • owner = 当前 run
  • assignee = 直接 children

第十步:派生告警

第一版告警来源建议:

  • run.status === error
  • 最近 run_status / run_finished 事件中有错误摘要
  • 长时间 waiting

输出原则:

  • 少而准
  • 不在首页堆满低价值提醒

第十一步:派生分区

第一版分区映射建议:

  • queued -> reception
  • waiting -> collab
  • running
    • actor_type 为 mcp 时可放 research
    • 其他默认放 workspace
  • error -> alert
  • cancelled -> alert
  • done -> done

注意:

  • 分区映射是 UI 规则,不是业务事实
  • 必须保持稳定,不能频繁变动语义

第十二步:派生进度

优先级建议:

  1. 若存在明确阶段总数与当前阶段,使用 mode = ratio
  2. 若仅能得到子任务完成数,使用 mode = ratio
  3. 若只能得到当前阶段标签,使用 mode = stage
  4. 否则使用 mode = status

第一版推荐公式:

  • value = doneRuns
  • max = totalRuns

注意:

  • 这只是“子任务完成比例”,不是业务整体真实完成度
  • 文案必须明确,例如“已完成子任务 3 / 7”

字段来源对照

来自 ProcessRun

  • run_id
  • parent_run_id
  • session_id
  • actor_id
  • actor_name
  • actor_type
  • title
  • status
  • started_at
  • finished_at
  • summary
  • metadata

来自 ProcessEvent

  • created_at
  • text
  • status
  • kind
  • metadata

用途:

  • 更新时间
  • 阶段标签
  • 告警摘要
  • 最近进展

来自 ProcessArtifact

  • artifact_id
  • run_id
  • title
  • artifact_type
  • created_at

用途:

  • 产物数量
  • 最近活跃时间
  • 结果完成感

来自 Session

  • key
  • created_at
  • updated_at

用途:

  • office 返回入口
  • source session label

当前实现提醒

不要在类型层做的事

  • 不要把办公室坐标直接写死进 OfficeView
  • 不要把动画状态混进数据模型
  • 不要把完整 event 文本直接塞进成员对象

可以在 UI 层处理的事

  • agent 卡的像素样式
  • 分区背景样式
  • 动画和入场过渡
  • hover / selection / drawer open 状态

当前明确不该做的事

第一版不要做:

  • 在画布上塞完整聊天消息
  • 在画布上展示原始 event 列表
  • 让一个 agent 因多个 run 复制出多个角色分身且没有解释
  • 使用没有依据的任务百分比
  • 把任务配置、任务编辑、故障排查都塞到同一屏

本次补充结论

本次新增共识:

  • sessionoffice UI 是分开的页面
  • session 负责维护对话
  • task 是用户在 session 中发起的一次主 agent 执行请求
  • office 是 task 的临时运行态空间,不是 session 的长期容器
  • office UI 第一版应直接建立在现有 processRuns + processEvents + processArtifacts 之上
  • root run / member runs 结构适合作为任务看板和分工区的基础
  • 办公室画布只表达态势,不承载深度细节
  • 深度细节通过结构化面板和详情抽屉承接
  • 页面应按“概览层 -> 事实层 -> 详情层”分层,而不是全部平铺

暂定非目标

当前不把以下内容设为首期目标:

  • 完整项目管理系统
  • 甘特图级别依赖编排
  • 精确工时统计
  • 复杂权限编排
  • 复刻 Star-Office-UI 的全部玩法和资产系统

后续需要继续明确的问题

  • 办公室切换是放在聊天页内,还是独立路由页
  • 一个 session 中多个 task 的切换入口应该如何暴露
  • 任务看板的数据源来自 process runs、cron、会话消息还是新的聚合接口
  • “分工” 是自动从委派关系推导,还是允许人工编辑
  • 进度计算是否需要后端显式上报阶段
  • 画布是否允许拖拽布局,还是固定布局
  • 是否采用像素风,还是只保留办公室隐喻、不使用像素素材

更新记录

2026-03-24

首次创建,记录当前共识:

  • 借鉴 Star-Office-UI 的办公室可视化概念
  • 目标是长耗时、多 agent 任务的运行态总览
  • session 和 office UI 分离
  • session 用于维护对话
  • task 是一次主 agent 执行周期
  • 一个 task 对应一个临时 officetask 结束则 office 解散
  • 办公室中可包含任务看板、进度、分工、人员名单
  • 但办公室页不应替代结构化任务管理和详细诊断视图

同日实现进展:

  • 已新增 /office 列表页骨架
  • 已新增 /office/[taskId] 详情页骨架
  • 已在顶部导航加入 Office 入口
  • 已实现 buildOfficeViewbuildOfficeTaskList
  • 第一版页面已接入真实的 processRuns / processEvents / processArtifacts 数据
  • 已补 OfficeView / OfficeTaskList 的单元测试
  • 已在聊天页加入直达当前 task 对应 /office/[taskId] 的入口
  • 已对 office 详情页的画布分区做第一轮视觉打磨

同日导航结构修正:

  • 一级导航将 Office定时任务 合并为 任务管理
  • 任务管理 默认跳转到 /office
  • 任务管理 内部再分两个子页:
    • Office
    • 定时任务
  • Office 列表页、Office 详情页、定时任务 页共享同一组二级页签
  • 路由保持不变:
    • /office
    • /office/[taskId]
    • /cron

同日视觉方向补充:

  • Office 画布应继续向“像素风游戏感”靠拢
  • 目标不是简单套一层像素贴图,而是让页面更像一个可观察的 2D 办公室场景
  • 第一优先级是空间感、角色感、状态感
  • 第二优先级才是像素装饰、像素字体、像素动效
  • 第一版技术选型改为 Phaser
  • Phaser 只负责办公室场景画布
  • 结构化面板、任务看板、详情抽屉仍保留在 React 页面层
  • 已把 /office/[taskId] 进一步改成更接近 Star-Office-UI 的舞台式布局
  • 页面主结构调整为:上方像素办公室舞台 + 下方像素面板 + 右侧结构化任务板

像素风画布的实现原则:

  • 画布先像一个房间,再像一个后台页面
  • 成员先像场景角色,再像数据卡片
  • 状态先通过位置、朝向、动作、灯光表达,再补文字标签
  • 仍然必须保留结构化信息入口,不能为了游戏感牺牲可读性

第一版建议做的视觉元素:

  • 固定视角办公室平面布局
  • 像素化地板、隔断、会议桌、工位、服务器角、归档区
  • 每个 agent 使用统一规则的小型像素角色牌
  • 用状态色和状态动作表达:
    • running:轻微闪动、桌面亮起
    • waiting:低饱和、静止
    • blocked:红色告警灯或感叹号
    • done:柔和高亮或归档动作
  • 用连接线或小型任务浮标表达主 agent 与 sub-agent 的委派关系

第一版不要做的伪像素化处理:

  • 整屏强行加像素滤镜
  • 用大量像素素材堆满背景
  • 为了复古感牺牲文字可读性
  • 把所有信息都做成悬浮气泡导致画面很吵
  • 让所有成员持续运动,破坏扫描效率

推荐的实现顺序:

  1. 先把画布从“分区卡片网格”改成“房间式布局”
  2. 再把成员卡改成带角色感的场景单位
  3. 再补状态动画、灯光、任务浮标
  4. 最后才决定是否引入真正的像素素材或像素字体

2026-03-25

像素风实现路线补充:

  • 当前版本虽然使用了 Phaser,但主要仍是程序化矩形和几何块体,观感更接近“示意图”而不是“像素游戏房间”
  • Star-Office-UI 的核心差距不在是否使用 Phaser,而在是否采用了完整的像素游戏生产方式
  • 后续不应继续主要依赖 graphics / rectangle 拼场景,而应转向 tileset + sprite + atlas + 低分辨率放大

像素风的 6 个必要层级:

  1. 低分辨率逻辑画布,再整数倍放大
  2. 统一调色板,而不是自由配色
  3. 像素素材驱动,而不是几何图形驱动
  4. 固定房间语法和明确空间分区
  5. 克制的帧动画和状态动画
  6. Phaser 世界层与 React / DOM 信息面板分离

建议工具链:

  • 场景引擎:Phaser
  • 角色 / 家具 / 图块绘制:Aseprite
  • 平铺地图编辑:Tiled
  • 最终资源形式:tileset png + sprite sheet png + json atlas

建议目录结构:

  • public/office/tiles/
  • public/office/sprites/
  • public/office/atlas/
  • public/office/maps/
  • components/office/phaser/

重做顺序:

  1. 先确定逻辑分辨率,例如 400x225480x270
  2. 先定义办公室专用调色板,控制主色、阴影色、灯光色、状态色
  3. 先做地板、墙体、隔断、桌椅、服务器、归档箱的 tileset
  4. 再做 agent 角色的最小动画集:
    • idle
    • walk
    • type
    • blocked
    • done
  5. Tiled 产出固定房间地图,而不是继续在代码里硬编码大量图形
  6. Phaser 中加载 tilemap、tileset、sprite atlas按图层拼装办公室
  7. 把运行状态映射成“房间位置 + 动画 + 状态浮标”,而不是主要靠文字标签
  8. React 页面继续只承载:
    • 昨日小记
    • 任务看板
    • 办公人员名单
    • 详情抽屉

当前代码层面的明确改造方向:

  • components/office/OfficePhaserCanvas.tsx 不应继续扩展矩形绘制细节
  • 下一版应拆成:
    • 场景资源加载
    • tilemap 创建
    • 成员 sprite 实例化
    • 动画注册
    • run -> scene state 映射
  • 角色、家具、房间应优先做成资源文件,而不是继续写死在 TSX 内

明确的非目标:

  • 不靠整页像素滤镜制造“伪像素感”
  • 不靠像素字体替代真正的像素场景
  • 不在没有素材体系前继续微调现有程序化块体配色

本轮进一步确定:

  • Office 像素画布的世界坐标固定为 400x225
  • 内部渲染分辨率提升为 800x450
  • 最终显示采用整数倍缩放,不做非整数拉伸
  • 调色板方向参考 openclaw-theme-stardew 的冬季主题
  • 视觉氛围关键词:
    • 冬夜深蓝
    • 冰霜蓝灰
    • 雪白文字
    • 壁炉橙点缀

冬季基础调色板:

  • 背景主色:#1a2433
  • 背景次色:#232f42
  • 背景抬升:#2c3a52
  • 卡片/家具中间色:#3a4a62
  • 边框色:#4a5a72
  • 边框高亮:#5a7092
  • 文本主色:#e8f0f8
  • 文本强色:#f5faff
  • 弱文本:#8aa0b8
  • 主强调色:#ff8a65
  • 强调高亮:#ffab91
  • 焦点/冷光:#90caf9

场景层建议的派生色:

  • 地板深色:#243041
  • 地板亮格:#31425b
  • 墙体阴影:#17202d
  • 窗外夜色:#101827
  • 屏幕冷光:#8fd3ff
  • 完成态绿:#78c27a
  • 阻塞态红:#d96c75
  • 等待态米黄:#d8c79a

第一批素材最小集合:

  • 房间 tileset
    • 墙体
    • 墙角
    • 地板
    • 地毯
    • 窗户
  • 家具 sprites
    • 工位桌
    • 椅子
    • 会议桌
    • 沙发
    • 茶几
    • 服务器柜
    • 归档箱
    • 植物
  • 角色 sprites
    • 主 agent
    • 通用 sub-agent
    • 访客 / 等待角色
  • 状态 sprites
    • 感叹号
    • 任务气泡
    • 屏幕闪烁
    • 告警灯
    • 完成勾标

角色第一版动画最小集合:

  • idle
  • walk
  • type
  • blocked
  • done

素材制作顺序:

  1. 先做房间 tileset再做家具
  2. 家具完成后先在 Tiled 里搭出固定办公室
  3. 最后再做角色和状态动画
  4. 没有房间和家具前,不先做复杂角色细节

第一批素材规格书:

基础尺寸约定:

  • 基础 tile 尺寸统一为 16x16
  • 大件家具优先按 16 的倍数出图,避免后续拼接时出现半格对齐
  • 角色单帧基准尺寸先定为 16x24
  • 小型状态图标基准尺寸先定为 8x812x12
  • UI 面板仍由 React / CSS 承载,不纳入本批像素素材制作

地图网格约定:

  • 逻辑分辨率:400x225
  • 地图绘制网格:16x16
  • 可视区域理论格数约为:
    • 25
    • 14
  • 允许顶部或底部保留少量非满格安全边距,但房间主体尽量在整数格内完成

tileset 规格:

  • 文件:public/office/tiles/office-winter-tileset.png
  • 单格:16x16
  • 首版建议内容:
    • 墙面浅色 tile
    • 墙面阴影 tile
    • 内墙/隔断 tile
    • 地板深色 tile
    • 地板亮色 tile
    • 地毯边缘 tile
    • 地毯中心 tile
    • 窗框 tile
    • 窗外夜景 tile
    • 踢脚线 / 边框 tile

家具 sprite 规格:

  • 文件目录:public/office/sprites/furniture/
  • 命名规则:
    • desk-workstation.png
    • chair-office.png
    • table-meeting.png
    • sofa-2seat.png
    • table-coffee.png
    • rack-server.png
    • crate-archive.png
    • lamp-floor.png
    • plant-office.png
  • 建议尺寸:
    • 工位桌:32x16
    • 椅子:16x16
    • 会议桌:32x24
    • 双人沙发:32x16
    • 茶几:16x16
    • 服务器柜:16x32
    • 归档箱:16x16
    • 落地灯:16x32
    • 植物:16x24

角色 sprite 规格:

  • 文件目录:public/office/sprites/agents/
  • 命名规则:
    • agent-main.png
    • agent-worker.png
    • agent-visitor.png
  • 单帧尺寸:16x24
  • 第一版朝向:
    • 先只做正面 / 背面 / 侧面三向
  • 第一版动画帧数建议:
    • idle: 2
    • walk: 4
    • type: 2
    • blocked: 2
    • done: 2

状态图标规格:

  • 文件目录:public/office/sprites/status/
  • 命名规则:
    • icon-alert.png
    • icon-task.png
    • icon-done.png
    • icon-wait.png
    • light-warning.png
  • 建议尺寸:
    • 感叹号:8x8
    • 任务气泡:12x12
    • 完成标记:8x8
    • 等待气泡:8x8
    • 告警灯:8x8

第一张办公室地图必须包含的区域:

  • 左侧工位区
  • 中央协作区
  • 右侧服务器 / 监控区
  • 下侧归档区
  • 上侧窗户 / 夜景区

第一张办公室地图不做的内容:

  • 多房间切换
  • 可拖拽家具
  • 复杂门禁
  • 楼梯 / 二层结构
  • 动态天气

Tiled 第一版图层建议:

  • bg-floor
  • bg-rug
  • walls
  • windows
  • furniture-base
  • furniture-top
  • markers
  • collision

第一批最先开画的 10 个资产:

  1. floor-dark
  2. floor-light
  3. wall-main
  4. window-night
  5. desk-workstation
  6. chair-office
  7. sofa-2seat
  8. rack-server
  9. crate-archive
  10. agent-worker

实现约束:

  • 所有像素图禁止后期模糊缩放
  • 输出时保留原始整数像素,不做抗锯齿
  • 家具和角色优先保证轮廓清晰,再补内部细节
  • 首版宁可资产少,也不要为了“丰富”而拉杂

仓库骨架已创建:

占位 Tiled 地图已生成:

  • 使用 25x14 网格和 16x16 tile
  • 直接引用未来的 ../tiles/office-winter-tileset.png
  • 图层已预拆为:
    • bg-floor
    • bg-rug
    • walls
    • windows
    • markers
    • furniture-anchors
    • collision
  • 家具、服务器、归档箱、装饰点暂时先落为 object layer anchors
  • 后续真实素材接入时,可优先替换 tilesetfurniture-anchors 的渲染映射,不必重画地图结构

首版占位 tileset 已生成:

当前地图预览已切换为真实 tileset 拼接:

已引入 pixel-agents 资产作为当前内用原型素材库:

  • public/office/vendor/pixel-agents/README.md
  • 资产已整体落入:
    • public/office/vendor/pixel-agents/assets/furniture/
    • public/office/vendor/pixel-agents/assets/floors/
    • public/office/vendor/pixel-agents/assets/walls/
    • public/office/vendor/pixel-agents/assets/characters/
  • 当前已经在 OfficePhaserCanvas 中接入的是真实家具 sprite不再只显示锚点框
  • 当前已映射的主要锚点类型:
    • desk-anchor
    • chair-anchor
    • sofa-anchor
    • coffee-anchor
    • meeting-anchor
    • server-anchor
    • archive-anchor
    • decor-anchor
  • pixel-agents 角色素材也已接入当前运行态画布
  • 当前做法是:
    • 每个成员按顺序分配一套角色皮肤
    • 先裁切站立帧作为第一版展示
    • 状态变化仍通过徽标、灯光、告警符号和轻微动画表达
  • 下一阶段再考虑把角色切到真正的多帧动画:
    • idle
    • walk
    • type
    • blocked
    • done

第一版 tileset 逐格设计表:

文件约定:

  • 文件名:public/office/tiles/office-winter-tileset.png
  • 单格尺寸:16x16
  • 第一版先做 4 x 416
  • 编号顺序按从左到右、从上到下

首版 16 格 tile 清单:

  1. tile-00-wall-main

    • 主墙面
    • 用于绝大多数内墙和外墙主体
  2. tile-01-wall-shadow

    • 主墙面的阴影变体
    • 用于墙角、隔断背光面
  3. tile-02-wall-trim-top

    • 墙顶部边线 / 踢脚线风格装饰
    • 用于形成冬季室内木质边框感
  4. tile-03-window-night

    • 窗框 + 夜色
    • 允许少量雪蓝高光
  5. tile-04-floor-dark

    • 深色地板主格
    • 为办公室主走道和大部分可行走区域提供底色
  6. tile-05-floor-light

    • 地板亮格
    • 与深格交替,形成轻微棋盘层次
  7. tile-06-floor-shadow

    • 地板压暗格
    • 用于家具下方、墙边和角落
  8. tile-07-rug-center

    • 地毯中心格
    • 适合中部休息区
  9. tile-08-rug-edge-top

    • 地毯上边缘
  10. tile-09-rug-edge-bottom

  • 地毯下边缘
  1. tile-10-rug-edge-left
  • 地毯左边缘
  1. tile-11-rug-edge-right
  • 地毯右边缘
  1. tile-12-corner-inner
  • 内转角
  • 用于墙体或地毯转角收边
  1. tile-13-corner-outer
  • 外转角
  • 用于房间边界和隔断端点
  1. tile-14-border-accent
  • 装饰边框格
  • 用于壁炉橙 / 冷蓝点缀的少量节奏
  1. tile-15-placeholder-debug
  • 调试占位格
  • 首版用于 Tiled 中快速查错,不进入最终视觉

每格绘制要求:

  • 所有 tile 都必须在 16x16 内完成,不允许跨格画主体
  • 第一版每格内部色彩控制在 3-5 个主色内
  • 轮廓优先用较深色,不用纯黑硬描整圈
  • 高光只落在上边或左上角,统一光源方向
  • 地板和墙面的纹理必须克制,不能把 tile 画成噪点块

首版 tileset 排版建议:

  • 第 1 行:墙体相关
  • 第 2 行:地板相关
  • 第 3 行:地毯相关
  • 第 4 行:角落 / 边框 / 调试格

首版绘制优先级:

  1. tile-04-floor-dark
  2. tile-05-floor-light
  3. tile-00-wall-main
  4. tile-03-window-night
  5. tile-07-rug-center
  6. tile-08/09/10/11-rug-edge-*

首版完成标准:

  • 能在 Tiled 里先拼出完整房间外轮廓
  • 能区分墙、地板、窗户、地毯 4 个层次
  • 即使还没有家具和角色,也能看出“冬季办公室”的空间氛围

最新运行时视觉约束:

  • 场景里不显示分区标题
  • 场景里不显示彩色分区框
  • 分区只用于成员落点和状态映射,不在画布上显式标注

最新机器人表现约束:

  • 机器人整体尺寸上调一档
  • 主 agent 比普通成员再大一档
  • running 态不使用走路朝向,统一正面朝下
  • 运行感主要靠轻微上下浮动和状态灯,不靠横向行走
  • 运行时角色必须使用 spritesheet frame 渲染,不允许再用整张角色图错误裁切
  • public/office/maps/office-winter-v1-scene-preview.png 必须跟随当前地图、家具和角色资源重导,不能长期作为过期效果图保留

最新画布简化约束:

  • 场景顶部左侧标题条移除
  • 场景顶部右侧阶段条移除
  • 场景底部 focus/点击提示牌匾移除

最新运行态规则修正:

  • 已完成成员不单独停留在完成区而是返回讨论区collab