Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

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

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

## 15. 里程碑 Gate
## 15. 房间助理与操作员面

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

## 16. 里程碑 Gate

### M0

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

## 16. 测试交付
## 17. 测试交付

每次 Gate 交付:

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

## D-001:透明 Broker

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

决定:

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

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

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

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

完成标准:fixture 证明并行观察、里程碑有界、interrupt 改道、steer 上限、自报角色无效、观察包不进记忆/压缩、不产生 `approval.*`、不改 unrestricted argv。不把「真实模型抓到了漂移」写成发布 Gate。
完成标准:fixture 证明并行观察、里程碑有界、interrupt 改道、steer 上限、自报角色无效、观察包不进记忆/压缩、不产生 `approval.*`、不改 unrestricted argv。不把「真实模型抓到了漂移」写成发布 Gate。操作员派活带 `supervision` 时复用同一 pair 合同,不新开审批面。

## D-028:房间助理是操作员客户端

触发:用户需要一个平级助手来控场和派活,但不能把它做成 Host Agent、第二房间或 Broker 内置模型。自然语言「清一下历史」不能直接触发房间命令。

决定:

1. **助理是 `user:assistant`,不是 `agent:assistant`**。binding 协议是 `local-operator`(`instance:operator` / `binding:operator`)。它与 `user:web` 平级,不进 `agents` 名册,不被 `@all` 唤醒,不吃 Context Packet,也不走成员当前回合 MCP。
2. **用户直连助理**。侧边对话走 `/api/assistant*`,不经 Broker composer,不先落房间 `message.created`,不创建 Agent Turn。默认提示词是产品常量,每次注入;`extraInstructions` 只能追加,不能绕过禁止项。
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。
4. **监督可启动,但不能自己观察**。派活或 `send` 可带与 Web 相同的 `supervision`。助理没有 `watch`/`steer`,也不能把自己放进 observers。
5. **配置在顶层 `assistant`**。禁止 `agents.assistant` 和保留 id `__assistant__`。首次引导默认启用;旧配置缺省该项时保持未启用。至少仍要有一个启用的房间 Agent。
6. **成员 MCP 面不变**。`/mcp` 仍要求当前 Turn,仍有 watch/steer。`/mcp/operator` 是独立入口,不要求 Agent Turn。

对原始需求的影响:R1 增加一个用户表面入口,不把助理做成房间成员。R2 不变——自然语言仍不派发。R3 不变——助理不是安全或审批层。R5 增加独立 operator 客户端,不把 LLM 放进 Broker 内核。

协议/存储迁移:schema v9 增加 `assistant_conversation_messages` 与 `context_resets`;Envelope 增加 `operator.dispatch` / `context.reset`;`sourceKind` 增加 `operator`;预置 actor `user:assistant`。

复杂度与回滚:未启用助理时房间行为与 v0.1.14 相同。回滚可停 `/api/assistant` 与 `/mcp/operator`,历史 `operator.dispatch` 和侧边对话行保留审计。

完成标准:schema `documented`;无模型 fixture `probed`;用户→助理不经 `POST /api/messages`;派活可无群气泡但有可重放 `operator.dispatch`;作者是 `user:assistant`;`from`/`actor`/`provenance` 与 dated 写入失败;真实 operator `tools/call` 才 `verified`。

## 决策变更规则

Expand Down
13 changes: 10 additions & 3 deletions docs/IMPLEMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,16 @@ M0-M2 不实现:

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

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

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

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