Merge current subagent naming stack into Team session UI
This commit is contained in:
commit
80f70969d9
5594 files changed
+141677
-692708
No files matched your search
@@ -9,8 +9,8 @@
|
||||
en: 8e99640e4936332d
|
||||
zh: 729d5de1e0ad2869
|
||||
/python-contributor-workflows/validate-the-sdk:
|
||||
en: 37884fe76e167a0e
|
||||
zh: 4b6e50768c4bb945
|
||||
en: ad4d61dccf2756a4
|
||||
zh: 9365affc91287738
|
||||
/python-contributor-workflows/run-against-node-source:
|
||||
en: 940c941d189a8248
|
||||
zh: 321f5183383d4a12
|
||||
|
||||
@@ -38,7 +38,7 @@ uv run --project python/sdk python scripts/smoke-python-runtime.py \
|
||||
--scenario sdk-minimal --exe dist-exe/deepseek-harness-sdk-runtime-macos-arm64
|
||||
```
|
||||
|
||||
SDK scenarios compare committed expected output under `scripts/snapshots/python-sdk-single-exe/`. `minimal/model-visible.json` pins the Linux/macOS `sdk-minimal` profile's assembled system prompts, advertised tool schemas, and model-visible messages; `minimal/win-x64/model-visible.json` pins its PowerShell counterpart. `authoring/model-visible.json` pins the Linux/macOS Office authoring catalog and dependency result; `authoring/win-x64/model-visible.json` pins the Windows catalog, including the ACL diagnostic skill. A plugin that contributes an unintended system section or user message therefore fails the job, and every message the profile emits is compared. `advanced/` pins one complex process's SDK result and parent/child session logs across every target. `restart/` launches two complete SDK runtime processes against one persistence root and snapshots their isolated model histories, high-level results, and separate durable logs across every target. `sdk-minimal-in-history` reuses the persistent-shell and editor scenario with a section that changes after the first successful shell call. `minimal-in-history/prompt-history.json` pins both prompt versions, the unchanged leading prompt in later requests, appended SDK system-message events, and `request/context.systemPromptUpdate`; tool schemas stay fixed and the editor file is checked independently. `sdk-dynamic-tools` pins native tool additions and removals in `dynamic-tools/tool-history.json`, including historical header references and agreement between Python SDK results, notifications, and persisted events. Rerun the owning scenario with `--update-snapshots` and review that diff before committing it.
|
||||
SDK scenarios compare committed expected output under `scripts/snapshots/python-sdk-single-exe/`. `minimal/model-visible.json` pins the Linux/macOS `sdk-minimal` profile's assembled system prompts, advertised tool schemas, and model-visible messages; `minimal/win-x64/model-visible.json` pins its PowerShell counterpart. `authoring/model-visible.json` pins the Linux/macOS Office authoring catalog and dependency result; `authoring/win-x64/model-visible.json` pins the Windows catalog, including the ACL diagnostic skill. A plugin that contributes an unintended system section or user message therefore fails the job, and every message the profile emits is compared. `advanced/` pins one complex process's SDK result and parent/child session logs across every target. `restart/` launches two complete SDK runtime processes against one persistence root and snapshots their isolated model histories, high-level results, and separate durable logs across every target. Its resumed turn initializes a different model and pins the persisted selection, request route, and SDK event sequence. `sdk-minimal-in-history` reuses the persistent-shell and editor scenario with a section that changes after the first successful shell call. `minimal-in-history/prompt-history.json` pins both prompt versions, the unchanged leading prompt in later requests, appended SDK system-message events, and `request/context.systemPromptUpdate`; tool schemas stay fixed and the editor file is checked independently. `sdk-dynamic-tools` pins native tool additions and removals in `dynamic-tools/tool-history.json`, including historical header references and agreement between Python SDK results, notifications, and persisted events. Rerun the owning scenario with `--update-snapshots` and review that diff before committing it.
|
||||
|
||||
`scheduler-recovery/` records a failed tool turn and a subsequent completed turn. It preserves the original `UNKNOWN` turn error, the first tool's completed result, and `TOOL_OUTCOME_UNKNOWN` / `TOOL_NOT_STARTED` results for the remaining calls. `sdk-snapshot` and `all` include this case; `--scenario sdk-recovery` runs it alone.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ uv run --project python/sdk python scripts/smoke-python-runtime.py \
|
||||
--scenario sdk-minimal --exe dist-exe/deepseek-harness-sdk-runtime-macos-arm64
|
||||
```
|
||||
|
||||
SDK 场景会比对 `scripts/snapshots/python-sdk-single-exe/` 下已提交的期望输出。`minimal/model-visible.json` 固定 Linux/macOS `sdk-minimal` profile 所组装的系统提示词、对外公布的工具 schema 与模型可见消息;`minimal/win-x64/model-visible.json` 固定对应的 PowerShell 版本。`authoring/model-visible.json` 固定 Linux/macOS 的 Office 创作技能目录和依赖结果;`authoring/win-x64/model-visible.json` 固定 Windows 的技能目录,其中包含 ACL 诊断技能。因此,插件一旦贡献出计划外的系统分段或 user 消息,该任务即失败,且该 profile 发出的每条消息都会参与比对。`advanced/` 跨所有目标固定一个复杂进程的 SDK 结果及父/子会话日志。`restart/` 针对同一持久化根目录启动两个完整 SDK 运行时进程,并跨所有目标固定其彼此隔离的模型历史、高层结果与独立持久日志。`sdk-minimal-in-history` 复用持久 shell 与编辑器场景,并在首次 shell 调用成功后更改一个分段。`minimal-in-history/prompt-history.json` 固定两个提示词版本、后续请求中不变的首条提示词、追加的 SDK system-message 事件及 `request/context.systemPromptUpdate`;工具 schema 保持不变,并独立检查编辑器创建的文件。`sdk-dynamic-tools` 在 `dynamic-tools/tool-history.json` 中固定原生工具的新增与移除,包括历史 header 引用,以及 Python SDK 结果、通知与持久事件的一致性。重新运行对应场景时加上 `--update-snapshots`,并在提交前审阅该差异。
|
||||
SDK 场景会比对 `scripts/snapshots/python-sdk-single-exe/` 下已提交的期望输出。`minimal/model-visible.json` 固定 Linux/macOS `sdk-minimal` profile 所组装的系统提示词、对外公布的工具 schema 与模型可见消息;`minimal/win-x64/model-visible.json` 固定对应的 PowerShell 版本。`authoring/model-visible.json` 固定 Linux/macOS 的 Office 创作技能目录和依赖结果;`authoring/win-x64/model-visible.json` 固定 Windows 的技能目录,其中包含 ACL 诊断技能。因此,插件一旦贡献出计划外的系统分段或 user 消息,该任务即失败,且该 profile 发出的每条消息都会参与比对。`advanced/` 跨所有目标固定一个复杂进程的 SDK 结果及父/子会话日志。`restart/` 针对同一持久化根目录启动两个完整 SDK 运行时进程,并跨所有目标固定其彼此隔离的模型历史、高层结果与独立持久日志。恢复后的轮次初始化另一个模型,并固定持久模型选择、请求路由与 SDK 事件顺序。`sdk-minimal-in-history` 复用持久 shell 与编辑器场景,并在首次 shell 调用成功后更改一个分段。`minimal-in-history/prompt-history.json` 固定两个提示词版本、后续请求中不变的首条提示词、追加的 SDK system-message 事件及 `request/context.systemPromptUpdate`;工具 schema 保持不变,并独立检查编辑器创建的文件。`sdk-dynamic-tools` 在 `dynamic-tools/tool-history.json` 中固定原生工具的新增与移除,包括历史 header 引用,以及 Python SDK 结果、通知与持久事件的一致性。重新运行对应场景时加上 `--update-snapshots`,并在提交前审阅该差异。
|
||||
|
||||
`scheduler-recovery/` 记录一个失败的工具轮次及后续完成的轮次。它保留原始的 `UNKNOWN` 轮次错误、第一个工具已完成的结果,以及其余调用的 `TOOL_OUTCOME_UNKNOWN` / `TOOL_NOT_STARTED` 结果。`sdk-snapshot` 和 `all` 包含此场景;`--scenario sdk-recovery` 单独运行它。
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
"@deepseek-ai/dsh": "workspace:*",
|
||||
"@deepseek-ai/dsh-acp": "workspace:*",
|
||||
"@deepseek-ai/dsh-agent": "workspace:*",
|
||||
"@deepseek-ai/dsh-agent-controller": "workspace:*",
|
||||
"@deepseek-ai/dsh-agent-default-model": "workspace:*",
|
||||
"@deepseek-ai/dsh-agent-instructions": "workspace:*",
|
||||
"@deepseek-ai/dsh-agent-loop": "workspace:*",
|
||||
@@ -111,6 +110,7 @@
|
||||
"@deepseek-ai/dsh-storage": "workspace:*",
|
||||
"@deepseek-ai/dsh-storage-domain": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-names": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-acp": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-fork-in-process": "workspace:*",
|
||||
"@deepseek-ai/dsh-subagent-spawn-in-process": "workspace:*",
|
||||
@@ -128,6 +128,7 @@
|
||||
"@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-executor-ptc": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-fs": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-fs-search": "workspace:*",
|
||||
"@deepseek-ai/dsh-tool-goal": "workspace:*",
|
||||
|
||||
@@ -9,8 +9,11 @@
|
||||
en: ddf4dabea526cef1
|
||||
zh: 6e31cab10d2f3ed8
|
||||
/deepseek-harness-python-sdk/start-a-runtime:
|
||||
en: 5fceaffcc35039c6
|
||||
zh: 1d87e3defe7e875b
|
||||
en: 1ae09bebf0f9e19b
|
||||
zh: 55a0d557a2cae4d8
|
||||
/deepseek-harness-python-sdk/client-approvals:
|
||||
en: fc69be1beb8abff1
|
||||
zh: 91b56781931a6f68
|
||||
/deepseek-harness-python-sdk/customize-plugins:
|
||||
en: 69a6a6745c6e89c1
|
||||
zh: 85e82a4cc31e16e5
|
||||
|
||||
@@ -58,6 +58,27 @@ with DeepSeekHarness(dsh_home="/absolute/path/to/saved-home") as harness:
|
||||
result = session.run("Continue the task.")
|
||||
```
|
||||
|
||||
<a id="client-approvals"></a>
|
||||
## Client approvals
|
||||
|
||||
This low-level example receives one approval and rejects it. Use a dedicated request-handling thread or loop for a full run: `next_request()` blocks, and the request handler must run concurrently with `session/wait` or a high-level `run()`. Set `approval_requests=True` on `HarnessClient.initialize()` or `DeepSeekHarnessConfig` only when that handler is ready. Omission preserves the runtime's answerer chain. Decisions are one-shot; invalid responses and lost connections fail closed, and cancellation discards late replies. `ApprovalRequestResult` validates response values when constructing decisions.
|
||||
|
||||
```py
|
||||
from deepseek_harness import ApprovalRequestParams, HarnessClient, HarnessConfig
|
||||
|
||||
with HarnessClient(HarnessConfig(dsh_home="/absolute/path/to/dsh-home")) as client:
|
||||
client.initialize(cwd="/absolute/path/to/workspace", provider="deepseek-official",
|
||||
model="deepseek-v4-flash", approval_requests=True)
|
||||
client.session_prompt("main", [{"type": "text", "text": "Run the operation requiring approval."}])
|
||||
request = client.next_request()
|
||||
if request.method == "approval/request":
|
||||
question = ApprovalRequestParams.model_validate(request.payload)
|
||||
print(question.toolName, question.reason)
|
||||
client.respond(request.id, {"outcome": "rejected"})
|
||||
else:
|
||||
client.respond_error(request.id, code=-32601, message="Unsupported client request")
|
||||
```
|
||||
|
||||
## 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:
|
||||
|
||||
@@ -58,6 +58,27 @@ with DeepSeekHarness(dsh_home="/absolute/path/to/saved-home") as harness:
|
||||
result = session.run("Continue the task.")
|
||||
```
|
||||
|
||||
<a id="client-approvals"></a>
|
||||
## 客户端审批
|
||||
|
||||
此底层示例接收一次审批并拒绝。完整运行应使用专门处理请求的线程或循环:`next_request()` 会阻塞,请求处理器必须与 `session/wait` 或高层 `run()` 并行运行。仅在处理器就绪时,在 `HarnessClient.initialize()` 或 `DeepSeekHarnessConfig` 设置 `approval_requests=True`;省略时保留运行时应答链。决定只作用于单次操作;无效响应和断连会拒绝放行,取消后丢弃迟到响应。构造决定时,可用 `ApprovalRequestResult` 校验响应值。
|
||||
|
||||
```py
|
||||
from deepseek_harness import ApprovalRequestParams, HarnessClient, HarnessConfig
|
||||
|
||||
with HarnessClient(HarnessConfig(dsh_home="/absolute/path/to/dsh-home")) as client:
|
||||
client.initialize(cwd="/absolute/path/to/workspace", provider="deepseek-official",
|
||||
model="deepseek-v4-flash", approval_requests=True)
|
||||
client.session_prompt("main", [{"type": "text", "text": "Run the operation requiring approval."}])
|
||||
request = client.next_request()
|
||||
if request.method == "approval/request":
|
||||
question = ApprovalRequestParams.model_validate(request.payload)
|
||||
print(question.toolName, question.reason)
|
||||
client.respond(request.id, {"outcome": "rejected"})
|
||||
else:
|
||||
client.respond_error(request.id, code=-32601, message="Unsupported client request")
|
||||
```
|
||||
|
||||
## 自定义插件
|
||||
|
||||
持久自定义属于 `dsh` profile。使用运行时 wheel 包提供的 `dsh` 命令初始化随附的 SDK profile,并安装外部 bundle:
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from .api import DeepSeekHarness, DeepSeekHarnessConfig, RunResult, Session
|
||||
from .client import HarnessClient, HarnessConfig, UserQuestionHandler
|
||||
from .errors import SdkProtocolError
|
||||
from .models import IncomingRequest, InitializeResponse, JsonObject, Notification, ServerInfo, UserQuestionAnswer, UserQuestionAnswerItem, UserQuestionRequest
|
||||
from .models import (
|
||||
ApprovalRequestParams, ApprovalRequestResult, IncomingRequest, InitializeResponse,
|
||||
JsonObject, Notification, ServerInfo, UserQuestionAnswer, UserQuestionAnswerItem, UserQuestionRequest,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"DeepSeekHarness",
|
||||
@@ -15,6 +18,8 @@ __all__ = [
|
||||
"UserQuestionAnswer",
|
||||
"UserQuestionAnswerItem",
|
||||
"SdkProtocolError",
|
||||
"ApprovalRequestParams",
|
||||
"ApprovalRequestResult",
|
||||
"IncomingRequest",
|
||||
"InitializeResponse",
|
||||
"JsonObject",
|
||||
|
||||
@@ -36,6 +36,7 @@ class DeepSeekHarnessConfig:
|
||||
base_url: str | None = None
|
||||
api_key: str | None = None
|
||||
on_user_question: UserQuestionHandler | None = None
|
||||
approval_requests: bool = False
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -112,6 +113,7 @@ class DeepSeekHarness:
|
||||
model=self.config.model,
|
||||
reasoning_effort=self.config.reasoning_effort,
|
||||
max_tokens=self.config.max_tokens,
|
||||
approval_requests=self.config.approval_requests,
|
||||
)
|
||||
self._initialized = True
|
||||
|
||||
|
||||
@@ -156,12 +156,21 @@ class HarnessClient:
|
||||
model: str,
|
||||
reasoning_effort: str | None = None,
|
||||
max_tokens: int | None = None,
|
||||
approval_requests: bool = False,
|
||||
) -> InitializeResponse:
|
||||
"""Initialize the runtime; approval_requests enables approval/request reception.
|
||||
|
||||
When enabled, drain next_request() concurrently with blocking waits and
|
||||
return one-operation decisions through respond(). Omission preserves the
|
||||
runtime's composed approval answerers.
|
||||
"""
|
||||
payload: JsonObject = {
|
||||
"cwd": str(Path(cwd).resolve()),
|
||||
"provider": provider,
|
||||
"model": model,
|
||||
}
|
||||
if approval_requests:
|
||||
payload["approvalRequests"] = True
|
||||
if reasoning_effort is not None:
|
||||
payload["reasoningEffort"] = reasoning_effort
|
||||
if max_tokens is not None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from typing import TypeAlias
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
from pydantic import BaseModel, Field, JsonValue as PydanticJsonValue
|
||||
|
||||
@@ -32,6 +32,20 @@ class InitializeResponse(BaseModel):
|
||||
serverInfo: ServerInfo | None = None
|
||||
|
||||
|
||||
class ApprovalRequestParams(BaseModel):
|
||||
"""Server-to-client approval/request payload after explicit handshake opt-in."""
|
||||
|
||||
sessionId: str
|
||||
toolName: str
|
||||
callId: str | None = None
|
||||
reason: str | None = None
|
||||
|
||||
|
||||
class ApprovalRequestResult(BaseModel):
|
||||
"""One-operation decision; allowed-once is the only grant."""
|
||||
|
||||
outcome: Literal["allowed-once", "rejected", "cancelled"]
|
||||
|
||||
class UserQuestionRequest(BaseModel):
|
||||
"""Runtime question batch; questions retain their options, detail, and presentation intent."""
|
||||
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
"""Approval request decoding and explicit wire capability negotiation."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from pydantic import ValidationError
|
||||
|
||||
from deepseek_harness import ApprovalRequestParams, ApprovalRequestResult, DeepSeekHarnessConfig, HarnessClient
|
||||
|
||||
|
||||
@pytest.mark.parametrize("enabled", [False, True])
|
||||
def test_approval_handshake_and_response(tmp_path: Path, enabled: bool) -> None:
|
||||
peer = tmp_path / "approval_peer.py"
|
||||
peer.write_text('''import json
|
||||
import sys
|
||||
for line in sys.stdin:
|
||||
msg = json.loads(line)
|
||||
if msg.get("method") == "initialize":
|
||||
print(json.dumps({"jsonrpc": "2.0", "id": msg["id"], "result": {"serverInfo": {"name": "test"}}}), flush=True)
|
||||
print(json.dumps({"jsonrpc": "2.0", "method": "capability", "params": msg["params"]}), flush=True)
|
||||
if msg["params"].get("approvalRequests"):
|
||||
print(json.dumps({"jsonrpc": "2.0", "id": "ask", "method": "approval/request", "params": {"sessionId": "main", "toolName": "bash", "reason": "write"}}), flush=True)
|
||||
elif msg.get("id") == "ask":
|
||||
print(json.dumps({"jsonrpc": "2.0", "method": "decision", "params": msg["result"]}), flush=True)
|
||||
elif msg.get("method") == "shutdown":
|
||||
print(json.dumps({"jsonrpc": "2.0", "id": msg["id"], "result": {}}), flush=True)
|
||||
break
|
||||
''')
|
||||
with HarnessClient(_launch_args=(sys.executable, str(peer))) as client:
|
||||
client.initialize(cwd=str(tmp_path), provider="mock", model="mock", approval_requests=enabled)
|
||||
payload = client.next_notification().payload
|
||||
assert payload.get("approvalRequests", False) is enabled
|
||||
if not enabled:
|
||||
assert "approvalRequests" not in payload
|
||||
return
|
||||
request = client.next_request()
|
||||
assert request.method == "approval/request"
|
||||
question = ApprovalRequestParams.model_validate(request.payload)
|
||||
assert question.toolName == "bash"
|
||||
assert question.callId is None
|
||||
client.respond(request.id, ApprovalRequestResult(outcome="rejected").model_dump())
|
||||
assert client.next_notification().payload == {"outcome": "rejected"}
|
||||
|
||||
|
||||
def test_approval_result_rejects_unrecognized_grants() -> None:
|
||||
with pytest.raises(ValidationError):
|
||||
ApprovalRequestResult(outcome="allow-always")
|
||||
|
||||
|
||||
def test_approval_opt_in_preserves_existing_config_positional_arguments() -> None:
|
||||
config = DeepSeekHarnessConfig("mock", "model", None, None, "/workspace")
|
||||
assert config.cwd == "/workspace"
|
||||
assert config.approval_requests is False
|
||||
@@ -0,0 +1,52 @@
|
||||
"""Python decisions control a guarded file operation through the built sdk profile."""
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import shutil
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from pydantic import BaseModel
|
||||
|
||||
from deepseek_harness import ApprovalRequestParams, HarnessClient, HarnessConfig
|
||||
|
||||
|
||||
class EmptyResponse(BaseModel):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize("outcome", ["allowed-once", "rejected"])
|
||||
def test_python_approval_controls_runtime_operation(tmp_path: Path, outcome: str) -> None:
|
||||
repo = Path(__file__).resolve().parents[3]
|
||||
node = shutil.which("node")
|
||||
binary = repo / "apps/cli/lib/bin.js"
|
||||
if node is None or not binary.exists():
|
||||
pytest.skip("requires Node and built dsh CLI")
|
||||
fixture = repo / "packages/sdk/server/tests/fixtures/approval.mjs"
|
||||
marker = tmp_path / "approved.txt"
|
||||
patch = tmp_path / "approval.patch.yml"
|
||||
patch.write_text("- insert:\n - id: approval-fixture\n name: " + json.dumps(str(fixture))
|
||||
+ "\n config:\n stopAfterApproval: true\n path: " + json.dumps(str(marker)) + "\n")
|
||||
# The client closes inside the executor lifetime, unblocking a reader even
|
||||
# when a regression prevents the expected request from arriving.
|
||||
with ThreadPoolExecutor(max_workers=1) as worker:
|
||||
with HarnessClient(
|
||||
HarnessConfig(cwd=str(repo), request_timeout_seconds=20, shutdown_timeout_seconds=20,
|
||||
env={"DSH_HOME": str(tmp_path / "home"), "DSH_PERMISSION_MODE": "workspace-write",
|
||||
"DSH_TELEMETRY_DISABLED": "1", "DEEPSEEK_API_KEY": "keyless-no-model-call"}),
|
||||
_launch_args=(node, str(binary), "--profile", "sdk", "--patch", str(patch)),
|
||||
) as client:
|
||||
client.initialize(cwd=str(tmp_path), provider="deepseek-official", model="deepseek-v4-flash",
|
||||
approval_requests=True)
|
||||
client.session_prompt("main", [{"type": "text", "text": "Request the marker write."}])
|
||||
request = worker.submit(client.next_request).result(timeout=20)
|
||||
assert request.method == "approval/request"
|
||||
question = ApprovalRequestParams.model_validate(request.payload)
|
||||
assert question.sessionId == "main"
|
||||
assert question.toolName == "fixture-write"
|
||||
client.respond(request.id, {"outcome": outcome})
|
||||
client.request("session/wait", {"sessionId": "main"}, response_model=EmptyResponse)
|
||||
assert marker.exists() is (outcome == "allowed-once")
|
||||
if marker.exists():
|
||||
assert marker.read_text() == "approved\n"
|
||||
@@ -165,6 +165,7 @@ for line in sys.stdin:
|
||||
)
|
||||
|
||||
with DeepSeekHarness(
|
||||
approval_requests=True,
|
||||
model="deepseek-v4-flash",
|
||||
reasoning_effort="max",
|
||||
max_tokens=4096,
|
||||
@@ -211,6 +212,7 @@ for line in sys.stdin:
|
||||
assert dumped_env["DSH_SESSION_ROOT"] is None
|
||||
assert dumped_env["DSH_CORDIS_CONFIG"] is None
|
||||
assert json.loads(init_dump.read_text()) == {
|
||||
"approvalRequests": True,
|
||||
"cwd": str(tmp_path),
|
||||
"provider": "deepseek-official",
|
||||
"model": "deepseek-v4-flash",
|
||||
|
||||
Reference in new issue
Block a user