Forked from tupik/openai-compat-endpoint
src / models.ts
// src/models.ts
// Module for caching and managing model list
import { GeneratorController } from "@lmstudio/sdk";
import { fetchModels, filterFreeModels } from "./api";
import { globalConfigSchematics } from "./schema";
import { loadCache, saveCache } from "./file-cache";
let cachedAllModels: string[] | null = null;
let cachedFreeModels: string[] | null = null;
let loadPromise: Promise<void> | null = null;
/**
* Loads and caches model list from API
* First checks file cache, then loads from API
*/
async function loadModels(ctl: GeneratorController): Promise<void> {
if (loadPromise) {
return loadPromise;
}
loadPromise = (async () => {
const cache = loadCache();
if (cache) {
cachedAllModels = cache.allModels;
cachedFreeModels = cache.freeModels;
loadPromise = null;
return;
}
const globalConfig = await ctl.getGlobalPluginConfig(globalConfigSchematics as any);
const baseUrl = globalConfig.get("baseUrl") || "https://openrouter.ai/api/v1";
const apiKey = globalConfig.get("apiKey") || "";
const allModels = await fetchModels(baseUrl, apiKey);
if (allModels.length > 0) {
cachedAllModels = allModels;
cachedFreeModels = filterFreeModels(allModels);
saveCache(cachedAllModels, cachedFreeModels);
} else {
console.warn("[Models] API returned empty list, using fallback");
cachedAllModels = ["x-ai/grok-4.1-fast:free"];
cachedFreeModels = ["x-ai/grok-4.1-fast:free"];
}
loadPromise = null;
})();
return loadPromise;
}
/**
* Gets model list (all or free only)
*/
export async function getModels(
ctl: GeneratorController,
onlyFree: boolean = false
): Promise<string[]> {
await loadModels(ctl);
if (onlyFree) {
return cachedFreeModels || [];
}
return cachedAllModels || [];
}
/**
* Gets first available model (for fallback)
*/
export async function getFirstModel(
ctl: GeneratorController,
onlyFree: boolean = false
): Promise<string> {
const models = await getModels(ctl, onlyFree);
return models[0] || "";
}
/**
* Forces reload of models from API (ignoring cache)
*/
export async function reloadModels(
ctl: GeneratorController,
onlyFree: boolean = false
): Promise<string[]> {
cachedAllModels = null;
cachedFreeModels = null;
loadPromise = null;
await loadModels(ctl);
if (onlyFree) {
return cachedFreeModels || [];
}
return cachedAllModels || [];
}