Replies: 2 comments
|
I checked the current repository HEAD (
This leaves the Python SDK accepting I did not find a fixing commit in the current HEAD, so this looks like a still-open protocol-consistency bug rather than a documentation issue. |
|
I reproduced this against the current Root cause. Fix. Make the three fields required so validation happens at the wire boundary, then translate the resulting pydantic Evidence. Three tests lock the model contract, the accepted identity, and the client-level refusal. The client-level one is load-bearing: applied to unpatched Patch --- a/python/sdk/src/deepseek_harness/models.py
+++ b/python/sdk/src/deepseek_harness/models.py
@@ -24,9 +24,9 @@ class IncomingRequest:
class ServerInfo(BaseModel):
- name: str | None = None
- version: str | None = None
+ name: str
+ version: str
class InitializeResponse(BaseModel):
- serverInfo: ServerInfo | None = None
+ serverInfo: ServerInfo--- a/python/sdk/src/deepseek_harness/client.py
+++ b/python/sdk/src/deepseek_harness/client.py
@@ -12,9 +12,9 @@
-from pydantic import BaseModel
+from pydantic import BaseModel, ValidationError
-from .errors import JsonRpcError, TransportClosedError
+from .errors import JsonRpcError, SdkProtocolError, TransportClosedError
@@ -158,6 +158,12 @@ class HarnessClient:
except TimeoutError as error:
self.close()
raise TimeoutError(f"{error}\nselected dsh profile {self.config.profile!r}") from error
+ except ValidationError as error:
+ # The handshake must carry both `serverInfo.name` and
+ # `serverInfo.version`; the TypeScript client refuses the same
+ # responses.
+ self.close()
+ raise SdkProtocolError(f"initialize returned no server identity: {error}") from error
except BaseException as error:
self.close()
diagnostics = self._runtime_diagnostics()The full patch, including tests and both READMEs, is attached below — I understand external PRs are not being accepted right now, so I am posting it here rather than opening a PR. Happy to adjust the shape or split it if that helps. One adjacent gap I deliberately left out of scope: a non-object Full patch (git am)From df08976aa74d08d7bcb4bb12b6fe21a1aec7079b Mon Sep 17 00:00:00 2001
From: lilei0311 <lilei0311@users.noreply.github.com>
Date: Sat, 26 Sep 2026 21:06:02 +0800
Subject: [PATCH] fix(python-sdk): reject a handshake without a complete server
identity
`ServerInfo.name`, `ServerInfo.version`, and `InitializeResponse.serverInfo`
were optional, so `initialize` accepted `{}`, `{"serverInfo": {}}`, and
partial `serverInfo` objects. A Python integration could therefore treat an
incompatible or malformed runtime as initialized and defer the protocol
error to a later request, unlike the TypeScript client, which requires both
fields as strings and rejects the same responses with `SdkProtocolError`.
Make all three fields required and translate the resulting wire validation
failure into `SdkProtocolError`, matching the TypeScript client's error type
and message. The bundled fake runtimes in the suite now answer with a
complete identity, and three tests pin the model contract, the accepted
identity, and the client-level refusal.
Also record the handshake identity requirement in both READMEs and re-record
their pairing entry.
---
python/sdk/README.i18n.yaml | 4 +-
python/sdk/README.md | 2 +-
python/sdk/README.zh.md | 2 +-
python/sdk/src/deepseek_harness/client.py | 10 ++-
python/sdk/src/deepseek_harness/models.py | 6 +-
python/sdk/tests/test_client.py | 83 +++++++++++++++++------
6 files changed, 79 insertions(+), 28 deletions(-)
diff --git a/python/sdk/README.i18n.yaml b/python/sdk/README.i18n.yaml
index ddc16b98c6..1cc9c5098c 100644
--- a/python/sdk/README.i18n.yaml
+++ b/python/sdk/README.i18n.yaml
@@ -6,8 +6,8 @@
en: 43f7de064985e731
zh: 9ad59629660b1f13
/deepseek-harness-python-sdk/start-a-runtime:
- en: 9a069c1a7cbb0779
- zh: 7f625a802cd1e9ea
+ en: 56adaf14c2ee1920
+ zh: 9ed7001d2036a76c
/deepseek-harness-python-sdk/customize-plugins:
en: d32ee602f121e6af
zh: fdea4487688e5774
diff --git a/python/sdk/README.md b/python/sdk/README.md
index bfca3b0dda..9d9b7ea521 100644
--- a/python/sdk/README.md
+++ b/python/sdk/README.md
@@ -30,7 +30,7 @@ with DeepSeekHarness(
print(result.final_response)- Customize pluginsdiff --git a/python/sdk/README.zh.md b/python/sdk/README.zh.md |
Uh oh!
There was an error while loading. Please reload this page.
Summary
The Python SDK accepts malformed
initializeresults that violate the shared SDK runtime protocol.Checked commit:
47f943859bef60e4160492346772ded9b24f765a.Expected behavior
initialize.result.serverInfomust contain bothnameandversionas strings. The TypeScript protocol declares both fields as required, and the TypeScript SDK rejects a malformed response withSdkProtocolError.References:
deepseek-harness/packages/sdk/protocol/src/types.ts
Lines 27 to 31 in 47f9438
deepseek-harness/packages/sdk/client/src/client.ts
Lines 268 to 275 in 47f9438
Actual behavior
The Python model makes
serverInfo,name, andversionoptional:deepseek-harness/python/sdk/src/deepseek_harness/models.py
Lines 26 to 32 in 47f9438
Consequently,
HarnessClient.initialize()accepts malformed runtime responses and returns successfully:deepseek-harness/python/sdk/src/deepseek_harness/client.py
Lines 117 to 135 in 47f9438
Minimal reproduction
All three payloads are accepted. At the transport level, the same result objects returned by a fake JSON-RPC runtime also make
HarnessClient.initialize()return normally.The corresponding TypeScript client rejects these shapes because
serverInfo.nameandserverInfo.versionare not strings.Impact
A Python integration can mark an incompatible or malformed runtime as initialized, delaying the protocol error until a later request and producing behavior inconsistent with the TypeScript SDK.
Suggested fix
Make
InitializeResponse.serverInfo,ServerInfo.name, andServerInfo.versionrequired strings, or add an equivalent explicit validation guard inHarnessClient.initialize(). Please also add regression tests for missingserverInfo, an empty identity object, and a missing/non-stringversion.Would you consider this a bug in the Python SDK, and if so, would you prefer tightening the Pydantic model or adding an explicit guard at the client boundary?
All reactions