The dsh-tools half of the Code Mode RFC (its fourth, final change): the registry gains its first config — mode: native | code | both — and OWNS how its tools reach the model. 'code' contributes exactly one wire tool, run_code, plus a lazy tools:sdk prompt section declaring every other tool as a generated TypeScript API (jsonSchemaToTs: total over the defineTool subset, unknown degradation, lexicographic byte-identical rendering); 'both' ships both representations; 'native' is byte-for-byte the old behavior. Non-native modes fail every assembly loudly without a typescript-language ctx.codeRuntime. run_code's dispatch bridge: JSON-normalizes each binding argument before dispatch (what dispatches is what the tool/code-dispatch event logs — the append can never fail on payload shape; BigInt/circulars reject that one call), serializes all program tool calls through a per-run queue (even Promise.all — no concurrency-safety metadata yet), routes every sub-call through tools/pre-execute → tools/post-execute (a deny rejects the program-side promise), drops sub-call additionalContext (no safe outlet mid-run; pinned), owns a run-scoped abort that follows the outer signal in and fires on settlement (in-flight sub-dispatch aborted, queued abandoned, queue drained before returning), and converts a failed run into CodeRunFailedError → a structured isError carrying kind + captured logs. tool/code-dispatch joins SessionEventMap by declaration merging (log-only; deriveMessages ignores it). The composed surface: the tools config forwards through agent-core and both app packages; examples/code-agent + demo:code run the worker runtime under mode code (keyless boot smoke + a with-key e2e proving the collapsed [run_code] header, the dispatch events, and the file the program wrote); two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK section, collapsed header, dispatch events, and result card — each its own header-pinning class (the harness gains per-scenario config overlays and per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the RFC (moved to implemented/, restructured to decision-era headings) updated in the same change.
@deepseek-ai/dsh-code-runtime
The code-execution seam: an abstract CodeRuntime service (ctx.codeRuntime) defining WHAT a code runtime does — run one model-written program against a set of host-provided async bindings and report { value, logs, error? } — without saying HOW.
This package is the interface third of the capability (the bash trio is the template — see capability seams): implementations subclass CodeRuntime and register the service; the consumer is the tool registry's Code Mode, which generates the model-facing SDK and bridges tool dispatch — both specified in the Code Mode RFC, whose first implementation is a Node worker-thread backend. The runtime knows nothing about tools or sessions: it is handed named async functions and a program string, and everything tool-shaped stays with the consumer.
Service API (ctx.codeRuntime)
| Member | Semantics |
|---|---|
run(request) |
Execute one program against the request's bindings. Resolves with an error FIELD for every program outcome — parse/transform failure, thrown exception, budget expiry, abort, substrate death (CodeRunFailure's orthogonal kind taxonomy); it rejects only for caller misuse of the seam itself (e.g. a run submitted after disposal). The program runs as the body of an async function: top-level await/return work, and the completion value becomes result.value when it survives the serialization boundary. |
language |
Readonly descriptor: the source language run expects ('typescript' is the well-known value). Informational, not gating — a consumer that generates language-specific presentation switches on it and fails loud on a language it cannot present. |
isolation |
Readonly descriptor: the execution substrate ('worker-thread', 'process', 'container'). A label for deployments and diagnostics, not a security claim. |
Semantics every implementation must honor (contract details in the class JSDoc): binding calls bridge to the caller's functions verbatim with structured-cloneable arguments/resolutions; the program is treated as a hostile peer (arbitrary binding names are own properties, malformed traffic never crashes the host); no state survives between runs; disposal terminates in-flight runs AND awaits their exit before completing.
Vocabulary
CodeRunRequest (program, bindings, signal?) carries everything the runtime acts on — defaulting (time budgets, output caps) is the implementation's validated config, never a hidden ?? inside run(). bindings is a list of CodeBindingNamespaces (global + functions), each exposed to the program as one global object of async callables. CodeRunResult reports the completion value?, the ordered logs (CodeLogEntry: console/stdout/stderr source, console level, capped text), and the error? (CodeRunFailure: kind + model-feedable message). See src/types.ts for the full contracts.