From 57d4ca0e75bb951dc7b248fec86bf847910df4a3 Mon Sep 17 00:00:00 2001 From: weishao Date: Thu, 30 Jul 2026 16:32:20 +0800 Subject: [PATCH] feat(doct): add app server design --- AGENTS-CN.md | 18 +- AGENTS.md | 29 +- .../agent-runtime-deployment-design.md | 673 +++++++++--------- .../agent-runtime-services-design.md | 11 +- .../agent-sdk-product-architecture.md | 56 +- .../app-server-architecture-design.md | 546 ++++++++++++++ docs/architecture/cli-product-line-design.md | 55 +- .../extensions/plugin-runtime-design.md | 3 +- docs/architecture/product-architecture.md | 292 +++++--- .../product-customization-blueprint.md | 8 + docs/plans/core-decomposition-plan.md | 6 +- src/apps/cli/AGENTS.md | 13 +- src/crates/adapters/AGENTS-CN.md | 2 +- src/crates/adapters/AGENTS.md | 2 +- .../adapters/agent-runtime-ipc/AGENTS-CN.md | 63 +- .../adapters/agent-runtime-ipc/AGENTS.md | 103 ++- 16 files changed, 1325 insertions(+), 555 deletions(-) create mode 100644 docs/architecture/app-server-architecture-design.md diff --git a/AGENTS-CN.md b/AGENTS-CN.md index 040e045b1..6d10cdacb 100644 --- a/AGENTS-CN.md +++ b/AGENTS-CN.md @@ -25,7 +25,7 @@ Stable Contracts and Security Control Plane 的边界以 |---|---|---|---|---|---| | 1 | 接口与入口层 | `src/apps/*`, `src/web-ui`, `src/mobile-web`, `BitFun-Installer`, `tests/e2e`, `src/crates/interfaces` | 产品宿主、命令、UI 入口、协议接口和跨形态测试 | desktop、CLI、server、relay、Web UI、mobile web、installer、E2E、`acp`、`sdk-host` | 最近的本地 `AGENTS.md`;[interfaces](src/crates/interfaces/AGENTS.md) | | 2 | 产品组装层 | `src/crates/assembly` | 兼容导出、产品能力选择、product-full 接线、adapter/service 注册和生态无关的来源协调 | `core`, `external-sources`, `product-capabilities` | [AGENTS.md](src/crates/assembly/AGENTS.md) | -| 3 | 适配层 | `src/crates/adapters` | AI/transport/WebDriver 协议 adapter、外部 AI work source adapter(OpenCode/Claude Code/Codex)和外部 provider 转换 | `agent-runtime-ipc`、`ai-adapters`, `opencode-adapter`, `claude-code-adapter`, `codex-adapter`, `static-hook-support`, `transport`, `webdriver` | [AGENTS.md](src/crates/adapters/AGENTS.md) | +| 3 | 适配层 | `src/crates/adapters` | AI/transport/WebDriver 协议 adapter、外部 AI work source adapter(OpenCode/Claude Code/Codex)和外部 provider 转换 | `agent-runtime-ipc`(仅迁移)、`ai-adapters`, `opencode-adapter`, `claude-code-adapter`, `codex-adapter`, `static-hook-support`, `transport`, `webdriver` | [AGENTS.md](src/crates/adapters/AGENTS.md) | | 4 | 服务实现层 | `src/crates/services` | 可复用 OS、filesystem、terminal、MCP、remote、git、watch、process、LSP plugin registry、session persistence primitives、network 和 MiniApp runtime IO 实现 | `services-core`, `services-integrations`, `relay-service`, `page-function-runtime`, `terminal` | [AGENTS.md](src/crates/services/AGENTS.md) | | 5 | 执行原语层 | `src/crates/execution` | 可移植 agent、harness、stream、DeepReview policy/report、插件运行时客户端、typed-service、tool-contract、tool-group 和 tool-execution 构件 | `agent-runtime`, `agent-stream`, `tool-contracts`, `harness`, `plugin-runtime-client`, `runtime-services`, `tool-provider-groups`, `tool-execution`, `tool-call-jsonrepair` | [AGENTS.md](src/crates/execution/AGENTS.md) | | 6 | 稳定契约与产品领域层 | `src/crates/contracts` | 跨层共享 DTO、事件形状、runtime port、LSP protocol/plugin DTO、产品领域契约和策略 | `core-types`, `events`, `runtime-ports`, `product-domains` | [AGENTS.md](src/crates/contracts/AGENTS.md) | @@ -191,13 +191,23 @@ await api.invoke('your_command', { request: { ... } }); 仓库级拆解规则: - 不要把 DTO / contract 抽取误判为 runtime owner 已迁移。 -- 产品表面可以有差异;共享稳定 facts 或 ports,不共享 UI、protocol、lifecycle 或平台实现。 +- 产品表面可以有差异;共享稳定 facts 或 ports。只有 Rich Client App Server consumer 等明确版本化的同一产品家族 + 才共享 protocol;UI、lifecycle 和平台实现仍不共享。 - 迁移 runtime owner 必须有评审过的 port/provider 设计、旧路径兼容、行为等价测试;如果可能改变行为边界,还需要先确认。 涉及 Agent Runtime 部署、多 GUI/TUI/Remote 实例、共享 Session 控制或进程拓扑时,还必须阅读 [`docs/architecture/agent-runtime-deployment-design.md`](docs/architecture/agent-runtime-deployment-design.md)。 -Rust Runtime 或 Node/Bun Plugin Host 不得默认按 Client、workspace、session 或 plugin 分进程;进程边界必须来自真实状态 -owner、execution/security domain、可兼容的安全条件和测量后的容量事实。 +App Server 只存在 Embedded(一个 Client 对一个 Server)与 Shared(同一种 `client_kind` 的多个 Client 对一个 +Server)两种部署。Shared Rust Runtime 或 Node/Bun Plugin Host 不得默认按窗口、workspace、session 或 plugin 分进程; +进程边界必须来自真实状态 owner、`client_kind`、execution/security domain、可兼容的安全条件和测量后的容量事实。 + +涉及 Rich Client 前后端分离、Desktop 替换 Electron、VS Code Extension 接入、App Server schema/transport 或第一方 GUI +进程拓扑时,还必须阅读 +[`docs/architecture/app-server-architecture-design.md`](docs/architecture/app-server-architecture-design.md)。Rich Client(包括交互式 +TUI)的 Embedded 与 Shared 部署共享同一 App Server wire,但领域契约仍归 Runtime/能力 owner。Embedded 只接受一个 +Client;Shared 只接受固定 `client_kind` 的多个 Client,TUI、Tauri Desktop、Electron Desktop、VS Code 和 Web 不得连接 +同一个实例;`client_kind` 表示具体宿主形态,不是宽泛界面类别。网络、租户和运维约束不形成 Hosted 第三形态。 +Headless CLI、ACP、SDK Host 保持独立协议和生命周期边界,不保留第二套 Shared TUI wire 或 handler。 ### CLI 产品线护栏 diff --git a/AGENTS.md b/AGENTS.md index 9b46c7507..c2a0a91e1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -26,7 +26,7 @@ Keep crate dependencies inside each layer to the smallest set needed. |---|---|---|---|---|---| | 1 | Interfaces and entrypoints | `src/apps/*`, `src/web-ui`, `src/mobile-web`, `BitFun-Installer`, `tests/e2e`, `src/crates/interfaces` | Product hosts, commands, UI entrypoints, protocol interfaces, and cross-surface tests | desktop, CLI, server, relay, Web UI, mobile web, installer, E2E, `acp`, `sdk-host` | nearest local `AGENTS.md`; [interfaces](src/crates/interfaces/AGENTS.md) | | 2 | Product assembly | `src/crates/assembly` | Compatibility exports, product capability selection, product-full wiring, adapter/service registration, and ecosystem-neutral source coordination | `core`, `external-sources`, `product-capabilities` | [AGENTS.md](src/crates/assembly/AGENTS.md) | -| 3 | Adapters | `src/crates/adapters` | AI/transport/WebDriver protocol adapters, external AI work source adapters (OpenCode/Claude Code/Codex), and external-provider translation | `agent-runtime-ipc`, `ai-adapters`, `opencode-adapter`, `claude-code-adapter`, `codex-adapter`, `static-hook-support`, `transport`, `webdriver` | [AGENTS.md](src/crates/adapters/AGENTS.md) | +| 3 | Adapters | `src/crates/adapters` | AI/transport/WebDriver protocol adapters, external AI work source adapters (OpenCode/Claude Code/Codex), and external-provider translation | `agent-runtime-ipc` (migration-only), `ai-adapters`, `opencode-adapter`, `claude-code-adapter`, `codex-adapter`, `static-hook-support`, `transport`, `webdriver` | [AGENTS.md](src/crates/adapters/AGENTS.md) | | 4 | Services | `src/crates/services` | Reusable OS, filesystem, terminal, MCP, remote, git, watch, process, LSP plugin registry, session persistence primitives, MiniApp runtime IO, and network implementations | `services-core`, `services-integrations`, `miniapp-market-service`, `relay-service`, `page-function-runtime`, `terminal` | [AGENTS.md](src/crates/services/AGENTS.md) | | 5 | Execution primitives | `src/crates/execution` | Portable agent, harness, stream, DeepReview policy/report, plugin runtime client, typed-service, tool-contract, tool-group, and tool-execution building blocks | `agent-runtime`, `agent-stream`, `tool-contracts`, `harness`, `plugin-runtime-client`, `runtime-services`, `tool-provider-groups`, `tool-execution`, `tool-call-jsonrepair` | [AGENTS.md](src/crates/execution/AGENTS.md) | | 6 | Stable contracts and product domains | `src/crates/contracts` | Shared DTOs, event shapes, runtime ports, LSP protocol/plugin DTOs, and product domain contracts/policies | `core-types`, `events`, `runtime-ports`, `product-domains` | [AGENTS.md](src/crates/contracts/AGENTS.md) | @@ -203,8 +203,9 @@ details in the nearest module `AGENTS.md`. Repository-level decomposition rules: - Do not confuse DTO/contract extraction with runtime owner migration. -- Product surfaces may diverge; share stable facts or ports, not UI, protocol, - lifecycle, or platform implementation. +- Product surfaces may diverge; share stable facts or ports. Share a protocol + only inside an explicitly versioned product family such as Rich Client App + Server consumers, and never share UI, lifecycle, or platform implementation. - Moving runtime ownership requires a reviewed port/provider design, old-path compatibility, behavior equivalence tests, and explicit confirmation when a behavior boundary could change. @@ -212,9 +213,25 @@ Repository-level decomposition rules: For Agent Runtime deployment, multi-GUI/TUI/Remote instances, shared Session control, or process-topology changes, also read [`docs/architecture/agent-runtime-deployment-design.md`](docs/architecture/agent-runtime-deployment-design.md). -Do not key Rust Runtime or Node/Bun Plugin Host processes by client, workspace, -session, or plugin by default; use the responsible state module, execution and -security conditions, and measured capacity. +App Server has only Embedded (one client to one server) and Shared (multiple +clients of one `client_kind` to one server) deployments. Do not key Shared Rust +Runtime or Node/Bun Plugin Host processes by window, workspace, session, or +plugin by default; use the responsible state module, `client_kind`, execution +and security conditions, and measured capacity. + +For Rich Client/backend separation, Desktop-to-Electron replacement, VS Code +Extension integration, App Server schema/transport, or first-party GUI process +topology, also read +[`docs/architecture/app-server-architecture-design.md`](docs/architecture/app-server-architecture-design.md). +Rich Clients, including interactive TUI, share one App Server wire across +Embedded and Shared deployments, while domain contracts remain with their +Runtime/capability owners. An Embedded server accepts exactly one client; a +Shared server accepts multiple clients of one fixed `client_kind`, so TUI, +Tauri Desktop, Electron Desktop, VS Code, and Web never connect to the same +instance. `client_kind` identifies the concrete host form, not a broad UI +category. Network, tenant, and operational constraints do not create a Hosted +third deployment. Headless CLI, ACP, and SDK Host keep separate protocol and +lifecycle boundaries; do not retain a second Shared TUI wire or handler. ### CLI product-line guardrails diff --git a/docs/architecture/agent-runtime-deployment-design.md b/docs/architecture/agent-runtime-deployment-design.md index 0cc7db915..e961efed0 100644 --- a/docs/architecture/agent-runtime-deployment-design.md +++ b/docs/architecture/agent-runtime-deployment-design.md @@ -1,399 +1,400 @@ # Agent Runtime 部署与多实例边界 -本文定义 Desktop、TUI、Headless CLI、Agent SDK 与本机控制端并存时,BitFun Agent Runtime 的部署、所有权和隔离边界。 +本文定义 Desktop、交互式 TUI、VS Code、Web、Headless CLI、ACP、Agent SDK 与 Remote +并存时,BitFun Agent Runtime 的最终部署、所有权、并发和隔离边界。 -Agent Runtime 的模块职责见 [`agent-runtime-services-design.md`](agent-runtime-services-design.md),公开 SDK 见 +Agent Runtime 的模块职责见 [`agent-runtime-services-design.md`](agent-runtime-services-design.md), +Rich Client 协议见 [`app-server-architecture-design.md`](app-server-architecture-design.md),公开 SDK 见 [`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md),第三方 JS/TS 进程见 [`extensions/plugin-runtime-design.md`](extensions/plugin-runtime-design.md)。 -## 1. 决策与当前状态 +> **状态说明**:第 1-7、9-10 节定义尚未实现的最终架构。第 8 节记录当前生产路径和逐项迁移; +> 在对应退出条件满足前,`agent-runtime-ipc`、Tauri command 和既有 Server WebSocket 仍按各自 +> 当前合同维护。迁移完成后不得保留第二套 Shared TUI server/wire。 -BitFun 只有一套 Agent Runtime 行为。`Embedded` 和 `Shared` 只描述同一套 Runtime 的物理部署方式,不是两套实现。 +## 1. 最终决策 + +BitFun 只有一套 Agent Runtime 行为。App Server 只存在 `Embedded` 和 `Shared` 两种部署形态; +Headless CLI/CI 的进程内 Runtime 调用称为 `Direct Runtime`,不属于 App Server 部署。 ```mermaid flowchart TB - subgraph "产品入口" - GUI["Desktop GUI"] - TUI["TUI / Headless CLI"] - ACP["ACP"] - SDK["Agent SDK · SDK Host"] - Server["Server agent bootstrap"] + subgraph RichClients["First-party Rich Clients"] + GUI["Tauri / Electron / VS Code / Web"] + TUI["Interactive TUI"] end - GUI --> Adapter["同级 first-party adapters"] - TUI --> Adapter - ACP --> Adapter - SDK --> Adapter - Server --> Adapter - Adapter --> API["Agent Runtime API"] - API --> Coordinator["ConversationCoordinator"] - Coordinator --> Owners["Session / Tool / Permission / MCP owners"] - Coordinator -. "local attach / mutation" .-> Ownership["CoreRuntimeOwnership"] + Headless["Headless CLI / CI"] + ACP["ACP"] + SDK["Agent SDK"] + Remote["Server / Remote"] + + GUI --> App["App Server adapter"] + TUI --> App + Headless --> Direct["Direct Runtime CLI adapter"] + ACP --> ACPA["ACP adapter"] + SDK --> SDKH["SDK Host adapter"] + Remote --> RemoteA["Server / Remote adapter"] + + App --> API["Agent Runtime API"] + Direct --> API + ACPA --> API + SDKH --> API + RemoteA --> API + API --> Owners["Session / Turn / Tool / Permission / MCP owners"] ``` -当前代码状态必须和目标设计分开阅读: - -| 范围 | 当前状态 | -|---|---| -| Embedded Desktop GUI | 继续使用 Desktop 事件投影和 Tauri adapter;按实际打开的本机 workspace 延迟取得并持有 Embedded ownership,不增加后台进程 | -| Embedded TUI/Headless CLI/Peer Host | Session、Turn、Permission 和事件订阅统一通过同一个 Rust Runtime SDK(当前 preview);CLI crate 只保留第一方 adapter 和各形态自己的展示/断流策略 | -| ACP/SDK Host | 使用同一个 Runtime 事件入口的 session-scoped 订阅;各自协议和进程生命周期保持独立 | -| Runtime ownership | Desktop、CLI、ACP、SDK Host 和现有 Server agent bootstrap 共用 Core owner;Embedded 取得共享锁,Shared TUI 取得独占锁,同一 workspace 上两种 deployment 互斥 | -| Session 写入 | BitFun Runtime 的持久化 Session 由 `SessionManager` 管理;同一存储位置中的同一 Session 同时只允许一个本机进程写入,list/view 等只读操作不受影响 | -| 当前 HTTP Server | 只提供 health/info/WebSocket 外壳,未装配 Agent Runtime,因此不取得 workspace ownership;`bootstrap.rs` 仅保持 agent-enabled composition 的一致边界,不由当前入口启动 | -| Shared local IPC | 未发布的本机协议已有 discovery、实例锁、严格握手、Session 控制权、有界事件流和 cleanup;唯一 consumer 是第一方交互式 TUI adapter | -| Shared TUI | `bitfun --shared` / `bitfun chat --shared` 可列出、创建、恢复和重命名当前 Session,读取 transcript,切换当前 Session 的 Agent mode/model,提交/取消 Turn,处理 Permission 和 UserInput;默认仍是 Embedded | -| Shared GUI/Headless/ACP/SDK Host/Remote | 未交付,也不会由 `--shared` 隐式启用;Replay、Observer、Controller transfer、Session delete/fork 同样不在当前协议中 | +最终决策: -因此当前交付的是一条窄的、显式启用的 Shared TUI deployment,不是通用本机 Server。具体 `EventQueue` 仍由 Core 产品装配;IPC 只把当前 TUI 必需的强类型操作和事件映射到同一个 Runtime owner,没有事件重放或公开协议承诺。 +1. Tauri、Electron、VS Code、Web 和交互式 TUI 是同一个 Rich Client 协议家族,统一经过 + App Server。 +2. App Server 只支持 **Embedded** 和 **Shared**。Embedded 是一个 Client 对一个 Server;Shared 是同一种 + `client_kind` 的多个 Client 对一个 Server。两种形态共享 schema、handler、Runtime API 和行为 conformance suite。 +3. `bitfun --shared` 只选择 Shared App Server instance,不选择另一套 TUI server 或 wire。 +4. Headless CLI/CI 默认 Direct Runtime,保留确定性启动、退出和故障隔离;它不为界面统一承担 + 子进程和序列化成本。 +5. ACP、SDK Host 和 Server/Remote 保留独立协议与安全边界,但都映射同一 Runtime API 和 + 行为 owner。 +6. Embedded 的 Client 数量固定为一;Shared 的 Client 数量不直接决定进程数,workspace 仍是 App Server + 内部 Runtime context 与 ownership lease 的隔离键。 +7. App Server instance 以产品身份、`client_kind`、数据命名空间、安全域、release channel、协议兼容范围和 + execution domain 隔离;不同形态 Client 不能连接同一个 Shared instance,也不能在连接后改写实例级产品组装事实。 -## 2. 最少名词 +## 2. 名词与部署模式 | 名词 | 唯一含义 | 不等于 | |---|---|---| -| Agent Runtime | 负责 Session、Turn、Tool、MCP、Permission、Hook、事件和持久化行为的既有模块 | 进程名、Server 或 SDK | -| Embedded deployment | Runtime 与调用入口位于同一 Rust 进程 | 简化版 Runtime | -| Shared deployment | 同一 Runtime 由一个本机进程承载,多个第一方 Client 通过私有 IPC 使用 | 新 Runtime、公开 Server 或 Agent SDK | -| Agent SDK Host | 将公开 SDK 合同映射到 Runtime API 的私有进程/adapter | CLI、Shared deployment 或 Plugin Host | -| Plugin Host | 运行 Node/Bun 和第三方插件代码的受监督子进程 | Agent Runtime 或 Rust IPC client | +| Agent Runtime | Session、Turn、Tool/MCP、Permission、Hook、Event 和持久化行为 owner | 进程名、Server 或 SDK | +| Direct Runtime | Runtime 与非 App Server 入口位于同一 Rust 进程 | App Server Embedded 或公开 wire | +| App Server | Rich Client 的版本化协议 adapter 和可部署 Runtime Host | 领域 owner、公共 SDK 或 Remote API | +| Embedded App Server | 一个 Client 独占一个 App Server instance,Server 由该 Client Host 私有承载 | Direct Runtime、可发现共享进程或按窗口复制业务状态 | +| Shared App Server | 同一种 `client_kind` 的多个 Client 连接一个 App Server instance 和 Runtime owner | 跨 TUI/GUI/IDE 混连、公开网络 API 或云同步 | +| Network/tenant policy | 对 Embedded 或 Shared 的正交认证、授权、租户与 execution-domain 约束 | 第三种 Hosted 部署形态 | +| SDK Host | 将公开 Agent SDK 合同映射到 Runtime API 的独立 adapter/process | App Server、CLI 或 Shared Runtime | +| Plugin Host | 运行第三方 Node/Bun 插件代码的受监督进程 | Agent Runtime、App Server 或安全沙箱 | -`Host` 只表示“一个进程承载某些模块”的内部关系,不新增普通用户必须理解或管理的产品入口。 +`Host` 表示进程承载关系,不要求普通用户理解或手工管理内部二进制。 -## 3. Logical View · Level 1 +## 3. 逻辑和开发视图 + +### 3.1 单一行为核心 ```mermaid flowchart TB - subgraph "逻辑层:始终只有一套" - API["Agent Runtime API"] --> Session["Session / Turn"] - API --> Permission["Permission"] - API --> Tool["Tool / MCP"] - API --> Events["Authoritative events"] - end - - Embedded["Embedded adapter"] --> API - Shared["Shared local IPC adapter · opt-in TUI"] --> API + App["App Server · Embedded / Shared"] --> API["Agent Runtime API"] + Direct["Headless Direct Runtime adapter"] --> API + ACP["ACP adapter"] --> API SDK["SDK Host adapter"] --> API - Remote["Remote adapter"] --> API -``` - -复用的是 Runtime API、权威事实和 owner;不复用 renderer、CLI 参数、SDK wire、远程认证或平台窗口生命周期。任何新能力必须先进入既有 Runtime owner,再由需要它的 adapter 映射,禁止在 Shared 路径复制业务实现。 + Remote["Server / Remote adapter"] --> API -### 3.1 Embedded 事件交付 - -```mermaid -flowchart LR - Queue["EventQueue"] --> Owner["Core product event queue owner"] - Owner -->|"injects read-only AgentEventSource"| Runtime["Agent Runtime API"] - Runtime --> TUI["TUI adapter"] - Runtime --> Exec["Headless adapter"] - Runtime --> Peer["Peer fanout adapter"] - Runtime --> ACP["ACP adapter"] - Runtime --> SDK["SDK Host adapter"] + API --> Session["Session / Turn owner"] + API --> Permission["Permission owner"] + API --> Tool["Tool / MCP owner"] + API --> Events["Authoritative event source"] ``` -- Core product assembly 创建事件 source,并维持旧消费队列的排空 task;第一方产品入口不再获得第二个订阅 API。 -- TUI、Headless CLI 和 Peer Host 只从 `AgentRuntime` 订阅,不能直接持有 Core-specific event source。 -- `bitfun-core` 的旧 event-source/builder API 仅保留为 deprecated 源码兼容 facade;它们委托给同一个 Core owner,不形成第二套运行时或第一方调用路径。 -- 各 adapter 继续拥有自己的失败投影:TUI 标记当前视图不可信,Headless CLI 返回非成功终态,Peer Host 中断其拥有的 turns,ACP 取消 turn 并返回协议错误,SDK Host 终结 Query 并提供 `RestartHost` recovery。 -- 有界 receiver 的 `Lagged` 或 `Closed` 是显式失败;当前没有 cursor/replay 合同,禁止伪装成透明恢复。 -- 这条链路仍全部位于当前 Embedded 进程,不增加 SDK Host、IPC 或后台进程依赖。 - -## 4. Process View · Level 1 +所有部署复用 Runtime API、权威事实和 owner。任何新能力必须先进入既有 owner,再由需要 +它的 adapter 映射。禁止在 App Server Shared handler、CLI adapter、SDK Host 或 Remote +route 中复制业务校验和最终状态。 -### 4.1 Runtime ownership - -ownership 分成“产品决策”和“文件锁原语”两层;入口不再各自拼 key、目录或锁模式: +### 3.2 代码依赖 ```mermaid flowchart TB - Entrypoints["Desktop · CLI · ACP · SDK Host · Server bootstrap"] - Entrypoints --> Core["CoreRuntimeOwnership
deployment · product identity · process-held lock"] - Core --> Primitive["services-core::runtime_ownership
canonical key · RAII file lock"] - Primitive --> E["Embedded · shared lock"] - Primitive --> S["Shared · exclusive lock"] + Rich["Desktop / CLI-TUI / Web Hosts"] --> AppInterface["interfaces/app-server"] + Rich --> Transport["adapters/app-server-transport"] + AppProcess["apps/app-server"] --> AppInterface + AppProcess --> Assembly["assembly"] + AppInterface --> Contracts["contracts"] + Transport --> Contracts + Assembly --> Runtime["execution/agent-runtime"] + Assembly --> Services["services"] + Runtime --> Contracts + Services --> Contracts ``` -```mermaid -flowchart TD - Op["Session operation"] --> Read{"read-only view/list?"} - Read -->|"yes"| NoLock["不取得 ownership"] - Read -->|"no · attach/mutate/turn"| Remote{"structured remote facts?"} - Remote -->|"yes"| RemoteHost["由目标 execution host 负责"] - Remote -->|"no"| Gate["Coordinator → CoreRuntimeOwnership"] - Gate --> Lock["按 canonical workspace 持有文件锁"] -``` +- `interfaces/app-server` 拥有 Rich Client schema、typed client facade、版本和 capability + negotiation,不拥有 transport 或产品策略; +- `adapters/app-server-transport` 拥有 in-memory、stdio、Named Pipe、UDS 和 WebSocket + 适配,不依赖 Runtime 实现或 `bitfun-core`; +- App Server 组装根创建唯一 Runtime owner;Embedded 由 Client Host 私有承载,Shared 由可发现的 + `apps/app-server` 实例承载; +- Desktop、Electron Main、VS Code Extension Host 和 CLI/TUI Host 负责创建 Embedded 或发现同类 Shared + Server,不直接构造 Runtime; +- Headless CLI/CI 使用独立 Direct Runtime composition,但调用相同 Runtime API; +- `agent-runtime-ipc` 的 TUI-only operation/server 不是目标模块。可复用的 endpoint、framing、 + discovery 原语应下沉到 App Server transport,旧 crate 在迁移后删除或改为无协议语义的 + 内部 transport 实现。 -| 场景 | 行为 | 原因 | -|---|---|---| -| 多个 Embedded 进程访问同一 workspace | 共享锁允许并存 | 保持单实例、CI 和隔离测试的既有成本模型 | -| Shared 与任一 Embedded 访问同一 workspace | 后启动者返回稳定错误码和启动建议 | 防止同一 workspace 同时存在两种 Runtime deployment | -| Desktop 打开多个 workspace | 首次 attach/write 时逐个取得并持有文件锁 | 不把窗口数、Session 数等同于 Runtime 进程数 | -| 只读 list/view | 不加锁 | ownership 只管理 Runtime deployment,不扩大成读取权限 | -| 已解析且带有效 `connection_id` 的 remote workspace | 本机不加锁 | 与 Session storage 的远端判据一致;`host` 提示本身不能绕过本地锁 | -| 当前只读 HTTP Server | 不创建 Core owner | 没有 Agent Runtime 就没有 ownership 可声明 | +## 4. 物理部署 -`CoreRuntimeOwnership` 只选择 deployment、产品 identity 并在进程存活期间持有锁;`services-core` 只负责 canonical key 和跨进程锁。二者都不选择 workspace、不启动 Runtime,也不替代 Session 单写、数据库事务、文件冲突控制或安全沙箱。 +### 4.1 部署矩阵 -### 4.2 Session 单写 - -workspace 可以被多个 Embedded 进程同时打开,但持久化 Session 不能被多个进程同时写入。保护粒度是“实际 Session 存储位置 + Session ID”,不是窗口、TUI 实例或 workspace。 +| 入口 | 默认部署 | 可选部署 | 协议 | +|---|---|---|---| +| Tauri Desktop | Embedded App Server | Tauri-only Shared App Server | App Server JSON-RPC | +| Electron Desktop | Embedded App Server | Electron-only Shared App Server | App Server JSON-RPC | +| VS Code Extension | Embedded App Server | VS Code-only Shared App Server | App Server JSON-RPC | +| Interactive TUI | Embedded App Server | `--shared` 连接 TUI-only Shared App Server | App Server JSON-RPC | +| Browser Web UI | Embedded App Server | Web-only Shared App Server | App Server JSON-RPC over authenticated WebSocket/HTTPS | +| Headless CLI / CI | Direct Runtime | 无 | Rust Runtime API | +| ACP | In-process ACP composition | 后续按 ACP 产品要求部署 | ACP wire | +| Public Agent SDK | Managed SDK Host | 预启动兼容 SDK Host | SDK Host wire | +| Remote | target-side Runtime Host | 受认证 Remote composition | Server/Remote wire | + +Headless CLI/CI 不作为 App Server client,也不接受 `--shared`。若未来需要非交互控制 Shared +Session,必须另行定义命令入口、调用方角色、stdout/stderr 或 JSON/JSONL、退出码、取消、断线与 +`outcome_unknown` 合同,并通过兼容评审后再修改本矩阵;当前设计不预留半实现路径。 + +Browser Web UI 不经公网连接用户本机 App Server。Web Backend 承载一个 Web Client 独占的 Embedded 实例, +或多个 Web Client 使用的 Web-only Shared 实例;两者都使用独立网络认证、方法 allowlist、租户隔离、数据与 +execution domain。网络位置不产生 Hosted 第三形态。 + +### 4.2 Embedded App Server ```mermaid flowchart LR - subgraph W["同一 workspace"] - A["Session A"] - B["Session B"] - end - - GUI["GUI 进程"] -->|"写入"| A - TUI["TUI 进程"] -->|"写入"| B - CLI["另一个 CLI 进程"] -.->|"写入 A:session_in_use"| A - View["任意入口的 list / view"] -.->|"只读"| A - View -.->|"只读"| B + Client["One Rich Client"] --> Host["Trusted Client Host"] + Host -->|"create + exclusive channel"| App["Embedded App Server"] + App --> Runtime["Agent Runtime"] + Runtime --> Data["Workspace / Session storage"] ``` -BitFun Runtime Session 只有 `SessionManager` 决定何时开始和结束写入;底层持久化方法复用同一文件锁,不再实现第二套判断。各产品入口只投影同一个 `session_in_use` 事实,不重新判断锁状态: +Embedded App Server 与一个 Client 一一绑定,由该 Client Host 私有创建和管理,不发布 discovery,也不接受 +第二个连接。实现可以同进程承载,也可以使用只对该 Client 可达的私有子进程;该选择不能改变一对一身份和 +生命周期合同。一个 Host 中若存在多个 renderer 或窗口,它们仍由一个逻辑 Client 汇聚后访问该 Server,不能让 +多个独立 Client identity 借 Embedded 之名共享实例。 -| 入口 | 冲突呈现 | 恢复方式 | -|---|---|---| -| Agent SDK / BitFun ACP | 结构化 `session_in_use`;SDK Host 映射为可重试的 `action_required` | 调用方在原实例关闭 Session 后重试 | -| Embedded / Shared TUI | 明确提示 Session 已在另一实例打开;切换失败时保留当前 Session | 用户关闭另一实例后再次选择;不自动等待或切换 | -| Desktop / Peer GUI | 历史视图保持只读可见;首次写入显示持久提示和显式“重试”操作 | 用户关闭另一实例后点击重试;不自动提交消息 | -| Headless `json` | 失败结果带 `error_code=session_in_use`,详细说明进入结果和 stderr | 调用方依据稳定码决定是否重试 | -| Headless `stream-json` | 复用已有 `SystemError`,`error=session_in_use`、`recoverable=true` | 调用方结束本次非零退出后重新执行 | - -Desktop 作为 ACP client 管理的外部 agent Session 不经过该 Runtime owner,不在本节的 Session 单写范围内。`recoverable` 只表示关闭现有 writer 后可以重新调用,不表示自动等待、自动抢占或恢复当前调用。 - -| 场景 | 行为 | -|---|---| -| 同一进程重复 restore 同一 Session | 返回已加载的 Session,不重复取得或释放写入权 | -| 另一个进程打开同一存储位置中的同一 Session | 立即返回 `session_in_use`;不等待、不自动抢占 | -| 多个进程打开同一 workspace 中的不同 Session | 允许,各 Session 独立写入 | -| 多个进程更新同一 Session 列表索引 | 按存储位置串行更新共享索引,不影响不同 Session 文件并行写入 | -| `.`、`..`、符号链接或 Windows 路径大小写指向同一存储位置 | 视为同一个 Session 存储位置 | -| 相同 Session ID 位于不同存储位置 | 文件锁相互独立;同一 `SessionManager` 仍按 Session ID 保持唯一绑定,不能同时加载 | -| Session 存储路径无法解析或错误地指向文件系统根目录 | 在发布内存状态前返回错误,不创建可写 Session | -| create/restore 在发布到内存前失败、取消或超时 | 临时文件锁随操作释放;后续进程可以重试 | -| save、cleanup 或 unload 失败 | 已加载 Session 继续持有写入权,避免另一个进程接手不完整状态 | -| unload 或 delete 成功 | 释放写入权 | -| 进程崩溃或被强制结束 | 操作系统释放文件锁;残留锁文件本身不代表 Session 仍在使用 | -| Remote workspace | 在实际 Session 存储所在机器执行同一检查;控制端不得用本机路径替代 | - -该机制不增加后台进程、轮询、连接或常驻线程,也不改变 Shared TUI 的连接控制规则。临时 Session 不写入磁盘,因此不参与此检查。 - -### 4.3 私有本机 IPC - -```mermaid -sequenceDiagram - participant C as Shared TUI client - participant D as User-private discovery - participant S as Shared Runtime process - - C->>D: read endpoint + token + identity + protocol - C->>S: connect via Named Pipe / UDS - C->>S: initialize(identity, protocol, token) - alt valid - S-->>C: initialized(health + interactive_tui) - C->>S: create or restore Session - S-->>C: Session control + Session facts - C->>S: rename or update current Session - C->>S: submit/cancel Turn or answer Permission/UserInput - S-->>C: Session-filtered authoritative events - else invalid - S-->>C: typed error and close - end -``` - -当前私有协议(v5)只覆盖 TUI 已有用户旅程需要的窄操作: - -| 已支持 | 明确不支持 | -|---|---| -| Health、Session list/create、原子 restore(含 transcript 与 pending Permission)、当前 Session rename、Agent mode/model update | Session delete/fork、跨 workspace attach、transcript 分页、模型目录/默认值和 Agent/Subagent 管理 | -| Turn submit/cancel | replay、cursor、resume event stream | -| pending/respond Permission、submit UserInput answers | observer、controller transfer、多 Session multiplex | -| 连接断开清理、Session-filtered events | detach/observer/controller transfer、SDK callbacks、GUI/Remote/Peer/ACP/Headless wire | - -这些操作先满足以下本机 IPC 地基,而不把协议升级为公开 SDK: - -- workspace、产品、release channel、用户和协议版本共同生成实例身份; -- instance lock 而不是 PID/discovery 文件决定唯一 server owner; -- Windows 使用拒绝远程连接的 Named Pipe;Unix 使用短且由 instance identity 决定的稳定 Domain Socket 名称,权限为 `0600`; -- discovery 所在目录必须由未来 composition 选择为当前用户私有目录; -- discovery 通过同目录临时文件原子替换;Unix endpoint 保留原生路径字节,路径过长时在 bind 前返回明确错误; -- 第一帧必须完成 token、instance identity 和 protocol version 校验; -- 未认证握手预算为 2 秒;认证后的单次操作、响应写入和断线取消预算为 120 秒,避免坏客户端长期占用连接或 Runtime handler; -- JSON frame 使用 4-byte 长度前缀;request 在发送前执行 128 KiB 上限(覆盖 TUI 已有的 64 KiB 粘贴输入及类型化信封),response/event 在序列化时执行 8 MiB 上限。超限返回类型化错误,不能进行无界分配;超过该上限的历史 Session 暂由 Embedded TUI 打开,不在本阶段引入分页协议; -- 未认证连接也计入有界 connection budget,单个客户端不能无限制造 server task; -- 未知 frame/operation 信封字段、未知 operation、错误身份和不兼容版本 fail closed;复用的 Runtime DTO 按其既有反序列化契约处理字段; -- 一个连接最多控制一个 Session、同时最多提交一个活动 Turn;一个 Session 同时只有一个 controller。create/restore 在完整结果通过大小检查后才原子切换控制权,失败时保留原 Session。活动 Turn 期间不能切换 Session,也不能修改其名称、Agent mode 或 model。 -- Submit 使用调用方已有的 `turn_id` 标识不确定结果;若提交超时,返回 `outcome_unknown`、关闭连接并按该 ID 取消。断连取消只有得到确认后才释放 Session 控制权;无法确认时继续隔离该 Session,直到 Runtime 进程退出。 -- Session rename 和 Agent mode/model update 复用既有 Runtime 端口和校验,Runtime 对最终更新保持权威并拒绝无效值。它们都是有副作用操作;发送前编码或 frame 上限失败表示请求未执行,连接仍可使用。rename 写入失败时恢复旧 metadata:确认恢复后返回明确失败,无法确认时返回 `outcome_unknown`。Shared Client 在请求写入后响应超时或丢失连接时也返回 `outcome_unknown` 并断开连接。两种情况都不自动重试;用户恢复 Session 并核对当前值后再决定是否重试。模式与模型目录仍是同版本第一方产品事实,不加入 IPC。 -- Shared TUI 的模型选择器复用 Client 已有的只读产品配置来显示同版本模型目录;它只把选中的 model ID 通过 `update current Session model` 交给 Runtime。Client 不持有 Session 写入权,也不通过 IPC 管理模型目录或默认值。 -- Agent 事件流 lag/closed 后 fail closed;Permission lag 先从 Runtime 权威 pending 集合重建,重建失败或流关闭时取消当前 Turn 并退出。路由到父 Session 的嵌套 Permission 与 AskUserQuestion 复用现有 TUI 交互,不新增第二套 UI 状态。 -- Windows Shared Runtime 在初始化前把自身放入 kill-on-close Job;Unix 仅在应用内优雅退出路径中通过受管子进程组回收后代。Runtime 被 `SIGTERM`、`SIGKILL` 或崩溃直接终止后的 Unix 后代回收不在当前保证内。两者都只负责生命周期,不是安全沙箱。 -- 最后一个连接离开后等待 30 秒再退出;新连接会取消 idle 退出。退出只删除自己发布的 discovery;Unix 下继任 owner 会在持有实例锁后清理同一 identity 的陈旧 socket。 - -这是一条本机同用户边界,不是沙箱、远程协议或公开兼容承诺。 - -### 4.4 Serialization、并发与性能 +### 4.3 Shared ```mermaid flowchart LR - T1["TUI 1"] --> IPC["有界本机 IPC"] - T2["TUI 2"] --> IPC - TN["TUI N"] --> IPC - IPC --> Runtime["一个 Shared Runtime"] - Runtime --> Tasks["Tokio tasks"] - Runtime --> Owner["一个 Session owner"] + TUI1["TUI client 1"] --> App["TUI Shared App Server"] + TUI2["TUI client 2"] --> App + App --> Contexts["Bounded Runtime context registry"] + Contexts --> W1["Workspace A context + lease"] + Contexts --> W2["Workspace B context + lease"] + W1 --> Data["Workspace / Session storage"] + W2 --> Data ``` -多个 Shared TUI 复用一个 Runtime 进程。每个连接使用独立异步任务,但连接、命令队列和事件队列都有上限;达到连接上限时暂停接收新连接,慢客户端不能建立无界任务或队列。默认不增加 Runtime 进程池,因为复制 Session 状态、模型连接和缓存会扩大一致性成本。只有经测量证明某类无状态 CPU 工作可独立分片时,才评审额外 worker 进程。 +Shared 与 Embedded 的区别只有: -| 路径 | 数据边界 | 性能约束 | -|---|---|---| -| Embedded | 第一方 adapter 以 Rust 类型直接调用 `AgentRuntime` | 不初始化本机 IPC,不执行 JSON framing、序列化或反序列化 | -| Shared request | Client 将 operation 编码一次并写入一个长度前缀 frame | 请求保持 128 KiB 上限;业务层只接收类型化 operation | -| Shared response/event | Server 将结果或事件编码一次后写出 | 响应/事件保持 8 MiB 上限;超限使事件流明确失效,不能无界分配 | -| Shared receive | 每个方向只有一个严格 transport decode 边界 | 未知信封字段和不兼容版本 fail closed;严格校验可以检查规范化 JSON,但不能把动态 JSON 传入 Runtime owner | -| 多 TUI | 一个 Runtime、最多 64 个连接;每个 Client 的 command channel 容量为 64、event channel 容量为 256 | request gate 使每个 Client 同时只有一个请求进入 channel;事件落后时失效而非无限缓存 | +- Shared 有稳定 instance identity、discovery 和多个认证连接; +- Shared 的 drain 同时考虑 Client、Controller、Observer、活动 Turn、后台任务和 Remote 引用; +- Shared 必须实施连接/请求/事件 budget、公平调度和慢客户端隔离; +- Shared 支持同一种 `client_kind` 内的同一 Session 观察和受控写入。 -协议只承载当前交互所需的小型控制请求和既有事件。大 transcript 继续受 frame 上限约束;本阶段不为假设场景增加通用分页、二进制 side channel、压缩或批处理协议。 +Shared 不允许增加专用 method、DTO、事件或 handler。若某能力只适合 Shared,应通过 +capability negotiation 表达可用性,而不是分叉协议。 -## 5. Development and Physical Views · Level 1 +Shared instance 在创建时固定 `client_kind`,discovery key 和 initialize 都必须验证该事实。TUI、Desktop、 +VS Code 与 Web 即使使用相同 schema,也必须连接不同实例;跨形态 Session 接力依赖持久化恢复或显式 handoff, +不依赖混连同一个 Server。 -### 5.1 Development View +`client_kind` 按具体宿主形态分配,至少区分 `tauri-desktop`、`electron-desktop`、`vscode`、`tui` 和 +`web`。它不是可由 Client 自报的自由文本,也不能把 Tauri 与 Electron 合并成宽泛的 `desktop` 后共享实例。 -```mermaid -flowchart TB - GUI["GUI adapter"] --> API["Agent Runtime API"] - TUI["TUI adapter"] --> API - CLI["Headless CLI adapter"] --> API - SDK["SDK Host adapter"] --> API - ACP["ACP adapter"] --> API - Server["Server adapter · when assembled"] --> API - API --> Coordinator["ConversationCoordinator"] - Coordinator --> Behavior["single behavior owners"] - - GUI -. "composition" .-> Ownership["CoreRuntimeOwnership"] - TUI -. "Embedded / opt-in Shared" .-> Ownership - CLI -. "Embedded" .-> Ownership - SDK -. "Embedded" .-> Ownership - ACP -. "Embedded" .-> Ownership - Server -. "only when Runtime is assembled" .-> Ownership - Ownership -. "injected once" .-> Coordinator -``` +### 4.4 产品组装与实例隔离 -```mermaid -flowchart LR - CLI["apps/cli"] --> Client["CLI Runtime client"] - Client -->|"Embedded"| Runtime["execution/agent-runtime"] - Client -->|"Shared only"| IPC["adapters/agent-runtime-ipc"] - IPC --> Handler["CLI Shared handler"] - Handler --> Runtime - Runtime --> Ports["runtime ports / owners"] -``` +Embedded 与 Shared 使用唯一 App Server Delivery Profile 创建 Runtime;Embedded 由匹配 Client Host 承载, +Shared 由 `apps/app-server` 或匹配服务端组装根承载。实例启动时固定产品组装结果、`client_kind`、数据命名空间、组织/用户安全域、release channel、 +Runtime Configuration 和 capability 上限;Client 握手只能声明前端与 Host capability,不能重选后端 +profile、产品策略、持久化根或内置扩展。 -CLI adapter 负责命令解析、TUI 状态和错误文案;私有 IPC 只负责本机传输、连接控制和类型映射;Agent Runtime 与 owner 负责 Session 校验、持久化和权威结果。业务代码通过同一个 CLI Runtime client 调用能力,不根据部署形态复制业务分支。 +因此只有同一种 `client_kind` 的多个 Client 可以共享一个兼容实例;Tauri Desktop、Electron Desktop、VS Code、 +TUI 和 Web 之间不得混连。不同产品身份、数据隔离域、安全策略、release channel 或 execution domain +也必须使用不同实例。Shared 进程键来自 `client_kind` 与这些状态和安全事实,不来自窗口、workspace、 +Session 或 plugin 数量。一个 Shared App Server process +可以承载多个 workspace,但不能让一个 workspace-bound Runtime object 改绑或跨 workspace 复用。 -- CLI 不依赖 SDK Host,GUI/TUI 也不依赖公开 SDK package。 -- 交互式 TUI 的启动页和会话页复用一个 CLI 私有 Runtime client;Session、Turn、Permission 和事件订阅都使用 Rust Runtime SDK(当前 preview)。该 client 只是第一方 adapter,不是公开 SDK、SDK Host client 或第二套 Runtime。 -- Headless CLI 和 Peer Host 使用同一 Runtime 订阅入口,但分别保留确定性退出与 Peer fanout 语义;共享订阅入口不等于共享 renderer 或产品生命周期。 -- TUI 不是 Server;未来是否连接 Shared deployment 是部署选择,不改变 TUI 的 renderer/键位职责。 -- Agent SDK Host 只服务外部 SDK 合同,不成为第一方 rich-client 的通用底座。 -- Headless CLI 默认继续 Embedded;CI 或测试可保持独立进程和独立 workspace,不承担后台实例成本。 -- Tauri 仍负责窗口和桌面能力;未来它可以管理 Shared process 的启动/重连,但不拥有 Agent Runtime 业务生命周期。 +## 5. Runtime ownership 与 Session 单写 -### 5.2 Physical View +### 5.1 Workspace ownership -```mermaid -flowchart TB - subgraph Embedded["默认 Embedded"] - TUI["TUI / Headless / CI"] --> Direct["in-process Agent Runtime"] - end - subgraph Shared["显式 --shared"] - Clients["one or more TUI processes"] -->|"Named Pipe / UDS"| SharedRuntime["Shared Runtime process"] - end - Direct --> Data["workspace + Session storage"] - SharedRuntime --> Data -``` - -默认交互式 TUI、Headless CLI 和 CI 保持 Embedded。只有显式 `--shared` 的交互式 TUI 进入 Shared;同一 workspace 的两种部署互斥。多开 TUI 增加 Client 进程和有界连接,不按 Client 数量复制 Runtime、Session owner 或 Plugin Host。 - -### 5.3 Scenario (+1) · Rename current Session +`CoreRuntimeOwnership` 仍是本机 Runtime deployment 的权威 gate。目标 App Server 不把当前 +Shared deployment object 从单 workspace 强行改成多 workspace;它在实例内维护有界的 Runtime +context registry,每个 context 独立绑定一个 workspace 与 lease: ```mermaid -sequenceDiagram - participant U as User - participant T as TUI adapter - participant C as CLI Runtime client - participant R as Agent Runtime - - U->>T: /rename Auth refactor - T->>T: trim + require idle Session - T->>C: rename_session(id, name) - C->>R: direct call or one Shared frame - R->>R: validate ownership + persist - R-->>C: applied / failed / outcome_unknown - C-->>T: typed result - T-->>U: update name only after applied +flowchart TB + App["Embedded / Shared App Server"] --> Registry["Runtime context registry"] + Registry --> Core["CoreRuntimeOwnership per workspace context"] + Roots["Direct CLI · ACP · SDK Host"] --> Core + Core --> Primitive["services-core runtime ownership primitive"] + NetworkApp["Networked Embedded / Shared"] --> TenantOwner["tenant-scoped ownership provider"] + Remote["Remote Runtime Host"] --> RemoteOwner["target-host ownership provider"] + Primitive --> Lease["local ownership fact"] + TenantOwner --> TenantLease["tenant ownership fact"] + RemoteOwner --> RemoteLease["remote ownership fact"] ``` -Embedded 和 Shared 最终调用同一 `AgentRuntime::rename_session`。Runtime 只有在确认旧名称已保留时才返回明确失败;持久化恢复无法确认时,两种部署都返回 `outcome_unknown`。Shared 还会在请求已发送但权威响应丢失时返回该结果并关闭连接。用户恢复 Session、检查当前名称后再决定是否重试。 - -## 6. 隔离和生命周期原则 - -实例身份与 ownership key 分工不同: - -| 事实 | 用途 | -|---|---| -| canonical workspace + product | 防止 Embedded 与 Shared 同时拥有同一工作区 Runtime | -| workspace + product + release channel + user + protocol | 定位兼容的本机 Shared instance | -| stable local endpoint + bearer token + owner id | endpoint 定位同一 instance;随机 token 认证本轮 server;owner id 防止旧实例误删新 discovery | -| 实际 Session 存储位置 + Session ID | 限制持久化 Session 的跨进程并发写入;不由 IPC 协议定义 | - -当前 Shared TUI 只有 controller,没有 observer 或 detached Query:一个 Client 关闭不会删除 Session;它会取消仍拥有的活动 Turn,只有取消得到确认才释放 Session 控制权,否则继续隔离该 Session,直到 Runtime 退出。最后一个 Client 关闭后,Runtime 进入 30 秒空闲期;期间重连可继续使用,超时后 Runtime 正常关闭。若未来增加后台任务、observer 或 Remote 引用,必须先扩展 Runtime-aware drain,不能把这些引用塞进当前简单连接计数。 - -对普通单实例用户,未显式启用 Shared deployment 时不增加后台进程、连接、发现扫描或常驻内存。 - -## 7. 能力扩展原则 - -未来每增加一类 Shared 能力,都必须同时满足: - -1. 已有明确第一方 consumer 和用户旅程; -2. 行为由现有 Runtime owner 提供,IPC 只映射 typed request/result/event; -3. 定义权限、取消、deadline、断线、背压和副作用结果不确定性; -4. Embedded 与 Shared 使用同一行为 fixture; -5. 新能力不被顺带发布为 Agent SDK、Remote 或浏览器 API。 - -Session/Turn、事件恢复、Permission/UserInput、Controller、配置管理和 Remote 应分别通过上述门槛,不能一次性加入一个“全量 Shared API”。 - -当前 IPC crate 只是一条可删除的预集成边界: - -| 约束 | 当前决定 | -|---|---| -| 当前 consumer | 仅第一方交互式 TUI adapter;不自动包含 GUI、Headless CLI、Remote 或 SDK Host | -| 稳定测试合同 | 本机 endpoint、initialize-first、128 KiB request / 8 MiB response-event 上限、连接上限、owner-checked cleanup、原子 Session controller 切换、单连接单活动 Turn、事件流失效后 fail closed、断连取消、30 秒空闲退出 | -| 当前业务范围 | Session/Turn/transcript、当前 Session name/Agent mode/model、Permission/UserInput 的 TUI 必需子集;任何新增操作都需要真实 consumer 和 owner 等价测试 | -| 协议地位 | crate 保持 `publish = false`;这是 workspace 内私有协议,不是 Agent SDK 或远程兼容承诺 | - -架构守卫只允许 CLI 消费该 crate;IPC 可以复用稳定的 Event、Product Domain 与 Runtime Port DTO,但禁止依赖 Runtime 实现、SDK Host、services、Tauri 或远程网络 transport。 - -## 8. 与竞品的取舍 - -| 产品 | 已验证做法 | BitFun 采用 | 不照搬 | -|---|---|---|---| -| [OpenCode Server/SDK](https://opencode.ai/docs/server/) | Server-first;类型化 SDK 直接消费 Server API | 一个 Runtime owner 可以服务多个第一方 Client | 不让默认 TUI 承担 HTTP/OpenAPI 编解码,也不把全量 route 固化为私有 Shared wire | -| [Codex App Server](https://developers.openai.com/codex/app-server/) | App Server 为 rich client 和 remote TUI 提供 JSON-RPC;自动化继续使用 SDK;WebSocket transport 仍是实验性接口 | rich-client 私有协议与公开 SDK 分层,并为 Shared 入口保留有界本机 transport | 不让默认 CLI 依赖 App Server,也不复制其完整 schema 或实验性远程 transport | -| [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/typescript) | Agent loop 由长期运行的 CLI 子进程承载,并提供 `startup()` 预热以减少首次请求成本 | 长期交互可以复用已启动进程,空闲后回收 | 不让第一方 Embedded TUI 为接口统一付出子进程和编解码成本,也不把多 TUI 映射为多个 Runtime | - -三种产品说明了不同部署的有效边界:server-first 适合稳定多客户端协议,长期子进程适合语言 SDK,进程内调用适合默认本机交互。BitFun 采用混合部署,不把任何一种形态强制成所有入口的公共底座;当前也没有为了追赶功能表一次性增加 Session/Tool/Permission 超集。 - -## 9. 不变量 +规则: + +- 本机 Embedded、Shared 和 Direct Runtime 使用 `CoreRuntimeOwnership`;服务端 Embedded/Shared 使用 tenant-scoped + provider,Remote 在目标 execution host 使用目标侧 provider,任何协议都不能绕过匹配的 ownership; +- instance/discovery compatibility identity 可以包含 product identity、security domain、execution domain + 和协议兼容范围,但它不等于可变 workspace 资源的 ownership collision key; +- workspace ownership collision key 必须保留当前 canonical workspace + product identity 的冲突等价关系。 + security/execution domain 只能在其 workspace、持久化根和执行资源已物理隔离时进一步分区,不能仅凭 + Client 声明或标签让同一现有资源取得第二把互不冲突的锁; +- 当前 `services-core` key 只有 canonical workspace 与 product identity,当前 Shared owner 只允许一个 + workspace。增加 registry 或升级 key 格式前必须先扩展 key/context 合同并保留旧行为;滚动迁移期间 + 新 owner 同时取得旧 collision key 与新 key,直到旧 binary 退出兼容窗口。禁止通过跳过 + `CoreRuntimeOwnership`、只取得新 key 或复用已绑定 Runtime 来支持第二 workspace; +- registry 对 context 数量、空闲回收和并发创建有上限;同一 key 的并发 attach 原子复用一个 context, + 不同 key 独立取得、持有和释放 lease;最后一个 Client 断开不自动释放仍有 active Turn、Session writer、 + 后台任务或恢复引用的 context; +- Remote workspace 的 ownership 位于目标 execution host,本机不得静默取得替代 lease; +- list/view 等只读操作可以不取得 mutation ownership,但仍需执行身份和访问控制; +- Shared 与其他可写 Runtime deployment 的互斥由 Core owner 决定,不由 App Server route + 或 discovery 文件冒充。 + +迁移验收必须覆盖:同一实例同时打开第二个本机 workspace、同 key 并发 attach、远程 workspace +目标侧 ownership、Direct/Embedded/Shared 冲突、最后一个 Client 断开后的有界回收,以及进程重启后的 +ownership 恢复。任一项未通过时,一个 App Server instance 只能暴露一个 workspace。 + +### 5.2 Session 单写 + +持久化 Session 的保护粒度是“实际 Session 存储位置 + Session ID”。任何部署中同一 Session +同时只能有一个权威 writer;Observer 可以读取投影,但不能提交 Turn、Permission 或 metadata。 + +| 操作 | Controller | Observer | +|---|---|---| +| transcript/event view | 是 | 是 | +| submit/cancel Turn | 是 | 否 | +| respond Permission/UserInput | 是 | 否 | +| rename/mode/model update | 是 | 否 | +| transfer control | 发起或接受 | 接受后成为 Controller | + +Controller lease 属于 Runtime-aware App Server session attachment,不属于 transport socket。连接 +断开、重连或 transport 切换时,只有 Runtime 确认活动副作用已结算后才能释放控制权。 + +## 6. 连接、并发与可靠性 -- 只有一套 Agent Runtime 业务实现;部署差异不能产生第二套 Session、Tool、Permission 或 MCP owner。 -- Client、窗口、Session 或 workspace 数量不会自动等量增加 Runtime 或 Plugin Host 进程。 -- 私有 IPC 不成为公开 SDK、Remote、Peer、HTTP 或浏览器协议。 -- 默认 GUI/TUI/Headless CLI、ACP 与 SDK Host 保持 Embedded;只有交互式 TUI 的显式 `--shared` 选择 Shared。互斥按 `workspace + product` 生效,不再按入口名称缩窄。 -- Account/session cloud sync 仍使用既有 Core compatibility 边界,不属于 Shared Runtime 支持。 -- Remote workspace 的文件、凭据、进程和 Runtime 位于目标执行域,禁止静默回落本机。 -- 未经真实 consumer 验证的接口不进入 wire;当前 wire 只包含表中列出的 Shared TUI 操作。 +### 6.1 初始化和认证 + +- 第一帧完成协议范围、instance identity、client identity、认证和 Host capability 协商; +- 第一帧还必须验证 deployment 与实例固定的 `client_kind`;Embedded 拒绝第二个 Client,Shared 拒绝 + 不同 `client_kind`; +- 本机 endpoint 使用 Windows Named Pipe 或 Unix Domain Socket,默认拒绝跨用户/远程连接; +- Web 使用独立网络认证、租户/workspace 授权、Origin/CORS 和 method allowlist; +- bearer token、凭据和 ownership key 不进入 URL、日志、renderer、事件或 transcript; +- 未认证连接也计入 connection budget,防止资源耗尽。 + +### 6.2 有界并发 + +App Server 必须为以下资源设定可配置且有上限的 budget: + +- 总连接和每身份连接数; +- 每连接并发 request 和 reverse request; +- command、response 和 event queue; +- request/response/event frame 大小; +- 每 Session 活动 Turn、pending Permission/UserInput; +- 全局模型调用、Tool/MCP 调用和后台任务。 + +达到上限时返回类型化 `overloaded`、暂停接收或使慢连接失效,不能创建无界 task、channel +或序列化缓冲。公平调度至少隔离不同 Client 和 Session,不能让一个慢 Observer 阻塞 Runtime +或其他 Controller。 + +### 6.3 取消和不确定结果 + +- 请求 deadline 和 Client cancel 映射到 Runtime 既有取消树; +- Client 断开不删除 Session,也不默认终止无关后台任务; +- Controller 断开时请求取消其活动 Turn,只有得到权威结算后才释放 lease; +- 请求发送前失败表示未执行;发送后响应丢失的副作用返回 `outcome_unknown`; +- `outcome_unknown` 不自动重试,Client 重新读取权威状态或使用幂等 operation ID; +- 无法确认取消结果时隔离 Session writer,直到 Runtime 恢复或退出。 + +### 6.4 事件恢复 + +- Runtime 提供唯一权威事件源,adapter 只做过滤、投影和脱敏; +- event queue 有界,`Lagged`/`Closed` 是显式失效; +- 首个稳定 Shared 版本必须提供 snapshot + cursor/resume,或明确以 snapshot 后新流恢复; +- 不能把丢失事件伪装成透明成功;Permission/UserInput pending 集合必须可从 Runtime 权威状态重建; +- event identity 在 Embedded/Shared 和各 `client_kind` 间保持一致,但这不允许跨类型混连实例。 + +### 6.5 Runtime-aware drain + +App Server 退出不能只按 TCP/socket 连接数决定。Drain 至少考虑: + +- 已认证 Client 与重连 grace period; +- Controller/Observer attachments; +- 活动 Turn、Tool/MCP、Permission/UserInput; +- Cron、长期任务和其他后台引用; +- Remote 控制或恢复引用; +- 持久化 flush、Plugin Host 与工具进程回收。 + +Embedded 随唯一 Host 退出进入有界 drain;Shared 使用独立 idle policy。两者最终 +调用同一个 Runtime shutdown coordinator。 + +## 7. Host capability 与 Remote + +App Server 通过初始化协商 Host capability。窗口、文件选择、剪贴板、终端窗口展示、截图和 Computer +Use 等界面宿主操作以 reverse request 发送到当前操作绑定的可信 Host,不按“任意已连接 Client” +广播。 + +- capability route 绑定 client identity、operation、deadline 和 execution domain; +- Observer 不能通过 Host capability 绕过 Controller 或 Permission owner; +- capability 缺失返回类型化 `unsupported`; +- PTY、Shell、命令执行、进程生命周期和取消属于 Runtime Services,不是 Host capability; +- Remote workspace 的文件、终端执行、凭据、进程和 Runtime 在目标 host 执行; +- 本机 App Server transport 不自动成为 Remote transport,Remote 复用业务 DTO 但保留认证、 + 网络恢复和租户隔离合同。 + +## 8. 迁移与删除 + +当前实现只提供迁移证据,不决定最终模块边界: + +- 交互式 TUI 当前默认使用 legacy in-process Runtime,显式 `--shared` 使用 `agent-runtime-ipc`; +- 当前 Shared owner 在创建时绑定一个 workspace,第二 workspace 返回 + `shared_runtime_workspace_mismatch`; +- 当前 ownership key 只包含 canonical workspace 与 product identity,尚无 security/execution domain; +- App Server assembly、transport、backend profile 和多 workspace registry 均未创建。 + +1. 将 Shared TUI 已验证的 controller lease、认证、framing 上限、断连取消、事件失效、 + `outcome_unknown` 和 cleanup fixture 提升为 App Server conformance tests; +2. App Server 首先完成 Session/Turn/Permission/UserInput 纵向切片,并让 Desktop 和交互式 + TUI 使用同一 typed client; +3. 默认 TUI 创建独占 Embedded App Server,`--shared` 连接 TUI-only Shared App Server; +4. 把真正通用的 Named Pipe/UDS、discovery 和有界 framing 原语迁入 + `app-server-transport`; +5. 删除 `agent-runtime-ipc` 的 TUI-specific operation、handler、server 和协议测试; +6. 删除旧 Tauri 业务 command、私有 WebSocket 信封和重复事件映射前,使用共同 fixture + 证明行为等价并保留有界回滚期; +7. Headless CLI/CI、ACP 和 SDK Host 不在本迁移中绕行 App Server;Headless `--shared` 继续拒绝。 + +迁移结束的删除条件是:仓库内不存在第二套第一方 Rich Client Session/Turn/Permission +wire、第二个 Shared server 入口或按 TUI/GUI 分叉的 App Server handler。 + +## 9. 验收门槛 + +最终部署架构至少通过: + +1. Tauri、Electron/VS Code 样例和交互式 TUI 使用同一 schema、typed client 和 handler; +2. Embedded 与 Shared 使用同一行为 fixture,只有承载、连接数和 discovery fixture 不同; +3. TUI `--shared` 不引用独立 Shared TUI operation/server; +4. Controller/Observer、control transfer、断连取消和 Session 单写有并发测试; +5. 多 workspace registry 覆盖第二 workspace、远程域、并发 attach、Direct/Embedded/Shared 冲突、旧新 key + 混合版本冲突、断连回收和重启恢复; +6. request/event budget、慢 Client 隔离、公平调度和 overload 有压力测试; +7. `outcome_unknown`、幂等 operation、snapshot/cursor 恢复有故障注入测试; +8. Runtime-aware drain 覆盖活动 Turn、后台任务、Remote 引用和进程树回收; +9. Embedded 单连接拒绝、Shared `client_kind` 隔离、本机认证、Web 认证、Host capability route 和 Remote execution domain 有安全测试; +10. Headless CLI/CI 的 Direct Runtime 启动、退出和性能不因 App Server 迁移退化; +11. 旧 Shared TUI wire、旧 Tauri 业务桥和重复 WebSocket schema 有明确删除证据。 + +## 10. 不变量 + +- 只有一套 Agent Runtime 行为 owner; +- 所有第一方 Rich Client,包括交互式 TUI,只使用 App Server wire; +- App Server 只存在 Embedded 与 Shared;网络、租户和运维约束不形成 Hosted 第三形态; +- Embedded 恰好一个 Client 对一个 Server;Shared 多个 Client 对一个 Server,但固定一个 `client_kind`; +- 不存在长期 Shared TUI server、Shared GUI server 或按前端分叉的 Runtime API; +- Headless CLI/CI 默认 Direct Runtime;ACP、SDK Host 和 Remote 保留独立协议边界; +- App Server、SDK Host、Plugin Host 和 Remote Host 是不同进程职责; +- workspace ownership、Session 单写、权限、取消和审计始终由既有 owner 决定; +- Shared 中 Client、窗口、workspace、Session 或 plugin 数量不自动等量增加 App Server/Plugin Host 进程; + App Server 内每个 workspace 仍有独立 Runtime context 和 ownership lease; +- Remote workspace 不静默回落本机; +- 未有真实 consumer、失败语义和验证的 method/capability 不进入稳定协议。 diff --git a/docs/architecture/agent-runtime-services-design.md b/docs/architecture/agent-runtime-services-design.md index 645755e77..ccb9d77c8 100644 --- a/docs/architecture/agent-runtime-services-design.md +++ b/docs/architecture/agent-runtime-services-design.md @@ -9,8 +9,9 @@ CLI Agent 体验边界见 [`cli-product-line-design.md`](cli-product-line-design 多宿主 adapter 的状态、权限、并发和兼容边界见 [`capability-runtime-integration-design.md`](extensions/capability-runtime-integration-design.md);公开 BitFun Agent SDK 的 用户心智、SDK Host、Headless CLI/ACP/Server 关系、竞品基线和能力发布门槛见 -[`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md);第一方 GUI/TUI/Remote 多实例、Headless CLI Embedded、 -Shared Agent Runtime 与 Plugin Host 的进程关系见 +[`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md);第一方 Rich Client(包括交互式 TUI)的统一协议见 +[`app-server-architecture-design.md`](app-server-architecture-design.md);Embedded/Shared App Server、Headless Direct Runtime、 +Remote 与 Plugin Host 的进程关系见 [`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md)。 本文中的接口片段只说明依赖方向和职责,不自动构成当前 API 或实施承诺。当前接口名称、字段和消费方以代码为准; @@ -744,8 +745,10 @@ Core 的 Network、Git 和 MCP Catalog 当前仍含兼容 marker,因此该诊 但完整持久化历史回放、模型/模式目录与提供方配置和 MCP 仍走单一 Core 兼容接口;会话模型/模式写入通过 Agent Runtime API 回到同一 Core 归属模块。ACP stdio、连接和协议转换仍在 `interfaces/acp`。Desktop 复用同一 Core owner 构造一个窄口径 Rust Runtime SDK,主界面的轮次提交/取消、工具确认/拒绝和 用户问题回答与会话模型更新已通过 Rust Runtime SDK;会话 CRUD/恢复视图、MCP、MiniApp、Cron、远程连接、Tauri 窗口与平台资源 -仍保留在 Desktop/Core 兼容入口。Server 仅提供健康检查、信息与 ping 路由。未接入入口的 profile、枚举分支和 -单元测试仍不能证明对应产品形态可用。 +仍保留在 Desktop/Core 兼容入口。Server 提供健康检查、信息与 ping,以及不启动 Agent Runtime 的窄 +detached-dispatch controller/observer 路由;该 loopback WebSocket 控制面会使用已保存的 SSH connection +执行 install、submit、cancel、answer、append 等可变操作,不等于完整 Server profile 或独立产品组装。 +未接入入口的 profile、枚举分支和单元测试仍不能证明对应产品形态可用。 Desktop 与 CLI Peer Host 还各自注入同一个 Core-backed `LocalWorkspaceSnapshotPort` 契约。它是两个本地宿主之间的内部 owner 边界, 不是公开 Agent SDK、Agent Runtime API 的通用能力、完整 Desktop profile、跨宿主远程能力或通用 checkpoint/rewind API。Core 继续持有 `SnapshotManager`、工具拦截、 diff --git a/docs/architecture/agent-sdk-product-architecture.md b/docs/architecture/agent-sdk-product-architecture.md index 6d046d3ee..a809e314c 100644 --- a/docs/architecture/agent-sdk-product-architecture.md +++ b/docs/architecture/agent-sdk-product-architecture.md @@ -7,7 +7,9 @@ [`cli-product-line-design.md`](cli-product-line-design.md) 定义;扩展能力导入和宿主适配由 [`capability-runtime-integration-design.md`](extensions/capability-runtime-integration-design.md) 定义;多个第一方界面与 SDK/CLI 并存时的 Runtime 部署、共享和进程隔离由 -[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md) 定义。 +[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md) 定义;Tauri、Electron、VS Code Extension、Web 等 +第一方 Rich Client 的统一协议由 +[`app-server-architecture-design.md`](app-server-architecture-design.md) 定义。 本文只记录长期产品心智、架构边界和发布门槛。当前代码中的 `agent-runtime::sdk` 是供 BitFun 内部入口和受控 Rust 嵌入使用的低层 Rust Runtime SDK; @@ -21,7 +23,7 @@ BitFun 不选择“复制 Claude”“复制 OpenCode”或“复制 Codex”中 | 问题 | 采用的成熟做法 | BitFun 决策 | |---|---|---| | 用户如何运行 Agent | Claude Agent SDK 的 Agent、Session、消息流、Tool、MCP、Permission、Hook 心智 | 公开 API 使用行业常见 Agent 概念,不暴露内部端口、协议和 Product Assembly | -| 如何让多个产品入口共享能力 | OpenCode 的 Server/Core 多客户端模式,Codex App Server 的 rich-client 边界 | 所有入口调用同一 Agent Runtime API;入口是同级 adapter,不相互依赖 | +| 如何让多个产品入口共享能力 | OpenCode 的 Server/Core 多客户端模式,Codex App Server 的 rich-client 边界 | 所有入口调用同一 Agent Runtime API;GUI/Web/交互式 TUI 共享 App Server wire,SDK/ACP/Headless CLI 保持同级独立 adapter | | SDK 如何保持简洁 | Codex SDK 的精选 Thread/Turn 用例,而不是全量管理 API | 公开 SDK 只提供 Agent 应用所需的高层用例,不直接镜像内部或 Server 全部路由 | | 本地 Runtime 如何交付 | Claude/Copilot SDK 管理匹配原生 runtime,Codex App Server 的握手与 schema 纪律 | SDK 默认管理匹配的本地 `bitfun-sdk-host`;用户不需要安装 CLI | | 多语言如何一致 | Copilot SDK 的单协议、多语言包、协议版本范围和 codegen drift check | Python/TypeScript 是同一 SDK 的语言绑定,共用一个 Host 协议和一致性套件 | @@ -30,7 +32,7 @@ BitFun 不选择“复制 Claude”“复制 OpenCode”或“复制 Codex”中 一句话定义: > BitFun Agent SDK 是同一 BitFun Agent Runtime 面向应用开发者的公开开发接口;它不是新的 Runtime, -> 不是 CLI/Server 的别名,也不是 GUI/TUI 的底层依赖。 +> 不是 CLI/Server/App Server 的别名,也不是 GUI/TUI 的底层依赖。 最终只向普通用户和外部开发者呈现三种产品选择: @@ -61,7 +63,7 @@ Codex 代码基线为 | Runtime 交付 | Python/TS 包携带原生 Claude Code binary | SDK 可启动 PATH 中的 Server,也可连接已有 Server | TS SDK 包装 CLI JSONL;App Server 提供更完整协议 | SDK 通过 JSON-RPC 管理 CLI server;部分语言包携带 CLI | 安装 SDK 后应得到匹配 Host,但 CLI 与 SDK Host 不能混为一个产品 | | 能力深度 | 内置 Tool、MCP、Hook、权限、Subagent、Skill、Plugin、Session、用量 | Project/Session/File/TUI/MCP/Provider 等广泛 Server API | SDK 精简;App Server 有审批、动态工具、事件、配置和稳定/实验分层 | Session、工具、Hook、权限、事件等经协议开放 | GA 能力下限参考 Claude,协议纪律参考 Codex/Copilot | | 生态发展 | 官方 Python/TS SDK 和完整能力文档;生态围绕 Claude Code 配置与插件 | 开源 Core/Server、Provider/Plugin 生态及 TUI/Web/Desktop/IDE 多客户端 | 开源 Runtime/App Server 快速演进;TS SDK 走 CLI JSONL,Python SDK 绑定匹配 Runtime/App Server | 六种语言包、统一协议和各语言 registry | 首版聚焦 Python/TS,但合同从第一天按可增加语言设计;不把某一语言实现当规范 | -| 多客户端/UI | SDK 示例为主,官方不提供通用 UI SDK | TUI/Web/Desktop/IDE 共享 Server;SDK 可控制 TUI | App、CLI、SDK 分层;App Server 面向 rich client | 面向各语言应用,无统一组件层 | BitFun 第一方界面直接用 Runtime API,外部 UI 经开发者后端使用 SDK | +| 多客户端/UI | SDK 示例为主,官方不提供通用 UI SDK | TUI/Web/Desktop/IDE 共享 Server;SDK 可控制 TUI | App、CLI、SDK 分层;App Server 面向 rich client | 面向各语言应用,无统一组件层 | BitFun Rich Client 经 App Server、其他第一方入口经各自 adapter 使用 Runtime API;外部 UI 经开发者后端使用 SDK | | 多语言 | Python/TypeScript,部分能力存在语言时差 | 官方主要 JS/TS,OpenAPI 可生成其他客户端 | TS 与 Python 当前底层形态不同 | TS/Python/Go/.NET/Java/Rust,共用协议版本 | 不能让 Python/TS 各写一套 transport 和行为 | | 可定制程度 | callback、Tool、Hook、MCP、Agent/Skill/Plugin 配置 | Server 全资源控制和插件生态,最开放 | 精选 SDK 较克制,App Server 更底层 | 多语言自定义 Tool/Hook | 公开 API 保持精选;高级资源管理通过明确 capability 增量开放 | | 发布渠道 | npm、PyPI,包内携带 binary | npm SDK;Server 由 OpenCode 安装提供 | npm SDK、PyPI SDK/Runtime、Codex CLI | npm、PyPI、NuGet、Go module、Maven、crates.io | 语言包走原生 registry;Host 版本必须与 SDK 可验证匹配 | @@ -161,6 +163,7 @@ flowchart TB | 层次 | 使用者 | 状态与职责 | |---|---|---| | Agent Runtime API | BitFun 各产品 adapter | 唯一 Agent loop 与应用用例边界;不是语言包 | +| Rich Client App Server | Tauri/Electron/VS Code/Web | 第一方交互界面的版本化 wire;不是公开 Agent SDK | | Rust Runtime SDK | BitFun 内部入口、受控 Rust 嵌入 | 当前 preview;不等于公开产品 | | BitFun Agent SDK | Python/TypeScript 应用开发者 | 一个公开产品、多个语言绑定;尚未交付 | @@ -172,12 +175,12 @@ Python SDK、TypeScript SDK、managed Host 和连接预启动 Host 不是四种 ```mermaid flowchart TB - GUI["GUI / TUI"] --> UIA["UI adapter"] + GUI["Tauri / Electron / VS Code / Web / Interactive TUI"] --> App["Rich Client App Server"] CLI["bitfun exec"] --> CLIA["CLI adapter"] SDK["Agent SDK"] --> SDKA["SDK Host"] ACP["ACP"] --> ACPA["ACP adapter"] Server["Server / Remote"] --> RemoteA["Server / Remote adapter"] - UIA --> API["Runtime API"] + App --> API["Runtime API"] CLIA --> API SDKA --> API ACPA --> API["Runtime API"] @@ -191,23 +194,27 @@ flowchart TB ### 4.2 互操作入口 -上图中的 ACP、Server/Remote 和 SDK Host 都是同级 adapter;虚线只表示第一方进程装配 ownership,不表示某个入口依赖另一个入口。 +上图中的 App Server、Headless CLI、ACP、Server/Remote 和 SDK Host 都是 Runtime API 之上的同级 adapter;虚线只表示第一方进程 +装配 ownership,不表示 SDK Host 或 ACP 依赖 App Server。 上图固定四条架构结论: -- GUI/TUI/CLI 同样使用 Query、MCP、Permission 和 Hook,但它们直接经过各自 adapter 调用共享 Runtime API, - 不依赖 Python/TypeScript SDK,也不依赖 SDK Host。 +- Tauri/Electron/VS Code/Web/交互式 TUI 等 Rich Client 经 App Server 调用共享 Runtime API;Headless CLI 经过自己的 + Direct Runtime adapter。它们都不依赖 Python/TypeScript SDK,也不依赖 SDK Host。 - SDK Host 是跨进程/跨语言 adapter,不拥有 Session、Tool、MCP、Permission、Hook 或 Event 状态。 -- 各入口共享业务事实和 owner,不共享 renderer、命令行参数、wire protocol 或平台生命周期。 +- Rich Client 的 Embedded 与 Shared deployment 共用 App Server wire;每个 Shared instance 固定一种 `client_kind`。 + SDK Host 和 ACP 保持各自 wire,Headless CLI 默认 Direct Runtime。所有入口共享业务事实和 owner,不共享 renderer、 + 命令行参数或平台生命周期。 - 增加 SDK 不得让 CLI、GUI/TUI 或 Server 的底层依赖变深;它只增加一个同级入口。 -该图表达逻辑依赖,不要求所有入口位于同一进程。目标部署中,GUI/TUI/本机 Remote 可以连接第一方 Shared Agent Runtime; -一次性 Headless CLI 继续 Embedded;公开 SDK 默认连接私有 SDK Host。Shared Agent Runtime process 和 SDK Host 都是 Rust 产品进程, -与运行第三方 JS/TS 的 Node/Bun Plugin Host 不同;三者不能共享名称或业务归属。 +该图表达逻辑依赖,不要求所有入口位于同一进程。目标部署中,Rich Client Host 创建独占 Embedded 或连接匹配 +`client_kind` 的 Shared App Server;交互式 TUI 的 `--shared` 与 GUI/IDE Shared 复用 schema/handler,但连接不同实例, +不存在独立 TUI wire。一次性 Headless CLI 继续 Direct Runtime,公开 SDK 默认连接私有 SDK Host。App Server 承载单元和 SDK Host +process 都由 Rust 实现,但合同和生命周期不同;它们与运行 +第三方 JS/TS 的 Node/Bun Plugin Host 也不能共享名称或业务归属。 -当前代码已经交付显式启用的 Shared TUI 最小切片,包含本机 IPC、身份、握手、Session/Turn、当前 Session 的 name/Agent mode/model、Permission/UserInput、 -ownership 和生命周期治理;GUI、Headless CLI、ACP、SDK Host、Server/Remote 仍没有 Shared consumer。该图中的多入口逻辑复用是 -当前事实,除 Shared TUI 外的跨进程 Shared deployment 仍是目标架构。 +当前 Shared TUI IPC 的身份、握手、Session/Turn、Permission/UserInput、ownership 和生命周期实现只作为 App Server +Shared conformance 的迁移证据;最终由统一 App Server 替代并删除独立 wire/server。 ### 4.3 各形态能做什么 @@ -233,7 +240,7 @@ flowchart LR API --> Runtime["Single Agent Runtime and owners"] ``` -本图只放大 SDK 特有的跨进程路径;GUI/TUI、CLI、ACP 和 Server 的同级 adapter 关系以第 4 节产品视图为准, +本图只放大 SDK 特有的跨进程路径;App Server、Headless CLI、ACP 和 Server 的同级 adapter 关系以第 4 节产品视图为准, 不在这里再次折叠或定义。 依赖约束: @@ -241,7 +248,8 @@ flowchart LR | 组件 | 必须 | 禁止 | |---|---|---| | `bitfun` CLI | 依赖共享 Runtime/Application 能力 | 依赖 SDK Host app、SDK protocol 或公开语言包 | -| GUI/TUI | 依赖共享应用用例和各自平台 adapter | 经公开 SDK 绕行 Runtime;共享 renderer/protocol | +| Rich Client GUI | 依赖 App Server typed client 和各自可信 Host | 经公开 SDK 绕行 Runtime;把平台对象或 App Server token 交给 renderer | +| Interactive TUI | 依赖 App Server typed client 和 CLI/TUI Host | 禁止经公开 SDK/SDK Host 绕行 Runtime;禁止另建 Shared TUI wire | | `bitfun-sdk-host` | 独立组装入口,选择 SDK profile | 依赖 CLI crate;成为第二个 Server 或 Runtime | | SDK Host adapter | 协议、能力协商、连接/Query 资源清理责任和 DTO 转换 | stdin/stdout 入口、Agent 业务状态、Tool/MCP 注册表 | | Python/TypeScript SDK | 管理或连接匹配 Host,提供一致公开 API | 要求用户安装 `bitfun` CLI;暴露内部 wire DTO | @@ -472,9 +480,11 @@ CLI 和 SDK 共享能力事实,但不是上下层关系: 因此: - CLI 不默认依赖 SDK Host,也不通过 SDK package 运行。 -- CLI、ACP、Desktop 与 SDK Host 只共享 Core ownership 和 Runtime 行为 owner;共享这些内部 owner 不构成产品依赖,也不新增第二种 SDK。 -- 一次性 `bitfun exec` 默认使用 Embedded Runtime;只有恢复或控制 Shared Agent Runtime 中的共享 Session 时,才使用第一方 - client adapter attach,且不经过 SDK Host。 +- Headless CLI、ACP、App Server/Desktop/TUI 与 SDK Host 只共享 Core ownership 和 Runtime 行为 owner;共享这些内部 owner 不构成产品依赖, + 也不新增第二种 SDK。SDK Host 不依赖 App Server schema 或 handler。 +- 一次性 `bitfun exec` 只使用 Direct Runtime,不作为 App Server client;当前 `--shared` 只允许交互式 TUI。 + 若未来需要非交互控制 Shared Session,必须单独版本化命令、角色、输出、退出码、取消和断线合同,不能从 + App Server 或 SDK Host 的存在推导支持。 - SDK 不解析 CLI `stream-json` 作为正式双向协议。 - 普通脚本/CI 不需要为了“架构统一”改写成 SDK;复杂生产自动化才选择 SDK。 - 两者使用共同的行为样例验证相同配置、权限和 Tool 结果,但 flags、事件格式和传输方式可以不同。 @@ -651,7 +661,7 @@ GA 必须同时满足: - TypeScript 和 Python 至少各有一个仓库外真实消费者,并通过同一 conformance suite。 - SDK/Host 安装、升级、版本不匹配、崩溃、取消和完整进程树回收通过 Windows/macOS/Linux 验证。 - Session resume/fork、structured output、usage、Tool/MCP/Permission/Hook/UserInput callback 有端到端样例。 -- CLI 与 SDK 共同 fixture 证明业务事实一致,但 CLI 仍不依赖 SDK Host。 +- Headless CLI、App Server 与 SDK 共同 fixture 证明业务事实一致,但 Headless CLI 和交互式 TUI 都不依赖 SDK Host。 - schema drift、stable/experimental、capability negotiation、错误码和兼容矩阵进入发布门禁。 - API 参考、快速开始、迁移说明、安全模型和外部 UI 参考架构完整。 @@ -660,7 +670,7 @@ GA 必须同时满足: - 不提供 Claude Agent SDK 的 import-compatible 或 source-compatible 替换包。 - 不发布多个互不兼容的“本地 SDK”“远程 SDK”“UI SDK”。 - 不让 CLI、GUI/TUI、ACP 或 Server 依赖公开 Python/TypeScript SDK 或 SDK Host。 -- 不把 `stream-json`、ACP 或 HTTP Server 全量路由冒充正式 Agent SDK。 +- 不把 App Server typed client 称为公开 Agent SDK,也不把 `stream-json`、ACP、App Server 或 HTTP Server 全量路由冒充正式 Agent SDK。 - 不发布 BitFun 第一方 React UI 作为稳定 SDK ABI。 - 不把 OpenCode/Claude/Codex 原始插件对象、Hook payload 或配置类型带入 Runtime 公共合同。 - 不在没有真实消费者、owner 和失败语义时建立通用工作流、HookBus、远程 SDK transport 或公共 Capability SDK。 diff --git a/docs/architecture/app-server-architecture-design.md b/docs/architecture/app-server-architecture-design.md new file mode 100644 index 000000000..94673e80f --- /dev/null +++ b/docs/architecture/app-server-architecture-design.md @@ -0,0 +1,546 @@ +# BitFun App Server 架构设计 + +本文定义 BitFun 面向第一方 Rich Client 的统一后端协议边界。它服务于 Desktop GUI、 +Electron、VS Code Extension、Web UI、交互式 TUI 和未来其他交互式客户端,使前端框架可以替换、前后端 +可以独立演进,同时保持产品逻辑、状态所有权和平台能力边界不变。 + +本文是 [`product-architecture.md`](product-architecture.md) 的专题展开;Agent Runtime 的 +Direct Runtime、Embedded App Server 与 Shared App Server 所有权和进程约束以 +[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md) 为准;公开 Agent SDK +与 SDK Host 的独立产品合同以 +[`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md) 为准。发生冲突时以上位 +文档为准。 + +> **规范范围**:第 3-7、9-10 节描述尚未实现的目标架构,不是当前仓库状态。当前生产路径和 +> 迁移退出条件集中在第 8 节;在对应纵向切片完成验收前,Tauri command、legacy in-process TUI 和 +> `agent-runtime-ipc` Shared TUI 仍是有效生产边界。 + +## 1. 决策摘要 + +BitFun 采用 **Rich Client App Server + 两种部署形态**: + +1. Tauri Desktop、Electron、VS Code Extension、Web UI、交互式 TUI 和未来第一方 Rich Client 共享一份 + 版本化 App Server 协议和生成的 typed client。 +2. App Server 是协议组合与交付边界,不是 Session、Permission、Git、MCP、Config、 + Workspace 等领域行为的 owner。权威 DTO、策略和状态继续位于 Runtime API、 + `contracts/*` 与对应能力归属模块。 +3. App Server 只定义 **Embedded** 与 **Shared** 两种部署形态。Embedded 是一个 Client 独占一个 + App Server;Shared 是同一种 `client_kind` 的多个 Client 连接一个 App Server。两种形态不改变 + schema、handler、错误、事件或业务语义。 +4. Headless CLI/CI 默认保留 Direct Runtime;公开 SDK 保留独立 SDK Host 合同;ACP + 保留 ACP 协议 adapter;它们不为了界面协议统一而依赖 App Server。 +5. Tauri、Electron、VS Code 等 Host 保留窗口、菜单、剪贴板、文件选择、终端界面、截图和 + Computer Use 等界面宿主职责。PTY、Shell、命令执行与进程生命周期属于目标 workspace 的 + Runtime Services,不是 Host reverse request。 +6. Shared Agent Runtime 是 App Server 的一种目标部署模式,不是第二套 server。Controller、Observer、取消、 + 背压、重放、公平调度和 Runtime-aware drain 属于统一 App Server 合同的多客户端部分。 +7. App Server 使用唯一的独立后端 profile `AppServer`。运行位置、网络暴露、tenant、数据与 execution + domain 通过组装输入和安全策略收窄能力,不形成第三种部署形态;当前代码尚未提供该 profile,不能用 + Desktop、CLI、Server 或 Web profile 代替。 +8. 每个 App Server instance 固定一个产品身份、`client_kind`、数据命名空间、release channel、安全域与后端 profile。 + Client 只能协商自身展示能力与 Host capability,不能通过握手改变 Server 的产品策略或能力上限。 +9. Browser Web UI 的 Web Backend 按场景承载 Embedded 或 Web-only Shared App Server。服务端运行必须增加 + 网络认证、租户隔离、方法 allowlist、数据与 execution domain 约束,但不得因此命名为 Hosted 第三形态。 + +一句话定义: + +> BitFun App Server 是第一方 Rich Client(包括交互式 TUI)面向同一 Agent Runtime 和产品能力的版本化 +> JSON-RPC 协议 adapter;它不是新的 Runtime、公共 Agent SDK、通用 Remote API,也不是 +> 所有产品入口必须经过的内部总线。 + +## 2. 背景与目标 + +### 2.1 要解决的问题 + +当前 Desktop 前端通过大量 Tauri commands 和事件消费后端能力。即使 command 后面的 +产品逻辑已经平台无关,前端仍了解 Tauri invoke、事件命名和宿主 DTO。直接替换为 +Electron 或新增 VS Code Extension 时,需要重新建立一套 Electron IPC 或 Extension Host +消息层,并容易复制服务调度、错误映射和事件投影。 + +Rich Client App Server 解决以下问题: + +- 前端不依赖 Tauri、Rust 内部类型或 `bitfun-core` 句柄; +- Tauri、Electron、VS Code 和 Web 复用相同的产品操作与事件协议; +- Rust schema 生成 TypeScript client/type,减少手写 DTO 漂移; +- 后端可独立启动、测试、诊断和演进; +- 同一业务行为只由既有 owner 实现一次,各 Host 只保留平台适配。 + +### 2.2 设计目标 + +1. **可替换前端**:替换 Tauri 为 Electron 或增加 VS Code Extension 时,不复制 Runtime、 + Session、Permission、Git、MCP、Config 或 Workspace 行为。 +2. **明确的实例关系**:Embedded 保持一对一生命周期,Shared 提供同类 Client 的多连接与独立恢复。 +3. **一份 Rich Client wire**:Rich Client 共享 JSON-RPC method、错误、事件和版本协商。 +4. **领域所有权不迁移**:App Server 映射既有 Runtime API 和能力接口,不创建第二套行为。 +5. **宿主能力显式化**:不同前端通过 capability negotiation 表达平台能力,不假设功能齐全。 +6. **远程默认关闭**:本机协议不因存在 WebSocket transport 自动成为远程或公网 API。 + +### 2.3 非目标 + +- 不把所有 Tauri command 原样转换为 JSON-RPC method; +- 不让 Headless CLI、CI、ACP 或 SDK Host 强制绕行 App Server;交互式 TUI 不属于该例外; +- 不用 App Server schema 取代 `contracts/*` 或领域 owner; +- 不把公开 SDK API 设计成 App Server 全量路由镜像; +- 不另建 Shared TUI wire、Shared GUI wire 或按客户端类型分叉的 App Server schema;Shared 实例仍按 + `client_kind` 隔离,不能用统一 schema 推导跨类型混连; +- 不保留 `Per-Client Managed` 或 `Hosted App Server` 作为第三种部署形态; +- 不以 App Server 的本机共享部署宣称已经支持 Remote 或公网协议; +- 不把 Tauri/Electron/VS Code 的 renderer、主题、快捷键或窗口状态放入协议; +- 不让浏览器 renderer、Electron renderer 或 VS Code Webview 持有本机启动令牌和系统凭据。 + +## 3. 逻辑架构 + +### 3.1 总体视图 + +```mermaid +flowchart TB + subgraph RichClients["First-party Rich Clients"] + Tauri["Tauri Desktop"] + Electron["Electron Desktop"] + VSCode["VS Code Extension"] + Web["Web UI"] + TUI["Interactive TUI"] + end + + subgraph TrustedHosts["Trusted Client Hosts"] + TauriHost["Tauri Host"] + ElectronHost["Electron Main"] + VSCodeHost["Extension Host"] + WebBackend["Authenticated Web Backend"] + TUIHost["CLI/TUI Host"] + end + + subgraph AppServer["App Server protocol adapter"] + Schema["Versioned JSON-RPC schema"] + Client["Generated / typed clients"] + Handler["Request, event and host-capability mapping"] + end + + RuntimeAPI["Agent Runtime API and capability interfaces"] + Owners["Session / Permission / Git / MCP / Config / Workspace owners"] + Platform["OS and host capabilities"] + + Tauri --> TauriHost + Electron --> ElectronHost + VSCode --> VSCodeHost + Web --> WebBackend + TUI --> TUIHost + TrustedHosts --> Client + Client --> Schema --> Handler + Handler --> RuntimeAPI --> Owners + Handler -. "negotiated reverse request" .-> TrustedHosts + TrustedHosts --> Platform +``` + +Rich Client 共享的是协议和 typed client。Tauri Host、Electron Main、VS Code Extension +Host、Web Backend 与 CLI/TUI Host 仍是不同的可信边界,负责启动、认证、连接和平台能力。Renderer 或 +Webview 不直接管理 App Server 实例,也不直接持有认证材料。 + +### 3.2 所有权边界 + +| 边界 | 拥有 | 不拥有 | +|---|---|---| +| 领域 owner / Runtime API | 业务 DTO、校验、状态、权限、取消、审计和持久化语义 | JSON-RPC method、连接、窗口或 WebSocket | +| App Server schema | method 名、wire 投影、错误信封、通知、协议版本和 capability negotiation | 领域状态、产品策略、具体 OS 服务和公开 SDK API | +| App Server handler | 调用上下文校验、DTO 映射、deadline/cancel 转换、事件过滤和反向请求协调 | 重复业务校验、第二份权威状态和平台句柄 | +| Client Host | App Server 生命周期、认证材料、renderer 隔离和平台 capability | Agent Session/Permission 权威状态 | +| Rich Client UI | 渲染、交互状态和产品工作流 | Runtime 句柄、凭据、进程生命周期和协议 owner | + +`schema.rs` 可以是 **Rich Client JSON-RPC schema** 的单一来源,但不是全部后端领域契约 +的单一来源。Schema 应引用、包装或生成自稳定领域 DTO;只有 wire 特有字段,例如 +`request_id`、`operation_id`、协议版本和客户端 capability,才由 App Server 定义。 + +### 3.3 与其他入口的关系 + +```mermaid +flowchart LR + Rich["Tauri / Electron / VS Code / Web / Interactive TUI"] --> App["App Server adapter"] + Headless["Headless CLI / CI"] --> CLIAdapter["CLI adapter"] + ACP["ACP client"] --> ACPAdapter["ACP adapter"] + SDK["Public Agent SDK"] --> SDKHost["SDK Host adapter"] + + App --> API["Agent Runtime API"] + CLIAdapter --> API + ACPAdapter --> API + SDKHost --> API +``` + +- Rich Client(包括交互式 TUI)经 App Server 共享 wire; +- Headless CLI/CI 继续进程内强类型调用,以保留启动成本、确定性退出和故障隔离; +- ACP 和 SDK Host 映射各自独立、版本化的外部合同;它们可以共享领域 DTO 和行为 fixture, + 但不依赖 App Server handler 或 Rich Client wire。 + +## 4. 协议设计 + +### 4.1 JSON-RPC 与版本 + +协议使用正规 JSON-RPC 2.0。方法采用 `domain/verb` 命名,例如 +`session/create`、`turn/submit` 和 `git/getStatus`。协议分为三层版本事实: + +1. **App Server protocol range**:method、wire DTO、错误、事件和 capability; +2. **Runtime capability version**:Session、Tool、Permission 等业务语义; +3. **Client release version**:Tauri/Electron/VS Code/Web 自身版本。 + +初始化必须在任何业务请求前完成: + +```json +{ + "jsonrpc": "2.0", + "id": 1, + "method": "initialize", + "params": { + "instanceIdentity": "opaque-instance-id", + "deployment": "shared", + "authentication": { "scheme": "localBearer", "credential": "" }, + "client": { + "id": "opaque-client-id", + "kind": "vscode", + "version": "1.2.0" + }, + "protocol": { "min": 1, "max": 1 }, + "capabilities": { + "filePicker": true, + "clipboard": true, + "terminalPresentation": true, + "desktopCapture": false + } + } +} +``` + +Server 返回选定版本、固定的 deployment/client kind、Runtime capability、Host requirement、消息大小和并发上限。未知 +字段、未知 method 和不兼容版本按稳定规则 fail closed;stable 与 experimental method +必须显式分层,不能仅靠文档约定。 + +本机认证合同: + +- Embedded 凭据由唯一可信 Host 在创建实例时直接注入,不发布 discovery record,也不接受第二个 + client identity;Shared token、instance identity 与固定 `client_kind` 由私有 discovery record 提供。凭据只对一个 instance、用户安全域、 + protocol range 和有限有效期有效,不进入 renderer、命令行、URL、日志或普通事件; +- Server 依次校验 frame/JSON 结构、initialize-first、instance identity、凭据、client identity、 + deployment、`client_kind` 和 protocol range,最后才分配业务队列、attachment 或 Runtime context; + Embedded 对第二个 Client fail closed,Shared 对不同 `client_kind` fail closed;失败不能泄露哪一项实例事实匹配; +- Host 重启、显式登出、权限或安全域变化时轮换并撤销旧凭据。Shared discovery 只有 owner 可以替换或清理, + 旧 instance 必须拒绝新凭据,新的 instance 必须拒绝旧凭据; +- 未认证连接也计入很小的连接与握手 budget。连续失败按 endpoint/OS peer 限速并在上限后关闭, + 但日志只记录脱敏原因码;错误 token、错误 instance、过期/撤销 token 和重复失败是协议必测项; +- 经网络暴露的 Embedded 或 Shared App Server 由 Web Backend 校验用户、tenant、workspace 和 method + scope,再向 App Server 注入不可由浏览器覆盖的认证上下文;网络认证是正交安全层,不新增部署形态。 + +### 4.2 消息方向 + +| 方向 | 类型 | 示例 | +|---|---|---| +| Client -> Server | Request | Session、Turn、Git、Config 查询或操作 | +| Server -> Client | Response | 类型化结果或稳定错误信封 | +| Server -> Client | Notification | Agent 事件、状态失效、诊断和 capability 变化 | +| Server -> Client | Reverse request | 文件选择、用户输入、宿主确认、终端界面展示等已协商能力 | +| Client -> Server | Reverse response | Host capability 的结果、拒绝或取消 | + +Permission owner 保留最终决定权。GUI 点击、SDK callback 或 Host reverse response 都只是 +输入,不能直接改写权限状态或扩大产品/组织策略。 + +### 4.3 错误和副作用 + +稳定错误至少包含: + +- `code`、`stage`、`retryable`、`message`; +- `operation_id` 和可选 `session_id` / `turn_id`; +- `action_required` 或类型化 `unsupported` 原因; +- 对已发送但结果未知的副作用返回 `outcome_unknown`。 + +创建、删除、重命名、配置写入、Git 写操作和 Turn 提交不得在响应丢失后自动重试。 +客户端必须通过幂等 operation ID 或重新读取权威状态后再决定下一步。 + +### 4.4 事件、取消与背压 + +- 请求有 deadline,取消沿 Runtime 既有取消树传播;断开连接不自动等于删除 Session; +- request、response、notification 和 reverse request 队列必须有界; +- `Lagged` 或 `Closed` 是显式状态失效,不能伪装成透明恢复; +- 在事件 cursor/replay 交付前,重连只能重新查询权威快照,不能声称无缝续流; +- 事件按连接身份、Session attachment 和方法 capability 过滤; +- 多客户端共享前必须定义 Controller、Observer、审批竞争和 controller transfer。 + +现有 Shared TUI IPC 的 controller lease、断连取消、有界 framing 和 `outcome_unknown` +语义必须迁入统一 App Server 合同。迁移完成后删除旧 wire/server,不保留两套长期协议。 + +## 5. Transport 与部署 + +### 5.1 Transport 选择 + +Transport 由可信 Host 选择,schema 不感知具体实现: + +| 场景 | Transport | 约束 | +|---|---|---| +| 测试和迁移 | in-memory pair | 使用相同 handler;不作为进程分离证明 | +| Embedded App Server | in-process channel、私有 stdio 或私有 Pipe/UDS | 一个 Client 独占一个 Server;无 discovery,拒绝第二连接 | +| 本机 Shared App Server | Windows Named Pipe / Unix Domain Socket | 私有 endpoint、认证握手、有界 framing、固定 `client_kind` | +| 服务端 Embedded/Shared | authenticated WebSocket/HTTPS | 独立网络认证、授权、Origin/CORS、租户与方法 allowlist | +| 远程 Rich Client | 暂不默认支持 | 必须经过 Server/Remote 安全设计评审 | + +Transport adapter 位于 adapters 层;App Server interface 只依赖抽象连接和类型化消息。 +不得因为实现了 WebSocket helper 就自动暴露完整本机 schema。 + +### 5.2 两种目标拓扑 + +```mermaid +flowchart LR + Client["One Rich Client"] --> Host["Trusted Client Host"] + Host --> Choice{"deployment selection"} + Choice -->|"Embedded"| Embedded["Exclusive Embedded App Server"] + SameKind["Clients of one client_kind"] --> Shared["Shared App Server"] + Choice -->|"Shared"| Shared + Embedded --> Runtime["Agent Runtime + assembled services"] + Shared --> Runtime2["Agent Runtime + assembled services"] + Runtime --> Data["Workspace and Session storage"] + Runtime2 --> Data +``` + +`Embedded` 和 `Shared` 使用同一个 App Server schema、handler 和 conformance suite: + +| 模式 | 实例关系 | 适用场景 | +|---|---|---| +| Embedded | 一个 Client 独占一个 App Server 实例 | 默认单 Client 工作流、由 Client Host 私有创建和管理 | +| Shared | 同一种 `client_kind` 的多个 Client 连接一个 App Server 实例 | 多个 TUI、Tauri Desktop、Electron Desktop、VS Code 或 Web 同类 Client 的协作与连续运行 | + +部署选择只决定承载方式、discovery、连接数量和 drain 条件。不得按模式复制 method、handler、 +领域 DTO 或 Runtime owner。Shared 模式必须完成 Controller/Observer、事件恢复、公平调度、审批竞争和 +Runtime-aware drain;Embedded 使用同一逻辑协议合同,只可因单连接事实简化运行时状态。 + +不同 `client_kind` 不得连接同一 Shared instance。例如 TUI、Desktop、VS Code 和 Web 必须分别发现或创建 +自己的 Shared instance;跨形态接力通过持久化 Session、显式 handoff 或其他领域合同完成,不通过混连同一 Server。 +Browser Web UI 也只在 Embedded/Web-only Shared 两种形态中选择,本机超集不能因 wire 相同而自动发布到网络。 + +### 5.3 生命周期与身份 + +- Host 使用产品身份、数据命名空间、release channel、当前用户和协议范围定位兼容 binary 与 instance; +- 业务 payload 前必须完成双向版本校验和本机认证;token 不进入日志、URL 或 renderer; +- Host 负责选择 Embedded/Shared、创建或发现实例、健康检查、崩溃提示和有界重启,Runtime 负责 Session/Turn 生命周期; +- Embedded 的身份和生命周期绑定唯一 Client Host,可同进程或私有子进程承载;Shared 使用独立 idle policy; +- 服务端 orchestrator 可以创建 Embedded 或 Shared 实例并绑定 tenant、数据与 execution domain;浏览器身份不能选择或覆盖这些实例事实; +- App Server 退出必须执行 Runtime-aware drain,不能只按连接计数推导; +- workspace ownership 和 Session 单写继续使用现有 Core owner,不进入普通 wire; +- Remote workspace 的文件、进程、凭据和 Runtime 必须位于目标 execution domain,禁止 + 静默回落本机。 + +### 5.4 产品组装与共享兼容性 + +App Server 是后端产品组装根。目标产品能力系统增加唯一的 `AppServer` profile,不得由现有 `Desktop`、 +`Cli`、`Server` 或 `Web` profile 拼接冒充。具体运行环境再通过受信组装输入选择本机或 tenant-scoped provider; +服务端环境默认不包含用户机器的 filesystem、process、credential、Computer Use 或本机 plugin runtime。 +这些 capability 与安全差异不改变 Embedded/Shared 两种实例关系。 + +实例启动时消费唯一后端 profile、已验证的产品组装结果和 Runtime Configuration,之后这些实例级事实不可由 +任一 Client 改写。Desktop、TUI、VS Code 和 Web 的宿主形态只影响前端布局、renderer 生命周期和可提供的 +Host capability,不形成不同的领域语义。 + +`client_kind` 标识具体宿主形态,而不是宽泛界面类别。至少区分 `tauri-desktop`、`electron-desktop`、 +`vscode`、`tui` 和 `web`;只有值完全相同的 Client 才能连接同一 Shared instance。新增 Client 形态必须 +分配新值并独立验证,不得仅因复用 Desktop 布局或 App Server schema 就沿用其他形态的值。 + +Shared discovery key 至少包含产品身份、`client_kind`、数据命名空间、用户/组织安全域、release channel、协议兼容范围和 execution +domain。只有这些事实兼容且 `client_kind` 完全相同的 Client 才能连接同一 Shared instance。不同客户端形态、品牌、数据隔离域、组织策略或不兼容 release +channel 必须使用不同实例;禁止先连接再通过 Client 参数切换 Server identity、插件策略、权限上限或持久化根。 + +连接握手可以协商 Client 类型、release version、语言、展示 capability、Host capability,以及 Server 已组装能力的 +只读可用性和类型化降级原因。它不能协商产品身份、数据根、组织安全策略、内置扩展集合或 Server capability 上限; +这些都是实例创建事实。 + +method/capability 的可用性由三个独立集合共同收窄,不能只靠 UI 隐藏或单层 capability negotiation: + +1. **Backend assembly**:该 `AppServer` profile 与运行环境实际装配的 Runtime 和 service capabilities; +2. **Host capabilities**:仅当 operation 需要 reverse request 时,当前认证 Client 可提供的文件选择、 + 剪贴板、窗口、终端展示等反向能力; +3. **Connection method allowlist**:当前身份、tenant/workspace scope 和协议版本允许调用的方法。 + +这三个集合不是完整授权公式。每次 operation 仍必须由 Server 解析且 Client 不可覆盖的 identity、tenant、 +workspace/resource ownership 和 operation scope 建立授权上下文,再交给 Runtime Permission owner、组织/用户 +策略与 operation-specific policy 作最终裁决并记录审计。已装配且在 method allowlist 中,只表示请求可以进入 +该裁决流程,不表示请求已经获准;不需要 reverse request 的普通 Runtime method 也不受 Host capability +可用性虚假限制。 + +本机与服务端运行环境至少各有 allow/deny fixture;服务端必须证明未装配或拒绝本机文件、进程、凭据、原生插件 +和 Computer Use 能力,本机也不能因 Host 声明某能力就绕过 backend plan 或 connection allowlist。 + +## 6. 平台能力边界 + +现有 Desktop commands 需要按所有权分类,而不是机械迁移: + +| 类型 | 处理方式 | +|---|---| +| Session、Turn、Permission、Git、MCP、Config、Workspace 等产品能力 | 通过 App Server 映射既有 Runtime/能力接口 | +| 窗口、托盘、菜单、更新、原生对话框 | 留在 Tauri/Electron/VS Code Host | +| 文件选择、剪贴板、终端窗口打开/聚焦/展示、截图、Computer Use 界面操作 | 经协商后的 Host capability/reverse request | +| PTY、Shell、命令执行、子进程、取消和回收 | 由 workspace execution domain 中的 Runtime Services 执行;不发送回 Client Host | +| 只适用于特定 Host 的能力 | 返回类型化 `unsupported`,UI 据此隐藏或禁用 | + +Host capability 必须声明输入、结果、权限、deadline、取消和失效语义。App Server 不得 +直接持有 `tauri::AppHandle`、Electron 对象、VS Code API 对象或原始 OS 窗口句柄。 +命令请求必须携带由 Server 解析且 Client 不可覆盖的 workspace/execution-domain identity,并沿该域的 +权限、审计、取消和资源预算执行。远程 workspace 缺少目标 terminal provider 时返回 `unsupported`,禁止 +回落到运行 GUI/TUI 的控制端机器。 + +## 7. 模块与依赖 + +目标代码组织: + +```text +src/crates/interfaces/app-server + Rich Client schema、typed Rust client、抽象 handler contract、版本与 capability negotiation + +src/crates/adapters/app-server-transport + in-memory、stdio、Named Pipe、UDS、WebSocket transport adapter + +src/apps/app-server + Shared App Server 独立进程入口、产品组装、生命周期、日志与诊断 + +src/apps/desktop + Tauri Host、Embedded App Server 私有承载、同类 Shared discovery、Desktop capabilities + +src/apps/server + 服务端 Embedded/Web-only Shared App Server 承载、WebSocket/HTTP 暴露、网络认证、租户/远程策略和 capability allowlist + +src/crates/contracts/* + 领域 DTO、事件事实、稳定错误与 Runtime ports +``` + +依赖方向: + +```mermaid +flowchart TB + Hosts["apps/desktop · apps/server · apps/app-server"] --> Interface["interfaces/app-server"] + Hosts --> Transport["adapters/app-server-transport"] + Interface --> Contracts["contracts"] + Transport --> Contracts + AppRoots["apps/app-server · apps/server"] --> Assembly["assembly / Runtime API"] + AppRoots --> Interface + Assembly --> Execution["execution"] + Assembly --> Services["services"] + Execution --> Contracts + Services --> Contracts +``` + +约束: + +- App Server interface 不依赖 `src/apps/*`; +- App Server interface 只通过 `contracts` 中的稳定 DTO/ports 描述 handler contract,不依赖具体 + Assembly、Runtime 或 service 实现; +- transport adapter 不依赖 `bitfun-core`、Tauri、SDK Host 或 Runtime 实现; +- Embedded Client Host、`apps/app-server` Shared 入口与服务端 `apps/server` 组装根把 Assembly/Runtime API provider + 注入 handler contract; + 具体 handler wiring 不进入客户端共享的 interface crate,也不直接构造 OS service; +- `interfaces/sdk-host` 继续保持独立,不依赖 App Server 或 `bitfun-core`; +- ACP adapter 不经 App Server 做 ACP -> JSON-RPC -> Runtime 的双重协议转换; +- Web 生成类型只暴露该 Host allowlist 中真实可用的 method,不把本机超集自动发布到网络。 + +## 8. 非规范迁移说明 + +### 8.1 迁移来源 + +| 范围 | 当前状态 | +|---|---| +| Desktop | Tauri command/event adapter 直接消费 Core/Runtime 能力 | +| Server Host | Health、Info 与 SSH-backed detached dispatch controller/observer 外壳;不启动 Agent Runtime | +| Server WebSocket | 当前仅绑定 loopback,无连接认证;只有请求携带 `Origin` 时才校验 allowlist,缺失 `Origin` 会放行。既有 `type=request/response/event` 私有信封暴露 install、submit、cancel、answer、append 等可变 dispatch,不是正规 JSON-RPC 2.0 | +| App Server crate/process | 尚未创建 | +| Shared TUI | 当前私有 IPC 是迁移来源;目标改为 App Server Shared deployment 并删除独立 wire/server | +| Headless CLI / CI | Direct Runtime;当前明确拒绝非交互 `--shared`,本迁移不改变该合同 | +| Runtime ownership | 当前 Shared owner 绑定单一 workspace;目标多 workspace registry 尚未实现 | +| Product capabilities | 当前没有 App Server backend profile;Desktop/CLI/Server/Web profile 不能代替 | +| ACP / SDK Host | 各自协议 adapter 与生命周期保持独立 | + +迁移映射与退出条件: + +| 当前模块/合同 | 目标位置 | 退出或调整条件 | +|---|---|---| +| Tauri business command/event | App Server method/event 或保留为 Host-only command | 对应纵向切片行为等价、Remote/network policy 明确、Desktop dogfood 与有界回滚通过 | +| `agent-runtime-ipc` operation/handler/server | App Server schema/handler | TUI 改用 typed client,controller/cancel/backpressure/`outcome_unknown` fixture 全部通过 | +| Named Pipe/UDS、discovery、framing | `app-server-transport` 内部原语 | 证明协议中立;保留认证、frame、queue、deadline 和 cleanup 限制或记录经测量的变更 | +| 单 workspace Shared ownership | App Server Runtime context registry + per-workspace `CoreRuntimeOwnership` | 第二 workspace、并发 attach、Remote、冲突、断连回收和重启恢复测试通过 | +| Desktop/CLI capability profile | 唯一 `AppServer` backend profile + 环境安全策略 | 本机/服务端 allow/deny、tenant/data/execution-domain 隔离通过,禁止用旧 profile 临时代替 | +| 既有 Server WebSocket envelope | allowlisted App Server network exposure,或保留独立 Server/Remote wire | 网络认证、Origin/CORS、tenant/workspace scope 和方法 allowlist 通过;不得直接发布本机超集 | + +当前 Server WebSocket 的安全边界是 loopback bind,而不是连接认证或只读 Observer。它会使用 Server Host +已加载的 SSH connection 执行可变 detached dispatch;在 OS peer/身份认证、workspace/target scope、方法 +allowlist 和拒绝测试完成前,不得放宽 loopback bind,也不得把该 envelope 复用为网络 App Server +或远程入口。 + +在最后一个旧 consumer 退出前,`agent-runtime-ipc` 继续遵守其局部 `AGENTS.md` 中的完整当前生产 +合同。迁移不得以“旧协议最终会删除”为由提前放宽认证、大小、连接、operation、idle 或 cleanup 限制。 + +### 8.2 迁移阶段 + +#### 阶段 A:合同归属与首个纵向切片 + +1. 选择 Session create/list/restore、Turn submit/cancel、事件和 Permission 作为首个完整旅程; +2. 将共享业务 DTO 和错误放入现有 contracts/Runtime owner,而不是 App Server 私有 DTO; +3. 建立 schema codegen、drift check、stable/experimental 和 capability negotiation; +4. 使用 in-memory pair 完成 handler/typed client 行为 fixture; +5. 保留既有 Tauri 路径作为兼容回退,证明结果和副作用等价。 + +#### 阶段 B:Desktop dogfood + +1. Desktop 的目标纵向切片改用 AppServerClient; +2. 窗口和平台 command 保留在 Tauri Host; +3. Permission/UserInput 与文件选择建立 reverse request; +4. 测量启动、首 token、事件吞吐、内存和取消延迟; +5. 达到行为与性能门槛后逐域迁移,不按 command 数量批量搬运。 + +#### 阶段 C:Embedded 承载 + +1. 增加可嵌入的 App Server 组装入口与私有 transport; +2. 实现版本匹配、唯一 Client 身份、drain 和崩溃恢复; +3. Desktop 使用一个 Client 对一个 Embedded App Server; +4. 删除对应旧 Tauri 业务桥前,保留端到端兼容测试和回滚开关。 + +#### 阶段 D:交互式 TUI 收敛 + +1. CLI/TUI Host 使用与 Desktop 相同的 AppServerClient 和本机 transport; +2. 默认交互式 TUI 使用独占 Embedded 实例,`--shared` 连接 TUI-only Shared 实例; +3. 将当前 Shared TUI 的 controller lease、取消、背压、`outcome_unknown` 和 idle cleanup 合同迁入 App Server; +4. 使用同一 fixture 验证旧 Shared TUI 与 App Server Shared 模式行为等价; +5. 删除 `agent-runtime-ipc` 的独立 operation、framing、server 和 discovery 实现,或将真正通用的本机原语下沉为 + App Server transport 内部实现,不保留第二套协议入口。 + +#### 阶段 E:新增 Rich Client + +1. Electron Main 或 VS Code Extension Host 创建匹配 Embedded App Server,或发现完全相同 `client_kind` 的 Shared instance; +2. Renderer/Webview 复用生成的 client API,但只经可信 Host 访问; +3. 每个新 Host 提交 capability、权限、生命周期、安装升级和远程 workspace 验证; +4. Web 接入另行完成网络认证与方法 allowlist,不能复用本机信任假设;每种新 Client 只能连接自身 + `client_kind` 的 Shared instance。 + +#### 阶段 F:同形态 Shared Rich Client + +分别为 TUI、Desktop、VS Code 和 Web 验证 Shared 模式。同一 Shared App Server 只接受一个固定 +`client_kind`;不同形态即使协议兼容也必须使用不同实例。每种 Shared 形态都必须完成 Controller/Observer、 +事件恢复、公平调度、Runtime-aware drain、Host capability 路由和客户端身份审计。 + +## 9. 验收门槛 + +每个迁移切片至少证明: + +1. Runtime/领域 owner 未迁移,旧入口和 App Server 路径共享行为 fixture; +2. schema 生成可重复,Rust/TypeScript drift check 通过; +3. 请求、响应、事件和 reverse request 都有大小、队列、deadline 和取消上限; +4. 副作用具有 operation ID、明确失败与 `outcome_unknown` 语义; +5. Host capability 缺失返回类型化 `unsupported`,不静默调用本机替代能力; +6. 本机认证材料不进入 renderer、URL、日志、Session transcript 或普通事件; +7. 服务端 Embedded/Shared 覆盖网络认证、tenant/data 隔离、方法 allowlist、跨租户拒绝和 Runtime-aware drain; +8. Remote workspace 行为在目标 execution domain 验证; +9. Desktop 与交互式 TUI 至少覆盖启动、Session 恢复、Turn、Permission/UserInput、取消、重连和退出; +10. 性能基线覆盖冷启动、首 token、流式事件吞吐、CPU、内存和大 transcript; +11. 删除旧 adapter 前有兼容期限、回滚方式和生产 consumer 证据。 + +## 10. 不变量 + +- 只有一套 Agent Runtime 行为 owner; +- App Server 不拥有 Session、Tool、MCP、Permission、Hook、Event、Git 或 Workspace 状态; +- Rich Client 只有一套 App Server wire;App Server 只存在 Embedded 与 Shared 两种部署形态,不得分叉协议或业务 handler; +- Embedded 恰好一个 Client 对一个 Server;Shared 多个 Client 对一个 Server,但一个实例只接受一种 `client_kind`; +- SDK Host wire 和 ACP wire 与 App Server 合同独立;Headless CLI/CI 是 Direct Runtime 调用而不是 App Server Embedded; +- Headless CLI/CI 不因 GUI 解耦增加后台进程或序列化成本; +- 平台能力留在真实 Host,凭据和执行发生在正确 execution domain; +- 未经过认证、授权和远程策略评审的本机 method 不暴露到 WebSocket/HTTP; +- 多客户端共享必须在统一 App Server 合同中交付 Controller、背压、恢复和生命周期语义; +- 未有真实 consumer 的 method、transport 或 capability 不进入稳定协议。 diff --git a/docs/architecture/cli-product-line-design.md b/docs/architecture/cli-product-line-design.md index 2ad4496d3..10771773d 100644 --- a/docs/architecture/cli-product-line-design.md +++ b/docs/architecture/cli-product-line-design.md @@ -11,8 +11,9 @@ CLI/TUI 的目标、问题和风险规约见 [`platform-portability-design.md`]( CLI 产品入口、配置兼容、TUI 布局消费和 CLI Agent 体验,不重复定义这些文档中的通用契约或内部 ABI。公开 BitFun Agent SDK 与 Headless CLI 的产品选择、能力一致性和 SDK Host 边界见 [`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md);多个 GUI/TUI/Remote/CLI 实例并存时,交互式 TUI -连接 Shared Agent Runtime、一次性 CLI 保留 Embedded 的部署边界见 -[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md)。 +经 App Server 使用 Embedded/TUI-only Shared、一次性 CLI 保留 Direct Runtime 的部署边界见 +[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md);统一 Rich Client wire 见 +[`app-server-architecture-design.md`](app-server-architecture-design.md)。 OpenCode 的完整扩展矩阵、配置资产、插件执行和 TUI Plugin 映射分别见 [`opencode-extension-compatibility.md`](extensions/opencode-extension-compatibility.md)、 [`opencode-config-assets-adapter-design.md`](extensions/opencode-config-assets-adapter-design.md)、 @@ -252,18 +253,25 @@ Headless CLI 和公开 Agent SDK 都调用同一 Agent Runtime API,但交付 - 两者的能力对照、共同 fixture 和等价门槛以 [Agent SDK 产品与宿主架构第 9 节](agent-sdk-product-architecture.md#9-headless-cli-与-agent-sdk)为唯一事实源。 -交互式 TUI 另有一个显式部署选项:`bitfun --shared` 或 `bitfun chat --shared`。它通过 CLI 私有本机 IPC adapter 连接同一 Agent Runtime,不经过 SDK Host,也不改变 Headless CLI 或公开 SDK 的协议。当前范围如下: +交互式 TUI 是 Rich Client App Server consumer,不经过 SDK Host。默认创建一个 Client 独占的 Embedded App Server; +`bitfun --shared` 或 `bitfun chat --shared` 连接 TUI-only Shared App Server。两种部署使用相同 schema、typed client、handler、 +错误和事件,只改变 instance discovery、连接和生命周期;Headless CLI 与公开 SDK 的协议不变。 -| 形态 | 默认部署 | 当前 Shared 范围 | +| 形态 | 默认部署 | 可选部署 | |---|---|---| -| 交互式 TUI | Embedded | 显式 `--shared` 后支持 Session list/create/restore、transcript、当前 Session rename/Agent mode/model、Turn submit/cancel、Permission 和 UserInput | -| `bitfun exec` / CI | Embedded | 不接受 Shared;保持独立进程、stdout/stderr 和退出码语义 | -| ACP / SDK Host / GUI / Remote / Peer | 各自既有部署 | 不消费 TUI IPC,也不因本开关改变生命周期 | - -Shared TUI 不提供 Session delete/fork、模型目录/默认值、Agent/Subagent 管理、MCP/扩展、账号同步、用量、observer、replay 或 controller transfer;对应入口给出明确的 Embedded 恢复建议,不在 Client 进程初始化第二套 Core owner。 -Shared 模式的斜杠命令、快捷键帮助和底部提示使用同一能力投影:`/rename ` 修改当前 Session 名称;`/agent`、Tab 和 Shift+Tab 只切换当前 Session 的 Agent mode;`/models` 只切换当前 Session 的 model。Embedded 与 Shared 的 `/help` 都从 Action Registry 展示 `/rename `;在 slash menu 中选择它只预填命令并等待用户输入名称。若外部来源使用相同命令名,用户明确选择的 BitFun 命令可完成这一次参数提交,即使偏好保存失败也不会重新弹出来源选择。它们不进入管理页面,也不修改未来 Session 的默认值。其他不支持动作不显示为可执行入口。Session 切换失败保留原控制权;单个连接已有活动 Turn 时拒绝重复提交以及 Session rename/mode/model update;事件订阅失效后当前视图立即失效并要求重启 Shared TUI。 - -部署差异由 CLI Runtime client 封装。Embedded 以 Rust 类型直接调用 `AgentRuntime`,不初始化 IPC 或执行 JSON 编解码;Shared 将同一业务请求映射为一个有界本机 frame,Client/Server 各自只编码一次,再交给同一 Runtime owner。多 TUI 复用一个 Runtime 进程,连接和队列保持有界,不按 TUI 数量复制 Session owner。详细的 4+1 视图、帧上限和并发边界见 +| 交互式 TUI | Embedded App Server | 显式 `--shared` 后连接 TUI-only Shared App Server;不与 GUI/IDE 混连 | +| `bitfun exec` / CI | Direct Runtime | 不作为 App Server client;保持独立进程、stdout/stderr 和退出码语义 | +| GUI / VS Code | Embedded App Server | 各自只能连接对应 `client_kind` 的 Shared App Server | +| ACP / SDK Host / Remote / Peer | 各自既有部署 | 不因 TUI 开关改变协议或生命周期 | + +交互式 TUI 的可用操作由统一 App Server capability negotiation 和产品能力决定,不建立 TUI-only operation budget。 +斜杠命令、快捷键帮助和底部提示消费同一 capability projection;不支持动作不显示为可执行入口。Session +切换失败保留原控制权;同一 Controller 已有活动 Turn 时按 Runtime 策略拒绝或排队冲突更新;事件流失效后使用 +App Server snapshot/cursor 恢复,无法恢复时明确使当前视图失效。 + +交互式 TUI 的部署差异由 AppServerClient 封装;Embedded 与 Shared 都执行同一 JSON-RPC contract。Headless +Direct Runtime 以 Rust 类型直接调用 `AgentRuntime`。多个 TUI 可以复用一个 TUI-only Shared App Server,连接和队列保持 +有界,不按 TUI Client 数量复制 Session owner;GUI/IDE 使用各自实例。详细的进程、并发和恢复边界见 [`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md)。 #### 管理与诊断 @@ -301,8 +309,9 @@ TUI renderer、实验性接口和完整外部 Server 协议按总矩阵明确降 | 层/模块 | 负责 | 不负责 | |---|---|---| | `src/apps/cli` | Clap 入口、TUI 状态/渲染、终端事件、入口本地设置、命令展示与结构化输出 | 会话状态机、工具执行、权限裁决、插件内部 ABI、品牌能力真值 | -| CLI Runtime client | 屏蔽 Embedded/Shared 部署差异,将 CLI 的类型化调用映射到进程内 Runtime 或私有本机 IPC | 实现 Session 业务规则、暴露公开 SDK 或在两种部署中复制行为 | -| `adapters/agent-runtime-ipc` | Shared TUI 的私有本机 transport、严格握手、frame 上限、连接控制和封闭 operation 映射 | 服务 Embedded、公开协议、Remote transport 或 Runtime 业务 owner | +| AppServerClient | 为交互式 TUI 屏蔽 Embedded/Shared 部署差异,消费统一 schema、事件、错误和 capability | 实现 Session 业务规则、依赖 SDK Host 或分叉 TUI-only wire | +| Headless Runtime client | 为 `exec`/CI 提供 Direct Runtime API | attach Shared App Server、改变 stdout/exit contract、默认启动后台进程或复制 Rich Client handler | +| `adapters/app-server-transport` | App Server 的本机/stdio/WebSocket transport、严格握手、frame 上限和连接控制 | Runtime 业务 owner、TUI-only operation 或公开 SDK API | | `assembly/product-capabilities` | Delivery Profile、Product Capability 计划、静态 eligibility、服务需求和组装计划 | 品牌资源读取、动态可用性、用户配置、UI 状态、具体服务创建 | | 产品构建期校验 | 校验产品定义、品牌资源、TUI 布局选择和内置扩展版本,输出产品组装结果 | 创建运行时服务、实现终端行为或保存用户配置 | | Product Assembly | 读取产品组装结果中本次 CLI 需要的字段,选择能力/服务/扩展,构建 Runtime Parts | 读取原始品牌资源、实现 Agent/Tool/插件适配器/终端行为或运行构建脚本 | @@ -317,20 +326,22 @@ TUI renderer、实验性接口和完整外部 Server 协议按总矩阵明确降 ```mermaid flowchart LR Exec["bitfun exec"] --> Choice{"Session"} - Choice -->|"new / free"| Embedded["Embedded"] + Choice -->|"new / free"| Direct["Direct Runtime"] Choice -->|"already owned"| Reject["typed occupied error"] TUI["bitfun chat"] --> Deploy{"deployment"} - Deploy -->|"default"| EmbeddedTui["Embedded"] - Deploy -->|"--shared"| SharedTui["private local IPC"] - SharedTui --> Runtime["one Shared Runtime owner"] + Deploy -->|"default"| Embedded["Embedded App Server"] + Deploy -->|"--shared"| Shared["TUI-only Shared App Server"] + Embedded --> Runtime1["Agent Runtime owner"] + Shared --> Runtime2["one Shared Runtime owner"] ``` -Embedded 只意味着 Runtime 与 CLI 同进程,不意味着绕过持久化单写规则。新 Session 取得自己的写入权;恢复既有 Session 时, -CLI 必须先取得该 Session 的写入权。如果 Shared Agent Runtime 或另一个 `exec` 已持有,Headless CLI 返回明确的 -“Session 已占用”;它不会自动切换部署。只有用户显式选择 `--shared` 的交互式 TUI 才连接 Shared Runtime,且同一 Session 同时只有一个 controller。 +Direct Runtime 只意味着 Runtime 与 Headless CLI 同进程,不意味着绕过持久化单写规则。新 Session 取得自己的写入权;恢复既有 Session 时, +CLI 必须先取得该 Session 的写入权。如果 Shared App Server 或另一个 `exec` 已持有,Headless CLI 返回明确的 +“Session 已占用”;它不会自动切换部署。交互式 TUI 始终使用 App Server,`--shared` 只选择 Shared instance; +同一 Session 同时只有一个 controller,但可以有多个 observer。 -CLI/TUI 的会话创建、列出、删除、恢复和历史转录读取通过 Rust Runtime SDK 的类型化端口完成;TUI 只把 +Headless CLI 的会话操作通过 Rust Runtime SDK 的类型化端口完成;交互式 TUI 通过 AppServerClient 消费同一领域事实,并只把 `SessionTranscript` 转换为本地渲染状态,不再消费 Core `Message`。Peer Host 的对话提交、精确取消、基础会话控制、thread-goal 查询、会话模型更新和 工具确认/拒绝通过 Agent Runtime API 回到 Core owner;本地会话分支通过显式本地范围的内部端口完成,携带远程身份的请求返回类型化 `NotAvailable`,本轮不扩展远程分支。TUI 用量卡片通过固定语义的完成态本地命令轮次端口持久化,不暴露通用 transcript writer。 diff --git a/docs/architecture/extensions/plugin-runtime-design.md b/docs/architecture/extensions/plugin-runtime-design.md index bcaada2a7..12e267240 100644 --- a/docs/architecture/extensions/plugin-runtime-design.md +++ b/docs/architecture/extensions/plugin-runtime-design.md @@ -77,7 +77,8 @@ flowchart TD workspace、session、插件和贡献数量都不是默认进程键。一个 Plugin Host 可以承载多个来源、多个 workspace 的逻辑实例和多个 session 的调用;这些身份必须随请求显式传递,进程内状态仍按生态的真实语义分区。 -因此 Shared Agent Runtime 中多个 GUI/TUI/Remote Client 不会各自创建 Plugin Host;一次性 Embedded CLI、私有 SDK Host 和 +因此同一 `client_kind` 的 Shared Agent Runtime 中多个 Client 不会各自创建 Plugin Host;不同 GUI/TUI/Remote +形态不连接同一个 Shared App Server。一次性 Direct Runtime CLI、私有 SDK Host 和 目标机器 Runtime 则各自只管理自己的子进程树,不跨 Rust 进程或 execution domain 共享模块实例。 容量压力本身不直接创建进程。只有测量证明单进程队列不足,并且待拆调用同时满足“无共享模块状态、无顺序 Hook diff --git a/docs/architecture/product-architecture.md b/docs/architecture/product-architecture.md index 707917bc7..e99ce1114 100644 --- a/docs/architecture/product-architecture.md +++ b/docs/architecture/product-architecture.md @@ -19,9 +19,13 @@ Headless CLI 与各产品入口的统一心智见 [`agent-sdk-product-architecture.md`](agent-sdk-product-architecture.md);多个 GUI/TUI/Remote/CLI/SDK 实例共存时的 Agent Runtime 部署、 状态共享、隔离、容量与 Plugin Host 关系见 -[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md)。详细设计与本文件冲突时,以本文件为准。 +[`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md);Tauri、Electron、VS Code Extension、Web 等第一方 +Rich Client 的统一后端协议与迁移边界见 +[`app-server-architecture-design.md`](app-server-architecture-design.md)。详细设计与本文件冲突时,以本文件为准。 -本文件只约束稳定边界,不记录单次 PR 进度,也不把未来可能支持的生态能力提前声明为公开接口。 +本文件的原则和目标视图约束稳定边界,不记录单次 PR 进度,也不把未来可能支持的生态能力提前声明为公开接口。 +为避免把设计目标误作仓库事实,第 2.2 节先给出当前 Development View,再给出明确标记的目标增量; +第 4.1 和第 6 节同样分别标注当前与目标调用链。 ## 1. 架构目标 @@ -36,8 +40,9 @@ BitFun 同时面向桌面 GUI、TUI/CLI、Web、ACP、Server、Remote、SDK 和 4. **OpenCode 是兼容目标,不是内部模型**:适配层尽量保持 OpenCode plugin、hook、custom tool、TUI plugin、 Client、配置和加载顺序的外部可观察行为,但这些类型不能反向成为 BitFun 智能体、配置或界面的内部数据模型。 5. **公开接口有预算**:新增公开 DTO、trait、模块或入口必须同时具备归属模块、真实消费方、版本策略、验证方式和删除条件。 -6. **入口形态受宿主约束**:TUI、GUI、Web、Headless CLI 和公开 SDK adapter 共享 Agent Runtime API - 用例、能力服务接口和只读视图,不共享公开语言包、传输、渲染句柄、主题键、键位模型或界面状态; +6. **入口形态受宿主约束**:各入口共享 Agent Runtime API 用例、能力服务接口和只读视图;Tauri、Electron、 + VS Code Extension 与 Web 等第一方 Rich Client 可以共享版本化 App Server wire,但不共享渲染句柄、主题键、 + 键位模型、界面状态或平台生命周期。交互式 TUI 也属于 Rich Client;Headless CLI、ACP 和公开 SDK 仍保留各自边界; 插件界面贡献必须先声明目标入口形态,再由对应宿主适配。 7. **产品定制先解析,运行时扩展后加载**:产品身份、能力上限和 GUI/TUI 布局选择在构建/组装期解析;用户配置和插件只能在该上限内扩展,不能反向改写产品事实。 8. **平台差异留在入口和具体能力实现**:target 只选择 ABI,feature 只控制确实可选的依赖;共享内核不按平台 @@ -62,8 +67,10 @@ BitFun 同时面向桌面 GUI、TUI/CLI、Web、ACP、Server、Remote、SDK 和 13. **一个 Agent Runtime,多种交付形态**:GUI、TUI、Headless CLI、公开 SDK、ACP 与 Server/Remote 都是 同一 Agent Runtime 的 adapter。Query、Session、Tool/MCP、Permission、Hook、Event/Usage 只有一个行为 归属模块;公开 SDK 不成为内部入口的依赖,ACP 和 Headless CLI 也不成为完整 SDK 的别名。目标部署中,第一方 - GUI/TUI/本机 Remote 可以共享 Agent Runtime,一次性 Headless CLI 保留 Embedded,公开 SDK 默认使用私有 SDK Host; - 这些 Rust 部署都只通过 `PluginRuntimeClient` 和 services 归属模块管理自己的 Node/Bun Plugin Host 子进程。 + Rich Client(GUI、Web、交互式 TUI)经 App Server 协议访问 Runtime,并可在相同 `client_kind` 内通过 Shared + deployment 共享 Agent Runtime;不同形态 Client 不连接同一个 Shared Server。一次性 + Headless CLI 保留 Direct Runtime,公开 SDK 默认使用私有 SDK Host;这些 Rust 部署都只通过 + `PluginRuntimeClient` 和 services 归属模块管理自己的 Node/Bun Plugin Host 子进程。 调用路径长度只作为工程成本处理,不作为独立架构目标。允许保留承担兼容隔离、只读视图或能力选择职责的中间层;不允许为了兼容而长期暴露没有消费方的抽象接口。 @@ -71,12 +78,12 @@ BitFun 同时面向桌面 GUI、TUI/CLI、Web、ACP、Server、Remote、SDK 和 4+1 视图分别描述系统职责、代码组织、运行协作、部署边界和关键场景,避免把逻辑模块、crate、进程和调用链混在同一张图中。分类沿用 [Kruchten 4+1](https://www3.software.ibm.com/ibmdl/pub/software/rational/web/whitepapers/2003/Pbk4p1.pdf),图的层级、动态协作和部署节点表达参考 [C4](https://c4model.com/diagrams) 以及 arc42 的 [Building Block](https://docs.arc42.org/section-5/)、[Runtime](https://docs.arc42.org/section-6/) 和 [Deployment](https://docs.arc42.org/section-7/) 视图;这些方法只提供视角和表达规则,不替代 BitFun 的真实 owner 与代码边界。 -Level 0 展示系统级主要边界和依赖方向;Level 1 再按 Level 0 的模块或范围展开。每张图必须能独立说明范围和图例,关系使用明确方向或协议,逻辑模块、crate、运行任务和部署实例不要求一一对应。Agent Runtime 的 Embedded/Shared 逻辑、开发、进程、物理和场景视图集中在 +Level 0 展示系统级主要边界和依赖方向;Level 1 再按 Level 0 的模块或范围展开。每张图必须能独立说明范围和图例,关系使用明确方向或协议,逻辑模块、crate、运行任务和部署实例不要求一一对应。App Server 的 Embedded/Shared 与 Headless Direct Runtime 逻辑、开发、进程、物理和场景视图集中在 [`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md),本文件不重复其连接和性能细节。 ### 2.1 Logical View · Level 0 -Logical View 只表达当前系统的职责模块与依赖方向,不表达 crate 归属或进程位置。 +Logical View 只表达目标系统的职责模块与依赖方向,不表达 crate 归属或进程位置。 ```mermaid %%{init: {"theme":"base","flowchart":{"curve":"basis","nodeSpacing":28,"rankSpacing":34},"themeVariables":{"fontFamily":"Inter, ui-sans-serif, system-ui","primaryColor":"#ffffff","primaryTextColor":"#171717","primaryBorderColor":"#737373","lineColor":"#525252","secondaryColor":"#fafafa","tertiaryColor":"#ffffff","clusterBkg":"#ffffff","clusterBorder":"#a3a3a3"}}}%% @@ -191,6 +198,12 @@ flowchart TB Development View 展示仓库的静态代码组织。层间依赖只允许向下,可跨过中间层,但不能反向依赖上层;图中子项表示主要 crate 家族或产品入口,不等同于 Logical View 的职责模块。 +#### 当前仓库快照 + +当前不存在 `src/apps/app-server`、`src/crates/interfaces/app-server` 或 +`src/crates/adapters/app-server-transport`。当前 Shared TUI 生产路径仍由 +`src/crates/adapters/agent-runtime-ipc` 提供;它在目标纵向切片完成前按现有生产合同维护。 + ```mermaid flowchart TB subgraph AppsLayer[" "] @@ -205,7 +218,7 @@ flowchart TB subgraph AdaptersLayer[" "] direction LR - AdaptersTitle["3 · Adapters"] ~~~ RuntimeIPC["Runtime IPC"] ~~~ ModelAdapters["Model Adapters"] ~~~ SourceAdapters["Source Adapters"] ~~~ Transport["Transport"] ~~~ WebDriver["WebDriver"] + AdaptersTitle["3 · Adapters"] ~~~ RuntimeIpc["Agent Runtime IPC · current Shared TUI"] ~~~ ModelAdapters["Model Adapters"] ~~~ SourceAdapters["Source Adapters"] ~~~ Transport["Transport"] ~~~ WebDriver["WebDriver"] end subgraph ServicesLayer[" "] @@ -228,7 +241,7 @@ flowchart TB classDef header fill:#fafafa,stroke:#404040,stroke-width:1.6px,color:#171717; classDef module fill:#ffffff,stroke:#737373,stroke-width:1.3px,color:#171717; class AppsTitle,AssemblyTitle,AdaptersTitle,ServicesTitle,ExecutionTitle,ContractsTitle header; - class Desktop,CLI,Server,Relay,WebUI,MobileUI,ACP,SDKHost,CoreAssembly,ExternalSources,ProductCaps,RuntimeIPC,ModelAdapters,SourceAdapters,Transport,WebDriver,CoreServices,Integrations,MiniAppMarket,RelayService,Terminal,PageRuntime,AgentRuntime,AgentStream,ToolRuntime,PluginClient,Harness,RuntimeServices,CoreTypes,Events,RuntimePorts,ProductDomains module; + class Desktop,CLI,Server,Relay,WebUI,MobileUI,ACP,SDKHost,CoreAssembly,ExternalSources,ProductCaps,RuntimeIpc,ModelAdapters,SourceAdapters,Transport,WebDriver,CoreServices,Integrations,MiniAppMarket,RelayService,Terminal,PageRuntime,AgentRuntime,AgentStream,ToolRuntime,PluginClient,Harness,RuntimeServices,CoreTypes,Events,RuntimePorts,ProductDomains module; style AppsLayer fill:#ffffff,stroke:#a3a3a3; style AssemblyLayer fill:#ffffff,stroke:#a3a3a3; style AdaptersLayer fill:#ffffff,stroke:#a3a3a3; @@ -248,11 +261,22 @@ flowchart TB | Execution | `execution/*` | Agent Core、Extensions、Service Ports | | Contracts | `contracts/*` | Stable Contracts、Security Control、Service Ports | -Assembly 是唯一组装根,只选择下层能力和实现,不能反向依赖 app。每个生态 adapter 独立保留外部格式和顺序语义,再映射到 BitFun owner;生态 adapter 之间不能形成兄弟依赖。 +当前 Product Assembly 是唯一能力选择与 wiring 机制;Desktop、CLI、ACP 和 SDK Host 按已接入程度消费其结果。 +每个生态 adapter 独立保留外部格式和顺序语义,再映射到 BitFun owner;生态 adapter 之间不能形成兄弟依赖。 + +#### 目标增量(尚未实现) + +目标在 Apps & Interfaces 增加 `apps/app-server` 与 `interfaces/app-server`,在 Adapters 增加 +`app-server-transport`,并在 Product Capabilities 增加唯一的 App Server backend profile;本机、服务端、 +网络和 tenant 安全策略是该 profile 的受信组装输入,不形成新部署形态。 +这些目标模块不能出现在“当前仓库快照”中,也不能在有生产 consumer 前建立占位 crate。迁移完成后删除 +`agent-runtime-ipc` 的独立 wire/server;详细模块和退出门槛见 +[`app-server-architecture-design.md`](app-server-architecture-design.md#8-非规范迁移说明)。 ### 2.3 Process View · Level 0 -Process View 展示当前 Agent Runtime 内的异步任务、流和取消传播;Embedded 与 Shared 复用同一任务结构。本视图不描述具体部署环境,也不把一次用户场景误作进程结构。 +Process View 展示目标 Agent Runtime 内的异步任务、流和取消传播;App Server Embedded/Shared 与 Direct Runtime +复用同一任务结构。本视图不描述具体部署环境,也不把一次用户场景误作进程结构。 ```mermaid flowchart LR @@ -297,28 +321,39 @@ flowchart LR ### 2.4 Physical View · Level 0 -Physical View 展示当前可执行单元到设备、主机和存储的映射。Desktop、CLI、ACP 和 SDK Host 使用 Embedded Runtime;交互式 TUI 可以显式连接 Shared Runtime。当前 Web Server 和 Relay Server 都不承载 Agent Runtime。 +Physical View 展示**最终目标(尚未实现)**中可执行单元到设备、主机和存储的映射。第一方 Rich Client 经 App Server +使用 Runtime;Headless CLI/CI、ACP 和 SDK Host 保留各自部署与协议。Relay 只承担账户、同步和控制转发, +不能冒充 App Server 或 Runtime owner。 ```mermaid flowchart LR subgraph LocalHost["Local Host"] direction TB - subgraph EmbeddedNodes["Embedded"] + subgraph ClientHosts["Trusted Rich Client Hosts"] direction LR - DesktopApp["Desktop App"] ~~~ CLIApp["CLI App"] ~~~ ACPApp["ACP"] ~~~ SDKHost["SDK Host"] + TauriHost["Tauri Host"] ~~~ ElectronHost["Electron Host"] ~~~ IDEHost["VS Code Extension Host"] ~~~ TUIHost["CLI / TUI Host"] end - SharedRuntime["Shared Runtime"] + DesktopApp["Tauri App Server · Embedded or Tauri-only Shared"] + ElectronApp["Electron App Server · Embedded or Electron-only Shared"] + IDEApp["VS Code App Server · Embedded or VS Code-only Shared"] + TUIApp["TUI App Server · Embedded or TUI-only Shared"] + DirectCLI["Headless CLI / CI · Direct Runtime"] + ACPApp["ACP · in-process composition"] + SDKHost["SDK Host"] WorkspaceData["Workspace Data"] ToolProcesses["Tool Processes"] end - subgraph UserDevice["Client Device"] + subgraph NetworkClients["Authenticated Network Clients"] direction TB WebClient["Web Client"] MobileClient["Mobile Client"] end - WebServer["Web Server"] + WebBackend["Authenticated Web Backend"] + WebApp["Web App Server · Embedded or Web-only Shared"] + ServerData["Tenant Workspace / Session Data"] + ServerTools["Server Tool / Plugin Processes"] subgraph RelayHost["Relay Node"] direction TB @@ -328,52 +363,83 @@ flowchart LR end AIProviders["AI Providers"] - RemoteHosts["Remote Hosts"] - - WebClient -->|WebSocket| WebServer + RemoteRuntime["Target-side Remote Runtime Host"] + + TauriHost -->|App Server protocol| DesktopApp + ElectronHost -->|App Server protocol| ElectronApp + IDEHost -->|App Server protocol| IDEApp + TUIHost -->|App Server protocol| TUIApp + WebClient -->|HTTPS / WebSocket| WebBackend + WebBackend -->|Authenticated App Server protocol| WebApp + WebApp --> ServerData + WebApp -->|spawn| ServerTools + WebApp -->|HTTPS| AIProviders MobileClient -->|HTTPS| RelayServer - DesktopApp <-->|WebSocket| RelayServer - CLIApp <-->|WebSocket| RelayServer - CLIApp -.->|Local IPC| SharedRuntime + TauriHost <-->|Authenticated control / sync| RelayServer + ElectronHost <-->|Authenticated control / sync| RelayServer + TUIHost <-->|Authenticated control / sync| RelayServer RelayServer --> RelayDB RelayServer --> AssetStore - EmbeddedNodes --> WorkspaceData - SharedRuntime --> WorkspaceData - EmbeddedNodes -->|spawn| ToolProcesses - SharedRuntime -->|spawn| ToolProcesses - EmbeddedNodes -->|HTTPS| AIProviders - SharedRuntime -->|HTTPS| AIProviders - DesktopApp -->|SSH| RemoteHosts + DesktopApp --> WorkspaceData + ElectronApp --> WorkspaceData + IDEApp --> WorkspaceData + TUIApp --> WorkspaceData + DirectCLI --> WorkspaceData + ACPApp --> WorkspaceData + SDKHost --> WorkspaceData + DesktopApp -->|spawn| ToolProcesses + ElectronApp -->|spawn| ToolProcesses + IDEApp -->|spawn| ToolProcesses + TUIApp -->|spawn| ToolProcesses + DirectCLI -->|spawn| ToolProcesses + ACPApp -->|spawn| ToolProcesses + SDKHost -->|spawn| ToolProcesses + DesktopApp -->|HTTPS| AIProviders + ElectronApp -->|HTTPS| AIProviders + IDEApp -->|HTTPS| AIProviders + TUIApp -->|HTTPS| AIProviders + DirectCLI -->|HTTPS| AIProviders + ACPApp -->|HTTPS| AIProviders + SDKHost -->|HTTPS| AIProviders + DesktopApp -->|Remote adapter| RemoteRuntime + ElectronApp -->|Remote adapter| RemoteRuntime + IDEApp -->|Remote adapter| RemoteRuntime + TUIApp -->|Remote adapter| RemoteRuntime classDef unit fill:#ffffff,stroke:#737373,stroke-width:1.3px,color:#171717; - class DesktopApp,CLIApp,ACPApp,SDKHost,SharedRuntime,WorkspaceData,ToolProcesses,WebClient,MobileClient,WebServer,RelayServer,RelayDB,AssetStore,AIProviders,RemoteHosts unit; + class TauriHost,ElectronHost,IDEHost,TUIHost,DesktopApp,ElectronApp,IDEApp,TUIApp,DirectCLI,ACPApp,SDKHost,WorkspaceData,ToolProcesses,WebClient,MobileClient,WebBackend,WebApp,ServerData,ServerTools,RelayServer,RelayDB,AssetStore,AIProviders,RemoteRuntime unit; style LocalHost fill:#ffffff,stroke:#737373; - style EmbeddedNodes fill:#ffffff,stroke:#a3a3a3; - style UserDevice fill:#ffffff,stroke:#a3a3a3; + style ClientHosts fill:#ffffff,stroke:#a3a3a3; + style NetworkClients fill:#ffffff,stroke:#a3a3a3; style RelayHost fill:#ffffff,stroke:#737373; ``` -实线表示主要协议、存储访问或进程创建,虚线表示显式启用的 Shared TUI 本机连接。Relay DB 只在账户模式启用,Asset Store 的具体实现由部署配置选择。完整 package plugin 尚未形成生产闭环,因此不把规划中的 Plugin Host 画成当前部署实例。 +Embedded 与 Shared 复用 App Server schema、handler 和行为 fixture。每个 Shared instance 固定一个 +`client_kind`,Desktop、VS Code、TUI 与 Web 不混连。服务端运行使用独立网络认证、方法 allowlist、租户隔离、 +数据和 execution domain,但不形成 Hosted 第三形态。Relay DB 和 Asset Store 由账户/同步部署选择;Remote Runtime +位于目标 execution domain,本机 App Server 不取得其 workspace lease。 | Deployment unit | Main contents | |---|---| -| Desktop App | Web UI、Tauri Host、embedded Agent Runtime | -| CLI App | TUI、Headless、Peer;默认 Embedded,可显式使用 Shared TUI | -| Shared Runtime | 私有本机 IPC;当前只有交互式 TUI consumer | -| ACP | Embedded Agent Runtime、ACP 协议生命周期 | -| SDK Host | 私有跨进程 adapter;公开 SDK 产品尚未交付 | -| Web Server | Health、Info、WebSocket 外壳;不包含 Agent Runtime | -| Relay Server | WebSocket/HTTP bridge、账户与同步;不包含 Agent Runtime | +| Rich Client Host | Tauri/Electron/VS Code/TUI/Web 的宿主生命周期、认证和平台 capability;不拥有 Runtime 状态 | +| App Server | 第一方 Rich Client 协议、产品组装根与有界 Runtime context registry;每个 workspace context 独立持有 ownership lease | +| Headless CLI / CI | Direct Runtime、结构化输出、退出码与一次性生命周期 | +| ACP | ACP adapter、独立协议生命周期和匹配的 Runtime composition | +| SDK Host | 公开 Agent SDK 的独立 adapter/process;不复用 App Server wire | +| Web Backend | 网络认证、授权、Origin/CORS、方法 allowlist 与 App Server 网络暴露 | +| Networked App Server | Embedded 或 Web-only Shared 实例的网络暴露、租户隔离和 workspace/session ownership | +| Relay Server | 账户、同步和控制转发;不成为 Agent Runtime 或 App Server owner | +| Remote Runtime Host | 在目标 execution domain 持有 workspace、凭据、进程和 Runtime ownership | ### 2.5 Scenarios (+1) · Level 0 -Scenarios 选择少量具有架构意义的当前路径来校验前四个视图,不穷举产品功能,也不重复 Process View 的任务调度细节。 +Scenarios 选择少量具有架构意义的目标路径来校验前四个视图,不穷举产品功能,也不重复 Process View 的任务调度细节。 ```mermaid flowchart TB subgraph InteractiveTurn["Chat Turn"] direction LR - TurnUser["User"] --> TurnHost["Product Host"] --> TurnCore["Agent Core"] --> TurnProvider["AI Provider"] --> TurnResponse["Response"] + TurnUser["User"] --> TurnHost["Rich Client Host"] --> TurnApp["App Server"] --> TurnCore["Agent Core"] --> TurnProvider["AI Provider"] --> TurnResponse["Response"] end subgraph ToolExecution["Tool Run"] @@ -388,24 +454,27 @@ flowchart TB subgraph RemoteControl["Remote Turn"] direction LR - RemoteClient["Mobile Client"] --> RemoteRelay["Relay Server"] --> RemoteDesktop["Desktop Host"] --> RemoteAPI["Runtime API"] --> RemoteCore["Agent Core"] + RemoteClient["Mobile Client"] --> RemoteRelay["Relay Server"] --> RemoteDesktop["Target Execution Host"] --> RemoteAPI["Runtime API"] --> RemoteCore["Agent Core"] end InteractiveTurn ~~~ ToolExecution ~~~ SourceDiscovery ~~~ RemoteControl classDef step fill:#ffffff,stroke:#737373,stroke-width:1.3px,color:#171717; - class TurnUser,TurnHost,TurnCore,TurnProvider,TurnResponse,ToolCore,ToolRuntime,ToolPorts,PlatformResource,ToolResult,SourceRoots,SourceAdapters,ControlPlane,SourceHost,RemoteClient,RemoteRelay,RemoteDesktop,RemoteAPI,RemoteCore step; + class TurnUser,TurnHost,TurnApp,TurnCore,TurnProvider,TurnResponse,ToolCore,ToolRuntime,ToolPorts,PlatformResource,ToolResult,SourceRoots,SourceAdapters,ControlPlane,SourceHost,RemoteClient,RemoteRelay,RemoteDesktop,RemoteAPI,RemoteCore step; style InteractiveTurn fill:#ffffff,stroke:#a3a3a3; style ToolExecution fill:#ffffff,stroke:#a3a3a3; style SourceDiscovery fill:#ffffff,stroke:#a3a3a3; style RemoteControl fill:#ffffff,stroke:#a3a3a3; ``` -四条路径分别覆盖核心对话、内置工具、运行时无关的外部来源发现,以及经 Relay 回到 Desktop owner 的远程控制。Source Scan 的发现与控制事实由 `ExternalSourceControlPlane` 统一持有,adapter 不成为第二个业务 owner。完整 package plugin、公开 SDK 产品和 HarmonyOS 不在当前生产闭环中,因此不作为 Level 0 场景。 +四条路径分别覆盖 Rich Client 对话、内置工具、运行时无关的外部来源发现,以及经 Relay 回到目标 execution +host 的远程控制。Source Scan 的发现与控制事实由 `ExternalSourceControlPlane` 统一持有,adapter 不成为第二个业务 owner。 ## 3. 接口边界 -BitFun 只保留四个稳定接口边界;工具、事件和权限作为归属子接口被复用,不在插件层重复定义。本文使用“接口”描述可被调用或依赖的能力面;只有描述跨进程消息封装、结构化 schema、序列化对象或强兼容约束时才使用“契约”;只读状态视图表示从权威状态派生出的查询结果。 +BitFun 只保留四个稳定能力接口边界;工具、事件和权限作为归属子接口被复用,不在插件层重复定义。Rich Client App Server +是 Agent Runtime API 之上的版本化宿主通信契约,不新增第五个业务能力 owner。本文使用“接口”描述可被调用或依赖的能力面; +只有描述跨进程消息封装、结构化 schema、序列化对象或强兼容约束时才使用“契约”;只读状态视图表示从权威状态派生出的查询结果。 | 接口边界 | 谁使用 | 提供 | 不包含 | |---|---|---|---| @@ -458,16 +527,17 @@ client 或未来 CLI/HarmonyOS 计划,不能证明同名 Rust transport adapte ### 3.2 宿主通信契约与 Tauri 薄适配 前后端契约按能力语义归属,不按 Tauri command 名称归属。稳定的请求、响应、状态事实和类型化错误放在对应 -`contracts/*`、Agent Runtime API 或能力归属模块;Tauri、HTTP/WebSocket、CLI/TUI、ACP 与公开 SDK -Host adapter 只负责把各自协议映射到 -这些类型。该规则降低框架耦合,但不要求把每个 Desktop DTO 都搬进共享 crate。 +`contracts/*`、Agent Runtime API 或能力归属模块。Tauri、Electron、VS Code Extension、Web 与交互式 TUI 等第一方 Rich Client +经版本化 App Server schema 消费这些事实;Headless CLI、ACP、Server/Remote 与公开 SDK Host adapter 仍按各自交付合同映射。 +该规则降低框架耦合,但不要求把每个 Desktop DTO 都搬进共享 crate,也不允许 App Server schema 反向成为领域 owner。 | 层 | 允许 | 禁止 | |---|---|---| | 能力归属模块 / Agent Runtime API | 字段明确的请求和响应、状态事实、权限/取消规则、与框架无关的用例方法 | `tauri::State`、`AppHandle`、窗口/菜单对象、command 宏、HTTP/WebSocket/ACP/SDK Host 消息结构 | -| Desktop Tauri adapter | 读取宿主状态、构造稳定请求、调用对应 Agent Runtime API 或归属模块接口、把明确错误转换为 Desktop 协议、投递桌面事件 | 复制业务校验、持有第二份权威状态、把 Tauri 类型传入下层 | +| Rich Client App Server | 组合版本化 JSON-RPC method、wire 投影、事件、错误、Host capability 与协议协商 | 领域行为 owner、公开 SDK 全量镜像、平台句柄或未经授权的远程能力面 | +| Tauri / Electron / VS Code Host | 创建 Embedded 或发现完全相同 `client_kind` 的 Shared App Server,提供认证、窗口、剪贴板、文件选择等协商后平台能力 | 复制业务校验、持有第二份权威状态、把平台对象传入下层 | | Server / Remote adapter | 路由鉴权、协议消息、连接生命周期、流量控制与取消转换 | 为同一能力另建业务含义不同的 DTO 或 handler | -| GUI / TUI 消费方 | 依赖入口侧 API interface、稳定读模型或 Agent Runtime API;各自保留渲染状态 | 依赖公开 Python/TypeScript SDK、直接持有平台句柄,或让 React/TUI 状态成为后端契约 | +| GUI / 交互式 TUI 消费方 | 依赖 App Server typed client 并各自保留渲染状态 | 依赖公开 Python/TypeScript SDK、直接持有平台句柄,或让 React/TUI 状态成为后端契约 | 本文其他章节和历史设计中出现的“Runtime SDK”,如果指 `agent-runtime::sdk`,统一称为 **Rust Runtime SDK(当前 preview)**;它是共享 **Agent Runtime API** 的当前 Rust 入口。只有 @@ -475,10 +545,15 @@ Host adapter 只负责把各自协议映射到 **BitFun Agent SDK**,其跨进程适配器称为 **SDK Host**。该术语区分不要求机械重命名现有 crate/module,但禁止用 Rust preview 的存在证明公开 SDK 已交付。 -第一方多实例目标称为 **Shared Agent Runtime deployment**。承载它的 Rust 进程与 SDK Host、Plugin Host、Server/Relay 和 Remote -execution Host 都是不同职责;其部署与进程生命周期以 +第一方多实例目标称为 **Shared Agent Runtime deployment**,由 App Server 的 Shared 模式承载,不新增 Shared TUI/GUI server。 +每个 Shared instance 固定一种 `client_kind`;TUI、Desktop、VS Code 和 Web 可以复用 schema/handler,但不能混连同一实例。 +该 Rust 进程与 SDK Host、Plugin Host、Server/Relay 和 Remote execution Host 都是不同职责;其部署与进程生命周期以 [`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md) 为准。 +面向 Tauri、Electron、VS Code Extension、Web 与交互式 TUI 的统一后端协议称为 **Rich Client App Server**。它以同一 +schema/handler 只支持 Embedded 与 Shared deployment;其 Host capability、安全、版本和迁移边界以 +[`app-server-architecture-design.md`](app-server-architecture-design.md) 为准。 + Rust 与 TypeScript 的字段一致性以能力所有者的 DTO 为事实源,不以 Tauri command 参数为事实源。单宿主阶段由 前端基础设施层维护对应接口,并用序列化契约测试锁定字段命名、可选字段和错误形状;达到独立版本化门槛后,才使用 不依赖 Tauri 的 JSON Schema 或类型生成任务输出只读 TypeScript 类型。生成结果只同步数据形状,不承载权限、重试或 @@ -515,22 +590,45 @@ Desktop command 使用的序列化对象继续留在 `src/apps/desktop`;即使 ## 4. 运行协作细节 -本节在 Process View Level 0 之下展开产品入口、插件调用和平台能力的当前调用链;这些图描述组件协作,不构成新的 4+1 视图。 +本节在 Process View Level 0 之下展开产品入口、插件调用和平台能力的协作链;每张图明确标注当前或目标, +不构成新的 4+1 视图。 ### 4.1 产品入口 +当前生产调用链: + ```mermaid flowchart LR - Products["GUI · TUI · CLI · Web"] --> Adapter["入口适配器"] + Desktop["Tauri Desktop"] --> Tauri["Tauri command/event adapters"] --> API["Runtime API / Core compatibility"] + TUI["Interactive TUI · default"] --> LegacyInProcess["legacy in-process Runtime client"] --> API + SharedTUI["Interactive TUI · --shared"] --> Legacy["agent-runtime-ipc"] --> API + Headless["Headless CLI / CI"] --> LegacyInProcess + ACP["ACP"] --> ACPAdapter["ACP adapter"] --> API +``` + +当前 `CliAgentRuntimeBackend` 只有 in-process 与 Shared IPC 两种实现;App Server assembly、typed client +与 transport 尚未创建,Desktop 也仍使用 Tauri 路径。 + +目标调用链(尚未实现): + +```mermaid +flowchart LR + Rich["Tauri · Electron · VS Code · Web · Interactive TUI"] --> AppServer["Rich Client App Server"] + Products["Headless CLI"] --> Adapter["入口适配器"] Protocol["ACP · Server · Remote"] --> Adapter SDK["Agent SDK"] --> SDKHost["SDK Host"] + AppServer --> API["Runtime API"] Adapter --> API["Runtime API"] SDKHost --> API API --> Runtime["共享 Runtime"] Assembly["产品组装"] -. "选择" .-> Runtime ``` -入口 adapter 消费同一 Runtime API,部署选择不能进入业务 owner:Embedded 使用进程内强类型调用;Shared 或 SDK Host 才在各自私有 adapter 中执行 transport 封装。GUI、TUI、Headless CLI、ACP 和 SDK 不共享 wire、renderer 或生命周期,也不得为了统一接口而让默认 Embedded 路径承担序列化成本。 +入口最终消费同一 Runtime API,部署选择不能进入业务 owner。第一方 Rich Client(包括交互式 TUI)共享版本化 App Server +wire。Embedded 与 Shared 使用同一个 schema 和 handler;Shared instance 按 `client_kind` 隔离。服务端组装根、网络安全和 +租户边界是正交约束,不形成 Hosted 第三形态。部署差异不能进入领域 owner。 +Headless CLI、ACP 与 SDK Host 不因 Rich Client 协议统一而共享 wire、renderer 或生命周期;Headless CLI/CI 默认 Direct Runtime, +不承担无收益的后台进程和序列化成本。目标架构不保留第二套 Shared TUI server/wire。 ### 4.2 插件调用 @@ -560,7 +658,8 @@ flowchart LR 关键规则: -- 产品入口先经过自己的 adapter,再消费 Agent Runtime API 和只读视图;公开 SDK 只多一层 SDK Host 跨进程适配。 +- Rich Client 先经过 App Server adapter,其他产品入口经过自己的 adapter,再消费 Agent Runtime API 和只读视图; + 公开 SDK 只多一层 SDK Host 跨进程适配。 Agent Runtime API 是一组小而明确的用例接口,不是必须实例化的总入口;adapter 可以调用对应归属模块的少量接口, 但不能访问内部状态、绕过既有编排或复制业务规则。任何入口都不直接调用 Plugin Host。 - 插件只进入扩展贡献接口,不直接写内核状态、工具结果、权限结果或审计事实。 @@ -700,6 +799,11 @@ flowchart LR 也不执行产品定义中携带的任意脚本。 - Product Assembly 只消费产品组装结果和调用方唯一传入的 Delivery Profile;不读取原始品牌资源, 不运行构建脚本,也不从产品定义再次选择 Delivery。 +- 目标 App Server 使用唯一独立后端 Delivery Profile。App Server instance 在启动时固定产品身份、`client_kind`、数据命名空间、 + 安全域、release channel、Runtime Configuration 和 capability 上限;连接的 Desktop/TUI/VS Code/Web Host + 不能用自身 profile 改写这些实例事实。 +- Shared App Server 只接受 `client_kind`、产品身份、数据命名空间、安全域、release channel、协议范围和 execution domain + 兼容的 Client;窗口、workspace、Session 或 plugin 数量不构成默认实例键,不同 `client_kind` 必须使用不同实例。 - GUI 与 TUI 布局由对应宿主独立校验,只共享产品身份、Capability ID、品牌资源索引和策略引用,不共享布局、 组件、主题键、键位或渲染状态。 - 布局选择只能引用宿主已注册的稳定 ID;品牌生成和校验继续使用仓库现有构建流程,不新增通用脚本运行时。 @@ -712,55 +816,39 @@ flowchart LR 产品形态由产品组装决定,不由插件配置、单个 Cargo feature 或生态适配器临时决定。 -当前本机入口组装: +当前入口组装仍以 Desktop/CLI 的既有 profile 和 compatibility composition 为准;当前 +`DeliveryProfile` 没有 App Server 变体,不能把下图当作已接入能力。 -```mermaid -flowchart TB - Desktop["Desktop"] --> Full["product-full"] - CLI["CLI / TUI"] --> Full - ACP["ACP"] --> Parts["Runtime Parts"] - SDKHost["SDK Host"] --> Parts - ServerBootstrap["Server agent bootstrap · dormant"] --> Full - - Full --> Coordinator["ConversationCoordinator"] - Parts --> Coordinator - Ownership["CoreRuntimeOwnership"] -. "first-party composition injects once" .-> Coordinator -``` - -当前公开 HTTP Server 不调用 agent bootstrap,因此不创建 Runtime 或 workspace ownership;图中的 Server 节点只记录已有 agent-enabled composition 边界,不能据此宣称 Server Agent API 已交付。 - -当前 Peer 运行连接: +目标入口组装(尚未实现): ```mermaid -flowchart LR - Peer["Peer UI"] --> Host["Peer Host"] -``` - -尚未交付的公开 SDK 路径: - -```mermaid -flowchart LR - SDK["Public SDK"] -.-> Host["SDK Host"] +flowchart TB + Rich["Desktop / TUI / VS Code / Web Host"] --> AppClient["App Server typed client"] + AppClient --> App["App Server · unique backend profile"] + Headless["Headless CLI / CI"] --> Direct["Direct Runtime composition"] + ACP["ACP"] --> ACPParts["ACP composition"] + SDKHost["SDK Host"] --> SDKParts["SDK composition"] + + App --> RuntimeAPI["Agent Runtime API"] + Direct --> RuntimeAPI + ACPParts --> RuntimeAPI + SDKParts --> RuntimeAPI + RuntimeAPI --> Coordinator["Runtime owners"] ``` -| 当前入口 | 已有能力 | 明确边界 | -|---|---|---| -| Desktop | 使用 `product-full`;显示外部来源、审批、冲突、诊断和 Host 能力 | 可执行能力在事实所在 Host 运行;Safe Mode 只阻止新调用,不改来源、不取消正在运行的调用 | -| CLI / TUI | 使用 `product-full`;提供 `/extensions`、统一 `/hooks`(旧 `/hooks_external` 为别名)、`/tools` 和 `/agents`;Claude Code/Codex 命令 Hook 可经显式审阅复制为原生层 | 生态解析仍在适配器,不启动第二套 Agent Runtime;OpenCode Hook 仍只静态发现;远程能力未接入时不回退本机 | -| ACP | 使用 `DeliveryProfile::Acp` 和 Runtime Parts | load 成功后才发布活动状态;close 排空后再卸载;完整历史和配置仍由 Core/ACP 管理 | -| Peer / Server | Server 提供 control/catalog;Peer Host 执行真实工作区操作;当前 HTTP Server 不装配 Agent Runtime | 控制端不替远端发现或执行;旧 Host 明确降级,SSH Remote 未接入时返回不支持;只读 Server 不声明 Runtime ownership | -| Web / Mobile Web | 依赖现有后端入口 | 不持有插件执行单元,也不能据空 profile 宣称独立能力 | -| HarmonyOS 手机 Remote | phone-only ArkTS 远程入口 | 不等于 HarmonyOS PC 本地 Runtime、CLI/TUI 或 GUI | - -| 目标形态 | 当前状态 | 设计边界 | +| 目标入口 | 组装与协议 | 明确边界 | |---|---|---| -| HarmonyOS PC CLI/TUI | 未实现 | HAP、手机 Remote App 和远端代执行均不能替代 | -| HarmonyOS PC GUI | 未实现 | 与 CLI/TUI 共享 Runtime 语义,但独立验证宿主、界面和发布 | -| Public Agent SDK | Python/TypeScript 尚未交付;Rust Runtime SDK 是内部 preview | 一个 `AgentClient`、多个语言绑定;SDK Host 不依赖或冒充 CLI | - -Shared Agent Runtime 是第一方多实例的目标部署,不是上表新增的当前产品形态。当前文档中表示“事实实际所在位置”的泛称 Host -可能仍指 Desktop 进程、Peer、Server 或 Remote execution host,不能据此推断 Shared deployment、多 Client Session 单写或 -跨进程重连已经交付;完成条件以 +| Tauri Desktop / Electron Desktop | App Server typed client;默认 Embedded;分别只能连接 Tauri-only / Electron-only Shared instance | 两种 Desktop Host 也不混连;Host 保留平台 capability 和界面状态 | +| VS Code / Interactive TUI | App Server typed client;默认 Embedded,可连接自身 `client_kind` 的 Shared instance | 不与 Desktop/Web 混连同一 Shared Server | +| Browser Web UI | 经认证 Web Backend 暴露 Embedded 或 Web-only Shared App Server | 网络方法 allowlist 与本机超集分离;浏览器不持有本机凭据 | +| Headless CLI / CI | Direct Runtime;不作为 App Server client | `--shared` 仅属于交互式 TUI;未来非交互 attach 需独立稳定合同 | +| ACP | 独立 ACP composition 和 wire | 不经 App Server 双重转换,不冒充公开 SDK | +| Public Agent SDK | 独立 SDK Host composition 和 wire | 一个 `AgentClient`、多个语言绑定;SDK Host 不依赖或冒充 CLI/App Server | +| Peer / Relay / Remote | Relay 负责账户、同步和控制转发;目标 execution host 持有 Runtime ownership | 控制端不替目标 host 发现或执行;能力不可用时类型化降级,不静默回落本机 | +| HarmonyOS PC | 本地 CLI/TUI 与 GUI 分别作为匹配 Host 接入 Runtime/App Server | HAP、手机 Remote App 和远端代执行均不能替代本地产品形态 | + +App Server、SDK Host、ACP 和 Headless Direct Runtime composition 共享 Runtime API 与行为 fixture,但不共享 wire、 +进程生命周期或安全边界。Shared Agent Runtime 只由 App Server Shared deployment 承载,完成条件以 [`agent-runtime-deployment-design.md`](agent-runtime-deployment-design.md) 为准。 对外一级状态统一使用[外部 AI 工作内容设计](extensions/external-ai-work-sources-design.md#7-状态与提示规则)定义的 diff --git a/docs/architecture/product-customization-blueprint.md b/docs/architecture/product-customization-blueprint.md index 73b7cf829..bc5f97c37 100644 --- a/docs/architecture/product-customization-blueprint.md +++ b/docs/architecture/product-customization-blueprint.md @@ -115,6 +115,14 @@ flowchart LR 3. 计算实际包含的产品能力,验证依赖、互斥项和平台要求。 4. GUI 或 TUI 交付只解析自己对应的布局选择;无界面交付不接收界面配置。 5. 解析内置扩展的固定版本、内容摘要、必要性和不可用时的产品行为。 + +目标 App Server 是独立后端交付形态。它只消费后端所需的产品身份、数据命名空间、release channel、能力上限、 +默认策略引用和内置扩展事实,不消费 GUI/TUI 布局。Desktop、Electron、VS Code、Web 和 TUI Host 的布局选择仍由各自 +构建/宿主校验;连接自身 `client_kind` 的 Shared App Server 时,这些 Client 不能把自身布局或 Delivery Profile 注入 Server 组装。 + +Shared discovery 只允许 `client_kind`、产品身份、数据命名空间、用户/组织安全域、release channel、协议兼容范围和 execution +domain 相容的 Client 复用实例。不同 Client 形态、品牌或数据隔离域必须启动不同实例,不能依靠运行时切换 +客户端类型、品牌、数据根或产品策略。 6. 输出产品组装结果,供打包、签名和运行时启动使用。 交付形态与目标平台保持互不影响。HarmonyOS PC 原生 TUI 仍是 `CLI` 交付,不把 HAP 或手机 Remote App 写入 CLI diff --git a/docs/plans/core-decomposition-plan.md b/docs/plans/core-decomposition-plan.md index 73478da21..6a6412bea 100644 --- a/docs/plans/core-decomposition-plan.md +++ b/docs/plans/core-decomposition-plan.md @@ -23,7 +23,7 @@ |---|---|---| | 产品能力组装 | `DeliveryProfile`、`ProductAssembler`、能力计划、服务可用性和测试已存在 | 这些是可测试的 assembly facts,不代表产品入口已接入 | | CLI / Desktop / ACP | 三者仍按需启用 `bitfun-core/product-full`;CLI 与 ACP 已分别提交对应 `DeliveryProfile` 并消费 Runtime Parts/SDK,Desktop 主交互已消费由现有 owner 构造的窄口径 SDK 接口 | 三个入口均复用单一 Core owner;完整 Desktop profile 和剩余兼容操作仍需逐项迁移 | -| Server | 当前生产路由只形成 health/info/ping 基线 | 没有插件状态或独立产品组装完整流程 | +| Server | 当前生产路由包含 health/info/ping,以及 loopback WebSocket 上不启动 Agent Runtime 的 SSH-backed detached-dispatch controller/observer 操作 | 已有窄可变控制面,但没有完整 Server profile、插件状态或独立产品组装流程 | | Server / Remote / Web / Mobile Web / SDK profile | 当前为空计划、未接入入口或仅有 preview 测试 | 不得据枚举值宣称产品能力已交付 | | Agent Runtime SDK | 已有无 `bitfun-core` 依赖的 v2 preview 接口和 smoke test | 发布边界仍需真实嵌入方证明 | | 插件运行时 | 现有路径只覆盖 BitFun 原生包和 OpenCode custom tool 静态名称预览 | 不能据通用消息结构或静态候选扩张稳定 ABI | @@ -95,7 +95,9 @@ CLI-P0 整体退出条件尚未满足;真实供应商审批流、OS 级终端 ### 4.4 最后晋级 Server、Remote 与 SDK -- Server 先从现有 health/info/ping 基线选择一个真实 API 消费方,不预建完整产品 surface。 +- Server 后续切片从现有 health/info/ping 与窄 detached-dispatch 控制面选择真实产品 API 消费方;不得把该 + loopback、无连接认证的 SSH-backed WebSocket envelope 当作完整产品 surface、网络 App Server 或远程入口; + 网络暴露不形成 Hosted 第三部署形态。 - Remote 必须在实际工作区执行域完成能力协商,不以本地 provider 代替。 - SDK 只有在外部或仓库内独立嵌入方无需 `bitfun-core/product-full` 即可完成最小 session/turn/event 流程后,才从 preview 晋级。 - 空 capability plan、disabled stub 和单元测试用于保护降级,不构成产品完成证据。 diff --git a/src/apps/cli/AGENTS.md b/src/apps/cli/AGENTS.md index b185da02e..e656d4def 100644 --- a/src/apps/cli/AGENTS.md +++ b/src/apps/cli/AGENTS.md @@ -3,7 +3,9 @@ Scope: this guide applies to `src/apps/cli`. Read [`docs/architecture/cli-product-line-design.md`](../../../docs/architecture/cli-product-line-design.md), -[`docs/architecture/product-architecture.md`](../../../docs/architecture/product-architecture.md), and +[`docs/architecture/product-architecture.md`](../../../docs/architecture/product-architecture.md), +[`docs/architecture/app-server-architecture-design.md`](../../../docs/architecture/app-server-architecture-design.md), +[`docs/architecture/agent-runtime-deployment-design.md`](../../../docs/architecture/agent-runtime-deployment-design.md), and [`docs/architecture/product-customization-blueprint.md`](../../../docs/architecture/product-customization-blueprint.md) before product-definition, TUI layout, branding, packaging, runtime, or plugin architecture changes. @@ -18,6 +20,15 @@ before product-definition, TUI layout, branding, packaging, runtime, or plugin a Desktop+CLI share one `device_id`; last AuthConnect wins. - Shared session, turn, task, tool, permission, context, checkpoint, Subagent, Harness, MCP, plugin, and capability facts belong to their runtime owners. +- Interactive TUI is a Rich Client and must use `AppServerClient` in the target + architecture. Embedded and `--shared` deployments use one App Server wire; + the Embedded server is exclusive to one TUI client, and the Shared server is + TUI-only. Do not add operations or consumers to the legacy + `agent-runtime-ipc` protocol. +- Headless CLI/CI remains Direct Runtime by default and must keep its stdout/stderr, + exit-code, startup, and lifecycle contract separate from interactive TUI. It + is not an App Server client; `--shared` remains interactive-TUI-only unless a + separate reviewed non-interactive contract is implemented. - Existing `bitfun-core/product-full` compatibility paths may remain during a reviewed migration. Do not add new concrete managers, global mutable services, or CLI-only copies of shared product behavior. diff --git a/src/crates/adapters/AGENTS-CN.md b/src/crates/adapters/AGENTS-CN.md index 29deb4ee8..77d240e6f 100644 --- a/src/crates/adapters/AGENTS-CN.md +++ b/src/crates/adapters/AGENTS-CN.md @@ -8,7 +8,7 @@ | Crate | 职责 | 本地文档 | |---|---|---| -| `agent-runtime-ipc` | 不发布的私有本机 IPC adapter,为可选的第一方 Shared TUI Runtime 提供封闭交互操作 | [AGENTS.md](agent-runtime-ipc/AGENTS.md) | +| `agent-runtime-ipc` | 旧 Shared TUI IPC,冻结并迁移到统一 App Server wire;禁止新增 operation 或 consumer | [AGENTS.md](agent-runtime-ipc/AGENTS.md) | | `ai-adapters` | AI provider 请求/响应 adapter 与 stream protocol glue | [AGENTS.md](ai-adapters/AGENTS.md) | | `opencode-adapter` | OpenCode Command、standalone Tool 和 Subagent 实时 provider 的生态语义;受管包静态预览 | [AGENTS.md](opencode-adapter/AGENTS.md) | | `transport` | Event transport emitter 与宿主 transport adapter | [AGENTS.md](transport/AGENTS.md) | diff --git a/src/crates/adapters/AGENTS.md b/src/crates/adapters/AGENTS.md index 8e9f17533..3db8a91c5 100644 --- a/src/crates/adapters/AGENTS.md +++ b/src/crates/adapters/AGENTS.md @@ -11,7 +11,7 @@ services. | Crate | Responsibility | Local doc | |---|---|---| -| `agent-runtime-ipc` | Non-published private local IPC adapter for the opt-in first-party Shared TUI Runtime; closed interactive operations only | [AGENTS.md](agent-runtime-ipc/AGENTS.md) | +| `agent-runtime-ipc` | Legacy Shared TUI IPC, frozen for migration to the unified App Server wire; no new operations or consumers | [AGENTS.md](agent-runtime-ipc/AGENTS.md) | | `ai-adapters` | AI provider request/response adapters and stream protocol glue | [AGENTS.md](ai-adapters/AGENTS.md) | | `opencode-adapter` | OpenCode source semantics for the live Command, standalone Tool, Subagent, MCP, and static Hook providers; managed-package static preview | [AGENTS.md](opencode-adapter/AGENTS.md) | | `claude-code-adapter` | Runtime-free Claude Code Command, Subagent, MCP, and Hook source semantics with redacted projection | [AGENTS.md](claude-code-adapter/AGENTS.md) | diff --git a/src/crates/adapters/agent-runtime-ipc/AGENTS-CN.md b/src/crates/adapters/agent-runtime-ipc/AGENTS-CN.md index 7f5a54515..77ff0f37e 100644 --- a/src/crates/adapters/agent-runtime-ipc/AGENTS-CN.md +++ b/src/crates/adapters/agent-runtime-ipc/AGENTS-CN.md @@ -1,25 +1,54 @@ **中文** | [English](AGENTS.md) -# Agent Runtime IPC +# Agent Runtime IPC 迁移指南 范围:`src/crates/adapters/agent-runtime-ipc`。 -该 crate 不发布,是第一方 Shared TUI adapter 使用的私有本机协议。它提供 discovery、单实例锁、有界 framing、认证初始化、封闭的交互操作集、Session controller lease、事件传递、连接上限和 cleanup;它不是公开 SDK、远程协议、service layer 或 Runtime owner。 - -## 预集成约束 - -- 唯一 consumer 是 `src/apps/cli` 中的第一方交互式 TUI adapter;不自动包含 GUI、Remote、Peer、ACP、Headless CLI 或 SDK Host。 -- 稳定测试合同包括本机 endpoint、严格 initialize-first、分离的握手/请求 deadline、128 KiB 请求与 8 MiB 响应/事件上限、有界连接、每个 Session 一个 controller、断线取消、30 秒空闲退出和 owner-checked discovery cleanup。 -- consumer 必须复用既有 Agent Runtime owners,并证明 Embedded/Shared 行为等价,不能依赖 SDK Host。 - -## 边界 - -- 只导出 CLI adapter 实际使用的 workspace-private API,且 crate 不得发布,也不得把 wire 作为 SDK 合同。 -- 封闭 operation 范围为 Health、Session list/create/restore(restore 结果包含 transcript)、当前 Session rename 和 Agent mode/model update、Turn submit/cancel、pending/respond Permission 和 UserInput answers。断连 cleanup 属于内部生命周期,不是 detach operation。模型目录和默认值仍是 wire 之外的产品配置;禁止顺带加入 delete、fork、replay、observer、controller transfer、Tool/MCP/Hook 管理或其他产品配置。 -- 可以复用稳定 Event、Product Domain 和 Runtime Port DTO。禁止依赖 `bitfun-core`、Agent Runtime 实现、SDK Host、services、Tauri、terminal、tool runtime 或远程 transport。 -- 只使用 Windows Named Pipe 或 Unix Domain Socket;禁止 TCP、HTTP、WebSocket、浏览器访问或远程 fallback。 -- 这是本机同用户隔离,不是沙箱。未来产品 composition 必须提供当前用户私有 runtime 目录。 -- Embedded 调用方必须继续以强类型直接调用 Agent Runtime,不能初始化本 transport。Shared 的 request、response 和 event frame 在写出前只编码一次;不能为了吞吐量削弱严格解码、未知字段拒绝、frame 上限、有界队列和背压。 +该 crate 是旧 Shared TUI 私有协议,只用于迁移,不是目标架构边界。最终架构中,交互式 +TUI、Desktop、Electron、VS Code 与 Web 的 Embedded/Shared 部署统一使用 App Server +wire,但 Shared 实例按 `client_kind` 隔离,这些 Client 形态不连接同一个实例。修改前阅读 +[`docs/architecture/app-server-architecture-design.md`](../../../../docs/architecture/app-server-architecture-design.md) +和 +[`docs/architecture/agent-runtime-deployment-design.md`](../../../../docs/architecture/agent-runtime-deployment-design.md)。 + +## 迁移规则 + +- 禁止向旧协议新增 operation、consumer、公开导出、transport 或产品能力。 +- App Server 纵向切片完成前,只允许为兼容和回归修复保持当前行为。 +- 删除旧实现前,将 controller lease、认证、frame 上限、断连取消、事件失效、 + `outcome_unknown` 和 cleanup 提升为 App Server conformance tests。 +- 只有真正与协议无关的 Named Pipe/UDS、discovery、framing 或 budget 原语可以迁入 App + Server transport adapter;不得上移 TUI-specific operation envelope 或 handler。 +- 交互式 TUI 必须迁移到 `AppServerClient`:默认使用独占 Embedded App Server, + `--shared` 连接 TUI-only Shared App Server。 +- 旧 consumer 删除后,删除本 crate;或将其缩减为 App Server 内部 transport 实现,不再 + 拥有独立 wire 语义。 + +## 当前生产合同 + +在最后一个 Shared TUI consumer 迁移并满足删除门槛前,该协议虽不是目标边界,仍是生产合同: + +- 唯一 consumer 是 `src/apps/cli` 中的第一方交互式 TUI adapter;GUI、Remote、Peer、ACP、 + Headless CLI 和 SDK Host 都不是 consumer。 +- 只使用本机 Windows Named Pipe 或 Unix Domain Socket。Windows 当前拒绝远程 Client 并要求 bearer + 握手,但代码尚未显式安装仅 owner 可访问的 pipe DACL,也未校验 peer SID;完成实现和跨用户拒绝测试前 + 不得宣称同用户隔离。Unix 保持仅 owner 可访问的 discovery/socket 权限。禁止 TCP、HTTP、WebSocket、 + 浏览器访问或远程 fallback;本机 transport 加认证不是沙箱。 +- 第一帧必须是 initialize,并分离握手/request deadline。初始化校验协议版本、instance identity、 + bearer token、client ID 和 client version;token 与 discovery secret 必须脱敏。错误 token、错误 + instance、版本不匹配、初始化前请求和未认证连接耗尽仍是拒绝测试。 +- 拒绝未知字段与 operation。请求 frame 上限为 128 KiB,响应/事件 frame 上限为 8 MiB;连接、 + 队列、pending request 和序列化缓冲必须有界并实施背压。 +- 封闭 operation 范围为 Health、Session list/create/restore(含 transcript)、当前 Session rename + 与 Agent mode/model update、Turn submit/cancel、pending/respond Permission 和 UserInput answers。 + 禁止加入 delete、fork、replay、Observer、controller transfer、Tool/MCP/Hook 管理或产品配置。 +- 保持每个 Session 一个 Controller、每个连接一个 active Turn,以及断连取消、`outcome_unknown`、 + 事件流粘性失效、30 秒空闲退出和 owner-checked discovery cleanup。 +- 旧的进程内调用方与 Headless Direct Runtime 调用方继续强类型直调 Agent Runtime,不初始化本 transport。 + Shared frame 写出前只编码一次;吞吐优化不得放宽严格解码、边界或背压。 + +只有等价 App Server 限制具备测量依据、conformance/overload 测试和明确兼容性决策后,迁移才可调整 +某个限制;在此之前原值保持不变。 ## 验证 diff --git a/src/crates/adapters/agent-runtime-ipc/AGENTS.md b/src/crates/adapters/agent-runtime-ipc/AGENTS.md index 3a5c3e17f..ac7528410 100644 --- a/src/crates/adapters/agent-runtime-ipc/AGENTS.md +++ b/src/crates/adapters/agent-runtime-ipc/AGENTS.md @@ -1,43 +1,76 @@ [中文](AGENTS-CN.md) | **English** -# Agent Runtime IPC +# Agent Runtime IPC Migration Scope: `src/crates/adapters/agent-runtime-ipc`. -This non-published crate is the private local protocol used by the first-party Shared TUI adapter. -It provides discovery, one-instance locking, bounded framing, authenticated initialization, a closed interactive operation set, -session controller leases, event delivery, connection bounds, and cleanup. It is not a public SDK, remote protocol, service layer, or Runtime owner. - -## Pre-integration contract - -- Only consumer: the first-party interactive TUI adapter in `src/apps/cli`. - GUI, Remote, Peer, ACP, Headless CLI, and SDK Host are not implied consumers. -- Stable test contract: platform-local endpoint, strict initialize-first handshake, separate handshake/request deadlines, - 128 KiB request and 8 MiB response/event limits, bounded connections, one controller per Session, one active Turn per connection, - disconnect cancellation, sticky event-stream invalidation, 30-second idle exit, and owner-checked discovery cleanup. -- Integration check: the consumer must reuse existing Agent Runtime owners and - prove Embedded/Shared behavior equivalence without depending on SDK Host. - -## Boundaries - -- Export only the exact workspace-private API needed by the CLI adapter. Do not - publish this crate or expose its wire as an SDK contract. -- The closed operation budget is Health, Session list/create/restore (including transcript), current-Session rename and Agent mode/model update, - Turn submit/cancel, pending/respond Permission, and UserInput answers. Disconnect cleanup is internal lifecycle, not a detach operation. - Model catalogs and defaults remain product configuration outside this wire. Do not add delete, fork, replay, observer, - controller transfer, Tool/MCP/Hook management, or other product configuration incidentally. -- Stable Event, Product Domain, and Runtime Port DTOs may be reused. Do not - depend on `bitfun-core`, Agent Runtime implementations, SDK Host, services, - Tauri, terminal, tool runtime, or remote transports. -- Use only Windows Named Pipes or Unix Domain Sockets. Do not add TCP, HTTP, - WebSocket, browser access, or remote fallback. -- Treat this as same-user local isolation, not a sandbox. Product composition - must supply a user-private runtime directory. -- Embedded callers must continue to invoke the typed Agent Runtime directly and - must not initialize this transport. Shared outgoing request, response, and - event frames are encoded once before write; strict decoding, unknown-field - rejection, frame limits, bounded queues, and backpressure must not be weakened - for throughput. +This crate is the legacy private Shared TUI protocol. It is migration-only and +is not a target architecture boundary. The final architecture uses one App +Server wire for interactive TUI, Desktop, Electron, VS Code, and Web across +Embedded and Shared deployments. Shared instances are isolated by +`client_kind`; those client forms never connect to one instance. Read +[`docs/architecture/app-server-architecture-design.md`](../../../../docs/architecture/app-server-architecture-design.md) +and +[`docs/architecture/agent-runtime-deployment-design.md`](../../../../docs/architecture/agent-runtime-deployment-design.md). + +## Migration Rules + +- Do not add operations, consumers, public exports, transports, or product + capabilities to this protocol. +- Preserve current behavior only for compatibility and regression fixes while + the App Server vertical slice is incomplete. +- Promote controller leases, authentication, frame bounds, disconnect + cancellation, event invalidation, `outcome_unknown`, and cleanup into App + Server conformance tests before removing their old implementations. +- Move only genuinely protocol-neutral Named Pipe/UDS, discovery, framing, or + budget primitives into the App Server transport adapter. Do not carry the + TUI-specific operation envelope or handler upward. +- Interactive TUI must migrate to `AppServerClient`: default TUI uses an + exclusive Embedded App Server and `--shared` connects a TUI-only Shared App + Server. +- Remove this crate, or reduce it to an App Server-internal transport + implementation with no independent wire semantics, once the old consumer is + gone. + +## Current Production Contract + +Until the last Shared TUI consumer migrates and the deletion gates pass, this +remains a production contract even though it is not a target boundary: + +- The only consumer is the first-party interactive TUI adapter in + `src/apps/cli`. GUI, Remote, Peer, ACP, Headless CLI, and SDK Host are not + consumers. +- Use only a local Windows Named Pipe or Unix Domain Socket. Windows rejects + remote clients and requires the bearer handshake, but the current code does + not explicitly install an owner-only pipe DACL or verify the peer SID; do not + claim same-user isolation until that is implemented and tested. Unix keeps + owner-only discovery/socket permissions. Do not add TCP, HTTP, WebSocket, + browser access, or remote fallback; local transport plus authentication is + not a sandbox. +- Require initialize as the first frame and use separate handshake/request + deadlines. Initialization validates protocol version, instance identity, + bearer token, client ID, and client version; token and discovery secrets stay + redacted. Invalid token, wrong instance, protocol mismatch, pre-initialize + requests, and unauthenticated connection exhaustion remain rejection tests. +- Reject unknown fields and operations. Request frames are limited to 128 KiB; + response/event frames are limited to 8 MiB. Connections, queues, pending + requests, and serialized buffers remain bounded and backpressured. +- The closed operation budget is Health; Session list/create/restore including + transcript; current-Session rename and Agent mode/model update; Turn + submit/cancel; pending/respond Permission; and UserInput answers. Do not add + delete, fork, replay, Observer, controller transfer, Tool/MCP/Hook management, + or product configuration. +- Keep one Controller per Session and one active Turn per connection. Preserve + disconnect cancellation, `outcome_unknown`, sticky event-stream invalidation, + 30-second idle exit, and owner-checked discovery cleanup. +- Legacy in-process and Headless Direct Runtime callers continue to invoke the + typed Agent Runtime directly and do not initialize this transport. Shared + frames are encoded once before write; throughput work must not relax strict + decoding, bounds, or backpressure. + +Migration may change a limit only after the equivalent App Server limit has a +measured rationale, conformance and overload tests, and an explicit compatibility +decision. Until then, carry the current value forward unchanged. ## Verification