All files / src/models refresh.ts

90.24% Statements 37/41
53.84% Branches 7/13
100% Functions 3/3
90.24% Lines 37/41

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 982x 2x 2x         2x 2x     2x 2x             2x               16x 16x 16x       16x               16x             16x 16x   16x 16x 14x 11x 11x 11x           9x 9x 9x       9x 3x       9x     3x 3x 3x           4x 4x 4x 4x 3x           2x 8x    
import * as vscode from "vscode";
import { fetchModels, fetchModelsOrThrow } from "../api/client";
import {
  MODELS_CACHE_KEY_FINGERPRINT_STATE_KEY,
  PROVIDER_DISPLAY_NAME,
  SECRET_STORAGE_KEY,
} from "../shared/constants";
import { normalizeNvidiaModels } from "./catalog";
import { debugLog } from "../shared/logging";
import { NimChatModelProvider } from "../provider/chat-provider";
import { StatusBarManager } from "../shared/status-bar";
import { getApiKeyFingerprint, NvidiaApiKeyResolver } from "../api/key-resolver";
import {
  reportMissingCuratedModels,
  resetModelCacheOperationQueue,
  runSerializedModelCacheOperation,
  writeModelCacheAtomically,
} from "./cache";
 
export async function refreshModelsFromApi(
  context: vscode.ExtensionContext,
  ua: string,
  options: { showMessages: boolean; apiKey?: string },
  provider: NimChatModelProvider | null,
  statusBar?: StatusBarManager,
  keyResolver?: NvidiaApiKeyResolver,
): Promise<void> {
  return runSerializedModelCacheOperation(async () => {
    const configuredApiKey = options.apiKey?.trim();
    const cacheKeyFingerprint = context.globalState.get<string>(
      MODELS_CACHE_KEY_FINGERPRINT_STATE_KEY,
    );
    const apiKey =
      configuredApiKey ||
      (
        await keyResolver?.resolveForTool({
          cacheKeyFingerprint,
          allowUnmatchedRuntimeKey: true,
        })
      )?.value ||
      (await context.secrets.get(SECRET_STORAGE_KEY))?.trim();
    Iif (!apiKey) {
      Iif (options.showMessages) {
        vscode.window.showWarningMessage(`No ${PROVIDER_DISPLAY_NAME} API key configured.`);
      }
      return;
    }
 
    statusBar?.showRefreshing();
    try {
      const fetchModelsRequest =
        typeof fetchModelsOrThrow === "function" ? fetchModelsOrThrow : fetchModels;
      const rawModels = await fetchModelsRequest(apiKey, undefined, ua);
      if (Array.isArray(rawModels)) {
        reportMissingCuratedModels(rawModels);
        const normalizedModels = normalizeNvidiaModels(rawModels);
        await writeModelCacheAtomically(
          context.globalState,
          rawModels,
          normalizedModels,
          getApiKeyFingerprint(apiKey),
        );
        provider?.fireModelInfoChanged({ invalidateModelCache: false });
        statusBar?.showOk(normalizedModels.length);
        debugLog(
          "refreshModels",
          `Refreshed ${normalizedModels.length} models from ${PROVIDER_DISPLAY_NAME} API.`,
        );
        if (options.showMessages) {
          vscode.window.showInformationMessage(
            `Refreshed ${normalizedModels.length} ${PROVIDER_DISPLAY_NAME} models.`,
          );
        }
        return;
      }
 
      statusBar?.showError("Model refresh failed");
      debugLog("refreshModels", "Model refresh failed or returned malformed data.");
      Iif (options.showMessages) {
        vscode.window.showWarningMessage(
          `Failed to refresh models from ${PROVIDER_DISPLAY_NAME} API.`,
        );
      }
    } catch (error) {
      const msg = error instanceof Error ? error.message : String(error);
      statusBar?.showError(msg);
      debugLog("refreshModels", `Model refresh failed: ${msg}`);
      if (options.showMessages) {
        vscode.window.showErrorMessage(`Failed to refresh models: ${msg}`);
      }
    }
  });
}
 
export function resetRefreshQueue(): void {
  resetModelCacheOperationQueue();
}