178 lines · 5.7 KB · TypeScript
RawDownload
// CRITICALimport { config as loadEnvironment } from "dotenv";import { z } from "zod";import { existsSync } from "node:fs";import { basename, resolve } from "node:path";import { loadPersistedConfig, type ProviderConfig } from "./persisted-config"; /** * Runtime configuration for the controller. */export interface Config {  host: string;  port: number;  api_key?: string;  cors_origins?: string[];  inference_port: number;   data_dir: string;  db_path: string;  models_dir: string;  sglang_python?: string;  tabby_api_dir?: string;  llama_bin?: string;  exllamav3_command?: string;  strict_openai_models: boolean;  providers: ProviderConfig[];} /** * Load the closest .env file from current or parent directories. * @returns The loaded .env path or undefined. */export const loadDotEnvironment = (): string | undefined => {  const candidates = [    resolve(process.cwd(), ".env"),    resolve(process.cwd(), "..", ".env"),    resolve(process.cwd(), "..", "..", ".env"),  ];   const envPath = candidates.find((pathValue) => existsSync(pathValue));  if (envPath) {    loadEnvironment({ path: envPath });  }  return envPath;}; /** * Create a validated runtime configuration from environment variables. * @returns Validated configuration object. */export const createConfig = (): Config => {  loadDotEnvironment();   const cwd = process.cwd();  const localDataDirectory = resolve(cwd, "data");  const parentDataDirectory = resolve(cwd, "..", "data");  const defaultDataDirectory =    basename(cwd) === "controller" && existsSync(parentDataDirectory)      ? parentDataDirectory      : localDataDirectory;  const defaultDatabasePath = resolve(defaultDataDirectory, "controller.db");   const isLoopbackHost = (value: string): boolean => {    const normalized = value.trim().toLowerCase();    return normalized === "127.0.0.1" || normalized === "localhost" || normalized === "::1";  };   const parseBooleanFlag = (value: string | undefined): boolean => {    if (!value) return false;    return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase());  };   const normalizeOrigin = (value: string): string | null => {    try {      const origin = new URL(value.trim()).origin;      return origin === "null" ? null : origin;    } catch {      return null;    }  };   const parseCorsOrigins = (value: string | undefined): string[] => {    const defaults = [      "http://localhost:3000",      "http://127.0.0.1:3000",      "http://localhost:3001",      "http://127.0.0.1:3001",      "http://host.docker.internal:3000",      "http://host.docker.internal:3001",    ];    const candidates =      value && value.trim().length > 0 ? value.split(",").map((entry) => entry.trim()) : defaults;    return [      ...new Set(        candidates          .map((entry) => normalizeOrigin(entry))          .filter((entry): entry is string => Boolean(entry))      ),    ];  };   const schema = z.object({    VLLM_STUDIO_HOST: z.string().default("127.0.0.1"),    VLLM_STUDIO_PORT: z.coerce.number().int().positive().default(8080),    VLLM_STUDIO_API_KEY: z.string().optional(),    VLLM_STUDIO_ALLOW_UNAUTHENTICATED: z.string().optional(),    VLLM_STUDIO_CORS_ORIGINS: z.string().optional(),    VLLM_STUDIO_INFERENCE_PORT: z.coerce.number().int().positive().default(8000),     VLLM_STUDIO_DATA_DIR: z.string().default(defaultDataDirectory),    VLLM_STUDIO_DB_PATH: z.string().default(defaultDatabasePath),    VLLM_STUDIO_MODELS_DIR: z.string().default("/models"),    VLLM_STUDIO_SGLANG_PYTHON: z.string().optional(),    VLLM_STUDIO_TABBY_API_DIR: z.string().optional(),    VLLM_STUDIO_LLAMA_BIN: z.string().optional(),    VLLM_STUDIO_EXLLAMAV3_COMMAND: z.string().optional(),    VLLM_STUDIO_STRICT_OPENAI_MODELS: z.string().optional(),  });   const parsed = schema.parse(process.env);  const host = parsed.VLLM_STUDIO_HOST.trim() || "127.0.0.1";   const strictOpenAIModels = parsed.VLLM_STUDIO_STRICT_OPENAI_MODELS;  const strictOpenAIModelsEnabled = strictOpenAIModels    ? ["1", "true", "yes", "on"].includes(strictOpenAIModels.trim().toLowerCase())    : false;   const config: Config = {    host,    port: parsed.VLLM_STUDIO_PORT,    inference_port: parsed.VLLM_STUDIO_INFERENCE_PORT,     data_dir: resolve(parsed.VLLM_STUDIO_DATA_DIR),    db_path: resolve(parsed.VLLM_STUDIO_DB_PATH),    models_dir: resolve(parsed.VLLM_STUDIO_MODELS_DIR),    strict_openai_models: strictOpenAIModelsEnabled,    cors_origins: parseCorsOrigins(parsed.VLLM_STUDIO_CORS_ORIGINS),    providers: [],  };   if (parsed.VLLM_STUDIO_API_KEY) {    config.api_key = parsed.VLLM_STUDIO_API_KEY;  }   const allowUnauthenticated = parseBooleanFlag(parsed.VLLM_STUDIO_ALLOW_UNAUTHENTICATED);  if (!config.api_key && !allowUnauthenticated && !isLoopbackHost(host)) {    throw new Error(      "VLLM_STUDIO_API_KEY is required when binding the controller to a non-loopback host. Set VLLM_STUDIO_ALLOW_UNAUTHENTICATED=true only for trusted local environments."    );  }   if (parsed.VLLM_STUDIO_SGLANG_PYTHON) {    config.sglang_python = parsed.VLLM_STUDIO_SGLANG_PYTHON;  }  if (parsed.VLLM_STUDIO_TABBY_API_DIR) {    config.tabby_api_dir = parsed.VLLM_STUDIO_TABBY_API_DIR;  }  if (parsed.VLLM_STUDIO_LLAMA_BIN) {    config.llama_bin = parsed.VLLM_STUDIO_LLAMA_BIN;  }  if (parsed.VLLM_STUDIO_EXLLAMAV3_COMMAND) {    const command = parsed.VLLM_STUDIO_EXLLAMAV3_COMMAND.trim();    if (command) {      config.exllamav3_command = command;    }  }   const persisted = loadPersistedConfig(config.data_dir);  if (persisted.models_dir) {    config.models_dir = resolve(persisted.models_dir);  }   if (Array.isArray(persisted.providers)) {    config.providers = persisted.providers;  }   return config;};

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t