All files / src/models cache.ts

93.75% Statements 30/32
66.66% Branches 2/3
80% Functions 8/10
96.55% Lines 28/29

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 848x             8x   8x             8x     8x 125x 125x 125x     125x       8x 8x       8x           33x           132x   33x 33x 126x     3x 12x 12x   1x               3x       8x 33x 33x 297x   33x 33x                
import {
  MODELS_CACHE_KEY_FINGERPRINT_STATE_KEY,
  MODELS_CACHE_VERSION,
  MODELS_CACHE_VERSION_STATE_KEY,
  MODELS_STATE_KEY,
  RAW_MODELS_STATE_KEY,
} from "../shared/constants";
import { debugLog, outputLog } from "../shared/logging";
import type { NvidiaModelSummary } from "../types";
import { ELITE_MODELS_WHITELIST, type NormalizedNvidiaModel } from "./catalog";
 
export interface ModelCacheState {
  get<T>(key: string): T | undefined;
  update(key: string, value: unknown): PromiseLike<void>;
}
 
let modelCacheOperationQueue: Promise<void> = Promise.resolve();
 
/** Serialize discovery and manual refresh so rollback cannot clobber a newer cache write. */
export function runSerializedModelCacheOperation<T>(operation: () => Promise<T>): Promise<T> {
  const nextOperation = modelCacheOperationQueue.catch(() => undefined).then(operation);
  modelCacheOperationQueue = nextOperation.then(
    () => undefined,
    () => undefined,
  );
  return nextOperation;
}
 
/** Reset the shared serializer during extension teardown and between isolated tests. */
export function resetModelCacheOperationQueue(): void {
  modelCacheOperationQueue = Promise.resolve();
}
 
/** Commit all cache facets together, restoring the previous snapshot after any write failure. */
export async function writeModelCacheAtomically(
  globalState: ModelCacheState,
  rawModels: readonly NvidiaModelSummary[],
  normalizedModels: readonly NormalizedNvidiaModel[],
  keyFingerprint: string,
): Promise<void> {
  const entries: ReadonlyArray<readonly [string, unknown]> = [
    [RAW_MODELS_STATE_KEY, rawModels],
    [MODELS_STATE_KEY, normalizedModels],
    [MODELS_CACHE_VERSION_STATE_KEY, MODELS_CACHE_VERSION],
    [MODELS_CACHE_KEY_FINGERPRINT_STATE_KEY, keyFingerprint],
  ];
  const previousValues = entries.map(([key]) => [key, globalState.get<unknown>(key)] as const);
 
  try {
    for (const [key, value] of entries) {
      await globalState.update(key, value);
    }
  } catch (writeError) {
    for (const [key, previousValue] of previousValues) {
      try {
        await globalState.update(key, previousValue);
      } catch (rollbackError) {
        debugLog(
          "modelCache",
          `Cache rollback failed for ${key}: ${
            rollbackError instanceof Error ? rollbackError.message : String(rollbackError)
          }`,
        );
      }
    }
    throw writeError;
  }
}
 
export function reportMissingCuratedModels(rawModels: readonly NvidiaModelSummary[]): void {
  const apiModelIds = new Set(rawModels.map((model) => model.id));
  const missingCuratedModels = Object.keys(ELITE_MODELS_WHITELIST).filter(
    (modelId) => !apiModelIds.has(modelId),
  );
  if (missingCuratedModels.length > 0) {
    outputLog(
      "models",
      `Curated NVIDIA NIM models missing from the current API response: ${missingCuratedModels.join(
        ", ",
      )}`,
    );
  }
}