docs: clarify architecture baselines
This commit is contained in:
parent
a37fbc4723
commit
ae1faa03d0
@ -1,271 +1,208 @@
|
||||
# Assistant 任务线程信息架构
|
||||
|
||||
笔记名建议:
|
||||
本文分为两部分:
|
||||
|
||||
- `不是聊天框,是任务工作台:AI App 里的线程隔离设计`
|
||||
- 当前已实现的线程信息架构基线
|
||||
- 尚未落地、只应视为未来扩展方向的 IA 目标
|
||||
|
||||
这份文档不再把未来目标写成“当前 UI 已实现”。
|
||||
|
||||
## 目标
|
||||
|
||||
为 `XWorkmate` 定义一套“任务即线程”的 Assistant 信息架构,让用户能同时处理多个任务,同时保持以下几类状态互不污染:
|
||||
`XWorkmate` 的 Assistant 已经采用“任务即线程”的基本模型,目标是让以下状态尽量按线程隔离:
|
||||
|
||||
- 会话历史
|
||||
- 执行模式
|
||||
- skills
|
||||
- 模型
|
||||
- 附件
|
||||
- 顶部连接状态
|
||||
- 草稿输入与结果输出
|
||||
- 线程标题 / 归档状态
|
||||
|
||||
核心原则:
|
||||
同时需要明确哪些能力当前还没有做成线程级持久化。
|
||||
|
||||
1. 一个任务就是一个线程,不是一个全局聊天框里的子状态。
|
||||
2. 右上角状态只代表当前线程,不代表全局最近一次连接结果。
|
||||
3. 模式、skills、模型、附件都跟线程走,不跟页面走。
|
||||
## 当前已实现基线
|
||||
|
||||
## 页面结构图
|
||||
### 核心原则
|
||||
|
||||
1. 一个任务对应一个 `AssistantThreadRecord`
|
||||
2. `executionTarget`、`selectedSkillKeys`、`assistantModelId`、`messageViewMode` 跟线程走
|
||||
3. 右上角 connection chip 只反映当前线程的解析结果,不直接沿用别的线程状态
|
||||
4. 全局设置只提供默认值,不直接覆盖已有线程
|
||||
|
||||
### 当前页面结构
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["左侧任务线程栏"] --> B["中间会话区"]
|
||||
C["顶部线程状态栏"] --> B
|
||||
D["底部输入与执行区"] --> B
|
||||
E["右侧上下文抽屉"] --> B
|
||||
C["会话头部"] --> B
|
||||
D["底部 composer 工具栏"] --> B
|
||||
|
||||
A1["线程列表"]
|
||||
A2["新建任务"]
|
||||
A3["分组:本地 / 远程 / AI Only"]
|
||||
A4["线程卡片:标题 / 状态 / 更新时间"]
|
||||
A1["分组:仅 AI Gateway / 本地 / 远程"]
|
||||
A2["新对话"]
|
||||
A3["任务卡片"]
|
||||
A4["归档动作"]
|
||||
|
||||
C1["当前线程名称"]
|
||||
C2["当前模式"]
|
||||
C3["当前连接状态"]
|
||||
C4["已启用 skills 数"]
|
||||
C5["当前模型 / Agent"]
|
||||
C1["标题"]
|
||||
C2["任务状态"]
|
||||
C3["owner / surface / session key"]
|
||||
C4["message view mode"]
|
||||
C5["connection chip"]
|
||||
|
||||
B1["消息流"]
|
||||
B2["任务结果"]
|
||||
B3["运行中步骤"]
|
||||
B4["错误与重试"]
|
||||
|
||||
D1["输入框"]
|
||||
D2["模式切换"]
|
||||
D3["skills 选择"]
|
||||
D4["附件"]
|
||||
D5["提交 / 停止 / 重连"]
|
||||
|
||||
E1["线程配置"]
|
||||
E2["已选 skills"]
|
||||
E3["附件列表"]
|
||||
E4["运行历史"]
|
||||
E5["导出 / 归档"]
|
||||
D1["执行模式切换"]
|
||||
D2["多 Agent toggle"]
|
||||
D3["skills"]
|
||||
D4["permission"]
|
||||
D5["model"]
|
||||
D6["thinking"]
|
||||
D7["附件选择"]
|
||||
D8["发送 / 重连 / 打开设置"]
|
||||
```
|
||||
|
||||
## 信息架构
|
||||
当前没有独立落地的右侧“线程上下文抽屉”。
|
||||
|
||||
## 当前 UI 真实分布
|
||||
|
||||
### 1. 左侧:任务线程栏
|
||||
|
||||
用途:
|
||||
当前已实现:
|
||||
|
||||
- 管理任务线程
|
||||
- 显示线程分组与归属
|
||||
- 快速切换当前上下文
|
||||
- 任务按 `AssistantExecutionTarget` 分组显示
|
||||
- 支持新建线程
|
||||
- 支持切换线程
|
||||
- 支持归档线程
|
||||
- 任务卡片显示标题、状态、更新时间
|
||||
|
||||
建议字段:
|
||||
当前未实现:
|
||||
|
||||
- 标题:`任务`
|
||||
- 主操作:`新建任务`
|
||||
- 分组:
|
||||
- `仅 AI Gateway`
|
||||
- `本地 OpenClaw Gateway`
|
||||
- `远程 OpenClaw Gateway`
|
||||
- 单条线程卡片:
|
||||
- `任务名`
|
||||
- `模式 · 状态 · 更新时间`
|
||||
- 线程导出
|
||||
- 线程模板
|
||||
- 线程级自动化入口
|
||||
|
||||
建议文案:
|
||||
### 2. 会话头部
|
||||
|
||||
- 空态:`还没有任务线程,先新建一个。`
|
||||
- 分组说明:`任务按当前执行模式分组展示。`
|
||||
当前头部显示的是:
|
||||
|
||||
### 2. 顶部:线程状态栏
|
||||
- 当前线程标题
|
||||
- 当前任务状态 pill
|
||||
- owner
|
||||
- surface
|
||||
- session key
|
||||
- message view mode
|
||||
- connection chip
|
||||
|
||||
用途:
|
||||
当前没有把以下信息集中放到头部:
|
||||
|
||||
- 告诉用户当前正在操作哪个线程
|
||||
- 让模式、状态、skills、模型一眼可见
|
||||
- 单独的 skills 数
|
||||
- 单独的模型标签
|
||||
- 独立的模式标签字段
|
||||
|
||||
建议字段:
|
||||
|
||||
- 当前线程名称
|
||||
- 当前模式
|
||||
- 当前连接状态
|
||||
- 当前地址或模型
|
||||
- 当前 skills 数
|
||||
|
||||
状态显示规则:
|
||||
|
||||
- `仅 AI Gateway` 线程:
|
||||
- `仅 AI Gateway · gpt-5.4`
|
||||
- 不显示 `已连接 OpenClaw ...`
|
||||
- `本地 OpenClaw Gateway` 线程:
|
||||
- `已连接 · 127.0.0.1:18789`
|
||||
- 若当前线程未连通,则显示本线程目标地址,不沿用别的线程状态
|
||||
- `远程 OpenClaw Gateway` 线程:
|
||||
- `已连接 · gateway.example.com:9443`
|
||||
- 若当前线程失败,则显示 `错误 · gateway.example.com:9443`
|
||||
|
||||
建议文案:
|
||||
|
||||
- `这里显示的状态只属于当前任务线程。`
|
||||
这些能力目前主要在底部 composer 工具栏里呈现;模式语义则通过 connection chip 和执行模式按钮共同体现。
|
||||
|
||||
### 3. 中间:会话内容区
|
||||
|
||||
用途:
|
||||
当前已实现:
|
||||
|
||||
- 承载当前线程完整消息历史
|
||||
- 承载当前线程的执行结果、错误与流式过程
|
||||
|
||||
建议区块:
|
||||
|
||||
- 消息流
|
||||
- 任务结果
|
||||
- 运行步骤
|
||||
- 错误与重试
|
||||
|
||||
建议文案:
|
||||
|
||||
- 区块标题:`当前任务会话`
|
||||
- 说明:`当前线程的消息、结果和运行记录都独立保存。`
|
||||
- 运行中:`正在执行当前任务,结果将回到这个线程。`
|
||||
- 错误:`当前线程连接失败,请重试或调整该线程配置。`
|
||||
- 渲染当前线程的消息历史
|
||||
- 渲染本地任务卡片 / tool call / assistant message
|
||||
- 流式结果回到当前线程
|
||||
- 切线程后按当前线程重新解析内容来源
|
||||
|
||||
### 4. 底部:输入与执行区
|
||||
|
||||
用途:
|
||||
当前已实现:
|
||||
|
||||
- 所有输入动作默认绑定当前线程
|
||||
- 防止用户误以为切模式是全局行为
|
||||
- 执行模式切换
|
||||
- skills 选择
|
||||
- 模型选择
|
||||
- 权限等级
|
||||
- reasoning 选择
|
||||
- 附件选择
|
||||
- 提交 / 停止 / 重连 / 打开设置
|
||||
|
||||
建议字段:
|
||||
也就是说,当前“模型”和“skills”不是头部状态栏字段,而是 composer toolbar 字段。
|
||||
|
||||
- 输入框
|
||||
- 任务模式
|
||||
- 本线程 skills
|
||||
- 附件
|
||||
- 提交 / 停止 / 重连
|
||||
### 5. 右侧上下文抽屉
|
||||
|
||||
建议文案:
|
||||
当前状态:
|
||||
|
||||
- 输入框 placeholder:
|
||||
- `输入需求、补充上下文、继续追问,系统只会沿用当前任务线程上下文。`
|
||||
- 附件说明:
|
||||
- `仅附加到当前线程`
|
||||
- 独立的“线程上下文抽屉”没有落地为已交付能力
|
||||
- 文档里提到的 `线程配置 / 已选技能 / 附件 / 运行历史 / 导出` 目前不应视为已实现 UI
|
||||
|
||||
### 5. 右侧:上下文抽屉
|
||||
## 当前线程隔离矩阵
|
||||
|
||||
用途:
|
||||
|
||||
- 汇总当前线程的结构化状态
|
||||
- 让用户知道哪些配置只影响当前线程
|
||||
|
||||
建议分组:
|
||||
|
||||
- `线程配置`
|
||||
- `已选技能`
|
||||
- `附件`
|
||||
- `运行历史`
|
||||
- `导出 / 归档`
|
||||
|
||||
建议文案:
|
||||
|
||||
- `这些设置只影响当前线程,不会污染其他任务。`
|
||||
|
||||
## 线程隔离矩阵
|
||||
|
||||
| 维度 | 是否线程隔离 | 说明 |
|
||||
| 维度 | 当前状态 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 消息历史 | 是 | 每个线程独立保存历史消息 |
|
||||
| 消息历史 | 是 | 每个线程独立保存 / 解析历史 |
|
||||
| 执行模式 | 是 | `AI Gateway Only / Local / Remote` 跟线程绑定 |
|
||||
| Skills | 是 | 本线程已选 skills 不影响其他线程 |
|
||||
| 模型 | 是 | 当前模型选择跟线程走 |
|
||||
| 附件 | 是 | 仅附着当前线程 |
|
||||
| 草稿输入 | 是 | 输入框草稿按线程保留 |
|
||||
| 顶部状态 | 是 | 只显示当前线程真实状态 |
|
||||
| 全局设置 | 否 | 仅作为默认值,不直接覆盖已有线程 |
|
||||
| Skills | 是 | 已导入 / 已选 skills 跟线程绑定 |
|
||||
| 模型 | 是 | `assistantModelId` 跟线程绑定,没设时回退到默认模型 |
|
||||
| 顶部连接状态 | 是 | 只显示当前线程解析出的连接状态 |
|
||||
| message view mode | 是 | 跟线程绑定 |
|
||||
| 自定义标题 | 是 | 通过 settings 持久化 |
|
||||
| 归档状态 | 是 | 通过 settings 持久化 |
|
||||
| 草稿输入 | 否 | 当前只有页面级 `_inputController` |
|
||||
| 发送前附件草稿 | 否 | 当前只有页面级 `_attachments` |
|
||||
| 导出 | 否 | 未实现 |
|
||||
|
||||
## 交互规则
|
||||
## 当前交互规则
|
||||
|
||||
### 新建线程
|
||||
|
||||
- 新线程默认继承“当前线程模式”和“当前视图模式”
|
||||
当前实现:
|
||||
|
||||
- 新线程继承当前线程的 `executionTarget`
|
||||
- 新线程继承当前线程的 `messageViewMode`
|
||||
- 不继承上一线程的消息历史
|
||||
- 可选择继承当前线程已选 skills,或默认空白
|
||||
|
||||
当前未实现:
|
||||
|
||||
- 创建时可选继承当前线程已选 skills
|
||||
- 线程级输入草稿继承
|
||||
|
||||
### 切换线程
|
||||
|
||||
- 必须同步切换以下状态:
|
||||
- 当前模式
|
||||
- 当前 skills
|
||||
- 当前模型
|
||||
- 当前草稿
|
||||
- 当前顶部状态
|
||||
- 不允许继续显示上一个线程的连接标签
|
||||
当前会同步切换:
|
||||
|
||||
- 当前模式
|
||||
- 当前 skills
|
||||
- 当前模型
|
||||
- 当前顶部连接状态
|
||||
- 当前消息内容解析路径
|
||||
|
||||
当前不会恢复线程级输入草稿,因为这项能力还没有实现。
|
||||
|
||||
### 切模式
|
||||
|
||||
当前实现:
|
||||
|
||||
- 模式切换默认只影响当前线程
|
||||
- 若用户需要更改默认新线程模式,应单独在设置中完成
|
||||
- 切模式后,顶部状态立即切到目标线程语义,再异步刷新真实连接结果
|
||||
- 同时允许更新 `settings.assistantExecutionTarget` 作为默认新线程模式
|
||||
- 切换后会按线程目标重连 / 断连 runtime,并刷新 skills / connection state
|
||||
|
||||
## 推荐的用户可见文案
|
||||
## 当前实现与未来目标的边界
|
||||
|
||||
- `每个任务都是独立线程。`
|
||||
- `模式只对当前线程生效。`
|
||||
- `技能只绑定当前线程。`
|
||||
- `右上角状态只代表当前线程,不代表全局。`
|
||||
下面这些描述只应视为未来扩展方向,不能再当成“当前 UI 已实现”:
|
||||
|
||||
## 讨论补充
|
||||
|
||||
### 为什么不能继续用“一个大聊天框”
|
||||
|
||||
单一聊天框模型在以下场景会迅速失效:
|
||||
|
||||
- 用户并行处理多个任务
|
||||
- 本地 / 远程 / AI Gateway Only 频繁切换
|
||||
- skills 与模型依赖任务上下文
|
||||
- 用户需要回到旧线程继续追问
|
||||
|
||||
一旦线程态和全局态混用,用户会立刻遇到:
|
||||
|
||||
- 模式看起来切了,但顶部状态没切
|
||||
- 远程线程显示了本地连接结果
|
||||
- skills 继承错线程
|
||||
- 附件或草稿进入错误任务
|
||||
|
||||
### 为什么顶部状态必须线程化
|
||||
|
||||
用户不会区分“全局 runtime”与“当前任务线程”。
|
||||
用户只会看见:
|
||||
|
||||
- 我当前在哪个任务里
|
||||
- 这个任务现在通过哪条链路工作
|
||||
- 这个任务到底连没连上
|
||||
|
||||
所以顶部状态必须遵守“当前线程优先”,否则用户会失去信任。
|
||||
|
||||
### 产品定位上的收益
|
||||
|
||||
把 Assistant 从“聊天框”升级成“任务工作台”后,后续功能才更自然:
|
||||
|
||||
- 多 Agent 协作
|
||||
- 线程归档
|
||||
- 右侧线程上下文抽屉
|
||||
- 线程级输入草稿持久化
|
||||
- 发送前附件的线程级草稿隔离
|
||||
- 新线程可选继承当前线程已选 skills
|
||||
- 线程导出
|
||||
- 线程模板
|
||||
- 线程级自动化
|
||||
- 线程级审阅与导出
|
||||
|
||||
这也是后续做任务列表、归档、线程模板、任务恢复的前提。
|
||||
## 为什么仍然坚持线程优先
|
||||
|
||||
虽然当前 UI 还没把所有线程信息都集中到一个面板里,但线程优先原则已经成立:
|
||||
|
||||
- 当前线程决定执行模式
|
||||
- 当前线程决定模型
|
||||
- 当前线程决定 imported / selected skills
|
||||
- 当前线程决定 connection chip 显示
|
||||
|
||||
这也是后续继续扩展任务工作台能力的基础。
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [模式切换与线程连续追问](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate.svc.plus/docs/cases/thread_mode_switch_followup.md)
|
||||
- [XWorkmate 集成架构](/Users/shenlan/workspaces/cloud-neutral-toolkit/xworkmate.svc.plus/docs/architecture/xworkmate-integrations.md)
|
||||
- [模式切换与线程连续追问](/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/docs/cases/thread_mode_switch_followup.md)
|
||||
- [XWorkmate 集成架构](/Users/shenlan/workspaces/cloud-neutral-toolkit/XWorkmate.svc.plus/docs/architecture/xworkmate-integrations.md)
|
||||
|
||||
@ -2,10 +2,13 @@
|
||||
|
||||
## 目标
|
||||
|
||||
这次补丁保持现有 UI 不变,只重设计 `XWorkmate` 的本地配置与任务会话持久层,满足两个约束:
|
||||
本文记录 `XWorkmate.svc.plus` 当前桌面端本地持久化实现的真实基线,并明确区分:
|
||||
|
||||
- 本地配置和任务会话必须能跨重启、跨覆盖安装恢复。
|
||||
- 持久化以前提 `secure storage` 为本地信任根,避免把可恢复状态明文落盘。
|
||||
- 当前正在使用的持久化路径
|
||||
- 仅用于旧版本恢复的 legacy sealed-state 路径
|
||||
- secret 与 recoverable local state 的边界
|
||||
|
||||
如果后续重新引入 sealed local state,这份文档必须和 `SettingsStore` 写路径、测试断言一起更新。
|
||||
|
||||
## 当前实现基线(v0.6.1)
|
||||
|
||||
@ -15,68 +18,79 @@
|
||||
|
||||
- `~/Library/Application Support/plus.svc.xworkmate/xworkmate`
|
||||
|
||||
关键文件与目录:
|
||||
当前活跃文件与目录:
|
||||
|
||||
- `config-store.sqlite3`(`SettingsStore` 主库)
|
||||
- `settings-snapshot.json`(durable mirror)
|
||||
- `assistant-threads.json`(durable mirror)
|
||||
- `gateway-auth/secure-storage/*`(`SecretStore` 文件型安全存储 fallback)
|
||||
- `config-store.sqlite3`
|
||||
- `SettingsStore` 主库
|
||||
- `settings-snapshot.json`
|
||||
- `SettingsSnapshot` 的 durable mirror
|
||||
- `assistant-threads.json`
|
||||
- `AssistantThreadRecord` 列表的 durable mirror
|
||||
- `gateway-auth/secure-storage/*`
|
||||
- `SecretStore` 的文件型 secure-storage fallback
|
||||
|
||||
### 2) 首次安装初始化
|
||||
|
||||
- `SettingsStore.initialize()` 会初始化并打开 `config-store.sqlite3`。
|
||||
- `SecretStore.initialize()` 会初始化 `gateway-auth` 与 `secure-storage` 目录结构。
|
||||
- 因此 DMG 首次安装后,重启前无需手工“触发一次保存”即可完成持久化目录与主存储文件的准备。
|
||||
- `SettingsStore.initialize()` 会初始化并打开 `config-store.sqlite3`
|
||||
- `SecretStore.initialize()` 会初始化 `gateway-auth` 与 `secure-storage` 目录结构
|
||||
- 因此首次安装后,不需要等用户手工保存一次,目录与主存储文件就会被准备好
|
||||
|
||||
### 3) 升级与重启行为
|
||||
|
||||
- 应用升级 / 系统更新重启不会改写或重置既有路径。
|
||||
- 只在用户主动执行“设置 -> 诊断 -> 清理任务线程与本地配置”时清理本地 settings/thread 状态。
|
||||
- 清理流程不删除已保存 secrets(Gateway token/password、AI Gateway API key、Vault token 等)。
|
||||
- 应用升级 / 系统更新重启不会改写既有持久化目录
|
||||
- 用户主动执行“设置 -> 诊断 -> 清理任务线程与本地配置”时,清理的是本地 settings / thread 状态
|
||||
- 清理流程不会删除已保存 secrets(Gateway token / password、AI Gateway API key、Vault token、device token 等)
|
||||
|
||||
### 4) 路径解析失败策略(默认)
|
||||
|
||||
- 默认策略为 `fail-fast`:当 `SettingsStore` 无法解析或打开耐久数据库路径时,直接抛错,不再静默降级为内存持久化。
|
||||
- 这样可以避免“看起来保存成功、重启后全部丢失”的隐性故障。
|
||||
- 默认策略仍然是 `fail-fast`
|
||||
- 当 `SettingsStore` 无法解析或打开耐久数据库路径时,直接抛错
|
||||
- 只有显式开启 `allowInMemoryFallback` 时才允许内存数据库回退
|
||||
|
||||
### 5) 内存回退(仅显式开启场景)
|
||||
### 5) 当前最重要的实现结论
|
||||
|
||||
- 仅在显式开启 `allowInMemoryFallback`(主要用于测试/诊断)时允许内存回退。
|
||||
- 即使发生内存回退,也会在后续写入和销毁阶段尽力回写同步到耐久目录(若路径恢复可用)。
|
||||
|
||||
核心结论:
|
||||
|
||||
- `FlutterSecureStorage` 仍是长期 secret 的主存储。
|
||||
- 本地配置和任务会话不直接明文写入 SQLite / JSON,而是先用本地状态密钥加密后再落盘。
|
||||
- 本地状态密钥本身必须优先保存在主 secure storage,不再把它当成普通可降级 secret。
|
||||
- 长期 secret 继续通过 `SecretStore` 持久化,主路径是 `FlutterSecureStorage`
|
||||
- `SettingsSnapshot` 与 `AssistantThreadRecord` 当前写入的是明文 JSON 字符串
|
||||
- 会写入 `config-store.sqlite3`
|
||||
- 也会写入 `settings-snapshot.json` / `assistant-threads.json`
|
||||
- `assistant-state-backup.json`、`sealedState`、`xworkmate.local_state.key` 现在不是当前主写路径
|
||||
- 它们只保留在旧版本恢复 / 迁移兼容逻辑里
|
||||
|
||||
## Trust Boundary
|
||||
|
||||
需要明确区分 3 类状态:
|
||||
当前需要区分 3 类状态:
|
||||
|
||||
1. 用户输入的高敏感 secret
|
||||
- Gateway shared token
|
||||
- Gateway password
|
||||
- AI Gateway API key
|
||||
- Vault token
|
||||
### 1. 高敏感 secret
|
||||
|
||||
2. 可恢复但不应明文落盘的本地状态
|
||||
- `SettingsSnapshot`
|
||||
- Assistant 任务线程记录
|
||||
- 最后活动线程
|
||||
- 本地恢复 backup
|
||||
- Gateway shared token
|
||||
- Gateway password
|
||||
- AI Gateway API key
|
||||
- Vault token
|
||||
- device token / device identity 私钥材料
|
||||
|
||||
3. 仅调试或测试环境可接受的替代路径
|
||||
- 注入式 secure storage client
|
||||
- 临时文件型 secure storage fallback
|
||||
### 2. 可恢复的本地应用状态
|
||||
|
||||
- `SettingsSnapshot`
|
||||
- `AssistantThreadRecord` 列表
|
||||
- assistant custom task titles
|
||||
- archived task keys
|
||||
- last session key
|
||||
- 本地审计 trail
|
||||
|
||||
### 3. Legacy sealed-state 恢复输入
|
||||
|
||||
- 旧版 `assistant-state-backup.json`
|
||||
- 旧版 `xworkmate.sealed.local-state.v1` payload
|
||||
- `local-state-key.txt`
|
||||
- secure storage 里的 `xworkmate.local_state.key`
|
||||
|
||||
边界规则:
|
||||
|
||||
- 第 1 类状态优先进入 secure storage;secure storage 超时或异常时,可进入持久化 fallback 文件,但绝不退化成“仅内存”。
|
||||
- 第 2 类状态不直接进入 `SharedPreferences` 或明文 SQLite;必须先 sealed。
|
||||
- 第 3 类路径只用于 debug / test,不进入 release 行为。
|
||||
- 第 1 类状态走 `SecretStore`
|
||||
- 第 2 类状态当前走 `SettingsStore`,属于 recoverable app state,不是 secret store
|
||||
- 第 3 类状态只用于 recovery / migration,不是当前版本的常规写入目标
|
||||
|
||||
## 架构图
|
||||
## 当前架构图
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
@ -85,164 +99,173 @@ flowchart TD
|
||||
B --> E["SecureConfigStore"]
|
||||
D --> E
|
||||
|
||||
E --> F["Primary Secure Storage<br/>FlutterSecureStorage"]
|
||||
E --> G["Local State Key<br/>xworkmate.local_state.key"]
|
||||
G --> H["AES-GCM Seal / Unseal"]
|
||||
E --> F["SecretStore"]
|
||||
E --> G["SettingsStore"]
|
||||
|
||||
H --> I["SQLite config-store.sqlite3"]
|
||||
H --> J["Durable state files<br/>settings-snapshot.json<br/>assistant-threads.json"]
|
||||
H --> K["assistant-state-backup.json<br/>schemaVersion=2 / sealedState"]
|
||||
F --> H["FlutterSecureStorage"]
|
||||
F --> I["gateway-auth/secure-storage/*<br/>file fallback"]
|
||||
|
||||
E --> L["Secure secret fallback files<br/>gateway-auth/*"]
|
||||
G --> J["config-store.sqlite3"]
|
||||
G --> K["settings-snapshot.json"]
|
||||
G --> L["assistant-threads.json"]
|
||||
|
||||
M["Legacy sealed-state sources"] --> N["legacy recovery / migration"]
|
||||
N --> G
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- 当前活跃写路径是 `SecretStore` + `SettingsStore`
|
||||
- legacy sealed-state 只参与读旧数据并迁移到当前 store,不参与当前常规写入
|
||||
|
||||
## 存储分层
|
||||
|
||||
### 1. Primary Secure Storage
|
||||
### 1. 当前 secret 存储
|
||||
|
||||
用途:
|
||||
|
||||
- 保存 Gateway token / password / AI Gateway API key / Vault token
|
||||
- 保存本地状态密钥 `xworkmate.local_state.key`
|
||||
- 保存 Gateway token / password
|
||||
- 保存 AI Gateway API key
|
||||
- 保存 Vault token
|
||||
- 保存 device identity / device token
|
||||
|
||||
关键要求:
|
||||
实现要点:
|
||||
|
||||
- 主路径仍然是 `FlutterSecureStorage`
|
||||
- 本地状态密钥不允许再走“通用 secret fallback”
|
||||
- 如果主 secure storage 不可用,不允许把本地状态密钥退化成普通文件常态
|
||||
- 主路径是 `FlutterSecureStorage`
|
||||
- 当 secure storage 不可用时,`SecretStore` 会尝试提升到文件型 fallback
|
||||
- 文件型 fallback 位于 `gateway-auth/secure-storage/*`
|
||||
|
||||
### 2. Sealed Local State
|
||||
|
||||
本地配置和任务会话的持久化结构统一改为:
|
||||
|
||||
- `storageFormat = xworkmate.sealed.local-state.v1`
|
||||
- `nonce`
|
||||
- `cipherText`
|
||||
- `mac`
|
||||
|
||||
加密方式:
|
||||
|
||||
- AES-GCM 256
|
||||
- 每次写入使用新的随机 nonce
|
||||
- AAD 绑定存储 key,避免跨 key 错读
|
||||
### 2. 当前本地状态持久化
|
||||
|
||||
当前覆盖对象:
|
||||
|
||||
- `xworkmate.settings.snapshot`
|
||||
- `xworkmate.assistant.threads`
|
||||
- `assistant-state-backup.json`
|
||||
- `xworkmate.secrets.audit`
|
||||
|
||||
### 3. Durable Recovery Files
|
||||
实现要点:
|
||||
|
||||
当 SQLite 不可用时,仍需保证本地状态可以恢复。为此保留两类耐久化文件:
|
||||
- `SettingsSnapshot` 通过 `toJsonString()` 写入
|
||||
- `AssistantThreadRecord` 列表通过 `jsonEncode(...)` 写入
|
||||
- 当前写路径没有 AES-GCM seal / unseal
|
||||
- durable mirror 文件内容当前也是明文 JSON,不是 sealed envelope
|
||||
|
||||
### 3. Durable mirror files
|
||||
|
||||
当前保留两类 durable mirror:
|
||||
|
||||
- `settings-snapshot.json`
|
||||
- `assistant-threads.json`
|
||||
|
||||
注意:
|
||||
语义:
|
||||
|
||||
- 文件名虽然保持旧风格,但内容已改为 sealed payload,不再是明文 JSON。
|
||||
- 作为 SQLite 的文件镜像 / fallback 来源
|
||||
- 也是测试里会直接读取和断言的当前持久化内容
|
||||
|
||||
### 4. Assistant Backup
|
||||
### 4. Legacy sealed-state recovery path
|
||||
|
||||
`assistant-state-backup.json` 升级到 schema v2:
|
||||
旧版 sealed local state 兼容仍然保留,但仅用于 recovery:
|
||||
|
||||
- 用 `sealedState` 保存整体恢复快照
|
||||
- 不再把 settings / threads 明文拼进 backup
|
||||
- 识别旧版 `xworkmate.sealed.local-state.v1`
|
||||
- 读取旧版 `assistant-state-backup.json` 里的 `sealedState`
|
||||
- 通过 legacy local state key 解密旧 payload
|
||||
- 成功恢复后重写到当前 `SettingsStore`
|
||||
|
||||
这样做的目的:
|
||||
这条路径的目标是兼容旧数据,不代表当前版本仍在主动写 sealed local state。
|
||||
|
||||
- 避免备份文件成为最容易泄露的明文副本
|
||||
- 保持“数据库损坏时仍可恢复”的能力
|
||||
|
||||
## 写入流程
|
||||
## 当前写入流程
|
||||
|
||||
### SettingsSnapshot
|
||||
|
||||
1. `SettingsController` 生成新的 `SettingsSnapshot`
|
||||
2. `SecureConfigStore.saveSettingsSnapshot()` 进入本地状态写队列
|
||||
3. 读取或生成 `xworkmate.local_state.key`
|
||||
4. 先 sealed,再写入 SQLite / durable file / backup
|
||||
1. `SettingsController` 或 `AppController` 生成新的 `SettingsSnapshot`
|
||||
2. `SecureConfigStore.saveSettingsSnapshot()`
|
||||
3. `SettingsStore.saveSettingsSnapshot()`
|
||||
4. `snapshot.toJsonString()`
|
||||
5. 写入 SQLite
|
||||
6. 同步写入 `settings-snapshot.json`
|
||||
|
||||
### Assistant Threads
|
||||
|
||||
1. `AppController` 更新线程记录
|
||||
2. 持久化进入 `_assistantThreadPersistQueue`
|
||||
3. `SecureConfigStore.saveAssistantThreadRecords()` 串行 sealed 写入
|
||||
4. 同步刷新 SQLite / durable file / backup
|
||||
2. 更新被串行排入 `_assistantThreadPersistQueue`
|
||||
3. `SecureConfigStore.saveAssistantThreadRecords()`
|
||||
4. `jsonEncode(records.map(...))`
|
||||
5. 写入 SQLite
|
||||
6. 同步写入 `assistant-threads.json`
|
||||
|
||||
这么做是为了避免异步写晚到,把旧线程快照覆盖新状态。
|
||||
这么做的目标是避免异步写晚到覆盖较新的线程快照;当前目标不是加密封装。
|
||||
|
||||
## 读取与恢复流程
|
||||
## 当前读取与恢复流程
|
||||
|
||||
恢复顺序:
|
||||
|
||||
1. 优先读 SQLite
|
||||
2. SQLite 不可用时读 durable state files
|
||||
3. 若主状态缺失,再读 `assistant-state-backup.json`
|
||||
4. 若读到的是旧明文格式,则立即迁移为 sealed 格式
|
||||
1. 初始化 SQLite
|
||||
2. 优先读取 SQLite entry
|
||||
3. SQLite 读不到时,再读 durable mirror 文件
|
||||
4. 如果当前 state 不可读,再尝试 legacy recovery
|
||||
5. 若发现旧 sealed-state 但缺少 key,则产生 locked recovery report
|
||||
|
||||
迁移原则:
|
||||
补充说明:
|
||||
|
||||
- 兼容旧明文快照,避免升级后直接丢历史
|
||||
- 一旦成功恢复,就把旧格式重写成 sealed 新格式
|
||||
- legacy `SharedPreferences` 里的本地状态在迁移后会被清理
|
||||
- `SharedPreferences` 只作为旧数据迁移兼容来源,不是当前桌面端的主状态真值源
|
||||
- Web 端有独立的 `WebStore`,不适用这里的桌面持久化链路
|
||||
|
||||
## Secure Secret Fallback
|
||||
## Legacy backup / sealedState 的当前语义
|
||||
|
||||
Secret fallback 仍然保留,但语义变了:
|
||||
当前代码里:
|
||||
|
||||
- 用于 Gateway token / password / API key 等长期 secret 的持久化兜底
|
||||
- 不再因为一次超时就退化成“仅内存”
|
||||
- 这样即使 secure storage 一时不可用,重启后 secret 仍能恢复
|
||||
- `assistant-state-backup.json` 只在 legacy recovery 时读取
|
||||
- `sealedState` 只在旧版 backup 或旧版 durable value 解密时出现
|
||||
- `xworkmate.local_state.key` 只通过 legacy loader 参与旧数据恢复
|
||||
|
||||
约束:
|
||||
因此这三者现在应该被理解为:
|
||||
|
||||
- `xworkmate.local_state.key` 不在通用 fallback 白名单里
|
||||
- 对旧版遗留的 `local-state-key.txt`,启动时做一次迁移,成功后删除
|
||||
- 兼容旧版本
|
||||
- 避免升级后直接丢历史
|
||||
- 不属于当前日常写入架构
|
||||
|
||||
## Clear 行为
|
||||
|
||||
`clearAssistantLocalState()` 只清理:
|
||||
`clearAssistantLocalState()` 当前会清理:
|
||||
|
||||
- 本地 settings snapshot
|
||||
- 本地 assistant thread records
|
||||
- durable state files
|
||||
- assistant backup
|
||||
- `SettingsSnapshot`
|
||||
- `AssistantThreadRecord` 列表
|
||||
- `settings-snapshot.json`
|
||||
- `assistant-threads.json`
|
||||
- 旧版 `assistant-state-backup.json`(如果存在)
|
||||
|
||||
不会误删:
|
||||
|
||||
- 已保存的 Gateway token / password
|
||||
- Gateway token / password
|
||||
- AI Gateway API key
|
||||
- Vault token
|
||||
- 其他 secure refs
|
||||
- device token / device identity
|
||||
|
||||
## Debug / Test 策略
|
||||
|
||||
为了让测试稳定运行,新增了可注入的 secure storage 层:
|
||||
为了让测试稳定运行,当前保留可注入的 secure storage client:
|
||||
|
||||
- `SecureStorageClient`
|
||||
- `FlutterSecureStorageClient`
|
||||
- `FileSecureStorageClient`
|
||||
- `MemorySecureStorageClient`
|
||||
|
||||
策略是:
|
||||
策略:
|
||||
|
||||
- release:使用真实 `FlutterSecureStorage`
|
||||
- debug / test:允许走注入式或文件型 secure storage,保证单测和回归可跑
|
||||
- release:优先真实 `FlutterSecureStorage`
|
||||
- debug / test:允许注入式或文件型 secure storage
|
||||
- `allowInMemoryFallback` 只在显式场景下允许内存数据库回退
|
||||
|
||||
这不会改变 release 的安全边界。
|
||||
## 当前文档结论
|
||||
|
||||
## 与现有 UI 的关系
|
||||
当前桌面端本地持久化不是 sealed local state 架构,而是:
|
||||
|
||||
这次补丁不改:
|
||||
- secrets 走 secure storage / file fallback
|
||||
- recoverable local app state 走 SQLite + plain JSON durable mirrors
|
||||
- legacy sealed-state 只用于恢复旧数据
|
||||
|
||||
- Gateway 设置页结构
|
||||
- Assistant 任务线程 UI
|
||||
- 模型、skills、入口按钮布局
|
||||
如果后续要把本地状态重新升级为 sealed payload,必须同步更新:
|
||||
|
||||
变化只在持久层和恢复链路:
|
||||
|
||||
- 重启后不再因为 secure storage 一次超时而丢本地配置
|
||||
- 覆盖安装后本地配置与任务会话仍可恢复
|
||||
- 本地 snapshot / backup 不再以明文保存
|
||||
- `SettingsStore` 写路径
|
||||
- 文档中的架构图与存储分层
|
||||
- 相关测试断言
|
||||
|
||||
@ -17,15 +17,20 @@ This document records the default `simple` theme token set for `XWorkmate.svc.pl
|
||||
|
||||
## Radius
|
||||
|
||||
- card radius: `6`
|
||||
- input radius: `8`
|
||||
- button radius: `8`
|
||||
- dialog radius: `5`
|
||||
- card radius: `16`
|
||||
- input radius: `14`
|
||||
- button radius: `12`
|
||||
- dialog radius: `18`
|
||||
- chip radius: `12`
|
||||
- sidebar radius: `20`
|
||||
|
||||
## Size
|
||||
|
||||
- input height: `36`
|
||||
- button height: `16`
|
||||
- textarea height: `36`
|
||||
- input height: `40`
|
||||
- button height: `30` desktop / `36` mobile
|
||||
- toolbar height: `40`
|
||||
- sidebar item height: `34`
|
||||
|
||||
## Source Of Truth
|
||||
|
||||
|
||||
@ -2,39 +2,50 @@
|
||||
|
||||
## 概述
|
||||
|
||||
XWorkmate 现阶段的集成基线已经从“单一 Codex bridge”升级为“统一发现与分发中心”。App 负责发现、托管和分发三类协作资产:
|
||||
XWorkmate 现阶段已经不只是“单一 Codex bridge”,但当前实现也不是一个单独的 “Discovery / Distribution Catalog” 模块。
|
||||
|
||||
1. `skills`
|
||||
2. `MCP server list`
|
||||
3. `AI Gateway` 默认注入
|
||||
当前集成能力分散在几条明确的实现路径里:
|
||||
|
||||
运行时上,XWorkmate 不再把 CLI 视为孤立工具,而是通过本地 broker 与编排层统一驱动 `OpenClaw / Codex / Claude / Gemini / OpenCode`。
|
||||
1. `GatewayRuntime`
|
||||
- 负责 OpenClaw Gateway 的实时 RPC、会话、chat、pairing、cron
|
||||
2. `MultiAgentBrokerServer` + `MultiAgentOrchestrator`
|
||||
- 负责多 Agent 协作运行
|
||||
3. `MultiAgentMountManager`
|
||||
- 负责按 adapter 做 CLI 能力探测、MCP reconcile、挂载状态汇总
|
||||
4. `CodexConfigBridge` / `OpencodeConfigBridge`
|
||||
- 负责特定 CLI 的配置文件写入
|
||||
5. Assistant composer 与 feature flags
|
||||
- 决定当前哪些集成入口真实对用户可见
|
||||
|
||||
也就是说,当前架构更接近“分布式集成面”,不是单一 catalog service。
|
||||
|
||||
## 当前架构基线
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
X["XWorkmate App"] --> D["Discovery / Distribution Catalog"]
|
||||
X --> B["MultiAgentBroker<br/>WebSocket JSON-RPC"]
|
||||
X --> G["OpenClaw Gateway / Host"]
|
||||
B --> O["MultiAgentOrchestrator"]
|
||||
O --> C["Codex CLI"]
|
||||
O --> L["Claude CLI"]
|
||||
O --> M["Gemini CLI"]
|
||||
O --> P["OpenCode CLI"]
|
||||
C --> A["AI Gateway"]
|
||||
L --> A
|
||||
M --> A
|
||||
P --> A
|
||||
A --> OL["Ollama / Upstream Model Endpoints"]
|
||||
X["XWorkmate App"] --> GR["GatewayRuntime"]
|
||||
X --> BM["MultiAgentBrokerServer<br/>WebSocket JSON-RPC"]
|
||||
X --> MM["MultiAgentMountManager"]
|
||||
X --> NO["CodeAgentNodeOrchestrator"]
|
||||
X --> UI["Assistant composer / Settings / Feature flags"]
|
||||
|
||||
BM --> O["MultiAgentOrchestrator"]
|
||||
O --> C["Codex / Claude / Gemini / OpenCode"]
|
||||
|
||||
MM --> MA["Codex / Claude / Gemini / OpenCode / OpenClaw adapters"]
|
||||
MA --> CFG["Managed config writes / mcp list / local file discovery"]
|
||||
|
||||
GR --> G["OpenClaw Gateway / Host"]
|
||||
NO --> G
|
||||
C --> A["AI Gateway or Ollama endpoint"]
|
||||
```
|
||||
|
||||
关键点:
|
||||
|
||||
- `XWorkmate App` 是唯一的 discovery / distribution center。
|
||||
- `MultiAgentBroker` 是多 CLI 协作的本地运行时入口。
|
||||
- `OpenClaw` 既是现有 Gateway 集成面,也是可被托管发现的宿主控制面。
|
||||
- `AI Gateway` 的语义是“XWorkmate 协作运行默认 provider”,不是用户全局 provider 替换器。
|
||||
- `OpenClaw` 既是现有 Gateway 集成面,也是当前 app-mediated code-agent dispatch 的宿主控制面。
|
||||
- `AI Gateway` 既可以是 direct AI 对话入口,也可以是协作运行的注入式模型入口。
|
||||
- 当前没有一个单独命名为 `Discovery / Distribution Catalog` 的实现模块。
|
||||
|
||||
## 1. OpenClaw Gateway / Host
|
||||
|
||||
@ -57,19 +68,19 @@ flowchart LR
|
||||
- `agent/register`
|
||||
- `memory/sync`
|
||||
|
||||
新的定位:
|
||||
当前定位:
|
||||
|
||||
- 继续作为 Gateway RPC 面存在。
|
||||
- 额外纳入“可挂载目标”集合。
|
||||
- 发现 `agents / skills / plugins` 状态,但不覆盖用户现有默认 agent。
|
||||
- 继续作为 Gateway RPC 面存在
|
||||
- 也是 app-mediated code-agent dispatch 的控制面目标
|
||||
- 在 mount 视角下,OpenClaw 目前更多是“本地发现 + 宿主控制面”,不是一个统一的 skills / plugins catalog service
|
||||
|
||||
## 2. AI Gateway
|
||||
|
||||
用途:
|
||||
|
||||
- 统一模型入口
|
||||
- 作为 XWorkmate 协作运行的默认模型路由
|
||||
- 为外部 CLI 提供 launch-scoped 或托管 provider 注入
|
||||
- direct AI 对话入口
|
||||
- 协作运行时的模型注入入口
|
||||
- 对部分 CLI 的配置桥接入口
|
||||
|
||||
边界:
|
||||
|
||||
@ -79,9 +90,12 @@ flowchart LR
|
||||
|
||||
当前策略:
|
||||
|
||||
- `Codex` 可以追加 `xworkmate` provider 托管块
|
||||
- `Claude / Gemini / OpenCode` 优先采用 launch-scoped 注入
|
||||
- Gateway 不可用时允许回退到 CLI 原有配置
|
||||
- `CodexConfigBridge` 可以写入受管 provider / MCP block
|
||||
- `MultiAgentOrchestrator` 在协作运行中会通过环境变量或 `ollama launch` 传递模型入口
|
||||
- `Claude / Gemini` 的 mount reconcile 目前主要做 discovery,AI Gateway 仍保持 launch-scoped
|
||||
- `OpenCode` 当前有受管 MCP config;AI Gateway 语义仍偏 launch-scoped / runtime injection
|
||||
|
||||
换句话说,AI Gateway 能力是分散落地的,不是所有 CLI 都通过同一条托管 provider 路径接入。
|
||||
|
||||
## 3. Multi-Agent Runtime
|
||||
|
||||
@ -107,12 +121,15 @@ flowchart LR
|
||||
### UI 接线
|
||||
|
||||
- Assistant 继续复用现有 composer、附件、当前会话
|
||||
- Settings 继续复用现有 Multi-Agent 区块
|
||||
- 桌面端真正对用户可见的协作入口,当前主要是 Assistant composer 上的协作 toggle
|
||||
- `SettingsPage` 里有 Multi-Agent 配置区块与 detail 页面代码,但桌面端 `settings.agents` 仍被 feature flag 关闭
|
||||
- 不新增独立任务页面
|
||||
|
||||
## 4. 发现与分发
|
||||
|
||||
XWorkmate 统一维护两类状态:
|
||||
当前实现里,`managed / external` 更像一套按 adapter 执行的操作规则,而不是单独的中心化状态目录。
|
||||
|
||||
XWorkmate 仍然区分两类对象:
|
||||
|
||||
- `managed`
|
||||
- 由 App 创建与维护的托管项
|
||||
@ -124,16 +141,17 @@ XWorkmate 统一维护两类状态:
|
||||
- 只更新 XWorkmate 托管项
|
||||
- 不删除外部已有项
|
||||
- 启动时与保存设置后自动 reconcile
|
||||
- 这套规则当前由 `MultiAgentMountManager` 在各 adapter 上分别执行
|
||||
|
||||
## 5. 挂载入口矩阵
|
||||
|
||||
| 目标 | Skills 挂载入口 | MCP 挂载入口 | AI Gateway 挂载入口 |
|
||||
| --- | --- | --- | --- |
|
||||
| OpenClaw | 发现 `skills / plugins / agents`,broker 注入上下文 | 不作为 MCP 主挂载点 | XWorkmate 协作路径默认 route |
|
||||
| Codex | `AGENTS.md` / skill 上下文 / broker 注入 | `~/.codex/config.toml` 托管块 | `model_providers.xworkmate`,不替换用户默认 |
|
||||
| Claude | broker 注入 | `claude mcp list/add/remove` 发现与兼容 | 启动参数 / 环境注入 |
|
||||
| Gemini | broker 注入,后续可扩展 `extensions` | `gemini mcp list/add/remove` 发现与兼容 | 启动参数 / 环境注入 |
|
||||
| OpenCode | broker 注入,后续可扩展 agent preset | `~/.opencode/config.toml` 托管块 | 启动参数或托管 preset 注入 |
|
||||
| OpenClaw | 本地文件 / 目录发现 + Gateway 控制面 | 不作为 MCP 主挂载点 | app-mediated dispatch / gateway route |
|
||||
| Codex | 当前线程 skills 上下文 +协作运行注入 | `~/.codex/config.toml` 受管 MCP block | 受管 provider bridge + runtime injection |
|
||||
| Claude | 当前线程 skills 上下文 +协作运行注入 | `claude mcp list` 做 discovery | launch-scoped / env / `ollama launch` |
|
||||
| Gemini | 当前线程 skills 上下文 +协作运行注入 | `gemini mcp list` 做 discovery | launch-scoped / env |
|
||||
| OpenCode | 当前线程 skills 上下文 +协作运行注入 | `~/.opencode/config.toml` 受管 MCP block | runtime injection |
|
||||
|
||||
## 6. 外部 Provider 与执行路径
|
||||
|
||||
@ -149,7 +167,7 @@ XWorkmate 统一维护两类状态:
|
||||
现状:
|
||||
|
||||
- `codex` 仍是当前最完整 provider
|
||||
- 其他 CLI 通过 `CliMountAdapter` 与 broker 接入
|
||||
- 其他 CLI 当前主要通过 `CliMountAdapter` discovery / reconcile 与 `MultiAgentOrchestrator` 运行时调用接入
|
||||
- 多 provider 调度 UI 不是当前交付目标
|
||||
|
||||
## 7. 安全边界
|
||||
@ -172,17 +190,21 @@ XWorkmate 统一维护两类状态:
|
||||
实现约束:
|
||||
|
||||
- Gateway 集成页不再重复显示顶层全局 `Save / Apply`,避免与卡片内动作语义冲突。
|
||||
- `settings.gateway_setup_code` 与 `settings.agents` 当前均按 `experimental + enabled: false` 发布策略控制。
|
||||
- 桌面端 `settings.gateway_setup_code` 与 `settings.agents` 当前都被 feature flag 关闭。
|
||||
- 但桌面端 `assistant.multi_agent` 仍然开启,所以协作入口当前主要暴露在 Assistant composer,而不是设置页独立标签。
|
||||
|
||||
## 相关代码
|
||||
|
||||
- `lib/app/app_controller.dart`
|
||||
- `lib/app/app_controller_desktop.dart`
|
||||
- `lib/app/app_controller_web.dart`
|
||||
- `lib/features/assistant/assistant_page.dart`
|
||||
- `lib/features/settings/settings_page.dart`
|
||||
- `lib/runtime/gateway_runtime.dart`
|
||||
- `lib/runtime/runtime_models.dart`
|
||||
- `lib/runtime/multi_agent_orchestrator.dart`
|
||||
- `lib/runtime/multi_agent_broker.dart`
|
||||
- `lib/runtime/multi_agent_mounts.dart`
|
||||
- `lib/runtime/codex_config_bridge.dart`
|
||||
- `lib/runtime/opencode_config_bridge.dart`
|
||||
- `lib/runtime/code_agent_node_orchestrator.dart`
|
||||
- `lib/runtime/runtime_coordinator.dart`
|
||||
|
||||
@ -198,6 +198,9 @@ Primary fields:
|
||||
- _pendingAiGatewayApply
|
||||
- settings.gatewayProfiles
|
||||
- settings.assistantExecutionTarget
|
||||
- settings.assistantCustomTaskTitles
|
||||
- settings.assistantArchivedTaskKeys
|
||||
- settings.assistantLastSessionKey
|
||||
|
||||
Sources:
|
||||
- settings
|
||||
@ -216,6 +219,10 @@ Responsibilities:
|
||||
- Persist secure secrets
|
||||
- Persist OpenClaw connection source profiles
|
||||
- Persist the default work mode for newly created threads
|
||||
- Persist assistant task metadata that is not owned by `AssistantThreadRecord`
|
||||
- custom task titles
|
||||
- archived task keys
|
||||
- last restored session key
|
||||
- Make the saved configuration take effect only when Apply is executed
|
||||
|
||||
Important APIs:
|
||||
@ -423,11 +430,18 @@ Resolution rule:
|
||||
Primary source:
|
||||
- assistantSessions
|
||||
- _taskSeeds in AssistantPage as a rendering cache
|
||||
- settings.assistantCustomTaskTitles
|
||||
- settings.assistantArchivedTaskKeys
|
||||
|
||||
Important rule:
|
||||
Task list is a derived representation of thread/session state.
|
||||
Task list must not become the owner of mode, model, or skill state.
|
||||
|
||||
Important companion rule:
|
||||
Task titles, archive membership, and last-session recovery are not owned only by
|
||||
`AssistantThreadRecord`. Part of that metadata is persisted in `SettingsSnapshot`
|
||||
and must be considered when reconstructing the task list.
|
||||
|
||||
Implementation note:
|
||||
_taskSeeds is still a cache of derived values such as title, preview, status,
|
||||
owner, surface, and executionTarget. It is not an authoritative source, but it
|
||||
|
||||
Loading…
Reference in New Issue
Block a user