Files
deepseek-harness/packages/sdk/protocol
Tianyi Cui a3cb678875 Merge master current-directory support into subagent activations
Integrate the observed master checkpoint 7ab215e23e5d977aae7eb5d4fb91782d39969dbb without rewriting the earlier published checkpoints. Master adds current-directory events, directory-aware consumers, and retained Git worktrees; its old subagent startup paths overlapped the unified activation implementation.

Resolve directory selection within managed startup after acquiring parent ownership. Preserve the original Session origin while setting each new local child directory, retain persisted directory state on cold resume, and pass a required absolute cwd to external providers. Keep unified local/external ownership, full completion notices, parked-input host completion, SDK wait/error/shutdown behavior, and ACP cancellation semantics. Retain removal of the old in-process driver and continuation managers.

Combine SDK wait with the new directory requests, preserve the new master directory/worktree fixtures, regenerate derived catalogs from the combined sources, and refresh only the four stale prompt/schema sidecars. Preserve every protected historical schema, archived note, catalog-v2 acknowledgement, and recorded predecessor input.

Validation: full build; 59 CI static gates; 855 subagent tests with 100% coverage on changed core/external sources; affected consumer suites including 119 repaired-fixture tests; SDK 11 and headless 16 recorded scenarios; two local headless expected cases; six built nested SDK/ACP cases; lint, strict cast inventory, workspace constraints, and whitespace checks. Native Windows worker diagnostics remain additive and require the next CI run to classify the original crash.
2026-10-06 10:52:35 +08:00
..
2026-10-03 10:46:11 +08:00

description, kind
description kind
The SDK wire protocol for client and server implementers: the newline-delimited JSON-RPC transport and the named request, result, and notification types spoken between a Harness runtime and its SDK clients. package-library

@deepseek-ai/dsh-sdk-protocol

English | 中文

Summary

dsh-sdk-protocol lets a DeepSeek Harness runtime and its SDK clients exchange JSON-RPC 2.0 messages over newline-delimited byte streams: one transport class plus the named request, result, and notification types both wire ends speak. The serving side is the dsh-sdk-jsonrpc-server plugin; the clients are the TypeScript dsh-sdk-client and the Python SDK, which mirrors these shapes without importing them. Use this package when you implement or debug a wire end: framing rules, method names, payload types, and error semantics all live here. It is a pure library — no plugin, no configuration, no registrations.

Table of Contents


Use this package

Use this package when you build or debug an SDK wire end — the serving plugin, a client library, or custom tooling that speaks the SDK protocol. It gives you one transport for JSON-RPC 2.0 over caller-owned byte streams and the typed shapes for every SDK method and notification.

Framing and transport

Wire one JSON-RPC 2.0 message per \n-terminated line over byte streams you own. A frame with both id and method is a request, id alone is a response, and method alone is a notification; malformed lines are ignored. Requests with no registered handler answer -32601, handler failures answer -32603, and error responses reject the pending request with JsonRpcResponseError, which preserves the wire code and optional data. start() attaches stream listeners and close() detaches them and rejects pending requests without destroying the streams.

The SDK methods

Both wire ends share one method set: six client-to-server requests and four server-to-client notifications.

Direction Method Payload types
client→server initialize InitializeParams → InitializeResult
client→server session/prompt SessionPromptParams → SessionPromptResult (durable enqueue receipt)
client→server session/wait SessionWaitParams → {}
client→server session/working-directory/get SessionWorkingDirectoryParams → SessionWorkingDirectoryResult
client→server session/working-directory/set SessionWorkingDirectorySetParams → SessionWorkingDirectoryResult
client→server shutdown no params → {}
server→client session.event SessionEventNotification (every session in the runtime, unfiltered)
server→client session.status SessionStatusNotification (whole-agent running/idle transition)
server→client subagent.started SubagentStartedNotification
server→client subagent.finished SubagentFinishedNotification (in-process runs only)

HarnessSdkRequestMap and HarnessSdkNotificationMap index these shapes by method name; the package root exports them together with the transport.

session/wait accepts { sessionId } for an existing SDK-owned session and returns {} after the root stays idle and progressing managed descendant work finishes. Idle descendants with parked input remain resident without blocking this wait. Unknown ids and live Agent failures without a newer committed terminal are rejected. Notifications committed during the wait precede its response on the same transport; raw session.status transitions retain their whole-agent meaning.

Payload semantics

SessionPromptResult.messageId identifies the queued user message; it does not identify a later assistant message, turn ending, or prompt result. SdkPromptContentBlock accepts ordinary durable content plus SdkEncodedImageBlock { type: "image", data, mimeType }; the server converts encoded images to durable references before enqueue. InitializeParams.reasoningEffort is an optional non-empty adapter-owned identifier for the selected provider/model route; omission preserves that model's default. InitializeParams.maxTokens is an optional positive safe integer that caps each conversation-model output for SDK-created agents and their in-process descendants; omission lets the selected adapter's exact-model default apply. The server resolves the exact route during initialization and rejects session/prompt until that handshake succeeds, so a missing adapter, unavailable model, or unsupported effort cannot fall back to constructor defaults. SubagentFinishedNotification.lastAssistantMessage carries the child's last non-empty assistant message, or its accumulated assistant text when no such message exists; the field is absent when the child produced neither. serverInfo.name stays the wire-stable deepseek-harness-sdk-runtime. Notification payloads depend on SessionEvent (dsh-session), ContentBlock (dsh-llm), and SubagentStopReason (dsh-subagent), so the session vocabulary is part of the wire contract.


Understand the implementation

Implementation internals — click to expand

This section explains the design behind the wire library; the observable behavior is fully covered in Use this package.

Design concept

The package is built on one separation: a single newline-delimited transport class shared by both wire ends, and named types that index the protocol methods. The package root is the only import surface — source modules are not exported as deep imports. It is a pure library with no plugin, config, or registration; the serving plugin and the clients own all behavior around it.

Source map

File Role
src/transport.ts JsonRpcLineTransport: line framing, request/response/notification dispatch, error mapping, pending-request bookkeeping
src/types.ts Named request/result and notification payload types, indexed by method
src/index.ts Consumer interface: the transport and the named wire types

Frame dispatch

Incoming lines are parsed one at a time: a frame with id and method is answered through the request handler (or -32601), a frame with id alone resolves the matching pending request (an error frame rejects it with JsonRpcResponseError), and a frame with method alone is handed to the notification handler. start() attaches the input listeners; close() detaches them and fails every pending request without destroying the streams.


Further Exploration

Read these pages when the wire contract is not enough. They move from the serving plugin to the clients and the runnable application.


Model Experience

None, as this is a client-facing wire library; the runtime plugins behind the serving entry own all model-facing behavior.

KV Cache effect

None; this package neither assembles nor sends a provider request.

Known Limitations and Deferred Work

These limits define what the protocol does not cover or promise. They are current package constraints, not a comparison with other wire formats or a task backlog.

  • No protocol-version negotiation — the handshake carries only serverInfo.version (0.0.1, unvalidated by clients); pre-release stance, no compatibility promise.
  • No cancel or session-close methods — a client abandons a turn by closing the runtime process; see the JSON-RPC serving plugin.
  • Server→client requests are a dead capability — the transport supports them, but the server never sends one; the Python SDK's responder surface exists for future approval flows.

Dev Note

Working context for maintainers — click to expand

This Dev Note is working context for maintainers and is explicitly non-authoritative — shipped behavior and limits live in the sections above and in the code. This protocol's shapes are mirrored (not imported) by the Python SDK, so changing a method, payload, or the wire-stable serverInfo.name here requires updating the Python counterpart and the TypeScript client in the same change. No other unresolved design questions are recorded.