Repository navigation
feat(agent): run OpenClaw inside task sandboxes #3637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
yaoyu-33
merged 50 commits into
NVIDIA-NeMo:main
from
yaoyu-33:codex/openclaw-native-sessions
Oct 10, 2026
Merged
Changes from all commits
Commits
Show all changes
50 commits
Select commit
Hold shift + click to select a range
d211645
feat(agent): run OpenClaw inside native task sandboxes
yaoyu-33 f4bef5b
fix(openclaw): isolate cached runtime version checks
yaoyu-33 e3766aa
fix(openclaw): account for rewritten transcript usage
yaoyu-33 6c81819
fix(openclaw): preserve unknown optional usage details
yaoyu-33 44bdd97
fix(openclaw): retain valid native envelope usage subtotals
yaoyu-33 14b5fbb
fix(openclaw): retain fallback text with malformed usage
yaoyu-33 bcab742
fix(openclaw): retain unknown cache detail provenance
yaoyu-33 f4f64fc
fix(openclaw): route native evaluation through environment sessions
yaoyu-33 41675d8
fix(openclaw): reject expired and malformed session cookies
yaoyu-33 6637a9b
docs(openclaw): separate server startup from native collection
yaoyu-33 42d203d
docs(openclaw): remove trailing whitespace
yaoyu-33 eb95e8d
fix(openclaw): run native sandboxes without PTY sessions
yaoyu-33 2ec87a2
fix(openclaw): align native sessions with the shared contract
yaoyu-33 47d0439
docs(openclaw): preserve pairing opt-in across head discovery
yaoyu-33 75cbc65
fix(openclaw): allow longer model requests before idle timeout
yaoyu-33 04121ea
fix(openclaw): support agent-owned native sandboxes
yaoyu-33 5b39930
refactor(openclaw): share sandbox cleanup and runtime contracts
yaoyu-33 2d92a63
test(openclaw): wait for cancelled descendants to be reaped
yaoyu-33 8952633
refactor(hermes): decouple default harness configuration
yaoyu-33 6d443b6
refactor(hermes): share cleanup and runtime validation
yaoyu-33 7b1b593
fix(hermes): report provider token usage for root model calls
yaoyu-33 7dd777f
fix(agent): derive usage from shared model capture
yaoyu-33 55d742f
refactor(hermes): move token usage to its own PR
yaoyu-33 1f95e8e
refactor(hermes): share sandbox supervision and session transport
yaoyu-33 ba8a2c6
refactor(sandbox): share harness execution and close lifecycle
yaoyu-33 c4aabf0
fix(sandbox): validate bootstrap and tolerate diagnostic gaps
yaoyu-33 1a7dfb1
refactor(agent): move shared execution helpers into agent_utils
yaoyu-33 29e979f
feat(sandbox): add binary file transfer helpers
yaoyu-33 e1f36cd
refactor(sandbox): simplify utility imports and ordering
yaoyu-33 5671efa
refactor(harness): centralize supervised session ownership
yaoyu-33 2093960
refactor(agent): restore agent_utils package name
yaoyu-33 a309dfb
fix(hermes): default owned sandbox lifetime
yaoyu-33 127c21c
Merge remote-tracking branch 'origin/main' into codex/openclaw-agent-…
yaoyu-33 a67ebd7
refactor(openclaw): adopt shared sandbox session lifecycle
yaoyu-33 a88a216
test(openclaw): prepare seeded config directory in exec fixture
yaoyu-33 d5e6ad2
fix(config): preserve native Hermes templates during migration
yaoyu-33 0db6de0
fix(config): preserve native openclaw templates during migration
yaoyu-33 2a1a5cb
chore(openclaw): merge complete shared sandbox lifecycle dependency
yaoyu-33 d07d993
fix(openclaw): reconcile native sessions with current main
yaoyu-33 e9fff6a
fix(openclaw): align shared model errors and native routing
yaoyu-33 5f3f95d
Merge commit '0b27f0efa15f0e3a4a64777e85eac1053b8b0929' into codex/op…
yaoyu-33 c0136ae
fix(openclaw): align native bootstrap and model error policy
yaoyu-33 f757424
refactor(openclaw): align session and local config names
yaoyu-33 fa5ae88
test(openclaw): enforce session-based local CLI routing
yaoyu-33 4e5107b
Merge main into OpenClaw native-session branch
yaoyu-33 0ecc9b0
refactor(openclaw): remove redundant fixed-model example
yaoyu-33 e01e9a0
fix(openclaw): preserve setup errors with absent output
yaoyu-33 9073807
Merge main into OpenClaw sandbox sessions
yaoyu-33 01218cd
fix(openclaw): align sandbox terminology and request contract
yaoyu-33 0ba7a55
fix(openclaw): clarify metadata controls and retry failed setup
yaoyu-33 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
38 changes: 13 additions & 25 deletions
38
responses_api_agents/openclaw_agent/configs/openclaw_agent.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,30 +1,18 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| # Agent sessions run in a sandbox; unseeded requests run the local CLI. | ||
| openclaw_agent: | ||
| responses_api_agents: | ||
| openclaw_agent: | ||
| entrypoint: app.py | ||
| resources_server: | ||
| type: resources_servers | ||
| name: ??? | ||
| concurrency: 32 | ||
| command: openclaw | ||
| model: nvinf/nvidia/meta/llama-3.3-70b-instruct | ||
| workspace_root: outputs/openclaw_agent/workspaces | ||
| openclaw_agent_id: main | ||
| thinking: "off" | ||
| system_prompt: null | ||
| setup_timeout: 900 | ||
| timeout: 900 | ||
| extra_args: [] | ||
| env: {} | ||
| openclaw_config: | ||
| models: | ||
| providers: | ||
| nvinf: | ||
| api: openai-completions | ||
| baseUrl: https://integrate.api.nvidia.com/v1 | ||
| apiKey: ${policy_api_key} | ||
| models: | ||
| - id: nvidia/meta/llama-3.3-70b-instruct | ||
| name: nvidia/meta/llama-3.3-70b-instruct | ||
| api: openai-completions | ||
| num_workers: 1 | ||
| resources_server: null | ||
| model_server: {type: responses_api_models, name: policy_model} | ||
| model: ${policy_model_name} | ||
| openclaw_version: 2026.6.11 | ||
| timeout: 900 | ||
| model_timeout_seconds: 600 | ||
| sandbox_install_timeout_seconds: 600 | ||
| session_close_timeout_seconds: 60 | ||
| session_close_retry_window_seconds: 300 | ||
126 changes: 126 additions & 0 deletions
126
responses_api_agents/openclaw_agent/install_openclaw_runtime.sh
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| set -euo pipefail | ||
| trap 'status=$?; echo "OpenClaw installer failed (exit $status) at line $LINENO: $BASH_COMMAND" >&2; exit "$status"' ERR | ||
|
|
||
| runtime=$1 | ||
| openclaw_version=$2 | ||
| node_version=22.19.0 | ||
| if [ "$(uname -s)" != Linux ]; then | ||
| echo 'OpenClaw sandbox execution requires a Linux sandbox.' >&2 | ||
| exit 1 | ||
| fi | ||
| if ! command -v python3 >/dev/null 2>&1; then | ||
| echo 'OpenClaw sandbox execution requires Python >=3.8 in the task image for descendant supervision.' >&2 | ||
| exit 1 | ||
| fi | ||
| python3 -c 'import sys; assert sys.version_info >= (3, 8), "OpenClaw sandbox execution requires Python >=3.8"' | ||
| case "$(uname -m)" in | ||
| x86_64) arch=x64 ;; | ||
| aarch64) arch=arm64 ;; | ||
| *) echo 'OpenClaw sandbox execution supports Linux x86_64/aarch64 only.' >&2; exit 1 ;; | ||
| esac | ||
| platform="linux-${arch}" | ||
| node_dist="https://nodejs.org/dist/v${node_version}" | ||
| if getconf GNU_LIBC_VERSION >/dev/null 2>&1; then | ||
| : | ||
| elif [[ "$(ldd --version 2>&1 || true)" == *musl* ]]; then | ||
| if [ "$arch" != x64 ]; then | ||
| echo "OpenClaw sandbox execution's pinned Node ${node_version} musl build supports x86_64 only" >&2 | ||
| exit 1 | ||
| fi | ||
| platform=linux-x64-musl | ||
| node_dist="https://unofficial-builds.nodejs.org/download/release/v${node_version}" | ||
| else | ||
| echo 'OpenClaw sandbox execution requires glibc or musl; could not identify the sandbox libc' >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| install_packages() { | ||
| if [ "$(id -u)" -ne 0 ]; then | ||
| echo "OpenClaw sandbox execution requires $*: preinstall these packages (automatic installation requires root)." >&2 | ||
| exit 1 | ||
| fi | ||
| if command -v apk >/dev/null 2>&1; then | ||
| apk add --no-cache "$@" | ||
| elif command -v apt-get >/dev/null 2>&1; then | ||
| apt-get update | ||
| DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends "$@" | ||
| else | ||
| echo "OpenClaw sandbox execution requires $*: preinstall these packages (automatic installation requires apt-get or apk)." >&2 | ||
| exit 1 | ||
| fi | ||
| } | ||
|
|
||
| # Never change the task repository or its dependency environment. | ||
| python3 - "$runtime" "$PWD" <<'PY' | ||
| import pathlib, sys | ||
| runtime, workdir = (pathlib.Path(p).resolve() for p in sys.argv[1:]) | ||
| if workdir == runtime or workdir in runtime.parents or runtime in workdir.parents: | ||
| raise SystemExit('OpenClaw runtime must be outside the task repository') | ||
| PY | ||
| # One sandbox can receive overlapping session setup attempts. Keep the ready | ||
| # check and all cache writes under a version-scoped advisory lock. | ||
| if ! command -v flock >/dev/null 2>&1; then | ||
| install_packages util-linux | ||
| fi | ||
| mkdir -p "$runtime" | ||
| exec 9>"$runtime/.install.lock" | ||
| flock -x 9 | ||
| mkdir -p "$runtime/home" "$runtime/cache" | ||
| export HOME="$runtime/home" | ||
| export npm_config_cache="$runtime/cache/npm" | ||
| export XDG_CACHE_HOME="$runtime/cache" | ||
| verify_version() { | ||
| "$runtime/node/bin/node" -e \ | ||
| 'const p=require(process.argv[1]); if(p.version!==process.argv[2])throw Error("OpenClaw version mismatch")' \ | ||
| "$runtime/openclaw/node_modules/openclaw/package.json" "$openclaw_version" | ||
| } | ||
| if [ -f "$runtime/ready" ]; then | ||
| verify_version | ||
| "$runtime/node/bin/node" "$runtime/openclaw/node_modules/openclaw/openclaw.mjs" --version | ||
| exit 0 | ||
| fi | ||
|
|
||
| missing=() | ||
| for prerequisite in curl tar gzip sha256sum awk; do | ||
| command -v "$prerequisite" >/dev/null 2>&1 || missing+=("$prerequisite") | ||
| done | ||
| if [ ! -s /etc/ssl/certs/ca-certificates.crt ] && [ ! -s /etc/pki/tls/certs/ca-bundle.crt ]; then | ||
| missing+=(ca-certificates) | ||
| fi | ||
| if [ "${#missing[@]}" -gt 0 ]; then | ||
| echo "OpenClaw sandbox execution prerequisites missing: ${missing[*]}. Preinstall curl, ca-certificates, tar, gzip, coreutils, gawk." >&2 | ||
| install_packages curl ca-certificates tar gzip coreutils gawk | ||
| fi | ||
| if [ "$platform" = linux-x64-musl ] && ! python3 -c 'import ctypes; ctypes.CDLL("libstdc++.so.6")' 2>/dev/null; then | ||
| install_packages libstdc++ | ||
| fi | ||
| cd "$runtime" | ||
| archive="node-v${node_version}-${platform}.tar.gz" | ||
| curl -fsSL --retry 3 "${node_dist}/${archive}" -o "$archive" | ||
| curl -fsSL --retry 3 "${node_dist}/SHASUMS256.txt" -o SHASUMS256.txt | ||
| awk -v archive="$archive" '$2 == archive' SHASUMS256.txt | sha256sum -c - | ||
| mkdir -p node | ||
| tar -xzf "$archive" --strip-components=1 -C node | ||
| if [ "$platform" = linux-x64-musl ] && ! "$runtime/node/bin/node" --version; then | ||
| # Confine the newer C++ runtime to our Node binary, preserving task libraries. | ||
| command -v patchelf >/dev/null 2>&1 || install_packages patchelf | ||
| curl -fsSL --retry 3 \ | ||
| 'https://dl-cdn.alpinelinux.org/alpine/v3.19/main/x86_64/libstdc++-13.2.1_git20231014-r0.apk' \ | ||
| -o libstdc++.apk | ||
| echo '3cf66a7164240ef590106496d3c75f486bac46cba9cf2198c0c3b318c53ad027 libstdc++.apk' | sha256sum -c - | ||
| mkdir -p libstdcpp | ||
| tar -xzf libstdc++.apk -C libstdcpp usr/lib | ||
| patchelf --set-rpath '$ORIGIN/../../libstdcpp/usr/lib' "$runtime/node/bin/node" | ||
| fi | ||
| "$runtime/node/bin/node" --version | ||
| PATH="$runtime/node/bin:$PATH" "$runtime/node/bin/node" \ | ||
| "$runtime/node/lib/node_modules/npm/bin/npm-cli.js" install \ | ||
| --prefix "$runtime/openclaw" --no-audit --no-fund "openclaw@${openclaw_version}" | ||
| "$runtime/node/bin/node" -e \ | ||
| 'const p=require(process.argv[1]); if(p.version!==process.argv[2])throw Error("OpenClaw version mismatch")' \ | ||
| "$runtime/openclaw/node_modules/openclaw/package.json" "$openclaw_version" | ||
| "$runtime/node/bin/node" "$runtime/openclaw/node_modules/openclaw/openclaw.mjs" --version | ||
| printf '%s\n' "$openclaw_version" > "$runtime/ready" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,132 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| """OpenClaw artifacts and request state over the shared sandbox lifecycle.""" | ||
|
|
||
| import asyncio | ||
| import json | ||
| import logging | ||
| from dataclasses import dataclass | ||
|
|
||
| from pydantic import BaseModel, ConfigDict, JsonValue, ValidationError | ||
|
|
||
| from nemo_gym.agent_utils.sandbox_session import SandboxCommand, SandboxSession | ||
| from nemo_gym.base_responses_api_agent import AgentSessionState | ||
| from nemo_gym.openai_utils import NeMoGymResponse, NeMoGymResponseCreateParamsNonStreaming | ||
| from nemo_gym.rollout_observability import AgentObservationBundle | ||
| from nemo_gym.sandbox.utils import read_text, upload_text | ||
|
|
||
|
|
||
| LOG = logging.getLogger(__name__) | ||
|
|
||
|
|
||
| # Executed by sandbox Python before uploading any adapter-owned files. Resolve | ||
| # symlinks and '..' on the sandbox filesystem, not on the agent-server host. | ||
| _SANDBOX_PATH_CHECK = """ | ||
| from pathlib import Path | ||
| import sys | ||
| workdir, session_root, runtime_root = (Path(value).resolve() for value in sys.argv[1:]) | ||
| if not workdir.is_dir(): | ||
| raise SystemExit("OpenClaw task workdir is missing or is not a directory: " + str(workdir)) | ||
| for owned in (session_root, runtime_root): | ||
| if workdir == owned or workdir in owned.parents or owned in workdir.parents: | ||
| raise SystemExit("OpenClaw task workdir overlaps adapter-owned storage: " + str(owned)) | ||
| """ | ||
|
|
||
|
|
||
| class HarnessProcessInfo(BaseModel): | ||
|
yaoyu-33 marked this conversation as resolved.
Resolved
|
||
| """Optional OpenClaw shim identity, independent of supervisor cleanup.""" | ||
|
|
||
| model_config = ConfigDict(extra="forbid", strict=True) | ||
| hostname: str | ||
| pid: int | ||
| python: str | None = None | ||
|
|
||
|
|
||
| def parse_runtime_info(payload: object) -> HarnessProcessInfo | None: | ||
| """Read OpenClaw diagnostics without failing an otherwise valid episode.""" | ||
| try: | ||
| return HarnessProcessInfo.model_validate(payload) | ||
| except ValidationError: | ||
| LOG.warning("OpenClaw runtime metadata is missing or malformed") | ||
| return None | ||
|
|
||
|
|
||
| @dataclass | ||
| class OpenClawSandboxSession(AgentSessionState): | ||
| """OpenClaw request/output state; SandboxSession owns execution and teardown.""" | ||
|
|
||
| session: SandboxSession[dict[str, str]] | ||
| runtime: str | ||
| task: asyncio.Task[NeMoGymResponse] | None = None | ||
| runtime_info: HarnessProcessInfo | None = None | ||
| observations: AgentObservationBundle | None = None | ||
| activation_request: NeMoGymResponseCreateParamsNonStreaming | None = None | ||
|
|
||
| async def upload_json(self, name: str, payload: JsonValue) -> None: | ||
| """Stage adapter input using the shared text-transfer utility.""" | ||
| await upload_text(self.session.sandbox, path=f"{self.session.session_dir}/{name}", text=json.dumps(payload)) | ||
|
|
||
| async def read_text(self, name: str) -> str: | ||
| """Read adapter output using file transfer.""" | ||
| return await read_text(self.session.sandbox, path=f"{self.session.session_dir}/{name}") | ||
|
|
||
| async def close(self, timeout: float) -> None: | ||
| """Capture and release before cancelling the HTTP activation.""" | ||
| await self.session.close(timeout=timeout) | ||
| if self.task is not None and not self.task.done() and not self.task.cancelling(): | ||
| self.task.cancel() | ||
| if self.task is not None: | ||
| try: | ||
| await asyncio.wait_for(asyncio.shield(self.task), timeout=timeout) | ||
| except asyncio.CancelledError: | ||
| if not self.task.cancelled(): | ||
| raise | ||
| except Exception: | ||
| if not self.task.done(): | ||
| raise | ||
| # The agent base replays the activation error independently of close. | ||
|
|
||
| async def execute(self, payload: dict[str, JsonValue], *, timeout: float, close_timeout: float) -> dict[str, str]: | ||
| """Run through the common lifecycle; the adapter validates terminal events.""" | ||
| artifacts = await self.session.execute( | ||
| stage_activation=lambda: self.stage_activation(payload), | ||
| collect=self.collect_artifacts, | ||
| timeout=timeout, | ||
| close_timeout=close_timeout, | ||
| ) | ||
| if self.session.closing: | ||
| raise asyncio.CancelledError | ||
| return artifacts | ||
|
|
||
| async def stage_activation(self, payload: dict[str, JsonValue]) -> SandboxCommand: | ||
| """Stage the invocation and return the OpenClaw worker command.""" | ||
| await self.upload_json("home/.openclaw/openclaw.json", payload["config"]) | ||
| await self.upload_json("input.json", payload) | ||
| return SandboxCommand( | ||
| python="python3", | ||
| argv=[ | ||
| "python3", | ||
| "-I", | ||
| f"{self.session.session_dir}/sandbox_runner.py", | ||
| f"{self.session.session_dir}/input.json", | ||
| ], | ||
| ) | ||
|
|
||
| async def collect_artifacts(self) -> dict[str, str]: | ||
| """Retain transcript and diagnostics before releasing the task sandbox.""" | ||
| artifacts = {} | ||
| session_id = self.session.session_dir.rsplit("/", 1)[-1] | ||
| for name in ("stdout.log", "stderr.log", f"home/.openclaw/agents/main/sessions/{session_id}.jsonl"): | ||
| try: | ||
| artifacts[name] = await self.read_text(name) | ||
| except Exception: | ||
| LOG.warning("OpenClaw artifact unavailable: %s", name, exc_info=True) | ||
| try: | ||
| runtime = json.loads(await self.read_text("runtime.json")) | ||
| except Exception: | ||
| runtime = None | ||
| self.runtime_info = parse_runtime_info(runtime) | ||
| if "stdout.log" not in artifacts and not any(name.endswith(".jsonl") for name in artifacts): | ||
| logs = await self.session.read_output_log() | ||
| raise RuntimeError(f"OpenClaw sandbox runner returned no valid result: {logs}") | ||
| return artifacts | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
| """Capture OpenClaw output; the shared process supervisor owns deadlines and cleanup.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import json | ||
| import os | ||
| import signal | ||
| import subprocess | ||
| import sys | ||
| from contextlib import ExitStack | ||
| from pathlib import Path | ||
| from typing import TypedDict | ||
|
|
||
|
|
||
| class RunnerInput(TypedDict): | ||
| """Harness input, independent of supervisor cleanup and runtime metadata.""" | ||
|
|
||
| directory: str | ||
| prompt: str | ||
| command: list[str] | ||
| cwd: str | ||
| env: dict[str, str] | ||
|
|
||
|
|
||
| def run(params: RunnerInput) -> int: | ||
| """Run the harness with isolated files and let the supervisor reap descendants.""" | ||
| directory = Path(params["directory"]) | ||
| (directory / "runtime.json").write_text(json.dumps({"hostname": os.uname().nodename, "pid": os.getpid()})) | ||
| (directory / "prompt.txt").write_text(params["prompt"]) | ||
| stopping = False | ||
|
|
||
| def interrupt(*_: object) -> None: | ||
| nonlocal stopping | ||
| # Defer TERM until Popen returns so a signal cannot lose the child handle. | ||
| stopping = True | ||
|
|
||
| signal.signal(signal.SIGTERM, interrupt) | ||
| with ExitStack() as stack: | ||
| stdout = stack.enter_context((directory / "stdout.log").open("wb")) | ||
| stderr = stack.enter_context((directory / "stderr.log").open("wb")) | ||
| stdin = subprocess.DEVNULL | ||
| process = subprocess.Popen( | ||
| params["command"], | ||
| cwd=params["cwd"], | ||
| env={**os.environ, **params["env"]}, | ||
| stdin=stdin, | ||
| stdout=stdout, | ||
| stderr=stderr, | ||
| ) | ||
| while True: | ||
| if stopping: | ||
| process.terminate() | ||
| stopping = False | ||
| try: | ||
| return process.wait(timeout=0.05) | ||
| except subprocess.TimeoutExpired: | ||
| pass | ||
|
|
||
|
|
||
| def main() -> None: | ||
| params = json.loads(Path(sys.argv[1]).read_text()) | ||
| raise SystemExit(run(params)) | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| main() |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.