feat(agent): 添加对持久化子智能体的支持并增强委派管理 添加了持久化子智能体的完整生命周期管理功能,包括创建、更新、删除和查询API接口。 新增了子智能体的JSON-RPC通信协议支持,实现了远程调用和任务管理功能。 同时增强了委派管理器的功能: - 添加了对本地委派、插件委派和本地回退的开关控制 - 实现了持久化子智能体任务的自动检测和本地执行保护 - 增加了对不同委派类型的权限验证机制 修改了智能体注册表以支持插件智能体的条件性包含,并更新了工具注册逻辑以支持可选工具。 BREAKING CHANGE: 委派管理器的构造函数签名已更改,添加了新的控制参数。 ```
47 KiB
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 级运行态页面
而不是替换这些已有页面。
适配现有数据结构的信息架构
当前前端已具备的关键数据:
sessionIdsessionsprocessRunsprocessEventsprocessArtifactsselectedRunId- 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_idprocessRuns.actor_nameprocessRuns.actor_type
注意:
- 成员名单应按 actor 聚合,而不是按 run 平铺
- 否则一个 agent 多次执行会在名单中重复出现
任务卡
建议实体:
task card = root run 或独立 run
第一版推荐:
- 一个 office 绑定一个主 task
- 以
root run作为该 task 的主执行单元 - 其
member runs视为子任务 / 分工项
依据:
- 现有
parent_run_id已足够支撑这种树状关系 - 现有聊天页中的 team group 逻辑已经在这么做
建议字段:
titlestatusactor_namestarted_atfinished_atsummary- 子任务数量
- 最近更新时间
进度
当前数据模型下,最安全的进度表达方式:
- 按子任务完成数计算
- 按状态分布计算
- 按阶段标签计算
当前不安全的进度表达方式:
- 伪百分比
- 纯时间推算 ETA
第一版建议的进度来源优先级:
metadata中显式阶段信息member runs的完成数量run status分布
分工
建议实体:
assignment = root run -> member runs
展示方式:
- 主 agent
- 子 agent 列表
- 每个子 agent 的当前标题 / 阶段 / 状态
适合来源:
parent_run_idactor_nametitlestatus
详情抽屉
建议实体:
detail drawer = selected run
主要来源:
selectedRunId- 对应 run 的
events - 对应 run 的
artifacts
这层应承接:
- 任务摘要
- 最近事件时间线
- 产物列表
- 失败信息
第一版页面布局建议
推荐布局:
顶部
- task office 切换器
- 当前办公室摘要
- 总体状态统计
中部左侧
- 办公室画布
中部右侧
- 任务看板
- 进度区
- 分工区
底部或右侧抽屉
- 成员名单
- 任务详情
- 事件与产物
这样的好处:
- 左边负责“看态势”
- 右边负责“看事实”
- 抽屉负责“看细节”
第一版强约束
为了避免首版失控,建议强约束如下:
- 一个 task 对应一个办公室
- office 生命周期跟随 task,task 结束后 office 解散
- 画布只展示 agent 和简化任务态势,不展示全量任务文字
- 任务看板只展示 root run 及其子任务摘要
- 进度不用伪百分比
- 详情只对单个 run 下钻
- 不在首版加入自由拖拽装修系统
- 不在首版复刻像素资产编辑系统
当前建议的数据派生逻辑
建议在前端增加一层 office view model,而不是直接把 store 数据原样灌进 UI。
建议派生对象:
OfficeViewOfficeMemberViewOfficeTaskViewOfficeAssignmentViewOfficeAlertView
建议派生过程:
- 先识别当前 task 的 root run
- 收集该 root run 及其子树中的 runs / events / artifacts
- 将
runs按parent_run_id组织成树 - 按
actor_id聚合成员状态 - 从状态和 metadata 推导画布分区
- 将异常和阻塞单独提取为 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 归属规则
推荐规则:
- 找到
parent_run_id = null的主 run - 将该 run 及其所有子孙 runs 视为一个 task
- 该 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 标题生成建议
优先级:
- root run.title
- 用户该轮请求的首句摘要
- 默认标题,例如
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 摘要
- 最近事件
- 产物列表
- 错误信息
首版组件清单
建议先拆成以下组件,而不是把整个页面写成单文件。
页面级组件
OfficeListPageOfficeDetailPage
数据组装层
buildOfficeView(taskId, storeState)buildOfficeTaskList(sessionId?, storeState)
列表页组件
OfficeTaskCardOfficeTaskStatusBadgeOfficeTaskFilterBar
详情页组件
OfficeHeaderOfficeCanvasOfficeZonesOfficeAgentCardOfficeTaskBoardOfficeProgressPanelOfficeAssignmentPanelOfficeRosterPanelOfficeDetailDrawer
公共派生组件
TaskDurationTaskStageBadgeAgentStateDotOfficeAlertPill
首版交互原则
列表页
- 单击卡片进入 office 详情
- 已结束 task 默认折叠到“最近任务”区
- 活跃 task 永远优先展示在上方
详情页
- 点击 agent 卡,打开对应 run 详情
- 点击任务卡,定位到对应分工或详情
- 点击 session 入口,返回聊天页对应会话
任务结束时
- 如果用户正在 office 详情页内,不强制跳走
- 页面显示“任务已完成,办公室已解散”
- 保留摘要和结果查看能力
- 从活跃状态切换为历史状态
当前实现建议
如果按现有代码结构推进,推荐顺序:
- 先新增
/office和/office/[taskId]路由骨架 - 先做
OfficeView派生函数 - 先接真实
processRuns / processEvents / processArtifacts - 再做静态办公室画布
- 最后补动效和视觉包装
这样可以避免先做出一套漂亮但没有稳定数据归属的空画布。
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[];
}
说明:
officeId和taskId第一版可以相同,均使用rootRunIdstatus以 root run 为主,再允许前端推导blockeddetailRunIds用于详情抽屉的可选对象列表
进度对象
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 聚合,不是简单复制 runcurrentRunId指向该 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
派生结果:
taskRunstaskRunIds
第三步:收集 events / artifacts
规则:
taskEvents = processEvents.filter(event => taskRunIds.has(event.run_id))taskArtifacts = processArtifacts.filter(artifact => taskRunIds.has(artifact.run_id))
第四步:派生 task 更新时间
优先级:
- taskEvents 中最新
created_at - taskArtifacts 中最新
created_at - root run.finished_at
- root run.started_at
第五步:派生 task 状态
规则:
- 默认直接取 root run.status
- 只有在存在明确阻塞信号时才提升为
blocked
第一版阻塞信号建议:
- root run.status 为
waiting - 且在一段阈值时间内没有新的 progress / artifact / status 更新
注意:
blocked是前端推导态,不是后端事实态- 第一版如果证据不足,可以先不启用
blocked
第六步:派生阶段标签
优先级建议:
rootRun.metadata.stage_label- 最近一个相关 event 的
metadata.stage_label - 基于状态的回退文案,例如“执行中”“等待中”“已完成”
第一版要求:
- 没有可靠阶段字段就显示空,不要硬猜复杂阶段
第七步:派生成员列表
规则:
- 按
actor_id分组 taskRuns - 每组选择“当前展示 run”
当前展示 run 选择优先级:
runningwaitingqueued- 最近更新的非终态 run
- 最近完成的终态 run
然后派生:
statuszoneIdcurrentTitleartifactCountchildRunIds
第八步:派生任务看板
规则:
- 将 taskRuns 全量转为
OfficeTaskView - 保留树形关系
parentRunId -> childTaskIds - root run 置
isRoot = true
排序建议:
isRoot- 非终态优先
- 最近更新时间倒序
第九步:派生分工关系
规则:
- 对每个有子 run 的 run 生成一条
OfficeAssignmentView - owner = 当前 run
- assignee = 直接 children
第十步:派生告警
第一版告警来源建议:
run.status === error- 最近
run_status/run_finished事件中有错误摘要 - 长时间
waiting
输出原则:
- 少而准
- 不在首页堆满低价值提醒
第十一步:派生分区
第一版分区映射建议:
queued->receptionwaiting->collabrunning- actor_type 为
mcp时可放research - 其他默认放
workspace
- actor_type 为
error->alertcancelled->alertdone->done
注意:
- 分区映射是 UI 规则,不是业务事实
- 必须保持稳定,不能频繁变动语义
第十二步:派生进度
优先级建议:
- 若存在明确阶段总数与当前阶段,使用
mode = ratio - 若仅能得到子任务完成数,使用
mode = ratio - 若只能得到当前阶段标签,使用
mode = stage - 否则使用
mode = status
第一版推荐公式:
value = doneRunsmax = totalRuns
注意:
- 这只是“子任务完成比例”,不是业务整体真实完成度
- 文案必须明确,例如“已完成子任务 3 / 7”
字段来源对照
来自 ProcessRun
run_idparent_run_idsession_idactor_idactor_nameactor_typetitlestatusstarted_atfinished_atsummarymetadata
来自 ProcessEvent
created_attextstatuskindmetadata
用途:
- 更新时间
- 阶段标签
- 告警摘要
- 最近进展
来自 ProcessArtifact
artifact_idrun_idtitleartifact_typecreated_at
用途:
- 产物数量
- 最近活跃时间
- 结果完成感
来自 Session
keycreated_atupdated_at
用途:
- office 返回入口
- source session label
当前实现提醒
不要在类型层做的事
- 不要把办公室坐标直接写死进
OfficeView - 不要把动画状态混进数据模型
- 不要把完整 event 文本直接塞进成员对象
可以在 UI 层处理的事
- agent 卡的像素样式
- 分区背景样式
- 动画和入场过渡
- hover / selection / drawer open 状态
当前明确不该做的事
第一版不要做:
- 在画布上塞完整聊天消息
- 在画布上展示原始 event 列表
- 让一个 agent 因多个 run 复制出多个角色分身且没有解释
- 使用没有依据的任务百分比
- 把任务配置、任务编辑、故障排查都塞到同一屏
本次补充结论
本次新增共识:
session和office 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 对应一个临时 office,task 结束则 office 解散
- 办公室中可包含任务看板、进度、分工、人员名单
- 但办公室页不应替代结构化任务管理和详细诊断视图
同日实现进展:
- 已新增
/office列表页骨架 - 已新增
/office/[taskId]详情页骨架 - 已在顶部导航加入
Office入口 - 已实现
buildOfficeView和buildOfficeTaskList - 第一版页面已接入真实的
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 的委派关系
第一版不要做的伪像素化处理:
- 整屏强行加像素滤镜
- 用大量像素素材堆满背景
- 为了复古感牺牲文字可读性
- 把所有信息都做成悬浮气泡导致画面很吵
- 让所有成员持续运动,破坏扫描效率
推荐的实现顺序:
- 先把画布从“分区卡片网格”改成“房间式布局”
- 再把成员卡改成带角色感的场景单位
- 再补状态动画、灯光、任务浮标
- 最后才决定是否引入真正的像素素材或像素字体
2026-03-25
像素风实现路线补充:
- 当前版本虽然使用了
Phaser,但主要仍是程序化矩形和几何块体,观感更接近“示意图”而不是“像素游戏房间” - 与
Star-Office-UI的核心差距不在是否使用Phaser,而在是否采用了完整的像素游戏生产方式 - 后续不应继续主要依赖
graphics/rectangle拼场景,而应转向tileset + sprite + atlas + 低分辨率放大
像素风的 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/
重做顺序:
- 先确定逻辑分辨率,例如
400x225或480x270 - 先定义办公室专用调色板,控制主色、阴影色、灯光色、状态色
- 先做地板、墙体、隔断、桌椅、服务器、归档箱的 tileset
- 再做 agent 角色的最小动画集:
- idle
- walk
- type
- blocked
- done
- 用
Tiled产出固定房间地图,而不是继续在代码里硬编码大量图形 - 在
Phaser中加载 tilemap、tileset、sprite atlas,按图层拼装办公室 - 把运行状态映射成“房间位置 + 动画 + 状态浮标”,而不是主要靠文字标签
- 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
- 感叹号
- 任务气泡
- 屏幕闪烁
- 告警灯
- 完成勾标
角色第一版动画最小集合:
idlewalktypeblockeddone
素材制作顺序:
- 先做房间 tileset,再做家具
- 家具完成后先在
Tiled里搭出固定办公室 - 最后再做角色和状态动画
- 没有房间和家具前,不先做复杂角色细节
第一批素材规格书:
基础尺寸约定:
- 基础 tile 尺寸统一为
16x16 - 大件家具优先按
16的倍数出图,避免后续拼接时出现半格对齐 - 角色单帧基准尺寸先定为
16x24 - 小型状态图标基准尺寸先定为
8x8或12x12 - 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.pngchair-office.pngtable-meeting.pngsofa-2seat.pngtable-coffee.pngrack-server.pngcrate-archive.pnglamp-floor.pngplant-office.png
- 建议尺寸:
- 工位桌:
32x16 - 椅子:
16x16 - 会议桌:
32x24 - 双人沙发:
32x16 - 茶几:
16x16 - 服务器柜:
16x32 - 归档箱:
16x16 - 落地灯:
16x32 - 植物:
16x24
- 工位桌:
角色 sprite 规格:
- 文件目录:
public/office/sprites/agents/ - 命名规则:
agent-main.pngagent-worker.pngagent-visitor.png
- 单帧尺寸:
16x24 - 第一版朝向:
- 先只做正面 / 背面 / 侧面三向
- 第一版动画帧数建议:
idle:2帧walk:4帧type:2帧blocked:2帧done:2帧
状态图标规格:
- 文件目录:
public/office/sprites/status/ - 命名规则:
icon-alert.pngicon-task.pngicon-done.pngicon-wait.pnglight-warning.png
- 建议尺寸:
- 感叹号:
8x8 - 任务气泡:
12x12 - 完成标记:
8x8 - 等待气泡:
8x8 - 告警灯:
8x8
- 感叹号:
第一张办公室地图必须包含的区域:
- 左侧工位区
- 中央协作区
- 右侧服务器 / 监控区
- 下侧归档区
- 上侧窗户 / 夜景区
第一张办公室地图不做的内容:
- 多房间切换
- 可拖拽家具
- 复杂门禁
- 楼梯 / 二层结构
- 动态天气
Tiled 第一版图层建议:
bg-floorbg-rugwallswindowsfurniture-basefurniture-topmarkerscollision
第一批最先开画的 10 个资产:
floor-darkfloor-lightwall-mainwindow-nightdesk-workstationchair-officesofa-2seatrack-servercrate-archiveagent-worker
实现约束:
- 所有像素图禁止后期模糊缩放
- 输出时保留原始整数像素,不做抗锯齿
- 家具和角色优先保证轮廓清晰,再补内部细节
- 首版宁可资产少,也不要为了“丰富”而拉杂
仓库骨架已创建:
- public/office/README.md
- public/office/tiles/README.md
- public/office/sprites/furniture/README.md
- public/office/sprites/agents/README.md
- public/office/sprites/status/README.md
- public/office/atlas/README.md
- public/office/maps/README.md
- public/office/maps/office-winter-v1-sketch.md
- public/office/maps/office-winter-v1-grid.txt
- public/office/maps/office-winter-v1.tmj
占位 Tiled 地图已生成:
- 使用
25x14网格和16x16tile - 直接引用未来的
../tiles/office-winter-tileset.png - 图层已预拆为:
bg-floorbg-rugwallswindowsmarkersfurniture-anchorscollision
- 家具、服务器、归档箱、装饰点暂时先落为
object layer anchors - 后续真实素材接入时,可优先替换
tileset和furniture-anchors的渲染映射,不必重画地图结构
首版占位 tileset 已生成:
- public/office/tiles/office-winter-tileset.png
- public/office/tiles/office-winter-tileset-preview.png
- 当前是“可用占位图块”,目标是:
- 让
Tiled和Phaser不再处于缺图状态 - 让布局讨论从纯色块进入“基础像素质感”阶段
- 后续真实美术可以逐格替换,不影响现有地图编号
- 让
当前地图预览已切换为真实 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-anchorchair-anchorsofa-anchorcoffee-anchormeeting-anchorserver-anchorarchive-anchordecor-anchor
pixel-agents角色素材也已接入当前运行态画布- 当前做法是:
- 每个成员按顺序分配一套角色皮肤
- 先裁切站立帧作为第一版展示
- 状态变化仍通过徽标、灯光、告警符号和轻微动画表达
- 下一阶段再考虑把角色切到真正的多帧动画:
idlewalktypeblockeddone
第一版 tileset 逐格设计表:
文件约定:
- 文件名:
public/office/tiles/office-winter-tileset.png - 单格尺寸:
16x16 - 第一版先做
4 x 4共16格 - 编号顺序按从左到右、从上到下
首版 16 格 tile 清单:
-
tile-00-wall-main- 主墙面
- 用于绝大多数内墙和外墙主体
-
tile-01-wall-shadow- 主墙面的阴影变体
- 用于墙角、隔断背光面
-
tile-02-wall-trim-top- 墙顶部边线 / 踢脚线风格装饰
- 用于形成冬季室内木质边框感
-
tile-03-window-night- 窗框 + 夜色
- 允许少量雪蓝高光
-
tile-04-floor-dark- 深色地板主格
- 为办公室主走道和大部分可行走区域提供底色
-
tile-05-floor-light- 地板亮格
- 与深格交替,形成轻微棋盘层次
-
tile-06-floor-shadow- 地板压暗格
- 用于家具下方、墙边和角落
-
tile-07-rug-center- 地毯中心格
- 适合中部休息区
-
tile-08-rug-edge-top- 地毯上边缘
-
tile-09-rug-edge-bottom
- 地毯下边缘
tile-10-rug-edge-left
- 地毯左边缘
tile-11-rug-edge-right
- 地毯右边缘
tile-12-corner-inner
- 内转角
- 用于墙体或地毯转角收边
tile-13-corner-outer
- 外转角
- 用于房间边界和隔断端点
tile-14-border-accent
- 装饰边框格
- 用于壁炉橙 / 冷蓝点缀的少量节奏
tile-15-placeholder-debug
- 调试占位格
- 首版用于 Tiled 中快速查错,不进入最终视觉
每格绘制要求:
- 所有 tile 都必须在
16x16内完成,不允许跨格画主体 - 第一版每格内部色彩控制在
3-5个主色内 - 轮廓优先用较深色,不用纯黑硬描整圈
- 高光只落在上边或左上角,统一光源方向
- 地板和墙面的纹理必须克制,不能把 tile 画成噪点块
首版 tileset 排版建议:
- 第 1 行:墙体相关
- 第 2 行:地板相关
- 第 3 行:地毯相关
- 第 4 行:角落 / 边框 / 调试格
首版绘制优先级:
tile-04-floor-darktile-05-floor-lighttile-00-wall-maintile-03-window-nighttile-07-rug-centertile-08/09/10/11-rug-edge-*
首版完成标准:
- 能在
Tiled里先拼出完整房间外轮廓 - 能区分墙、地板、窗户、地毯 4 个层次
- 即使还没有家具和角色,也能看出“冬季办公室”的空间氛围
最新运行时视觉约束:
- 场景里不显示分区标题
- 场景里不显示彩色分区框
- 分区只用于成员落点和状态映射,不在画布上显式标注
最新机器人表现约束:
- 机器人整体尺寸上调一档
- 主 agent 比普通成员再大一档
- running 态不使用走路朝向,统一正面朝下
- 运行感主要靠轻微上下浮动和状态灯,不靠横向行走
- 运行时角色必须使用 spritesheet frame 渲染,不允许再用整张角色图错误裁切
public/office/maps/office-winter-v1-scene-preview.png必须跟随当前地图、家具和角色资源重导,不能长期作为过期效果图保留
最新画布简化约束:
- 场景顶部左侧标题条移除
- 场景顶部右侧阶段条移除
- 场景底部 focus/点击提示牌匾移除
最新运行态规则修正:
- 已完成成员不单独停留在完成区,而是返回讨论区(collab)