Merge remote-tracking branch 'origin/master' into worktree/web-multimodal-image-input

# Conflicts:
#	docs/architecture.i18n.yaml
#	docs/architecture.md
#	docs/architecture.zh.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/llm-streaming.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	packages/client/connection/README.i18n.yaml
#	packages/client/connection/README.md
#	packages/client/connection/README.zh.md
#	packages/client/connection/src/client/fixture.ts
#	packages/client/runtime/README.i18n.yaml
#	packages/client/runtime/README.md
#	packages/client/runtime/README.zh.md
#	packages/client/ui-conversation/README.i18n.yaml
#	packages/client/ui-conversation/src/client/chat/AssistantMarkdown.tsx
#	packages/client/ui-conversation/src/client/chat/ChatView.tsx
#	packages/host/apiproxy/README.i18n.yaml
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/llm/llm-deepseek/tests/adapter.spec.ts
#	packages/llm/llm-pi-ai/README.i18n.yaml
#	packages/llm/llm-pi-ai/src/index.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/llm/llm/README.md
#	packages/llm/llm/README.zh.md
#	packages/llm/llm/src/index.ts
#	packages/llm/llm/src/types.ts
This commit is contained in:
creatixchu
2026-07-31 02:14:07 +08:00
465 changed files with 9284 additions and 1401 deletions

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/README.md
README.md: f1e16e724efd6f71f63e475e47d7e4d704b8ceac
README.zh.md: 11ff235a0eea23acab5f1737537c799021c35bea
README.md: bb3420f1a1bd461facbd0eb1312a255df1da4412
README.zh.md: adc8e377ca9f70838b6164301a9052e2247c8eff

View File

@@ -25,7 +25,7 @@ By default, the SDK launches the bundled single-file `dsh-jsonrpc-agent` executa
from deepseek_harness import DeepSeekHarness
with DeepSeekHarness(
provider="deepseek",
provider="deepseek-official",
model="deepseek-v4-flash",
max_tokens=49_152,
cordis="examples/jsonrpc-agent/cordis.yml",
@@ -33,7 +33,7 @@ with DeepSeekHarness(
result = harness.run("Make the requested code change.")
```
`provider` selects a provider route registered by the chosen Cordis composition; `model` is the model id resolved by that adapter. `max_tokens` is an optional positive per-request output-token cap for the root agent and its in-process descendants; omission leaves the provider default in control. Compaction summaries keep the separate limit configured by their compaction plugin. The bundled default composition registers `deepseek`. A custom composition can mount `llm-pi-ai`, configure provider-specific credentials/endpoints there, and select any provider/model present in pi-ai's installed catalog.
`provider` selects a provider route registered by the chosen Cordis composition; `model` is the model id resolved by that adapter. `max_tokens` is an optional positive per-request output-token cap for the root agent and its in-process descendants; omission leaves the provider default in control. Compaction summaries keep the separate limit configured by their compaction plugin. The bundled default composition registers `deepseek-official`. A custom composition can mount `llm-pi-ai`, configure provider-specific credentials/endpoints there, and select any provider/model present in pi-ai's installed catalog.
`HarnessClient` retains discovered subagent ancestry for the lifetime of the runtime process. During each `Session.run()`, `TurnResult.notifications` and `on_notification` receive the root session and all known descendant notifications in wire order, including nested subagent lifecycle and session events. `TurnResult.events` remains the root session's complete event stream, and `TurnResult.final_response` is the text content from its last `assistant/message`; descendant messages therefore cannot replace the root response.

View File

@@ -21,7 +21,7 @@ with DeepSeekHarness() as harness:
from deepseek_harness import DeepSeekHarness
with DeepSeekHarness(
provider="deepseek",
provider="deepseek-official",
model="deepseek-v4-flash",
max_tokens=49_152,
cordis="examples/jsonrpc-agent/cordis.yml",
@@ -29,7 +29,7 @@ with DeepSeekHarness(
result = harness.run("Make the requested code change.")
```
`provider` 用于选择当前 Cordis 组合已注册的提供方路由;`model` 是该适配器解析的模型 ID。`max_tokens` 是可选的正整数,用于限制根 agent 及其进程内后代每次请求的输出 token省略时由提供方默认值控制。压缩摘要继续使用压缩插件单独配置的上限。内置默认组合注册 `deepseek`。自定义组合可以挂载 `llm-pi-ai`,在其中配置各提供方的凭据与端点,再选择 pi-ai 已安装目录中的任意提供方/模型组合。
`provider` 用于选择当前 Cordis 组合已注册的提供方路由;`model` 是该适配器解析的模型 ID。`max_tokens` 是可选的正整数,用于限制根 agent 及其进程内后代每次请求的输出 token省略时由提供方默认值控制。压缩摘要继续使用压缩插件单独配置的上限。内置默认组合注册 `deepseek-official`。自定义组合可以挂载 `llm-pi-ai`,在其中配置各提供方的凭据与端点,再选择 pi-ai 已安装目录中的任意提供方/模型组合。
`HarnessClient` 会在运行时进程的生命周期内保留已发现的 subagent子 agent祖先关系。每次执行 `Session.run()` 时,`TurnResult.notifications``on_notification` 会按协议传输顺序收到根会话及所有已知后代的通知,其中包括嵌套 subagent 的生命周期事件与会话事件。`TurnResult.events` 仍只保存根会话的完整事件流,`TurnResult.final_response` 则取该会话最后一个 `assistant/message` 的文本内容,因此后代消息不会覆盖根会话回复。

View File

@@ -18,7 +18,7 @@ class DeepSeekHarnessConfig:
intentionally override or inject variables for a subprocess.
"""
provider: str = "deepseek"
provider: str = "deepseek-official"
model: str = "deepseek-v4-flash"
max_tokens: int | None = None
cwd: str | None = None

View File

@@ -72,7 +72,7 @@ def test_bundled_runtime_boots_a_cordis_config(tmp_path: Path, mode: str) -> Non
(tmp_path / "cordis.yml").write_text(_CORDIS_YML)
with _client(tmp_path, launch_args) as client:
init = client.initialize(provider="deepseek", cwd=str(tmp_path), model="deepseek-v4-pro")
init = client.initialize(provider="deepseek-official", cwd=str(tmp_path), model="deepseek-v4-pro")
assert init.serverInfo is not None
assert init.serverInfo.name == "deepseek-harness-sdk-runtime"
@@ -89,7 +89,7 @@ def test_bundled_runtime_surfaces_unbundled_plugin_failure(tmp_path: Path, mode:
client.start()
try:
with pytest.raises((TransportClosedError, TimeoutError)) as excinfo:
client.initialize(provider="deepseek", cwd=str(tmp_path), model="deepseek-v4-pro")
client.initialize(provider="deepseek-official", cwd=str(tmp_path), model="deepseek-v4-pro")
finally:
client.close()

View File

@@ -94,7 +94,7 @@ for line in sys.stdin:
assert dumped_env["DSH_CORDIS_CONFIG"] == str(tmp_path / "cordis.yml")
assert json.loads(init_dump.read_text()) == {
"cwd": str(tmp_path),
"provider": "deepseek",
"provider": "deepseek-official",
"model": "deepseek-v4-flash",
"maxTokens": 4096,
}
@@ -404,7 +404,7 @@ for line in sys.stdin:
with HarnessClient(
HarnessConfig(launch_args_override=(sys.executable, str(script)))
) as client:
init = client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
init = client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
assert init.serverInfo.name == "fake-dsh"
client.session_prompt("main", [{"type": "text", "text": "fix it"}])
@@ -542,7 +542,7 @@ for line in sys.stdin:
raise RuntimeError("bad notification filter")
with HarnessClient(HarnessConfig(launch_args_override=(sys.executable, str(script)))) as client:
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
with (
client.subscribe_notifications(broken_filter) as broken,
client.subscribe_notifications(lambda notification: notification.method == "tick") as healthy,
@@ -579,7 +579,7 @@ for line in sys.stdin:
)
with HarnessClient(HarnessConfig(launch_args_override=(sys.executable, str(script)))) as client:
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
with pytest.raises(ValueError):
client.session_prompt("main", [{"type": "text", "text": "fix it"}])
@@ -608,7 +608,7 @@ for line in sys.stdin:
with HarnessClient(
HarnessConfig(launch_args_override=(sys.executable, str(script)))
) as client:
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
request = client.next_request()
assert request.id == "bridge-req-1"
@@ -642,7 +642,7 @@ for line in sys.stdin:
with HarnessClient(
HarnessConfig(launch_args_override=(sys.executable, str(script)))
) as client:
init = client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
init = client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
assert init.serverInfo.name == "fake-dsh"
@@ -664,7 +664,7 @@ time.sleep(60)
) as client:
start = time.monotonic()
try:
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
except TimeoutError:
assert time.monotonic() - start < 2
else:
@@ -700,7 +700,7 @@ for line in sys.stdin:
client.start()
proc = client._proc
assert proc is not None
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
start = time.monotonic()
client.close()
assert time.monotonic() - start < 2
@@ -731,7 +731,7 @@ for line in sys.stdin:
assert proc is not None
with pytest.raises(Exception, match="bad initialize"):
client.initialize(provider="deepseek", cwd=".", model="dsagent")
client.initialize(provider="deepseek-official", cwd=".", model="dsagent")
assert proc.wait(timeout=1) is not None
assert client._proc is None
@@ -773,7 +773,7 @@ for line in sys.stdin:
client = HarnessClient(HarnessConfig(launch_args_override=(sys.executable, str(script))))
client.start()
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
client.close()
client.close()
@@ -796,7 +796,7 @@ sys.exit(42)
)
) as client:
with pytest.raises(Exception, match="fatal bridge exploded"):
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
def test_client_serializes_concurrent_writes(tmp_path: Path) -> None:
@@ -827,7 +827,7 @@ with open(os.environ["SEEN"], "w") as seen:
env={"SEEN": str(output)},
)
) as client:
client.initialize(provider="deepseek", cwd="/workspace", model="dsagent")
client.initialize(provider="deepseek-official", cwd="/workspace", model="dsagent")
threads = [
threading.Thread(target=client.notify, args=(f"notice-{index}", {"index": index}))
for index in range(50)
@@ -898,7 +898,7 @@ def test_client_default_launch_uses_bundled_runtime_and_injects_default_config(
monkeypatch.setenv("DSH_CORDIS_CONFIG", ambient_config)
with HarnessClient(HarnessConfig(env={"ENV_DUMP": str(env_dump)})) as client:
init = client.initialize(provider="deepseek", cwd="/workspace", model="deepseek-v4-pro")
init = client.initialize(provider="deepseek-official", cwd="/workspace", model="deepseek-v4-pro")
assert init.serverInfo.name == "bundled-runtime"
assert json.loads(env_dump.read_text())["DSH_CORDIS_CONFIG"] == str(default_config)
@@ -914,7 +914,7 @@ def test_client_respects_explicit_config_over_bundled_default(
with HarnessClient(
HarnessConfig(env={"ENV_DUMP": str(env_dump), "DSH_CORDIS_CONFIG": "./explicit.yml"})
) as client:
client.initialize(provider="deepseek", cwd="/workspace", model="deepseek-v4-pro")
client.initialize(provider="deepseek-official", cwd="/workspace", model="deepseek-v4-pro")
assert json.loads(env_dump.read_text())["DSH_CORDIS_CONFIG"] == "./explicit.yml"