DSH plugin 怎么接 PTC 运行时?ctx.ptcRuntime、超时取消与沙箱边界
PTC 运行时的核心不是“执行一段代码”,而是“把一段程序放进一个有 Host 绑定、有预算、有沙箱事实的执行世界”。 ctx.ptcRuntime 提供两个动作:resolve(request) 把调用方输入补齐成完整的 PtcRunSpec,run(spec) 执行并返回 PtcRunResult。程序失败是结果字段,不是异常;沙箱事实是独立报告,不是“成功即证明”。
DeepSeek Harness:三个核心对象
先分清 request、spec 与 result,写实现时就不会把校验和执行混在一起。 三者关系:(来源)
| 对象 | 谁产生 | 关键字段 |
|---|---|---|
PtcRunRequest | 调用方 | program、bindings、timeoutMs、sandboxPolicy、signal |
PtcRunSpec | 提供方 resolve | 补齐后的 cwd、timeoutMs 与支持的选择 |
PtcRunResult | 提供方 run | value、logs、error、sandbox |
resolve 的职责是“验证支持的选择并应用部署默认值”。省略 timeout 用提供方默认值,数值请求封顶经过时间预算,null 请求不设截止。提供方在执行前拒绝不支持的选择,而不是等程序跑起来再失败。
run 只接收完整输入:cwd 一定存在,timeoutMs 一定是正数或 null。这样实现者不必在每次执行里重复补默认值。
DeepSeek Harness:绑定怎么设计
绑定是程序能看到的 Host 函数,不是任意对象通道;参数与返回值都必须是无损 JSON。 设计要点:(来源)
- 一个命名空间一个全局对象 — 每个
PtcBindingNamespace以global名暴露,函数按名字挂在下面。预期:程序里能像调普通异步函数一样调用。 - 名字必须是可移植标识符 — 只允许
[A-Za-z_][A-Za-z0-9_]*,且不能是保留字。预期:同一份命名空间列表能跑在 JS 与 Python 后端。 - 函数名按自有属性处理 —
__proto__、constructor这类名字也要当普通键,构造时用 null-prototype。预期:不会发生原型碰撞。 - 错误可以类型化 — 可选
errorClass让程序看到真实的错误构造器与成员名。预期:拒绝能以结构化方式被程序捕获。 - 值必须无损 — 参数与解析值都要能无损穿过 JSON 边界。预期:不可克隆的值被明确拒绝,而不是悄悄变成字符串。
如果一个绑定需要传复杂对象,先把它拆成 JSON 可表达的字段;不要依赖后端的序列化“碰巧能过”。
DeepSeek Harness:失败分类与结果处理
PTC 的失败是正交结果:超时不是异常,中止不是超时,基底崩溃也不是两者中的任何一个。 八类:(来源)
exception— 程序抛出或解析/转换失败。timeout— 实现拥有的预算耗尽。abort— 请求的signal触发。worker-exit— 执行基底死亡,例如 OOM。invalid-output— 完成值不是无损 JSON。output-limit— 序列化后的日志、值或诊断超过上限。protocol— 程序发出非法或超预算的控制流量。sandbox-unavailable— 所需约束无法建立。
处理时不要把 error 当成异常再抛一遍;它本来就是给调用方展示或回喂模型自纠的字段。日志是纯字符串,每个来源通道保留自己的顺序,但跨通道如何交错由后端决定。
DeepSeek Harness:三种接入方式
接 PTC 不只有“自己写一个运行时”一条路;按隔离与持久化需求选。 三种:(来源)
- 使用发布的 Node 提供方 — 适合大多数本地执行,已有沙箱与持久 REPL 行为。预期:不用自己处理进程隔离。
- 实现无状态提供方 — 每次请求全新环境,忽略
stateOwner。预期:实现简单,适合一次性计算。 - 实现保留状态的提供方 — 用
stateOwner隔离内存,消费者结束时release(owner)。预期:能在同一所有者下复用环境,但保留对象不会进入持久 Session。
无论哪种,每个实现都要在资源释放期间终止并等待活跃执行;清理失败应拒绝 release 或 shutdown。
DeepSeek Harness:实现前的检查表
写一个能用的 PTC 提供方,先把下面四件事定下来,再写代码。 检查表:(来源)
- 语言与 programFormat — 是异步函数体还是 REPL,决定顶层
await与return的语义。预期:程序不会因为格式不符在解析阶段失败。 - 绑定命名空间 — 哪些 Host 函数暴露、全局名是什么、是否带类型化错误。预期:名字符合可移植标识符规则。
- 预算与隔离 — 默认 timeout、数值上限、
null的含义、是否有沙箱。预期:resolve能给出完整的PtcRunSpec。 - 资源释放 — 每个运行的状态如何隔离,
release(owner)如何终止在途执行。预期:清理失败会显式拒绝。
四件事没定清楚就写 run,通常会在“错误处理”和“状态泄漏”上返工。
DeepSeek Harness:一个最小调用骨架
调用方只需要关心 resolve 与 run 两步,程序失败看 result.error。 骨架:(来源)
const spec = ctx.ptcRuntime.resolve({
program,
bindings: [{ global: 'tools', functions: { readFile } }],
cwd,
timeoutMs: 30_000,
})
const result = await ctx.ptcRuntime.run(spec)
if (result.error) return { ok: false, kind: result.error.kind }
return { ok: true, value: result.value, logs: result.logs }
注意 resolve 可能因为不支持的选择而抛错,这属于调用方契约错误;run 里的程序失败则是 result.error,两者不要混。
安全与边界
沙箱事实是“报告”,不是“保证”;程序成功本身不能证明每项限制都强制执行。 四点:
- 看
sandbox.mode与denied— 模式、观察到的拒绝、强制完整性是独立事实。预期:不把“没报错”当成“没有越权”。 isolation不是安全声明 — 它只描述执行基底。预期:不要拿它当合规证明。- 不接收代理配置 — Workflow worker 与 Node PTC 进程不继承代理变量。预期:模型脚本读不到可能带密码的代理 URL;需要出网时自行配置并受沙箱约束。
- 区分运行失败与契约误用 — 程序失败进
error,只有 Service Definition 误用才让调用拒绝。预期:调用方不会把用户代码错误当成框架崩溃。
DeepSeek Harness 常见问题
Q:PTC 和普通工具调用有什么区别? 普通工具调用是一次函数调用;PTC 让模型写一段程序,在 Host 绑定上组合多次调用,并共享一次执行的目录、预算与沙箱事实。
Q:能不能让 PTC 程序持久保存状态?
可以用 stateOwner 在进程内保留,但它不是持久 Session 格式;进程退出后状态不保证存在。
Q:超时后绑定里的在途调用会怎样? 运行时会停止程序,但在途绑定调用由调用方负责收尾;不要把 timeout 当成“所有副作用都已停止”。
一句话收束: PTC 运行时要把“校验、执行、结果、沙箱”四件事分开看;混在一起,最容易把程序失败误判成框架异常。
常见问题
DeepSeek Harness 里,PTC 运行时是 dsh-ptc-runtime 提供的可选能力 seam,通过 ctx.ptcRuntime 让一段程序在 Host 绑定上执行,并报告输出、失败与适用的沙箱事实。它不属于智能体循环主干。
DeepSeek Harness 里,PtcRunRequest 是调用方输入,包含程序、绑定、取消与可选执行选择;resolve 会校验支持的选择并补齐目录、截止与权限,产出 cwd 与 timeoutMs 都明确的 PtcRunSpec,run 只接收完整输入。
DeepSeek Harness 里,不会。程序失败通过 PtcRunResult.error 返回,error 是结果上的字段;只有 Service Definition 契约误用才拒绝。失败类型包括 exception、timeout、abort、worker-exit、invalid-output、output-limit、protocol 与 sandbox-unavailable。
DeepSeek Harness 里,不能。绑定参数与返回值必须是无损 JSON;运行时会把不可克隆或会丢信息的值拒绝掉,而不是静默转换。不同后端还有各自的传输上限,seam 不设统一字节上限。
DeepSeek Harness 里,官方明确说 Workflow worker 与 Node ptc-runtime 进程不接收代理配置,避免模型脚本读到可能带密码的代理 URL。直接请求要自行配置代理,并继续受执行沙箱约束。
相关术语
- PTC
- PTC 是 DeepSeek Harness 中让模型编写程序并调用 Host 绑定的执行能力,由可选的 ctx.ptcRuntime seam 提供,不属于智能体循环主干。— DeepSeek Harness 官方参考 - PTC 运行时
- PtcRunRequest
- PtcRunRequest 是一次 PTC 执行的调用方输入,包含 program、bindings、cwd、timeoutMs、sandboxPolicy、stateOwner 与 signal;resolve 负责校验并补齐默认值。— DeepSeek Harness 官方参考 - PTC 运行时
- PtcRunResult
- PtcRunResult 是一次 PTC 执行的结果,包含可选的 sandbox 事实、完成值 value、日志 logs 与失败字段 error;程序失败不会让 run() 拒绝。— DeepSeek Harness 官方参考 - PTC 运行时
- stateOwner
- stateOwner 是 PTC 请求里用于标识可选保留内存的进程内对象身份;不同对象相互隔离,省略时请求全新环境,消费者在所有者结束时调用 release(owner)。— DeepSeek Harness 官方参考 - PTC 运行时
来源
- DeepSeek Harness 官方参考 - PTC 运行时· deepseek-ai
- DeepSeek Harness 官方文档 - 网络代理· deepseek-ai