mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
fix(python-sdk): harden profile runtime startup
Resolve packaged profile proxies with Node ESM import conditions from each package installation, and fail loud when an explicit runtime export or legacy main entry is missing. Serialize the shared profile fallback under the existing cross-process writer lock so concurrent dsh processes cannot observe partial proxies; either carrier now replaces the other carrier’s managed entry without manual cleanup. Give Python initialize its own 10-second default bound and name the selected profile in timeout diagnostics, while leaving ordinary agent turns unbounded by default. Package the dynamically resolved web frontend and skill-badge assets so the runtime wheel’s normal dsh profiles do not depend on pkg static-discovery accidents. Rewrite the root launch rule and every active stale SDK-runtime note to the shipped dsh profile architecture in both languages. Focused tests prove import-only and transitive package exports, lock contention, cross-carrier transitions, missing-entry failures, asset inventory, and bounded initialization.
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write python/sdk/README.md
|
||||
README.md: edf5ced63f181bb17895d81cc060577916554305
|
||||
README.zh.md: e03a19e5b8f0cef2e2f9d86f8d91b8808e268ff4
|
||||
README.md: ef2ba1764aa93fc6499941dd372a1de94f33d454
|
||||
README.zh.md: b5c36b6ff0fbce303649ae92efd7e1edac954e82
|
||||
|
||||
@@ -26,7 +26,7 @@ with DeepSeekHarness(
|
||||
print(result.final_response)
|
||||
```
|
||||
|
||||
`DeepSeekHarness` starts lazily and reuses its runtime until `close()` or context-manager exit. `cwd` is the agent workspace; `runtime_cwd` independently selects the subprocess working directory. Both become absolute before launch. `provider`, `model`, and optional positive `max_tokens` are sent during JSON-RPC initialization. `base_url` and `api_key` explicitly override `DEEPSEEK_BASE_URL` and `DEEPSEEK_API_KEY` in the child environment.
|
||||
`DeepSeekHarness` starts lazily and reuses its runtime until `close()` or context-manager exit. The initial profile handshake has an independent 10-second default bound through `initialize_timeout_seconds`; ordinary turns remain unbounded unless `request_timeout_seconds` is set. A timeout names the selected profile and includes retained runtime diagnostics. `cwd` is the agent workspace; `runtime_cwd` independently selects the subprocess working directory. Both become absolute before launch. `provider`, `model`, and optional positive `max_tokens` are sent during JSON-RPC initialization. `base_url` and `api_key` explicitly override `DEEPSEEK_BASE_URL` and `DEEPSEEK_API_KEY` in the child environment.
|
||||
|
||||
## Customize plugins
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ with DeepSeekHarness(
|
||||
print(result.final_response)
|
||||
```
|
||||
|
||||
`DeepSeekHarness` 延迟启动运行时,并在调用 `close()` 或退出上下文管理器前复用该进程。`cwd` 是 agent workspace;`runtime_cwd` 独立选择子进程工作目录。两者都会在启动前转成绝对路径。`provider`、`model` 和可选的正整数 `max_tokens` 通过 JSON-RPC 初始化发送。`base_url` 与 `api_key` 会显式覆盖子进程环境中的 `DEEPSEEK_BASE_URL` 与 `DEEPSEEK_API_KEY`。
|
||||
`DeepSeekHarness` 延迟启动运行时,并在调用 `close()` 或退出上下文管理器前复用该进程。首次 profile 握手通过 `initialize_timeout_seconds` 使用独立的 10 秒默认上限;普通轮次在未设置 `request_timeout_seconds` 时仍不设上限。超时诊断会指明所选 profile,并包含保留的运行时诊断。`cwd` 是 agent workspace;`runtime_cwd` 独立选择子进程工作目录。两者都会在启动前转成绝对路径。`provider`、`model` 和可选的正整数 `max_tokens` 通过 JSON-RPC 初始化发送。`base_url` 与 `api_key` 会显式覆盖子进程环境中的 `DEEPSEEK_BASE_URL` 与 `DEEPSEEK_API_KEY`。
|
||||
|
||||
## 自定义插件
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ class DeepSeekHarnessConfig:
|
||||
patches: tuple[str, ...] = ()
|
||||
dsh_home: str | None = None
|
||||
env: dict[str, str] = field(default_factory=dict)
|
||||
initialize_timeout_seconds: float = 10.0
|
||||
request_timeout_seconds: float | None = None
|
||||
shutdown_timeout_seconds: float | None = 1.0
|
||||
base_url: str | None = None
|
||||
@@ -79,6 +80,7 @@ class DeepSeekHarness:
|
||||
dsh_home=self.config.dsh_home,
|
||||
cwd=runtime_cwd,
|
||||
env=env,
|
||||
initialize_timeout_seconds=self.config.initialize_timeout_seconds,
|
||||
request_timeout_seconds=self.config.request_timeout_seconds,
|
||||
shutdown_timeout_seconds=self.config.shutdown_timeout_seconds,
|
||||
),
|
||||
|
||||
@@ -31,6 +31,7 @@ class HarnessConfig:
|
||||
dsh_home: str | None = None
|
||||
cwd: str | None = None
|
||||
env: dict[str, str] | None = None
|
||||
initialize_timeout_seconds: float = 10.0
|
||||
request_timeout_seconds: float | None = None
|
||||
shutdown_timeout_seconds: float | None = 1.0
|
||||
_launch_args: tuple[str, ...] | None = None
|
||||
@@ -137,7 +138,15 @@ class HarnessClient:
|
||||
if max_tokens is not None:
|
||||
payload["maxTokens"] = max_tokens
|
||||
try:
|
||||
return self.request("initialize", payload, response_model=InitializeResponse)
|
||||
return self.request(
|
||||
"initialize",
|
||||
payload,
|
||||
response_model=InitializeResponse,
|
||||
timeout_seconds=self.config.initialize_timeout_seconds,
|
||||
)
|
||||
except TimeoutError as error:
|
||||
self.close()
|
||||
raise TimeoutError(f"{error}\nselected dsh profile {self.config.profile!r}") from error
|
||||
except BaseException as error:
|
||||
self.close()
|
||||
diagnostics = self._runtime_diagnostics()
|
||||
|
||||
@@ -731,7 +731,8 @@ time.sleep(60)
|
||||
with HarnessClient(
|
||||
HarnessConfig(
|
||||
_launch_args=(sys.executable, str(script)),
|
||||
request_timeout_seconds=0.1,
|
||||
profile="web",
|
||||
initialize_timeout_seconds=0.1,
|
||||
)
|
||||
) as client:
|
||||
start = time.monotonic()
|
||||
@@ -740,6 +741,7 @@ time.sleep(60)
|
||||
except TimeoutError as exc:
|
||||
assert time.monotonic() - start < 2
|
||||
assert "bridge is still starting" in str(exc)
|
||||
assert "profile 'web'" in str(exc)
|
||||
else:
|
||||
raise AssertionError("initialize should time out")
|
||||
|
||||
@@ -832,6 +834,8 @@ def test_public_signatures_omit_unsupported_wire_parameters() -> None:
|
||||
assert {"dsh_bin", "profile", "patches", "dsh_home"} <= set(
|
||||
HarnessConfig.__dataclass_fields__
|
||||
)
|
||||
assert "initialize_timeout_seconds" in DeepSeekHarnessConfig.__dataclass_fields__
|
||||
assert "initialize_timeout_seconds" in HarnessConfig.__dataclass_fields__
|
||||
for removed in ("cordis", "session_root", "runtime_bin", "bridge_bin", "launch_args_override"):
|
||||
assert removed not in DeepSeekHarnessConfig.__dataclass_fields__
|
||||
assert removed not in HarnessConfig.__dataclass_fields__
|
||||
|
||||
Reference in New Issue
Block a user