Merge latest master into Office progressive skills

This commit is contained in:
yudshj committed 2026-10-12 12:50:33 +08:00
commit b6fc04f403
1458 files changed
+29668 -5360

No files matched your search

+2 -2
View File
@@ -9,8 +9,8 @@
en: ddf4dabea526cef1
zh: 6e31cab10d2f3ed8
/deepseek-harness-python-sdk/start-a-runtime:
en: 9a069c1a7cbb0779
zh: 7f625a802cd1e9ea
en: 5fceaffcc35039c6
zh: 1d87e3defe7e875b
/deepseek-harness-python-sdk/customize-plugins:
en: d32ee602f121e6af
zh: fdea4487688e5774
+8
View File
@@ -50,6 +50,14 @@ print(result.final_response)
`DeepSeekHarness` starts lazily and reuses its runtime until `close()` or context-manager exit. The initial profile handshake has an independent 30-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`, optional `reasoning_effort`, 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.
`harness.resume_session(saved_session_id)` restores persisted history and returns a `Session` ready for `run()`. Save the original session id and reuse its `dsh_home` and workspace. Restoration preserves the stored directory, repairs an interrupted final turn, and sends no new input. Missing, unreadable, incompatible, or occupied sessions raise without creating a replacement. `start_session(id)` only opens a lazy handle; it does not request persisted restoration. This API does not restore shell, browser, or other external processes.
```py
with DeepSeekHarness(dsh_home="/absolute/path/to/saved-home") as harness:
session = harness.resume_session(saved_session_id)
result = session.run("Continue the task.")
```
## Customize plugins
Persistent customization belongs to a `dsh` profile. Initialize the shipped SDK profile and install an external bundle with the runtime wheel's `dsh` command:
+8
View File
@@ -50,6 +50,14 @@ print(result.final_response)
`DeepSeekHarness` 延迟启动运行时,并在调用 `close()` 或退出上下文管理器前复用该进程。首次 profile 握手通过 `initialize_timeout_seconds` 使用独立的 30 秒默认上限;普通轮次在未设置 `request_timeout_seconds` 时仍不设上限。超时诊断会指明所选 profile,并包含保留的运行时诊断。`cwd` 是 agent workspace;`runtime_cwd` 独立选择子进程工作目录。两者都会在启动前转成绝对路径。`provider`、`model`、可选的 `reasoning_effort` 和可选的正整数 `max_tokens` 通过 JSON-RPC 初始化发送。`base_url` 与 `api_key` 会显式覆盖子进程环境中的 `DEEPSEEK_BASE_URL` 与 `DEEPSEEK_API_KEY`。
`harness.resume_session(saved_session_id)` 恢复持久化历史,并返回可调用 `run()` 的 `Session`。请保存原会话 id,并沿用其 `dsh_home` 和工作区。恢复会保留存储的目录、修复最后一个被中断的轮次,且不发送新输入。会话缺失、不可读、不兼容或被占用时会抛出异常,不创建替代会话。`start_session(id)` 只打开惰性句柄,不会请求持久化恢复。此 API 不恢复 shell、浏览器或其他外部进程。
```py
with DeepSeekHarness(dsh_home="/absolute/path/to/saved-home") as harness:
session = harness.resume_session(saved_session_id)
result = session.run("Continue the task.")
```
## 自定义插件
持久自定义属于 `dsh` profile。使用运行时 wheel 包提供的 `dsh` 命令初始化随附的 SDK profile,并安装外部 bundle:
+9
View File
@@ -121,6 +121,15 @@ class DeepSeekHarness:
self.start()
return Session(self, session_id or f"session-{uuid.uuid4().hex}")
def resume_session(self, session_id: str) -> "Session":
"""Restore persisted history from the configured Harness home without sending input.
Missing, unreadable, incompatible, or occupied sessions raise instead of creating a new session.
"""
self.start()
self._client.resume_session(session_id)
return Session(self, session_id)
def run(
self,
input: str | list[JsonObject],
+11 -3
View File
@@ -14,7 +14,7 @@ from typing import Callable, TypeAlias, TypeVar
from pydantic import BaseModel
from .errors import JsonRpcError, TransportClosedError
from .errors import JsonRpcError, SdkProtocolError, TransportClosedError
from .models import IncomingRequest, InitializeResponse, JsonObject, JsonValue, Notification
ModelT = TypeVar("ModelT", bound=BaseModel)
@@ -98,7 +98,7 @@ class HarnessClient:
return
shutdown_completed = False
try:
self.request("shutdown", None, response_model=_ShutdownResponse, timeout_seconds=self.config.shutdown_timeout_seconds)
self.request("shutdown", None, response_model=_EmptyResponse, timeout_seconds=self.config.shutdown_timeout_seconds)
shutdown_completed = True
except Exception as exc:
self._stderr_lines.append(f"shutdown request failed: {exc}")
@@ -188,6 +188,14 @@ class HarnessClient:
)
return response.messageId
def resume_session(self, session_id: str) -> None:
"""Restore a persisted session without sending a prompt; propagate restoration failures."""
self.request(
"session/resume",
{"sessionId": session_id},
response_model=_EmptyResponse,
)
def get_working_directory(self, session_id: str) -> str:
"""Read the effective directory, recovering a missing directory to the Session origin."""
response = self.request(
@@ -603,7 +611,7 @@ class _WorkingDirectoryResponse(BaseModel):
cwd: str
class _ShutdownResponse(BaseModel):
class _EmptyResponse(BaseModel):
pass
+58
View File
@@ -0,0 +1,58 @@
from __future__ import annotations
import json
import sys
from pathlib import Path
import pytest
from deepseek_harness import DeepSeekHarness
from deepseek_harness.errors import JsonRpcError
@pytest.mark.parametrize("outcome", ["restored", "missing"])
def test_resume_preserves_identity_and_propagates_failure(tmp_path: Path, outcome: str) -> None:
script = tmp_path / "runtime.py"
requests = tmp_path / "requests.jsonl"
script.write_text(
"""
import json
import os
import sys
for line in sys.stdin:
frame = json.loads(line)
with open(os.environ["REQUESTS"], "a") as log:
log.write(line)
method = frame["method"]
response = {"jsonrpc": "2.0", "id": frame["id"]}
if method == "initialize":
response["result"] = {"serverInfo": {"name": "fake-runtime"}}
elif method == "session/resume":
outcome = os.environ["OUTCOME"]
if outcome == "missing":
response["error"] = {"code": -32603, "message": "session not found"}
else:
response["result"] = {}
else:
response["result"] = {}
print(json.dumps(response), flush=True)
if method == "shutdown":
break
""",
encoding="utf-8",
)
with DeepSeekHarness(
_launch_args=(sys.executable, str(script)),
env={"OUTCOME": outcome, "REQUESTS": str(requests)},
) as harness:
if outcome == "restored":
session = harness.resume_session("saved")
assert session.id == "saved"
assert session.harness is harness
else:
with pytest.raises(JsonRpcError, match="session not found"):
harness.resume_session("saved")
frames = [json.loads(line) for line in requests.read_text(encoding="utf-8").splitlines()]
assert [frame["method"] for frame in frames] == ["initialize", "session/resume", "shutdown"]
assert frames[1]["params"] == {"sessionId": "saved"}