docs: rebuild the documentation skill and standards (#2983)

This commit is contained in:
Magolor
2026-08-25 23:47:20 +08:00
committed by GitHub
parent f4d1d3fb25
commit 0b5eba0c8d
1061 changed files with 57862 additions and 12379 deletions
@@ -1,54 +1,156 @@
---
description: "Worker 线程代码执行,供用户与维护者组合、调优或排查这个已发布的 TypeScript 后端——它在全新的 Node worker 中运行每个程序。"
kind: "package-reference"
---
# @deepseek-ai/dsh-code-runtime-worker-thread
[English](README.md) | 中文
这是 [`@deepseek-ai/dsh-code-runtime`](../code-runtime/README.zh.md) seam 的 worker 线程实现:`WorkerThreadCodeRuntime` 会在每次运行中使用一个全新的 Node `worker_threads.Worker`,输入 TypeScript,由宿主侧剥离类型,通过消息端口桥接绑定,输出 `{ value, logs, error? }`。**这是隔离措施,而非安全边界**:其信任立场有意与 bash 等价(参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md) 的 Trust posture 章节),但提供 bash 没有的隔离:独立 isolate、空环境、堆上限与强制终止。
## 概述
## 配置
`dsh-code-runtime-worker-thread` 为 [`dsh-code-runtime`](../code-runtime/README.zh.md) seam 执行 TypeScript 程序:每个程序都在一个全新的 Node Worker 线程中运行,宿主提供的绑定可作为普通异步函数调用,运行返回 `{ value, logs, error? }`。它是 `dsh-tools` 中 Code Mode 的已发布后端,因此挂载它正是让模型编写的 TypeScript 执行在组合中生效的方式。运行时「包含」程序,但不隔离它:信任立场与 bash 等价,并带有空环境、堆上限、实测忙碌时间与墙钟预算,以及强制终止。程序每次请求只运行一次,运行之间不保留状态;每个失败——语法错误、预算到期、中止、OOM 退出或输出溢出——都以结果字段返回。
## 目录
- [使用本包](#use-this-package)
- [理解实现](#understand-the-implementation)
- [进一步探索](#further-exploration)
- [模型体验](#model-experience)
- [已知限制与延期工作](#known-limitations-and-deferred-work)
- [开发备注](#dev-note)
-----
<a id="use-this-package"></a>
## 使用本包
当组合需要执行模型编写的 TypeScript 程序时,连同 code-runtime seam 一起挂载此后端;只要模型调用 `run_code``dsh-tools` 中的 Code Mode 就会通过 `ctx.codeRuntime` 驱动它。每个执行上限都是已验证的配置,因此你可以从 `cordis.yml` 为部署调整运行时规模。
### 最小配置
```yaml
- id: code-runtime
name: '@deepseek-ai/dsh-code-runtime-worker-thread'
- name: '@deepseek-ai/dsh-code-runtime'
- name: '@deepseek-ai/dsh-code-runtime-worker-thread'
config:
computeMs: 60000 # busy-time budget (measured event-loop active time)
maxWallMs: 600000 # wall-clock ceiling; never pauses for anything
maxOutputBytes: 67108864 # combined serialized outer-output cap (64 MiB)
maxOldGenerationSizeMb: 512 # worker heap cap (resourceLimits)
computeMs: 60000 # busy-time budget (measured event-loop active time)
maxWallMs: 600000 # wall-clock ceiling; never pauses for anything
maxOutputBytes: 67108864 # combined serialized outer-output cap (64 MiB)
maxOldGenerationSizeMb: 512 # worker heap cap
```
每个字段都会验证并提供默认值;`maxOutputBytes` 必须是至少 4 字节的安全整数,其余字段必须是有限正数,`maxWallMs` 还必须不超过 `2147483647`Node 的 `setTimeout` 最大延迟),此外没有其他可调项。
| 字段 | 默认值 | 含义 |
|---|---|---|
| `computeMs` | `60,000` | 忙碌时间预算:worker 实测事件循环活跃时间超过该值时,运行以 `timeout` 失败 |
| `maxWallMs` | `600,000` | 墙钟上限,为忙碌时间无法观测的等待兜底;最大 `2_147_483_647` |
| `maxOutputBytes` | `67,108,864` | 序列化日志加完成值或失败消息的硬上限;至少 `4` |
| `maxOldGenerationSizeMb` | `512` | worker 堆上限;溢出会杀死 worker,并以 `worker-exit` 呈现 |
## 设计
每个字段在加载时都会验证并提供默认值;没有其他可调项。生成的[配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-code-runtime-worker-thread)是每个受支持字段的穷尽式真源。
- **每次运行使用一个全新 worker,不设池化**:程序所在的世界会随 worker 一同终止,不会留下需要记录的跨运行状态,也无法发生状态泄漏;仅凭会话日志即可重建运行。
- **在执行上下文中,由宿主侧剥离类型**:程序会包裹在异步函数外壳中,通过 `node:module``stripTypeScriptTypes` 剥离类型(只支持可擦除语法;`enum`namespace 会作为程序 `exception` 被拒绝,且不会启动 worker),再按字节位置切回原内容。之后程序作为 `AsyncFunction` 的函数体执行,因此顶层 `await``return` 可用。
- **端口把对端视为不可信**:模型代码能够访问 `parentPort` 并伪造通信,因此任何代码读取入站消息前,系统都会验证其形状并重新构建(`null`、原始值、无效类型和格式错误的载荷会被静默丢弃;伪造的额外字段绝不会被带入);宿主对每个调用 id 最多响应一次,只将绑定名称解析为自有属性(伪造的 `constructor` 无法沿原型链访问),丢弃结算后的回复,并验证每个绑定 resolve 值与完成值是否为无损 JSON。伪造的 `log``done` 消息无法绕过外层上限:宿主会再次验证,并统计每条获准日志以及完成值或诊断。worker 侧命名空间使用 null-prototype 和 `defineProperty`,因此形似 `__proto__` 的绑定名称只是普通键。
- **绑定调用被拒绝时使用的异常类属于请求数据**:可选命名空间描述符会指定构造器全局变量,以及用于接收调用失败的成员名称的自有属性。worker 会创建并注入该真实类,使 `instanceof` 生效,同时无需硬编码 `tools``ToolCallError`;全局变量无效或冲突的声明会在启动 worker 前失败。失败路径使用模块捕获的错误 intrinsic 与属性定义 intrinsic,以及 null-prototype 描述符,因此模型之后的修改无法把被拒绝的绑定变成 worker 崩溃。
- **两个独立预算,因为对端不可信**:`computeMs` 统计 worker 实际测得的忙碌时间(轮询 `worker.performance.eventLoopUtilization()`);热循环无法借助待完成的诱饵 dispatch 隐藏,程序等待慢工具时则不累计。`maxWallMs` 为忙碌时间无法观测的情况兜底(例如等待永远不会 resolve 的 promise)。二者最终都会调用 `worker.terminate()`,连同步热循环也能终止;堆溢出会表现为 worker 的 OOM 退出(`kind: 'worker-exit'`)。`maxWallMs` 在加载时会对照 `MAX_TIMER_DELAY_MS` 做范围校验:`setTimeout` 会把更长的延迟限制为 1 ms,仅有正数校验会放行一个在第一个 tick 就到期的上限。`computeMs` 不需要这道上界,因为它对照的是实测占用率,而不是喂给定时器。
- **中间绑定值是完整 JSON**:绑定参数与 resolve 值会接受无损 JSON 校验,并在没有字节上限的情况下传输。worker 会在执行不可信代码前捕获校验原语,因此对全局对象或原型的修改无法削弱校验或字节计量。中间值绝不会进入外层输出账本或模型上下文;上限仍来自提供方/执行器获取限制与进程/worker 内存。
- **日志主动流入一个外层账本**consolestdoutstderr 文本按产生顺序经端口传输,因此超时或被终止的程序仍会显示已经打印的内容。worker 会精确统计 JSON 字符串的字节数,并在发送完成值和异常诊断前,根据组合预算的剩余量预检;因此,抛出的百万字节 stack 会在 worker 边界变成固定的 `output-limit` 诊断。绕过补丁 stream 槽的原生写入会到达独立于完成端口的 pipe,因此宿主会针对这些字节和不可信伪造通信再次执行账本统计;在物化结果前,结算过程会持续进行有界 pipe 捕获,直到 worker 完成终止。`maxOutputBytes` 统计外层 `logs` 数组加完成值或失败消息载荷的 JSON 序列化;固定的 `CodeRunResult` 字段名、花括号、有界错误 kind 标签,以及后续呈现空白不计入这份可变载荷账本。未超过上限时会返回精确值;有损完成值属于 `invalid-output`,组合溢出属于 `output-limit`,不会用 inspected string 代替。失败会保留能容纳的已捕获前缀,之后按普通外层 `run_code` 落盘策略处理。
- **空环境**worker 使用 `env: {}``execArgv: []`,既不会获得环境变量中的凭据(比 spawn 命令的清理环境规则更严格),也不会继承 loader 标志。
- **dispose(资源释放)时等待完全停稳**:清理会使进行中的运行以 `abort` 失败,并会等待每个 worker 退出后再完成。
### 运行返回什么
## 未构建与已构建的 worker 入口
成功的运行把程序的无损 JSON 完成值作为 `result.value` 返回,把程序打印的文本按顺序作为 `result.logs` 返回。顶层 `await``return` 可用,程序可以把宿主提供的绑定函数(Code Mode 暴露一个 `tools` 对象)当作普通异步调用。
源代码模式通过 Node 原生类型剥离加载只包含可擦除语法的 `src/worker.ts`。其传递运行时闭包只包含 Node 内置模块和相对源模块,因此全新 checkout 绝不需要兄弟工作区包尚未构建的 `lib/` 导出。worker 本地和会话自有的 JSON 边界都会在消息端口两侧展平并重建已验证值,使应用嵌套永远不会进入 structured clone。构建模式会把兄弟文件 `lib/worker.cjs` 作为文件系统路径传入,因为 pkg 的虚拟文件系统(VFSWorker hook 要求 CommonJS;同一路径也可在普通 Node 下使用。对这个已发布入口路径进行测试的仓库级要求由[测试策略](../../../docs/testing.zh.md)规定。
### 包含而非安全边界
SDK 对外提供默认及具名导出的 `WorkerThreadCodeRuntime` 类,以及 `Config`。运行所用的 `./worker` 子路径仅作为打包后的 spawn 入口存在;wire 协议与启动辅助模块是源代码私有的实现细节
程序运行时的权限与 bash 工具相当:它可以访问 Node API,后端也刻意不承诺与宿主的隔离。它提供的是包含——独立 isolate、空环境(没有环境变量凭据,也不继承 loader 标志)、可配置堆上限,以及也能终止同步热循环的强制终止。程序派生的 OS 进程在 `terminate()` 后仍然存活,需要部署层面的清理
### 可能出什么问题
每个程序结果都以结果 resolve,因此失败的运行是 `result.error`,而不是 rejection:语法错误或不可擦除的 TypeScript(`enum`、namespace)在任何 worker 启动前就以 `exception` 失败;预算到期是 `timeout`;中止信号是 `abort`;堆溢出或其他 worker 终止是 `worker-exit`;不是无损 JSON 的完成值是 `invalid-output`;超出上限的序列化输出是 `output-limit`——并保留能容纳的已捕获日志前缀。reject 只表示调用方误用,例如在 dispose(资源释放)后提交运行。
-----
<a id="understand-the-implementation"></a>
## 理解实现
<details>
<summary>实现细节——点击展开</summary>
本节解释后端背后的设计;可观察行为已在[使用本包](#use-this-package)中完整说明。
### 设计理念
后端建立在一个分离之上:**包含,而非安全边界**。模型代码拥有与 bash 等价的信任([Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md) 的 Trust posture),因此设计追求可重建性与有界资源使用,而非硬性的多租户边界——那需要等待容器级后端。每次运行使用一个全新的 worker,程序的世界随 worker 一同终止:不存在可泄漏、也无需记录的跨运行状态,仅凭会话日志即可重建一次运行。
### 执行流程
一次运行在宿主侧剥离类型(`node:module``stripTypeScriptTypes`,保持字节位置不变),包裹为异步函数的函数体使顶层 `await``return` 可用,然后发送给全新的 worker,由 bootstrap 物化绑定命名空间。绑定调用以无损 JSON 跨消息端口传递,每个调用 id 至多应答一次。日志文本主动流向宿主,因此被终止的程序仍会显示已打印的内容。恰好一个结果结算运行——`done` 帧、预算到期、中止或 worker 终止——之后宿主终止 worker 并等待其退出。
### 把对端视为不可信
模型代码能够访问 `parentPort` 并伪造通信,因此任何代码读取入站消息前,系统都会逐字段验证并重建:伪造的额外字段绝不随行,非数字的 call id 绝不会被回显进 reply,绑定名称只解析为自有属性(伪造的 `constructor` 无法沿原型链访问),垃圾被静默丢弃。worker 侧命名空间使用 null-prototype,因此形似 `__proto__` 的绑定名称只是普通键。
### 预算
存在两个独立预算,因为对端不可信:`computeMs` 计量 worker 的实测忙碌时间(每 25 ms 轮询一次 `eventLoopUtilization()`),因此热循环无论是否有诱饵 dispatch 在途都会到期,而等待慢绑定的程序不累计;`maxWallMs` 为忙碌时间无法观测的情况兜底,例如永远不会 resolve 的 promise。二者最终都会调用 `worker.terminate()``maxWallMs` 在加载时对照 `MAX_TIMER_DELAY_MS` 做范围校验,因为 `setTimeout` 会把更长的延迟限制为 1 ms。
### 输出账本
`maxOutputBytes` 统计外层 `logs` 数组加完成值或失败消息载荷的 JSON 序列化;固定的 `CodeRunResult` 字段名与信封语法不计入这份账本。未超过上限时返回精确值;有损完成值属于 `invalid-output`,组合溢出属于 `output-limit`,不会用 inspected string 代替。失败会保留日志中能容纳的已捕获前缀。
### 源码地图
| 文件 | 职责 |
|---|---|
| [`src/index.ts`](src/index.ts) | 插件入口:`Config` schema、`WorkerThreadCodeRuntime`、运行编排、输出账本 |
| [`src/worker.ts`](src/worker.ts) | 源码模式 worker 入口(可擦除 TypeScript,不依赖 `lib/` |
| [`src/bootstrap.ts`](src/bootstrap.ts) | worker 侧 bootstrap:命名空间物化、console shim、日志捕获 |
| [`src/protocol.ts`](src/protocol.ts) | host 与 worker 之间的端口消息词汇 |
| [`src/worker-json.ts`](src/worker-json.ts) | worker 侧无损 JSON 编解码 |
| [`src/output-json.ts`](src/output-json.ts) | 外层账本的字节计量与截断 |
| [`src/invariant.ts`](src/invariant.ts) | 不变式伴生插件(无运行时不变式;理由见其说明) |
### 未构建与已构建的 worker 入口
源代码模式通过 Node 原生类型剥离加载只包含可擦除语法的 `src/worker.ts`;其传递运行时闭包只包含 Node 内置模块和相对源模块,因此全新 checkout 绝不需要兄弟工作区包尚未构建的 `lib/` 导出。构建模式会把兄弟文件 `lib/worker.cjs` 作为文件系统路径传入,因为 pkg 的虚拟文件系统(VFSWorker hook 要求 CommonJS;同一路径也可在普通 Node 下使用。
</details>
-----
<a id="further-exploration"></a>
## 进一步探索
当后端约定不够用时阅读以下内容。它们从 seam 定义进入消费方与配置面。
- [代码运行时 seam](../code-runtime/README.zh.md)——此后端实现的抽象约定。
- [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md)——`dsh-tools` 如何消费 `ctx.codeRuntime` 并呈现 `run_code`
- [代码运行时子系统参考](../../../docs/subsystems/code-runtime.zh.md)——请求/结果词汇、绑定与失败分类体系。
- [生成配置目录](../../../docs/config-catalog.zh.md#deepseek-aidsh-code-runtime-worker-thread)——每个受支持配置字段及其源声明。
-----
<a id="model-experience"></a>
## 模型体验
通过 [`dsh-tools`](../../core/tools/README.zh.md) 中的 Code Mode 间接提供如果外层值能容纳则原样渲染,否则返回明确的 `invalid-output``output-limit` 失败只有外层 `run_code` 结果进入模型上下文并使用普通落盘策略;绑定通信与中间值始终只存在于执行环境中。
通过 `dsh-tools` 中的 Code Mode 间接提供如果外层值能容纳则原样渲染,否则返回明确的 `invalid-output``output-limit` 失败,且只有外层 `run_code` 结果在其普通落盘策略下进入模型上下文,绑定通信与中间值始终只存在于执行环境中。
#### KV Cache 影响
不会直接失效;由上述消费方负责请求前缀变更。
## 已知限制与暂缓事项
## 已知限制与延期工作
- **程序派生的 OS 进程在程序终止后仍会存活**:`worker.terminate()` 只结束线程,比 bash-local 的进程组终止更弱;在容器后端出现前,孤儿进程清理属于部署职责。
- **类型剥离依赖 Node 的实验性 `stripTypeScriptTypes` API**:如依赖的行为发生变化,amaro 或 sucrase 是已经点名的直接替代品。
- **`computeMs` 到期最多可能超过一个轮询间隔**:系统每 25 ms 采样一次忙碌时间(内部常量,有意不做成配置)。
- **程序获得一个含 5 个方法的 `console` shim**`log``info``warn``error``debug`):有意不提供 Node 的完整 console 接口
- **中间绑定值没有字节上限**:程序可以用永远不会成为外层输出的值耗尽进程或 worker 内存。
- **默认 64 MiB 是拒绝边界,不是可恢复存储**:外层落盘只能保存发生 `output-limit` 后返回的有界日志和诊断;在运行时上限之外被拒绝的字节永远不会到达落盘层
<a id="known-limitations-and-deferred-work"></a>
这些限制说明此后端何时不合适,或何时需要特别的运维注意。它们是当前包约束,不是任务积压
- **程序派生的 OS 进程在程序终止后仍会存活**——`worker.terminate()` 只结束线程,比 bash-local 的进程组终止更弱;在容器后端出现前,孤儿进程清理属于部署职责
- **类型剥离依赖 Node 的实验性 `stripTypeScriptTypes` API**——如依赖的行为发生变化,amaro 或 sucrase 是已经点名的直接替代品。
- **`computeMs` 到期最多可能超过一个轮询间隔**——系统每 25 ms 采样一次忙碌时间(内部常量,有意不做成配置)。
- **程序获得一个含 5 个方法的 `console` shim**`log``info``warn``error``debug`)——有意不提供 Node 的完整 console 接口。
- **中间绑定值没有字节上限**——程序可以用永远不会成为外层输出的值耗尽进程或 worker 内存。
- **默认 64 MiB 上限是拒绝边界,不是可恢复存储**——外层落盘只能保存发生 `output-limit` 后返回的有界日志和诊断;在运行时上限之外被拒绝的字节永远不会到达落盘层。
<a id="dev-note"></a>
### 开发备注
<details>
<summary>维护者的工作上下文——点击展开</summary>
无。
</details>