docs(i18n): align single-exe terminology

Add canonical Chinese bindings for build target, deploy root, peer
dependency, serving surface, wheel, wrapper, and VFS so future translations
have one source of truth. Apply the existing runtime, plugin, artifact, and
pipeline bindings throughout every Chinese counterpart touched by this PR.

Require the first Chinese use of peer dependency to retain the English term
so readers can map it back to the package-manager concept without
reintroducing mixed prose throughout the document.

Rewrite mixed-language prose where the English term is not an identifier,
while retaining package names, paths, flags, pkg, single-exe, and other
literal names exactly. Explain VFS on first use and keep technical constraints
readable without inventing compatibility terminology.

Describe single-executable worker support as implemented behavior, including
the filesystem-string entry contract and CommonJS worker artifact required by
the pkg loader, and remove the obsolete bundled-but-unsupported limitation.

Regenerate pairing fingerprints and the generated catalog reference so the
mechanical documentation gates validate the revised English and Chinese
pairs. This keeps the terminology table authoritative and prevents the two
languages from drifting as the runtime documentation evolves.
This commit is contained in:
Tianyi Cui
2026-07-13 22:09:41 +08:00
parent ebcfab1621
commit b49c37f83a
11 changed files with 69 additions and 62 deletions
+1 -1
View File
@@ -212,7 +212,7 @@ export interface Config {
} }
``` ```
Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:29`](../packages/code-runtime/code-runtime-worker/src/index.ts) Source: [`packages/code-runtime/code-runtime-worker/src/index.ts:30`](../packages/code-runtime/code-runtime-worker/src/index.ts)
## `@deepseek-ai/dsh-compact-basic` ## `@deepseek-ai/dsh-compact-basic`
+7
View File
@@ -22,6 +22,7 @@
| RAG | RAG | 首次出现可写:检索增强生成(RAG) | | RAG | RAG | 首次出现可写:检索增强生成(RAG) |
| SDK | SDK | | | SDK | SDK | |
| SSE | SSE | 首次出现可写:SSEServer-Sent Events | | SSE | SSE | 首次出现可写:SSEServer-Sent Events |
| VFS | VFS | 首次出现写:虚拟文件系统(VFS) |
| agent | agent | 首次出现可写:agent(智能体) | | agent | agent | 首次出现可写:agent(智能体) |
| agent loop | agent loop | | | agent loop | agent loop | |
| backlog | backlog | 双语翻译语境指待翻清单 | | backlog | backlog | 双语翻译语境指待翻清单 |
@@ -52,6 +53,7 @@
| block | 块 | | | block | 块 | |
| background task | 后台任务 | | | background task | 后台任务 | |
| backend | 后端 | | | backend | 后端 | |
| build target | 构建目标 | |
| capability | 能力 | | | capability | 能力 | |
| cancel | 取消 | | | cancel | 取消 | |
| checkpoint | 检查点 | | | checkpoint | 检查点 | |
@@ -66,6 +68,7 @@
| coverage | 覆盖率 | | | coverage | 覆盖率 | |
| crash recovery | 崩溃恢复 | | | crash recovery | 崩溃恢复 | |
| dispose | dispose | 首次出现可写:dispose(释放资源);正文优先保留英文 | | dispose | dispose | 首次出现可写:dispose(释放资源);正文优先保留英文 |
| deploy root | 部署根目录 | |
| durability | 持久性 | | | durability | 持久性 | |
| enforcement frontier | 强制边界 | i18n 机制词:manifest `required` 清单所划的门禁生效范围 | | enforcement frontier | 强制边界 | i18n 机制词:manifest `required` 清单所划的门禁生效范围 |
| event log | 事件日志 | | | event log | 事件日志 | |
@@ -95,6 +98,7 @@
| module | 模块 | | | module | 模块 | |
| orphan | 孤立 | git 官方中文同译(如「孤立分支」);指英文源已不存在的 `.zh.md`;不要译作:孤儿 | | orphan | 孤立 | git 官方中文同译(如「孤立分支」);指英文源已不存在的 `.zh.md`;不要译作:孤儿 |
| pairing | 配对 | | | pairing | 配对 | |
| peer dependency | 对等依赖 | 首次出现写:对等依赖(peer dependency |
| permission | 权限 | | | permission | 权限 | |
| persistence | 持久化 | | | persistence | 持久化 | |
| pipeline | 流水线 | | | pipeline | 流水线 | |
@@ -110,6 +114,7 @@
| runtime | 运行时 | | | runtime | 运行时 | |
| sandbox | 沙箱 | | | sandbox | 沙箱 | |
| service | 服务 | | | service | 服务 | |
| serving surface | 对外服务接口 | |
| session | 会话 | | | session | 会话 | |
| session event | 会话事件 | | | session event | 会话事件 | |
| smoke test | 冒烟测试 | | | smoke test | 冒烟测试 | |
@@ -133,4 +138,6 @@
| turn | 轮次 | | | turn | 轮次 | |
| typecheck | 类型检查 | | | typecheck | 类型检查 | |
| vocabulary | 词汇 | | | vocabulary | 词汇 | |
| wheel | wheel 包 | |
| workflow | 工作流 | | | workflow | 工作流 | |
| wrapper | 包装层 | |
@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority; # 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: # after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write # pnpm run verify-translation-pairing --write
2026-07-10-single-file-executable-sdk-runtime-distribution.md: 511f5f2cf8b43aac5960dfe4630f489ec3dc5086 2026-07-10-single-file-executable-sdk-runtime-distribution.md: ac392a80310e70c846e80b6660bab22e01acfeb2
2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md: 6774fc7ec2d9439154305ba0ae35dceeff922a4a 2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md: 021ca6a1c5c4b4214bf9dc16931c5b32a7117c9b
@@ -58,7 +58,7 @@ The exe's "must be explicitly configured" hard semantic is unchanged; the zero-c
## Disposition of worker-style plugins ## Disposition of worker-style plugins
`dsh-workflow-workerthread` and `dsh-code-runtime-worker` are supported inside the exe. Their built entries convert the sibling worker URL with `fileURLToPath()` and pass the resulting filesystem string to `Worker`, which is the form pkg's Worker hook resolves inside the VFS. The workflow engine keeps its data-URL bootstrap for unbuilt source execution; only its built sibling entry uses the filesystem string. The custom-config executable smoke loads both backends, invokes a real `run_code` call and a zero-agent `workflow` call, and requires each worker to return `42` from inside pkg's VFS. `dsh-workflow-workerthread` and `dsh-code-runtime-worker` are supported inside the exe. Their built hosts convert the sibling `lib/worker.cjs` URL with `fileURLToPath()` and pass the resulting filesystem string to `Worker`, which is the form pkg's Worker hook resolves inside the VFS. The worker entries are CommonJS because that hook compiles VFS worker files as CommonJS. The workflow engine keeps its data-URL bootstrap for unbuilt source execution; only its built sibling entry uses the filesystem string. The custom-config executable smoke loads both backends, invokes a real `run_code` call and a zero-agent `workflow` call, and requires each worker to return `42` from inside pkg's VFS.
## Testing ## Testing
@@ -6,80 +6,80 @@ Status: implemented
## 问题 ## 问题
DeepSeek Harness 需要为 Python 库专门提供一个免安装 Node、可直接在目标平台运行的 SDK 分发形态:一个单文件可执行程序(下称 exe),对外提供 stdio JSON-RPC 服务面`HarnessSdkServer`,Python SDK 的对端),且实际启动的插件与配置完全由 exe 外部输入的 `cordis.yml` 决定。 DeepSeek Harness 需要为 Python 库专门提供一种无需安装 Node、可直接在目标平台运行的 SDK 分发形态:一个单文件可执行程序(下称 exe),通过 stdio 提供 JSON-RPC 对外服务接口`HarnessSdkServer`,Python SDK 的对端),且实际启动的插件与配置完全由 exe 外部输入的 `cordis.yml` 决定。
- 与 Python SDK 通信的 JSONRPC 协议已经过验证 - 与 Python SDK 通信的 JSON-RPC 协议已经过验证
- 需要提供标准化 cordis.yml 加载所有插件(ESModule)的能力 - 需要提供通过标准化 `cordis.yml` 加载所有插件(ES 模块)的能力
- 分发物要自带 Node 运行时,并支持本地源码链接的调试模式 - 分发物要自带 Node 运行时,并支持本地源码链接的调试模式
## 决策 ## 决策
### 打包路线:@yao-pkg/pkg 的 `--sea` 模式 ### 打包路线:@yao-pkg/pkg 的 `--sea` 模式
exe 用 [@yao-pkg/pkg](https://github.com/yao-pkg/pkg)vercel/pkg 归档后的活跃维护 fork)的 **`--sea`enhanced SEA)模式**打包。相比 Node 原生 SEA,pkg 在其上加 `/snapshot` VFS 与运行时模块钩子,ESM 入口原样交给 Node 默认 ESM loader,不依赖任何 ESM→CJS 转译。 exe 使用 [@yao-pkg/pkg](https://github.com/yao-pkg/pkg)vercel/pkg 归档后的活跃维护 fork)的 **`--sea`enhanced SEA)模式**打包。相比 Node 原生 SEA,pkg 在其上`/snapshot` 虚拟文件系统(VFS与运行时模块钩子,ESM 入口原样交给 Node 默认 ESM loader,不依赖任何 ESM→CJS 转译。
> 实测(macos-arm64、node24 target、pkg 6.21.0):VFS 内裸包名 ESM 动态 import(含顶层 await)、CJS 互操作、`node:sqlite`、集合外包名 fail loud、VFS 外磁盘 ESM import 全部通过,`import.meta.url` 原样为 `file:///snapshot/...`。 > 实测(macos-arm64、node24 构建目标、pkg 6.21.0):VFS 内裸包名 ESM 动态 `import()`(含顶层 `await`)、CJS 互操作、`node:sqlite`、集合外包名明确报错、VFS 外磁盘 ESM `import()` 全部通过,`import.meta.url` 原样为 `file:///snapshot/...`。
`--sea` 要求 target ≥ node22exe 统一以 node24 为 target;单次 pkg 调用只打一个 target,多平台各调一次。 `--sea` 要求构建目标 ≥ node22exe 统一以 node24 为构建目标;每次 pkg 调用只打一个构建目标,多平台各调一次。
术语提醒:pkg 的 `/snapshot` VFS 与本仓库测试体系的「snapshot」(ACP replay goldens`$DSH_SNAPSHOT`)无关,本文用VFS指前者。 术语提醒:pkg 的 `/snapshot` VFS 与本仓库测试体系的“快照”(ACP 回放 golden、`$DSH_SNAPSHOT`)无关,本文用VFS指前者。
### serving 面是插件:ui/jsonrpc + ui/jsonrpc-agent 两包 ### 对外服务接口也是插件:ui/jsonrpc + ui/jsonrpc-agent 两包
确定性协议实现(`server.ts` / `transport.ts`)按 `ui/acp` + `ui/acp-agent` 的既有模式落为两包——serving 面本身也是插件: 确定性协议实现(`server.ts` / `transport.ts`)按 `ui/acp` + `ui/acp-agent` 的既有模式落为两包——对外服务接口本身也是插件:
- [`packages/ui/jsonrpc`](../../../../packages/ui/jsonrpc/README.md)`@deepseek-ai/dsh-jsonrpc`):纯协议插件apply 时在进程 stdio 上挂 `HarnessSdkServer` + 行式 JSON-RPC transportdisposal `ctx.effect()`。是否服务由 `cordis.yml` 决定;一份 yml 没挂它就是一个不 serve 的合法进程。协议级退出归插件`shutdown` 请求应答后 dispose 自身 fiber `exit(0)`HMR 式卸载只停服务不退进程)。 - [`packages/ui/jsonrpc`](../../../../packages/ui/jsonrpc/README.md)`@deepseek-ai/dsh-jsonrpc`):纯协议插件;执行 `apply`在进程 stdio 上挂 `HarnessSdkServer` 与按行传输的 JSON-RPC 层,资源释放`ctx.effect()`。是否提供服务由 `cordis.yml` 决定;未挂载该插件的配置会启动一个不提供此服务的合法进程。协议级退出归插件所有(应答 `shutdown` 请求后 dispose 自身 fiber,再调用 `exit(0)`HMR 式卸载只停服务不退进程)。
- [`packages/ui/jsonrpc-agent`](../../../../packages/ui/jsonrpc-agent/README.md)`@deepseek-ai/dsh-jsonrpc-agent`):薄 app bin——`installFailLoud` + `loadEnv` + 配置发现 + [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts) 的 `boot()`boot 完即毕,server 由 yml 里`dsh-jsonrpc` 条目带起。依赖只有 app-boot。进程级退出归 binstdin EOF/SIGTERM → dispose 后 0SIGINT → 130)。 - [`packages/ui/jsonrpc-agent`](../../../../packages/ui/jsonrpc-agent/README.md)`@deepseek-ai/dsh-jsonrpc-agent`):轻量应用入口——`installFailLoud` + `loadEnv` + 配置发现 + [`dsh-app-boot`](../../../../packages/ui/app-boot/src/index.ts) 的 `boot()``boot()` 完成后入口即完成,服务器由 `cordis.yml``dsh-jsonrpc` 条目启动。它只依赖 `app-boot`。进程级退出归 `bin` 所有stdin EOF/SIGTERM → dispose 后返回 0SIGINT → 130)。
配置发现通道,缺失即报错:`DSH_CORDIS_CONFIG` 环境变量优先(SDK 客户端约定),argv 位置参数次之;无任何默认路径或内置回退——实际启动的插件由外部 cordis.yml 决定是硬语义。 配置发现有两个通道,缺失时立即报错:优先使用 `DSH_CORDIS_CONFIG` 环境变量(SDK 客户端约定),其次使用 argv 位置参数;没有默认路径或内置回退——实际启动的插件由外部 `cordis.yml` 决定是硬语义。
### 插件解析:VFS 装真实包树,闭包清单即 deploy root ### 插件解析:VFS 装真实包树,闭包清单就是部署根目录
exe 的 VFS 内是**构建产物形态的真实包树**(各包 `lib/` + 真实 `node_modules`Loader 解析插件名走标准动态 `import()`:裸包名从 VFS 内 Loader 位置沿 `node_modules` 向上解析,然落在 VFS 内。封闭集不需要白名单代码——集合就是 VFS 装了什么,引用集合外的名字 import 失败。 exe 的 VFS 内是**构建产物形态的真实包树**(各包 `lib/` + 真实 `node_modules`。loader 通过标准动态 `import()` 解析插件名:裸包名从 VFS 内 loader 所在位置沿 `node_modules` 向上解析,然落在 VFS 内。封闭集不需要白名单代码——VFS 中安装了什么,集合中就有什么;`import()` 集合外的名称会失败。
deploy root 是 [`python/sdk-runtime/package.json`](../../../../python/sdk-runtime/package.json)`dsh-jsonrpc-agent-pkg`pnpm workspace 成员、零代码纯依赖清单)——「exe 装什么插件」与「Python runtime 分发什么」的合一事实源。 exe 加插件 = 清单加一行依赖再重打包。[`scripts/verify-runtime-closure.ts`](../../../../scripts/verify-runtime-closure.ts) 遍历该清单覆盖的全部 workspace 包,要求每个非 optional workspace peer 显式列在 runtime root,并报告引用包 → 缺失 peer」的完整链路;CI static、pre-push 与 single-exe 构建都会在打包前运行该门禁。deploy 还会按各包 `files` 打包,因此 tsdown 拆出的共享 chunk 必须被 `files` 覆盖。 部署根目录是 [`python/sdk-runtime/package.json`](../../../../python/sdk-runtime/package.json)`dsh-jsonrpc-agent-pkg`pnpm 工作区成员、零代码纯依赖清单),也是“exe 安装哪些插件”与“Python 运行时分发什么”的统一事实源。 exe 加插件,就是在清单中增加一行依赖后重新打包。[`scripts/verify-runtime-closure.ts`](../../../../scripts/verify-runtime-closure.ts) 遍历该清单覆盖的全部工作区包,要求每个非可选的工作区对等依赖(peer dependency)都显式列在运行时根目录,并报告引用包 → 缺失对等依赖”的完整链路;CI 静态检查、pre-push 与 single-exe 构建都会在打包前运行该门禁。部署还会依据各包 `files` 字段打包,因此 tsdown 拆出的共享分片必须被 `files` 覆盖。
### 构建管线与产物 ### 构建管线与产物
[`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts)runtime 闭包校验 → `pnpm run build` →(清空后)`pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **直** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/`→ 注入 pkg 配置(`bin` 指闭包内 `node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js``assets` 全量 glob——动态 import 对 pkg 静态分析不可见,必须显式全量打入)→ 每 target 一次 `pkg --sea` → 可执行文件 `dsh-jsonrpc-agent-pkg-<platform>-<arch>` `dist-exe/` 并拷回 runtime 目录。CI 把它们作为测试中间输入,只保留对应平台 wheel。deploy 四 flag 均有实测依据:`--legacy` 是未开 inject-workspace-packages 时的必选路径;hoisted 产出符号链接文件树(pkg VFS 最稳物理保证 cordis 实例);关 peer 自动安装避免未发布包名触发 registry 解析;link-workspace-packages 让闭包指向 workspace/vendor 源。 [`scripts/build-exe-for-python-sdk.ts`](../../../../scripts/build-exe-for-python-sdk.ts)运行时闭包校验 → `pnpm run build` →(清空后)`pnpm --filter dsh-jsonrpc-agent-pkg deploy --legacy --prod --config.node-linker=hoisted --config.auto-install-peers=false --config.link-workspace-packages=true` **直接写入** `python/sdk-runtime/src/deepseek_harness_runtime/runtime/node/` → 注入 pkg 配置(`bin`闭包内 `node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js``assets` 使用全量 glob,因为动态 `import()` 对 pkg 静态分析不可见,必须显式打入全部内容)→ 每个构建目标调用一次 `pkg --sea` → 可执行文件 `dsh-jsonrpc-agent-pkg-<platform>-<arch>` 写入 `dist-exe/`并拷回运行时目录。CI 将这些文件作为测试中间输入,只保留对应平台 wheel 包。四个部署标志都有实测依据:未启用 `inject-workspace-packages` 时必须使用 `--legacy``hoisted` 产出符号链接文件树(pkg VFS 最稳定,并从物理保证只有一个 Cordis 实例);关闭对等依赖自动安装避免未发布包名触发注册表解析;`link-workspace-packages` 让闭包指向工作区/vendor 源
CI[`.github/workflows/build-exe-for-python-sdk.yml`](../../../../.github/workflows/build-exe-for-python-sdk.yml)仅显式触发——`workflow_dispatch` 手动派发,或给 PR `build-exe` 标签linux-x64 / linux-arm64`ubuntu-24.04-arm`/ macos-arm64 三平台原生构建,并缓存 `~/.pkg-cache`macOS ad-hoc 签名由 pkg 处理。每个平台都以 mock SSE 模型分别通过默认配置和自定义 `cordis.yml` 驱动 SDK,再 NDJSON JSON-RPC 直接驱动 exe,校验 JSONL 与最终响应最后把 release 形态的 wheel 安装到干净 venv 中并在不传 `runtime_bin` 的情况下运行Linux 还检查 GLIBC 依赖并在 manylinux 2.28 容器中运行。整次运行只保留 4 个产物,每个只含一个发布文件:平台无关的 SDK wheel 3 个原生 runtime wheel;裸 exe 源码 bundle 只作为测试中间输入。[`.gitlab-ci.yml`](../../../../.gitlab-ci.yml) 只接受版本与根目录 `package.json` 匹配的 `python-vX.Y.Z` tag 流水线,构建一个 SDK wheel 3 个原生 runtime wheel,再由单个串行 job 校验并发布这 4 个文件到项目 PyPI 注册表。Windows 是非目标 CI 使用 [`.github/workflows/build-exe-for-python-sdk.yml`](../../../../.github/workflows/build-exe-for-python-sdk.yml)且只允许显式触发:手动派发 `workflow_dispatch`,或给 PR 添加 `build-exe` 标签linux-x64linux-arm64`ubuntu-24.04-arm` macos-arm64 三平台分别进行原生构建,并缓存 `~/.pkg-cache`macOS ad-hoc 签名由 pkg 处理。每个平台都使用模拟 SSE 模型分别通过默认配置和自定义 `cordis.yml` 驱动 SDK,再通过 NDJSON JSON-RPC 直接驱动 exe,校验 JSONL 与最终响应最后把发布形态的 wheel 安装到干净 venv 中并在不传 `runtime_bin` 的情况下运行Linux 还检查 GLIBC 依赖并在 manylinux 2.28 容器中运行。整次运行只保留 4 个产物,每个产物只含一个发布文件:平台无关的 SDK wheel 包和 3 个原生运行时 wheel;裸 exe 源码只作为测试中间输入。[`.gitlab-ci.yml`](../../../../.gitlab-ci.yml) 只接受版本与根目录 `package.json` 匹配的 `python-vX.Y.Z` 标签流水线,构建一个 SDK wheel 包和 3 个原生运行时 wheel,再由单个串行任务校验并这 4 个文件发布到项目 PyPI 注册表。Windows 不在目标范围内
### Python SDK 分发:双载体,exe 为生产、node 为开发 ### Python SDK 分发:双载体,exe 用于生产,`node` 用于开发
Python SDK 位于 [`python/`](../../../../python/README.md)`python/sdk`客户端+ `python/sdk-runtime`运行时载体包)。runtime 包数据目录三类内容:检入的默认 `runtime/cordis.yml`、构建注入的平台 exe构建注入的 `runtime/node/` 闭包树。`resolve_bundled_launch_args()` 自动解析**只找 exe**;node 载体仅显式 `DSH_RUNTIME_MODE=node` 启用( `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`,需系统 node ≥22.19),定位本仓库成员的开发验证通道,不 wheel 分发 Python SDK 位于 [`python/`](../../../../python/README.md)`python/sdk`客户端`python/sdk-runtime`运行时载体包。运行时包的数据目录包含三类内容:检入的默认 `runtime/cordis.yml`、构建注入的平台 exe,以及构建注入的 `runtime/node/` 闭包树。`resolve_bundled_launch_args()` 自动解析**只找 exe**`node` 载体仅显式设置 `DSH_RUNTIME_MODE=node` 启用(运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`,需系统 Node ≥22.19),定位本仓库成员的开发验证通道,不 wheel 分发。
[`scripts/build-python-release.py`](../../../../scripts/build-python-release.py) 从仓库根目录 `package.json` 读取权威的稳定 `X.Y.Z`以该版本暂存两个包,同时让 SDK 精确依赖 `deepseek-harness-runtime-bin==X.Y.Z`。可选的 `python-vX.Y.Z` 发布 tag 只是一项一致性断言,与仓库版本不同时会被拒绝;源码 `pyproject.toml` 中的开发占位版本从不决定发布版本。SDK 是 `py3-none-any` wheel;只提供 wheel 的 runtime 包恰好包含一个 exetag `py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`。其 Hatch 钩子拒绝 sdist、通用 tag、混合可执行载荷以及不支持的平台。 [`scripts/build-python-release.py`](../../../../scripts/build-python-release.py) 从仓库根目录 `package.json` 读取权威的稳定版本 `X.Y.Z`,以该版本暂存两个包,让 SDK 精确依赖 `deepseek-harness-runtime-bin==X.Y.Z`。可选的 `python-vX.Y.Z` 发布标签只是一项一致性断言,与仓库版本不同时会被拒绝;源码 `pyproject.toml` 中的开发占位版本从不决定发布版本。SDK 是 `py3-none-any` wheel;只提供 wheel 包的运行时包恰好包含一个 exe标签`py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`。其 Hatch 钩子拒绝 sdist、通用标签、混合可执行载荷以及不支持的平台。
exe必须显式配置的硬语义不变;零配置体验由 wrapper 恢复:调用方没 `cordis`、没显式指定 runtime、环境无 `DSH_CORDIS_CONFIG` 时,客户端检入的默认 `cordis.yml`agent-core + 预载 llm-deepseek + JSONL 持久化 + bash-local + `dsh-jsonrpc` serving 条目,`!!js` 环境变量兜底)显式注入 `DSH_CORDIS_CONFIG` exe必须显式配置的硬语义不变;零配置体验由包装层恢复:调用方没有提供 `cordis`、没显式指定运行时,且环境中没有 `DSH_CORDIS_CONFIG` 时,客户端检入的默认 `cordis.yml``agent-core` + 预载`llm-deepseek` + JSONL 持久化 + `bash-local` + `dsh-jsonrpc` 对外服务条目,并通过 `!!js` 使用环境变量兜底)显式注入 `DSH_CORDIS_CONFIG`
### 命名血统 ### 命名血统
`@deepseek-ai/dsh-jsonrpc-agent`(包)→ `dsh-jsonrpc-agent`bin)→ `dsh-jsonrpc-agent-pkg`(闭包清单;无 scope 前缀,刻意避开 constraints 对 `@deepseek-ai/dsh-*` 的包形状规则)→ `dsh-jsonrpc-agent-pkg-<platform>-<arch>`exe 产物)。wire `serverInfo.name` 保持 `deepseek-harness-sdk-runtime`(协议稳定值);Python dist 名为 `deepseek-harness` / `deepseek-harness-runtime-bin` `@deepseek-ai/dsh-jsonrpc-agent`(包)→ `dsh-jsonrpc-agent``bin`)→ `dsh-jsonrpc-agent-pkg`(闭包清单;没有作用域前缀,刻意避开 `constraints``@deepseek-ai/dsh-*` 的包形状规则)→ `dsh-jsonrpc-agent-pkg-<platform>-<arch>`exe 产物)。协议字段 `serverInfo.name` 保持 `deepseek-harness-sdk-runtime`(协议稳定值);Python 分发名为 `deepseek-harness` / `deepseek-harness-runtime-bin`
## 工作线程插件 ## 工作线程插件
exe 内支持 `dsh-workflow-workerthread``dsh-code-runtime-worker`。两个后端构建入口都通过 `fileURLToPath()` 转换相邻 worker 的 URL,再将所得文件系统字符串传给 `Worker`pkg 的 Worker 钩子可以用这种形式解析 VFS 内文件。工作流引擎在未构建的源码执行中仍保留 data URL 引导程序,只有构建后的相邻入口使用文件系统字符串。自定义配置的可执行文件冒烟测试会加载两个后端,实际调用 `run_code` 与不启动 agent 的 `workflow`,并要求两个 worker 都从 pkg 的 VFS 内返回 `42` exe 内支持 `dsh-workflow-workerthread``dsh-code-runtime-worker`。两个后端构建后的宿主都通过 `fileURLToPath()` 转换相邻 `lib/worker.cjs` 的 URL,再将所得文件系统字符串传给 `Worker`pkg 的 Worker 钩子可以用这种形式解析 VFS 内文件。该钩子会把 VFS 内的工作线程文件作为 CommonJS 编译,所以工作线程入口采用 CommonJS。工作流引擎在未构建的源码执行中仍保留 `data:` URL 引导程序,只有构建后的相邻入口使用文件系统字符串。自定义配置的可执行文件冒烟测试会加载两个后端,实际调用 `run_code` 与不启动 agent 的 `workflow`,并要求两个工作线程都从 pkg 的 VFS 内返回 `42`
## 测试 ## 测试
验证面分三层。机制层:`--sea` 链路的实测结论内嵌在决策各节(VFS 内 ESM 动态 import、cordis 实例、fail-loud 配置链路、`node:sqlite`、macOS ad-hoc 签名可运行)。SDK 层:完整的 keyless pytest 套件以假运行时对端覆盖客户端协议、子进程清理、绝对 cwd 传递、双载体启动与载体解析;根 CI 在 Python 3.10 上运行全部用例。端到端层:每个平台构建都通过默认 SDK 路径、自定义配置和直接二进制协议对着 mock 端点完成一个轮次,并校验最终文本与 JSONL。自定义配置还会通过打包进 VFS 的真实 worker 文件执行 `run_code` 和不启动 agent 的 `workflow`。随后把平台 wheel 安装进干净 venv,在不传 `runtime_bin` 的情况下运行。JSON-RPC 协议不在 ACP snapshot 体系内,无 snapshot 层(点名后的明确空缺,非遗漏)。 验证面分三层。机制层:`--sea` 链路的实测结论内嵌在决策各节(VFS 内 ESM 动态 `import()`、单一 Cordis 实例、明确报错的配置链路、`node:sqlite`、macOS ad-hoc 签名可运行)。SDK 层:完整的无密钥 pytest 套件以假运行时对端覆盖客户端协议、子进程清理、绝对 `cwd` 传递、双载体启动与载体解析;根 CI 在 Python 3.10 上运行全部用例。端到端层:每个平台构建都通过默认 SDK 路径、自定义配置和直接二进制协议,对模拟端点完成一个轮次,并校验最终文本与 JSONL。自定义配置还会通过打包进 VFS 的真实工作线程文件执行 `run_code` 和不启动 agent 的 `workflow`。随后把平台 wheel 安装进干净 venv在不传 `runtime_bin` 的情况下运行。JSON-RPC 协议不在 ACP 快照体系内,因此没有快照层(这是明确指出的空缺,非遗漏)。
手工驱动注意:bin stdin EOF 为「客户端已走」并立即 dispose,短命管道会中止在飞回合——管道驱动必须保持 stdin 打开到回合结束。 手工驱动注意:`bin` stdin EOF 视为“客户端已离开”并立即 dispose,短命管道会中止进行中的轮次——管道驱动必须保持 stdin 打开,直到轮次结束。
## 曾考虑的替代方案 ## 曾考虑的替代方案
**Node 原生 SEA 裸用** 注入主脚本必须是 CJS 单文件blob 内文件系统与模块解析,动态 import 裸包名无从解析,只能把插件静态编译进主脚本并手工注册——绕过标准模块解析、插件集合被硬编码,与配置决定一切相悖。最终路线实为「官方 SEA 基 + pkg 的 VFS/模块钩子层」,否掉的是裸用而非 SEA 本身。 **裸用 Node 原生 SEA。** 注入主脚本必须是 CJS 单文件blob 内没有文件系统与模块解析,因此动态 `import()` 无法解析裸包名;只能把插件静态编译进主脚本并手工注册。这会绕过标准模块解析并硬编码插件集合,与配置决定一切相悖。最终路线实际是“官方 SEA 基 + pkg 的 VFS/模块钩子层”;否决的是裸用方式,而不是 SEA 本身。
**pkg standard 模式。** PoC 判死,非取舍:它把 ESM 经 esbuild CJS + V8 字节码,运行时 vm 编译未接动态 import 回调,任何 `import()` 一律抛 `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING``--options experimental-require-module` 无效;依赖社区补丁 Node 二进制(macos-arm64 预编译,现场源码编译约 10 分钟)。本仓库架构零可行性 **pkg 标准模式。** PoC 证明该模式不可行,而非权衡后放弃:它通过 esbuild 将 ESM 转为 CJS + V8 字节码,运行时 VM 编译没有接入动态 `import()` 回调,任何 `import()` 都会抛出 `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING``--options experimental-require-module` 无效;此外,它依赖社区补丁 Node 二进制(macos-arm64 没有预编译版本,现场源码编译约 10 分钟)。该模式不适用于本仓库架构。
**每包 ESM→CJS 预打包进 VFS。** 保持真实解析语义、只降级模块格式的折中;`--sea` 直接通过实测,这层构建复杂度无需引入。 **每包 ESM→CJS 预打包进 VFS。** 保持真实解析语义、只降级模块格式的折中;`--sea` 直接通过实测,这层构建复杂度无需引入。
**jsonrpc-agent 背全量闭包依赖。** app bin 声明 53+它不 import 的依赖,打包清单」冒充真实依赖关系,迫使 constraints 为其cordis-in-dependencies 与 files-通配两个例外。闭包清单python 侧的清单包上,constraints 无需任何例外,bin 保持与 acp-agent 同构的正常包形状。 **jsonrpc-agent 承担完整闭包依赖。** 应用入口将声明 53 个以上自身并不 `import()` 的依赖,使“打包清单”伪装成真实依赖关系,还会迫使 `constraints` 为其增加 `cordis-in-dependencies``files` 通配两个例外。闭包清单Python 侧的清单包后,`constraints` 不需要任何例外,`bin` 也能保持与 acp-agent 同构的正常包形状。
**开放插件集(磁盘加载用户插件)。** 本期封闭集;PoC 顺带证实 VFS 外磁盘 ESM import 可行(经 `ctx.baseUrl` 相对路径通道),列为后续演进,需另解外部插件与 exe 内 cordis 实例的共享问题。 **开放插件集(磁盘加载用户插件)。** 本期采用封闭集;PoC 同时证实,可以通过 `ctx.baseUrl` 相对路径通道从 VFS 外的磁盘 `import()` ESM。该能力列为后续演进,届时还需解决外部插件与 exe 内 Cordis 实例的共享问题。
## 后果 ## 后果
**买到的**:目标平台零依赖单文件分发;插件语义与源码运行严格一致(同一棵真实包树,无转译无注册表);serving 面、插件集配置三者全部收敛到 `cordis.yml` + 一份依赖清单两个事实源;exe 与 node 双载体同树同语义,开发验证不必等打包;官方 Node 二进制消除了补丁二进制供应链顾虑。 **买到的**:目标平台零依赖单文件分发;插件语义与源码运行严格一致(同一棵真实包树,无转译无注册表);对外服务接口、插件集配置全部收敛到 `cordis.yml` 一份依赖清单两个事实源;exe 与 `node` 双载体使用同一棵树和相同语义,开发验证无需等待打包;官方 Node 二进制消除了补丁二进制供应链顾虑。
**付出的**:产物 174MB且源码原样进 blob字节码混淆闭源分发诉求需另行评估);pkg 的 VFS/模块钩子层仍社区维护(构建脚本钉死 `@yao-pkg/pkg@6.21.0`,升级显式改动);`--sea` 每个 target 调用一次(与 CI 每平台一匹配,本地多平台构建串行)。 **付出的**:产物 174MB且源码原样进 blob没有字节码混淆闭源分发诉求需另行评估);pkg 的 VFS/模块钩子层仍社区维护(构建脚本钉死 `@yao-pkg/pkg@6.21.0`,升级需要显式改动);`--sea` 每个构建目标调用一次(与 CI 每平台一个任务相匹配,本地多平台构建串行执行)。
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with: # after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write # pnpm run verify-translation-pairing --write
README.md: 35ed645ce0e4d5e4c88c8aae2fe33d94aea79b3e README.md: 35ed645ce0e4d5e4c88c8aae2fe33d94aea79b3e
README.zh.md: bddb709114df2e46bbea6e6faeb660bffa30df2b README.zh.md: 214c5cd1900e52f9fe479247f9940a97bb22766b
+9 -9
View File
@@ -2,11 +2,11 @@
[English](README.md) | 中文 [English](README.md) | 中文
以子进程方式驱动 DeepSeek Harness 的 Python 包:客户端 SDK spawn `dsh-jsonrpc-agent` 二进制, stdio 上以换行分隔的 JSON-RPC 与之通信。运行时载体是本仓库产出的单文件可执行文件;设计、构建与验收细节见 [docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md](../docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md)。 以子进程方式驱动 DeepSeek Harness 的 Python 包:客户端 SDK spawn `dsh-jsonrpc-agent` 二进制,并通过 stdio 上行分隔的 JSON-RPC 与之通信。运行时载体是本仓库产出的单文件可执行文件;设计、构建与验收细节见 [docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md](../docs/rfc/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md)。
## 包 ## 包
| 目录 | Dist / 模块 | 职责 | | 目录 | 分发名 / 模块 | 职责 |
|---|---|---| |---|---|---|
| [sdk](sdk/) | `deepseek-harness` / `deepseek_harness` | 客户端 SDK:高层回合 API `DeepSeekHarness` 与低层 JSON-RPC 客户端 `HarnessClient` | | [sdk](sdk/) | `deepseek-harness` / `deepseek_harness` | 客户端 SDK:高层回合 API `DeepSeekHarness` 与低层 JSON-RPC 客户端 `HarnessClient` |
| [sdk-runtime](sdk-runtime/) | `deepseek-harness-runtime-bin` / `deepseek_harness_runtime` | 运行时载体:定位内置的运行时二进制,并携带默认的 agent(智能体)配置 | | [sdk-runtime](sdk-runtime/) | `deepseek-harness-runtime-bin` / `deepseek_harness_runtime` | 运行时载体:定位内置的运行时二进制,并携带默认的 agent(智能体)配置 |
@@ -22,7 +22,7 @@ pnpm exec tsx scripts/build-exe-for-python-sdk.ts --skip-build # lib/ artifac
pnpm exec tsx scripts/build-exe-for-python-sdk.ts --targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64 pnpm exec tsx scripts/build-exe-for-python-sdk.ts --targets=node24-linux-x64,node24-linux-arm64,node24-macos-arm64
``` ```
产物落入 `dist-exe/`,并同步进本包的 `sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-pkg-<platform>-<arch>`platform`linux`/`macos`arch`x64`/`arm64`),本地构建完成后 SDK 不需要额外设置就能找到可执行文件。`build-exe-for-python-sdk` CI 工作流(手动触发,或给 PR 打 `build-exe` 标签)会测试同样的二进制,但只保留 4 个发布 wheel。exe 内置哪些插件、载体如何组织,见 [sdk-runtime README](sdk-runtime/README.md);构建还会顺带刷新仅供开发用的 node 载体(见下文「对着 Node 源码运行」)。 产物落入 `dist-exe/`,并同步进本包的 `sdk-runtime/src/deepseek_harness_runtime/runtime/dsh-jsonrpc-agent-pkg-<platform>-<arch>`platform`linux`/`macos`arch`x64`/`arm64`),本地构建完成后 SDK 不需要额外设置就能找到可执行文件。`build-exe-for-python-sdk` CI 工作流(手动触发,或给 PR 打 `build-exe` 标签)会测试同样的二进制,但只保留 4 个发布 wheel。exe 内置哪些插件、载体如何组织,见 [sdk-runtime README](sdk-runtime/README.md);构建还会顺带刷新仅供开发使用的 `node` 载体(见下文「对着 Node 源码运行」)。
## 用可执行文件验证 SDK ## 用可执行文件验证 SDK
@@ -45,12 +45,12 @@ with DeepSeekHarness() as harness:
两种方式,均面向仓库成员: 两种方式,均面向仓库成员:
- **已构建的 node 载体**——设置 `DSH_RUNTIME_MODE=node`SDK 会用系统 Node>= 22.19)运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`。这棵树每次构建脚本都会刷新,与 exe 打VFS 的是同一份依赖闭包,插件语义一致。不会被自动选中,也不进入分发物。 - **已构建的 `node` 载体**——设置 `DSH_RUNTIME_MODE=node`SDK 会用系统 Node>= 22.19)运行 `runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js`。这棵树每次运行构建脚本都会刷新,与 exe 打入 pkg 虚拟文件系统(VFS的是同一份依赖闭包,因此插件语义一致。不会被自动选中,也不进入分发物。
- **未构建的源码(tsx)**——把客户端直接指向 bin 的 TypeScript 源码,用于编辑-运行循环与调试:`launch_args_override=("./node_modules/.bin/tsx", "packages/ui/jsonrpc-agent/src/bin.ts")``cwd` 设为仓库根,另经 `cordis=...` 传入配置(或依赖默认配置注入)。[sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) 是现成范例。 - **未构建的源码(tsx)**——把客户端直接指向 `bin` 的 TypeScript 源码,用于编辑运行调试:`launch_args_override=("./node_modules/.bin/tsx", "packages/ui/jsonrpc-agent/src/bin.ts")``cwd` 设为仓库根,再通过 `cordis=...` 传入配置(或使用默认配置注入)。[sdk/tests/manual_sdk_agent_smoke.py](sdk/tests/manual_sdk_agent_smoke.py) 是现成范例。
## 分发 Python 包 ## 分发 Python 包
根目录 [`package.json`](../package.json) 的版本是两个 Python 分发物的权威版本。统一暂存脚本读取这个版本并注入两个 wheel,同时在 SDK 元数据中钉死相同版本的 `deepseek-harness-runtime-bin==X.Y.Z`;可选的 `python-vX.Y.Z` 发布 tag 只有与仓库版本匹配时才会被接受。纯 SDK wheel 只构建一次,runtime wheel 则在每个原生平台各构建一个: 根目录 [`package.json`](../package.json) 的版本是两个 Python 分发物的权威版本。统一暂存脚本读取这个版本并注入两个 wheel,同时在 SDK 元数据中钉死相同版本的 `deepseek-harness-runtime-bin==X.Y.Z`;可选的 `python-vX.Y.Z` 发布标签只有与仓库版本匹配时才会被接受。纯 SDK wheel 只构建一次,运行时 wheel 则在每个原生平台各构建一个:
```sh ```sh
version="$(node -p "require('./package.json').version")" version="$(node -p "require('./package.json').version")"
@@ -59,11 +59,11 @@ python scripts/build-python-release.py --package runtime --platform macos-arm64
pip install --find-links dist-python deepseek-harness=="$version" pip install --find-links dist-python deepseek-harness=="$version"
``` ```
runtime 分发物只提供 wheel,并拒绝 sdist 构建、缺失可执行文件以及混合平台载荷。三个 wheel tag 分别是 `py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`SDK 保持 `py3-none-any`。匹配的 `python-vX.Y.Z` tag 流水线统一构建并发布这 4 个互不冲突的文件,因此常规的 `pip install deepseek-harness==X.Y.Z` 会选中匹配平台的 runtime wheel`import deepseek_harness` 不需要 `runtime_bin` 运行时分发物只提供 wheel,并拒绝 sdist 构建、缺失可执行文件以及混合平台载荷。三个 wheel 包标签分别是 `py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`SDK 保持 `py3-none-any`。匹配的 `python-vX.Y.Z` 标签流水线统一构建并发布这 4 个互不冲突的文件,因此常规的 `pip install deepseek-harness==X.Y.Z` 会选中匹配平台的运行时 wheel`import deepseek_harness` 不需要 `runtime_bin`
## 零配置语义 ## 零配置语义
运行时二进制本身始终要求显式配置(`$DSH_CORDIS_CONFIG`,或作为首个 argv 参数的配置路径),没有内置兜底,也只启动配置里列出的东西。零配置是 SDK 包装层的行为:调用方没有任何显式通道时,客户端把 runtime 包检入的默认配置([runtime/cordis.yml](sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml))注入 `DSH_CORDIS_CONFIG`;任一显式通道存在即胜出并禁用注入。注入条件的完整定义见 [sdk README](sdk/README.md),默认配置的内容与硬语义见 [sdk-runtime README](sdk-runtime/README.md)。 运行时二进制本身始终要求显式配置(`$DSH_CORDIS_CONFIG`,或作为首个 argv 参数的配置路径),没有内置兜底,也只启动配置里列出的内容。零配置是 SDK 包装层的行为:调用方没有使用任何显式通道时,客户端把运行时包检入的默认配置([runtime/cordis.yml](sdk-runtime/src/deepseek_harness_runtime/runtime/cordis.yml))注入 `DSH_CORDIS_CONFIG`;任一显式通道存在即优先采用,并禁用注入。注入条件的完整定义见 [sdk README](sdk/README.md),默认配置的内容与硬语义见 [sdk-runtime README](sdk-runtime/README.md)。
可执行文件也支持直接调用;在 NDJSON JSON-RPC 交互期间保持 stdin 打开,并显式提供配置: 可执行文件也支持直接调用;在 NDJSON JSON-RPC 交互期间保持 stdin 打开,并显式提供配置:
@@ -73,4 +73,4 @@ DSH_CORDIS_CONFIG=/absolute/path/cordis.yml ./dsh-jsonrpc-agent-pkg-macos-arm64
## 测试布局 ## 测试布局
`test_client.py` 完全无需 key(对端是 Python 假运行时)。`test_bundled_runtime.py` 逐个启动内置载体,某载体产物缺失时对应用例跳过`test_runtime_resolution.py` 覆盖载体解析规则,不 spawn 任何进程。 `test_client.py` 完全无需密钥(对端是 Python 假运行时)。`test_bundled_runtime.py` 逐个启动内置载体,某载体产物缺失时跳过对应用例。`test_runtime_resolution.py` 覆盖载体解析规则,不 spawn 任何进程。
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with: # after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write # pnpm run verify-translation-pairing --write
README.md: 4beac57526761bb150e90b60f0030ed311c4034d README.md: 4beac57526761bb150e90b60f0030ed311c4034d
README.zh.md: 3c715bce17ed1630ef0439b042d2b67047968c55 README.zh.md: c0cc0eef6a9b569105408d2f2e6321795493036a
+11 -11
View File
@@ -1,29 +1,29 @@
# DeepSeek Harness 运行时 wheel # DeepSeek Harness 运行时 wheel
[English](README.md) | 中文 [English](README.md) | 中文
Python SDK 的运行时载体包(dist `deepseek-harness-runtime-bin`,模块名 `deepseek_harness_runtime`):它定位 `deepseek-harness` 客户端要 spawn 的内置运行时二进制,并附带支撑零配置运行的默认配置。 Python SDK 的运行时载体包(分发`deepseek-harness-runtime-bin`,模块名 `deepseek_harness_runtime`):它定位 `deepseek-harness` 客户端要 spawn 的内置运行时二进制,并附带支撑零配置运行的默认配置。
## 运行时载体 ## 运行时载体
两种载体并存于 `src/deepseek_harness_runtime/runtime/` 之下,均由仓库的 `scripts/build-exe-for-python-sdk.ts` 构建注入,且均被 gitignore 两种载体并存于 `src/deepseek_harness_runtime/runtime/` 之下,均由仓库的 `scripts/build-exe-for-python-sdk.ts` 构建注入,且均被 git 忽略
- **exe(生产)**——单文件可执行程序 `dsh-jsonrpc-agent-pkg-<platform>-<arch>`platform`linux`/`macos`arch`x64`/`arm64`)。目标机器无需安装 Node。这是唯一进入 wheel 分发的载体;本包不发布 sdist。 - **exe(生产)**——单文件可执行程序 `dsh-jsonrpc-agent-pkg-<platform>-<arch>`platform`linux`/`macos`arch`x64`/`arm64`)。目标机器无需安装 Node。这是唯一 wheel 分发的载体;本包不发布 sdist。
- **node(仅限开发)**——`runtime/node/` 下的完整 deploy 闭包(`package.json` + `node_modules/`),在系统 Node >= 22.19 上以 `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` 执行。它是当前检出的源码构建,仅用于仓库本地的开发与验证;不会被自动选中,也不进入分发物。 - **`node`(仅限开发)**——`runtime/node/` 下的完整部署闭包(`package.json` + `node_modules/`),在系统 Node >= 22.19 上以 `node runtime/node/node_modules/@deepseek-ai/dsh-jsonrpc-agent/lib/bin.js` 执行。它是当前检出的源码构建,仅用于仓库本地的开发与验证;不会被自动选中,也不进入分发物。
两种载体承载相同的内容,且只定义一次:本包根目录的 [package.json](package.json) 是 single-exe 流水线的 deploy root——一份零代码的纯依赖 manifest,其依赖闭包既是编译进 exe 的插件集,也是物化到 `runtime/node/` 的文件树。往分发物里加插件,就是在那里加一行依赖再重新构建。 两种载体承载相同的内容,且只定义一次:本包根目录的 [package.json](package.json) 是 single-exe 流水线的部署根目录——一份零代码的纯依赖 manifest,其依赖闭包既是编译进 exe 的插件集,也是物化到 `runtime/node/` 的文件树。往分发物里加插件,就是在那里加一行依赖再重新构建。
载体缺失时抛出 `FileNotFoundError` 并写明获取途径:在 deepseek-harness 检出中经 `scripts/build-exe-for-python-sdk.ts` 构建,或安装 `build-exe-for-python-sdk` CI 工作流生成的对应平台 runtime wheel。该工作流只保留 wheel,不保留独立 exe 归档。获取策略与查找接口刻意分离,之后可以换成按需下载而不动任何调用方。 载体缺失时抛出 `FileNotFoundError` 并写明获取途径:在 deepseek-harness 检出中经 `scripts/build-exe-for-python-sdk.ts` 构建,或安装 `build-exe-for-python-sdk` CI 工作流生成的对应平台运行时 wheel。该工作流只保留 wheel,不保留独立 exe 归档。获取策略与查找接口刻意分离,之后可以换成按需下载而不动任何调用方。
每个 wheel 只包含一个可执行文件。固定 tag `py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`;构建钩子会拒绝 `py3-none-any`、可执行文件缺失或重复以及不支持的平台 tag。仓库根目录的 `package.json` 为本包和 SDK 提供共同版本,`python-vX.Y.Z` 发布 tag 必须与其匹配。 每个 wheel 只包含一个可执行文件。固定标签`py3-none-manylinux_2_28_x86_64``py3-none-manylinux_2_28_aarch64``py3-none-macosx_11_0_arm64`;构建钩子会拒绝 `py3-none-any`、可执行文件缺失或重复以及不支持的平台标签。仓库根目录的 `package.json` 为本包和 SDK 提供共同版本,`python-vX.Y.Z` 发布标签必须与其匹配。
## 解析 API ## 解析 API
- `resolve_bundled_launch_args(mode=None) -> tuple[str, ...]`——启动内置运行时的 argv 元组:exe 模式下为 `(exe_path,)`node 模式下为 `(node_path, bin_js_path)`。模式选择:显式参数 > `DSH_RUNTIME_MODE` 环境变量(`exe` | `node`)> 自动。自动解析只找生产 exe——仅限开发的 node 载体必须显式选用,从而生产部署绝不会悄悄跑在源码构建上。 - `resolve_bundled_launch_args(mode=None) -> tuple[str, ...]`——启动内置运行时的 argv 元组:exe 模式下为 `(exe_path,)``node` 模式下为 `(node_path, bin_js_path)`。模式选择:显式参数 > `DSH_RUNTIME_MODE` 环境变量(`exe` | `node`)> 自动。自动解析只找生产 exe——仅限开发的 `node` 载体必须显式选用,从而生产部署绝不会悄悄跑在源码构建上。
- `bundled_runtime_path() -> Path`——平台 exe 路径(仅 exe 载体;node 载体没有单一路径的等价物,经由上面的 argv 元组启动)。 - `bundled_runtime_path() -> Path`——平台 exe 路径(仅 exe 载体;`node` 载体没有单一路径的等价物,经由上面的 argv 元组启动)。
- `bundled_default_config_path() -> Path`——检入的默认配置(见下文)。 - `bundled_default_config_path() -> Path`——检入的默认配置(见下文)。
- `bundled_package_dir() -> Path`——已安装包的数据根目录。 - `bundled_package_dir() -> Path`——已安装包的数据根目录。
## 零配置设计 ## 零配置设计
运行时二进制始终要求显式配置(`$DSH_CORDIS_CONFIG`,或作为 argv 位置参数的配置路径),缺了就报错退出——这一硬语义是运行时设计的一部分,本包不软化它。bin(`dsh-jsonrpc-agent`)只启动配置里列出的插件;服务面stdio JSON-RPC 服务器)也是其中一个条目(`@deepseek-ai/dsh-jsonrpc`),缺了它启动出的 agent 没有对外通道。本包检入 `runtime/cordis.yml`JSON-RPC 服务条目、agent core、预载的 DeepSeek 适配器、JSONL 会话持久化、本地 bash,各项由 SDK 设置的 `DSH_*` 环境变量参数化);调用方未任何显式配置通道时,`deepseek_harness` 客户端把该文件路径注入 `DSH_CORDIS_CONFIG`(注入条件见 [sdk README](../sdk/README.md))。零配置因此是 wrapper 里一次显式、可见的参数传递,不是运行时的隐藏回退。 运行时二进制始终要求显式配置(`$DSH_CORDIS_CONFIG`,或作为 argv 位置参数的配置路径),缺了就报错退出——这一硬语义是运行时设计的一部分,本包不软化它。`bin``dsh-jsonrpc-agent`)只启动配置里列出的插件;对外服务接口stdio JSON-RPC 服务器)也是其中一个条目(`@deepseek-ai/dsh-jsonrpc`),缺了它启动出的 agent 没有对外通道。本包检入 `runtime/cordis.yml`JSON-RPC 服务条目、`agent-core`、预载的 DeepSeek 适配器、JSONL 会话持久化、本地 bash,各项由 SDK 设置的 `DSH_*` 环境变量参数化);调用方未使用任何显式配置通道时,`deepseek_harness` 客户端把该文件路径注入 `DSH_CORDIS_CONFIG`(注入条件见 [sdk README](../sdk/README.md))。因此,零配置是包装层中一次显式、可见的参数传递,不是运行时的隐藏回退。
+1 -1
View File
@@ -3,4 +3,4 @@
# after editing either side, bring the other along and re-record with: # after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write # pnpm run verify-translation-pairing --write
README.md: 60540376c5fd85b0852e204bc8bad3f01c849de5 README.md: 60540376c5fd85b0852e204bc8bad3f01c849de5
README.zh.md: 7148a45c8f4bd22aaa28fc15ac9cd589cba13dfb README.zh.md: 241c06057889f1aa4add6fc54024fba92bd19429
+4 -4
View File
@@ -4,7 +4,7 @@
通过 JSON-RPC stdio 驱动 DeepSeek Harness 的 Python 子进程 SDK。运行时继承常规的 DeepSeek Harness 环境变量(如 `DEEPSEEK_BASE_URL``DEEPSEEK_API_KEY`),调用方可以直接用真实模型端点,也可以在跑基准测试时把它们指向本地代理。 通过 JSON-RPC stdio 驱动 DeepSeek Harness 的 Python 子进程 SDK。运行时继承常规的 DeepSeek Harness 环境变量(如 `DEEPSEEK_BASE_URL``DEEPSEEK_API_KEY`),调用方可以直接用真实模型端点,也可以在跑基准测试时把它们指向本地代理。
安装 `deepseek-harness` 会同时安装版本完全相同的 `deepseek-harness-runtime-bin` 平台 wheel。因此常规入口不需要传可执行文件参数: 安装 `deepseek-harness` 会同时安装版本完全相同的 `deepseek-harness-runtime-bin` 平台 wheel。因此常规入口不需要传可执行文件参数:
```py ```py
from deepseek_harness import DeepSeekHarness from deepseek_harness import DeepSeekHarness
@@ -15,7 +15,7 @@ with DeepSeekHarness() as harness:
`DeepSeekHarness` 会保留延迟启动的运行时子进程,以供多次调用复用。请像上例一样将其用作上下文管理器,或在用完后显式调用 `close()` `DeepSeekHarness` 会保留延迟启动的运行时子进程,以供多次调用复用。请像上例一样将其用作上下文管理器,或在用完后显式调用 `close()`
默认情况下,SDK 启动 `deepseek-harness-runtime-bin` 包内置的单文件 `dsh-jsonrpc-agent` 可执行程序,并通过 `DSH_CORDIS_CONFIG` 注入该包的默认配置(stdio JSON-RPC 服务器、agent core、预载的 DeepSeek 适配器、JSONL 会话持久化、本地 bash)。要运行自己插件组合需要在配置里保留 `@deepseek-ai/dsh-jsonrpc` 条目,并传入 Cordis 配置路径。 默认情况下,SDK 启动 `deepseek-harness-runtime-bin` 包内置的单文件 `dsh-jsonrpc-agent` 可执行程序,并通过 `DSH_CORDIS_CONFIG` 注入该包的默认配置(stdio JSON-RPC 服务器、`agent-core`、预载的 DeepSeek 适配器、JSONL 会话持久化、本地 bash)。要运行自己插件组合,请在配置里保留 `@deepseek-ai/dsh-jsonrpc` 条目,并传入 Cordis 配置路径。
```py ```py
from deepseek_harness import DeepSeekHarness from deepseek_harness import DeepSeekHarness
@@ -29,6 +29,6 @@ with DeepSeekHarness(
`TurnResult.final_response` 是本轮次最后一个 `assistant/message` 事件的文本内容。完整的事件流(包括中间的助手消息与工具活动)用 `TurnResult.events` 获取。 `TurnResult.final_response` 是本轮次最后一个 `assistant/message` 事件的文本内容。完整的事件流(包括中间的助手消息与工具活动)用 `TurnResult.events` 获取。
同样的行为也可以 `DSH_CORDIS_CONFIG` 为运行时子进程选定。注入逻辑位于 `HarnessClient.start()`,因此层客户端的默认启动同样享有它:当启动解析到内置运行时,且 `cordis` 与非空的 `DSH_CORDIS_CONFIG` 均未设置时(运行时把空值当作缺省,注入检查与之一致),使用内置的默认配置;显式给出 `runtime_bin``launch_args_override` 则完全禁用注入。运行时载体(生产用 exe 与仅限开发的 node 闭包)及其获取方式见 [sdk-runtime README](../sdk-runtime/README.md)。 同样的行为也可以通过 `DSH_CORDIS_CONFIG` 为运行时子进程选定。注入逻辑位于 `HarnessClient.start()`,因此层客户端的默认启动也具有此行为:当启动解析到内置运行时,且 `cordis` 与非空的 `DSH_CORDIS_CONFIG` 均未设置时(运行时把空值视为缺省,注入检查与之一致),使用内置的默认配置;显式给出 `runtime_bin``launch_args_override` 则完全禁用注入。运行时载体(生产用 exe 与仅限开发的 `node` 闭包)及其获取方式见 [sdk-runtime README](../sdk-runtime/README.md)。
`cwd``runtime_cwd` 会在启动子进程、注入环境变量和协议握手前解析为绝对路径。公开 API 只暴露真正生效的选项:部署 persona 与持久化配置归 `cordis.yml` 管理,而 `session_root` 继续作为设置 `DSH_SESSION_ROOT` 的高层便捷选项。 `cwd``runtime_cwd` 会在启动子进程、注入环境变量和协议握手前解析为绝对路径。公开 API 只暴露真正生效的选项:部署的角色设定与持久化配置归 `cordis.yml` 管理,而 `session_root` 继续作为设置 `DSH_SESSION_ROOT` 的高层便捷选项。