Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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
4 changes: 2 additions & 2 deletions src/lib/inference/vllm-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ export interface VllmModelDef {
* platform-specific flags (the NVFP4 MoE checkpoint targets `sm_121a` only,
* the very large V4 Flash recipe wants Station-class VRAM) appear only on
* profiles they can actually run on. Direct `NEMOCLAW_VLLM_MODEL`
* overrides normally bypass the picker filter, but a model-specific runtime
* is rejected outside this list so an incompatible image is never pulled.
* overrides bypass the picker filter, so `runVllmInstall` rejects any
* override outside this list before the image pull and model download.
*/
platforms: readonly VllmPlatform[];
/**
Expand Down
60 changes: 60 additions & 0 deletions src/lib/inference/vllm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -760,6 +760,66 @@ describe("installVllm model resolution", () => {
);
});

it("rejects a Spark-only override without a runtime before side effects on generic Linux (#7358)", async () => {
process.env.NEMOCLAW_VLLM_MODEL = "qwen3.6-35b-a3b-nvfp4";
const profile = detectVllmProfile({ platform: "linux", type: "nvidia" })!;
const beforeInstall = vi.fn();

const result = await installVllm(profile, {
hasImage: true,
nonInteractive: true,
promptFn: vi.fn(),
beforeInstall,
});

expect(result).toEqual({ ok: false });
expect(beforeInstall).not.toHaveBeenCalled();
expect(mocks.runCapture).not.toHaveBeenCalled();
expect(mocks.dockerPullWithProgressWatchdog).not.toHaveBeenCalled();
expect(mocks.dockerSpawn).not.toHaveBeenCalled();
const errors = errSpy.mock.calls.map((c: unknown[]) => String(c[0])).join("\n");
expect(errors).toContain("Qwen3.6 35B-A3B NVFP4 is not supported on Linux + NVIDIA GPU");
});

it("rejects the Station-only V4 Flash override before its 352 GB download on generic Linux (#7358)", async () => {
process.env.NEMOCLAW_VLLM_MODEL = "deepseek-v4-flash";
const profile = detectVllmProfile({ platform: "linux", type: "nvidia" })!;
const beforeInstall = vi.fn();

const result = await installVllm(profile, {
hasImage: true,
nonInteractive: true,
promptFn: vi.fn(),
beforeInstall,
});

expect(result).toEqual({ ok: false });
expect(beforeInstall).not.toHaveBeenCalled();
expect(mocks.dockerPullWithProgressWatchdog).not.toHaveBeenCalled();
expect(mocks.dockerSpawn).not.toHaveBeenCalled();
const errors = errSpy.mock.calls.map((c: unknown[]) => String(c[0])).join("\n");
expect(errors).toContain("DeepSeek V4 Flash is not supported on Linux + NVIDIA GPU");
});

it("still accepts a platform-matched override on its own platform (#7358)", async () => {
process.env.NEMOCLAW_VLLM_MODEL = "qwen3.6-35b-a3b-nvfp4";
const profile = detectVllmProfile({ platform: "spark", type: "nvidia" })!;
const promptFn = vi.fn<(q: string) => Promise<string>>();

const result = await installVllm(profile, {
hasImage: true,
nonInteractive: true,
promptFn,
});

expect(result).toEqual({ ok: false });
expect(promptFn).not.toHaveBeenCalled();
const summary = logSpy.mock.calls.map((c: unknown[]) => String(c[0])).join("\n");
expect(summary).toContain("Model: nvidia/Qwen3.6-35B-A3B-NVFP4 (NEMOCLAW_VLLM_MODEL override)");
const errors = errSpy.mock.calls.map((c: unknown[]) => String(c[0])).join("\n");
expect(errors).not.toContain("is not supported on");
});

it("installs the complete Nemotron Ultra Station recipe without another selection", async () => {
process.env.NEMOCLAW_VLLM_MODEL = "nemotron-3-ultra-550b-a55b";
mocks.getGpuIndicesByName.mockReturnValue([0]);
Expand Down
8 changes: 7 additions & 1 deletion src/lib/inference/vllm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,13 @@ async function runVllmInstall(
});
if (!resolved) return { ok: false };
const { model, source: modelSource } = resolved;
if (model.runtime && !model.platforms.includes(profile.platform)) {
// Platform-restricted models are filtered out of the interactive picker,
// but a direct NEMOCLAW_VLLM_MODEL override bypasses that filter, so this
// gate is the only platform enforcement on the env-override path. It must
// reject every wrong-platform model, not just runtime-carrying ones — an
// NVFP4 Spark checkpoint or a 352 GB Station recipe cannot serve here and
// must fail before the image pull and download (#7358).
if (!model.platforms.includes(profile.platform)) {
console.error(` vLLM install failed: ${model.label} is not supported on ${profile.name}`);
return { ok: false };
}
Expand Down
Loading