fix(rebase): migrate the replayed E2B branch onto the rebased parent

The linear replay carried old-lineage content over parent-owned files;
this checkpoint restores them and adapts the branch to the parent's
post-rebase seam:

- restore all pty/lsp/subprocess/code-runtime surfaces to the parent's
  exact content (this branch claims none of them) and drop the net-zero
  code-runtime-e2b/pty-e2b/lsp-e2b residue and its registrations
- widen serializeRemoteEnvironment to the seam's NodeJS.ProcessEnv
  tombstone contract: an explicit undefined removes an ambient entry
- migrate the two E2B fixture Agent stubs to the Inbox-model interface
  and Session.create
- re-apply the branch's gen-doc-graphs roles, THIRD_PARTY_NOTICES e2b
  row, and packages/README group row (trimmed to the doc budget);
  regenerate catalogs and re-record bilingual pairings
This commit is contained in:
Tianyi Cui
2026-08-07 21:04:33 +08:00
parent 6e1ae76c9b
commit d488330ba4
40 changed files with 1043 additions and 446 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/code-runtime/README.md
README.md: 34eecc4874afc5a576ed129e72eeeb944b95f67f
README.zh.md: 85d7a95a37cd1f4090062f3036a6634fde5011ee
README.md: f20a287419b94b1a9dc1d8da7303fc4d3032cfd3
README.zh.md: f5cd4c9949f2bd7a7d6d7cd078144910712a3819

View File

@@ -2,12 +2,11 @@
English | [中文](README.zh.md)
The code-execution capability seam (see [capability seams](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): an abstract runtime interface for executing one model-written program against host-provided async bindings, capturing what it printed and returned. The consumer is the tool registry's [Code Mode](../core/tools/README.md) (`tools: { mode: code }` — the `run_code` tool and the generated TypeScript SDK); design in the [Code Mode Agent Note](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). **Product** packages.
The code-execution capability seam (see [capability seams](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)): an abstract runtime interface for executing one model-written program against host-provided async bindings, capturing what it printed and returned. The consumer is the tool registry's [Code Mode](../core/tools/README.md) (`tools: { mode: code }` — the `run_code` tool and the SDK generated in the loaded runtime's `language`); design in the [Code Mode Agent Note](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md). **Product** packages.
| Package | Role | ctx key |
|---|---|---|
| `code-runtime/` | Abstract code-execution seam (interface + vocabulary) | `ctx.codeRuntime` |
| [`code-runtime-worker/`](code-runtime-worker/README.md) | Worker-thread backend: fresh worker per run, TypeScript via host-side type-strip (annotations advisory, never type-checked), port-bridged bindings, budget/heap containment | registers `ctx.codeRuntime` |
| [`e2b/code-runtime-e2b`](../e2b/code-runtime-e2b/README.md) | E2B backend: host type-strip and bindings, fresh remote runner/worker, framed bridge, remote process-group cleanup | registers `ctx.codeRuntime` |
| [`code-runtime/`](code-runtime/README.md) | Code-execution seam and shared vocabulary | `ctx.codeRuntime` |
| [`code-runtime-worker/`](code-runtime-worker/README.md) | Worker-thread backend | registers `ctx.codeRuntime` |
Backends differ by execution substrate and source language—both readonly descriptors on the service—and register `ctx.codeRuntime` without touching the interface or its consumer. The E2B ownership split is recorded in the [shared E2B runtime note](../../.agents/notes/implemented/feature/2026-07-27-e2b-remote-runtime-poc.md).
Backends register the seam without changing its consumer. The child READMEs own language, isolation, and execution-budget details.

View File

@@ -1,13 +1,12 @@
# code-runtime/代码执行能力家族
# code-runtime/代码执行能力家族
[English](README.md) | 中文
代码执行能力 seam参见[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):一个抽象运行时接口,用于对宿主提供的异步绑定执行一段模型编写的程序,并捕获程序打印和返回的内容。消费方是工具注册表的 [Code Mode](../core/tools/README.md)`tools: { mode: code }`,即 `run_code` 工具与生成的 TypeScript SDK设计记录在 [Code Mode Agent Note](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)。这些是**产品** 包。
代码执行能力 seam参见[能力 seam](../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):一个抽象运行时接口,用于对宿主提供的异步绑定执行模型编写的程序,并捕获打印和返回的内容。消费方是工具注册表的 [Code Mode](../core/tools/README.md)`tools: { mode: code }`,即 `run_code` 工具和按所加载运行时 `language` 生成的 SDK设计 [Code Mode Agent Note](../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)。这些是**产品**包。
| 包 | 职责 | ctx |
| 包 | 职责 | ctx key |
|---|---|---|
| `code-runtime/` | 抽象代码执行 seam(接口 + 词汇 | `ctx.codeRuntime` |
| [`code-runtime-worker/`](code-runtime-worker/README.md) | worker 线程后端:每次运行使用全新 worker由宿主侧剥离 TypeScript 类型(类型注解仅供参考,绝不执行类型检查)、端口桥接绑定、预算/堆隔离 | 注册 `ctx.codeRuntime` |
| [`e2b/code-runtime-e2b`](../e2b/code-runtime-e2b/README.md) | E2B 后端:宿主侧类型剥离与绑定、全新远程 runnerworker、分帧桥、远程进程组清理 | 注册 `ctx.codeRuntime` |
| [`code-runtime/`](code-runtime/README.md) | 代码执行 seam 与共享词汇 | `ctx.codeRuntime` |
| [`code-runtime-worker/`](code-runtime-worker/README.md) | Worker 线程后端 | 注册 `ctx.codeRuntime` |
不同后端的执行基底和源语言各异,二者都是服务上的只读描述符;后端注册 `ctx.codeRuntime`无需修改接口或消费方。E2B 所有权拆分记录在[共享 E2B 运行时 Agent Note](../../.agents/notes/implemented/feature/2026-07-27-e2b-remote-runtime-poc.md) 中
后端在不改变消费方的情况下注册该 seam。子 README 负责语言、隔离和执行预算细节

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime-worker/README.md
README.md: 35196a0b4fba5cd0388246a70354308ece08b39f
README.zh.md: 49871c38c540addd06f5d24793ae00b45e2f8bb0
README.md: 590b79dcd1bc322350060b55767b09c6305edacc
README.zh.md: 12c25f892bd20892cb47e593f16b6aadd9ffa84c

View File

@@ -32,7 +32,7 @@ Every field is validated and defaulted; `maxOutputBytes` is a safe integer of at
## The worker entry, unbuilt and built
Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Its transitive runtime closure contains only Node built-ins and relative source modules, so a fresh checkout never requires a sibling workspace package's unbuilt `lib/` export. The worker-local JSON snapshotter is parity-tested against the session-owned canonical boundary; both sides flatten and rebuild validated values around the message port so application nesting never reaches structured clone. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. `tests/built-lib.e2e.ts` pins the real load path required by [docs/testing.md](../../../docs/testing.md).
Source mode loads erasable-only `src/worker.ts` through Node's native type stripping. Its transitive runtime closure contains only Node built-ins and relative source modules, so a fresh checkout never requires a sibling workspace package's unbuilt `lib/` export. The worker-local and session-owned JSON boundaries both flatten and rebuild validated values around the message port so application nesting never reaches structured clone. Built mode passes the sibling `lib/worker.cjs` as a filesystem path because pkg's VFS Worker hook expects CommonJS; the same path works under ordinary Node. The repository-wide requirement to exercise this published entry path belongs to the [testing policy](../../../docs/testing.md).
The SDK surface is the default/named `WorkerCodeRuntime` class plus `Config`. The operational `./worker` subpath exists only as the packaged spawn entry; the wire protocol and bootstrap helpers are source-private implementation details.
@@ -46,8 +46,8 @@ No direct invalidation; the named consumer owns any request-prefix changes.
## Known Limitations and Deferred Work
- **OS processes a program spawns survive termination** — `worker.terminate()` ends the thread only; deployments requiring process-tree cleanup select `dsh-code-runtime-subprocess`, whose mounted subprocess provider owns that cleanup.
- **Type-strip rides Node's experimental `stripTypeScriptTypes` API** — the relied-on behavior is pinned by unit tests, with amaro/sucrase as named drop-in replacements if it shifts.
- **OS processes a program spawns survive termination** — `worker.terminate()` ends the thread only, weaker than bash-local's process-group kill; orphan cleanup is a deployment concern until a container backend exists.
- **Type-strip rides Node's experimental `stripTypeScriptTypes` API** — amaro or sucrase are the named drop-in replacements if the relied-on behavior shifts.
- **`computeMs` expiry can overshoot by up to one poll interval** — busy time is sampled every 25 ms (an internal constant, deliberately not config).
- **Programs get a five-method `console` shim** (`log`/`info`/`warn`/`error`/`debug`) — deliberately not Node's full console surface.
- **Intermediate binding values have no byte cap** — a program can exhaust process or worker memory with a value that never becomes outer output.

View File

@@ -23,18 +23,18 @@
- **每次运行使用一个全新 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__` 的绑定名称只是普通键。
- **绑定 reject 类属于请求数据**可选命名空间描述符会指定构造器全局变量以及用于接收失败成员名称的自有属性。worker 会创建并注入该真实类,使 `instanceof` 生效,同时无需硬编码 `tools``ToolCallError`;全局变量无效或冲突的声明会在启动 worker 前失败。失败路径使用模块捕获的错误与属性定义 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 会捕获自己 realm 中的普通容器原型身份,以及只用于外部 realm 的原生函数源码检查,因此构造器槽修改和用户编写的仿冒对象都无法改变容器分类。它还会捕获该 JSON 边界使用的每一个结构与计量 intrinsic以无原型对象创建属性描述符并绕过可变集合原型管理私有遍历状态因此模型对全局对象、原型方法或 `Object.prototype` 上形似描述符字段的修改都无法改变验证、wire 传输或字节计量。值会展平为有深度上限的前序 wire 值,供 structured clone 使用并在另一侧迭代式重建。它们没有字节、JavaScript 调用栈或嵌套 structured-clone 深度上限绝不会进入外层输出账本或模型上下文上限仍来自提供方执行器获取限制与进程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 标志。
- **释放资源时等待完全停稳**:清理会进行中的运行标记为 `abort`,并在 resolve 前等待每个 worker 退出。
- **绑定调用被拒绝时使用的异常类属于请求数据**:可选命名空间描述符会指定构造器全局变量,以及用于接收调用失败成员名称的自有属性。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 会捕获自己 realm 中的普通容器原型身份,以及只用于外部 realm 的原生函数源码检查,因此构造器槽修改和用户编写的仿冒对象都无法改变容器分类。它还会捕获该 JSON 边界使用的每一个结构与计量 intrinsic以无原型对象创建属性描述符并绕过可变集合原型管理私有遍历状态因此模型对全局对象、原型方法或 `Object.prototype` 上形似描述符字段的修改都无法改变验证、wire 传输或字节计量。值会展平为自身嵌套深度有界的前序 wire 值,供 structured clone 使用并在另一侧迭代式重建。它们没有字节、JavaScript 调用栈或嵌套 structured-clone 深度上限绝不会进入外层输出账本或模型上下文上限仍来自提供方执行器获取限制与进程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 入口
源代码模式通过 Node 原生类型剥离加载只包含可擦除语法的 `src/worker.ts`。其传递运行时闭包只包含 Node 内置模块和相对源模块,因此全新 checkout 绝不需要兄弟工作区包尚未构建的 `lib/` 导出。worker 本地 JSON 快照器会与会话自有的规范边界执行一致性测试;消息端口两侧都会展平并重建已验证值,使应用嵌套永远不会进入 structured clone。构建模式会把兄弟文件 `lib/worker.cjs` 作为文件系统路径传入,因为 pkg 的 VFS Worker hook 要求 CommonJS同一路径也可在普通 Node 下使用。`tests/built-lib.e2e.ts` 固定了 [docs/testing.md](../../../docs/testing.md) 要求的真实加载路径
源代码模式通过 Node 原生类型剥离加载只包含可擦除语法的 `src/worker.ts`。其传递运行时闭包只包含 Node 内置模块和相对源模块,因此全新 checkout 绝不需要兄弟工作区包尚未构建的 `lib/` 导出。worker 本地和会话自有的 JSON 边界都会在消息端口周围展平并重建已验证值,使应用嵌套永远不会进入 structured clone。构建模式会把兄弟文件 `lib/worker.cjs` 作为文件系统路径传入,因为 pkg 的虚拟文件系统(VFSWorker hook 要求 CommonJS同一路径也可在普通 Node 下使用。演练这个已发布入口路径的仓库级要求由[测试策略](../../../docs/testing.md)规定
SDK 接口是默认具名 `WorkerCodeRuntime` `Config`可操作`./worker` 子路径仅作为打包后的 spawn 入口存在wire 协议与启动辅助模块是源代码私有的实现细节。
SDK 对外提供默认具名导出的 `WorkerCodeRuntime`,以及 `Config`运行所用`./worker` 子路径仅作为打包后的 spawn 入口存在wire 协议与启动辅助模块是源代码私有的实现细节。
## 模型体验
@@ -42,13 +42,13 @@ SDK 接口是默认/具名 `WorkerCodeRuntime` 类与 `Config`。可操作的
#### KV Cache 影响
不会直接失效;由具名消费方负责请求前缀变更。
不会直接失效;由上述消费方负责请求前缀变更。
## 已知限制与暂缓工作
## 已知限制与暂缓事项
- **程序 spawn 的 OS 进程在终止后仍会存活**`worker.terminate()` 只结束线程;需要清理进程树的部署应选择 `dsh-code-runtime-subprocess`,由其挂载的子进程提供方负责该清理
- **类型剥离依赖 Node 的实验性 `stripTypeScriptTypes` API**:依赖的行为由单元测试固定;如其发生变化amarosucrase 是已经点名的直接替代品。
- **程序派生的 OS 进程在程序终止后仍会存活**`worker.terminate()` 只结束线程,比 bash-local 的进程组终止更弱;在容器后端出现前,孤儿进程清理属于部署职责
- **类型剥离依赖 Node 的实验性 `stripTypeScriptTypes` API**依赖的行为发生变化amarosucrase 是已经点名的直接替代品。
- **`computeMs` 到期最多可能超过一个轮询间隔**:系统每 25 ms 采样一次忙碌时间(内部常量,有意不做成配置)。
- **程序获得一个含 5 方法的 `console` shim**`log``info``warn``error``debug`):有意不提供 Node 的完整 console 接口。
- **程序获得一个含 5 方法的 `console` shim**`log``info``warn``error``debug`):有意不提供 Node 的完整 console 接口。
- **中间绑定值没有字节上限**:程序可以用永远不会成为外层输出的值耗尽进程或 worker 内存。
- **默认 64 MiB 是拒绝边界,不是可恢复存储**:外层落盘只能保存发生 `output-limit` 后返回的有界日志和诊断;在运行时上限之外被拒绝的字节永远不会到达落盘层。

View File

@@ -21,10 +21,6 @@ import { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from
import { decodeWorkerJson, encodeWorkerJson } from './worker-json.ts'
import type { WorkerJsonWire } from './worker-json.ts'
export { jsonStringBytesUpTo, jsonValueBytesUpTo, truncateJsonStringBytes } from './output-json.ts'
export { decodeWorkerJson, encodeWorkerJson } from './worker-json.ts'
export type { WorkerJsonWire } from './worker-json.ts'
/** Plugin config: every execution cap, changeable from `cordis.yml` (no hardcoded tunables). */
export interface Config {
/**
@@ -169,19 +165,14 @@ function parseWorkerMessage(raw: unknown): WorkerToHost | undefined {
}
/** Shared outer-output accounting for one isolated run; binding values never enter it. */
export class OutputLedger {
/** One run's combined outer-output ledger; binding values never enter it. */
class OutputLedger {
private bytes = 2 // JSON serialization of the empty logs array: []
private entries = 0
constructor(private readonly maxBytes: number) {}
/**
* Admit one exact log entry, or report that the hard cap was crossed.
* @param text - Candidate log entry.
* @param sink - Accepted log entries for the current run.
* @returns Whether the complete entry fits the remaining outer-output budget.
*/
/** Admit one exact log entry, or report that the hard cap was crossed. */
admit(text: string, sink: string[]): boolean {
const separatorBytes = this.entries > 0 ? 1 : 0
const stringBytes = jsonStringBytesUpTo(text, this.maxBytes - this.bytes - separatorBytes)
@@ -192,33 +183,19 @@ export class OutputLedger {
return true
}
/**
* Finalize a successful absent-or-JSON completion against the combined cap.
* @param logs - Already accepted log entries.
* @param value - Optional lossless-JSON completion value.
* @returns A success result or an output-limit failure.
*/
/** Finalize a successful absent-or-JSON completion against the combined cap. */
success(logs: string[], value?: CodeJsonValue): CodeRunResult {
if (value !== undefined && jsonValueBytesUpTo(value, this.maxBytes - this.bytes) === undefined) return this.limit(logs)
return { logs, ...value !== undefined ? { value } : {} }
}
/**
* Finalize a failure diagnostic, with output-limit taking precedence when combined bytes exceed the cap.
* @param logs - Already accepted log entries.
* @param error - Candidate failure diagnostic.
* @returns The diagnostic result or an output-limit failure.
*/
/** Finalize a failure diagnostic, with output-limit taking precedence when combined bytes exceed the cap. */
failure(logs: string[], error: CodeRunFailure): CodeRunResult {
if (jsonStringBytesUpTo(error.message, this.maxBytes - this.bytes) === undefined) return this.limit(logs)
return { logs, error }
}
/**
* Build the explicit output-limit failure while retaining a fitting prefix of the final log.
* @param logs - Candidate log entries in original order.
* @returns A capped output-limit result.
*/
/** Build the explicit output-limit failure while retaining a fitting prefix of the final log. */
limit(logs: string[]): CodeRunResult {
const fullMessage = `outer output exceeded ${this.maxBytes} bytes`
// The fixed diagnostic is ASCII, so every character is one byte plus the quotes.

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/code-runtime/code-runtime/README.md
README.md: c7690412d0f1bc8556fc758da4e94c6ce5a08d8f
README.zh.md: ecfa48a97c46113c52f13c7a6edfc5d6fbbc2285
README.md: bb1c20d00a260f643f601c42c6e48722437d5aab
README.zh.md: 15fbcecf77b2318acf3b09101802cd032ae426d2

View File

@@ -34,5 +34,5 @@ No direct invalidation; the named consumer owns any request-prefix changes.
- **`run()` is one-shot** — `logs` arrive only on the resolved `CodeRunResult`; the seam exposes no streaming-log or progress surface for a live program's output.
- **A persistent REPL-style kernel is recorded future work** — the no-state-between-runs contract stands until a persistent-kernel backend brings its own logging story ([Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md)).
- **Isolation is backend-specific** — the worker backend is process-local, while the E2B backend reports `container` and keeps orchestration and bindings on the host; the descriptor remains informational rather than a security claim.
- **Only the worker-thread backend ships** — `'process'`/`'container'` are declared well-known `isolation` values with no implementation; a hard security boundary awaits a container backend.
- **Intermediate binding values have no byte cap** — implementations remain subject to structured-clone cost and process memory, while a provider or executor may already have imposed its own acquisition bound.

View File

@@ -4,21 +4,23 @@
这是**代码执行 seam**:抽象的 `CodeRuntime` 服务(`ctx.codeRuntime`)只定义代码运行时做什么,即针对宿主提供的一组异步绑定运行一段模型编写的程序,并报告 `{ value, logs, error? }`,而不规定如何实现。
此包该能力的接口(以 bash 三包结构为模板,参见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):实现通过继承 `CodeRuntime` 并注册服务接入;消费方是工具注册表的 Code Mode它生成面向模型的 SDK并桥接工具分发。两者都由 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 规定,首个实现是 Node worker 线程后端。运行时不了解工具或会话:调用方只向它提供具名异步函数与程序字符串;所有工具形状的内容都留在消费方。
此包承担该能力三个组成部分中的接口职责(以 bash 三包结构为模板,参见[能力 seam](../../../.agents/notes/implemented/architecture/2026-06-13-capability-seams.md)):实现通过继承 `CodeRuntime` 并注册服务接入;消费方是工具注册表的 Code Mode它生成面向模型的 SDK并桥接工具分发。这两项职责均由 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md) 规定,首个实现是 Node worker 线程后端。运行时不了解工具或会话:调用方只向它提供具名异步函数与程序字符串;所有工具有关的内容都留在消费方。
## 服务 API`ctx.codeRuntime`
| 成员 | 语义 |
|---|---|
| `run(request)` | 针对请求的绑定执行一段程序。**每一种程序结果都通过 error 字段完成 resolve**:包括解析/转换失败、抛出异常、无效完成值、输出溢出、预算到期、中止或执行基底死亡(由 `CodeRunFailure` 的正交 `kind` 分类表示);只有调用方误用 seam 本身时才 reject例如资源释放后仍提交运行。程序作为异步函数的函数体运行因此顶层 `await``return` 可用,无损 JSON 完成值会成为 `result.value`。 |
| `language` | 只读描述符:`run` 期望的源语言已知值为 `'typescript'`。仅供参考,不作门禁;生成语言专用呈现的消费方会对该值执行分支,遇到无法呈现的语言时明确失败。 |
| `run(request)` | 针对请求的绑定执行一段程序。**所有程序失败结果都通过 resolve 结果中的 error 字段报告**:包括解析/转换失败、抛出异常、无效完成值、输出溢出、预算到期、中止或执行基底终止(由 `CodeRunFailure` 的正交 `kind` 分类表示);只有调用方误用 seam 本身时才 reject例如 dispose资源释放后仍提交运行)。程序作为异步函数的函数体运行,因此顶层 `await``return` 可用,无损 JSON 完成值会成为 `result.value`。 |
| `language` | 只读描述符:`run` 期望的源语言已知值为 `'typescript'``'python'`——`dsh-tools` 能呈现的那些;其中只有 `'typescript'` 有已发布的后端。仅供参考,不作门禁;生成语言专用呈现的消费方会根据该值选择分支,遇到无法呈现的语言时明确失败。 |
| `isolation` | 只读描述符:执行基底(`'worker-thread'``'process'``'container'`)。供部署与诊断使用,**不构成安全声明**。 |
每个实现都必须遵守以下语义(完整契约见类 JSDoc绑定调用会桥接完整的无损 JSON 参数与 resolve 值seam 层不设字节上限;程序被视为不可信对等方(任意绑定名称都自有属性,格式错误的通信绝不能使宿主崩溃);不同运行之间不保留任何状态;资源释放会终止进行中的运行,并且在完成前等待其退出。
每个实现都必须遵守以下语义(完整契约见类 JSDoc绑定调用会桥接完整的无损 JSON 参数与 resolve 值seam 层不设字节上限;程序被视为敌对对等方(任意绑定名称都会成为自有属性,格式错误的通信绝不能使宿主崩溃);不同运行之间不保留任何状态;dispose 会终止进行中的运行,并且在完成前等待其退出。
## 词汇
`CodeRunRequest``program``bindings``signal?`)携带运行时操作所需的全部内容;默认值解析(时间预算与外层输出上限)属于实现的已验证配置,绝不能是隐藏的 `??`,更不能藏在 `run()` 内部。`bindings``CodeBindingNamespace` 列表(`global` + `functions` + 可选 `errorClass`);每个命名空间会作为一个由异步可调用函数组成的全局对象公开给程序,这些函数返回 `CodeJsonValue`。后者是 seam 本地、与规范 `JsonValue` 结构等价的类型,使接口包保持独立于会话。`errorClass` 描述符点名真实的程序全局构造器,以及用于接收 reject 成员名称的自有属性;运行时不依赖 `ToolCallError` 等消费方术语。`CodeRunResult` 报告无损 JSON 完成值 `value?`、有序的 `logs: string[]``error?``CodeRunFailure``kind` + 可反馈给模型的 `message`)。完整契约见 `src/types.ts`
`CodeRunRequest``program``bindings``signal?`)携带运行时操作所需的全部内容;默认值解析(时间预算与外层输出上限)属于实现的已验证配置,绝不能是隐藏的 `??`,更不能藏在 `run()` 内部。`bindings``CodeBindingNamespace` 列表(`global` + `functions` + 可选 `errorClass`);每个命名空间会作为一个由异步可调用函数组成的全局对象公开给程序,这些函数返回 `CodeJsonValue`。后者是 seam 本地、与规范 `JsonValue` 结构等价的类型,使接口包保持独立于会话。`errorClass` 描述符点名真实的程序全局构造器,以及用于接收被拒绝成员名称的自有属性;运行时不依赖 `ToolCallError` 等消费方术语。`CodeRunResult` 报告无损 JSON 完成值 `value?`、有序的 `logs: string[]``error?``CodeRunFailure``kind` + 可反馈给模型的 `message`)。完整契约见 `src/types.ts`
binding-global 与 error-class 名称是**语言可移植**的:必须匹配标识符子集 `[A-Za-z_][A-Za-z0-9_]*`(不含 JS 专有的 `$`)并通过 seam 导出的排除集,因此同一份 `bindings` 列表对每个后端都有效,无论其 `language` 为何。本包导出每个后端都执行的契约——`PORTABLE_RESERVED_WORDS`ECMAScript Python 保留字)、`RESERVED_BINDING_GLOBALS`(如 `console` 等后端拥有的 global`RESERVED_ERROR_MEMBERS``DUNDER_MEMBER`error-member 排除)——因此 `$tools``lambda``__dsh_main__` 之类的名称会让 `run()` 在任何后端上作为 seam 误用而 reject而非只在某些后端。确切集合与理由见 `src/index.ts`
## 模型体验
@@ -26,11 +28,11 @@
#### KV Cache 影响
不会直接失效;由具名消费方负责请求前缀变更。
不会直接失效;由上述消费方负责请求前缀变更。
## 已知限制与暂缓工作
## 已知限制与暂缓事项
- **`run()` 是一次性的**`logs` 只有在 `CodeRunResult` resolve 后才能获得seam 不提供活跃程序输出的流式日志或进度接口。
- **`run()` 是一次性的**`logs` 只有在 `CodeRunResult` resolve 后才能获得seam 不提供正在运行的程序所产生输出的流式日志或进度接口。
- **持久 REPL 风格内核已记录为未来工作**:在持久内核后端带来自己的日志方案前,运行之间不保留状态的契约继续有效(参见 [Code Mode Agent Note](../../../.agents/notes/implemented/feature/2026-06-15-code-mode.md))。
- **隔离方式由后端决定**worker 后端位于宿主进程内,而 E2B 后端报告 `container`,并把编排与绑定留在宿主;该描述符仍只提供信息,不构成安全声明
- **目前只提供 worker 线程后端**`'process'``'container'` 是已经声明但没有实现的已知 `isolation` 值;强安全边界需要等待容器后端
- **中间绑定值没有字节上限**:实现仍受 structured-clone 成本与进程内存约束,而提供方或执行器可能已经应用自己的获取上限。