Skip to content

Commit 8b64e80

Browse files
doudouOUCqwencoder
andcommitted
docs: Translate daemon developer docs to English
Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
1 parent 667a25a commit 8b64e80

24 files changed

Lines changed: 2331 additions & 2716 deletions

docs/developers/_meta.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export default {
2121
'channel-plugins': 'Channel Plugin Guide',
2222
tools: 'Tools',
2323
'qwen-serve-protocol': 'qwen serve HTTP protocol',
24-
daemon: 'Daemon 模式 · 开发者深度指南',
24+
daemon: 'Daemon Mode (Developer Deep Dive)',
2525

2626
examples: {
2727
display: 'hidden',

docs/developers/daemon-client-adapters/tui.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# TUI Daemon Adapter Draft
22

3-
> **⚠️ 已过时**:本文档描述的是早期 `DaemonTuiAdapter` spike。该 legacy adapter 仍在 `packages/cli/src/ui/daemon/` 中,但新的可复用方向是 SDK 里的共享 UI Transcript 层。当前架构请参考 [`../daemon/14-cli-tui-adapter.md`](../daemon/14-cli-tui-adapter.md)
3+
> **Deprecated**: this document describes the early `DaemonTuiAdapter` spike. The legacy adapter still exists in `packages/cli/src/ui/daemon/`, but the reusable direction is now the SDK shared UI transcript layer. For the current architecture, see [`../daemon/14-cli-tui-adapter.md`](../daemon/14-cli-tui-adapter.md).
44
55
---
66

docs/developers/daemon/00-index.md

Lines changed: 147 additions & 150 deletions
Large diffs are not rendered by default.

docs/developers/daemon/01-architecture.md

Lines changed: 51 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
1-
# Daemon 架构
1+
# Daemon Architecture
22

3-
## 概览
3+
## Overview
44

5-
一个 `qwen serve` 进程坚持 ** daemon = workspace** 的不变式。它内嵌一个 Express HTTP 服务、持有一个 `acp-bridge` 实例、拉起一个 ACP 子进程(`qwen --acp`)来跑真正的 agent 运行时。多个客户端(CLI TUIIDE companionIM channel 机器人、Web BFF、自定义脚本)通过 HTTP + SSE 连进来,要么共享同一个 ACP session`sessionScope: 'single'`,默认),要么每个客户端各拿一个(`'thread'`)。
5+
A `qwen serve` process is **one daemon = one workspace**. It hosts a single Express HTTP server, owns an `acp-bridge` instance, and spawns one ACP child process (`qwen --acp`) that runs the actual agent runtime. Multiple clients (CLI TUI, IDE companion, IM channel bots, web BFFs, custom scripts) connect over HTTP + SSE and either share one ACP session (`sessionScope: 'single'`, default) or split sessions by conversation thread (`sessionScope: 'thread'`).
66

7-
ACP 子进程内部,MCP server 通过 `McpTransportPool`(F2)实现工作区内共享:一对 (server name + 配置指纹) 对应一条 MCP transport,不管被几个 session 发现都只起一份。Bridge 的 `MultiClientPermissionMediator`(F3)在四种策略之一下协调多客户端的权限投票。
7+
Inside the ACP child, MCP servers are shared workspace-wide through `McpTransportPool` (F2): a single (server-name + config-fingerprint) tuple maps to one MCP transport, regardless of how many sessions discover it. The bridge's `MultiClientPermissionMediator` (F3) coordinates permission votes across all connected clients under one of four policies.
88

9-
本文给出 **系统级全景**,本文档集其余 18 篇文档都挂在它下面。每条主干流程都给一张 Mermaid 时序图,单个组件的实现细节请看对应的专题文档。
9+
This doc gives the **system-level picture** that every other doc in this set hangs off. Each load-bearing flow is shown as a Mermaid sequence diagram; per-component implementation details live in the other 18 docs.
1010

11-
## 进程拓扑
11+
## Process topology
1212

1313
```mermaid
1414
flowchart LR
1515
subgraph clients["Clients"]
16-
WUI["Web UI<br/>(packages/webui/src/daemon)"]
17-
TUI["CLI TUI<br/>(待迁移到 SDK ui/*)"]
16+
TUI["CLI TUI<br/>(packages/cli/src/ui/daemon)"]
1817
IDE["VSCode IDE<br/>(packages/vscode-ide-companion)"]
1918
CH["Channel bots<br/>(DingTalk / WeChat / Telegram)"]
2019
SDK["Any SDK consumer<br/>(packages/sdk-typescript/src/daemon)"]
@@ -39,7 +38,6 @@ flowchart LR
3938
MCP2["MCP server B<br/>(websocket)"]
4039
end
4140
42-
WUI -- "HTTP+SSE" --> EXP
4341
TUI -- "HTTP+SSE" --> EXP
4442
IDE -- "HTTP+SSE (loopback)" --> EXP
4543
CH -- "HTTP+SSE" --> EXP
@@ -57,12 +55,9 @@ flowchart LR
5755
POOL -- "shared transport" --> MCP2
5856
```
5957

60-
要点:
58+
The daemon process and the ACP child are connected by an `AcpChannel` (default: a real subprocess pair-of-pipes; `inMemoryChannel` for tests). Everything the daemon does is shaped by this split: HTTP and SSE traffic terminate in the daemon; agent decisions and tool invocations happen in the child; the bridge is the seam.
6159

62-
- daemon 进程与 ACP 子进程通过 `AcpChannel` 连接,默认是真实的子进程 + 一对管道;`inMemoryChannel` 用于测试。
63-
- 所有架构都被这条「daemon ↔ child」缝隙塑造:HTTP / SSE 在 daemon 终止,agent 决策与工具调用在子进程发生,bridge 是中转。
64-
65-
## 包关系
60+
## Package map
6661

6762
```mermaid
6863
flowchart TB
@@ -97,11 +92,10 @@ flowchart TB
9792
EVT["events.ts"]
9893
SSE["sse.ts"]
9994
AUTHF["DaemonAuthFlow.ts"]
100-
UI["ui/* (#4328 + #4353)<br/>normalizer / transcript / store / render"]
10195
end
10296
10397
subgraph adapters["Adapters"]
104-
WUIP["webui/src/daemon/<br/>DaemonSessionProvider.tsx"]
98+
TUIA["cli/src/ui/daemon/<br/>DaemonTuiAdapter.ts"]
10599
CHB["channels/base/<br/>DaemonChannelBridge.ts"]
106100
DT["channels/dingtalk"]
107101
WX["channels/weixin"]
@@ -125,8 +119,7 @@ flowchart TB
125119
POOL2 --> WBG
126120
POOL2 --> SMV
127121
128-
WUIP --> DSC
129-
WUIP --> UI
122+
TUIA --> DSC
130123
CHB --> DSC
131124
DT --> CHB
132125
WX --> CHB
@@ -137,37 +130,26 @@ flowchart TB
137130
DC --> EVT
138131
DC --> SSE
139132
DC --> AUTHF
140-
UI --> EVT
141133
```
142134

143-
箭头方向表示编译期依赖:`serve/` 启动层依赖 `@qwen-code/acp-bridge`,bridge 包本身不反向 import `serve/`。HTTP、auth、filesystem adapter 留在 CLI 包里,ACP session 生命周期和权限协调留在 bridge 包里。
144-
145-
记住三条信任边界:
146-
147-
1. HTTP 入口边界:`serve/auth.ts` 中间件链。
148-
2. bridge ↔ ACP 子进程边界:stdio 上的 NDJSON,没有认证 —— 子进程默认信任 bridge。
149-
3. agent ↔ MCP server 边界:agent 可能触发涉及宿主资源的工具调用。
135+
Three trust boundaries to keep in mind: the HTTP edge (`serve/auth.ts` middleware chain), the bridge ↔ ACP-child seam (NDJSON over stdio, no auth — the child trusts the bridge implicitly), and the agent ↔ MCP server seam (the agent may invoke tools that touch the host).
150136

151-
## 流程 1:HTTP 请求生命周期
137+
## Workflow 1: HTTP request lifecycle
152138

153139
```mermaid
154140
sequenceDiagram
155141
autonumber
156142
participant C as Client (SDK)
157-
participant MW as Middleware<br/>(CORS→host→log→bearer→rate-limit→JSON→telemetry)
143+
participant MW as Middleware<br/>(bearer→host→CORS→mutationGate)
158144
participant R as Route handler
159145
participant BR as AcpBridge
160146
participant BC as BridgeClient
161147
participant CH as ACP child
162148
163149
C->>MW: POST /session/:id/prompt<br/>Authorization: Bearer …<br/>X-Qwen-Client-Id: …
164-
MW->>MW: deny/allow Origin CORS
165-
MW->>MW: hostAllowlist (DNS rebinding guard)
166-
MW->>MW: access-log hook (if daemonLog enabled)
167150
MW->>MW: bearerAuth (constant-time compare)
168-
MW->>MW: rateLimit (when enabled)
169-
MW->>MW: express.json body parser
170-
MW->>MW: daemonTelemetryMiddleware
151+
MW->>MW: hostAllowlist (DNS rebinding guard)
152+
MW->>MW: denyBrowserOriginCors
171153
MW->>MW: mutationGate (strict on mutating routes)
172154
MW->>R: req validated
173155
R->>BR: bridge.sendPrompt(sessionId, body, clientId)
@@ -179,9 +161,9 @@ sequenceDiagram
179161
R-->>C: 200 JSON
180162
```
181163

182-
非流式路由(promptcancelmodel 切换、metadataworkspace CRUD)以一次 JSON 响应结束。流式输出**不是**在该 HTTP 连接上以分块方式返回,而是走 SSE 通道;见流程 2。
164+
Non-streaming routes (prompt, cancel, model switch, metadata, workspace CRUD) terminate as a single JSON reply. Streaming output is delivered out-of-band on the SSE channel, **not** as a chunked HTTP body on this connection. See workflow 2.
183165

184-
## 流程 2:SSE 事件投递与重放
166+
## Workflow 2: SSE event delivery and replay
185167

186168
```mermaid
187169
sequenceDiagram
@@ -203,13 +185,9 @@ sequenceDiagram
203185
Note over EB,SR: If subscriber queue >= maxQueued,<br/>EventBus emits client_evicted terminal frame<br/>and closes subscriber.
204186
```
205187

206-
要点:
188+
The ring buffer is bounded (`eventRingSize`, default 1024). A reconnecting client whose `Last-Event-ID` is older than the ring's head receives a synthetic catch-up signal and must call `loadSession` / `resumeSession` to rebuild deeper state. Slow clients trigger `slow_client_warning` at 75% queue fill and `client_evicted` at the cap.
207189

208-
- 环形缓冲有上限(`eventRingSize`,默认 8000)。
209-
- 重连客户端如果 `Last-Event-ID` 已经落出环外,会收到合成 catch-up 信号,必须用 `loadSession` / `resumeSession` 重建更深层状态。
210-
- 慢消费者在队列 75% 触发 `slow_client_warning`,达到上限时收到 `client_evicted`(终态)后被关掉。
211-
212-
## 流程 3:多客户端权限协调
190+
## Workflow 3: Multi-client permission mediation
213191

214192
```mermaid
215193
sequenceDiagram
@@ -252,16 +230,9 @@ sequenceDiagram
252230
end
253231
```
254232

255-
跨策略「逃生口」:任何客户端都可以投 `CANCEL_VOTE_SENTINEL` 把请求短路成 `cancelled / agent_cancelled`。bridge 防止 wire 端通过普通 `optionId` 字段偷偷塞这个哨兵(`InvalidPermissionOptionError`)。
256-
257-
四种策略一句话:
233+
Cross-policy escape hatch: any client may vote `CANCEL_VOTE_SENTINEL` to short-circuit the request as `cancelled / agent_cancelled`. The bridge guards against wire callers smuggling the sentinel via the normal `optionId` field (`InvalidPermissionOptionError`).
258234

259-
- `first-responder` — 第一个有效投票获胜(默认,保留 live 协作 UX)。
260-
- `designated` — 只有 `originatorClientId` 能投,其他客户端收 `permission_forbidden`
261-
- `consensus` — N-of-M 法定人数,过程中发 `permission_partial_vote` 让 UI 渲染进度。
262-
- `local-only` — 拒绝任何 HTTP 投票,只接受 loopback。
263-
264-
## 流程 4:MCP transport 池的 acquire / release / restart
235+
## Workflow 4: MCP transport pool acquire / release / restart
265236

266237
```mermaid
267238
sequenceDiagram
@@ -307,13 +278,9 @@ sequenceDiagram
307278
P->>EB: publish mcp_server_restarted
308279
```
309280

310-
要点:
311-
312-
- `releaseSession(sessionId)` 借助 `sessionToEntries` 反向索引,以 O(refs) 释放该 session 持有的所有条目。
313-
- daemon 关停时 `drainAll()``draining` 标志(拒绝新的 acquire),并以可配置超时等待所有条目关闭。
314-
- `restartByName` 可以接 `entryIndex` 来精确重启某条;池里同名多条目时返回 `{entries: RestartResult[]}` 形状。
281+
`releaseSession(sessionId)` uses the reverse `sessionToEntries` index to release every entry the session holds in O(refs). On daemon shutdown, `drainAll()` sets the `draining` flag (refusing new acquires) and waits for every entry to close under a configurable timeout.
315282

316-
## 流程 5:生命周期 —— 启动与优雅退出
283+
## Workflow 5: Lifecycle — startup and graceful shutdown
317284

318285
```mermaid
319286
sequenceDiagram
@@ -342,35 +309,30 @@ sequenceDiagram
342309
Note over Op,RQS: Second SIGTERM during shutdown →<br/>bridge.killAllSync() + process.exit(1) (orphan prevention)
343310
```
344311

345-
为什么要分两阶段:
346-
347-
- 还在飞的 HTTP 请求、还连着的 SSE 订阅者、子进程里还在跑的工具调用都需要有上限的退出窗口。
348-
- 任何一条卡过窗口,force-close 路径会接管,避免子进程把 daemon 进程拖住。
349-
- 第二次 SIGTERM 直接走 `bridge.killAllSync()` + `process.exit(1)`,防孤儿。
350-
351-
## 关键文件
352-
353-
| 关注点 | 文件 |
354-
| ------------------ | -------------------------------------------------------------------- |
355-
| Bootstrap | `packages/cli/src/serve/runQwenServe.ts` |
356-
| Express 应用 | `packages/cli/src/serve/server.ts` |
357-
| 能力注册表 | `packages/cli/src/serve/capabilities.ts` |
358-
| Auth 中间件 | `packages/cli/src/serve/auth.ts` |
359-
| Bridge | `packages/acp-bridge/src/bridge.ts` |
360-
| BridgeClient | `packages/acp-bridge/src/bridgeClient.ts` |
361-
| 权限协调器 | `packages/acp-bridge/src/permissionMediator.ts` |
362-
| EventBus | `packages/acp-bridge/src/eventBus.ts` |
363-
| MCP transport 池 | `packages/core/src/tools/mcp-transport-pool.ts` |
364-
| Workspace MCP 预算 | `packages/core/src/tools/mcp-workspace-budget.ts` |
365-
| Workspace 文件系统 | `packages/cli/src/serve/fs/` |
366-
| SDK DaemonClient | `packages/sdk-typescript/src/daemon/DaemonClient.ts` |
367-
| SDK SessionClient | `packages/sdk-typescript/src/daemon/DaemonSessionClient.ts` (61-385) |
368-
| 事件 schema | `packages/sdk-typescript/src/daemon/events.ts` (14-112) |
369-
370-
## 参考
371-
372-
- 设计 issue:[#3803](https://github.com/QwenLM/qwen-code/issues/3803)(daemon 总体设计)、[#4175](https://github.com/QwenLM/qwen-code/issues/4175)(F 系列里程碑)。
373-
- 用户使用文档:[`../../users/qwen-serve.md`](../../users/qwen-serve.md)
374-
- Wire 协议参考:[`../qwen-serve-protocol.md`](../qwen-serve-protocol.md)
375-
- F2 设计文档(v2.2,含 32 条 review fold-in):[`../../design/f2-mcp-transport-pool.md`](../../design/f2-mcp-transport-pool.md)
376-
- F2 设计笔记:issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) commit 4-6。
312+
The two-phase shutdown matters because in-flight HTTP requests, in-flight SSE subscribers, and the ACP child's in-flight tool calls all need bounded teardown windows. If anything blocks past those deadlines, the force-close path takes over so a stuck child can't keep the daemon process alive.
313+
314+
## Critical files
315+
316+
| Concern | File |
317+
| -------------------- | -------------------------------------------------------------------- |
318+
| Bootstrap | `packages/cli/src/serve/runQwenServe.ts` (308-994) |
319+
| Express app | `packages/cli/src/serve/server.ts` (261-339) |
320+
| Capability registry | `packages/cli/src/serve/capabilities.ts` (37-215) |
321+
| Auth middleware | `packages/cli/src/serve/auth.ts` (1-60) |
322+
| Bridge | `packages/acp-bridge/src/bridge.ts` |
323+
| BridgeClient | `packages/acp-bridge/src/bridgeClient.ts` |
324+
| Permission mediator | `packages/acp-bridge/src/permissionMediator.ts` (1-1292) |
325+
| EventBus | `packages/acp-bridge/src/eventBus.ts` |
326+
| MCP transport pool | `packages/core/src/tools/mcp-transport-pool.ts` (104+) |
327+
| Workspace MCP budget | `packages/core/src/tools/mcp-workspace-budget.ts` |
328+
| Workspace FS | `packages/cli/src/serve/fs/` |
329+
| SDK DaemonClient | `packages/sdk-typescript/src/daemon/DaemonClient.ts` (209-1506) |
330+
| SDK SessionClient | `packages/sdk-typescript/src/daemon/DaemonSessionClient.ts` (61-385) |
331+
| Event schema | `packages/sdk-typescript/src/daemon/events.ts` (13-63) |
332+
333+
## References
334+
335+
- Design issues: [#3803](https://github.com/QwenLM/qwen-code/issues/3803) (daemon design), [#4175](https://github.com/QwenLM/qwen-code/issues/4175) (F-series milestones).
336+
- User guide: [`../../users/qwen-serve.md`](../../users/qwen-serve.md).
337+
- Wire protocol reference: [`../qwen-serve-protocol.md`](../qwen-serve-protocol.md).
338+
- F2 design notes: issue [#4175](https://github.com/QwenLM/qwen-code/issues/4175) commits 4-6.

0 commit comments

Comments
 (0)