fix(tools): name the two bound SDK names and escape NEL

The static-stub sentence over-generalized: `tools` and `ToolCallError`
ARE bound at run time, and a model reading "everything below is a stub"
could stop catching `ToolCallError`. State the boundary and pin both
halves in the fixed-instruction assertions.

UNPRINTABLE missed U+0085: it is Cc but not ECMAScript whitespace, so
it survived the collapse and reached the docstring raw and invisible.
Add it and scope the docstring to Cc, since the `\xNN` escape cannot
address the Cf formatting characters that pass through by design.

Record the backend PR's two runtime contracts -- inject only `tools`
and `ToolCallError`, and bind the assembly-time language to the
request -- in the Agent Note and at requireCodeRuntime.
This commit is contained in:
Chinesezjc
2026-08-05 17:45:38 +08:00
parent bc94431c34
commit 1b4cb031f0
6 changed files with 46 additions and 6 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 .agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md
2026-07-31-code-mode-language-dispatch.md: 2d9649b922157992c86e3421aeeac23a84a4edb4
2026-07-31-code-mode-language-dispatch.zh.md: 61af77eb43d61061683f3ab6bf0d3c71587792a9
2026-07-31-code-mode-language-dispatch.md: cbcc8eb54ce78b922e584d050bb9d6a73439a08c
2026-07-31-code-mode-language-dispatch.zh.md: 5502daf926a62fa2b6981457be8f2b5583f477b8

View File

@@ -40,3 +40,5 @@ The standard that cap serves is grammatical validity, and the boundary is delibe
Adding a backend language is two table entries — an `SDK_RENDERERS` entry and a `RUN_CODE_FLAVORS` entry — plus the renderer function the former points at, with no change to `agent-loop` or the registry structure. The two tables (`SDK_RENDERERS`, `RUN_CODE_FLAVORS`) must stay in step: a language present in one but not the other is a latent inconsistency the `Object.hasOwn` guards turn into a loud failure rather than a wrong-language prompt. The tool layer stays free of any concrete backend dependency, so it lands and is testable on master ahead of the Python protocol and backend.
The cost is that the Python branch of both tables is unreachable on this base: `CodeRuntime.language` is set by the loaded backend, the only published backend is `dsh-code-runtime-worker` (`'typescript'`), and the registry reads the loaded runtime rather than a config field, so no assembled application can select `renderToolsSdkPy` or `PYTHON_FLAVOR`. The model-visible surface is therefore unchanged by this note's work until a backend reporting `'python'` is published, and this PR's coverage is unit-level — the renderer output plus the dispatch and rejection paths. The keyless snapshot for the Python model interface belongs to the PR that publishes that backend, because only there does a real `cordis.yml` over published plugins produce a Python assembly; a snapshot example that mounted a fixture runtime here would assert against a test double, which [docs/testing.md](../../../../docs/testing.md) rejects as a substitute for the assembled application transcript.
Two runtime contracts the Python SDK text asserts are owed by that same backend PR. First, the instructions tell the model that exactly `tools` and `ToolCallError` are bound and that the declared `TypedDict` classes are not, so the backend must inject those two names — with `ToolCallError.toolName` populated per the seam's `errorClass` contract — and must NOT bind the declared class names into the program's globals; injecting them "helpfully" would make the SDK text false. Second, the language has to be bound to the request: `requireCodeRuntime` resolves `ctx.codeRuntime` separately at assembly and at `run_code` execution, so a reload that swapped the runtime between those two points would hand a program written against one flavor to the other. Neither is reachable here — one published backend means both reads return the same flavor and no program ever runs against this renderer's output — and the cross-language rejection is not testable until a second language exists.

View File

@@ -40,3 +40,5 @@ Code Mode 只生成一种 SDK 形态TypeScript。`ToolRegistry` 为 `tools:sd
新增一门后端语言就是两条表项——一个 `SDK_RENDERERS` 表项加一个 `RUN_CODE_FLAVORS` 表项——再加前者所指向的渲染器函数,不动 `agent-loop`,也不动注册表结构。两张表(`SDK_RENDERERS``RUN_CODE_FLAVORS`)必须同步:某语言只在其一而不在另一是潜在的不一致,`Object.hasOwn` 守卫会把它变成一次 loud failure而不是错误语言的 prompt。工具层不依赖任何具体后端因此它能先于 Python 协议和后端在 master 上落地并可测。
代价是两张表的 Python 分支在当前 base 上不可达:`CodeRuntime.language` 由所加载的后端设定,已发布的后端只有 `dsh-code-runtime-worker``'typescript'`),而注册表读取的是所加载的运行时而非某个配置字段,因此没有任何一份组装好的应用能选中 `renderToolsSdkPy``PYTHON_FLAVOR`。也就是说,在报告 `'python'` 的后端发布之前,本 note 的工作不改变模型可见表面,本 PR 的覆盖因此是 unit 级——渲染器输出加分发与拒绝路径。Python 模型界面的 keyless snapshot 归属于发布该后端的那个 PR因为只有在那里一份基于已发布插件的真实 `cordis.yml` 才会产出 Python 组装;在此处挂载 fixture 运行时的快照示例断言的是测试替身,而 [docs/testing.md](../../../../docs/testing.md) 明确拒绝以此替代组装好的应用 transcript。
Python SDK 文本断言的两条运行时契约同样归属那个 backend PR。其一说明文字告诉模型运行时恰好绑定 `tools``ToolCallError` 两个名字、所声明的 `TypedDict` 类不绑定,因此后端必须注入这两个名字(并按 seam 的 `errorClass` 契约填充 `ToolCallError.toolName`),且**不得**把所声明的类名绑进程序全局——「好心」注入会使这段 SDK 文本变成假话。其二,语言必须绑定到请求上:`requireCodeRuntime` 在组装时与 `run_code` 执行时分别解析 `ctx.codeRuntime`,若在这两点之间发生重载并换掉运行时,就会把针对一种形态写成的程序交给另一种形态执行。两者在此处都不可达——只有一个已发布后端意味着两次读取返回同一形态,且没有任何程序会针对本渲染器的输出运行——而跨语言拒绝在第二门语言存在之前也无法测试。