Files
deepseek-harness/packages/sdk/sdk-protocol
Tianyi Cui cf2b9e211d fix(sdk-client): address ds-review-bot findings
- api: resolve a relative workspace cwd to absolute before the handshake —
  the child spawns relative to the parent cwd, but the wire cwd is resolved
  again inside the child, so a relative value double-resolved
  (worker -> worker/worker).
- api: make the documented handshake retry real — HarnessClient.close() is
  permanent, so a failed initialize now reaps the runtime and swaps in a
  fresh client; DeepSeekHarness.close() is terminal and stops the respawns.
- api: validate session.event envelopes, assistant/message content, and
  session.finished reasons at the wire boundary — a malformed runtime
  surfaces as SdkProtocolError instead of type-invalid TurnResult data or a
  TypeError out of finalResponse.
- client: a throwing subscribe() filter fails and detaches only its own
  subscription (normalized to Error); sibling fan-out and the transport read
  loop are undisturbed.
- client: NotificationSubscription.close() drops its queued notifications,
  matching its documented contract; runtime-death fail() still leaves
  already-delivered items drainable.
- client: subscribe() after close()/runtime death returns a born-failed
  subscription so next() rejects instead of parking forever.
- client/transport: bounded requests abandon via AbortSignal — the transport
  drops the pending entry at timeout, so repeated bounded calls against a
  hung method retain no per-call state.

One test per finding; per-file coverage stays 100% on both packages.
2026-07-27 17:48:07 +08:00
..

@deepseek-ai/dsh-sdk-protocol

English | 中文

The shared wire protocol for the DeepSeek Harness SDK runtime: one newline-delimited JSON-RPC 2.0 transport class plus the named request, result, and notification types both wire ends speak. The server side is the dsh-jsonrpc plugin; clients are dsh-sdk-client (TypeScript) and the Python SDK (which mirrors these shapes but does not import them). A pure library — no plugin, no Config, no registration.

Transport

JsonRpcLineTransport frames JSON-RPC 2.0 over caller-owned byte streams, one compact JSON frame per \n-terminated line. Frames with id and method are requests, id alone is a response, method alone is a notification; malformed JSON lines are ignored. start() attaches stream listeners, close() detaches them and rejects pending requests without destroying the streams. Missing request handlers answer -32601; handler rejections answer -32603 with the error message. An error response rejects the pending request() with JsonRpcResponseError, which preserves the wire code and optional data. JsonRpcTransportPeer is the outbound surface (request/notify) the server class is typed against.

Wire types

types.ts names every payload of the protocol served by HarnessSdkServer:

Direction Method Types
client→server initialize InitializeParamsInitializeResult
client→server session/prompt SessionPromptParamsSessionPromptResult (answered only after turn settlement)
client→server shutdown no params → {}
server→client session.event SessionEventNotification (every session in the runtime, unfiltered)
server→client session.finished SessionFinishedNotification (one per accepted prompt)
server→client subagent.started SubagentStartedNotification
server→client subagent.finished SubagentFinishedNotification (in-process runs only)

HarnessSdkRequestMap and HarnessSdkNotificationMap index these by method name. The notification payload types depend on SessionEvent (dsh-session), ContentBlock (dsh-llm), and SubagentStopReason (dsh-subagent) — the protocol streams full session-log envelopes, so the session vocabulary is part of the wire contract. serverInfo.name stays the wire-stable deepseek-harness-sdk-runtime.

Model Experience

None, as this package defines the client-facing wire protocol; the model-visible surfaces belong to the runtime plugins composed behind the serving dsh-jsonrpc entry.

KV Cache effect

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

Known Limitations and Deferred Work

  • 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 dsh-jsonrpc README.
  • Server→client requests are dead capability — the transport supports them, but the server never sends one; the Python SDK's responder surface exists for future approval flows.