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

1819 lines
47 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.`runs``parent_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。
### 顶层对象
```ts
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` 第一版可以相同,均使用 `rootRunId`
- `status` 以 root run 为主,再允许前端推导 `blocked`
- `detailRunIds` 用于详情抽屉的可选对象列表
### 进度对象
```ts
interface OfficeProgressView {
mode: 'stage' | 'ratio' | 'status';
label: string;
value: number | null;
max: number | null;
stageLabel: string | null;
}
```
约束:
- `value/max` 只在有可靠分子分母时填写
- 没有可靠比值时只显示 `stageLabel`
### 统计对象
```ts
interface OfficeStatsView {
totalRuns: number;
activeRuns: number;
doneRuns: number;
errorRuns: number;
cancelledRuns: number;
memberCount: number;
artifactCount: number;
}
```
### 分区对象
```ts
interface OfficeZoneView {
id: OfficeZoneId;
label: string;
memberIds: string[];
taskIds: string[];
tone: 'neutral' | 'info' | 'warn' | 'danger' | 'success';
}
```
### 成员对象
```ts
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
### 任务对象
```ts
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`
### 分工对象
```ts
interface OfficeAssignmentView {
ownerRunId: string;
ownerActorName: string;
assigneeRunIds: string[];
assigneeActorNames: string[];
label: string;
}
```
### 告警对象
```ts
interface OfficeAlertView {
id: string;
level: 'info' | 'warn' | 'error';
title: string;
description: string | null;
runId: string | null;
actorId: string | null;
createdAt: string;
}
```
## buildOfficeView 派生规则
这一节定义如何从现有 store 数据推导 `OfficeView`
### 输入
建议输入:
```ts
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 复制出多个角色分身且没有解释
- 使用没有依据的任务百分比
- 把任务配置、任务编辑、故障排查都塞到同一屏
## 本次补充结论
本次新增共识:
- `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 对应一个临时 officetask 结束则 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 的委派关系
第一版不要做的伪像素化处理:
- 整屏强行加像素滤镜
- 用大量像素素材堆满背景
- 为了复古感牺牲文字可读性
- 把所有信息都做成悬浮气泡导致画面很吵
- 让所有成员持续运动,破坏扫描效率
推荐的实现顺序:
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. 先确定逻辑分辨率,例如 `400x225``480x270`
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](/home/ivan/xuan/nano_project/app-instance/frontend/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`
- 小型状态图标基准尺寸先定为 `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.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`
实现约束:
- 所有像素图禁止后期模糊缩放
- 输出时保留原始整数像素,不做抗锯齿
- 家具和角色优先保证轮廓清晰,再补内部细节
- 首版宁可资产少,也不要为了“丰富”而拉杂
仓库骨架已创建:
- [public/office/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/README.md)
- [public/office/tiles/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/tiles/README.md)
- [public/office/sprites/furniture/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/sprites/furniture/README.md)
- [public/office/sprites/agents/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/sprites/agents/README.md)
- [public/office/sprites/status/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/sprites/status/README.md)
- [public/office/atlas/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/atlas/README.md)
- [public/office/maps/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/maps/README.md)
- [public/office/maps/office-winter-v1-sketch.md](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/maps/office-winter-v1-sketch.md)
- [public/office/maps/office-winter-v1-grid.txt](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/maps/office-winter-v1-grid.txt)
- [public/office/maps/office-winter-v1.tmj](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/maps/office-winter-v1.tmj)
占位 Tiled 地图已生成:
- 使用 `25x14` 网格和 `16x16` tile
- 直接引用未来的 `../tiles/office-winter-tileset.png`
- 图层已预拆为:
- `bg-floor`
- `bg-rug`
- `walls`
- `windows`
- `markers`
- `furniture-anchors`
- `collision`
- 家具、服务器、归档箱、装饰点暂时先落为 `object layer anchors`
- 后续真实素材接入时,可优先替换 `tileset``furniture-anchors` 的渲染映射,不必重画地图结构
首版占位 tileset 已生成:
- [public/office/tiles/office-winter-tileset.png](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/tiles/office-winter-tileset.png)
- [public/office/tiles/office-winter-tileset-preview.png](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/tiles/office-winter-tileset-preview.png)
- 当前是“可用占位图块”,目标是:
-`Tiled``Phaser` 不再处于缺图状态
- 让布局讨论从纯色块进入“基础像素质感”阶段
- 后续真实美术可以逐格替换,不影响现有地图编号
当前地图预览已切换为真实 tileset 拼接:
- [public/office/maps/office-winter-v1-preview.png](/home/ivan/xuan/nano_project/app-instance/frontend/public/office/maps/office-winter-v1-preview.png)
已引入 `pixel-agents` 资产作为当前内用原型素材库:
- [public/office/vendor/pixel-agents/README.md](/home/ivan/xuan/nano_project/app-instance/frontend/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 4``16`
- 编号顺序按从左到右、从上到下
首版 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`
- 地毯下边缘
11. `tile-10-rug-edge-left`
- 地毯左边缘
12. `tile-11-rug-edge-right`
- 地毯右边缘
13. `tile-12-corner-inner`
- 内转角
- 用于墙体或地毯转角收边
14. `tile-13-corner-outer`
- 外转角
- 用于房间边界和隔断端点
15. `tile-14-border-accent`
- 装饰边框格
- 用于壁炉橙 / 冷蓝点缀的少量节奏
16. `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