fix(account,models): reconcile provider lifecycle with master

This commit is contained in:
lsdsjy committed 2026-09-22 15:06:16 +08:00
commit 6ef32577a3
3271 files changed
+111666 -48764

No files matched your search

+2 -2
View File
@@ -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-runtime/README.md
README.md: b2fb0b29c44db0e9e251ce0227e334e08a14e0f1
README.zh.md: 0f13c0a60c7378cb897ccfa7b7082bb86d722a07
README.md: 3a27ef586cce3290b13b9cd4517ff5a491f312c2
README.zh.md: 85bf35f62aa60bdb84e612518e2af740f1e8c708
+13
View File
@@ -12,6 +12,19 @@ Production executables are named `deepseek-harness-sdk-runtime-<platform>-<arch>
Each target also requires `<executable-stem>-office/`, where the stem excludes `.exe`. This directory contains the complete installed Office packages and their dependencies, preserving engine resources, manifests, licenses, source inventories, and helper permissions. Copy this directory together with the executable. A missing target engine fails the sidecar build with its npm package name and target platform/architecture.
Each wheel also includes `<platform>-<arch>/primary-runtime/` (CPython and the locked Office Python libraries) and sibling `office-skills/` (three default workflows and their shared checker). These are ordinary relocatable files, not bytes embedded in the executable. The shared builder selects target-native archives for all five wheel targets and executes its smoke on the native build host. Packaging and installed-runtime lookup reject missing resources, wrong-platform metadata, and lost Python executable permissions. The short platform directory avoids repeating the executable name in Python DLL paths on Windows.
The packaged bootstrap supplies `DSH_BUNDLED_PRIMARY_RUNTIME` as a carrier default. The `sdk` profile uses it when `DSH_PRIMARY_RUNTIME` is unset; an explicit path overrides it, and an empty string disables the query and Office provider. External payloads retain the `primary-runtime/` plus sibling `office-skills/` layout. The SDK reads Python in place without copying it into `DSH_HOME`. Source and dev-only Node carriers have no bundled default; they use an explicit `DSH_PRIMARY_RUNTIME`.
Skill selection is independent of delivery: project, custom-directory, and user filesystem skills override same-name bundled skills. An SDK patch can disable only the Office provider while retaining the Python query:
```yaml
- id: skill-office
disabled: true
```
To replace the three Office workflows and shared checker as a set, patch `skill-office.config.assetRoot` to another absolute resource directory. Use the filesystem skill provider for arbitrary skill collections. Configuration patches apply at process startup; changing skills does not require rebuilding the runtime wheel or Python environment.
Repository builds also materialize a dev-only `runtime/node/` carrier. It runs `node runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js` on system Node 22.19 or newer. It is never selected automatically and is excluded from wheels and sdists.
Both carriers execute the same `dsh` grammar and shipped profiles, including the standalone `sdk-minimal` tree and the full `web` profile with its frontend assets. The private `dsh-python-runtime-closure` manifest defines the packaged dependency closure; there is no Python-specific Node application or checked-in default `cordis.yml`.
+13
View File
@@ -12,6 +12,19 @@ wheel 包会安装 `dsh` 控制台命令和 `deepseek_harness_runtime` Python
每个目标还要求 `<executable-stem>-office/`,其中 stem 不含 `.exe`。该目录包含完整的已安装 Office 包及其依赖,保留引擎资源、清单、许可证、源码清单与辅助程序权限。复制可执行文件时必须一并复制此目录。缺少目标引擎会使 sidecar 构建失败,错误会指出其 npm 包名与目标平台/架构。
每个 wheel 还包含 `<platform>-<arch>/primary-runtime/`(CPython 与锁定版本的 Office Python 库)及同级 `office-skills/`(三个默认工作流与共用检查脚本)。它们是可重定位的普通文件,不嵌入可执行文件。共享构建器为全部五个 wheel 目标选择原生归档,并在对应构建主机上执行冒烟检查。打包与已安装运行时定位会拒绝缺失资源、平台不符的元数据及 Python 执行权限丢失。 较短的平台目录避免在 Windows Python DLL 路径中重复可执行文件名称。
打包启动器通过 `DSH_BUNDLED_PRIMARY_RUNTIME` 提供载体默认路径。`sdk` profile 在未设置 `DSH_PRIMARY_RUNTIME` 时使用该路径;显式路径覆盖它,空字符串禁用查询与 Office 提供方。外部 payload 保持 `primary-runtime/` 与同级 `office-skills/` 布局。SDK 原位读取 Python,不复制到 `DSH_HOME`。源码与仅供开发的 Node 载体没有随包默认路径,需显式设置 `DSH_PRIMARY_RUNTIME`。
选择 skills 与交付资源相互独立:项目、自定义目录和用户文件系统 skills 优先于同名随包 skills。SDK patch 可以仅禁用 Office 提供方,同时保留 Python 查询:
```yaml
- id: skill-office
disabled: true
```
要成套替换三个 Office 工作流与共用检查脚本,可将 `skill-office.config.assetRoot` 配置为另一个绝对资源目录。任意 skill 集合通过文件系统 skill 提供方加载。配置 patch 在进程启动时生效;切换 skills 无需重建 runtime wheel 或 Python 环境。
仓库构建还会物化仅限开发的 `runtime/node/` 载体。它在系统 Node 22.19 或更高版本上运行 `node runtime/node/node_modules/@deepseek-ai/dsh/lib/bin.js`。系统不会自动选择它,而且 wheel 包与 sdist 均不包含它。
两种载体执行相同的 `dsh` 语法与随附 profile,包括独立的 `sdk-minimal` 配置树,以及包含前端产物的完整 `web` profile。私有 `dsh-python-runtime-closure` manifest(元数据清单)定义打包依赖闭包;不存在 Python 专用 Node 应用或检入的默认 `cordis.yml`。
+8 -1
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import json
import os
import platform
import runpy
import stat
from pathlib import Path
@@ -76,7 +77,7 @@ class RuntimeBuildHook(BuildHookInterface):
target = next(name for name, value in _PLATFORMS.items() if value[0] == platform_tag)
runtime_dir = Path(self.root) / "src" / "deepseek_harness_runtime" / "runtime"
runtime_files = sorted(
runtime_dir.glob("deepseek-harness-sdk-runtime-*") if runtime_dir.is_dir() else []
(path for path in runtime_dir.iterdir() if path.name != "node") if runtime_dir.is_dir() else []
)
expected_files = (
[expected_executable, f"{expected_executable.removesuffix('.exe')}-rg.exe"]
@@ -87,6 +88,8 @@ class RuntimeBuildHook(BuildHookInterface):
expected_files.append(f"{expected_executable}-spawn-helper")
office = runtime_dir / f"{expected_executable.removesuffix('.exe')}-office"
expected_files.append(office.name)
resources = runtime_dir / target
expected_files.append(resources.name)
expected_files.sort()
found_files = [path.name for path in runtime_files]
if found_files != expected_files:
@@ -94,6 +97,10 @@ class RuntimeBuildHook(BuildHookInterface):
f"runtime wheel {platform_tag} payload must be {expected_files}; found {found_files}"
)
for executable in runtime_files:
if executable == resources:
validate = runpy.run_path(str(runtime_dir.parent / "_resources.py"))["validate_resources"]
validate(resources, target)
continue
if executable == office:
adapter = office / "node_modules/@deepseek-ai/libreoffice-kit/package.json"
if not adapter.is_file():
+20 -4
View File
@@ -16,14 +16,20 @@
"@deepseek-ai/dsh-agent": "workspace:^",
"@deepseek-ai/dsh-agent-instructions": "workspace:^",
"@deepseek-ai/dsh-agent-loop": "workspace:^",
"@deepseek-ai/dsh-agent-preset-registry": "workspace:^",
"@deepseek-ai/dsh-agent-tool-presentation": "workspace:^",
"@deepseek-ai/dsh-anonymous-user-id": "workspace:^",
"@deepseek-ai/dsh-app-boot": "workspace:^",
"@deepseek-ai/dsh-atomic-write": "workspace:^",
"@deepseek-ai/dsh-attachment": "workspace:^",
"@deepseek-ai/dsh-authorization": "workspace:^",
"@deepseek-ai/dsh-base": "workspace:^",
"@deepseek-ai/dsh-bash-local": "workspace:^",
"@deepseek-ai/dsh-brand": "workspace:^",
"@deepseek-ai/dsh-client-connection": "workspace:^",
"@deepseek-ai/dsh-cmdline": "workspace:^",
"@deepseek-ai/dsh-command-feedback": "workspace:^",
"@deepseek-ai/dsh-message-feedback": "workspace:^",
"@deepseek-ai/dsh-ptc-runtime": "workspace:^",
"@deepseek-ai/dsh-ptc-runtime-node": "workspace:^",
"@deepseek-ai/dsh-command-compact": "workspace:^",
@@ -33,8 +39,10 @@
"@deepseek-ai/dsh-compaction-basic": "workspace:^",
"@deepseek-ai/dsh-compaction-image-offload": "workspace:^",
"@deepseek-ai/dsh-compaction-tool-result-pruner": "workspace:^",
"@deepseek-ai/dsh-config-editor": "workspace:^",
"@deepseek-ai/dsh-cordis-host-runner": "workspace:^",
"@deepseek-ai/dsh-credentials": "workspace:^",
"@deepseek-ai/dsh-deepseek-account": "workspace:^",
"@deepseek-ai/dsh-deepseek-llm-api-extensions": "workspace:^",
"@deepseek-ai/dsh-fs": "workspace:^",
"@deepseek-ai/dsh-fs-local": "workspace:^",
@@ -46,6 +54,8 @@
"@deepseek-ai/dsh-hook-protocol": "workspace:^",
"@deepseek-ai/dsh-hooks-claude-code": "workspace:^",
"@deepseek-ai/dsh-hooks-codex": "workspace:^",
"@deepseek-ai/dsh-host-plugin-inventory": "workspace:^",
"@deepseek-ai/dsh-host-webserver": "workspace:^",
"@deepseek-ai/dsh-http-proxy": "workspace:^",
"@deepseek-ai/dsh-invariants": "workspace:^",
"@deepseek-ai/dsh-jobs": "workspace:^",
@@ -60,7 +70,10 @@
"@deepseek-ai/dsh-permission-presets": "workspace:^",
"@deepseek-ai/dsh-persona": "workspace:^",
"@deepseek-ai/dsh-plan-mode": "workspace:^",
"@deepseek-ai/dsh-plugin-manager": "workspace:^",
"@deepseek-ai/dsh-plugin-package-inventory-deepseek": "workspace:^",
"@deepseek-ai/dsh-ptc-runtime": "workspace:^",
"@deepseek-ai/dsh-ptc-runtime-node": "workspace:^",
"@deepseek-ai/dsh-pwsh-local": "workspace:^",
"@deepseek-ai/dsh-repeat-tool-reminder": "workspace:^",
"@deepseek-ai/dsh-sandbox": "workspace:^",
@@ -86,6 +99,10 @@
"@deepseek-ai/dsh-shell-env": "workspace:^",
"@deepseek-ai/dsh-skill": "workspace:^",
"@deepseek-ai/dsh-skill-filesystem": "workspace:^",
"@deepseek-ai/dsh-skill-office": "workspace:^",
"@deepseek-ai/dsh-storage": "workspace:^",
"@deepseek-ai/dsh-storage-domain": "workspace:^",
"@deepseek-ai/dsh-tool-workspace-dependencies": "workspace:^",
"@deepseek-ai/dsh-spill": "workspace:^",
"@deepseek-ai/dsh-subagent": "workspace:^",
"@deepseek-ai/dsh-subagent-acp": "workspace:^",
@@ -104,11 +121,11 @@
"@deepseek-ai/dsh-tool-bash-persistent": "workspace:^",
"@deepseek-ai/dsh-tool-call-timeout-policy": "workspace:^",
"@deepseek-ai/dsh-tool-cordis": "workspace:^",
"@deepseek-ai/dsh-tool-present": "workspace:^",
"@deepseek-ai/dsh-tool-fs": "workspace:^",
"@deepseek-ai/dsh-tool-fs-search": "workspace:^",
"@deepseek-ai/dsh-tool-goal": "workspace:^",
"@deepseek-ai/dsh-tool-jobs": "workspace:^",
"@deepseek-ai/dsh-tool-present": "workspace:^",
"@deepseek-ai/dsh-tool-pwsh": "workspace:^",
"@deepseek-ai/dsh-tool-pwsh-persistent": "workspace:^",
"@deepseek-ai/dsh-tool-ralph": "workspace:^",
@@ -121,6 +138,7 @@
"@deepseek-ai/dsh-tool-workflow": "workspace:^",
"@deepseek-ai/dsh-tools": "workspace:^",
"@deepseek-ai/dsh-typert-protocol": "workspace:^",
"@deepseek-ai/dsh-typert-registry": "workspace:^",
"@deepseek-ai/dsh-user-approval": "workspace:^",
"@deepseek-ai/dsh-user-questions": "workspace:^",
"@deepseek-ai/dsh-util-time": "workspace:^",
@@ -132,8 +150,6 @@
"@deepseek-ai/dsh-web-search-perplexity": "workspace:^",
"@deepseek-ai/dsh-workflow": "workspace:^",
"@deepseek-ai/dsh-workflow-ptc": "workspace:^",
"@deepseek-ai/schemastery": "workspace:^",
"@deepseek-ai/dsh-plugin-manager": "workspace:^",
"@deepseek-ai/dsh-host-plugin-inventory": "workspace:^"
"@deepseek-ai/schemastery": "workspace:^"
}
}
+7 -1
View File
@@ -22,7 +22,13 @@ dsh = "deepseek_harness_runtime:main"
# Include the injected dsh executable and sidecars; exclude the dev-only node closure.
[tool.hatch.build]
artifacts = ["src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*", "src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**"]
artifacts = [
"src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*",
"src/deepseek_harness_runtime/runtime/deepseek-harness-sdk-runtime-*/**",
"src/deepseek_harness_runtime/runtime/linux-*/**",
"src/deepseek_harness_runtime/runtime/macos-*/**",
"src/deepseek_harness_runtime/runtime/win-*/**",
]
exclude = ["src/deepseek_harness_runtime/runtime/node"]
[tool.hatch.build.targets.wheel]
+6
View File
@@ -1,6 +1,7 @@
#!/usr/bin/env node
/** Private entry owned by the Python single-file runtime packaging. */
import { registerHooks } from 'node:module'
import { dirname, join } from 'node:path'
import { isSea } from 'node:sea'
import { fileURLToPath, pathToFileURL } from 'node:url'
@@ -28,6 +29,11 @@ if (aclRunner !== undefined && process.argv[2] === aclRunner) {
Reflect.deleteProperty(process.env, 'DSH_PTC_RUNTIME_NODE')
await import('@deepseek-ai/dsh-ptc-runtime-node/process')
} else if (selection === undefined) {
if (isSea()) {
// Carrier default stays separate so process/home environment and profile patches can override it.
const platform = process.platform === 'darwin' ? 'macos' : process.platform === 'win32' ? 'win' : process.platform
process.env.DSH_BUNDLED_PRIMARY_RUNTIME = join(dirname(process.execPath), `${platform}-${process.arch}`, 'primary-runtime')
}
const { runCli } = await import('@deepseek-ai/dsh/lib/bin.js')
await runCli()
} else {
@@ -28,6 +28,7 @@ import shutil
import subprocess
import sys
from pathlib import Path
from ._resources import validate_resources
PACKAGE_METADATA_FILENAME = "deepseek-harness-runtime.json"
@@ -59,7 +60,9 @@ def bundled_runtime_path() -> Path:
Raises FileNotFoundError when the platform is unsupported, the executable
has not been placed into this package, the ripgrep or Office sidecar is
missing, or the required macOS spawn helper is missing; the message names
missing, the authoring resources are incomplete, or the required macOS
spawn helper is missing. Invalid authoring metadata or Python permissions
raise ValueError. Missing executable/Office messages name
the acquisition routes (acquisition strategy is deliberately separate from
this lookup interface, so an on-demand download can replace it without
touching callers).
@@ -104,6 +107,7 @@ def bundled_runtime_path() -> Path:
f"deepseek-harness-runtime-bin is missing the Office sidecar engine {engine} at {office}. "
+ _EXE_ACQUISITION_HINT
)
validate_resources(path.with_name(tag), tag)
return path
@@ -0,0 +1,41 @@
"""Validate the authoring resources in staged, installed, or archived runtime wheels."""
from __future__ import annotations
import json
import re
import stat
import zipfile
from pathlib import Path
def validate_resources(root: Path | zipfile.Path, target: str) -> None:
"""Reject a missing or wrong-target Python environment or bundled Office skill tree."""
manifest_path = root / "primary-runtime/runtime.json"
if not manifest_path.is_file():
raise FileNotFoundError(f"runtime authoring resources are missing: {manifest_path}")
manifest = json.loads(manifest_path.read_text(encoding="utf-8"))
platform, arch = target.rsplit("-", 1)
platform = {"macos": "darwin", "win": "win32"}.get(platform, platform)
if not isinstance(manifest, dict) or (manifest.get("platform"), manifest.get("arch")) != (platform, arch):
raise ValueError(f"runtime authoring resources do not match target {target}")
version = manifest.get("python")
if not isinstance(version, str) or not re.fullmatch(r"\d+\.\d+\.\d+", version):
raise ValueError("runtime authoring resources have invalid Python version metadata")
if not isinstance(manifest.get("pythonPackages"), dict) or not manifest["pythonPackages"]:
raise ValueError("runtime authoring resources have no Python distributions")
python_root = root / "primary-runtime/dependencies/python"
executable = python_root / ("python.exe" if platform == "win32" else "bin/python3")
packages = python_root / ("Lib/site-packages" if platform == "win32" else f"lib/python{version.rsplit('.', 1)[0]}/site-packages")
required = [executable, root / "office-skills/scripts/check_office.py"]
required.extend(root / f"office-skills/office-{kind}/SKILL.md" for kind in ("docx", "pptx", "xlsx"))
for path in required:
if not path.is_file():
raise FileNotFoundError(f"runtime authoring resource is missing: {path}")
if not packages.is_dir():
raise FileNotFoundError(f"runtime Python site-packages is missing: {packages}")
if platform != "win32":
mode = (executable.root.getinfo(executable.at).external_attr >> 16
if isinstance(executable, zipfile.Path) else executable.stat().st_mode)
if mode & stat.S_IXUSR == 0:
raise ValueError(f"runtime Python lost its executable bit: {executable}")
+14 -7
View File
@@ -26,16 +26,22 @@ class MockCompletionHandler(BaseHTTPRequestHandler):
body = self.rfile.read(length).decode("utf-8")
self.requests.append({
"path": self.path,
"authorization": self.headers.get("authorization"),
"api_key": self.headers.get("x-api-key"),
"body": json.loads(body),
})
self.send_response(200)
self.send_header("content-type", "text/event-stream")
self.end_headers()
self.wfile.write(b'data: {"choices":[{"delta":{"role":"assistant","content":null,"reasoning_content":""}}]}\n\n')
self.wfile.write(b'data: {"choices":[{"delta":{"content":"SDK runtime reached the configured HTTP model endpoint."}}]}\n\n')
self.wfile.write(b'data: {"choices":[{"delta":{"content":""},"finish_reason":"stop"}],"usage":{"prompt_tokens":7,"completion_tokens":9}}\n\n')
self.wfile.write(b"data: [DONE]\n\n")
events = [
{"type": "message_start", "message": {"id": "sdk-smoke", "model": "sdk-smoke-model", "usage": {"input_tokens": 7, "output_tokens": 0}}},
{"type": "content_block_start", "index": 0, "content_block": {"type": "text", "text": ""}},
{"type": "content_block_delta", "index": 0, "delta": {"type": "text_delta", "text": "SDK runtime reached the configured HTTP model endpoint."}},
{"type": "content_block_stop", "index": 0},
{"type": "message_delta", "delta": {"stop_reason": "end_turn"}, "usage": {"output_tokens": 9}},
{"type": "message_stop"},
]
for event in events:
self.wfile.write(f"event: {event['type']}\ndata: {json.dumps(event)}\n\n".encode())
def log_message(self, _format: str, *_args: object) -> None:
return
@@ -46,7 +52,7 @@ def run_smoke(repo_root: Path, keep_sessions: bool) -> None:
session_root = dsh_home / "sessions"
runtime_entry = repo_root / "apps/cli/src/bin.ts"
server = ThreadingHTTPServer(("127.0.0.1", 0), MockCompletionHandler)
thread = threading.Thread(target=server.serve_forever, name="mock-openai-compatible-server", daemon=True)
thread = threading.Thread(target=server.serve_forever, name="mock-messages-server", daemon=True)
thread.start()
base_url = f"http://127.0.0.1:{server.server_address[1]}"
@@ -86,7 +92,8 @@ def run_smoke(repo_root: Path, keep_sessions: bool) -> None:
assert len(MockCompletionHandler.requests) == 1
request = MockCompletionHandler.requests[0]
print(json.dumps(request, ensure_ascii=False, indent=2)[:4000])
assert request["authorization"] == "Bearer sdk-smoke-key"
assert request["path"] == "/v1/messages"
assert request["api_key"] == "sdk-smoke-key"
assert request["body"]["model"] == "sdk-smoke-model"
jsonl_files = sorted(session_root.rglob("*.jsonl.zstd"))
+9
View File
@@ -595,6 +595,15 @@ def test_client_keeps_unmatched_notifications_available_globally_while_subscribe
def test_session_subscription_keeps_descendant_relationships_across_subscriptions() -> None:
client = HarnessClient()
with client.subscribe_session_notifications("main") as first:
unknown_child = {
"type": "subagent/catalog", "seq": 0, "time": 1,
"data": {"version": 1, "childId": "unreadable-child", "childCreatedAt": 1, "mode": "unknown"},
}
client._handle_message({
"jsonrpc": "2.0", "method": "session.event",
"params": {"sessionId": "main", "event": unknown_child},
})
assert first.next().payload == {"sessionId": "main", "event": unknown_child}
client._handle_message({
"jsonrpc": "2.0",
"method": "subagent.started",
+30
View File
@@ -26,6 +26,18 @@ def test_release_tag_is_optional_for_non_release_builds() -> None:
build_python_release.validate_release_tag(None, "1.2.3")
def test_wheel_verification_uses_distribution_metadata_not_nested_libraries(tmp_path: Path) -> None:
wheel = tmp_path / "sdk.whl"
with zipfile.ZipFile(wheel, "w") as archive:
archive.writestr("nested/library.dist-info/WHEEL", "Tag: cp312-cp312-linux_x86_64\n")
archive.writestr("nested/library.dist-info/METADATA", "Name: library\nVersion: 0.0.1\n")
archive.writestr("deepseek_harness_sdk-1.2.3.dist-info/WHEEL", "Tag: py3-none-any\n")
archive.writestr("deepseek_harness_sdk-1.2.3.dist-info/METADATA",
"Name: deepseek-harness-sdk\nVersion: 1.2.3\nLicense-Expression: MIT\n"
"License-File: LICENSE\nRequires-Dist: deepseek-harness-runtime-bin==1.2.3\n")
build_python_release.verify_wheel(wheel, "sdk", "1.2.3", None)
def test_release_tag_must_match_repository_version() -> None:
build_python_release.validate_release_tag("python-v1.2.3", "1.2.3")
@@ -96,6 +108,19 @@ def test_stage_sdk_keeps_distribution_module_and_runtime_pin_distinct(tmp_path:
assert (destination / "src" / "deepseek_harness" / "__init__.py").is_file()
def test_copy_package_omits_generated_carriers_before_staging_one_target(tmp_path: Path) -> None:
source = tmp_path / "source"
module = source / "src/deepseek_harness_runtime"
for path in ("runtime/macos-arm64/primary-runtime/runtime.json", "runtime/node/package.json",
"runtime/deepseek-harness-sdk-runtime-win-x64.exe", "__init__.py", "_resources.py"):
file = module / path
file.parent.mkdir(parents=True, exist_ok=True)
file.touch()
destination = tmp_path / "staged"
build_python_release.copy_package(source, destination)
assert sorted(path.name for path in (destination / "src/deepseek_harness_runtime").iterdir()) == ["__init__.py", "_resources.py"]
@pytest.mark.parametrize(
("target", "with_helper"),
[("linux-x64", False), ("macos-arm64", True), ("macos-x64", True), ("win-x64.exe", False)],
@@ -124,6 +149,10 @@ def test_stage_runtime_copies_platform_payload(
office_asset = office / "node_modules" / "@deepseek-ai" / "libreoffice-kit-wasm" / "assets" / "soffice.data"
office_asset.parent.mkdir(parents=True)
office_asset.write_bytes(b"office data")
resources = executable.with_name(executable.name.removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe"))
resource = resources / "office-skills/scripts/check_office.py"
resource.parent.mkdir(parents=True)
resource.write_text("checker")
destination = tmp_path / "staging"
build_python_release.stage_runtime(destination, "1.2.3", executable, executable.name)
@@ -135,6 +164,7 @@ def test_stage_runtime_copies_platform_payload(
if path.is_file()
} == expected
assert (runtime_dir / office.name / office_asset.relative_to(office)).read_bytes() == b"office data"
assert (runtime_dir / resources.name / resource.relative_to(resources)).read_text() == "checker"
pyproject = (destination / "pyproject.toml").read_text()
assert 'license = "MIT"' in pyproject
assert 'license-files = ["LICENSE", "THIRD_PARTY_NOTICES.md"]' in pyproject
+60 -6
View File
@@ -6,11 +6,13 @@ import json
import os
import subprocess
import sys
import zipfile
from pathlib import Path
from types import SimpleNamespace
import deepseek_harness_runtime as runtime
import pytest
from deepseek_harness_runtime._resources import validate_resources
from deepseek_harness_runtime import (
RUNTIME_MODE_ENV_VAR,
@@ -20,7 +22,7 @@ from deepseek_harness_runtime import (
)
def _office_sidecar(executable: Path, native_targets: tuple[str, ...] = ("darwin-arm64", "darwin-x64", "win32-x64")) -> Path:
def _resource_sidecars(executable: Path, native_targets: tuple[str, ...] = ("darwin-arm64", "darwin-x64", "win32-x64")) -> Path:
office = executable.with_name(f"{executable.name.removesuffix('.exe')}-office")
tag = executable.name.removeprefix("deepseek-harness-sdk-runtime-").removesuffix(".exe")
native = tag.replace("win-", "win32-").replace("macos-", "darwin-")
@@ -33,6 +35,21 @@ def _office_sidecar(executable: Path, native_targets: tuple[str, ...] = ("darwin
adapter.write_text(json.dumps({"optionalDependencies": {
f"@deepseek-ai/libreoffice-kit-{target}": "0.0.1" for target in (*native_targets, "wasm")
}}), encoding="utf-8")
resources = executable.with_name(tag)
manifest = resources / "primary-runtime/runtime.json"
manifest.parent.mkdir(parents=True)
manifest.write_text(json.dumps({"platform": native.rsplit("-", 1)[0], "arch": tag.rsplit("-", 1)[1],
"python": "3.12.14", "pythonPackages": {"numpy": "2.3.5"}}))
python = resources / "primary-runtime/dependencies/python" / ("python.exe" if tag.startswith("win-") else "bin/python3")
python.parent.mkdir(parents=True)
python.touch()
python.chmod(0o755)
packages = python.parent if tag.startswith("win-") else python.parent.parent
(packages / ("Lib/site-packages" if tag.startswith("win-") else "lib/python3.12/site-packages")).mkdir(parents=True)
for file in ["scripts/check_office.py", *(f"office-{kind}/SKILL.md" for kind in ("docx", "pptx", "xlsx"))]:
path = resources / "office-skills" / file
path.parent.mkdir(parents=True, exist_ok=True)
path.touch()
return office
@@ -41,6 +58,43 @@ def test_unknown_explicit_mode_fails_loud() -> None:
resolve_bundled_launch_args("bogus")
@pytest.mark.parametrize("target", ["linux-x64", "linux-arm64", "macos-arm64", "macos-x64", "win-x64"])
@pytest.mark.parametrize("invalid", [None, "manifest", "platform", "python", "skills", "packages", "mode"])
def test_authoring_resources_validate_installed_and_wheel_payloads(tmp_path: Path, target: str, invalid: str | None) -> None:
executable = tmp_path / f"deepseek-harness-sdk-runtime-{target}"
_resource_sidecars(executable)
root = tmp_path / target
python = root / "primary-runtime/dependencies/python" / ("python.exe" if target == "win-x64" else "bin/python3")
if invalid == "mode" and target == "win-x64":
pytest.skip("Windows executables do not require a POSIX executable bit")
if invalid == "manifest":
(root / "primary-runtime/runtime.json").unlink()
elif invalid == "platform":
manifest_path = root / "primary-runtime/runtime.json"
manifest = json.loads(manifest_path.read_text())
manifest["arch"] = "wrong"
manifest_path.write_text(json.dumps(manifest))
elif invalid == "python":
python.unlink()
elif invalid == "skills":
(root / "office-skills/office-docx/SKILL.md").unlink()
elif invalid == "packages":
next(root.rglob("site-packages")).rmdir()
elif invalid == "mode":
python.chmod(0o644)
archive_path = tmp_path / "payload.zip"
with zipfile.ZipFile(archive_path, "w") as archive:
for path in root.rglob("*"):
archive.write(path, str(path.relative_to(root)).replace("\\", "/"))
with zipfile.ZipFile(archive_path) as archive:
for candidate in (root, zipfile.Path(archive)):
if invalid is None:
validate_resources(candidate, target)
else:
with pytest.raises((ValueError, FileNotFoundError)):
validate_resources(candidate, target)
def test_unknown_env_mode_fails_loud(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setenv(RUNTIME_MODE_ENV_VAR, "bogus")
with pytest.raises(ValueError, match="expected 'exe' or 'node'"):
@@ -64,7 +118,7 @@ def test_runtime_requires_spawn_helper_only_on_macos(
linux = runtime_dir / "deepseek-harness-sdk-runtime-linux-x64"
linux.touch()
Path(f"{linux}-rg").touch()
_office_sidecar(linux)
_resource_sidecars(linux)
macos = runtime_dir / "deepseek-harness-sdk-runtime-macos-arm64"
macos.touch()
Path(f"{macos}-rg").touch()
@@ -85,7 +139,7 @@ def test_windows_runtime_uses_exe_payload_and_exe_sidecar(
executable = runtime_dir / "deepseek-harness-sdk-runtime-win-x64.exe"
executable.touch()
(runtime_dir / "deepseek-harness-sdk-runtime-win-x64-rg.exe").touch()
_office_sidecar(executable)
_resource_sidecars(executable)
monkeypatch.setattr(runtime, "bundled_package_dir", lambda: tmp_path)
monkeypatch.setattr(runtime, "_current_platform_tag", lambda: "win-x64")
@@ -122,7 +176,7 @@ def test_runtime_requires_ripgrep_sidecar(
runtime.bundled_runtime_path()
def test_runtime_requires_complete_office_sidecar(
def test_runtime_requires_complete_resource_sidecars(
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
) -> None:
executable = tmp_path / "runtime" / "deepseek-harness-sdk-runtime-linux-x64"
@@ -134,7 +188,7 @@ def test_runtime_requires_complete_office_sidecar(
with pytest.raises(FileNotFoundError, match="Office sidecar"):
runtime.bundled_runtime_path()
office = _office_sidecar(executable)
office = _resource_sidecars(executable)
assert runtime.bundled_runtime_path() == executable
(office / "node_modules/@deepseek-ai/libreoffice-kit-wasm/prebuilds.json").unlink()
with pytest.raises(FileNotFoundError, match="Office sidecar"):
@@ -250,7 +304,7 @@ def test_runtime_requires_its_platform_office_engine(
executable.with_name(f"{executable.stem}-rg{extension}").touch()
if target.startswith("macos-"):
Path(f"{executable}-spawn-helper").touch()
office = _office_sidecar(executable, native_targets)
office = _resource_sidecars(executable, native_targets)
monkeypatch.setattr(runtime, "bundled_package_dir", lambda: tmp_path)
monkeypatch.setattr(runtime, "_current_platform_tag", lambda: target)
assert runtime.bundled_runtime_path() == executable