mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-11 04:00:38 +00:00
Merge origin/master into subprocess containment
This commit is contained in:
@@ -56,6 +56,17 @@ MINIMAL_SHELL_COMMAND = (
|
||||
)
|
||||
)
|
||||
MINIMAL_SHELL_SECOND_CWD = str(Path(tempfile.gettempdir()).resolve()) if IS_WINDOWS else "/tmp"
|
||||
SPAWN_NODE_PROMPT = "Run node --version through the packaged shell tool."
|
||||
SPAWN_NODE_TEXT = "spawn node smoke ok"
|
||||
SPAWN_NODE_CALL_ID = "spawn-node-shell"
|
||||
# The POSIX command string starts with `node ` inside the shell tool's `bash -c`
|
||||
# argv, the exact form @yao-pkg/pkg's unpatched SEA bootstrap rewrites to the
|
||||
# executable itself while stamping PKG_EXECPATH into the child environment.
|
||||
SPAWN_NODE_COMMAND = (
|
||||
'node --version; if ($env:PKG_EXECPATH) { "PKG_EXECPATH=$env:PKG_EXECPATH" } else { "PKG_EXECPATH=ABSENT" }'
|
||||
if IS_WINDOWS
|
||||
else 'node --version; echo "PKG_EXECPATH=${PKG_EXECPATH:-ABSENT}"'
|
||||
)
|
||||
LEGACY_CUSTOM_DISABLED_ROWS = (
|
||||
"agent-instructions",
|
||||
"goal",
|
||||
@@ -310,6 +321,9 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
|
||||
fs_search = fs_search_tool_followup(call_id, tool_name, tool_text)
|
||||
if fs_search is not None:
|
||||
return fs_search
|
||||
spawn_node = spawn_node_tool_followup(call_id, tool_name, tool_text)
|
||||
if spawn_node is not None:
|
||||
return spawn_node
|
||||
minimal = minimal_tool_followup(body, call_id, tool_name, tool_text)
|
||||
if minimal is not None:
|
||||
return minimal
|
||||
@@ -352,6 +366,7 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
|
||||
CODE_PROMPT,
|
||||
WORKFLOW_PROMPT,
|
||||
FS_SEARCH_PROMPT,
|
||||
SPAWN_NODE_PROMPT,
|
||||
MCP_PROMPT,
|
||||
RESTART_FIRST_PROMPT,
|
||||
RESTART_SECOND_PROMPT,
|
||||
@@ -415,6 +430,13 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
|
||||
"grep",
|
||||
{"pattern": FS_SEARCH_MARKER, "path": "."},
|
||||
)
|
||||
if prompt == SPAWN_NODE_PROMPT:
|
||||
assert_advertised_tool(body, MINIMAL_SHELL_TOOL)
|
||||
return tool_call_chunks(
|
||||
SPAWN_NODE_CALL_ID,
|
||||
MINIMAL_SHELL_TOOL,
|
||||
{"command": SPAWN_NODE_COMMAND, "description": "Report the reachable Node version"},
|
||||
)
|
||||
if prompt == MCP_PROMPT:
|
||||
assert_advertised_tool(body, "mcp__fixture__add")
|
||||
return tool_call_chunks(
|
||||
@@ -470,6 +492,36 @@ def fs_search_tool_followup(
|
||||
raise AssertionError(f"unexpected filesystem-search follow-up: {call_id} {tool_name}: {tool_text}")
|
||||
|
||||
|
||||
def host_node_version() -> str:
|
||||
"""The machine's own `node --version` line, the required shell resolution target."""
|
||||
node = shutil.which("node")
|
||||
if node is None:
|
||||
raise AssertionError("the spawn-node scenario requires Node on PATH for comparison")
|
||||
return subprocess.run(
|
||||
[node, "--version"], capture_output=True, text=True, check=True,
|
||||
).stdout.strip()
|
||||
|
||||
|
||||
def spawn_node_tool_followup(
|
||||
call_id: str,
|
||||
tool_name: str,
|
||||
tool_text: str,
|
||||
) -> list[dict[str, object]] | None:
|
||||
"""Verify the packaged shell reached the machine's Node with a clean environment."""
|
||||
if call_id != SPAWN_NODE_CALL_ID:
|
||||
return None
|
||||
if tool_name != MINIMAL_SHELL_TOOL:
|
||||
raise AssertionError(f"spawn-node follow-up used an unexpected tool: {tool_name}")
|
||||
expected = host_node_version()
|
||||
if expected not in tool_text:
|
||||
raise AssertionError(
|
||||
f"packaged shell did not reach the machine's node {expected}: {tool_text}"
|
||||
)
|
||||
if "PKG_EXECPATH=ABSENT" not in tool_text:
|
||||
raise AssertionError(f"PKG_EXECPATH reached the shell child environment: {tool_text}")
|
||||
return text_chunks(SPAWN_NODE_TEXT)
|
||||
|
||||
|
||||
def minimal_tool_followup(
|
||||
body: dict[str, object],
|
||||
call_id: str,
|
||||
@@ -712,7 +764,7 @@ def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--scenario",
|
||||
choices=("all", "sdk-default", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-mcp", "sdk-snapshot", "sdk-restart", "sdk-profile-plugin", "sdk-live", "runner", "direct"),
|
||||
choices=("all", "sdk-default", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-spawn-node", "sdk-mcp", "sdk-snapshot", "sdk-restart", "sdk-profile-plugin", "sdk-live", "runner", "direct"),
|
||||
default="all",
|
||||
)
|
||||
parser.add_argument("--exe", type=Path)
|
||||
@@ -731,8 +783,8 @@ def main() -> None:
|
||||
parser.error("--scenario sdk-profile-plugin requires --installed-wheel")
|
||||
if args.installed_wheel:
|
||||
args.exe = assert_installed_wheel_environment()
|
||||
if args.scenario in {"all", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-snapshot", "sdk-restart", "runner", "direct"} and args.exe is None:
|
||||
parser.error("--exe is required for custom, minimal, fs-search, snapshot, restart, runner, and direct scenarios")
|
||||
if args.scenario in {"all", "sdk-custom", "sdk-minimal", "sdk-fs-search", "sdk-spawn-node", "sdk-snapshot", "sdk-restart", "runner", "direct"} and args.exe is None:
|
||||
parser.error("--exe is required for custom, minimal, fs-search, spawn-node, snapshot, restart, runner, and direct scenarios")
|
||||
if args.update_snapshots and args.scenario not in {"all", "sdk-minimal", "sdk-snapshot", "sdk-restart"}:
|
||||
parser.error("--update-snapshots requires --scenario sdk-minimal, sdk-snapshot, sdk-restart, or all")
|
||||
if args.exe is not None and not args.exe.is_file():
|
||||
@@ -762,6 +814,9 @@ def main() -> None:
|
||||
if args.scenario in {"all", "sdk-fs-search"}:
|
||||
assert args.exe is not None
|
||||
smoke_sdk_fs_search(model.url, args.exe.resolve())
|
||||
if args.scenario in {"all", "sdk-spawn-node"}:
|
||||
assert args.exe is not None
|
||||
smoke_sdk_spawn_node(model.url, args.exe.resolve())
|
||||
if args.scenario in {"all", "sdk-mcp"}:
|
||||
smoke_sdk_mcp(model.url, None if args.exe is None else args.exe.resolve())
|
||||
if args.scenario in {"all", "sdk-snapshot"}:
|
||||
@@ -1057,6 +1112,36 @@ def smoke_sdk_fs_search(base_url: str, executable: Path) -> None:
|
||||
assert_session_log(sessions, root, FS_SEARCH_TEXT, FS_SEARCH_MARKER, "needle.txt")
|
||||
|
||||
|
||||
def smoke_sdk_spawn_node(base_url: str, executable: Path) -> None:
|
||||
"""A shell command starting with `node` must reach the machine's Node, not the executable."""
|
||||
from deepseek_harness import DeepSeekHarness
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="dsh-sdk-spawn-node-") as temporary:
|
||||
root = Path(temporary).resolve()
|
||||
dsh_home = root / "home"
|
||||
sessions = dsh_home / "sessions"
|
||||
patch = write_profile_patch(root, "spawn-node.patch.yml", sessions, [])
|
||||
with DeepSeekHarness(
|
||||
provider="deepseek-official",
|
||||
model="smoke-model",
|
||||
cwd=str(root),
|
||||
dsh_bin=str(executable),
|
||||
dsh_home=str(dsh_home),
|
||||
patches=(str(patch),),
|
||||
env={
|
||||
"DSH_PERMISSION_MODE": "danger-full-access",
|
||||
"DSH_TELEMETRY_DISABLED": "1",
|
||||
},
|
||||
api_key="sk-keyless-smoke",
|
||||
base_url=base_url,
|
||||
request_timeout_seconds=60,
|
||||
) as harness:
|
||||
result = harness.run(SPAWN_NODE_PROMPT, session_id="spawn-node-smoke")
|
||||
|
||||
assert result.final_response == SPAWN_NODE_TEXT, result.final_response
|
||||
assert_session_log(sessions, root, SPAWN_NODE_TEXT, "PKG_EXECPATH=ABSENT")
|
||||
|
||||
|
||||
def smoke_sdk_mcp(base_url: str, executable: Path | None) -> None:
|
||||
"""Discover and call an external stdio MCP tool through the packaged client."""
|
||||
from deepseek_harness import DeepSeekHarness
|
||||
|
||||
Reference in New Issue
Block a user