Adding a published Python backend and reordering `flush_line` left several owning documents stating things that are no longer true. `src/invariant.ts` justified its empty installer with "ships only the fd-3 wire-protocol codec", which the subprocess execution path contradicts. The reason now states the actual one: every relation this backend maintains lives in the CPython child or on the fd-3 wire, so no same-process event sequence is observable from a listener -- the same shape the sibling worker-thread backend uses. The seam's `PORTABLE_RESERVED_WORDS` and `language` JSDoc, the code-runtime README pair, and docs/subsystems/code-runtime both said only TypeScript has a published backend. Corrected in all four, with the generated cordis catalog regenerated for the `language` change. The note attributed the 12x multiple to the settlement flush holding three copies. That stopped being true when `flush_line` was reordered to drop the pending chunks before its push: the binding worst case is the newline path's single near-budget write. Corrected in the note (both sides) and in the test comment that repeated it. The note's Testing section now registers the cases this stack added, and the Chinese side receives the O(depth) entry it never got plus the new ones -- it had drifted from the English. `INTERPRETER_BASELINE_BYTES` argued 64 MiB from a RESIDENT set while RLIMIT_AS bounds address space. It now cites the bootstrap's own measurement (30.23 MiB of mappings for `python3 -I`), making 64 MiB roughly twice the measured baseline. Also: a hardcoded `(:232-235)` comment reference becomes a reference by name, a "which now walks in O(depth) too" change narrative becomes a current-state statement, and a stray double blank line is removed.
description, kind
| description | kind |
|---|---|
| Abstract code-execution seam (`ctx.codeRuntime`) for users and maintainers composing, consuming, or building a backend that runs one model-written program against host-provided bindings. | package-reference |
@deepseek-ai/dsh-code-runtime
English | 中文
Summary
dsh-code-runtime defines what a code runtime does: run one model-written program against a set of host-provided async functions and report { value, logs, error? } — without dictating how any backend implements it. Load it in a composition with a backend and the service is available as ctx.codeRuntime; PTC mode in dsh-tools then runs model-written programs that compose tools. Every request runs once with no state carried between runs, and every program outcome — including failures — resolves as a result field rather than a rejection. The runtime knows nothing about tools or sessions: it is handed a program and named bindings, and everything tool-shaped stays with the consumer.
Table of Contents
- Use this package
- Understand the implementation
- Further Exploration
- Model Experience
- Known Limitations and Deferred Work
- Dev Note
Use this package
Choose this package when you compose a deployment that executes model-written programs, consume ctx.codeRuntime directly, or build a backend that runs programs. In the shipped composition, PTC mode in dsh-tools is the consumer: only what the program printed and returned re-enters the conversation.
Run a program
Give the runtime a program source and one or more binding namespaces. Each namespace becomes one global object of async functions inside the program — PTC mode passes one under tools. The program runs as the body of an async function, so top-level await and return work; a lossless-JSON completion becomes result.value, emitted text arrives in order as result.logs, and any failure is reported in result.error with a kind you can branch on. The runtime never rejects for a program failure — rejection means you misused the seam, for example by submitting a run after disposal.
const result = await ctx.codeRuntime.run({
program: 'return await tools.add({ a: 1, b: 2 })',
bindings: [{ global: 'tools', functions: { add: async (args) => args.a + args.b } }],
})
// result.value === 3
Choose a backend
Backends declare two descriptors you can rely on: language — what the program must be written in, with 'typescript' and 'python' as the well-known values and both backed by published providers — and isolation — the execution substrate ('worker-thread', 'process', 'container'), a label for deployments and diagnostics, not a security claim. dsh-code-runtime-worker-thread executes TypeScript in a fresh Node worker thread; dsh-code-runtime-python executes Python in a fresh CPython subprocess.
Name your bindings portably
Binding-global and error-class names are language-portable: they must match [A-Za-z_][A-Za-z0-9_]*, avoid every portable target language's reserved words, and avoid backend-owned slots, so one namespace list is valid against every backend. A name like $tools, lambda, or console fails the run before it starts; the exact exclusion sets are part of the seam contract.
What can go wrong
Failures arrive as result.error with an orthogonal kind: the program threw or failed to parse (exception), a budget expired (timeout), the run was aborted (abort), the execution substrate died (worker-exit), the completion value was not lossless JSON (invalid-output), or the serialized output exceeded the cap (output-limit). Each kind carries a model-feedable message. run() rejects only for seam misuse, such as a run submitted after disposal or a binding name that fails the portable-identifier rules.
Understand the implementation
Implementation internals — click to expand
This section explains the design behind the seam; observable behavior is fully covered in Use this package.
Design concept
The package is the Service Definition role of the code-execution capability seam (capability seams): an abstract CodeRuntime extends Service registered as ctx.codeRuntime, plus the vocabulary both backends and the consumer share. Providers subclass CodeRuntime, implement run, and register the service; the consumer (PTC mode in dsh-tools) generates the model-facing SDK and bridges tool dispatch. The runtime stays ignorant of tools and sessions by contract: it receives a program and named async bindings and returns { value, logs, error? }.
Service API
The contract is three members a backend implements: run(request) executes one program against the request's bindings and resolves every program outcome — parse/transform failure, thrown exception, invalid completion, output overflow, budget expiry, abort, or substrate death — as a result error field, with rejection reserved for caller misuse such as a run submitted after disposal; language and isolation are read-only descriptors labeling the source language and execution substrate for deployments and diagnostics.
The exhaustive semantics live in the code runtime subsystem reference; the exact signatures are in src/index.ts.
Vocabulary
CodeRunRequest (program, bindings, signal?) carries everything the runtime acts on; defaulting (time budgets, output caps) is each provider's validated config, never a hidden ?? inside run(). bindings is a list of CodeBindingNamespaces (global + functions + optional errorClass), each exposed to the program as one global object of async callables returning CodeJsonValue — the seam's structural lossless-JSON type. An errorClass descriptor names a real program-global constructor and the own property that receives the rejected member name, so backends never learn consumer terms such as ToolCallError. CodeRunResult reports the lossless-JSON completion value?, ordered logs: string[], and error? (CodeRunFailure: orthogonal kind + model-feedable message). See src/types.ts for the full contracts.
Portable identifiers
Binding-global and error-class names are language-portable: they must match the identifier subset [A-Za-z_][A-Za-z0-9_]* (no JS-only $) and clear the seam-exported exclusion sets, so one bindings list is valid against every backend. The package exports the contract every backend enforces — PORTABLE_RESERVED_WORDS (ECMAScript ∪ Python reserved words), RESERVED_BINDING_GLOBALS (backend-owned globals such as console and __dsh_main__), RESERVED_ERROR_MEMBERS and DUNDER_MEMBER (error-member exclusions) — so a name like $tools, lambda, or __dsh_main__ makes run() reject as seam misuse on any backend. See src/index.ts for the exact sets.
Source map
| File | Role |
|---|---|
src/index.ts |
Plugin entry: abstract CodeRuntime service and the portable-identifier exclusion sets |
src/types.ts |
Vocabulary: CodeRunRequest, CodeBindingNamespace, CodeJsonValue, CodeRunResult, CodeRunFailure |
src/invariant.ts |
Invariant companion (no runtime invariant; the seam registers no mutable data relation) |
Further Exploration
Read these when the package-level contract is not enough. They move from the PTC mode consumer to the shipped backends and the capability-seam model.
- PTC mode Agent Note — how the tool registry consumes
ctx.codeRuntimeand presentsrun_codeto the model. - Worker-thread backend — the shipped TypeScript execution backend.
- Python backend — the CPython subprocess execution provider and its fd-3 protocol.
- Code runtime subsystem reference — request/result vocabulary, bindings, and the
ctx.codeRuntimecordis surface. - Capability seams — the Service Definition / Service Provider / Consumer split.
Model Experience
Indirectly, through PTC mode in dsh-tools, which exposes run_code and returns program logs, values, or failures as retained tool-result tokens.
KV Cache effect
No direct invalidation; the named consumer owns any request-prefix changes.
Known Limitations and Deferred Work
These limits define what the seam cannot do; they are current package constraints, not a task backlog.
run()is one-shot —logsarrive only on the resolvedCodeRunResult; the seam exposes no streaming-log or progress API for a live program's output.- No state survives between runs — every request runs against a fresh world; a persistent REPL-style kernel is deferred until a backend brings its own logging story.
- Only the worker-thread backend ships —
'process'and'container'are declared well-knownisolationvalues with no implementation; a hard security boundary awaits a container backend. - Intermediate binding values have no byte cap — implementations remain subject to structured-clone cost and process memory, while a provider may already impose its own acquisition bound.
Dev Note
Working context for maintainers — click to expand
This Dev Note is working context for maintainers: undecided directions and open questions. It is explicitly non-authoritative — shipped behavior and limits live in the sections above and the package code.
Future: persistent kernel backend
A REPL-style kernel that keeps state across run_code calls remains undecided; it would need its own logging story, because the no-state-between-runs contract is what keeps every request reconstructable from the session log alone.
Future: container backend
A container-class backend would provide a hard multi-tenant boundary for both code and shell execution; nothing is decided beyond the well-known isolation value.