import {
  log
} from "./chunk-2ODBA7MQ.js";

// src/model-registry.ts
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
import { join } from "path";
var DEFAULT_CAPABILITIES = {
  modelId: "default",
  maxPositionEmbeddings: 32768,
  contextWindow: 32768,
  supportsExtendedContext: false,
  typicalOutputTokens: 8192,
  source: "default",
  fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
};
var KNOWN_MODELS = {
  "qwen3-30b-a3b-instruct": {
    maxPositionEmbeddings: 40960,
    contextWindow: 131072,
    // 128K with YaRN - but LM Studio defaults to ~32K
    supportsExtendedContext: true,
    ropeScaling: {
      type: "yarn",
      factor: 4,
      originalMaxPositionEmbeddings: 32768
    },
    typicalOutputTokens: 8192
  },
  "qwen3-coder-30b-a3b-instruct": {
    maxPositionEmbeddings: 40960,
    contextWindow: 131072,
    // 128K with YaRN - but LM Studio defaults to ~32K
    supportsExtendedContext: true,
    ropeScaling: {
      type: "yarn",
      factor: 4,
      originalMaxPositionEmbeddings: 32768
    },
    typicalOutputTokens: 8192
  },
  "qwen3-8b": {
    maxPositionEmbeddings: 40960,
    contextWindow: 131072,
    supportsExtendedContext: true,
    typicalOutputTokens: 4096
  },
  "qwen3-14b": {
    maxPositionEmbeddings: 40960,
    contextWindow: 131072,
    supportsExtendedContext: true,
    typicalOutputTokens: 4096
  },
  "qwen3-32b": {
    maxPositionEmbeddings: 40960,
    contextWindow: 131072,
    supportsExtendedContext: true,
    typicalOutputTokens: 4096
  },
  "llama-3.1": {
    maxPositionEmbeddings: 131072,
    contextWindow: 131072,
    supportsExtendedContext: false,
    typicalOutputTokens: 8192
  },
  "llama-3.2": {
    maxPositionEmbeddings: 131072,
    contextWindow: 131072,
    supportsExtendedContext: false,
    typicalOutputTokens: 8192
  },
  "mistral-nemo": {
    maxPositionEmbeddings: 131072,
    contextWindow: 131072,
    supportsExtendedContext: false,
    typicalOutputTokens: 8192
  },
  "gemma-2": {
    maxPositionEmbeddings: 8192,
    contextWindow: 8192,
    supportsExtendedContext: false,
    typicalOutputTokens: 4096
  }
};
var ModelRegistry = class {
  registryPath;
  data;
  CACHE_TTL_DAYS = 7;
  constructor(memoryDir) {
    const registryDir = join(memoryDir, ".registry");
    if (!existsSync(registryDir)) {
      mkdirSync(registryDir, { recursive: true });
    }
    this.registryPath = join(registryDir, "model-capabilities.json");
    this.data = this.loadRegistry();
  }
  loadRegistry() {
    try {
      if (existsSync(this.registryPath)) {
        const content = readFileSync(this.registryPath, "utf-8");
        const data = JSON.parse(content);
        log.info(`ModelRegistry: loaded ${Object.keys(data.models).length} cached models`);
        return data;
      }
    } catch (err) {
      log.warn(`ModelRegistry: failed to load registry: ${err}`);
    }
    return { models: {}, version: 1 };
  }
  saveRegistry() {
    try {
      writeFileSync(this.registryPath, JSON.stringify(this.data, null, 2));
    } catch (err) {
      log.warn(`ModelRegistry: failed to save registry: ${err}`);
    }
  }
  isCacheExpired(model) {
    const fetched = new Date(model.fetchedAt);
    const now = /* @__PURE__ */ new Date();
    const daysDiff = (now.getTime() - fetched.getTime()) / (1e3 * 60 * 60 * 24);
    return daysDiff > this.CACHE_TTL_DAYS;
  }
  normalizeModelId(modelId) {
    return modelId.toLowerCase().replace(/@\d+bit$/, "").replace(/-mlx$/, "").replace(/-awq$/, "").replace(/-gptq$/, "").replace(/-gguf$/, "").replace(/^mlx-community\//, "").replace(/^models\//, "").trim();
  }
  /**
   * Get capabilities for a model, using cache if available
   */
  getCapabilities(modelId) {
    const normalizedId = this.normalizeModelId(modelId);
    if (this.data.models[normalizedId]) {
      const cached = this.data.models[normalizedId];
      if (!this.isCacheExpired(cached)) {
        log.info(`ModelRegistry: using cached capabilities for ${modelId}`);
        return cached;
      }
      log.info(`ModelRegistry: cache expired for ${modelId}, will refresh`);
    }
    for (const [knownId, capabilities] of Object.entries(KNOWN_MODELS)) {
      if (normalizedId.includes(knownId)) {
        log.info(`ModelRegistry: using known capabilities for ${modelId}`);
        const caps = {
          ...DEFAULT_CAPABILITIES,
          ...capabilities,
          modelId: normalizedId,
          source: "default",
          fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
        };
        this.data.models[normalizedId] = caps;
        this.saveRegistry();
        return caps;
      }
    }
    log.info(`ModelRegistry: using default capabilities for ${modelId}`);
    return {
      ...DEFAULT_CAPABILITIES,
      modelId: normalizedId
    };
  }
  /**
   * Store capabilities for a model
   */
  setCapabilities(modelId, capabilities) {
    const normalizedId = this.normalizeModelId(modelId);
    const caps = {
      ...capabilities,
      modelId: normalizedId,
      fetchedAt: (/* @__PURE__ */ new Date()).toISOString()
    };
    this.data.models[normalizedId] = caps;
    this.saveRegistry();
    log.info(`ModelRegistry: stored capabilities for ${modelId}`);
  }
  /**
   * Calculate optimal input/output sizes for a model
   * @param maxContextOverride - Optional override for max context (e.g., if LLM server defaults to smaller window)
   */
  calculateContextSizes(modelId, maxContextOverride) {
    const caps = this.getCapabilities(modelId);
    const effectiveContextWindow = maxContextOverride ?? caps.contextWindow;
    const overheadTokens = Math.min(1e3, Math.floor(effectiveContextWindow / 10));
    const minInputTokens = Math.min(512, Math.floor(effectiveContextWindow / 4));
    const minOutputTokens = 256;
    let outputTokens = caps.typicalOutputTokens;
    if (effectiveContextWindow > 65536) {
      outputTokens = Math.min(Math.floor(effectiveContextWindow / 8), 16384);
    }
    outputTokens = Math.min(outputTokens, Math.floor(effectiveContextWindow / 4));
    outputTokens = Math.max(
      minOutputTokens,
      Math.min(outputTokens, effectiveContextWindow - overheadTokens - minInputTokens)
    );
    const availableForInput = Math.max(
      0,
      effectiveContextWindow - outputTokens - overheadTokens
    );
    const maxInputChars = Math.max(0, Math.floor(availableForInput * 3.5));
    const source = maxContextOverride ? "user override" : caps.source;
    return {
      maxInputChars,
      maxOutputTokens: outputTokens,
      description: `${caps.modelId}: ${effectiveContextWindow.toLocaleString()} context (${source}), using ${maxInputChars.toLocaleString()} chars input / ${outputTokens} tokens output`
    };
  }
  /**
   * Fetch capabilities from Hugging Face (if available)
   * Returns true if successful
   */
  async fetchFromHuggingFace(modelId) {
    log.info(`ModelRegistry: fetchFromHuggingFace not yet implemented for ${modelId}`);
    return false;
  }
  /**
   * List all cached models
   */
  listCached() {
    return Object.keys(this.data.models);
  }
  /**
   * Clear expired cache entries
   */
  cleanExpired() {
    const before = Object.keys(this.data.models).length;
    this.data.models = Object.fromEntries(
      Object.entries(this.data.models).filter(([_, caps]) => !this.isCacheExpired(caps))
    );
    const after = Object.keys(this.data.models).length;
    const removed = before - after;
    if (removed > 0) {
      this.saveRegistry();
      log.info(`ModelRegistry: cleaned ${removed} expired entries`);
    }
    return removed;
  }
};

export {
  ModelRegistry
};
//# sourceMappingURL=chunk-FEMOX5AD.js.map