Merge remote-tracking branch 'origin/master' into worktree/provider-routed-llm-adapters
# Conflicts: # docs/config-catalog.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/core.md # docs/event-producer-consumer.md # docs/persistence-catalog.md # examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl # examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl # examples/acp-agent/tests/snapshots/both-mode-turn/session.jsonl # examples/acp-agent/tests/snapshots/hook-cc-pretool-ask/session.jsonl # examples/acp-agent/tests/snapshots/skill-load/session.jsonl # examples/acp-agent/tests/snapshots/text-turn/session.jsonl # examples/sandbox-acp-agent/cordis.yml # examples/sandbox-acp-agent/tests/snapshots/escalation-approved/session.jsonl # examples/sandbox-acp-agent/tests/snapshots/escalation-rejected/session.jsonl # examples/sandbox-acp-agent/tests/snapshots/mode-switching/session.jsonl # packages/compact/compact-basic/README.md # packages/compact/compact-basic/src/index.ts # packages/compact/compact-basic/tests/compact-basic.spec.ts # packages/core/agent-loop/README.md # packages/core/agent-loop/src/loop.ts # packages/core/agent-loop/tests/properties.spec.ts # packages/core/session/README.md # packages/core/session/src/types.ts # packages/core/session/tests/derived-cache.spec.ts # packages/llm/llm-deepseek/src/index.ts # packages/llm/llm-pi-ai/README.md # packages/llm/llm-pi-ai/src/adapter.ts # packages/llm/llm-pi-ai/src/convert.ts # packages/llm/llm-pi-ai/tests/adapter.spec.ts # packages/llm/llm/README.md # packages/llm/llm/src/call-config.ts # packages/llm/llm/src/index.ts # packages/ui/acp-agent/src/index.ts # packages/ui/acp/tests/harness.ts # packages/ui/jsonrpc/README.md # packages/ui/jsonrpc/src/server.ts # packages/ui/stdio-agent/README.md # packages/ui/stdio-agent/src/index.ts # python/sdk/README.i18n.yaml
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
|
||||
README.md: b1189a789963a5e4180cc4ee402c885b0ec82dca
|
||||
README.zh.md: 721221418eb65f323f521a4fa16cbc355d283f0d
|
||||
README.md: 80c9d1f50d26fc4f4670800fd7d7f5ea442ad891
|
||||
README.zh.md: ffedb5eb30f17388fe589863dbc654b22716b40c
|
||||
|
||||
@@ -38,6 +38,6 @@ with DeepSeekHarness(
|
||||
`assistant/message` event in the turn. Use `TurnResult.events` for the complete
|
||||
event stream, including intermediate assistant messages and tool activity.
|
||||
|
||||
The same behavior can be selected for the runtime subprocess with `DSH_CORDIS_CONFIG`. The injection lives in `HarnessClient.start()`, so the low-level client's default launch gets it too: when the launch resolves to the bundled runtime and neither `cordis` nor a non-empty `DSH_CORDIS_CONFIG` is set (the runtime treats an empty value as absent, and so does the injection check), the bundled default configuration is used; an explicit `runtime_bin` or `launch_args_override` disables the injection entirely. See the [sdk-runtime README](../sdk-runtime/README.md) for the runtime carriers (production exe vs dev-only node closure) and how to obtain them.
|
||||
The same behavior can be selected for the runtime subprocess with `DSH_CORDIS_CONFIG`. The injection lives in `HarnessClient.start()`, so the low-level client's default launch gets it too: when the launch resolves to the bundled runtime and neither `cordis` nor a non-empty `DSH_CORDIS_CONFIG` is set (the runtime treats an empty value as absent, and so does the injection check), the bundled default configuration is used; an explicit `runtime_bin`, `bridge_bin`, or `launch_args_override` disables the injection entirely. See the [sdk-runtime README](../sdk-runtime/README.md) for the runtime carriers (production exe vs dev-only node closure) and how to obtain them.
|
||||
|
||||
`cwd` and `runtime_cwd` are resolved to absolute paths before subprocess launch, environment injection, and the wire handshake. The public API exposes only applied options: deployment persona and persistence belong in `cordis.yml`, while `session_root` remains the high-level convenience that sets `DSH_SESSION_ROOT`.
|
||||
|
||||
@@ -28,10 +28,10 @@ with DeepSeekHarness(
|
||||
result = harness.run("Make the requested code change.")
|
||||
```
|
||||
|
||||
`provider` 用于选择当前 Cordis 组合已注册的 provider 路由;`model` 是该适配器解析的模型 ID。内置默认组合注册 `deepseek`。自定义组合可以挂载 `llm-pi-ai`,在其中配置各 provider 的凭据与端点,再选择 pi-ai 已安装目录中的任意 provider/model。
|
||||
`provider` 用于选择当前 Cordis 组合已注册的提供方路由;`model` 是该适配器解析的模型 ID。内置默认组合注册 `deepseek`。自定义组合可以挂载 `llm-pi-ai`,在其中配置各提供方的凭据与端点,再选择 pi-ai 已安装目录中的任意提供方/模型组合。
|
||||
|
||||
`TurnResult.final_response` 是本轮次最后一个 `assistant/message` 事件的文本内容。完整的事件流(包括中间的助手消息与工具活动)用 `TurnResult.events` 获取。
|
||||
|
||||
同样的行为也可以通过 `DSH_CORDIS_CONFIG` 为运行时子进程选定。注入逻辑位于 `HarnessClient.start()`,因此底层客户端的默认启动也具有此行为:当启动解析到内置运行时,且 `cordis` 与非空的 `DSH_CORDIS_CONFIG` 均未设置时(运行时把空值视为缺省,注入检查与之一致),使用内置的默认配置;显式给出 `runtime_bin` 或 `launch_args_override` 则完全禁用注入。运行时载体(生产用 exe 与仅限开发的 `node` 闭包)及其获取方式见 [sdk-runtime README](../sdk-runtime/README.md)。
|
||||
同样的行为也可以通过 `DSH_CORDIS_CONFIG` 为运行时子进程选定。注入逻辑位于 `HarnessClient.start()`,因此底层客户端的默认启动也具有此行为:当启动解析到内置运行时,且 `cordis` 与非空的 `DSH_CORDIS_CONFIG` 均未设置时(运行时把空值视为缺省,注入检查与之一致),使用内置的默认配置;显式给出 `runtime_bin`、`bridge_bin` 或 `launch_args_override` 则完全禁用注入。运行时载体(生产用 exe 与仅限开发的 `node` 闭包)及其获取方式见 [sdk-runtime README](../sdk-runtime/README.md)。
|
||||
|
||||
`cwd` 与 `runtime_cwd` 会在启动子进程、注入环境变量和协议握手前解析为绝对路径。公开 API 只暴露真正生效的选项:部署的角色设定与持久化配置归 `cordis.yml` 管理,而 `session_root` 继续作为设置 `DSH_SESSION_ROOT` 的高层便捷选项。
|
||||
|
||||
@@ -24,8 +24,7 @@ testpaths = ["tests"]
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/deepseek_harness"]
|
||||
|
||||
# Editable: the runtime package's executables are injected into its source
|
||||
# tree AFTER install (by scripts/build-exe-for-python-sdk.ts or a manual copy); an
|
||||
# editable install sees them immediately instead of freezing a wheel snapshot.
|
||||
# Editable installs see runtime executables injected after installation instead
|
||||
# of freezing a wheel snapshot.
|
||||
[tool.uv.sources]
|
||||
deepseek-harness-runtime-bin = { path = "../sdk-runtime", editable = true }
|
||||
|
||||
@@ -418,16 +418,10 @@ class HarnessClient:
|
||||
return resolve_bundled_launch_args()
|
||||
|
||||
def _inject_bundled_default_config(self, env: dict[str, str]) -> None:
|
||||
"""Restore the zero-config experience over the config-mandatory bundled runtime.
|
||||
"""Inject the default config for a bundled launch with no non-empty config.
|
||||
|
||||
The bundled runtime (single-file exe or the dev-only node closure)
|
||||
always demands an explicit config. When the launch resolves to the
|
||||
bundled runtime (no ``runtime_bin`` / ``bridge_bin`` /
|
||||
``launch_args_override``) and the merged subprocess environment has no
|
||||
non-empty ``DSH_CORDIS_CONFIG`` — the runtime bin treats an empty
|
||||
value as absent, so this does too — inject the runtime package's
|
||||
checked-in default cordis.yml. With an explicit runtime or config
|
||||
channel the client stays out of the way.
|
||||
Both bundled carriers require an explicit config. Explicit runtime,
|
||||
launch-argument, and config channels remain untouched.
|
||||
"""
|
||||
uses_bundled_runtime = (
|
||||
self.config.launch_args_override is None
|
||||
@@ -436,9 +430,7 @@ class HarnessClient:
|
||||
)
|
||||
if not uses_bundled_runtime or env.get("DSH_CORDIS_CONFIG"):
|
||||
return
|
||||
# Cannot fail: _default_launch_args() already imported the runtime
|
||||
# package on this (bundled) path, raising the actionable install
|
||||
# error when it is absent.
|
||||
# _default_launch_args already imported the package or raised its install error.
|
||||
from deepseek_harness_runtime import bundled_default_config_path
|
||||
|
||||
env["DSH_CORDIS_CONFIG"] = str(bundled_default_config_path())
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
"""Manual keyless smoke: drive the repo-source jsonrpc-agent bin (node + tsx).
|
||||
"""Drive the repo-source JSON-RPC bin through the SDK and a keyless mock SSE server.
|
||||
|
||||
Runs the SDK against `packages/ui/jsonrpc-agent/src/bin.ts` executed from the
|
||||
repo checkout (requires `pnpm install`; no build, no API key — the model
|
||||
endpoint is a local mock SSE server). The bin only boots the supplied
|
||||
cordis.yml — the stdio JSON-RPC server itself comes from the config's
|
||||
`@deepseek-ai/dsh-jsonrpc` entry — so the runtime package's default cordis.yml
|
||||
is passed explicitly. Not collected by pytest; run it directly:
|
||||
`python tests/manual_sdk_agent_smoke.py`.
|
||||
Requires ``pnpm install`` but no build. This manual test is not collected by
|
||||
pytest; run ``python tests/manual_sdk_agent_smoke.py``.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
"""Smoke tests against the bundled dsh-jsonrpc-agent artifacts.
|
||||
"""Keyless boot tests for the production exe and development node carrier.
|
||||
|
||||
These boot the runtime the way an installed SDK does, once per bundled
|
||||
carrier: the platform single-file exe (production) and the dev-only node
|
||||
closure under ``runtime/node`` driven by system ``node``. Each carrier skips
|
||||
independently when its artifact is absent on this machine — build or fetch it
|
||||
per the FileNotFoundError guidance quoted in the skip reason. Keyless: the
|
||||
dummy DEEPSEEK_API_KEY only satisfies the adapter's load-time check;
|
||||
initialize/shutdown never call a model.
|
||||
Each carrier skips independently when absent. The dummy API key only satisfies
|
||||
adapter loading; initialize and shutdown do not call a model.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
@@ -21,8 +16,7 @@ from deepseek_harness_runtime import resolve_bundled_launch_args
|
||||
|
||||
_MODES = ("exe", "node")
|
||||
|
||||
# The serving surface is itself a plugin: without the dsh-jsonrpc entry the
|
||||
# runtime boots an agent nobody can talk to and exits 0 on stdin EOF.
|
||||
# The config must include the JSON-RPC serving plugin.
|
||||
_CORDIS_YML = """\
|
||||
- id: jsonrpc
|
||||
name: '@deepseek-ai/dsh-jsonrpc'
|
||||
@@ -57,9 +51,7 @@ def _client(tmp_path: Path, launch_args: tuple[str, ...]) -> HarnessClient:
|
||||
"DSH_CORDIS_CONFIG": "./cordis.yml",
|
||||
"DSH_SESSION_ROOT": str(tmp_path / "sessions"),
|
||||
"DSH_CWD": str(tmp_path),
|
||||
# initialize() lazily mounts the llm-deepseek adapter for the
|
||||
# requested model; a dummy key keeps the keyless boot green
|
||||
# (initialize/shutdown never call the model).
|
||||
# The lazily mounted adapter requires a key even without a model call.
|
||||
"DEEPSEEK_API_KEY": "sk-dummy-for-boot",
|
||||
"DEEPSEEK_BASE_URL": "http://127.0.0.1:9",
|
||||
},
|
||||
@@ -119,7 +111,4 @@ def test_zero_config_run_injects_bundled_default_cordis_config(
|
||||
request_timeout_seconds=120,
|
||||
)
|
||||
with harness:
|
||||
# __enter__ boots the runtime, which exits with a usage error unless
|
||||
# HarnessClient.start() injected the bundled default config over the
|
||||
# unset/empty DSH_CORDIS_CONFIG; __exit__ shuts it down.
|
||||
pass
|
||||
|
||||
@@ -682,11 +682,9 @@ with open(os.environ["SEEN"], "w") as seen:
|
||||
def _install_fake_bundled_runtime(
|
||||
tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
||||
) -> Path:
|
||||
"""Fake the deepseek-harness-runtime-bin package on sys.path.
|
||||
"""Install a fake runtime package that records config and serves lifecycle calls.
|
||||
|
||||
A stub exe that dumps DSH_CORDIS_CONFIG to $ENV_DUMP before serving
|
||||
initialize/shutdown, plus a module exposing the resolution surface the
|
||||
client consumes. Returns the fake bundled default config path.
|
||||
Returns the fake bundled default config path.
|
||||
"""
|
||||
runtime = tmp_path / "dsh-jsonrpc-agent"
|
||||
runtime.write_text(
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
"""Keyless tests for the deepseek_harness_runtime resolution API.
|
||||
|
||||
These never launch a runtime, so they run everywhere regardless of which
|
||||
bundled artifacts are present; the launch-and-boot coverage lives in
|
||||
``test_bundled_runtime.py``.
|
||||
"""
|
||||
"""Keyless runtime-resolution tests; launch coverage lives in test_bundled_runtime.py."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
Reference in New Issue
Block a user