Files
deepseek-harness/python/sdk
Tianyi Cui fc566119a7 refactor(subprocess): rename the process seam to subprocess and address review
Review feedback (tianyicui): 'process' is a poor service name. The family is
now packages/subprocess/ — @deepseek-ai/dsh-subprocess (ctx.subprocess,
abstract SubprocessService, Subprocess* vocabulary) and
@deepseek-ai/dsh-subprocess-local (LocalSubprocessService) — renamed
throughout code, compositions, docs (en+zh, pairs re-recorded), catalogs,
and gates. 'subprocess' is the precise term for managed OS children (the
Python-stdlib sense), avoids colliding with Node's global process object,
and reads as one system beside dsh-subagent-subprocess.

ds-review-bot findings addressed:
- kill() on a settled handle is now a no-op (no signal to a possibly-reused
  pgid, no referenced grace timer delaying exit); pinned by a spy test.
- The moved DshEnvironmentKey/DshEnvironment/CollectedOutput types get
  drift-checked type-equiv blocks on the new subprocess.md page, restoring
  their manifest registration.
- subprocess.md is registered in the core.md sub-page index (en+zh).
2026-07-26 12:43:59 +08:00
..

DeepSeek Harness Python SDK

English | 中文

Python subprocess SDK for driving DeepSeek Harness over JSON-RPC stdio. The runtime inherits normal DeepSeek Harness environment variables such as DEEPSEEK_BASE_URL and DEEPSEEK_API_KEY, so callers can use real model endpoints directly or point those variables at a local proxy during benchmark runs.

Installing deepseek-harness installs the exact same-version deepseek-harness-runtime-bin platform wheel. The normal entry point therefore needs no executable argument:

from deepseek_harness import DeepSeekHarness

with DeepSeekHarness() as harness:
    result = harness.run("Say hi.")

DeepSeekHarness keeps its lazily started runtime subprocess for reuse across calls. Use it as a context manager, as above, or call close() explicitly when finished.

By default, the SDK launches the bundled single-file dsh-jsonrpc-agent executable from the deepseek-harness-runtime-bin package and injects that package's default configuration (the stdio JSON-RPC server, agent core, preloaded DeepSeek adapter, JSONL session persistence with an explicitly composed semantic checkpoint policy, local bash) via DSH_CORDIS_CONFIG. To run a plugin composition of your own, keep the @deepseek-ai/dsh-jsonrpc entry in the config and pass the Cordis config path.

from deepseek_harness import DeepSeekHarness

with DeepSeekHarness(
    provider="deepseek",
    model="deepseek-v4-flash",
    cordis="examples/jsonrpc-agent/cordis.yml",
) as harness:
    result = harness.run("Make the requested code change.")

provider selects a provider route registered by the chosen Cordis composition; model is the model id resolved by that adapter. The bundled default composition registers deepseek. A custom composition can mount llm-pi-ai, configure provider-specific credentials/endpoints there, and select any provider/model present in pi-ai's installed catalog.

HarnessClient retains discovered subagent ancestry for the lifetime of the runtime process. During each Session.run(), TurnResult.notifications and on_notification receive the root session and all known descendant notifications in wire order, including nested subagent lifecycle and session events. TurnResult.events remains the root session's complete event stream, and TurnResult.final_response is the text content from its last assistant/message; descendant messages therefore cannot replace the root response.

The same behavior can be selected for the runtime subprocess with DSH_CORDIS_CONFIG. The injection lives in HarnessClient.start(), so the low-level client's default launch gets it too: when the launch resolves to the bundled runtime and neither cordis nor a non-empty DSH_CORDIS_CONFIG is set (the runtime treats an empty value as absent, and so does the injection check), the bundled default configuration is used; an explicit runtime_bin, bridge_bin, or launch_args_override disables the injection entirely. See the sdk-runtime README for the runtime carriers (production exe vs dev-only node closure) and how to obtain them.

cwd and runtime_cwd are resolved to absolute paths before subprocess launch, environment injection, and the wire handshake. The public API exposes only applied options: deployment persona and persistence belong in cordis.yml, while session_root remains the high-level convenience that sets DSH_SESSION_ROOT.