Skip to content

Commit b90fd07

Browse files
honor00cursoragent
andcommitted
feat: add the room assistant as a local-operator client
Give the user a peer operator for dispatch and room control without adding a roster agent, and keep reset a hard floor for later compaction. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 0a61415 commit b90fd07

57 files changed

Lines changed: 4867 additions & 138 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/ACCEPTANCE_TESTS.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -213,14 +213,16 @@ binding 是 provenance/correlation handle,不是 secret、token 或本机抗
213213
| --- | --- | --- |
214214
| W-001 | 默认监听 | `127.0.0.1`;非 loopback 不属于 v0.1 |
215215
| W-002 | bootstrap | 回显 selected transport、Agent process/session health、capability、cursor |
216-
| W-003 | composer | 只能选择 recipients 与可选 observer chips,不能设置 sender/transport/access;observer 不得与本次 worker 重叠 |
216+
| W-003 | composer | 只能选择 recipients 与可选 observer chips,不能设置 sender/transport/access;observer 不得与本次 worker 重叠;助理不进目标芯片 |
217217
| W-004 | transcript | sender badge、final/partial/failed 状态正确;监督 pair/observed/steer 可见且无审批按钮 |
218218
| W-005 | approval surface | 没有批准/拒绝按钮、pending 卡片或 approval API 调用;steer 文案写明打断的是整轮 |
219219
| W-006 | 模型输出 | 作为普通文本节点,不执行 HTML/script |
220220
| W-007 | 未知 event type | 非保留类型 generic render,不导致 SSE 断流;`approval.*`/`permission.*`/`user_input.*` 拒绝且不渲染 |
221221
| W-008 | 首次 init/start | 无配置时打开 loopback 引导页;添加并保存后生成严格 groupx.json,再启动主 UI |
222222
| W-009 | 多实例名册 | 可添加两个以上 Codex App Server,稳定 id 唯一,name/cwd 独立;保存后 runtime 各有独立 actor/binding/session |
223223
| W-010 | 运行中 Agent 设置 | `/setup` 载入现有名册,保存返回 restartRequired;主房间立即把新增启用项计入总数并显示 `pending_restart`,不可作为消息目标;不热换当前 session,不出现 access/approval/sandbox 控件 |
224+
| W-014 | 房间助理侧边对话 | 用户→助理走 `/api/assistant*`,不经 `POST /api/messages`,不落房间气泡;未启用时引导 `/setup#assistant` |
225+
| W-015 | 助理配置 | 首次引导默认启用顶层 `assistant`;旧配置缺省该项保持未启用;拒绝 `agents.assistant` / `__assistant__` |
224226
| W-011 | `groupx update` | 查询 npm latest;已最新/本地更高不安装,`--check` 无副作用,有更新时锁定精确版本并通过 shell-free npm 入口全局安装 |
225227
| W-012 | 单房间上下文控件 | 输入窗口右上角显示明确标注的字符估算;手动压缩经 Broker/clientCommandId 单飞,保留最近消息与完整 transcript,reasoning/tool 记录不进入摘要 |
226228
| W-013 | Agent 设置两层记忆 | core 独立展示并可维护;dated 只读按本地日期分组并允许显式移除;公共记忆仍在群聊左栏 |
@@ -253,7 +255,22 @@ Broker 指标不含模型网络/推理;只测 Structured session startup/reuse
253255

254256
未实际测量前不得写成达到。
255257

256-
## 15. 里程碑 Gate
258+
## 15. 房间助理与操作员面
259+
260+
| ID | 用例 | 通过标准 |
261+
| --- | --- | --- |
262+
| O-001 | 侧边对话 | 用户正文只进 `assistant_conversation_messages`,Broker 不因此创建房间 Turn |
263+
| O-002 | 默认派活 | `worker_dispatch` 写可重放 `operator.dispatch`,无 `message.created` 聊天气泡;content 可进目标 Context Packet |
264+
| O-003 | 作者 | send / dispatch 的 actor 是 `user:assistant`,不能写成 `user:web` |
265+
| O-004 | 禁止字段 | 操作员写请求带 `from`/`actor`/`provenance` 返回 `SENDER_FIELD_FORBIDDEN`;extraInstructions 不能绕过 |
266+
| O-005 | dated | 助理不能生成或改写 dated memory;只能 search 或 retract |
267+
| O-006 | 监督 | 助理可带 `supervision` 启动配对,但不能当 observer,也没有 watch/steer |
268+
| O-007 | 验收语言 | schema `documented`;无模型 fixture `probed`;真实 operator `tools/call``verified` |
269+
| O-008 | 派活后上下文 | `operator.dispatch` 计入 `context_usage` / compact,不抛 `INVALID_ENVELOPE` |
270+
| O-009 | 操作员记忆 | 助理写入的 memory/identity `sourceKind``operator`,REST/MCP 与 Web 列表可回读 |
271+
| O-010 | reset 下限 | reset 后 compact/usage 不读 `throughSeq <= resetThroughSeq` 的摘要或更早房间消息;仅有 `context.reset` 审计事件时再次 reset 为 no-op |
272+
273+
## 16. 里程碑 Gate
257274

258275
### M0
259276

@@ -289,7 +306,7 @@ Broker 指标不含模型网络/推理;只测 Structured session startup/reuse
289306
- A2A 只作为边缘 Adapter;
290307
- 不改变 fixed unrestricted 与 native interaction fail-turn 合同,除非另立版本决策。
291308

292-
## 16. 测试交付
309+
## 17. 测试交付
293310

294311
每次 Gate 交付:
295312

docs/DECISIONS.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
| D-025 | ask 超时不加回送机制,harness 只以有界文本指导模型闭环 | Accepted |
3838
| D-026 | 放宽消息 wire 上限(131,072)、运行超时与互调链路默认值 | Accepted |
3939
| D-027 | 同步监督是房间协作配对,不是治理或审批层 | Accepted |
40+
| D-028 | 房间助理是 user:assistant 操作员客户端,不是名册 worker | Accepted |
4041

4142
## D-001:透明 Broker
4243

@@ -375,7 +376,7 @@ Hermes 0.20.1 的 initialize 当前未声明 `mcpCapabilities.http`,但官方
375376

376377
决定:
377378

378-
1. **第三条路由是配对,不是自然语言**。`POST /api/messages` 的可选 `supervision: { observers, mode: "live_steer" }` 在同一 `rootCorrelationId` 下并行创建 worker Turn 与 `supervision.watch` Turn。Observer 不复用用户正文当执行提示。角色只写在本次配对行,不进入 Agent 名册枚举。`sourceKind: "supervision"` 由 Broker 写入;请求方不能自报监督者。
379+
1. **第三条路由是配对,不是自然语言**。`POST /api/messages` 的可选 `supervision: { observers, mode: "live_steer" }` 在同一 `rootCorrelationId` 下并行创建 worker Turn 与 `supervision.watch` Turn。`local-operator` 的 `send` / `worker_dispatch` / `worker_ask` / `dispatch_event` 也可带同一字段。Observer 不复用用户正文当执行提示。角色只写在本次配对行,不进入 Agent 名册枚举。`sourceKind: "supervision"` 由 Broker 写入;请求方不能自报监督者。无群气泡时,pair 的任务引用是 `operator.dispatch` event id。助理自己不当 observer,也没有 `watch`/`steer`
379380
2. **同步 = 并行 running + 有界里程碑**。`groupx.watch` 只在 Watch Turn 成功;等待 `next_milestone | terminal`,快照只含 status、deliveryCertainty、任务引用、公开消息摘要、工具名+status+toolCallId、steer 计数。不转发 token,不带推理正文或完整工具参数。
380381
3. **打断 = 整段 Turn cancel + 新 Worker Turn**。`steer(interrupt)` 复用现有 cancel 对账,再以 supervisor 公开指导为 `current_message` 入队;`nudge` 不打断,只在当前 worker 自然结束后 FIFO 入队。不能取消 Turn 内部某一次 native 工具。已 `delivered`/`unknown` 的原 prompt 不重放(D-016)。
381382
4. **steer ≠ approval**。不产生 `approval.*`,不出现允许/拒绝按钮,不改变 unrestricted argv/mode,不代答 `requestUserInput`。Watch Turn 对正在被观察的 worker 再 `ask`/`send` 返回 `SUPERVISION_STEER_REQUIRED`。
@@ -384,11 +385,32 @@ Hermes 0.20.1 的 initialize 当前未声明 `mcpCapabilities.http`,但官方
384385

385386
对原始需求的影响:R2 增加一条显式协作路由,不改变「自然语言不派发」。R3 不变——监督不是安全或审批层。R4 增加独立观察数据类,不与记忆层合并。R5 不把 memsuOS 治理内核搬进 Broker。
386387

387-
协议/存储迁移:schema v8 增加 `supervision_pairs` / `supervision_pair_turns` / `supervision_steer_counts`;Envelope `sourceKind` 增加 `supervision`。
388+
协议/存储迁移:schema v8 增加 `supervision_pairs` / `supervision_pair_turns` / `supervision_steer_counts`;Envelope `sourceKind` 增加 `supervision`。schema v9 允许配对任务引用 `operator.dispatch`。
388389

389390
复杂度与回滚:配对只在用户显式带 `supervision` 时创建;关闭开关即回到原两条路由。回滚可停用 watch/steer 工具面并停止写配对表,历史事件保留审计。
390391

391-
完成标准:fixture 证明并行观察、里程碑有界、interrupt 改道、steer 上限、自报角色无效、观察包不进记忆/压缩、不产生 `approval.*`、不改 unrestricted argv。不把「真实模型抓到了漂移」写成发布 Gate。
392+
完成标准:fixture 证明并行观察、里程碑有界、interrupt 改道、steer 上限、自报角色无效、观察包不进记忆/压缩、不产生 `approval.*`、不改 unrestricted argv。不把「真实模型抓到了漂移」写成发布 Gate。操作员派活带 `supervision` 时复用同一 pair 合同,不新开审批面。
393+
394+
## D-028:房间助理是操作员客户端
395+
396+
触发:用户需要一个平级助手来控场和派活,但不能把它做成 Host Agent、第二房间或 Broker 内置模型。自然语言「清一下历史」不能直接触发房间命令。
397+
398+
决定:
399+
400+
1. **助理是 `user:assistant`,不是 `agent:assistant`**。binding 协议是 `local-operator`(`instance:operator` / `binding:operator`)。它与 `user:web` 平级,不进 `agents` 名册,不被 `@all` 唤醒,不吃 Context Packet,也不走成员当前回合 MCP。
401+
2. **用户直连助理**。侧边对话走 `/api/assistant*`,不经 Broker composer,不先落房间 `message.created`,不创建 Agent Turn。默认提示词是产品常量,每次注入;`extraInstructions` 只能追加,不能绕过禁止项。
402+
3. **控场默默做,派活留下有界来源**。cancel / compact / reset / restart / memory / setup 直接打 Broker,时间线没有助理发言。默认派活是 `worker_dispatch` / `worker_ask`:创建 Turn,写 durable `operator.dispatch`(可重放、可进目标 Context Packet、计入房间 usage/compact),不先造群聊气泡。禁止 prompt 只活在内存里。`send` 仅在用户明确要求发到群里时使用,作者不能伪造成 `user:web`。助理写入的 memory/identity 记录 `sourceKind` 是 `operator`,必须能经 REST/MCP 合同回读。`context.reset` 是后续上下文下限:压缩不得把 reset 前的 transcript 或检查点滚进新摘要;仅有 reset 审计事件、没有新的房间上下文时再次 reset 为 no-op。
403+
4. **监督可启动,但不能自己观察**。派活或 `send` 可带与 Web 相同的 `supervision`。助理没有 `watch`/`steer`,也不能把自己放进 observers。
404+
5. **配置在顶层 `assistant`**。禁止 `agents.assistant` 和保留 id `__assistant__`。首次引导默认启用;旧配置缺省该项时保持未启用。至少仍要有一个启用的房间 Agent。
405+
6. **成员 MCP 面不变**。`/mcp` 仍要求当前 Turn,仍有 watch/steer。`/mcp/operator` 是独立入口,不要求 Agent Turn。
406+
407+
对原始需求的影响:R1 增加一个用户表面入口,不把助理做成房间成员。R2 不变——自然语言仍不派发。R3 不变——助理不是安全或审批层。R5 增加独立 operator 客户端,不把 LLM 放进 Broker 内核。
408+
409+
协议/存储迁移:schema v9 增加 `assistant_conversation_messages` 与 `context_resets`;Envelope 增加 `operator.dispatch` / `context.reset`;`sourceKind` 增加 `operator`;预置 actor `user:assistant`。
410+
411+
复杂度与回滚:未启用助理时房间行为与 v0.1.14 相同。回滚可停 `/api/assistant` 与 `/mcp/operator`,历史 `operator.dispatch` 和侧边对话行保留审计。
412+
413+
完成标准:schema `documented`;无模型 fixture `probed`;用户→助理不经 `POST /api/messages`;派活可无群气泡但有可重放 `operator.dispatch`;作者是 `user:assistant`;`from`/`actor`/`provenance` 与 dated 写入失败;真实 operator `tools/call` 才 `verified`。
392414

393415
## 决策变更规则
394416

docs/IMPLEMENTATION.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,11 +78,16 @@ M0-M2 不实现:
7878

7979
```mermaid
8080
flowchart LR
81-
UI["Local Web UI"] -- "POST commands" --> API["REST API"]
81+
UI["Local Web UI"] -- "POST /api/messages" --> API["REST API"]
82+
AssistantUI["Assistant drawer"] -- "POST /api/assistant" --> API
8283
SSE["SSE stream"] --> UI
8384
API --> Broker["GroupX Broker"]
8485
Broker --> SSE
8586
Broker --> Store["SQLite/WAL"]
87+
AssistantUI --> AssistantHost["Assistant host"]
88+
AssistantHost --> AssistantBrain["Private brain CLI"]
89+
AssistantBrain -.-> OperatorMCP["Operator MCP<br/>/mcp/operator"]
90+
OperatorMCP --> Broker
8691
Broker --> CodexAdapter["Codex App Server Adapter"]
8792
Broker --> GrokAdapter["Grok ACP Adapter"]
8893
Broker --> KimiAdapter["Kimi ACP Adapter"]
@@ -110,6 +115,7 @@ M0-M2 使用一个 GroupX Node.js 主进程:
110115
- 每个 Agent 启动一个 Structured 长驻协议子进程;Direct runtime 入口不存在;
111116
- 每个 Agent 有独立 Adapter、进程监督、输出解析、状态机、超时和队列;
112117
- GroupX MCP 与 Broker 同进程运行,只在 Structured 模式为已验证可挂载 MCP 的原生会话建立独立调用方 binding;
118+
- 房间助理是同进程的 `local-operator` 客户端:侧边对话不经房间 composer;operator MCP 与成员 MCP 分入口;私有脑不进 Adapter 名册;
113119
- Browser 和 CLI 不直接打开数据库。
114120

115121
CLI 退出不会使 Broker 退出;数据库异常属于 Broker 级故障,应停止接受新命令并保留明确健康状态。
@@ -305,8 +311,9 @@ M1 UI 使用原生 HTML/CSS/TypeScript,避免在首版引入大型框架。
305311

306312
- 左侧:Agent 状态、cwd、会话状态、能力、重启按钮和可折叠的公共记忆;
307313
- 中间:群聊、发送者徽标、reply/forward、目标选择和取消;
308-
- Agent 设置:每个 Agent 的稳定身份、可维护的核心记忆与按日期分组的自动记忆;不保留右侧记忆栏;
309-
- 底部:composer,左侧明确选择 `@codex/@grok/@kimi/@all`,可选监督开关与独立 observer chips(不得与本次 worker 重叠);输入区域右上角显示字符用量并提供“压缩会话”。时间线把 pair、观察里程碑和 steer 收成可见协作事件;不出现批准/拒绝原生工具的按钮。打断文案必须写明「取消的是整轮,不是某一次工具」。
314+
- 顶栏:房间助理入口打开侧边对话。未启用时引导去 `/setup#assistant`。助理不进目标芯片或 `@all`
315+
- Agent 设置:每个 Agent 的稳定身份、可维护的核心记忆与按日期分组的自动记忆;名册下方单独有房间助理卡,写入 `groupx.json` 顶层 `assistant`,不是 `agents.assistant`
316+
- 底部:composer,左侧明确选择已启用 `agent:*``@all`,可选监督开关与独立 observer chips(不得与本次 worker 重叠);输入区域右上角显示字符用量并提供“压缩会话”。时间线把 pair、观察里程碑、steer 和折叠的 `operator.dispatch` 收成可见协作事件;不出现批准/拒绝原生工具的按钮。打断文案必须写明「取消的是整轮,不是某一次工具」。
310317

311318
UI 只根据 Envelope actor 渲染发送者,不解析正文决定头像或身份。
312319
用量控件显示的是 active checkpoint 加其后 `message.created` 的保守字符估算,不是模型 token window;目标 Agent 身份、记忆与原生 instructions 仍会另占空间。手动压缩同样经过 Broker 和 `clientCommandId` receipt,保留最近 12 条消息原文,不删除 transcript。

0 commit comments

Comments
 (0)