336 lines · 9.2 KB · TypeScript
RawDownload
// CRITICALimport { spawn, spawnSync } from "node:child_process";import { existsSync, readdirSync, statSync } from "node:fs";import { dirname, join, resolve } from "node:path";import { resolveBinary } from "../../../core/command";import { resolveVllmPythonPath } from "./vllm-python-path";import { getUpgradeCommandFromEnvironment, getVllmUpgradeVersion, VLLM_UPGRADE_ENV } from "./runtime-upgrade-config";import {  VLLM_RUNTIME_COMMAND_TIMEOUT_MS,  VLLM_UPGRADE_TIMEOUT_MS,} from "./configs"; type CommandResult = {  code: number | null;  stdout: string;  stderr: string;}; const parseCommandInput = (args: unknown): string[] | null => {  if (!Array.isArray(args)) {    return null;  }  const parsed = args.map((item) => (typeof item === "string" ? item.trim() : "")).filter((item) => item.length > 0);  return parsed.length > 0 ? parsed : null;}; const resolveVllmUpgradeTarget = (version?: string): string => {  const configured = version && version.trim().length > 0 ? version.trim() : getVllmUpgradeVersion();  const normalized = configured.trim();  if (!normalized) {    return "vllm";  }  return normalized.includes("==") || normalized.endsWith(".whl") ? normalized : `vllm==${normalized}`;}; const resolveVllmUpgradeCommand = (  pythonPath: string,  version: string,  preferBundled: boolean,  bundledWheel: { path: string; version: string | null } | null,): { command: string; args: string[] } => {  if (preferBundled) {    if (bundledWheel) {      if (resolveBinary("uv")) {        return {          command: "uv",          args: ["pip", "install", "--python", pythonPath, "--upgrade", bundledWheel.path],        };      }      return { command: pythonPath, args: ["-m", "pip", "install", "--upgrade", bundledWheel.path] };    }  }   const packageSpec = resolveVllmUpgradeTarget(version);  if (resolveBinary("uv")) {    return {      command: "uv",      args: ["pip", "install", "--python", pythonPath, "--upgrade", packageSpec],    };  }   return {    command: pythonPath,    args: ["-m", "pip", "install", "--upgrade", packageSpec],  };}; const runCommand = (  command: string,  args: string[],  timeoutMs = VLLM_RUNTIME_COMMAND_TIMEOUT_MS): Promise<CommandResult> => {  return new Promise((resolveResult) => {    const child = spawn(command, args, { env: process.env });    let stdout = "";    let stderr = "";    const timer = setTimeout(() => {      child.kill("SIGKILL");    }, timeoutMs);     child.stdout?.on("data", (data) => {      stdout += data.toString();    });    child.stderr?.on("data", (data) => {      stderr += data.toString();    });    child.on("error", (error) => {      clearTimeout(timer);      resolveResult({ code: null, stdout: stdout.trim(), stderr: error.message });    });    child.on("close", (code) => {      clearTimeout(timer);      resolveResult({ code, stdout: stdout.trim(), stderr: stderr.trim() });    });  });}; const resolvePythonBinary = (): string | null => {  const candidates: string[] = [];  const runtimePython = resolveVllmPythonPath();  if (runtimePython) {    candidates.push(runtimePython);  }  const override = process.env["VLLM_STUDIO_RUNTIME_PYTHON"];  if (override) {    candidates.push(override);  }  candidates.push("python3", "python");   for (const candidate of candidates) {    try {      const result = spawnSync(candidate, ["--version"], { timeout: 2000 });      if (result.status === 0) {        return candidate;      }    } catch {      continue;    }  }  return null;}; const resolveBundledWheel = (): { path: string; version: string | null } | null => {  const runtimeDirectory = resolve(process.cwd(), "runtime", "wheels");  if (!existsSync(runtimeDirectory)) {    return null;  }  const candidates = readdirSync(runtimeDirectory).filter(    (file) => file.startsWith("vllm-") && file.endsWith(".whl")  );  if (candidates.length === 0) {    return null;  }  const withStats = candidates    .map((file) => {      const fullPath = join(runtimeDirectory, file);      return { file, fullPath, mtime: statSync(fullPath).mtimeMs };    })    .sort((a, b) => b.mtime - a.mtime);   const latest = withStats[0];  if (!latest) {    return null;  }  const versionMatch = latest.file.match(/^vllm-([0-9A-Za-z.+-]+)-/);  return {    path: latest.fullPath,    version: versionMatch?.[1] ?? null,  };}; const resolveVllmBinary = (pythonPath: string | null): string | null => {  if (pythonPath) {    const vllmBin = join(dirname(pythonPath), "vllm");    if (existsSync(vllmBin)) {      return vllmBin;    }  }  return resolveBinary("vllm");}; export const getVllmRuntimeInfo = async (): Promise<{  installed: boolean;  version: string | null;  python_path: string | null;  vllm_bin: string | null;  upgrade_command_available: boolean;  bundled_wheel: { path: string; version: string | null } | null;}> => {  const pythonPath = resolvePythonBinary();  const vllmBin = resolveVllmBinary(pythonPath);  const bundledWheel = resolveBundledWheel();   if (!pythonPath) {    return {      installed: false,      version: null,      python_path: null,      vllm_bin: vllmBin,      upgrade_command_available: false,      bundled_wheel: bundledWheel,    };  }   const result = await runCommand(pythonPath, [    "-c",    "import json, sys\ntry:\n import vllm\n print(json.dumps({'version': vllm.__version__, 'python': sys.executable}))\nexcept Exception:\n print(json.dumps({'version': None, 'python': sys.executable}))",  ]);   if (result.code !== 0) {    return {      installed: false,      version: null,      python_path: pythonPath,      vllm_bin: vllmBin,      upgrade_command_available: false,      bundled_wheel: bundledWheel,    };  }   let parsed: { version?: string | null; python?: string | null } | null = null;  try {    parsed = JSON.parse(result.stdout) as { version?: string | null; python?: string | null };  } catch {    parsed = null;  }   return {    installed: Boolean(parsed?.version),    version: parsed?.version ?? null,    python_path: parsed?.python ?? pythonPath,    vllm_bin: vllmBin,    upgrade_command_available: true,    bundled_wheel: bundledWheel,  };}; export const getVllmConfigHelp = async (): Promise<{  config: string | null;  error: string | null;}> => {  const pythonPath = resolvePythonBinary();  const vllmBin = resolveVllmBinary(pythonPath);   if (!pythonPath && !vllmBin) {    return { config: null, error: "vLLM runtime not available" };  }   const command = vllmBin ?? pythonPath ?? "";  const args = vllmBin    ? ["serve", "--help"]    : ["-m", "vllm.entrypoints.openai.api_server", "--help"];   const result = await runCommand(command, args, 15_000);  if (result.code !== 0) {    return {      config: result.stdout || null,      error: result.stderr || "Failed to fetch vLLM config",    };  }  return { config: result.stdout || null, error: null };}; type VllmUpgradeOptions = {  preferBundled?: boolean;  command?: string;  args?: string[];  version?: string;}; export const upgradeVllmRuntime = async (  options: VllmUpgradeOptions = {}): Promise<{  success: boolean;  version: string | null;  output: string | null;  error: string | null;  used_wheel: string | null;}> => {  const pythonPath = resolvePythonBinary();  if (!pythonPath) {    return {      success: false,      version: null,      output: null,      error: "Python runtime not found",      used_wheel: null,    };  }   const preferredCommand = options.command?.trim() ?? getUpgradeCommandFromEnvironment(VLLM_UPGRADE_ENV);  const command = preferredCommand;  const parsedArguments = parseCommandInput(options.args);  const preferBundled = options.preferBundled !== false;  if (!command) {      const version = resolveVllmUpgradeTarget(options.version);    const bundledWheel = resolveBundledWheel();    const resolvedCommand = resolveVllmUpgradeCommand(      pythonPath,      version,      preferBundled,      bundledWheel,    );    const result = await runCommand(      resolvedCommand.command,      resolvedCommand.args,      VLLM_UPGRADE_TIMEOUT_MS    );    if (result.code !== 0) {      const usedWheel = preferBundled ? bundledWheel?.path ?? null : null;      return {        success: false,        version: null,        output: result.stdout || null,        error: result.stderr || "Upgrade failed",        used_wheel: usedWheel,      };    }     const runtimeInfo = await getVllmRuntimeInfo();    const usedWheel = preferBundled ? bundledWheel?.path ?? null : null;    return {      success: true,      version: runtimeInfo.version,      output: result.stdout || null,      error: result.stderr || null,      used_wheel: usedWheel,    };  }   const customArguments = parsedArguments ?? [];    const result = await runCommand(      command,      customArguments,      VLLM_UPGRADE_TIMEOUT_MS    );   if (result.code !== 0) {    return {      success: false,      version: null,      output: result.stdout || null,      error: result.stderr || "Upgrade failed",      used_wheel: null,    };  }   const runtimeInfo = await getVllmRuntimeInfo();  return {    success: true,    version: runtimeInfo.version,    output: result.stdout || null,    error: result.stderr || null,    used_wheel: null,  };};