Files
deepseek-harness/packages/ptc-runtime/ptc-runtime

description, kind
description kind
Abstract PTC execution seam (`ctx.ptcRuntime`) 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-ptc-runtime

English | 中文

Summary

Use dsh-ptc-runtime to execute model programs against host-provided asynchronous functions. Requests return lossless JSON, captured logs, or structured failures; rejected promises indicate caller misuse. Providers isolate distinct state owners and declare whether source is an async function body, REPL statements, or a script. retainsState reports whether a provider retains memory for an explicit owner until release; it never restores that memory from a Session. Language and isolation descriptors identify syntax and execution substrate, not security guarantees.

Table of Contents


Use this package

Choose this package when you compose a deployment that executes model-written programs, consume ctx.ptcRuntime directly, or build a backend that runs programs. dsh-tool-executor-ptc uses it for tool programs, and dsh-workflow-ptc uses it for workflow orchestration. Each consumer owns the content returned to its model.

Run a program

Call resolve(request) followed by run(spec) with a program and binding namespaces. Resolution validates cwd, timeout and sandbox choices and applies provider defaults. programFormat: PtcProgramFormat selects an async function body with top-level await and return, or REPL/Script statements with top-level declarations, await, and a final expression. The Node Script provider lowers top-level await and awaits the completion value; its declaration limitations apply to transformed programs. Lossless-JSON completion becomes result.value, text becomes result.logs, and failures become result.error.

const spec = ctx.ptcRuntime.resolve({
  program: 'return await tools.add({ a: 1, b: 2 })',
  bindings: [{ global: 'tools', functions: { add: async (args) => args.a + args.b } }],
})
const result = await ctx.ptcRuntime.run(spec)
// result.value === 3

Choose a backend

Backends expose language and isolation as diagnostic descriptors; neither grants authority or proves confinement. dsh-ptc-runtime-node executes erasable TypeScript in a fresh managed Node process under the resolved sandbox policy. The private dsh-experimental-ptc-runtime-python provider executes Python in a fresh CPython subprocess without file confinement. sandboxMode advertises a provider's deployment file-policy mode, or is absent when that capability is unsupported.

For the optional Node in-memory mode, pass the same stateOwner object across runs and await release(owner) at the owner's end. Different object identities never share an environment; omitted owners use a temporary environment. Stateless providers ignore ownership. Calls for one retained owner must not overlap.

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: exception, timeout, abort, worker-exit, invalid-output, output-limit, protocol or sandbox-unavailable. Providers return applicable result.sandbox facts separately from success or failure. Invalid or unsupported execution options fail during resolve; run rejects caller misuse, such as unresolved inputs, invalid binding names or a call after disposal.


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 PTC execution capability seam (capability seams): an abstract PtcRuntime extends Service registered as ctx.ptcRuntime, plus the vocabulary providers and consumers share. Providers subclass PtcRuntime, implement resolve and run, and register the service. dsh-tool-executor-ptc owns tool bindings, while dsh-workflow-ptc owns workflow hooks and child agents. The runtime stays ignorant of tools and sessions by contract: it receives a program, named async bindings and resolved execution options, then returns captured output, the outcome and applicable sandbox facts.

Service API

The readonly timeout descriptor exposes numeric { defaultMs, maxMs } for consumer presentation; an absent descriptor means numeric overrides are unsupported. An omitted timeoutMs selects the provider default; a number requests a validated, capped elapsed budget; explicit null requests no elapsed deadline. A provider rejects choices it does not support. The Node workflow adapter requests null, while the model-facing run_code tool accepts only positive numeric overrides.

executionInstructions supplies provider-owned usage guidance, or an empty string when none is needed. Consumers can include it in their program presentation without identifying the provider from its language or isolation descriptor; PTC includes it in the logged run_code schema.

resolve(request) owns supported option validation and deployment defaulting. run(spec) executes the complete inputs and resolves program outcomes after cleanup. Language and substrate descriptors guide presentation; sandboxMode indicates whether the consumer can pass a resolved file policy. Neither descriptors nor a successful program result substitute for the backend's reported enforcement facts.

The exhaustive semantics live in the PTC runtime subsystem reference; the exact signatures are in src/index.ts.

Vocabulary

PtcRunRequest carries the program, host bindings, cancellation and optional execution choices. PtcRunSpec requires the resolved cwd and an explicit numeric or null deadline choice. PtcBindingNamespace declares program globals and optional typed rejection constructors. PtcRunResult separates logs/value, failure and PtcRunSandbox facts; exact fields and provider obligations live in src/types.ts.

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 PtcRuntime service and the portable-identifier exclusion sets
src/types.ts Vocabulary: PtcRunRequest, PtcRunSpec, bindings, results, failures and sandbox facts

Further Exploration

Read these when the package-level contract is not enough. They move from the PTC mode consumer to the backends and the capability-seam model.


Model Experience

Indirectly, through dsh-tool-executor-ptc and the workflow adapter, which present program outcomes through their own tool results.

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 — logs arrive only on the resolved PtcRunResult; the seam exposes no streaming-log or progress API for a live program's output.
  • Retained memory is disposable: providers may keep state for an explicit owner; restart, release, and provider-specific failures discard it. Programs, binding calls and results remain logged by consumers; live objects are neither serialized nor replayed.
  • Providers have different confinement capabilities — the shipped Node provider enforces a resolved file policy, while the private experimental Python provider rejects an explicit policy. No container provider is supplied.
  • No uniform binding byte cap applies across providers — each provider owns its transport limits; a binding can still allocate memory before its result reaches those limits.

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.

Retained state

Retained state has no disk checkpoint or restoration protocol. Consumers must tolerate its loss and retain only model-visible programs and outcomes in the Session log.

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.