mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-12 04:01:20 +00:00
4.7 KiB
4.7 KiB
@deepseek-ai/dsh-subprocess
English | 中文
The subprocess seam (ctx.subprocess) is the process half of one execution world. The abstract SubprocessRuntime exposes executable lookup, ordinary managed spawn, and one terminal-process primitive; its vocabulary covers raw/collected stdio, process and terminal handles, exit facts, tree/session cleanup, and the managed DSH_* environment namespace. The local implementation lives in dsh-subprocess-local.
Contract
spawn(spec)returns a live handle synchronously; a native provider may first complete its bounded setup handshake so the handle exposes the target pid.doneresolves at process close with exit facts (SubprocessOutcomecarries no output and no cause classification) and rejects for spawn-level or selected native-runner failures.- Spawn working directories and executable paths belong to the provider's execution world.
resolveExecutable(command, env?, signal?)verifies absolute commands or resolves bare names against that world's scrubbed PATH plus explicit overrides. - The spec is fully explicit — argv, cwd, per-stream stdio dispositions, grace — because deployment-varying defaults belong to the caller's config, not to a hidden subprocess-service default (the
dsh-shellrequest/spec split is the owning template).argvis never shell-interpreted; a consumer that wants a shell passes['bash', '-c', command]itself. - Stdio is Node-shaped per stream:
'pipe'hands the caller the raw stream for its own protocol framing (LSP JSON-RPC, ACP ndjson),'inherit'passes the parent descriptor through for diagnostics, and collect mode ({ maxBytes, spill? }) buffers a bounded tail with an optional full-stream spill file. Collect readers take whole-stream byte offsets and never consume, so independent readers cannot steal one another's deltas; a read whose offset slid out of the in-memory tail islossyand points at the spill file when one exists. Collected output stays readable after settlement. - Termination is tree-scoped on every platform (POSIX detached groups with direct-child fallback; Windows
taskkill /T):terminate()— the only termination verb — escalates SIGTERM→grace→SIGKILL (idempotent, driven by the spec's abort signal too, a no-op once the tree is gone), andwaitForExit(signal?)observes whole-tree liveness so a consumer-owned teardown ladder holds each tier on real quiescence. The wait rejects when a selected native owner can no longer observe its range; the manager reacts but never classifies why (callers own deadlines, teardown ladders, and cause classification). spawnTerminal(spec)is the only non-pipe primitive. Its handle owns a real PTY, UTF-8 text I/O, foreground-process-group inspection/signalling, and one awaitedterminate()operation that reaches quiescence for every session member the provider can still observe and settles in-flight handle calls; providers document substrate-specific observability limits. The spec signal cancels allocation only; the published handle owns its lifetime. The output stream ends after queued output when the top-level process exits, and a live transport failure rejectsdone. These operations remain one substrate primitive because ordinary pipes cannot allocate a controlling terminal or clean terminal-session members; readiness, scrollback, and owner policy remain in the PTY consumer.scrubbedParentEnv()/SENSITIVE_ENV_PATTERNare the one shared scrub definition: ambient credential-shaped andDSH_*names are dropped, and explicitenvmerges after the scrub. The local ordinary and terminal spawns both apply it; SDK-managed transports that own their spawn may import it directly.- Disposal of the service terminates all still-running managed processes and awaits their exit.
See the subprocess subsystem page and the seam Agent Note.
Model Experience
Indirectly, through Consumers (today the bash executor family behind dsh-tool-bash), which own all model-facing rendering of process output and lifecycle.
KV Cache effect
No direct invalidation; the named consumers own any request-prefix changes.
Known Limitations and Deferred Work
- SDK-managed spawns remain outside — an SDK transport that owns its internal spawn cannot route that call through this service; it can still import
scrubbedParentEnvso environment policy stays single-sourced. - Teardown ladders are consumer-owned — the seam ships signalling verbs and the tree-liveness wait, not a canned quiesce sequence; each out-of-process consumer encodes its child's cooperation shape itself (the ACP backend's stdin-EOF-first ladder is the in-repo template).