Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 19 additions & 3 deletions bin/nemoclaw.js
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,22 @@ async function setupSpark() {
run(`sudo bash "${SCRIPTS}/setup-spark.sh"`);
}

function normalizeBrevGpuName(value) {
const trimmed = String(value || "").trim();
if (!trimmed) return "";
return trimmed.replace(/^nvidia-tesla-/i, "").toUpperCase();
}

function resolveBrevCreateConfig() {
const legacyGpu = String(process.env.NEMOCLAW_GPU || "").trim();
const legacyParts = legacyGpu.includes(":") ? legacyGpu.split(":") : [legacyGpu];
const type = String(process.env.NEMOCLAW_BREV_TYPE || legacyParts[0] || "a2-highgpu-1g").trim();
const gpuName = normalizeBrevGpuName(
process.env.NEMOCLAW_BREV_GPU_NAME || legacyParts[1] || "A100"
);
return { type, gpuName };
}

// eslint-disable-next-line complexity
async function deploy(instanceName) {
if (!instanceName) {
Expand All @@ -380,7 +396,7 @@ async function deploy(instanceName) {
validateName(instanceName, "instance name");
const name = instanceName;
const qname = shellQuote(name);
const gpu = process.env.NEMOCLAW_GPU || "a2-highgpu-1g:nvidia-tesla-a100:1";
const { type, gpuName } = resolveBrevCreateConfig();

console.log("");
console.log(` Deploying NemoClaw to Brev instance: ${name}`);
Expand All @@ -403,8 +419,8 @@ async function deploy(instanceName) {
}

if (!exists) {
console.log(` Creating Brev instance '${name}' (${gpu})...`);
run(`brev create ${qname} --gpu ${shellQuote(gpu)}`);
console.log(` Creating Brev instance '${name}' (${type}, ${gpuName})...`);
run(`brev create ${qname} --type ${shellQuote(type)} --gpu-name ${shellQuote(gpuName)}`);
} else {
console.log(` Brev instance '${name}' already exists.`);
}
Expand Down
8 changes: 5 additions & 3 deletions docs/deployment/deploy-to-remote-gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,14 @@ $ openclaw agent --agent main --local -m "Hello from the remote sandbox" --sessi

## GPU Configuration

The deploy script uses the `NEMOCLAW_GPU` environment variable to select the GPU type.
The deploy script uses the `NEMOCLAW_GPU` environment variable to select the Brev instance type and GPU name.
The default value is `a2-highgpu-1g:nvidia-tesla-a100:1`.
Set this variable before running `nemoclaw deploy` to use a different GPU configuration:
For direct overrides, you can also set `NEMOCLAW_BREV_TYPE` and `NEMOCLAW_BREV_GPU_NAME` before running `nemoclaw deploy`:

```console
$ export NEMOCLAW_GPU="a2-highgpu-1g:nvidia-tesla-a100:2"
$ export NEMOCLAW_GPU="a2-highgpu-1g:nvidia-tesla-a100:1"
$ export NEMOCLAW_BREV_TYPE="a2-highgpu-1g"
$ export NEMOCLAW_BREV_GPU_NAME="A100"
$ nemoclaw deploy <instance-name>
```

Expand Down
43 changes: 43 additions & 0 deletions test/cli.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,49 @@ describe("CLI dispatch", () => {
expect(fs.readFileSync(markerFile, "utf8")).toContain("logs alpha --follow");
});

it("deploy uses brev --type and --gpu-name instead of legacy --gpu", () => {
const home = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-cli-deploy-brev-"));
const localBin = path.join(home, "bin");
const markerFile = path.join(home, "brev-args");
fs.mkdirSync(localBin, { recursive: true });

fs.writeFileSync(
path.join(localBin, "brev"),
[
"#!/usr/bin/env bash",
`marker_file=${JSON.stringify(markerFile)}`,
"printf '%s\\n' \"$*\" >> \"$marker_file\"",
"if [ \"$1\" = \"ls\" ]; then",
" exit 0",
"fi",
"exit 0",
].join("\n"),
{ mode: 0o755 }
);
fs.writeFileSync(
path.join(localBin, "ssh"),
[
"#!/usr/bin/env bash",
"exit 0",
].join("\n"),
{ mode: 0o755 }
);
fs.writeFileSync(path.join(localBin, "rsync"), "#!/usr/bin/env bash\nexit 0\n", { mode: 0o755 });
fs.writeFileSync(path.join(localBin, "scp"), "#!/usr/bin/env bash\nexit 0\n", { mode: 0o755 });

const r = runWithEnv("deploy pr-998-test", {
HOME: home,
PATH: `${localBin}:${process.env.PATH || ""}`,
NVIDIA_API_KEY: "nvapi-test",
NEMOCLAW_GPU: "a2-highgpu-1g:nvidia-tesla-a100:1",
}, 25000);

expect(r.code).toBe(0);
const calls = fs.readFileSync(markerFile, "utf8").trim().split("\n");
expect(calls).toContain("create pr-998-test --type a2-highgpu-1g --gpu-name A100");
expect(calls.some((call) => call.includes("--gpu "))).toBe(false);
}, 25000);

it("connect does not pre-start a duplicate port forward", () => {
const home = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-cli-connect-forward-"));
const localBin = path.join(home, "bin");
Expand Down