Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
df4f0e8
feat(onboard): use OpenShell docker GPU sandboxes
ericksoa May 4, 2026
74fe6eb
fix(onboard): clean up docker gpu check regressions
ericksoa May 4, 2026
1e94f2e
fix(test): isolate docker-driver onboarding guards
ericksoa May 4, 2026
a639877
fix(base): move sandbox images to trixie for openshell
ericksoa May 4, 2026
dccd4c5
fix(base): include chattr runtime dependency
ericksoa May 4, 2026
6b0c902
fix(base): satisfy docker lint for runtime deps
ericksoa May 4, 2026
6bc67c8
test(wsl): remove controlling tty in installer atomicity test
ericksoa May 4, 2026
f803fbc
fix(onboard): reuse docker-driver gateway runtime
ericksoa May 4, 2026
9fd1dae
fix(shields): gate docker-driver exec discovery
ericksoa May 4, 2026
ad613cf
fix(onboard): address docker gpu review feedback
ericksoa May 4, 2026
68a8315
fix(e2e): stabilize docker-driver lifecycle tests
ericksoa May 5, 2026
ff0fbbb
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
0186100
Merge branch 'main' into codex/openshell-docker-gpu-onboard
ericksoa May 5, 2026
eca7325
Merge remote-tracking branch 'origin/main' into repair/pr3001-clean-m…
ericksoa May 5, 2026
d99923c
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
edd1173
ci: force IPv4 for WSL apt setup
ericksoa May 5, 2026
f6056d5
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
a36c62d
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
6abace5
fix(cli): preserve onboard passthrough flags
ericksoa May 5, 2026
f683111
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
471453e
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 5, 2026
23afabf
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
a9350d1
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
b07dcc5
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
57857dc
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
6fe57b7
fix(onboard): preserve sandbox GPU auto mode on resume
ericksoa May 6, 2026
78dc20c
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
f4f38a8
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
fc3dfd4
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
c25df40
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 6, 2026
0ebfe4c
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 7, 2026
fd3133e
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 7, 2026
210e9e7
fix(onboard): narrow direct GPU proc writes
ericksoa May 7, 2026
dd76410
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 7, 2026
133ab48
fix(agent): bypass base resolver for forced rebuilds
ericksoa May 7, 2026
e9bf328
fix(onboard): support openshell gateway remove
ericksoa May 7, 2026
941f3c1
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 7, 2026
fe3f377
fix(onboard): persist reused gateway during onboard
ericksoa May 7, 2026
e6f8924
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
37bd091
fix(hermes): allow current Python runtime in Slack policy
ericksoa May 8, 2026
effe9a9
fix(e2e): align double-onboard alias with docker gateway
ericksoa May 8, 2026
6751206
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
f4c9540
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
c4b608a
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
85143a3
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
dbc099c
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
130d74d
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
cd43f8d
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
a43d8f5
fix(messaging): honor OpenShell scoped provider placeholders
ericksoa May 8, 2026
2363547
fix(hermes): tolerate runtime-scoped placeholders
ericksoa May 8, 2026
782b1b7
test(messaging): quiet loopback rewriter probe
ericksoa May 8, 2026
6cd7ddb
test(messaging): retry transient Discord upstream warmup
ericksoa May 8, 2026
c1a047a
test(messaging): accept scoped Slack placeholders
ericksoa May 8, 2026
bfe1033
test(messaging): retry Discord proxy warmup responses
ericksoa May 8, 2026
28c1091
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 8, 2026
0eba09a
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 9, 2026
2bb35c1
fix(onboard): target OpenShell 0.0.37 release
ericksoa May 9, 2026
277d481
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 9, 2026
524cfae
docs(cli): include sandbox GPU onboard flags
ericksoa May 9, 2026
a88a31e
fix(onboard): restart stale OpenShell docker gateway
ericksoa May 9, 2026
ec6434b
fix(ci): keep gateway upgrade e2e dev deps
ericksoa May 9, 2026
06d942f
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 9, 2026
de2137c
test(hermes): use available python for slack probe
ericksoa May 9, 2026
9bccc08
test(e2e): cover OpenShell upgrade cleanup drift
ericksoa May 9, 2026
269a378
fix(hermes): persist proxy CA env for Slack probes
ericksoa May 9, 2026
4d2c17c
test(hermes): classify Slack Python probe errors
ericksoa May 9, 2026
5fc43f9
test(hermes): treat Slack remote close as transient
ericksoa May 9, 2026
22f871d
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 10, 2026
416837e
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 10, 2026
5bb752a
Merge remote-tracking branch 'origin/main' into codex/openshell-docke…
ericksoa May 11, 2026
7ea3e79
fix(e2e): refresh mutable config hash before command exec
ericksoa May 11, 2026
1de0193
Merge branch 'main' into codex/openshell-docker-gpu-onboard
cv May 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 100 additions & 23 deletions scripts/install-openshell.sh
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,29 @@ MIN_VERSION="0.0.32"
MAX_VERSION="0.0.36"
# Pin fresh installs to this version instead of pulling "latest".
PIN_VERSION="$MAX_VERSION"
DEV_MIN_VERSION="0.0.37"

CHANNEL="${NEMOCLAW_OPENSHELL_CHANNEL:-auto}"
case "$CHANNEL" in
stable | dev | auto) ;;
*) fail "NEMOCLAW_OPENSHELL_CHANNEL must be one of: stable, dev, auto" ;;
esac

if [ "$CHANNEL" = "auto" ]; then
if [ "$OS" = "Linux" ]; then
RESOLVED_CHANNEL="dev"
else
RESOLVED_CHANNEL="stable"
fi
else
RESOLVED_CHANNEL="$CHANNEL"
fi

if [ "$RESOLVED_CHANNEL" = "dev" ]; then
RELEASE_TAG="dev"
else
RELEASE_TAG="v${PIN_VERSION}"
fi

version_gte() {
# Returns 0 (true) if $1 >= $2 — portable, no sort -V (BSD compat)
Expand All @@ -58,19 +81,28 @@ version_gte() {
}

if command -v openshell >/dev/null 2>&1; then
INSTALLED_VERSION="$(openshell --version 2>&1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
INSTALLED_VERSION_OUTPUT="$(openshell --version 2>&1 || true)"
INSTALLED_VERSION="$(printf '%s\n' "$INSTALLED_VERSION_OUTPUT" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true)"
[ -n "$INSTALLED_VERSION" ] || INSTALLED_VERSION="0.0.0"
if version_gte "$INSTALLED_VERSION" "$MIN_VERSION"; then
if ! version_gte "$MAX_VERSION" "$INSTALLED_VERSION"; then
fail "openshell $INSTALLED_VERSION is above the maximum ($MAX_VERSION) supported by this NemoClaw release. Upgrade NemoClaw first."
if [ "$RESOLVED_CHANNEL" = "dev" ]; then
if version_gte "$INSTALLED_VERSION" "$DEV_MIN_VERSION" && printf '%s\n' "$INSTALLED_VERSION_OUTPUT" | grep -qi 'dev'; then
info "openshell already installed: $INSTALLED_VERSION_OUTPUT (dev channel)"
exit 0
fi
warn "openshell $INSTALLED_VERSION is not the required dev-channel Docker-driver build — upgrading..."
else
if version_gte "$INSTALLED_VERSION" "$MIN_VERSION"; then
if ! version_gte "$MAX_VERSION" "$INSTALLED_VERSION"; then
fail "openshell $INSTALLED_VERSION is above the maximum ($MAX_VERSION) supported by this NemoClaw release. Upgrade NemoClaw first."
fi
info "openshell already installed: $INSTALLED_VERSION (>= $MIN_VERSION, <= $MAX_VERSION)"
exit 0
fi
info "openshell already installed: $INSTALLED_VERSION (>= $MIN_VERSION, <= $MAX_VERSION)"
exit 0
warn "openshell $INSTALLED_VERSION is below minimum $MIN_VERSION — upgrading..."
fi
warn "openshell $INSTALLED_VERSION is below minimum $MIN_VERSION — upgrading..."
fi

info "Installing openshell CLI..."
info "Installing OpenShell from release '$RELEASE_TAG'..."

case "$OS" in
Darwin)
Expand All @@ -87,51 +119,96 @@ case "$OS" in
;;
esac

declare -a ASSETS=("$ASSET")
declare -a CHECKSUM_FILES=("openshell-checksums-sha256.txt")
if [ "$OS" = "Linux" ]; then
case "$ARCH_LABEL" in
x86_64)
ASSETS+=("openshell-gateway-x86_64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-x86_64-unknown-linux-gnu.tar.gz")
;;
aarch64)
ASSETS+=("openshell-gateway-aarch64-unknown-linux-gnu.tar.gz")
ASSETS+=("openshell-sandbox-aarch64-unknown-linux-gnu.tar.gz")
;;
esac
CHECKSUM_FILES+=("openshell-gateway-checksums-sha256.txt")
CHECKSUM_FILES+=("openshell-sandbox-checksums-sha256.txt")
fi

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

CHECKSUM_FILE="openshell-checksums-sha256.txt"
download_with_curl() {
curl -fsSL "https://github.com/NVIDIA/OpenShell/releases/download/v${PIN_VERSION}/$ASSET" \
-o "$tmpdir/$ASSET"
curl -fsSL "https://github.com/NVIDIA/OpenShell/releases/download/v${PIN_VERSION}/$CHECKSUM_FILE" \
-o "$tmpdir/$CHECKSUM_FILE"
local name
for name in "${ASSETS[@]}" "${CHECKSUM_FILES[@]}"; do
curl -fsSL "https://github.com/NVIDIA/OpenShell/releases/download/${RELEASE_TAG}/$name" \
-o "$tmpdir/$name"
done
}

if command -v gh >/dev/null 2>&1; then
if GH_PROMPT_DISABLED=1 GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}" gh release download "v${PIN_VERSION}" --repo NVIDIA/OpenShell \
--pattern "$ASSET" --dir "$tmpdir" 2>/dev/null \
&& GH_PROMPT_DISABLED=1 GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}" gh release download "v${PIN_VERSION}" --repo NVIDIA/OpenShell \
--pattern "$CHECKSUM_FILE" --dir "$tmpdir" 2>/dev/null; then
gh_ok=1
for name in "${ASSETS[@]}" "${CHECKSUM_FILES[@]}"; do
if ! GH_PROMPT_DISABLED=1 GH_TOKEN="${GH_TOKEN:-${GITHUB_TOKEN:-}}" gh release download "$RELEASE_TAG" --repo NVIDIA/OpenShell \
--pattern "$name" --dir "$tmpdir" --clobber 2>/dev/null; then
gh_ok=0
break
fi
done
if [ "$gh_ok" = "1" ]; then
: # gh succeeded
else
warn "gh CLI download failed (auth may not be configured) — falling back to curl"
rm -f "$tmpdir/$ASSET" "$tmpdir/$CHECKSUM_FILE"
rm -f "$tmpdir"/*
download_with_curl
fi
else
download_with_curl
fi

info "Verifying SHA-256 checksum..."
(cd "$tmpdir" && grep -F "$ASSET" "$CHECKSUM_FILE" | shasum -a 256 -c -) \
|| fail "SHA-256 checksum verification failed for $ASSET"
for i in "${!ASSETS[@]}"; do
asset_name="${ASSETS[$i]}"
checksum_file="${CHECKSUM_FILES[$i]}"
(cd "$tmpdir" && grep -F "$asset_name" "$checksum_file" | shasum -a 256 -c -) \
|| fail "SHA-256 checksum verification failed for $asset_name"
done

tar xzf "$tmpdir/$ASSET" -C "$tmpdir"
for asset_name in "${ASSETS[@]}"; do
tar xzf "$tmpdir/$asset_name" -C "$tmpdir"
done

target_dir="/usr/local/bin"

install_bins() {
local dir="$1"
install -m 755 "$tmpdir/openshell" "$dir/openshell"
if [ -x "$tmpdir/openshell-gateway" ]; then
install -m 755 "$tmpdir/openshell-gateway" "$dir/openshell-gateway"
fi
if [ -x "$tmpdir/openshell-sandbox" ]; then
install -m 755 "$tmpdir/openshell-sandbox" "$dir/openshell-sandbox"
fi
}

if [ -w "$target_dir" ]; then
install -m 755 "$tmpdir/openshell" "$target_dir/openshell"
install_bins "$target_dir"
elif [ "${NEMOCLAW_NON_INTERACTIVE:-}" = "1" ] || [ ! -t 0 ]; then
target_dir="${XDG_BIN_HOME:-$HOME/.local/bin}"
mkdir -p "$target_dir"
install -m 755 "$tmpdir/openshell" "$target_dir/openshell"
install_bins "$target_dir"
warn "Installed openshell to $target_dir/openshell (user-local path)"
warn "For future shells, run: export PATH=\"$target_dir:\$PATH\""
warn "Add that export to your shell profile, or open a new shell before using openshell directly."
else
sudo install -m 755 "$tmpdir/openshell" "$target_dir/openshell"
if [ -x "$tmpdir/openshell-gateway" ]; then
sudo install -m 755 "$tmpdir/openshell-gateway" "$target_dir/openshell-gateway"
fi
if [ -x "$tmpdir/openshell-sandbox" ]; then
sudo install -m 755 "$tmpdir/openshell-sandbox" "$target_dir/openshell-sandbox"
fi
fi

info "$("$target_dir/openshell" --version 2>&1 || echo openshell) installed"
24 changes: 15 additions & 9 deletions src/lib/inventory-commands.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,12 @@ describe("inventory commands", () => {
model: "configured-alpha",
provider: "configured-provider",
gpuEnabled: true,
hostGpuDetected: false,
sandboxGpuEnabled: true,
sandboxGpuMode: null,
sandboxGpuDevice: null,
openshellDriver: null,
openshellVersion: null,
policies: ["pypi"],
agent: "openclaw",
isDefault: true,
Expand Down Expand Up @@ -149,7 +155,7 @@ describe("inventory commands", () => {
expect(lines).toContain(" Recovered 1 sandbox entry from the live OpenShell gateway.");
expect(lines).toContain(" alpha *");
expect(lines).toContain(
" agent: openclaw model: nvidia/nemotron-3-super-120b-a12b provider: nvidia-prod GPU policies: pypi",
" agent: openclaw model: nvidia/nemotron-3-super-120b-a12b provider: nvidia-prod sandbox GPU policies: pypi",
);
});

Expand All @@ -175,7 +181,7 @@ describe("inventory commands", () => {
});

expect(lines).toContain(
" agent: hermes model: nvidia/nemotron-3-super-120b-a12b provider: nvidia-prod CPU policies: none",
" agent: hermes model: nvidia/nemotron-3-super-120b-a12b provider: nvidia-prod CPU sandbox policies: none",
);
});

Expand Down Expand Up @@ -208,19 +214,19 @@ describe("inventory commands", () => {

// Default sandbox reflects live gateway state, with an onboarded drift note.
expect(lines).toContain(
" agent: openclaw model: live-model provider: live-provider GPU policies: none",
" agent: openclaw model: live-model provider: live-provider sandbox GPU policies: none",
);
// Stale stored row for the default sandbox must not leak through.
expect(lines).not.toContain(
" agent: openclaw model: configured-alpha provider: configured-provider GPU policies: none",
" agent: openclaw model: configured-alpha provider: configured-provider sandbox GPU policies: none",
);
expect(lines).toContain(
" (onboarded: model=configured-alpha, provider=configured-provider)",
);
// Non-default sandbox keeps its stored config — the gateway only applies
// to whichever sandbox is currently connected.
expect(lines).toContain(
" agent: openclaw model: configured-beta provider: beta-provider CPU policies: none",
" agent: openclaw model: configured-beta provider: beta-provider CPU sandbox policies: none",
);
});

Expand All @@ -245,7 +251,7 @@ describe("inventory commands", () => {
});

expect(lines).toContain(
" agent: openclaw model: configured-alpha provider: configured-provider GPU policies: none",
" agent: openclaw model: configured-alpha provider: configured-provider sandbox GPU policies: none",
);
expect(lines.some((l) => l.includes("onboarded"))).toBe(false);
});
Expand All @@ -271,7 +277,7 @@ describe("inventory commands", () => {
});

expect(lines).toContain(
" agent: openclaw model: configured-alpha provider: configured-provider GPU policies: none",
" agent: openclaw model: configured-alpha provider: configured-provider sandbox GPU policies: none",
);
expect(lines.some((l) => l.includes("onboarded"))).toBe(false);
});
Expand All @@ -298,7 +304,7 @@ describe("inventory commands", () => {
});

expect(lines).toContain(
" agent: openclaw model: live-model provider: configured-provider GPU policies: none",
" agent: openclaw model: live-model provider: configured-provider sandbox GPU policies: none",
);
expect(lines).toContain(" (onboarded: model=configured-alpha)");
});
Expand All @@ -325,7 +331,7 @@ describe("inventory commands", () => {
});

expect(lines).toContain(
" agent: openclaw model: configured-alpha provider: live-provider GPU policies: none",
" agent: openclaw model: configured-alpha provider: live-provider sandbox GPU policies: none",
);
expect(lines).toContain(" (onboarded: provider=configured-provider)");
});
Expand Down
40 changes: 39 additions & 1 deletion src/lib/inventory-commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ export interface SandboxEntry {
model?: string | null;
provider?: string | null;
gpuEnabled?: boolean;
hostGpuDetected?: boolean;
sandboxGpuEnabled?: boolean;
sandboxGpuMode?: string | null;
sandboxGpuDevice?: string | null;
openshellDriver?: string | null;
openshellVersion?: string | null;
policies?: string[] | null;
providerCredentialHashes?: Record<string, string> | null;
messagingChannels?: string[] | null;
Expand Down Expand Up @@ -51,6 +57,12 @@ export interface SandboxInventoryRow {
model: string | null;
provider: string | null;
gpuEnabled: boolean;
hostGpuDetected: boolean;
sandboxGpuEnabled: boolean;
sandboxGpuMode: string | null;
sandboxGpuDevice: string | null;
openshellDriver: string | null;
openshellVersion: string | null;
policies: string[];
agent: string | null;
dashboardPort?: number | null;
Expand Down Expand Up @@ -95,6 +107,12 @@ export interface StatusSandboxRow {
model: string | null;
provider: string | null;
gpuEnabled: boolean;
hostGpuDetected: boolean;
sandboxGpuEnabled: boolean;
sandboxGpuMode: string | null;
sandboxGpuDevice: string | null;
openshellDriver: string | null;
openshellVersion: string | null;
policies: string[];
agent: string | null;
dashboardPort?: number | null;
Expand Down Expand Up @@ -129,12 +147,22 @@ function buildSandboxInventoryRow(
getActiveSessionCount?: (sandboxName: string) => number | null,
): SandboxInventoryRow {
const activeSessionCount = getActiveSessionCount ? getActiveSessionCount(sandbox.name) : null;
const sandboxGpuEnabled =
typeof sandbox.sandboxGpuEnabled === "boolean"
? sandbox.sandboxGpuEnabled
: sandbox.gpuEnabled === true;

return {
name: sandbox.name,
model: sandbox.model || null,
provider: sandbox.provider || null,
gpuEnabled: sandbox.gpuEnabled === true,
hostGpuDetected: sandbox.hostGpuDetected === true,
sandboxGpuEnabled,
sandboxGpuMode: safeStatusString(sandbox.sandboxGpuMode || null),
sandboxGpuDevice: safeStatusString(sandbox.sandboxGpuDevice || null),
openshellDriver: safeStatusString(sandbox.openshellDriver || null),
openshellVersion: safeStatusString(sandbox.openshellVersion || null),
policies: Array.isArray(sandbox.policies) ? sandbox.policies : [],
agent: sandbox.agent || null,
...(sandbox.dashboardPort != null ? { dashboardPort: sandbox.dashboardPort } : {}),
Expand Down Expand Up @@ -225,7 +253,7 @@ export function renderSandboxInventoryText(
const modelDrifted = !!(useLive && liveInference.model && liveInference.model !== sandbox.model);
const providerDrifted =
!!(useLive && liveInference.provider && liveInference.provider !== sandbox.provider);
const gpu = sandbox.gpuEnabled ? "GPU" : "CPU";
const gpu = sandbox.sandboxGpuEnabled ? "sandbox GPU" : "CPU sandbox";
const presets = sandbox.policies.length > 0 ? sandbox.policies.join(", ") : "none";
const connected = sandbox.connected ? " ●" : "";
const agent = sandbox.agent || "openclaw";
Expand Down Expand Up @@ -267,11 +295,21 @@ function buildStatusSandboxRow(
typeof sandbox.dashboardPort === "number" && Number.isFinite(sandbox.dashboardPort)
? sandbox.dashboardPort
: null;
const sandboxGpuEnabled =
typeof sandbox.sandboxGpuEnabled === "boolean"
? sandbox.sandboxGpuEnabled
: sandbox.gpuEnabled === true;
return {
name: safeStatusString(sandbox.name) || sandbox.name,
model: safeStatusString(liveModel || sandbox.model || null),
provider: safeStatusString(liveProvider || sandbox.provider || null),
gpuEnabled: sandbox.gpuEnabled === true,
hostGpuDetected: sandbox.hostGpuDetected === true,
sandboxGpuEnabled,
sandboxGpuMode: safeStatusString(sandbox.sandboxGpuMode || null),
sandboxGpuDevice: safeStatusString(sandbox.sandboxGpuDevice || null),
openshellDriver: safeStatusString(sandbox.openshellDriver || null),
openshellVersion: safeStatusString(sandbox.openshellVersion || null),
policies: Array.isArray(sandbox.policies)
? sandbox.policies
.filter((policy): policy is string => typeof policy === "string")
Expand Down
Loading
Loading