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
@@ -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.