DSHarness 系统拆解 固定基线 47f943859b · 36 已复核 / 0 撰写中 / 36 章
English
执行环境·第 23 章

Code Mode、自修改与动态插件

模型如何编排工具,乃至检查和挂载自己的运行时

已复核上游 47f943859b范围: 分析 run_code transport、worker runtime、serialized subcall、Cordis inspect/define、VM 与处置生命周期。

结论:Code Mode 是“受治理的工具编排”,动态 Cordis 才是“临时运行时自修改”

DeepSeek Harness 没有把“写一段代码”当作扩大权限的捷径。Code Mode 只改变模型看见和调用工具的方式:模型提交一个 run_code,程序里的每个 tools.* 调用仍回到原来的 ToolRuntime,继续接受同一 agent 的可见性、审批、guard、工具沙箱和结果规范化。动态 Cordis 则是另一套显式 opt-in 的控制面:模型可以 inspect、定义不可变 Package、请求激活,并让临时 Plugin 在当前进程中注册工具、服务、事件或浏览器 UI。前者是一次调用内的 orchestration,后者是跨 turn 的 process-local extension;二者不能混称为同一种“自修改”。CODEMODE-MODESCODEMODE-POLICYCODEMODE-CORDIS-PROMPT

最重要的安全结论

两条路径都明确拒绝把运行载体包装成安全边界:worker-thread runtime 把模型代码视为 bash-equivalent trust;动态 Host VM 也承认 host-realm helper 可逃逸。这里的限制用于生命周期收敛、API discipline 与降低误用,不用于运行敌对代码。CODEMODE-WORKER-TRUSTCODEMODE-HOST-SANDBOX

1. 先看 shipped composition:CodeRuntime 已挂载,Code Mode 与自修改仍需显式选择

Headless bundle 默认挂载 worker-thread CodeRuntime,并把 tools.mode 接到 DSH_TOOLS_MODE;Web bundle 使用同一临时进程级开关。环境变量未设置时,ToolRuntime schema 的默认仍是 native。因此“runtime 存在”不等于“模型正使用 Code Mode”。CODEMODE-HEADLESS-COMPOSITIONCODEMODE-WEB-COMPOSITION

模型可见的自修改工具更窄:高级 headless overlay 才同时加入 CodeRuntime、Cordis Host runner 与 tool-cordis。也就是说,自修改不是 Code Mode 自动附带的能力;部署者必须显式把该工具集放进 composition。CODEMODE-SELF-MOD-OPTIN

2. 三种展示模式,两个同时生效的收缩点

mode模型收到的 tool schema执行边界
native当前作用域的可见原生工具原生工具可直接调用;无需 CodeRuntime
coderun_code,另加生成 SDK模型直调其他名字会得到 UNKNOWN_TOOL;嵌套调用可进入可见工具
both原生工具 + run_code + SDK两种调用形态都合法

展示模式可由部署默认、preset 或 agent scope 选择,最近作用域胜出并随 fiber dispose 撤销。run_code 又是注册层之外的保留 transport:restriction 不能删它,scoped registration 不能 shadow 它。CODEMODE-SCOPECODEMODE-TRANSPORT

安全关键不在 prompt 文字,而在 wire 与 execution 两端使用相同 collapse:code 只发送 run_code schema;真正执行时,只有带 opaque parent token 的嵌套 dispatch 才能越过 collapse。生成 SDK 同时排除 run_code,所以程序不能递归创建第二层 transport。CODEMODE-WIRECODEMODE-EXECUTION

3. run_code 是语言感知 transport,不是通用代码解释器承诺

run_code 有两个必填字符串:作为 async function body 的 code,以及用于 UI 标题的非空 description。它只返回有序 logs 与可选 JSON result;没有输出时给出固定占位文本。CODEMODE-RUN-SCHEMA

Tool 层准备了 TypeScript 与 Python 的 schema/SDK renderer,但 CodeRuntime seam 明确说当前只有 TypeScript 有已发布后端;languageisolation 只是 presentation/diagnostic descriptor,不是兼容性或安全证明。缺 runtime 或未知语言会在 prompt assembly 时 fail loud。CODEMODE-RUNTIME-DESCRIPTORSCODEMODE-WIRE

静态边界:语言没有绑定到一次请求

assembly 与执行分别读取 live ctx.codeRuntime。当前只有一个 published backend 时没有可见差异;若未来 HMR 在两次读取之间切换到另一语言,模型可能按旧 SDK 写程序、却交给新 runtime。源码已明确记录该窗口并延期到第二后端出现时修复。CODEMODE-RUNTIME-READS

4. Worker runtime:每次 fresh worker,四种预算,一个统一终局

限制默认真正约束的对象
computeMs60,000 msworker 自身 event-loop busy time;等待慢工具不计入
maxWallMs600,000 ms绝不暂停的 wall-clock ceiling
maxOutputBytes67,108,864 byteslogs + 最终 value 或 failure diagnostic 的合并 JSON 大小
maxOldGenerationSizeMb512 MiBworker old-generation heap

TypeScript 先在 Host 侧做 erasable type stripping;语法或 enum 一类 non-erasable syntax 失败时不会启动 worker。正常路径创建 env:{}execArgv:[]、带 heap resource limit 的 fresh worker,并捕获 stdout/stderr。CODEMODE-WORKER-LIMITSCODEMODE-WORKER-LIFECYCLE

程序以 strict AsyncFunction body 运行,显式形参只有 binding namespaces、它们的 typed error classes 与 console。无论正常完成、timeout、abort、output overflow、worker error 或 exit,Host 都只让一个终局获胜,并在 resolve 前 terminate worker、等待输出 pipe drain;runtime dispose 也会 abort 并 await 所有 live workers。CODEMODE-WORKER-BOOTCODEMODE-WORKER-LIFECYCLECODEMODE-WORKER-LIMITS

5. 数据边界只有 lossless JSON;外层输出 cap 不覆盖中间工具结果

CodeRuntime seam 要求 binding arguments、binding resolutions 与程序 completion 都是 lossless JSON。Worker wire 把值编码成扁平 token stream,并用迭代算法解码,因此深层结构不会把 JS 调用栈当作隐含限制;畸形、稀疏、循环、exotic、非有限数字或不完整值会 fail closed。CODEMODE-SEAMCODEMODE-FLAT-JSON

Worker 被当作 hostile peer:Host 重验消息形状,只做 own-property binding lookup,忽略重复 ID 与垃圾消息,并再次 snapshot binding resolution。相反,worker 也会在发出调用前 snapshot 参数。两端都拒绝“尽量 stringify”的有损降级。CODEMODE-WORKER-BRIDGECODEMODE-WORKER-BOOT

6. 嵌套工具继承的是“同一运行时治理”,不是 worker 的权限

model → run_code (outer ToolExecution)
  → worker program calls tools.read(...)
  → parent token + same agent + same run signal
  → ToolRuntime.prepare
      → pre-execute → approval → monotonic guards
  → ToolRuntime.dispatch
      → around wrapper → real tool body → its own sandbox/provider
  → ordered post/finalize → JSON value back to program

每次程序启动时,bridge 从调用 agent 的当前可见 schema 构造 tools namespace,并排除 run_code。每个调用再携带相同 agent、outer rootCallId、opaque parent token 与 run-scoped signal 回到 staged ToolRuntime。CODEMODE-BINDINGSCODEMODE-NESTED-DISPATCH

parent 只表示“这是 transport 内部调用”,用于绕过 code 的模型直调收缩;它不会跳过 restriction、approval、guard、around wrapper、工具自身的 filesystem/shell sandbox 或 post-policy。Worker 本身也没有“继承一个文件系统沙箱”;它只能请求 bindings,真正副作用发生在各工具自己的 provider 世界。CODEMODE-EXECUTIONCODEMODE-POLICY

7. 每次 run_code 都有自己的 bounded scheduler

默认 maxParallelSubCalls=10,只对这一段程序有效,不是进程级 semaphore。Driver 维护 pending queue、in-flight set、commit queue 与 exclusive flag:同一段程序提交的 concurrency-safe 调用可重叠;exclusive 工具必须等待池排空、独占执行,并一直占住 barrier 到 post/commit 完成。CODEMODE-MODESCODEMODE-SCHEDULER

并发只发生在 around-dispatch/body。start event、pre-execute/approval、post/finalization、context deferral 和 binding settle 都位于单一有序 lane;commit cursor 以程序提交顺序推进。工具在排队期间被替换时,classifier 会在启动前重读;工具在 binding 枚举后被卸载时,真正 dispatch 会按 live registry 解析并返回 unknown-tool failure。CODEMODE-SCHEDULERCODEMODE-NESTED-DISPATCH

8. 两层历史:模型只看 curated outer result,Session 保留 nested trajectory

程序的 console 输出与顶层 return 组成 outer run_code result,只有这一份进入后续模型历史。每个内部调用另写 tool/code-dispatch-starttool/code-dispatch,以 rootCallIdparentCallIdsubCallId 精确关联,并保存与实际 dispatch 分离的参数快照。CODEMODE-HISTORYCODEMODE-NESTED-DISPATCH

Nested result 的 additionalContexts 会在有序 commit 时 defer 到 outer execution;即使程序随后失败,这些上下文仍可随 outer error result 保留。成功 nested result 的 concludesTurn 也会向外传播。CODEMODE-NESTED-DISPATCH

静态可观测性边界

Binding 在 ordered commit 中先 resolve 给程序,再异步执行 shapeDispatchLog → session.append;所有 log work 只保证在 outer run 关闭前排空。若前一个 listener 比后一个慢,settle event 的 append 顺序可能不同于 binding 提交顺序。重建应按 subCallId 配对,不能把 nested event seq 当作 canonical body-completion order。CODEMODE-NESTED-DISPATCHCODEMODE-SCHEDULER

9. 故障与恢复:工具错误可由程序捕获,runtime 故障关闭整个 outer call

失败层程序/模型看到什么收敛动作
Nested tool 拒绝、policy deny、unknown tool程序中的 ToolCallError rejection;可 catch 后继续该 sub-call 仍完成 post/log/context pipeline
Program exception / invalid outputouter CODE_RUN_FAILED,带 kind、message 与已捕获 logsabort run-scoped signal,排空已启动与日志工作
busy/wall timeout、outer abort、OOM/worker exit、output limit对应独立 failure kind,不伪装成普通 exceptionterminate worker;晚到 binding resolution 被丢弃
Runtime contract misuserun() rejectionouter ToolRuntime 仍将其物化为结构化工具错误

Outer signal 会触发 run-scoped abort;程序一旦结束,不论成功还是失败,bridge 都立即拒绝 queued-unstarted 调用、让 started body 达到 quiescence,并等待 durable nested log work。这样 outer turn 不会在后台遗留仍可产生副作用的子调用。CODEMODE-SEAMCODEMODE-BINDINGSCODEMODE-WORKER-BRIDGE

10. Code Mode 的测试不变量

已固定的不变量fixture 证明方式
native/code/both 的 schema、SDK 与 code-only 指令一致分别 assemble 三种 mode,并检查 prompt section 顺序
安全调用可重叠,exclusive 形成完整 barrier,cap 生效gated tools 在释放前检查 live/pending 数量
pre/post、context 与 settle 按提交顺序;run 结束会 drain人工延迟 policy、post 与 runtime settlement
policy deny、lossy JSON、tool error、outer abort 均 fail closed从程序 rejection、Session events 与最终结果三面断言
worker 能承受伪造 port traffic、timeout、OOM、late reply直接注入 hostile messages 与资源失败

CODEMODE-TEST-PRESENTATIONCODEMODE-TEST-SCHEDULERCODEMODE-TEST-POLICY-FAILURECODEMODE-TEST-WORKERCODEMODE-TEST-WORKER-HOSTILE

11. 动态 Cordis 的真实模型面是七个工具

阶段工具效果
发现cordis_inspect_list列出 Host/Client Inspect Providers、方法与 schema
查询cordis_inspect_query运行 provider 声明的只读查询
自省cordis_inspect_self分层读取当前 Session 的 Plugin、Package、source 与诊断
定义cordis_define追加不可变 Package;不运行
激活cordis_run按 exact Package 发起 run/update
停用cordis_stop撤销 live effects,保留定义、grant 与版本指针
删除cordis_undefine永久删除 Plugin 及全部 Package

这组接口刻意把 inspect、define 与 execute 分开。cordis_define 只做参数、ownership 与语法校验并保存 source;它本身不修改仓库、配置或磁盘,也不触发 Plugin effects。真正能力只在 cordis_run 后由 Package 获取的 live services 决定。CODEMODE-CORDIS-INSPECTCODEMODE-CORDIS-DEFINECODEMODE-CORDIS-LIFECYCLE-TOOLS

12. Inspect 是运行时 schema discovery,不是业务 API 代理

inspect_list 给出 provider/method/schema 目录;inspect_query 只调用该目录中声明的只读方法。Host query 在本地验证输入、执行、再次验证输出;Client query 发布带 agent identity 的请求,等待第一个同 Session 的有效页面响应或调用取消。错误页面响应不会抢走 query。CODEMODE-CORDIS-INSPECTCODEMODE-INSPECT-REGISTRY

inspect_self 采用渐进披露:无 ID 只列 Plugin summaries,只有 pluginId 时返回 packages/version pointers/latest run,同时给出 pluginId 与 packageId 才返回 exact immutable source 与 Host/Client diagnostics。它把“先看当前事实再修复”做成工具形状,而不是靠 prompt 希望模型自觉。CODEMODE-CORDIS-INSPECT

13. 三种 identity 与两个 version pointer

Plugin (pluginId, session owner)
  ├─ Package A (packageId, immutable host/client source)
  ├─ Package B (packageId, immutable host/client source)
  ├─ currentPackageId → last fully successful Package
  ├─ nextPackageId    → in-progress or most recently failed target
  └─ active/latest Run (pluginRunId, mode, Host/Client diagnostics)

pluginId 是可持续修改的逻辑对象;packageId 是不可覆盖的 source version;pluginRunId 是一次 activation attempt,并串联 approval、Host/Client load、private handler 与错误。Registry 另存 per-Package grant 与 future-version grant。CODEMODE-REGISTRYCODEMODE-CORDIS-PROMPT

Define new 会 mint semantic-prefix ID;define existing 必须找到同 Session owner,随后总是 mint 新 packageId 并 append。旧 source 不会被原地改写,也没有“编辑正在运行函数体”的隐藏路径。CODEMODE-DEFINE-RUNNER

14. Host-only 与 Client-bearing Package 走不同 activation contract

Host-only Package 在同一调用中直接启动,并在成功后返回 running。带 Client half 的 Package 若没有 grant,会创建 approval request 并立即返回 awaiting-approval;已授权版本返回 starting,也不假装浏览器已经成功。CODEMODE-RUN-APPROVALCODEMODE-CORDIS-LIFECYCLE-TOOLS

页面侧严格按 Host half → exact active run 的 Client source → browser load → settlement 运行。Request、Package 与 Run identity 必须全部匹配;第一个有效 response claim pending request,未知、重复或陈旧 response 返回 accepted:falseCODEMODE-CLIENT-ORCHESTRATIONCODEMODE-APPROVAL-SETTLE

最终成功、用户拒绝或技术失败发生在原工具调用之后,通过 steering context 回到 owning Agent。失败消息带 current/next pointers,并要求在同一 Plugin 上 inspect、append corrected Package、再重试;用户拒绝则明确禁止自动重复索要同一批准。CODEMODE-OUTCOME-STEERING

15. “失败后保留 current”不等于自动运行时回滚

Update 会先 await retract(old run),再启动目标 Package。Host-only 成功可立即 commit;Client-bearing 版本先停在 client-pending,只有页面成功 settlement 后 commitActivation 才把 currentPackageId 指向新版本并删除 nextPackageIdCODEMODE-ACTIVATION

最容易误读的恢复语义

目标失败时,旧 currentPackageId 确实保留,便于显式 rollback;但旧 run 已在更新开始时停止,不会自动重启。因此指针回滚与 live-effect 回滚是两件事。正确恢复是用 run 显式重新激活 current,或修复 next 后再 updateCODEMODE-CORDIS-PROMPTCODEMODE-TEST-VERSIONING

16. 动态工具如何进入 Code Mode:下一次 assembly 与下一次 run 的快照

Host Package 不能交一份任意对象给 registry。它必须先经 harness.defineTool 校验参数 schema、output renderer、execute,并把跨 realm 的 schema/result/presentation data JSON-normalize;registerTool 只接受带内部 marker 的 definition。Guarded ctx.tools.get 也只返回 schema view,不泄漏 live execute 供 Package 绕过 policy pipeline。CODEMODE-DYNAMIC-TOOL-GUARD

工具注册后,下一次 prompt assembly 会从该 agent 的 live visible set 重建 SDK;下一次 run_code 又从当时 schemas 构造固定的 tools namespace。已经运行中的程序不会自动增加新 property;反过来,若某工具在 namespace 枚举后、真正调用前被 stop/unregister,binding 名仍存在,但 dispatch 会按 live registry 重新解析并 fail unknown-tool。CODEMODE-SDK-LIVECODEMODE-BINDINGSCODEMODE-TEST-SCHEDULER

17. 动态 Package 的“沙箱”是 capability façade,不是敌对代码隔离

降低误用的机制不能承诺的事
Hostfresh node:vm realm;process/Buffer 缺席;require/fetch/timer traps;declared-service ctx façadehost-realm helpers 可逃逸;async body 不受 vmTimeoutMs 限制
Clientnew Function closure 参数遮蔽 ambient globals;React/styles/host.call 显式注入;declared-service façade不是 browser security realm;代码与接受它的 Host 同等受信任
Services未声明 property、framework internals、Context-valued return 被拒绝;tools 只暴露受控 register/schema允许的 service 连接真实 runtime,能力大小取决于 composition

Host source 在 define 时 compile-only 预检,run 时以 async body 执行;vmTimeoutMs 只包围同步求值。Host façade 保留可逆 lifecycle verbs 与声明的 services,拒绝 rootfiber、raw registry 等 framework internals。CODEMODE-HOST-SANDBOXCODEMODE-HOST-CODECODEMODE-CONTEXT-GUARD

Client half 也不是模块 bundle:它是 plain JavaScript async body,显式收到 React、console、styles、host.call 与 trap functions。其 ctx twin 同样按 inject whitelist services,并给 slots/theme 额外 ownership guard。CODEMODE-CLIENT-EVALCODEMODE-CLIENT-GUARD

18. Lifecycle 的核心不是“能加载”,而是 stop 后达到 quiescence

Host retract 先从 registry 移除 active run,注销 package-private handlers,随后 await fiber.dispose(),最后广播 exact Plugin/Package/Run 的 retract event。所有通过 fiber-aware API 注册的 listener、tool、service、timer 等 effects 因此随 owner 反向撤销。CODEMODE-RETRACT

浏览器 runner 对同一 pluginId 的 load/unload 建立串行 queue:新 revision 会先 teardown 旧 entry;exact-run retract 不会误删更新后的 activation;单次失败被 queue tail 吸收,后续修复仍能继续;runner dispose 会卸载全部页面 package。CODEMODE-CLIENT-LIFECYCLE

控制面隔离不等于 effect 隔离

Plugin 的 define/run/stop/inspect action 由 session ownership 保护,但 Host package 挂在 process-local root group 下,并可使用 composition 授予的真实 services。Ownership 防止别的 Session 操纵记录,不自动证明所有注册或 service side effects 只影响 owning Session;具体作用域仍由被调用的 capability 决定。CODEMODE-REGISTRYCODEMODE-RETRACTCODEMODE-CONTEXT-GUARD

19. 自修改只活在进程内;@pluginId 不是 source persistence

Registry、ID counters、Package source、grants、current/next pointers 与 active run 都是 process memory。进程重启后定义消失;cordis_define 不写 repository/config/disk,也没有自动 promotion。要获得持久实现,仍需正常修改代码与配置。CODEMODE-CORDIS-PROMPTCODEMODE-REGISTRY

用户消息中的精确 @pluginId 会在 pre-step 注入 source-free identity/version context,并明确要求先用 pluginId+packageId 调 cordis_inspect_self 读取 source,再 append 新 Package。非 user-source 消息不会触发;已删除、跨 Session 或重启丢失的 ID 会返回 unavailable,而不是悄悄创建替代 Plugin。CODEMODE-REFERENCE

cordis_stop 是可逆停用:取消 pending approval、撤销 live run,但保留 definitions、grants 与 version pointers。cordis_undefine 才永久删除记录;两者都不会恢复到下一次进程启动。CODEMODE-CORDIS-LIFECYCLE-TOOLSCODEMODE-RETRACT

20. 动态自修改的测试不变量

已证明关键断言
define-only、语法预检、Session ownership坏 source 不入 registry;其他 Session 看起来像 absent
Host-only、approval、拒绝、异步 Client failure状态与 identity 正确,失败只撤销自己启动的 run
Context/tool escape closurectx.root、Context return、未声明 service、raw execute 都被拒绝
Version failure semanticscurrent pointer 保留、next/attempt 可诊断、attached page failure 不停既有 Host run
Client replace/serialize/recover/dispose每 Plugin 有序,exact retract,新 load 失败不 wedge queue

CODEMODE-TEST-DYNAMIC-RUNNERCODEMODE-TEST-DYNAMIC-GUARDCODEMODE-TEST-VERSIONINGCODEMODE-TEST-CLIENT-LIFECYCLE

21. 静态 findings 与文档漂移

Finding分类影响 / 建议
Prompt assembly 与 execution 未绑定同一 runtime language未来多后端热切换窗口第二 backend 前把 runtime/generation 绑定到 request
Binding resolution 不受 outer output byte cap内存与传输容量边界工具自行分页/裁剪;必要时增加 per-binding cap
Nested settle log append 可被异步 listener 重排可观测性边界按 subCallId 配对,不按 event seq 推断完成顺序
Host vmTimeoutMs 只管同步部分信任边界只运行受信代码;不能把 VM 当 hostile sandbox
Update failure 保留旧 current pointer,但旧 run 已停恢复语义陷阱UI/Agent 明示需要显式 rollback run
tool-cordis README 仍写旧五工具、旧 cordis_inspectackTimeoutMs已确认文档漂移以七工具生产源码为准并更新 README/generated links

CODEMODE-RUNTIME-READSCODEMODE-SEAMCODEMODE-NESTED-DISPATCHCODEMODE-HOST-CODECODEMODE-ACTIVATIONCODEMODE-README-DRIFT

22. 最终评价

架构判断

Code Mode 最成熟的地方,是把“模型写程序”降级成一种 presentation 与 composition technique:能力集合、审批和工具沙箱没有被复制到 worker,也没有被绕开,而是通过 nested dispatch 复用唯一 ToolRuntime。动态 Cordis 最成熟的地方,则是把自修改拆成 inspect → immutable define → identified activation → reversible stop,并把 browser approval 与异步失败变成显式状态。两者共同的短板不是控制流模糊,而是名称容易让人高估隔离:worker、node:vm 与 browser closure 都是受信代码的 containment/API discipline。

验证状态

本章在固定上游 commit 上逐行追踪 ToolRuntime、run_code bridge、CodeRuntime seam、worker bootstrap/transport、Cordis inspect/registry/Host/Client runner、guard、composition 与测试。定向 Vitest 覆盖 14 个文件,376 项测试全部通过。测试证明现有 presentation、调度、失败、approval、versioning、guard 与 teardown 不变量保持绿色;上节列出的语言绑定、nested log 顺序、binding 容量与异步 VM 边界仍是源码静态发现,不冒充已有回归证明。

我的学习体会

内容仅自动保存到当前浏览器,不上传、不进入仓库。你可以导出 Markdown 自行归档。