whichmodel 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +373 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5025 -0
- package/dist/index.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/catalog/cache.ts","../src/formatter/box.ts","../src/types.ts","../src/catalog/sources.ts","../src/commands/stats.ts","../src/model-pricing.ts","../src/commands/list.ts","../src/estimation/cost-calculator.ts","../src/commands/compare.ts","../src/catalog/compressor.ts","../src/schemas/llm-schemas.ts","../src/utils/common.ts","../src/utils/result.ts","../src/recommender/llm-client.ts","../src/commands/update-recommender.ts","../src/recommender/fallback.ts","../src/catalog/normalization.ts","../src/config.ts","../src/schemas/provider-schemas.ts","../src/catalog/fal.ts","../src/catalog/merge.ts","../src/catalog/openrouter.ts","../src/catalog/replicate-pricing-cache.ts","../src/catalog/replicate-page-pricing.ts","../src/catalog/replicate.ts","../src/formatter/json.ts","../src/formatter/terminal.ts","../src/recommender/prompts.ts","../src/recommender/validator.ts","../src/version.ts","../src/recommender/index.ts","../src/index.ts"],"sourcesContent":["import { Command, type OptionValues } from \"commander\";\nimport ora from \"ora\";\nimport { getCacheStats, invalidateCache, formatCacheStats } from \"./catalog/cache.js\";\nimport { parseSourcesCsv, validateSupportedSourcesList } from \"./catalog/sources.js\";\nimport { computeStats, formatStatsTerminal, formatStatsJSON } from \"./commands/stats.js\";\nimport { filterAndSortModels, formatListTerminal, formatListJSON } from \"./commands/list.js\";\nimport { parseWorkloadDescription, estimateCost, formatCostEstimate } from \"./estimation/cost-calculator.js\";\nimport {\n findModelById,\n callCompareLLM,\n formatCompareTerminal,\n formatCompareJSON,\n} from \"./commands/compare.js\";\nimport {\n updateRecommenderModel,\n formatRecommenderUpdate,\n} from \"./commands/update-recommender.js\";\nimport { FalCatalog } from \"./catalog/fal.js\";\nimport { mergeCatalogModels } from \"./catalog/merge.js\";\nimport { OpenRouterCatalog } from \"./catalog/openrouter.js\";\nimport { ReplicateCatalog } from \"./catalog/replicate.js\";\nimport {\n DEFAULT_RECOMMENDER_MODEL,\n getConfig,\n requireApiKey,\n validateConfig,\n} from \"./config.js\";\nimport { toJsonOutput } from \"./formatter/json.js\";\nimport { renderBox } from \"./formatter/box.js\";\nimport { formatTerminal } from \"./formatter/terminal.js\";\nimport { recommend } from \"./recommender/index.js\";\nimport {\n ExitCode,\n WhichModelError,\n type Constraints,\n type Config,\n type Modality,\n type ModelEntry,\n} from \"./types.js\";\nimport { APP_VERSION } from \"./version.js\";\nimport { getModelPrimaryPrice } from \"./model-pricing.js\";\n\nconst VALID_MODALITIES: ReadonlyArray<Modality> = [\n \"text\",\n \"image\",\n \"video\",\n \"audio_tts\",\n \"audio_stt\",\n \"audio_generation\",\n \"vision\",\n \"embedding\",\n \"multimodal\",\n];\nconst MAX_TASK_LENGTH = 2000;\n\ninterface RecommendCLIOptions {\n json?: boolean;\n modality?: string;\n model?: string;\n maxPrice?: string;\n minContext?: string;\n minResolution?: string;\n exclude?: string;\n sources?: string;\n estimate?: string;\n verbose?: boolean;\n color?: boolean;\n cache?: boolean;\n updateRecommender?: boolean;\n}\n\nconst program = new Command();\n\nprogram\n .name(\"whichmodel\")\n .description(\"Tell me what you want to build. I'll tell you which AI model to use.\")\n .version(APP_VERSION)\n .argument(\"[task...]\", \"Task description\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-m, --modality <type>\", \"Force a specific modality\")\n .option(\"--model <id>\", \"Override recommender LLM\")\n .option(\"--max-price <number>\", \"Maximum price per unit in USD\")\n .option(\"--min-context <tokens>\", \"Minimum context length in tokens\")\n .option(\"--min-resolution <WxH>\", \"Minimum resolution\")\n .option(\"--exclude <ids>\", \"Exclude model IDs (comma-separated)\")\n .option(\"--sources <list>\", \"Catalog sources (comma-separated)\")\n .option(\"--estimate <workload>\", \"Workload description for cost estimation\")\n .option(\"-v, --verbose\", \"Show extra recommendation metadata\")\n .option(\"--no-color\", \"Disable colored output\")\n .option(\"--no-cache\", \"Bypass cache and fetch fresh catalog\")\n .option(\"--update-recommender\", \"Update the default recommender model\")\n .action(async (taskWords: string[], options: RecommendCLIOptions) => {\n const runStartedAt = Date.now();\n const noCache = shouldBypassCache(options);\n const noColor = options.color === false || Boolean(process.env.NO_COLOR);\n try {\n // Handle --update-recommender flag first (special case)\n if (options.updateRecommender) {\n const config = getConfig();\n requireApiKey(config);\n\n const spinner = ora(\"Analyzing models for best recommender...\").start();\n const sources = options.sources\n ? parseSources(options.sources)\n : getDefaultCatalogSources(config);\n let update: Awaited<ReturnType<typeof updateRecommenderModel>>;\n try {\n const models = await fetchCatalogModels(sources, config, noCache);\n update = await updateRecommenderModel(\n models,\n config.recommenderModel ?? DEFAULT_RECOMMENDER_MODEL\n );\n } finally {\n spinner.stop();\n }\n\n console.log(formatRecommenderUpdate(update));\n return;\n }\n\n // Normal recommendation flow - validate task first\n const task = taskWords.join(\" \").trim();\n validateTask(task);\n const constraints = parseConstraints(options);\n const config = getConfig();\n const sources = options.sources\n ? parseSources(options.sources)\n : getDefaultCatalogSources(config);\n validateSupportedSources(sources);\n\n requireApiKey(config);\n\n const validationMessage = validateConfig(config);\n if (validationMessage?.startsWith(\"Warning:\")) {\n console.error(validationMessage);\n }\n\n const spinner = ora(\"Fetching model catalog...\").start();\n const catalogFetchStartedAt = Date.now();\n let catalogFetchLatencyMs = 0;\n let allModels: ModelEntry[] = [];\n let result: Awaited<ReturnType<typeof recommend>>;\n try {\n allModels = await fetchCatalogModels(sources, config, noCache);\n catalogFetchLatencyMs = Date.now() - catalogFetchStartedAt;\n let models = applyExclusions(allModels, options.exclude);\n models = applyModelConstraints(models, constraints);\n\n if (models.length === 0) {\n throw new WhichModelError(\n \"No models found after applying filters.\",\n ExitCode.NO_MODELS_FOUND,\n \"Relax --max-price/--min-context filters or remove exclusions.\"\n );\n }\n\n spinner.text = \"Analyzing task and generating recommendations...\";\n result = await recommend({\n task,\n models,\n apiKey: config.apiKey,\n recommenderModel: options.model ?? config.recommenderModel ?? DEFAULT_RECOMMENDER_MODEL,\n constraints,\n catalogSources: sources,\n });\n } finally {\n spinner.stop();\n }\n\n // Apply cost estimation if --estimate flag is provided\n if (options.estimate) {\n try {\n const workload = parseWorkloadDescription(options.estimate);\n const tiers = [\"cheapest\", \"balanced\", \"best\"] as const;\n for (const tier of tiers) {\n const modelId = result.recommendation.recommendations[tier].id;\n const model = allModels.find((m) => m.id === modelId);\n if (model) {\n const costEst = estimateCost(model, workload);\n result.recommendation.recommendations[tier].estimatedCost = formatCostEstimate(costEst);\n }\n }\n } catch {\n // If parsing fails, keep the LLM-generated estimate\n }\n }\n\n if (options.json) {\n console.log(\n JSON.stringify(toJsonOutput(task, result.recommendation, result.meta), null, 2)\n );\n return;\n }\n\n const output = formatTerminal(result.recommendation, {\n recommenderModel: result.meta.recommenderModel,\n cost: result.meta.recommendationCostUsd,\n promptTokens: result.meta.promptTokens,\n completionTokens: result.meta.completionTokens,\n verbose: Boolean(options.verbose),\n noColor,\n recommendationLatencyMs: result.meta.recommendationLatencyMs,\n catalogFetchLatencyMs,\n totalLatencyMs: Date.now() - runStartedAt,\n });\n console.log(output);\n } catch (error) {\n handleCLIError(error);\n }\n });\n\nprogram\n .command(\"compare <modelA> <modelB>\")\n .description(\"Compare two models head-to-head for a task\")\n .requiredOption(\"--task <description>\", \"Task to compare for\")\n .option(\"--json\", \"Output as JSON\")\n .option(\"-v, --verbose\", \"Show detailed comparison\")\n .action(\n async (\n modelA: string,\n modelB: string,\n options: { task: string; json?: boolean; verbose?: boolean },\n command: Command\n ) => {\n try {\n const config = getConfig();\n requireApiKey(config);\n const mergedOptions = command.optsWithGlobals() as OptionValues;\n const noCache = shouldBypassCache(mergedOptions);\n const noColor = mergedOptions.color === false || Boolean(process.env.NO_COLOR);\n const asJson = options.json ?? Boolean(mergedOptions.json);\n\n const spinner = ora(\"Fetching catalog...\").start();\n try {\n const sources = getDefaultCatalogSources(config);\n const models = await fetchCatalogModels(sources, config, noCache);\n\n // Find the models\n const modelAEntry = findModelById(models, modelA);\n const modelBEntry = findModelById(models, modelB);\n\n if (!modelAEntry) {\n throw new WhichModelError(\n `Model not found: ${modelA}`,\n ExitCode.INVALID_ARGUMENTS,\n \"Use 'whichmodel list' to see available models.\"\n );\n }\n\n if (!modelBEntry) {\n throw new WhichModelError(\n `Model not found: ${modelB}`,\n ExitCode.INVALID_ARGUMENTS,\n \"Use 'whichmodel list' to see available models.\"\n );\n }\n\n // Check if comparing the same model\n if (modelAEntry.id === modelBEntry.id) {\n if (asJson) {\n console.log(\n JSON.stringify(\n formatCompareJSON(\n {\n winner: \"tie\",\n reasoning: \"Both model IDs resolve to the same model.\",\n modelA: {\n strengths: [\"Same model selected\"],\n weaknesses: [],\n estimatedCost: \"N/A\",\n suitedFor: [\"Use a different second model for comparison\"],\n },\n modelB: {\n strengths: [\"Same model selected\"],\n weaknesses: [],\n estimatedCost: \"N/A\",\n suitedFor: [\"Use a different second model for comparison\"],\n },\n },\n modelAEntry,\n modelBEntry\n ),\n null,\n 2\n )\n );\n return;\n }\n\n console.log(\n renderBox(\n [\n `Both model IDs resolve to the same model: ${modelAEntry.name}`,\n `ID: ${modelAEntry.id}`,\n ].join(\"\\n\"),\n { title: \"Compare\", noColor, borderColor: \"yellow\" }\n )\n );\n return;\n }\n\n spinner.start(\"Comparing models...\");\n\n const result = await callCompareLLM(\n options.task,\n modelAEntry,\n modelBEntry,\n config.apiKey,\n config.recommenderModel ?? DEFAULT_RECOMMENDER_MODEL\n );\n\n if (asJson) {\n console.log(JSON.stringify(formatCompareJSON(result, modelAEntry, modelBEntry), null, 2));\n } else {\n console.log(\n formatCompareTerminal(\n result,\n modelAEntry,\n modelBEntry,\n { task: options.task },\n noColor\n )\n );\n }\n } finally {\n spinner.stop();\n }\n } catch (error) {\n handleCLIError(error);\n }\n }\n );\n\nprogram\n .command(\"list\")\n .description(\"List available models\")\n .option(\"--modality <type>\", \"Filter by modality\")\n .option(\"--source <name>\", \"Filter by source\")\n .option(\"--sort <field>\", \"Sort by field (price, name, context)\", \"price\")\n .option(\"--limit <n>\", \"Limit results\", \"50\")\n .option(\"--json\", \"Output as JSON\")\n .action(\n async (\n options: { modality?: string; source?: string; sort: string; limit: string; json?: boolean },\n command: Command\n ) => {\n try {\n const config = getConfig();\n const mergedOptions = command.optsWithGlobals() as OptionValues;\n const noCache = shouldBypassCache(mergedOptions);\n const noColor = mergedOptions.color === false || Boolean(process.env.NO_COLOR);\n const asJson = options.json ?? Boolean(mergedOptions.json);\n\n // Validate modality\n if (options.modality && !VALID_MODALITIES.includes(options.modality as Modality)) {\n throw new WhichModelError(\n `Invalid modality '${options.modality}'.`,\n ExitCode.INVALID_ARGUMENTS,\n `Valid modalities: ${VALID_MODALITIES.join(\", \")}`\n );\n }\n\n // Validate sort\n const validSorts = [\"price\", \"name\", \"context\"] as const;\n if (!validSorts.includes(options.sort as typeof validSorts[number])) {\n throw new WhichModelError(\n `Invalid sort field '${options.sort}'.`,\n ExitCode.INVALID_ARGUMENTS,\n `Valid sorts: ${validSorts.join(\", \")}`\n );\n }\n\n // Parse limit\n const limit = Number.parseInt(options.limit, 10);\n if (!Number.isFinite(limit) || limit <= 0) {\n throw new WhichModelError(\n `Invalid limit '${options.limit}'.`,\n ExitCode.INVALID_ARGUMENTS,\n \"Limit must be a positive integer.\"\n );\n }\n\n const sources = options.source\n ? parseSources(options.source)\n : getDefaultCatalogSources(config);\n if (options.source && sources.length !== 1) {\n throw new WhichModelError(\n `Invalid source '${options.source}'.`,\n ExitCode.INVALID_ARGUMENTS,\n \"Use a single source value like --source openrouter\"\n );\n }\n validateSupportedSources(sources);\n const spinner = ora(\"Fetching catalog...\").start();\n let models: ModelEntry[];\n try {\n models = await fetchCatalogModels(sources, config, noCache);\n } finally {\n spinner.stop();\n }\n const sourceFilter = options.source ? sources[0] : undefined;\n\n const listOptions = {\n modality: options.modality as Modality | undefined,\n source: sourceFilter,\n sort: options.sort as \"price\" | \"name\" | \"context\",\n limit,\n };\n\n const items = filterAndSortModels(models, listOptions);\n\n if (asJson) {\n console.log(JSON.stringify(formatListJSON(items), null, 2));\n } else {\n console.log(formatListTerminal(items, models.length, listOptions, noColor));\n }\n } catch (error) {\n handleCLIError(error);\n }\n }\n );\n\nprogram\n .command(\"stats\")\n .description(\"Show catalog statistics\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (options: { json?: boolean }, command: Command) => {\n try {\n const config = getConfig();\n const mergedOptions = command.optsWithGlobals() as OptionValues;\n const noCache = shouldBypassCache(mergedOptions);\n const noColor = mergedOptions.color === false || Boolean(process.env.NO_COLOR);\n const asJson = options.json ?? Boolean(mergedOptions.json);\n\n const spinner = ora(\"Fetching catalog...\").start();\n const sources = getDefaultCatalogSources(config);\n let models: ModelEntry[];\n try {\n models = await fetchCatalogModels(sources, config, noCache);\n } finally {\n spinner.stop();\n }\n\n const stats = computeStats(models, config, sources);\n\n if (asJson) {\n console.log(JSON.stringify(formatStatsJSON(stats), null, 2));\n } else {\n console.log(formatStatsTerminal(stats, noColor));\n }\n } catch (error) {\n handleCLIError(error);\n }\n });\n\nprogram\n .command(\"cache\")\n .description(\"Manage catalog cache\")\n .option(\"--stats\", \"Show cache statistics\")\n .option(\"--clear\", \"Clear all cached catalog data\")\n .action(async (options: { stats?: boolean; clear?: boolean }, command: Command) => {\n try {\n const mergedOptions = command.optsWithGlobals() as OptionValues;\n const noColor = mergedOptions.color === false || Boolean(process.env.NO_COLOR);\n if (options.clear) {\n await invalidateCache();\n console.log(\n renderBox(\"Cache cleared.\", { title: \"Cache\", noColor, borderColor: \"magenta\" })\n );\n return;\n }\n\n // Default to showing stats\n const stats = await getCacheStats();\n console.log(formatCacheStats(stats, noColor));\n } catch (error) {\n handleCLIError(error);\n }\n });\n\nexport { program };\nexport {\n validateTask,\n parseConstraints,\n parseSources,\n getDefaultCatalogSources,\n validateSupportedSources,\n shouldBypassCache,\n};\nexport { fetchCatalogModelsFromFetchers };\n\nfunction shouldBypassCache(options: { cache?: boolean }): boolean {\n return options.cache === false;\n}\n\nfunction validateTask(task: string): void {\n if (!task) {\n throw new WhichModelError(\n \"Task description required.\",\n ExitCode.INVALID_ARGUMENTS,\n [\n \"Usage: whichmodel <task>\",\n \"\",\n \"Examples:\",\n ' whichmodel \"summarize legal contracts\"',\n ' whichmodel \"generate product photos\"',\n \"\",\n \"Run 'whichmodel --help' for more information.\",\n ].join(\"\\n\")\n );\n }\n\n if (task.length > MAX_TASK_LENGTH) {\n throw new WhichModelError(\n `Task description too long (${task.length} characters).`,\n ExitCode.INVALID_ARGUMENTS,\n [\n \"Please shorten your description to under 2000 characters.\",\n \"Focus on the core requirements rather than detailed context.\",\n ].join(\"\\n\")\n );\n }\n}\n\nfunction parseConstraints(options: RecommendCLIOptions): Constraints {\n const constraints: Constraints = {};\n\n if (options.modality) {\n if (!VALID_MODALITIES.includes(options.modality as Modality)) {\n throw new WhichModelError(\n `Invalid modality '${options.modality}'.`,\n ExitCode.INVALID_ARGUMENTS,\n [\n \"Valid modalities:\",\n ...VALID_MODALITIES.map((modality) => ` ${modality}`),\n \"\",\n 'Example: whichmodel \"generate images\" --modality image',\n ].join(\"\\n\")\n );\n }\n\n constraints.modality = options.modality as Modality;\n }\n\n if (options.maxPrice !== undefined) {\n const parsedPrice = Number(options.maxPrice);\n if (!Number.isFinite(parsedPrice) || parsedPrice < 0) {\n throw new WhichModelError(\n `Invalid price format '${options.maxPrice}'.`,\n ExitCode.INVALID_ARGUMENTS,\n [\n \"--max-price expects a non-negative number in USD.\",\n \"\",\n \"Example: --max-price 0.05\",\n ].join(\"\\n\")\n );\n }\n constraints.maxPrice = parsedPrice;\n }\n\n if (options.minContext !== undefined) {\n if (!/^\\d+$/.test(options.minContext)) {\n throw new WhichModelError(\n `Invalid min context '${options.minContext}'.`,\n ExitCode.INVALID_ARGUMENTS,\n \"--min-context expects a positive integer, e.g. --min-context 200000\"\n );\n }\n const parsedContext = Number.parseInt(options.minContext, 10);\n if (!Number.isFinite(parsedContext) || parsedContext <= 0) {\n throw new WhichModelError(\n `Invalid min context '${options.minContext}'.`,\n ExitCode.INVALID_ARGUMENTS,\n \"--min-context expects a positive integer, e.g. --min-context 200000\"\n );\n }\n constraints.minContext = parsedContext;\n }\n\n if (options.minResolution) {\n if (!/^\\d+x\\d+$/i.test(options.minResolution)) {\n throw new WhichModelError(\n `Invalid resolution format '${options.minResolution}'.`,\n ExitCode.INVALID_ARGUMENTS,\n [\n \"--min-resolution expects WIDTHxHEIGHT format.\",\n \"\",\n \"Examples:\",\n \" --min-resolution 1024x1024\",\n \" --min-resolution 1920x1080\",\n ].join(\"\\n\")\n );\n }\n\n constraints.minResolution = options.minResolution;\n }\n\n if (options.exclude) {\n constraints.exclude = options.exclude\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n }\n\n return constraints;\n}\n\nfunction applyExclusions(models: ModelEntry[], excludeArg?: string): ModelEntry[] {\n if (!excludeArg) {\n return models;\n }\n\n const patterns = excludeArg\n .split(\",\")\n .map((item) => item.trim())\n .filter(Boolean);\n\n if (patterns.length === 0) {\n return models;\n }\n\n // Pre-compile patterns for O(n) filtering instead of O(n*m)\n const exactMatches = new Set<string>();\n const prefixMatches: string[] = [];\n\n for (const pattern of patterns) {\n if (pattern.endsWith(\"*\")) {\n prefixMatches.push(pattern.slice(0, -1));\n } else {\n exactMatches.add(pattern);\n }\n }\n\n return models.filter((model) => {\n // Check exact match first (O(1) lookup)\n if (exactMatches.has(model.id)) {\n return false;\n }\n // Check prefix matches\n for (const prefix of prefixMatches) {\n if (model.id.startsWith(prefix)) {\n return false;\n }\n }\n return true;\n });\n}\n\nfunction applyModelConstraints(models: ModelEntry[], constraints: Constraints): ModelEntry[] {\n return models.filter((model) => {\n if (constraints.modality && model.modality !== constraints.modality) {\n return false;\n }\n\n if (typeof constraints.minContext === \"number\") {\n if ((model.contextLength ?? 0) < constraints.minContext) {\n return false;\n }\n }\n\n if (typeof constraints.maxPrice === \"number\") {\n if (getModelPrimaryPrice(model) > constraints.maxPrice) {\n return false;\n }\n }\n\n if (constraints.minResolution && model.maxResolution) {\n if (!isResolutionAtLeast(model.maxResolution, constraints.minResolution)) {\n return false;\n }\n }\n\n return true;\n });\n}\n\nfunction isResolutionAtLeast(actual: string, minimum: string): boolean {\n const actualParts = actual.toLowerCase().split(\"x\");\n const minimumParts = minimum.toLowerCase().split(\"x\");\n const actualW = Number(actualParts[0] ?? Number.NaN);\n const actualH = Number(actualParts[1] ?? Number.NaN);\n const minimumW = Number(minimumParts[0] ?? Number.NaN);\n const minimumH = Number(minimumParts[1] ?? Number.NaN);\n if (\n !Number.isFinite(actualW) ||\n !Number.isFinite(actualH) ||\n !Number.isFinite(minimumW) ||\n !Number.isFinite(minimumH)\n ) {\n return false;\n }\n\n return actualW >= minimumW && actualH >= minimumH;\n}\n\nfunction parseSources(sourcesArg?: string): string[] {\n return parseSourcesCsv(sourcesArg);\n}\n\nfunction getDefaultCatalogSources(config: Config): string[] {\n const sources = [\"openrouter\"];\n if (config.falApiKey) {\n sources.push(\"fal\");\n }\n if (config.replicateApiToken) {\n sources.push(\"replicate\");\n }\n return sources;\n}\n\nfunction validateSupportedSources(sources: string[]): void {\n validateSupportedSourcesList(sources);\n}\n\nasync function fetchCatalogModels(\n sources: string[],\n config: Config,\n noCache: boolean = false\n): Promise<ModelEntry[]> {\n const sourceFetchers: SourceFetcher[] = [];\n for (const source of sources) {\n if (source === \"openrouter\") {\n sourceFetchers.push({\n source,\n fetch: async () => new OpenRouterCatalog({ noCache, cacheTtl: config.cacheTtl }).fetch(),\n });\n continue;\n }\n\n if (source === \"fal\") {\n sourceFetchers.push({\n source,\n fetch: async () =>\n new FalCatalog({ apiKey: config.falApiKey, noCache, cacheTtl: config.cacheTtl }).fetch(),\n });\n continue;\n }\n\n if (source === \"replicate\") {\n sourceFetchers.push({\n source,\n fetch: async () =>\n new ReplicateCatalog({\n apiToken: config.replicateApiToken,\n noCache,\n cacheTtl: config.cacheTtl,\n replicatePriceTtlSeconds: config.replicatePriceTtlSeconds,\n replicatePriceMaxStaleSeconds: config.replicatePriceMaxStaleSeconds,\n replicatePriceFetchBudget: config.replicatePriceFetchBudget,\n replicatePriceConcurrency: config.replicatePriceConcurrency,\n }).fetch(),\n });\n continue;\n }\n\n throw new WhichModelError(\n `Unsupported source '${source}'.`,\n ExitCode.INVALID_ARGUMENTS,\n \"Use --sources openrouter,fal,replicate\"\n );\n }\n\n return fetchCatalogModelsFromFetchers(sourceFetchers, sources);\n}\n\ninterface SourceFetcher {\n source: string;\n fetch: () => Promise<ModelEntry[]>;\n}\n\nasync function fetchCatalogModelsFromFetchers(\n fetchers: SourceFetcher[],\n requestedSources: string[],\n warn: (message: string) => void = (message) => {\n console.error(message);\n }\n): Promise<ModelEntry[]> {\n const settled = await Promise.allSettled(fetchers.map((fetcher) => fetcher.fetch()));\n const successfulModels: ModelEntry[][] = [];\n const failures: Array<{ source: string; message: string }> = [];\n\n settled.forEach((result, index) => {\n const source = fetchers[index]?.source ?? \"unknown\";\n if (result.status === \"fulfilled\") {\n successfulModels.push(result.value);\n return;\n }\n\n const reason = result.reason;\n const message = reason instanceof Error ? reason.message : String(reason);\n failures.push({ source, message });\n });\n\n if (successfulModels.length === 0) {\n if (failures.length === 1 && settled.length === 1) {\n const reason = settled[0];\n if (reason && reason.status === \"rejected\" && reason.reason instanceof WhichModelError) {\n throw reason.reason;\n }\n }\n\n const attempted = failures.map((failure) => ` ✗ ${failure.source}: ${failure.message}`).join(\"\\n\");\n throw new WhichModelError(\n \"All catalog sources failed to respond.\",\n ExitCode.NO_MODELS_FOUND,\n [\n \"Attempted sources:\",\n attempted || \" (none)\",\n \"\",\n \"Suggestions:\",\n \" • Check your internet connection\",\n \" • Verify API keys are valid\",\n \" • Try again in a few minutes\",\n ].join(\"\\n\")\n );\n }\n\n if (failures.length > 0) {\n const attempted = failures.map((failure) => ` ✗ ${failure.source}: ${failure.message}`).join(\"\\n\");\n warn(\n [\n \"Warning: Some catalog sources failed. Continuing with available sources.\",\n attempted,\n ].join(\"\\n\")\n );\n }\n\n const merged = mergeCatalogModels(successfulModels);\n if (merged.length === 0) {\n throw new WhichModelError(\n \"No models found from any source.\",\n ExitCode.NO_MODELS_FOUND,\n [\n `Configured sources: ${requestedSources.join(\", \")}`,\n \"\",\n \"If you expected more models:\",\n \" • Add FAL_API_KEY for image/video models\",\n \" • Add REPLICATE_API_TOKEN for broader coverage\",\n ].join(\"\\n\")\n );\n }\n\n return merged;\n}\n\nfunction handleCLIError(error: unknown): never {\n if (error instanceof WhichModelError) {\n console.error(`Error: ${error.message}`);\n if (error.recoveryHint) {\n console.error(error.recoveryHint);\n }\n process.exit(error.exitCode);\n }\n\n const detail = error instanceof Error ? error.message : \"Unknown error\";\n console.error(`Error: ${detail}`);\n process.exit(ExitCode.GENERAL_ERROR);\n}\n","/**\n * File-based cache for catalog data\n *\n * Caches normalized model catalogs to disk to reduce API calls.\n * Follows XDG Base Directory specification on Unix systems.\n *\n * @module catalog/cache\n */\n\nimport fs from \"node:fs/promises\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { renderBox } from \"../formatter/box.js\";\nimport type { CacheEntry, CacheStats, CacheSourceStats, ModelEntry } from \"../types.js\";\n\n/**\n * Get the cache directory path\n *\n * - Unix: ~/.cache/whichmodel/\n * - Windows: %LOCALAPPDATA%\\whichmodel\\cache\\\n */\nexport function getCacheDir(): string {\n if (process.platform === \"win32\") {\n const localAppData = process.env.LOCALAPPDATA ?? path.join(os.homedir(), \"AppData\", \"Local\");\n return path.join(localAppData, \"whichmodel\", \"cache\");\n }\n\n // Follow XDG Base Directory specification on Unix\n const xdgCacheHome = process.env.XDG_CACHE_HOME ?? path.join(os.homedir(), \".cache\");\n return path.join(xdgCacheHome, \"whichmodel\");\n}\n\n/**\n * Get the cache file path for a specific source\n */\nfunction getCachePath(source: string): string {\n return path.join(getCacheDir(), `${source}-catalog.json`);\n}\n\n/**\n * Get the metadata file path\n */\nfunction getMetadataPath(): string {\n return path.join(getCacheDir(), \"metadata.json\");\n}\n\n/**\n * Format a timestamp as a human-readable age string\n */\nfunction formatAge(timestamp: number): string {\n const now = Math.floor(Date.now() / 1000);\n const diffSeconds = now - timestamp;\n\n if (diffSeconds < 60) {\n return \"just now\";\n }\n\n const diffMinutes = Math.floor(diffSeconds / 60);\n if (diffMinutes < 60) {\n return `${diffMinutes}m ago`;\n }\n\n const diffHours = Math.floor(diffMinutes / 60);\n if (diffHours < 24) {\n return `${diffHours}h ago`;\n }\n\n const diffDays = Math.floor(diffHours / 24);\n return `${diffDays}d ago`;\n}\n\n/**\n * Check if a cache entry is still valid based on TTL\n */\nfunction isCacheValid(timestamp: number, ttl: number): boolean {\n const now = Math.floor(Date.now() / 1000);\n return now - timestamp <= ttl;\n}\n\n/**\n * Read cached catalog data for a source\n *\n * @param source - The catalog source ID (e.g., \"openrouter\", \"fal\")\n * @returns The cached models, or null if not cached or expired\n */\nexport async function readCache(source: string): Promise<ModelEntry[] | null> {\n const cachePath = getCachePath(source);\n\n try {\n const content = await fs.readFile(cachePath, \"utf-8\");\n const cache: CacheEntry<ModelEntry[]> = JSON.parse(content);\n\n // Validate cache structure\n if (!cache.data || !cache.timestamp || !cache.ttl) {\n return null;\n }\n\n // Check if expired\n if (!isCacheValid(cache.timestamp, cache.ttl)) {\n return null;\n }\n\n if (Array.isArray(cache.data) && cache.data.length === 0) {\n return null;\n }\n\n return cache.data;\n } catch {\n // Cache doesn't exist, is malformed, or can't be read\n return null;\n }\n}\n\n/**\n * Write catalog data to cache\n *\n * @param source - The catalog source ID\n * @param data - The normalized model entries to cache\n * @param ttl - Time-to-live in seconds\n */\nexport async function writeCache(\n source: string,\n data: ModelEntry[],\n ttl: number\n): Promise<void> {\n const cacheDir = getCacheDir();\n const cachePath = getCachePath(source);\n\n const cache: CacheEntry<ModelEntry[]> = {\n data,\n timestamp: Math.floor(Date.now() / 1000),\n ttl,\n source,\n };\n\n // Ensure cache directory exists with secure permissions\n await fs.mkdir(cacheDir, { recursive: true, mode: 0o700 });\n\n // Atomic write: write to temp file, then rename\n // Use mode 0o600 to ensure only owner can read cache files\n const tempPath = `${cachePath}.tmp`;\n await fs.writeFile(tempPath, JSON.stringify(cache, null, 2), { mode: 0o600 });\n await fs.rename(tempPath, cachePath);\n}\n\n/**\n * Invalidate (delete) cache for a specific source or all sources\n *\n * @param source - Optional source ID. If not provided, clears all caches.\n */\nexport async function invalidateCache(source?: string): Promise<void> {\n if (source) {\n const cachePath = getCachePath(source);\n try {\n await fs.unlink(cachePath);\n } catch {\n // File doesn't exist, ignore\n }\n return;\n }\n\n // Clear all caches\n const cacheDir = getCacheDir();\n try {\n const files = await fs.readdir(cacheDir);\n await Promise.all(\n files\n .filter((file) => file.endsWith(\"-catalog.json\"))\n .map((file) => fs.unlink(path.join(cacheDir, file)).catch(() => {}))\n );\n // Also remove metadata file\n await fs.unlink(getMetadataPath()).catch(() => {});\n } catch {\n // Directory doesn't exist or can't be read, ignore\n }\n}\n\n/**\n * Get statistics about cached data\n *\n * @param configuredTtl - The configured TTL to use for staleness calculation\n * @returns Cache statistics including location and per-source info\n */\nexport async function getCacheStats(configuredTtl: number = 3600): Promise<CacheStats> {\n const cacheDir = getCacheDir();\n const sources: CacheSourceStats[] = [];\n\n try {\n const files = await fs.readdir(cacheDir);\n const cacheFiles = files.filter((file) => file.endsWith(\"-catalog.json\"));\n\n for (const file of cacheFiles) {\n const source = file.replace(\"-catalog.json\", \"\");\n const cachePath = path.join(cacheDir, file);\n\n try {\n const content = await fs.readFile(cachePath, \"utf-8\");\n const cache: CacheEntry<ModelEntry[]> = JSON.parse(content);\n\n const ttl = cache.ttl ?? configuredTtl;\n const isStale = !isCacheValid(cache.timestamp, ttl);\n\n sources.push({\n name: source,\n timestamp: cache.timestamp,\n ttl,\n modelCount: Array.isArray(cache.data) ? cache.data.length : 0,\n age: formatAge(cache.timestamp),\n isStale,\n });\n } catch {\n // Skip malformed cache files\n }\n }\n } catch {\n // Directory doesn't exist or can't be read\n }\n\n // Sort by name for consistent output\n sources.sort((a, b) => a.name.localeCompare(b.name));\n\n return {\n location: cacheDir,\n sources,\n };\n}\n\n/**\n * Format cache statistics for terminal output\n */\nexport function formatCacheStats(stats: CacheStats, noColor: boolean = false): string {\n const lines: string[] = [];\n\n lines.push(\"Cache Statistics:\");\n lines.push(` Location: ${stats.location}`);\n lines.push(\"\");\n\n if (stats.sources.length === 0) {\n lines.push(\" No cached data.\");\n return renderBox(lines.join(\"\\n\"), {\n title: \"Cache\",\n noColor,\n borderColor: \"magenta\",\n });\n }\n\n lines.push(\" Source Age TTL Models\");\n lines.push(\" ───────────────────────────────────────\");\n\n for (const source of stats.sources) {\n const ttlStr = source.isStale ? `${source.ttl}s (stale)` : `${source.ttl}s`;\n const staleStr = source.isStale ? \" (stale)\" : \"\";\n lines.push(\n ` ${source.name.padEnd(14)} ${source.age.padEnd(10)} ${ttlStr.padEnd(6)} ${source.modelCount}${staleStr}`\n );\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Cache\",\n noColor,\n borderColor: \"magenta\",\n });\n}\n","import boxen, { type Options as BoxenOptions } from \"boxen\";\n\nexport interface RenderBoxOptions {\n title?: string;\n noColor?: boolean;\n borderColor?: BoxenOptions[\"borderColor\"];\n}\n\nexport function renderBox(content: string, options: RenderBoxOptions = {}): string {\n const boxOptions: BoxenOptions = {\n padding: { top: 0, right: 1, bottom: 0, left: 1 },\n margin: { top: 0, right: 0, bottom: 0, left: 0 },\n borderStyle: \"round\",\n title: options.title,\n ...(!options.noColor && options.borderColor\n ? { borderColor: options.borderColor }\n : {}),\n };\n\n return boxen(content, boxOptions);\n}\n","/**\n * Core type definitions for whichmodel\n *\n * These types define the data structures used throughout the application\n * for model catalogs, recommendations, configuration, and CLI options.\n *\n * @version 0.1.0\n */\n\n// =============================================================================\n// MODALITY TYPES\n// =============================================================================\n\n/**\n * All supported AI modalities\n *\n * - text: Text generation (LLMs)\n * - image: Image generation\n * - video: Video generation\n * - audio_tts: Text-to-speech\n * - audio_stt: Speech-to-text (transcription)\n * - audio_generation: Music/sound generation\n * - vision: Image understanding/analysis\n * - embedding: Text embeddings for search/RAG\n * - multimodal: Models that handle multiple modalities\n */\nexport type Modality =\n | \"text\"\n | \"image\"\n | \"video\"\n | \"audio_tts\"\n | \"audio_stt\"\n | \"audio_generation\"\n | \"vision\"\n | \"embedding\"\n | \"multimodal\";\n\n// =============================================================================\n// PRICING TYPES (Per Modality)\n// =============================================================================\n\n/**\n * Pricing for text generation models\n * Prices are per 1 million tokens\n */\nexport interface TextPricing {\n type: \"text\";\n /** Price per 1M prompt/input tokens in USD */\n promptPer1mTokens: number;\n /** Price per 1M completion/output tokens in USD */\n completionPer1mTokens: number;\n}\n\n/**\n * Pricing for image generation models\n * Different providers use different pricing units\n */\nexport interface ImagePricing {\n type: \"image\";\n /** Price per generated image in USD (optional - some providers use per-megapixel) */\n perImage?: number;\n /** Price per megapixel in USD (optional) */\n perMegapixel?: number;\n /** Price per diffusion step in USD (optional - for SD-based models) */\n perStep?: number;\n}\n\n/**\n * Pricing for video generation models\n */\nexport interface VideoPricing {\n type: \"video\";\n /** Price per second of video in USD */\n perSecond?: number;\n /** Price per generation (regardless of length) in USD */\n perGeneration?: number;\n}\n\n/**\n * Pricing for audio models (TTS, STT, generation)\n */\nexport interface AudioPricing {\n type: \"audio\";\n /** Price per minute of audio in USD */\n perMinute?: number;\n /** Price per character in USD (for TTS) */\n perCharacter?: number;\n /** Price per second of audio in USD */\n perSecond?: number;\n}\n\n/**\n * Pricing for embedding models\n */\nexport interface EmbeddingPricing {\n type: \"embedding\";\n /** Price per 1M tokens in USD */\n per1mTokens: number;\n}\n\n/**\n * Union type for all pricing structures\n */\nexport type Pricing =\n | TextPricing\n | ImagePricing\n | VideoPricing\n | AudioPricing\n | EmbeddingPricing;\n\n// =============================================================================\n// MODEL CATALOG TYPES\n// =============================================================================\n\n/**\n * A model entry in the catalog\n *\n * This is the unified format that all catalog sources (OpenRouter, fal.ai, Replicate)\n * are normalized to.\n */\nexport interface ModelEntry {\n /** Unique identifier with source prefix (e.g., \"openrouter::anthropic/claude-sonnet-4\") */\n id: string;\n\n /** Source catalog (e.g., \"openrouter\", \"fal\", \"replicate\") */\n source: string;\n\n /** Human-readable model name (e.g., \"Claude Sonnet 4\") */\n name: string;\n\n /** Primary modality of this model */\n modality: Modality;\n\n /** Input modalities supported (e.g., [\"text\"], [\"text\", \"image\"]) */\n inputModalities: string[];\n\n /** Output modalities supported (e.g., [\"text\"], [\"image\"]) */\n outputModalities: string[];\n\n /** Pricing information (structure varies by modality) */\n pricing: Pricing;\n\n /** Maximum context length in tokens (text/vision models only) */\n contextLength?: number;\n\n /** Maximum output resolution (image/video models, e.g., \"1024x1024\") */\n maxResolution?: string;\n\n /** Maximum duration in seconds (video/audio models) */\n maxDuration?: number;\n\n /** Whether the model supports streaming output */\n supportsStreaming?: boolean;\n\n /** Provider name (e.g., \"anthropic\", \"openai\", \"stability\") */\n provider: string;\n\n /** Model family (e.g., \"claude\", \"gpt\", \"flux\", \"llama\") */\n family: string;\n}\n\n/**\n * Compressed model entry for LLM context\n *\n * Stripped-down version of ModelEntry to minimize token usage when\n * sending the catalog to the recommender LLM.\n */\nexport interface CompressedModel {\n /** Full model ID */\n id: string;\n\n /** Human-readable name */\n name: string;\n\n /** Primary modality */\n modality: string;\n\n /** Flattened pricing (key-value pairs only, no \"type\" field) */\n pricing: Record<string, number>;\n\n /** Context length if applicable */\n contextLength?: number;\n\n /** Max resolution if applicable */\n maxResolution?: string;\n\n /** Max duration if applicable */\n maxDuration?: number;\n}\n\n// =============================================================================\n// RECOMMENDATION TYPES\n// =============================================================================\n\n/**\n * A single model recommendation\n */\nexport interface ModelPick {\n /** Model ID (e.g., \"openrouter::anthropic/claude-sonnet-4\") */\n id: string;\n\n /** Human-readable justification for this recommendation */\n reason: string;\n\n /** Human-readable pricing summary */\n pricingSummary: string;\n\n /** Estimated cost for a reasonable workload */\n estimatedCost: string;\n}\n\n/**\n * Task analysis performed by the recommender LLM\n */\nexport interface TaskAnalysis {\n /** One-line summary of what the task demands */\n summary: string;\n\n /** Detected modality for this task */\n detectedModality: Modality;\n\n /** Explanation of why this modality was chosen */\n modalityReasoning: string;\n\n /** Key requirements extracted from the task */\n keyRequirements: string[];\n\n /** Description of what drives cost for this specific task */\n costFactors: string;\n}\n\n/**\n * Complete recommendation response\n */\nexport interface Recommendation {\n /** Analysis of the task */\n taskAnalysis: TaskAnalysis;\n\n /** Three-tier recommendations */\n recommendations: {\n /** Cheapest viable option */\n cheapest: ModelPick;\n /** Best quality-to-price ratio */\n balanced: ModelPick;\n /** Highest quality regardless of cost */\n best: ModelPick;\n };\n\n /** Note about alternative approaches in other modalities (if applicable) */\n alternativesInOtherModalities: string | null;\n}\n\n/**\n * Metadata included in JSON output\n */\nexport interface RecommendationMeta {\n /** Model used for generating the recommendation */\n recommenderModel: string;\n\n /** Cost of this recommendation call in USD */\n recommendationCostUsd: number;\n\n /** Number of prompt tokens used */\n promptTokens?: number;\n\n /** Number of completion tokens used */\n completionTokens?: number;\n\n /** Recommender runtime in milliseconds */\n recommendationLatencyMs?: number;\n\n /** Catalog sources that were queried */\n catalogSources: string[];\n\n /** Total models in the catalog */\n catalogTotalModels: number;\n\n /** Models in the detected modality */\n catalogModelsInModality: number;\n\n /** ISO timestamp of the recommendation */\n timestamp: string;\n\n /** Tool version */\n version: string;\n}\n\n/**\n * Full JSON output structure\n */\nexport interface JSONOutput {\n /** Original task description */\n task: string;\n\n /** Task analysis */\n taskAnalysis: TaskAnalysis;\n\n /** Recommendations */\n recommendations: {\n cheapest: ModelPick;\n balanced: ModelPick;\n best: ModelPick;\n };\n\n /** Alternative approaches note */\n alternativesInOtherModalities: string | null;\n\n /** Metadata about the recommendation */\n meta: RecommendationMeta;\n}\n\n// =============================================================================\n// CONFIGURATION TYPES\n// =============================================================================\n\n/**\n * Application configuration\n */\nexport interface Config {\n /** OpenRouter API key (required for recommendation/comparison LLM calls) */\n apiKey: string;\n\n /** Model to use for recommendations */\n recommenderModel: string;\n\n /** Cache TTL in seconds */\n cacheTtl: number;\n\n /** fal.ai API key (optional, enables image/video catalog) */\n falApiKey?: string;\n\n /** Replicate API token (optional, enables broader catalog) */\n replicateApiToken?: string;\n\n /** ElevenLabs API key (optional, enables audio catalog) */\n elevenLabsApiKey?: string;\n\n /** Together AI API key (optional) */\n togetherApiKey?: string;\n\n /** Freshness TTL for Replicate page-pricing entries in seconds */\n replicatePriceTtlSeconds?: number;\n\n /** Maximum allowed staleness window for Replicate page-pricing entries in seconds */\n replicatePriceMaxStaleSeconds?: number;\n\n /** Max number of Replicate page-pricing lookups allowed per run */\n replicatePriceFetchBudget?: number;\n\n /** Max concurrent Replicate page-pricing lookups per run */\n replicatePriceConcurrency?: number;\n}\n\n/**\n * Constraints for filtering models\n */\nexport interface Constraints {\n /** Maximum price per unit in USD */\n maxPrice?: number;\n\n /** Minimum context length in tokens */\n minContext?: number;\n\n /** Minimum resolution (e.g., \"1024x1024\") */\n minResolution?: string;\n\n /** Force a specific modality */\n modality?: Modality;\n\n /** Model IDs to exclude (supports wildcards like \"openai/*\") */\n exclude?: string[];\n\n /** Catalog sources to use */\n sources?: string[];\n}\n\n// =============================================================================\n// CLI TYPES\n// =============================================================================\n\n/**\n * Parsed CLI options\n */\nexport interface CLIOptions {\n /** Output as JSON instead of formatted terminal output */\n json: boolean;\n\n /** Force a specific modality */\n modality?: Modality;\n\n /** Override the recommender model */\n model?: string;\n\n /** Maximum price per unit */\n maxPrice?: number;\n\n /** Minimum context length */\n minContext?: number;\n\n /** Minimum resolution */\n minResolution?: string;\n\n /** Model IDs to exclude */\n exclude?: string;\n\n /** Catalog sources to use */\n sources?: string;\n\n /** Workload description for cost estimation */\n estimate?: string;\n\n /** Show detailed/verbose output */\n verbose: boolean;\n\n /** Disable colored output */\n noColor: boolean;\n}\n\n// =============================================================================\n// CATALOG SOURCE TYPES\n// =============================================================================\n\n/**\n * Interface for a catalog source adapter\n *\n * Each catalog source (OpenRouter, fal.ai, Replicate) implements this interface\n * to fetch and normalize models.\n */\nexport interface CatalogSource {\n /** Unique identifier for this source (e.g., \"openrouter\", \"fal\") */\n readonly sourceId: string;\n\n /**\n * Fetch models from this source\n * @returns Array of normalized model entries\n */\n fetch(): Promise<ModelEntry[]>;\n}\n\n/**\n * Result of validating a recommendation\n */\nexport interface ValidationResult {\n /** Whether all recommended model IDs are valid */\n valid: boolean;\n\n /** List of invalid model IDs (if any) */\n invalidIds: string[];\n}\n\n// =============================================================================\n// ERROR TYPES\n// =============================================================================\n\n/**\n * Error codes used in the application\n */\nexport enum ExitCode {\n SUCCESS = 0,\n GENERAL_ERROR = 1,\n INVALID_ARGUMENTS = 2,\n NO_API_KEY = 3,\n NO_MODELS_FOUND = 4,\n LLM_FAILED = 5,\n NETWORK_ERROR = 6,\n}\n\n/**\n * Custom error class for whichmodel errors\n */\nexport class WhichModelError extends Error {\n constructor(\n message: string,\n public readonly exitCode: ExitCode,\n public readonly recoveryHint?: string\n ) {\n super(message);\n this.name = \"WhichModelError\";\n }\n}\n\n// =============================================================================\n// CACHE TYPES\n// =============================================================================\n\n/**\n * Cache entry structure\n */\nexport interface CacheEntry<T> {\n /** Cached data */\n data: T;\n\n /** Timestamp when cached (Unix epoch in seconds) */\n timestamp: number;\n\n /** TTL in seconds */\n ttl: number;\n\n /** Source that generated this data */\n source: string;\n}\n\n/**\n * Cache statistics for a single source\n */\nexport interface CacheSourceStats {\n /** Source name (e.g., \"openrouter\", \"fal\") */\n name: string;\n\n /** Timestamp when cached (Unix epoch in seconds) */\n timestamp: number;\n\n /** TTL in seconds */\n ttl: number;\n\n /** Number of models in cached data */\n modelCount: number;\n\n /** Human-readable age (e.g., \"45m ago\") */\n age: string;\n\n /** Whether the cache is stale (past TTL) */\n isStale: boolean;\n}\n\n/**\n * Cache statistics for all sources\n */\nexport interface CacheStats {\n /** Cache directory path */\n location: string;\n\n /** Statistics per source */\n sources: CacheSourceStats[];\n}\n\nexport type ReplicatePricingSource = \"billingConfig\" | \"price-string\";\n\nexport interface ReplicatePricingEntry {\n /** Normalized Replicate pricing payload merged into raw model.pricing */\n pricing: Record<string, number>;\n\n /** Where the pricing payload came from on the Replicate model page */\n source: ReplicatePricingSource;\n\n /** Timestamp when this entry was fetched (Unix epoch in seconds) */\n fetchedAt: number;\n\n /** Timestamp when this entry expires (Unix epoch in seconds) */\n expiresAt: number;\n}\n\nexport interface ReplicatePricingCacheFile {\n /** Cache schema version */\n version: 1;\n\n /** Last cache write time (Unix epoch in seconds) */\n updatedAt: number;\n\n /** Per-model pricing entries keyed by owner/name */\n entries: Record<string, ReplicatePricingEntry>;\n}\n\n// =============================================================================\n// API RESPONSE TYPES (Raw)\n// =============================================================================\n\n/**\n * Raw OpenRouter model from API response\n * Used for normalization, not exposed to the rest of the application\n */\nexport interface OpenRouterModel {\n id: string;\n name: string;\n description?: string;\n context_length: number;\n pricing: {\n prompt: string;\n completion: string;\n image?: string;\n request?: string;\n };\n architecture?: {\n modality?: string | null;\n tokenizer?: string | null;\n instruct_type?: string | null;\n input_modalities?: string[] | null;\n output_modalities?: string[] | null;\n } | null;\n top_provider?: {\n context_length?: number | null;\n max_completion_tokens?: number | null;\n is_moderated?: boolean | null;\n } | null;\n per_request_limits?: {\n prompt_tokens?: number | null;\n completion_tokens?: number | null;\n } | null;\n}\n\n/**\n * OpenRouter API response structure\n */\nexport interface OpenRouterResponse {\n data: OpenRouterModel[];\n}\n\n/**\n * OpenRouter chat completion request\n */\nexport interface OpenRouterChatRequest {\n model: string;\n messages: Array<{\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n }>;\n response_format?: { type: \"json_object\" };\n temperature?: number;\n max_tokens?: number;\n}\n\n/**\n * OpenRouter chat completion response\n */\nexport interface OpenRouterChatResponse {\n id: string;\n choices: Array<{\n index: number;\n message: {\n role: string;\n content: string;\n };\n finish_reason: string;\n }>;\n usage?: {\n prompt_tokens: number;\n completion_tokens: number;\n total_tokens: number;\n };\n model: string;\n}\n\n/**\n * Raw fal.ai model from API response\n */\nexport interface FalModel {\n id: string;\n name: string;\n description?: string;\n category: string;\n pricing?: {\n type: string;\n amount: number;\n };\n inputs?: Record<\n string,\n {\n type: string;\n description?: string;\n default?: unknown;\n }\n >;\n outputs?: Record<\n string,\n {\n type: string;\n description?: string;\n }\n >;\n}\n\n/**\n * fal.ai API response structure\n */\nexport type FalResponse =\n | FalModel[]\n | {\n models?: FalModel[];\n data?: FalModel[];\n };\n\n/**\n * Raw Replicate model from API response\n */\nexport interface ReplicateModel {\n url?: string;\n owner: string;\n name: string;\n description?: string | null;\n visibility?: \"public\" | \"private\";\n run_count?: number;\n latest_version?: {\n id?: string;\n created_at?: string;\n openapi_schema?: unknown;\n pricing?: unknown;\n [key: string]: unknown;\n } | null;\n pricing?: unknown;\n [key: string]: unknown;\n}\n\n/**\n * Replicate paginated models response\n */\nexport interface ReplicateModelsResponse {\n next?: string | null;\n previous?: string | null;\n results?: ReplicateModel[];\n}\n","import { ExitCode, WhichModelError } from \"../types.js\";\n\nexport const VALID_SOURCES = [\n \"openrouter\",\n \"fal\",\n \"replicate\",\n \"elevenlabs\",\n \"together\",\n] as const;\n\nexport const SUPPORTED_SOURCES = [\"openrouter\", \"fal\", \"replicate\"] as const;\n\nconst VALID_SOURCE_SET = new Set<string>(VALID_SOURCES);\nconst SUPPORTED_SOURCE_SET = new Set<string>(SUPPORTED_SOURCES);\n\nexport function parseSourcesCsv(sourcesArg?: string): string[] {\n if (!sourcesArg) {\n return [\"openrouter\"];\n }\n\n const sources = sourcesArg\n .split(\",\")\n .map((item) => item.trim().toLowerCase())\n .filter(Boolean);\n\n const normalized = sources.length > 0 ? sources : [\"openrouter\"];\n const invalid = normalized.filter((source) => !VALID_SOURCE_SET.has(source));\n if (invalid.length > 0) {\n throw new WhichModelError(\n `Invalid source value(s): ${invalid.join(\", \")}.`,\n ExitCode.INVALID_ARGUMENTS,\n `Valid sources: ${VALID_SOURCES.join(\", \")}`\n );\n }\n\n return normalized;\n}\n\nexport function validateSupportedSourcesList(sources: string[]): void {\n const unsupported = sources.filter((source) => !SUPPORTED_SOURCE_SET.has(source));\n if (unsupported.length === 0) {\n return;\n }\n\n throw new WhichModelError(\n `Source(s) not yet supported: ${unsupported.join(\", \")}.`,\n ExitCode.INVALID_ARGUMENTS,\n `Use --sources ${SUPPORTED_SOURCES.join(\",\")}`\n );\n}\n","/**\n * Stats command implementation\n *\n * Shows catalog statistics including model counts by modality,\n * price ranges, and configured/missing sources.\n *\n * @module commands/stats\n */\n\nimport chalk, { Chalk } from \"chalk\";\nimport type { Config, ModelEntry, Modality } from \"../types.js\";\nimport { renderBox } from \"../formatter/box.js\";\nimport { getModelPrimaryPrice, hasUsablePrice } from \"../model-pricing.js\";\n\nexport interface ModalityStats {\n count: number;\n pricedCount: number;\n priceRange: {\n min: number;\n max: number;\n };\n}\n\nexport interface CatalogStats {\n totalModels: number;\n queriedSources?: string[];\n sources: string[];\n byModality: Record<string, ModalityStats>;\n configuredSources: string[];\n missingSources: Array<{\n name: string;\n envVar: string;\n getUrl: string;\n }>;\n}\n\nconst MODALITY_ORDER: Modality[] = [\n \"text\",\n \"image\",\n \"video\",\n \"audio_tts\",\n \"audio_stt\",\n \"audio_generation\",\n \"vision\",\n \"embedding\",\n \"multimodal\",\n];\n\nconst MODALITY_LABELS: Record<Modality, string> = {\n text: \"Text\",\n image: \"Image\",\n video: \"Video\",\n audio_tts: \"Audio (TTS)\",\n audio_stt: \"Audio (STT)\",\n audio_generation: \"Audio (Gen)\",\n vision: \"Vision\",\n embedding: \"Embedding\",\n multimodal: \"Multimodal\",\n};\n\nconst DEFAULT_TERMINAL_COLUMNS = 80;\nconst MIN_CONTENT_WIDTH = 72;\n\n/**\n * Format a price for display\n */\nfunction formatPrice(price: number): string {\n if (!Number.isFinite(price) || price === Number.POSITIVE_INFINITY) {\n return \"N/A\";\n }\n if (price < 0.01) {\n return `$${price.toFixed(4)}`;\n }\n if (price < 1) {\n return `$${price.toFixed(3)}`;\n }\n return `$${price.toFixed(2)}`;\n}\n\n/**\n * Get the price unit for a modality\n */\nfunction getPriceUnit(modality: Modality): string {\n switch (modality) {\n case \"text\":\n case \"embedding\":\n return \"/ 1M tokens\";\n case \"image\":\n return \"/ image\";\n case \"video\":\n return \"/ second\";\n case \"audio_tts\":\n case \"audio_stt\":\n case \"audio_generation\":\n return \"/ minute\";\n case \"vision\":\n case \"multimodal\":\n return \"varies\";\n default:\n return \"\";\n }\n}\n\n/**\n * Compute statistics from a list of models\n */\nexport function computeStats(\n models: ModelEntry[],\n config: Config,\n queriedSources?: string[]\n): CatalogStats {\n const byModality: Record<string, ModalityStats> = {};\n const sources = new Set<string>();\n let totalModels = 0;\n\n for (const model of models) {\n totalModels += 1;\n\n sources.add(model.source);\n\n const modality = model.modality;\n if (!byModality[modality]) {\n byModality[modality] = {\n count: 0,\n pricedCount: 0,\n priceRange: { min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY },\n };\n }\n\n byModality[modality].count++;\n\n if (hasUsablePrice(model)) {\n byModality[modality].pricedCount++;\n const price = getModelPrimaryPrice(model);\n if (Number.isFinite(price)) {\n byModality[modality].priceRange.min = Math.min(byModality[modality].priceRange.min, price);\n byModality[modality].priceRange.max = Math.max(byModality[modality].priceRange.max, price);\n }\n }\n }\n\n // Determine configured and missing sources\n const configuredSources: string[] = [];\n const missingSources: CatalogStats[\"missingSources\"] = [];\n\n configuredSources.push(\"openrouter\");\n\n if (config.falApiKey) {\n configuredSources.push(\"fal\");\n } else {\n missingSources.push({\n name: \"fal\",\n envVar: \"FAL_API_KEY\",\n getUrl: \"https://fal.ai/dashboard/keys\",\n });\n }\n\n if (config.replicateApiToken) {\n configuredSources.push(\"replicate\");\n } else {\n missingSources.push({\n name: \"replicate\",\n envVar: \"REPLICATE_API_TOKEN\",\n getUrl: \"https://replicate.com/account/api-tokens\",\n });\n }\n\n if (config.elevenLabsApiKey) {\n configuredSources.push(\"elevenlabs\");\n } else {\n missingSources.push({\n name: \"elevenlabs\",\n envVar: \"ELEVENLABS_API_KEY\",\n getUrl: \"https://elevenlabs.io/app/settings/api-keys\",\n });\n }\n\n if (config.togetherApiKey) {\n configuredSources.push(\"together\");\n } else {\n missingSources.push({\n name: \"together\",\n envVar: \"TOGETHER_API_KEY\",\n getUrl: \"https://api.together.xyz/settings/api-keys\",\n });\n }\n\n return {\n totalModels,\n queriedSources,\n sources: Array.from(sources).sort(),\n byModality,\n configuredSources,\n missingSources,\n };\n}\n\nfunction getMaxContentWidth(): number {\n const columns = process.stdout?.columns;\n if (typeof columns !== \"number\" || !Number.isFinite(columns) || columns <= 0) {\n return DEFAULT_TERMINAL_COLUMNS - 8;\n }\n return Math.max(MIN_CONTENT_WIDTH, columns - 8);\n}\n\nfunction truncateCell(value: string, width: number): string {\n if (value.length <= width) {\n return value;\n }\n if (width <= 3) {\n return value.slice(0, width);\n }\n return `${value.slice(0, width - 3)}...`;\n}\n\nfunction buildSeparator(\n left: string,\n middle: string,\n right: string,\n widths: number[]\n): string {\n return `${left}${widths.map((width) => \"─\".repeat(width + 2)).join(middle)}${right}`;\n}\n\nfunction buildRow(cells: string[], widths: number[]): string {\n return `│ ${cells\n .map((cell, index) => {\n const width = widths[index] ?? 0;\n return truncateCell(cell, width).padEnd(width);\n })\n .join(\" │ \")} │`;\n}\n\n/**\n * Format stats for terminal output\n */\nexport function formatStatsTerminal(stats: CatalogStats, noColor: boolean = false): string {\n const c = noColor ? new Chalk({ level: 0 }) : chalk;\n const lines: string[] = [];\n const queriedSourceCount = stats.queriedSources?.length ?? stats.sources.length;\n if (queriedSourceCount !== stats.sources.length) {\n lines.push(\n `Catalog: ${c.bold(stats.totalModels.toString())} models from ${c.bold(\n queriedSourceCount.toString()\n )} queried source${queriedSourceCount !== 1 ? \"s\" : \"\"} (${c.bold(\n stats.sources.length.toString()\n )} with priced models)`\n );\n } else {\n lines.push(\n `Catalog: ${c.bold(stats.totalModels.toString())} models from ${c.bold(\n stats.sources.length.toString()\n )} source${stats.sources.length !== 1 ? \"s\" : \"\"}`\n );\n }\n lines.push(\"\");\n const rows = MODALITY_ORDER.map((modality) => {\n const label = MODALITY_LABELS[modality];\n const modStats = stats.byModality[modality];\n let priceRange = \"N/A\";\n if (modStats && modStats.pricedCount > 0) {\n const unit = getPriceUnit(modality);\n const min = formatPrice(modStats.priceRange.min);\n const max = formatPrice(modStats.priceRange.max);\n if (min === \"N/A\" || max === \"N/A\") {\n priceRange = \"N/A\";\n } else if (min === max) {\n priceRange = `${min} ${unit}`;\n } else {\n priceRange = `${min} - ${max} ${unit}`;\n }\n }\n return {\n label,\n count: (modStats?.count ?? 0).toString(),\n priceRange,\n };\n });\n\n let labelWidth = Math.max(\"Modality\".length, ...rows.map((row) => row.label.length));\n let countWidth = Math.max(\"Count\".length, ...rows.map((row) => row.count.length));\n let priceWidth = Math.max(\"Price Range\".length, ...rows.map((row) => row.priceRange.length));\n const widths: [number, number, number] = [labelWidth, countWidth, priceWidth];\n const tableWidth = (): number => widths.reduce((sum, width) => sum + width, 0) + 10;\n const maxContentWidth = getMaxContentWidth();\n const minimums: [number, number, number] = [8, 5, 12];\n\n let overflow = tableWidth() - maxContentWidth;\n if (overflow > 0) {\n const shrinkOrder: Array<0 | 1 | 2> = [2, 0];\n for (const index of shrinkOrder) {\n if (overflow <= 0) {\n break;\n }\n const reducible = widths[index] - minimums[index];\n if (reducible <= 0) {\n continue;\n }\n const reduction = Math.min(reducible, overflow);\n widths[index] -= reduction;\n overflow -= reduction;\n }\n }\n [labelWidth, countWidth, priceWidth] = widths;\n const finalWidths = [labelWidth, countWidth, priceWidth];\n\n lines.push(buildSeparator(\"┌\", \"┬\", \"┐\", finalWidths));\n lines.push(buildRow([\"Modality\", \"Count\", \"Price Range\"], finalWidths));\n lines.push(buildSeparator(\"├\", \"┼\", \"┤\", finalWidths));\n\n for (const row of rows) {\n lines.push(buildRow([row.label, row.count, row.priceRange], finalWidths));\n }\n\n lines.push(buildSeparator(\"└\", \"┴\", \"┘\", finalWidths));\n lines.push(\"\");\n\n // Sources section\n if (stats.configuredSources.length > 0) {\n lines.push(`Sources configured: ${c.green(stats.configuredSources.join(\", \"))}`);\n }\n\n if (stats.missingSources.length > 0) {\n const missing = stats.missingSources\n .map((s) => `${s.name} (${c.dim(`set ${s.envVar}`)})`)\n .join(\", \");\n lines.push(`Missing sources: ${c.yellow(missing)}`);\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Stats\",\n noColor,\n borderColor: \"blue\",\n });\n}\n\n/**\n * Format stats for JSON output\n */\nexport function formatStatsJSON(stats: CatalogStats): object {\n return {\n totalModels: stats.totalModels,\n queriedSources: stats.queriedSources ?? null,\n sources: stats.sources,\n byModality: Object.fromEntries(\n Object.entries(stats.byModality).map(([modality, modStats]) => [\n modality,\n {\n count: modStats.count,\n pricedCount: modStats.pricedCount,\n priceRange: {\n min: Number.isFinite(modStats.priceRange.min) ? modStats.priceRange.min : null,\n max: Number.isFinite(modStats.priceRange.max) ? modStats.priceRange.max : null,\n },\n },\n ])\n ),\n configuredSources: stats.configuredSources,\n missingSources: stats.missingSources,\n };\n}\n","import type { ModelEntry, Pricing } from \"./types.js\";\n\nfunction toNonNegativeFinite(value: number | undefined): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value < 0) {\n return undefined;\n }\n\n return value;\n}\n\nfunction firstDefined(values: Array<number | undefined>): number | undefined {\n for (const value of values) {\n if (typeof value === \"number\") {\n return value;\n }\n }\n\n return undefined;\n}\n\nexport function getPrimaryPriceFromPricing(pricing: Pricing): number {\n const price = (() => {\n switch (pricing.type) {\n case \"text\":\n return toNonNegativeFinite(pricing.promptPer1mTokens);\n case \"image\":\n return firstDefined([\n toNonNegativeFinite(pricing.perImage),\n toNonNegativeFinite(pricing.perMegapixel),\n toNonNegativeFinite(pricing.perStep),\n ]);\n case \"video\":\n return firstDefined([\n toNonNegativeFinite(pricing.perSecond),\n toNonNegativeFinite(pricing.perGeneration),\n ]);\n case \"audio\":\n return firstDefined([\n toNonNegativeFinite(pricing.perMinute),\n toNonNegativeFinite(pricing.perCharacter),\n toNonNegativeFinite(pricing.perSecond),\n ]);\n case \"embedding\":\n return toNonNegativeFinite(pricing.per1mTokens);\n default:\n return undefined;\n }\n })();\n\n return typeof price === \"number\" ? price : Number.POSITIVE_INFINITY;\n}\n\nexport function getModelPrimaryPrice(model: Pick<ModelEntry, \"pricing\">): number {\n return getPrimaryPriceFromPricing(model.pricing);\n}\n\nexport function hasUsablePrice(model: Pick<ModelEntry, \"pricing\">): boolean {\n return Number.isFinite(getModelPrimaryPrice(model));\n}\n","/**\n * List command implementation\n *\n * Lists available models with filtering and sorting options.\n *\n * @module commands/list\n */\n\nimport chalk, { Chalk } from \"chalk\";\nimport type { Modality, ModelEntry } from \"../types.js\";\nimport { renderBox } from \"../formatter/box.js\";\nimport { getModelPrimaryPrice } from \"../model-pricing.js\";\n\nexport interface ListOptions {\n modality?: Modality;\n source?: string;\n sort: \"price\" | \"name\" | \"context\";\n limit: number;\n}\n\nexport interface ModelListItem {\n id: string;\n name: string;\n pricing: string;\n context?: number;\n modality: string;\n source: string;\n}\n\nconst DEFAULT_TERMINAL_COLUMNS = 80;\nconst MIN_CONTENT_WIDTH = 72;\n\nfunction getMaxContentWidth(): number {\n const columns = process.stdout?.columns;\n if (typeof columns !== \"number\" || !Number.isFinite(columns) || columns <= 0) {\n return DEFAULT_TERMINAL_COLUMNS - 8;\n }\n return Math.max(MIN_CONTENT_WIDTH, columns - 8);\n}\n\nfunction truncateCell(value: string, width: number): string {\n if (value.length <= width) {\n return value;\n }\n if (width <= 3) {\n return value.slice(0, width);\n }\n return `${value.slice(0, width - 3)}...`;\n}\n\nfunction fitCell(value: string, width: number): string {\n return truncateCell(value, width).padEnd(width);\n}\n\nfunction buildSeparator(\n left: string,\n middle: string,\n right: string,\n widths: number[]\n): string {\n return `${left}${widths.map((width) => \"─\".repeat(width + 2)).join(middle)}${right}`;\n}\n\n/**\n * Get the primary price for a model based on its modality\n */\n/**\n * Format pricing for display\n */\nfunction formatPricing(model: ModelEntry): string {\n const pricing = model.pricing;\n\n switch (pricing.type) {\n case \"text\":\n return `$${pricing.promptPer1mTokens.toFixed(2)} / $${pricing.completionPer1mTokens.toFixed(2)}`;\n case \"image\":\n if (pricing.perImage) {\n return `$${pricing.perImage.toFixed(3)} / image`;\n }\n if (pricing.perMegapixel) {\n return `$${pricing.perMegapixel.toFixed(3)} / MP`;\n }\n return \"N/A\";\n case \"video\":\n if (pricing.perSecond) {\n return `$${pricing.perSecond.toFixed(3)} / sec`;\n }\n if (pricing.perGeneration) {\n return `$${pricing.perGeneration.toFixed(2)} / gen`;\n }\n return \"N/A\";\n case \"audio\":\n if (pricing.perMinute) {\n return `$${pricing.perMinute.toFixed(3)} / min`;\n }\n if (pricing.perCharacter) {\n return `$${pricing.perCharacter.toFixed(6)} / char`;\n }\n if (pricing.perSecond) {\n return `$${pricing.perSecond.toFixed(4)} / sec`;\n }\n return \"N/A\";\n case \"embedding\":\n return `$${pricing.per1mTokens.toFixed(3)} / 1M`;\n default:\n return \"N/A\";\n }\n}\n\n/**\n * Format context length for display\n */\nfunction formatContext(context?: number): string {\n if (!context) return \"-\";\n if (context >= 1_000_000) {\n return `${(context / 1_000_000).toFixed(1)}M`;\n }\n if (context >= 1000) {\n return `${Math.round(context / 1000)}K`;\n }\n return context.toString();\n}\n\n/**\n * Filter and sort models based on options\n */\nexport function filterAndSortModels(models: ModelEntry[], options: ListOptions): ModelListItem[] {\n let filtered = [...models];\n\n // Filter by modality\n if (options.modality) {\n filtered = filtered.filter((m) => m.modality === options.modality);\n }\n\n // Filter by source\n if (options.source) {\n filtered = filtered.filter((m) => m.source === options.source);\n }\n\n // Sort\n filtered.sort((a, b) => {\n switch (options.sort) {\n case \"price\": {\n const priceA = getModelPrimaryPrice(a);\n const priceB = getModelPrimaryPrice(b);\n const pricedA = Number.isFinite(priceA);\n const pricedB = Number.isFinite(priceB);\n if (pricedA !== pricedB) {\n return pricedA ? -1 : 1;\n }\n if (!pricedA && !pricedB) {\n return a.name.localeCompare(b.name);\n }\n return priceA - priceB;\n }\n case \"name\":\n return a.name.localeCompare(b.name);\n case \"context\": {\n const ctxA = a.contextLength ?? 0;\n const ctxB = b.contextLength ?? 0;\n return ctxB - ctxA; // Higher context first\n }\n default:\n return 0;\n }\n });\n\n // Limit\n filtered = filtered.slice(0, options.limit);\n\n return filtered.map((m) => ({\n id: m.id,\n name: m.name,\n pricing: formatPricing(m),\n context: m.contextLength,\n modality: m.modality,\n source: m.source,\n }));\n}\n\n/**\n * Format list for terminal output\n */\nexport function formatListTerminal(\n items: ModelListItem[],\n total: number,\n options: ListOptions,\n noColor: boolean = false\n): string {\n const c = noColor ? new Chalk({ level: 0 }) : chalk;\n const lines: string[] = [];\n\n // Header\n const showingText = options.limit < total ? `(showing top ${options.limit}` : \"\";\n const filterText = options.modality ? `${options.modality} models` : \"models\";\n const sortText = `sorted by ${options.sort})`;\n\n if (showingText) {\n lines.push(c.dim(`${total} ${filterText} ${showingText}, ${sortText}`));\n } else {\n lines.push(c.dim(`${total} ${filterText} (${sortText})`));\n }\n lines.push(\"\");\n\n if (items.length === 0) {\n lines.push(\"No models found matching the criteria.\");\n return renderBox(lines.join(\"\\n\"), {\n title: \"Models\",\n noColor,\n borderColor: \"green\",\n });\n }\n\n // Calculate and fit column widths to terminal content width\n const widths: [number, number, number, number, number] = [\n Math.max(10, \"ID\".length, ...items.map((item) => item.id.length)),\n Math.max(10, \"Name\".length, ...items.map((item) => item.name.length)),\n Math.max(16, \"Pricing\".length, ...items.map((item) => item.pricing.length)),\n Math.max(7, \"Context\".length),\n Math.max(6, \"Source\".length, ...items.map((item) => item.source.length)),\n ];\n const maxWidths: [number, number, number, number, number] = [56, 28, 24, 8, 12];\n for (const index of [0, 1, 2, 3, 4] as const) {\n widths[index] = Math.min(widths[index], maxWidths[index]);\n }\n const minWidths: [number, number, number, number, number] = [18, 12, 12, 7, 6];\n const tableWidth = (): number => widths.reduce((sum, width) => sum + width, 0) + 16;\n const maxContentWidth = getMaxContentWidth();\n\n let overflow = tableWidth() - maxContentWidth;\n if (overflow > 0) {\n const shrinkOrder: Array<0 | 1 | 2 | 3 | 4> = [0, 1, 2, 4, 3];\n for (const columnIndex of shrinkOrder) {\n if (overflow <= 0) {\n break;\n }\n const reducible = widths[columnIndex] - minWidths[columnIndex];\n if (reducible <= 0) {\n continue;\n }\n const reduction = Math.min(reducible, overflow);\n widths[columnIndex] -= reduction;\n overflow -= reduction;\n }\n }\n const [idWidth, nameWidth, pricingWidth, contextWidth, sourceWidth] = widths;\n\n lines.push(buildSeparator(\"┌\", \"┬\", \"┐\", widths));\n lines.push(\n `│ ${c.bold(fitCell(\"ID\", idWidth))} │ ${c.bold(fitCell(\"Name\", nameWidth))} │ ${c.bold(\n fitCell(\"Pricing\", pricingWidth)\n )} │ ${c.bold(fitCell(\"Context\", contextWidth))} │ ${c.bold(fitCell(\"Source\", sourceWidth))} │`\n );\n lines.push(buildSeparator(\"├\", \"┼\", \"┤\", widths));\n\n // Table rows\n for (const item of items) {\n lines.push(\n `│ ${c.cyan(fitCell(item.id, idWidth))} │ ${fitCell(item.name, nameWidth)} │ ${fitCell(\n item.pricing,\n pricingWidth\n )} │ ${fitCell(formatContext(item.context), contextWidth)} │ ${fitCell(item.source, sourceWidth)} │`\n );\n }\n\n lines.push(buildSeparator(\"└\", \"┴\", \"┘\", widths));\n\n // Footer hint\n if (options.limit < total) {\n lines.push(\"\");\n lines.push(c.dim(`Use --limit ${total} to show all, or filter with --modality, --source`));\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Models\",\n noColor,\n borderColor: \"green\",\n });\n}\n\n/**\n * Format list for JSON output\n */\nexport function formatListJSON(items: ModelListItem[]): object {\n return {\n models: items.map((item) => ({\n id: item.id,\n name: item.name,\n pricing: item.pricing,\n context: item.context ?? null,\n modality: item.modality,\n source: item.source,\n })),\n count: items.length,\n };\n}\n","/**\n * Cost estimation module\n *\n * Parses workload descriptions and calculates estimated costs for models.\n *\n * @module estimation/cost-calculator\n */\n\nimport type { ModelEntry, TextPricing, ImagePricing, VideoPricing, AudioPricing, Modality } from \"../types.js\";\n\nexport interface WorkloadSpec {\n quantity: number;\n unit: \"requests\" | \"images\" | \"minutes\" | \"seconds\" | \"tokens\";\n period: \"day\" | \"week\" | \"month\";\n parameters?: {\n resolution?: string;\n duration?: number;\n tokensPerRequest?: number;\n };\n}\n\nexport interface CostEstimate {\n monthlyUnits: number;\n costPerUnit: number;\n monthlyCost: number;\n yearlyCost: number;\n breakdown: string;\n}\n\n// Period multipliers to convert to monthly\nconst PERIOD_MULTIPLIERS: Record<string, number> = {\n day: 30,\n week: 4.33,\n month: 1,\n};\n\n// Default assumptions for estimation\nconst DEFAULT_TOKENS_PER_REQUEST = 2000; // Assume 2K tokens per request for text tasks\n\n/**\n * Parse a workload description string into a structured spec\n *\n * Supports formats like:\n * - \"500 images/month at 1024x1024\"\n * - \"1000 requests per day\"\n * - \"10000 tokens/week\"\n * - \"500 images per month\"\n */\nexport function parseWorkloadDescription(description: string): WorkloadSpec {\n const normalized = description.toLowerCase().trim();\n\n // Extract quantity\n const quantityMatch = normalized.match(/(\\d+(?:[.,]\\d+)?)\\s*(?:k|thousand|m|million)?/i);\n if (!quantityMatch) {\n throw new Error(`Could not parse quantity from workload description: \"${description}\"`);\n }\n let quantity = parseFloat(quantityMatch[1]!.replace(\",\", \"\"));\n\n // Handle k/m suffixes\n if (/\\d+k\\b/i.test(normalized) || /\\d+\\s*thousand/i.test(normalized)) {\n quantity *= 1000;\n } else if (/\\d+m\\b/i.test(normalized) || /\\d+\\s*million/i.test(normalized)) {\n quantity *= 1_000_000;\n }\n\n // Extract unit\n let unit: WorkloadSpec[\"unit\"] = \"requests\";\n if (/images?\\b/i.test(normalized) || /pics?\\b/i.test(normalized) || /photos?\\b/i.test(normalized)) {\n unit = \"images\";\n } else if (/videos?\\b/i.test(normalized)) {\n unit = \"seconds\"; // Video usually priced per second\n } else if (/minutes?\\b/i.test(normalized) || /mins?\\b/i.test(normalized)) {\n unit = \"minutes\";\n } else if (/seconds?\\b/i.test(normalized) || /secs?\\b/i.test(normalized)) {\n unit = \"seconds\";\n } else if (/tokens?\\b/i.test(normalized)) {\n unit = \"tokens\";\n } else if (/requests?\\b/i.test(normalized) || /calls?\\b/i.test(normalized) || /queries?\\b/i.test(normalized)) {\n unit = \"requests\";\n }\n\n // Extract period\n let period: WorkloadSpec[\"period\"] = \"month\"; // Default to monthly\n if (/\\bper\\s*day\\b/i.test(normalized) || /\\/day\\b/i.test(normalized) || /\\bdaily\\b/i.test(normalized)) {\n period = \"day\";\n } else if (/\\bper\\s*week\\b/i.test(normalized) || /\\/week\\b/i.test(normalized) || /\\bweekly\\b/i.test(normalized)) {\n period = \"week\";\n } else if (/\\bper\\s*month\\b/i.test(normalized) || /\\/month\\b/i.test(normalized) || /\\bmonthly\\b/i.test(normalized)) {\n period = \"month\";\n }\n\n // Extract parameters\n const parameters: WorkloadSpec[\"parameters\"] = {};\n\n // Resolution (e.g., \"1024x1024\")\n const resolutionMatch = normalized.match(/(\\d+)\\s*[xX×]\\s*(\\d+)/);\n if (resolutionMatch) {\n parameters.resolution = `${resolutionMatch[1]}x${resolutionMatch[2]}`;\n }\n\n // Duration (e.g., \"30 seconds\")\n const durationMatch = normalized.match(/(\\d+)\\s*(?:second|sec|minute|min)s?\\b/);\n if (durationMatch) {\n const dur = parseInt(durationMatch[1]!, 10);\n if (/minute|min/i.test(normalized)) {\n parameters.duration = dur * 60; // Convert to seconds\n } else {\n parameters.duration = dur;\n }\n }\n\n // Tokens per request (e.g., \"5000 tokens each\")\n const tokensMatch = normalized.match(/(\\d+)\\s*tokens?\\s*(?:each|per|\\/request)/i);\n if (tokensMatch) {\n parameters.tokensPerRequest = parseInt(tokensMatch[1]!, 10);\n }\n\n const spec: WorkloadSpec = {\n quantity,\n unit,\n period,\n parameters: Object.keys(parameters).length > 0 ? parameters : undefined,\n };\n\n return spec;\n}\n\n/**\n * Calculate the cost estimate for a model given a workload spec\n */\nexport function estimateCost(model: ModelEntry, workload: WorkloadSpec): CostEstimate {\n const periodMultiplier = PERIOD_MULTIPLIERS[workload.period] ?? 1;\n const monthlyUnits = workload.quantity * periodMultiplier;\n\n let costPerUnit: number;\n let breakdown: string;\n\n const pricing = model.pricing;\n\n switch (pricing.type) {\n case \"text\": {\n // For text models, cost is per token\n const tokensPerRequest = workload.parameters?.tokensPerRequest ?? DEFAULT_TOKENS_PER_REQUEST;\n let tokensPerUnit: number;\n\n if (workload.unit === \"tokens\") {\n tokensPerUnit = 1;\n costPerUnit = pricing.promptPer1mTokens / 1_000_000;\n } else if (workload.unit === \"requests\") {\n tokensPerUnit = tokensPerRequest;\n costPerUnit = (pricing.promptPer1mTokens / 1_000_000) * tokensPerRequest;\n } else {\n // Default to requests\n tokensPerUnit = tokensPerRequest;\n costPerUnit = (pricing.promptPer1mTokens / 1_000_000) * tokensPerRequest;\n }\n\n breakdown = `${monthlyUnits.toLocaleString()} ${workload.unit}/month × $${pricing.promptPer1mTokens.toFixed(2)}/1M tokens × ${tokensPerUnit} tokens`;\n break;\n }\n\n case \"image\": {\n if (pricing.perImage) {\n costPerUnit = pricing.perImage;\n breakdown = `${monthlyUnits.toLocaleString()} images/month × $${pricing.perImage.toFixed(4)}/image`;\n } else if (pricing.perMegapixel && workload.parameters?.resolution) {\n const [widthRaw, heightRaw] = workload.parameters.resolution.split(\"x\");\n const width = Number(widthRaw);\n const height = Number(heightRaw);\n // Validate resolution is numeric\n if (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {\n const megapixels = (width * height) / 1_000_000;\n costPerUnit = pricing.perMegapixel * megapixels;\n breakdown = `${monthlyUnits.toLocaleString()} images/month × ${megapixels.toFixed(1)}MP × $${pricing.perMegapixel.toFixed(4)}/MP`;\n } else {\n // Invalid resolution, use 1MP default\n costPerUnit = pricing.perMegapixel;\n breakdown = `${monthlyUnits.toLocaleString()} images/month × $${pricing.perMegapixel.toFixed(4)}/MP (assumed 1MP)`;\n }\n } else if (pricing.perMegapixel) {\n // Assume 1MP default\n costPerUnit = pricing.perMegapixel;\n breakdown = `${monthlyUnits.toLocaleString()} images/month × $${pricing.perMegapixel.toFixed(4)}/MP (assumed 1MP)`;\n } else {\n costPerUnit = 0.02; // Default fallback\n breakdown = `${monthlyUnits.toLocaleString()} images/month (estimated)`;\n }\n break;\n }\n\n case \"video\": {\n const duration = workload.parameters?.duration ?? 5; // Default 5 seconds per video\n if (pricing.perSecond) {\n if (workload.unit === \"seconds\") {\n costPerUnit = pricing.perSecond;\n breakdown = `${monthlyUnits.toLocaleString()} seconds/month × $${pricing.perSecond.toFixed(4)}/sec`;\n } else {\n costPerUnit = pricing.perSecond * duration;\n breakdown = `${monthlyUnits.toLocaleString()} videos/month × ${duration}s × $${pricing.perSecond.toFixed(4)}/sec`;\n }\n } else if (pricing.perGeneration) {\n costPerUnit = pricing.perGeneration;\n breakdown = `${monthlyUnits.toLocaleString()} videos/month × $${pricing.perGeneration.toFixed(2)}/video`;\n } else {\n costPerUnit = 0.10; // Default fallback\n breakdown = `${monthlyUnits.toLocaleString()} videos/month (estimated)`;\n }\n break;\n }\n\n case \"audio\": {\n if (pricing.perMinute) {\n if (workload.unit === \"minutes\") {\n costPerUnit = pricing.perMinute;\n breakdown = `${monthlyUnits.toLocaleString()} minutes/month × $${pricing.perMinute.toFixed(4)}/min`;\n } else if (workload.unit === \"seconds\") {\n costPerUnit = pricing.perMinute / 60;\n breakdown = `${monthlyUnits.toLocaleString()} seconds/month × $${(pricing.perMinute / 60).toFixed(4)}/sec`;\n } else {\n costPerUnit = pricing.perMinute;\n breakdown = `${monthlyUnits.toLocaleString()} minutes/month × $${pricing.perMinute.toFixed(4)}/min`;\n }\n } else if (pricing.perSecond) {\n costPerUnit = pricing.perSecond;\n breakdown = `${monthlyUnits.toLocaleString()} seconds/month × $${pricing.perSecond.toFixed(4)}/sec`;\n } else if (pricing.perCharacter) {\n // For TTS, estimate ~15 characters per second of audio\n costPerUnit = pricing.perCharacter * 15 * 60; // ~900 chars per minute\n breakdown = `${monthlyUnits.toLocaleString()} requests/month × $${pricing.perCharacter.toFixed(6)}/char (estimated)`;\n } else {\n costPerUnit = 0.01; // Default fallback\n breakdown = `${monthlyUnits.toLocaleString()} requests/month (estimated)`;\n }\n break;\n }\n\n case \"embedding\": {\n const tokensPerRequest = workload.parameters?.tokensPerRequest ?? 1000;\n if (workload.unit === \"tokens\") {\n costPerUnit = pricing.per1mTokens / 1_000_000;\n breakdown = `${monthlyUnits.toLocaleString()} tokens/month × $${pricing.per1mTokens.toFixed(3)}/1M tokens`;\n } else {\n costPerUnit = (pricing.per1mTokens / 1_000_000) * tokensPerRequest;\n breakdown = `${monthlyUnits.toLocaleString()} requests/month × ${tokensPerRequest} tokens × $${pricing.per1mTokens.toFixed(3)}/1M tokens`;\n }\n break;\n }\n\n default:\n costPerUnit = 0.01;\n breakdown = `${monthlyUnits.toLocaleString()} units/month (estimated)`;\n }\n\n const monthlyCost = monthlyUnits * costPerUnit;\n const yearlyCost = monthlyCost * 12;\n\n return {\n monthlyUnits,\n costPerUnit,\n monthlyCost,\n yearlyCost,\n breakdown,\n };\n}\n\n/**\n * Format a cost estimate for display\n */\nexport function formatCostEstimate(estimate: CostEstimate): string {\n const monthlyStr = estimate.monthlyCost < 0.01\n ? `<$0.01`\n : `$${estimate.monthlyCost.toFixed(2)}`;\n\n const yearlyStr = estimate.yearlyCost < 1\n ? `<$1`\n : `$${estimate.yearlyCost.toFixed(0)}`;\n\n return `~${monthlyStr}/mo (~${yearlyStr}/yr)`;\n}\n","/**\n * Compare command implementation\n *\n * Compares two models head-to-head for a specific task.\n *\n * @module commands/compare\n */\n\nimport chalk, { Chalk } from \"chalk\";\nimport { ExitCode, WhichModelError, type CompressedModel, type ModelEntry } from \"../types.js\";\nimport { compressForLLM } from \"../catalog/compressor.js\";\nimport { renderBox } from \"../formatter/box.js\";\nimport { requestRecommendationCompletion } from \"../recommender/llm-client.js\";\nimport { parseCompareResultPayload } from \"../schemas/llm-schemas.js\";\nimport { wrapResult } from \"../utils/result.js\";\n\nexport interface CompareOptions {\n task: string;\n}\n\nexport interface CompareResult {\n winner: \"A\" | \"B\" | \"tie\";\n reasoning: string;\n modelA: {\n strengths: string[];\n weaknesses: string[];\n estimatedCost: string;\n suitedFor: string[];\n };\n modelB: {\n strengths: string[];\n weaknesses: string[];\n estimatedCost: string;\n suitedFor: string[];\n };\n}\n\nexport interface CompareJSONOutput {\n winner: CompareResult[\"winner\"];\n reasoning: string;\n modelA: CompareResult[\"modelA\"] & {\n id: string;\n name: string;\n };\n modelB: CompareResult[\"modelB\"] & {\n id: string;\n name: string;\n };\n}\n\nconst COMPARE_SYSTEM_PROMPT = `You are an expert AI model evaluator. Your task is to compare two AI models for a specific use case.\n\nYou will receive:\n1. A task description\n2. Two models with their specifications\n\nYou must analyze both models and determine which is better suited for the given task.\n\nConsider:\n- Pricing and cost efficiency\n- Context length and capabilities\n- Quality and reliability for the specific task\n- Speed and latency implications\n\nRespond with a JSON object matching this exact structure:\n{\n \"winner\": \"A\" or \"B\" or \"tie\",\n \"reasoning\": \"A brief explanation of why this model won (2-3 sentences)\",\n \"modelA\": {\n \"strengths\": [\"strength 1\", \"strength 2\"],\n \"weaknesses\": [\"weakness 1\"],\n \"estimatedCost\": \"Cost estimate for typical usage\",\n \"suitedFor\": [\"use case 1\", \"use case 2\"]\n },\n \"modelB\": {\n \"strengths\": [\"strength 1\", \"strength 2\"],\n \"weaknesses\": [\"weakness 1\"],\n \"estimatedCost\": \"Cost estimate for typical usage\",\n \"suitedFor\": [\"use case 1\", \"use case 2\"]\n }\n}`;\n\nfunction buildCompareUserPrompt(\n task: string,\n modelA: CompressedModel,\n modelB: CompressedModel\n): string {\n return `Task: ${task}\n\nModel A (ID: ${modelA.id}):\n${JSON.stringify(modelA, null, 2)}\n\nModel B (ID: ${modelB.id}):\n${JSON.stringify(modelB, null, 2)}\n\nCompare these two models for the given task and determine which is better suited.`;\n}\n\n/**\n * Find a model by ID (supports partial matching)\n */\nexport function findModelById(models: ModelEntry[], id: string): ModelEntry | null {\n // Try exact match first\n const exact = models.find((m) => m.id === id);\n if (exact) return exact;\n\n // Try matching without source prefix\n const withoutSource = models.find((m) => {\n const parts = m.id.split(\"::\");\n const modelId = parts.length > 1 ? parts.slice(1).join(\"::\") : m.id;\n return modelId === id || m.id.endsWith(`/${id}`);\n });\n if (withoutSource) return withoutSource;\n\n // Try partial match\n const partial = models.find((m) =>\n m.id.toLowerCase().includes(id.toLowerCase()) ||\n m.name.toLowerCase().includes(id.toLowerCase())\n );\n return partial ?? null;\n}\n\n/**\n * Call the LLM to compare models\n */\nexport async function callCompareLLM(\n task: string,\n modelA: ModelEntry,\n modelB: ModelEntry,\n apiKey: string,\n recommenderModel: string\n): Promise<CompareResult> {\n // Compress models for LLM context\n const [compressedA] = compressForLLM([modelA]);\n const [compressedB] = compressForLLM([modelB]);\n\n const userPrompt = buildCompareUserPrompt(task, compressedA!, compressedB!);\n\n const response = await requestRecommendationCompletion({\n apiKey,\n model: recommenderModel,\n systemPrompt: COMPARE_SYSTEM_PROMPT,\n userPrompt,\n temperature: 0.3, // Lower temperature for more consistent comparisons\n });\n\n // Parse the JSON response\n const parseResult = wrapResult(\n () => JSON.parse(stripMarkdownFences(response.content)),\n () => new WhichModelError(\"Invalid compare response JSON.\", ExitCode.LLM_FAILED)\n );\n if (parseResult.isErr()) {\n // If parsing fails, return a default comparison\n return {\n winner: \"tie\",\n reasoning: \"Could not determine a clear winner from the comparison.\",\n modelA: {\n strengths: [\"Model specifications available\"],\n weaknesses: [],\n estimatedCost: formatModelPricing(modelA),\n suitedFor: [\"General use\"],\n },\n modelB: {\n strengths: [\"Model specifications available\"],\n weaknesses: [],\n estimatedCost: formatModelPricing(modelB),\n suitedFor: [\"General use\"],\n },\n };\n }\n\n const comparisonResult = parseCompareResultPayload(parseResult.value);\n if (comparisonResult.isErr()) {\n return {\n winner: \"tie\",\n reasoning: \"Could not determine a clear winner from the comparison.\",\n modelA: {\n strengths: [\"Model specifications available\"],\n weaknesses: [],\n estimatedCost: formatModelPricing(modelA),\n suitedFor: [\"General use\"],\n },\n modelB: {\n strengths: [\"Model specifications available\"],\n weaknesses: [],\n estimatedCost: formatModelPricing(modelB),\n suitedFor: [\"General use\"],\n },\n };\n }\n\n return comparisonResult.value;\n}\n\nfunction stripMarkdownFences(content: string): string {\n return content.replace(/^```(?:json)?\\s*/i, \"\").replace(/\\s*```$/, \"\").trim();\n}\n\n/**\n * Format a model's pricing for display\n */\nfunction formatModelPricing(model: ModelEntry): string {\n const pricing = model.pricing;\n switch (pricing.type) {\n case \"text\":\n return `$${pricing.promptPer1mTokens.toFixed(2)} / $${pricing.completionPer1mTokens.toFixed(2)} per 1M tokens`;\n case \"image\":\n if (pricing.perImage) return `$${pricing.perImage.toFixed(4)} per image`;\n if (pricing.perMegapixel) return `$${pricing.perMegapixel.toFixed(4)} per MP`;\n return \"Pricing varies\";\n case \"video\":\n if (pricing.perSecond) return `$${pricing.perSecond.toFixed(4)} per second`;\n if (pricing.perGeneration) return `$${pricing.perGeneration.toFixed(2)} per video`;\n return \"Pricing varies\";\n case \"audio\":\n if (pricing.perMinute) return `$${pricing.perMinute.toFixed(4)} per minute`;\n if (pricing.perCharacter) return `$${pricing.perCharacter.toFixed(6)} per character`;\n return \"Pricing varies\";\n case \"embedding\":\n return `$${pricing.per1mTokens.toFixed(3)} per 1M tokens`;\n default:\n return \"Pricing varies\";\n }\n}\n\n/**\n * Format compare result for terminal output\n */\nexport function formatCompareTerminal(\n result: CompareResult,\n modelA: ModelEntry,\n modelB: ModelEntry,\n options: CompareOptions,\n noColor: boolean = false\n): string {\n const c = noColor ? new Chalk({ level: 0 }) : chalk;\n const lines: string[] = [];\n\n lines.push(c.bold(\"Model Comparison\"));\n lines.push(c.dim(`Task: ${options.task}`));\n lines.push(\"\");\n\n // Winner announcement\n let winnerText: string;\n let winnerColor: (text: string) => string;\n if (result.winner === \"A\") {\n winnerText = `Winner: ${modelA.name}`;\n winnerColor = c.green;\n } else if (result.winner === \"B\") {\n winnerText = `Winner: ${modelB.name}`;\n winnerColor = c.green;\n } else {\n winnerText = \"Result: It's a tie!\";\n winnerColor = c.yellow;\n }\n lines.push(winnerColor(winnerText));\n lines.push(c.dim(result.reasoning));\n lines.push(\"\");\n\n // Model A details\n lines.push(c.cyan(`Model A: ${c.bold(modelA.name)}`));\n lines.push(` ${c.dim(`ID: ${modelA.id}`)}`);\n lines.push(` ${c.dim(`Pricing: ${formatModelPricing(modelA)}`)}`);\n if (result.modelA.strengths.length > 0) {\n lines.push(` ${c.green(\"Strengths:\")}`);\n for (const s of result.modelA.strengths) {\n lines.push(` • ${s}`);\n }\n }\n if (result.modelA.weaknesses.length > 0) {\n lines.push(` ${c.red(\"Weaknesses:\")}`);\n for (const w of result.modelA.weaknesses) {\n lines.push(` • ${w}`);\n }\n }\n lines.push(\"\");\n\n // Model B details\n lines.push(c.magenta(`Model B: ${c.bold(modelB.name)}`));\n lines.push(` ${c.dim(`ID: ${modelB.id}`)}`);\n lines.push(` ${c.dim(`Pricing: ${formatModelPricing(modelB)}`)}`);\n if (result.modelB.strengths.length > 0) {\n lines.push(` ${c.green(\"Strengths:\")}`);\n for (const s of result.modelB.strengths) {\n lines.push(` • ${s}`);\n }\n }\n if (result.modelB.weaknesses.length > 0) {\n lines.push(` ${c.red(\"Weaknesses:\")}`);\n for (const w of result.modelB.weaknesses) {\n lines.push(` • ${w}`);\n }\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Compare\",\n noColor,\n borderColor: \"yellow\",\n });\n}\n\n/**\n * Format compare result for JSON output\n */\nexport function formatCompareJSON(\n result: CompareResult,\n modelA: ModelEntry,\n modelB: ModelEntry\n): CompareJSONOutput {\n return {\n winner: result.winner,\n reasoning: result.reasoning,\n modelA: {\n id: modelA.id,\n name: modelA.name,\n ...result.modelA,\n },\n modelB: {\n id: modelB.id,\n name: modelB.name,\n ...result.modelB,\n },\n };\n}\n","import type { CompressedModel, ModelEntry } from \"../types.js\";\n\nexport function compressForLLM(models: ModelEntry[]): CompressedModel[] {\n return models.map((model) => {\n const compressed: CompressedModel = {\n id: model.id,\n name: model.name,\n modality: model.modality,\n pricing: flattenPricing(model.pricing),\n };\n\n if (typeof model.contextLength === \"number\") {\n compressed.contextLength = model.contextLength;\n }\n if (model.maxResolution) {\n compressed.maxResolution = model.maxResolution;\n }\n if (typeof model.maxDuration === \"number\") {\n compressed.maxDuration = model.maxDuration;\n }\n\n return compressed;\n });\n}\n\nexport function groupByModality(\n models: CompressedModel[]\n): Record<string, CompressedModel[]> {\n const grouped: Record<string, CompressedModel[]> = {};\n\n for (const model of models) {\n const bucket = grouped[model.modality] ?? [];\n bucket.push(model);\n grouped[model.modality] = bucket;\n }\n\n return grouped;\n}\n\nfunction flattenPricing(pricing: ModelEntry[\"pricing\"]): Record<string, number> {\n const flat: Record<string, number> = {};\n\n for (const [key, value] of Object.entries(pricing)) {\n if (key === \"type\") {\n continue;\n }\n if (typeof value === \"number\") {\n flat[key] = value;\n }\n }\n\n return flat;\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { z } from \"zod\";\nimport { ExitCode, WhichModelError } from \"../types.js\";\n\nconst modalitySchema = z.enum([\n \"text\",\n \"image\",\n \"video\",\n \"audio_tts\",\n \"audio_stt\",\n \"audio_generation\",\n \"vision\",\n \"embedding\",\n \"multimodal\",\n]);\n\nconst modelPickSchema = z.object({\n id: z.string().min(1),\n reason: z.string().min(1),\n pricingSummary: z.string().min(1),\n estimatedCost: z.string().min(1),\n});\n\nexport const recommendationSchema = z.object({\n taskAnalysis: z.object({\n summary: z.string().min(1),\n detectedModality: modalitySchema,\n modalityReasoning: z.string().min(1),\n keyRequirements: z.array(z.string()),\n costFactors: z.string().min(1),\n }),\n recommendations: z.object({\n cheapest: modelPickSchema,\n balanced: modelPickSchema,\n best: modelPickSchema,\n }),\n alternativesInOtherModalities: z.string().nullable().optional().default(null),\n});\n\nexport const compareResultSchema = z.object({\n winner: z.enum([\"A\", \"B\", \"tie\"]),\n reasoning: z.string().min(1),\n modelA: z.object({\n strengths: z.array(z.string()),\n weaknesses: z.array(z.string()),\n estimatedCost: z.string().min(1),\n suitedFor: z.array(z.string()),\n }),\n modelB: z.object({\n strengths: z.array(z.string()),\n weaknesses: z.array(z.string()),\n estimatedCost: z.string().min(1),\n suitedFor: z.array(z.string()),\n }),\n});\n\nexport const openRouterChatResponseSchema = z\n .object({\n id: z.string().optional(),\n choices: z.array(\n z.object({\n index: z.number(),\n message: z.object({\n role: z.string(),\n content: z.string(),\n }),\n finish_reason: z.string().nullable().optional().default(null),\n })\n ),\n usage: z\n .object({\n prompt_tokens: z.number(),\n completion_tokens: z.number(),\n total_tokens: z.number().optional(),\n })\n .optional(),\n model: z.string(),\n })\n .passthrough();\n\nexport type RecommendationParsed = z.infer<typeof recommendationSchema>;\nexport type CompareResultParsed = z.infer<typeof compareResultSchema>;\nexport type OpenRouterChatResponseParsed = z.infer<typeof openRouterChatResponseSchema>;\n\nexport function parseRecommendationPayload(\n payload: unknown\n): Result<RecommendationParsed, WhichModelError> {\n const parsed = recommendationSchema.safeParse(payload);\n if (parsed.success) {\n return ok(parsed.data);\n }\n\n return err(\n new WhichModelError(\n \"LLM JSON response does not match expected recommendation structure.\",\n ExitCode.LLM_FAILED,\n \"Retry in a few minutes or use fallback mode.\"\n )\n );\n}\n\nexport function parseCompareResultPayload(payload: unknown): Result<CompareResultParsed, Error> {\n const parsed = compareResultSchema.safeParse(payload);\n if (parsed.success) {\n return ok(parsed.data);\n }\n\n return err(new Error(\"Compare response did not match expected schema.\"));\n}\n\nexport function parseOpenRouterChatResponse(\n payload: unknown\n): Result<OpenRouterChatResponseParsed, WhichModelError> {\n const parsed = openRouterChatResponseSchema.safeParse(payload);\n if (parsed.success) {\n return ok(parsed.data);\n }\n\n return err(\n new WhichModelError(\n \"OpenRouter LLM response is malformed.\",\n ExitCode.LLM_FAILED,\n \"Retry the request.\"\n )\n );\n}\n","/**\n * Shared utility functions for the whichmodel CLI\n *\n * @module utils/common\n */\n\n/**\n * Check if an error is an AbortError (from AbortController/AbortSignal)\n */\nexport function isAbortError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"name\" in error &&\n (error as { name?: string }).name === \"AbortError\"\n );\n}\n\n/**\n * Wait for a specified number of milliseconds\n */\nexport async function wait(ms: number): Promise<void> {\n if (ms <= 0) return;\n await new Promise<void>((resolve) => {\n setTimeout(resolve, ms);\n });\n}\n\n/**\n * Add jitter to a delay value to prevent thundering herd\n * Returns a value between 50% and 100% of the base delay\n */\nexport function withJitter(baseDelayMs: number): number {\n return Math.floor(baseDelayMs * (0.5 + Math.random() * 0.5));\n}\n\n/**\n * Default retry delays in milliseconds (exponential backoff)\n */\nexport const DEFAULT_RETRY_DELAYS_MS = [1_000, 2_000, 4_000] as const;\n","import { err, ok, Result, ResultAsync } from \"neverthrow\";\nimport { ExitCode, WhichModelError } from \"../types.js\";\n\nexport function toWhichModelError(\n error: unknown,\n fallbackMessage: string,\n exitCode: ExitCode,\n recoveryHint?: string\n): WhichModelError {\n if (error instanceof WhichModelError) {\n return error;\n }\n\n if (error instanceof Error && error.message) {\n return new WhichModelError(`${fallbackMessage}: ${error.message}`, exitCode, recoveryHint);\n }\n\n return new WhichModelError(fallbackMessage, exitCode, recoveryHint);\n}\n\nexport function wrapResult<T>(\n fn: () => T,\n onError: (error: unknown) => WhichModelError\n): Result<T, WhichModelError> {\n try {\n return ok(fn());\n } catch (error) {\n return err(onError(error));\n }\n}\n\nexport function wrapResultAsync<T>(\n promiseFactory: () => Promise<T>,\n onError: (error: unknown) => WhichModelError\n): ResultAsync<T, WhichModelError> {\n return ResultAsync.fromPromise(Promise.resolve().then(promiseFactory), onError);\n}\n","import {\n ExitCode,\n WhichModelError,\n type OpenRouterChatRequest,\n} from \"../types.js\";\nimport { parseOpenRouterChatResponse } from \"../schemas/llm-schemas.js\";\nimport { isAbortError, wait, withJitter, DEFAULT_RETRY_DELAYS_MS } from \"../utils/common.js\";\nimport { wrapResultAsync } from \"../utils/result.js\";\n\nconst OPENROUTER_CHAT_URL = \"https://openrouter.ai/api/v1/chat/completions\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport interface LLMClientOptions {\n apiKey: string;\n model: string;\n systemPrompt: string;\n userPrompt: string;\n timeoutMs?: number;\n retryDelaysMs?: number[];\n fetchImpl?: typeof fetch;\n temperature?: number;\n maxTokens?: number;\n}\n\nexport interface LLMCompletion {\n content: string;\n model: string;\n usage?: {\n promptTokens: number;\n completionTokens: number;\n };\n}\n\nexport async function requestRecommendationCompletion(\n options: LLMClientOptions\n): Promise<LLMCompletion> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const retryDelaysMs = options.retryDelaysMs ?? [...DEFAULT_RETRY_DELAYS_MS];\n const fetchImpl = options.fetchImpl ?? fetch;\n const maxAttempts = retryDelaysMs.length + 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n const response = await postChatCompletion(fetchImpl, options, timeoutMs);\n\n if (!response.ok) {\n if (response.status === 401) {\n throw new WhichModelError(\n \"Invalid OpenRouter API key.\",\n ExitCode.LLM_FAILED,\n [\n \"Please check that your key is valid, active, and starts with sk-or-.\",\n \"Manage keys at https://openrouter.ai/keys\",\n ].join(\"\\n\")\n );\n }\n\n if (response.status === 402) {\n throw new WhichModelError(\n \"Insufficient credits in your OpenRouter account.\",\n ExitCode.LLM_FAILED,\n [\n \"Add credits at https://openrouter.ai/credits\",\n \"The default recommender model is low-cost, but requires a positive balance.\",\n ].join(\"\\n\")\n );\n }\n\n if (response.status === 429 && attempt < maxAttempts - 1) {\n await wait(withJitter(retryDelayForAttempt(retryDelaysMs, attempt)));\n continue;\n }\n\n if (shouldRetryStatus(response.status) && attempt < maxAttempts - 1) {\n await wait(withJitter(retryDelayForAttempt(retryDelaysMs, attempt)));\n continue;\n }\n\n throw new WhichModelError(\n `OpenRouter LLM request failed with status ${response.status}.`,\n ExitCode.LLM_FAILED,\n \"Retry shortly or switch --model.\"\n );\n }\n\n const rawPayload = await wrapResultAsync(\n () => response.json(),\n () =>\n new WhichModelError(\n \"OpenRouter LLM returned malformed JSON.\",\n ExitCode.LLM_FAILED,\n \"Retry the request.\"\n )\n );\n if (rawPayload.isErr()) {\n throw rawPayload.error;\n }\n\n const payloadResult = parseOpenRouterChatResponse(rawPayload.value);\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n const payload = payloadResult.value;\n const content = payload.choices?.[0]?.message?.content;\n if (!content || typeof content !== \"string\") {\n throw new WhichModelError(\n \"OpenRouter LLM returned an empty response.\",\n ExitCode.LLM_FAILED,\n \"Retry the request.\"\n );\n }\n\n return {\n content,\n model: payload.model,\n usage: payload.usage\n ? {\n promptTokens: payload.usage.prompt_tokens,\n completionTokens: payload.usage.completion_tokens,\n }\n : undefined,\n };\n } catch (error) {\n lastError = error;\n\n if (error instanceof WhichModelError && !isRetryableCode(error.exitCode)) {\n throw error;\n }\n\n if (attempt < maxAttempts - 1 && isRetryableError(error)) {\n await wait(withJitter(retryDelayForAttempt(retryDelaysMs, attempt)));\n continue;\n }\n\n break;\n }\n }\n\n if (lastError instanceof WhichModelError) {\n throw lastError;\n }\n\n if (isAbortError(lastError)) {\n throw new WhichModelError(\n \"OpenRouter LLM request timed out.\",\n ExitCode.LLM_FAILED,\n \"Retry in a few minutes. If this continues, try a smaller task description.\"\n );\n }\n\n const detail = lastError instanceof Error ? lastError.message : \"Unknown LLM error\";\n throw new WhichModelError(\n `LLM recommendation failed: ${detail}`,\n ExitCode.LLM_FAILED,\n \"Retry in a few minutes or use fallback mode.\"\n );\n}\n\nasync function postChatCompletion(\n fetchImpl: typeof fetch,\n options: LLMClientOptions,\n timeoutMs: number\n): Promise<Response> {\n const body: OpenRouterChatRequest = {\n model: options.model,\n messages: [\n {\n role: \"system\",\n content: options.systemPrompt,\n },\n {\n role: \"user\",\n content: options.userPrompt,\n },\n ],\n response_format: {\n type: \"json_object\",\n },\n temperature: options.temperature ?? 0.2,\n max_tokens: options.maxTokens ?? 1_200,\n };\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n return await fetchImpl(OPENROUTER_CHAT_URL, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${options.apiKey}`,\n \"Content-Type\": \"application/json\",\n \"HTTP-Referer\": \"https://github.com/whichmodel/whichmodel\",\n \"X-Title\": \"whichmodel CLI\",\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nfunction shouldRetryStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n}\n\nfunction isRetryableCode(code: ExitCode): boolean {\n return code === ExitCode.LLM_FAILED || code === ExitCode.NETWORK_ERROR;\n}\n\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof WhichModelError) {\n return isRetryableCode(error.exitCode);\n }\n\n if (isAbortError(error)) {\n return true;\n }\n\n return error instanceof TypeError;\n}\n\nfunction retryDelayForAttempt(delays: ReadonlyArray<number>, attempt: number): number {\n return delays[Math.min(attempt, delays.length - 1)] ?? 0;\n}\n","/**\n * Self-updating recommender module\n *\n * Allows the tool to analyze available models and update its default recommender.\n *\n * @module commands/update-recommender\n */\n\nimport chalk, { Chalk } from \"chalk\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport os from \"node:os\";\nimport { renderBox } from \"../formatter/box.js\";\nimport type { ModelEntry, TextPricing } from \"../types.js\";\nimport { generateFallbackRecommendation } from \"../recommender/fallback.js\";\n\nexport interface RecommenderCriteria {\n modality: \"text\";\n maxPromptPricePer1m: number;\n maxCompletionPricePer1m: number;\n minContextLength: number;\n}\n\nexport interface RecommenderUpdate {\n currentModel: string;\n newModel: string;\n newModelName: string;\n changed: boolean;\n reasoning: string;\n newPricing: {\n promptPer1m: number;\n completionPer1m: number;\n };\n savings: {\n promptPer1m: number;\n completionPer1m: number;\n } | null;\n}\n\nexport const DEFAULT_RECOMMENDER_CRITERIA: RecommenderCriteria = {\n modality: \"text\",\n maxPromptPricePer1m: 1.00,\n maxCompletionPricePer1m: 2.00,\n minContextLength: 32000,\n};\n\nconst RECOMMENDER_SELECTION_TASK =\n \"Select the best-value model for analyzing user tasks and returning structured JSON recommendations.\";\n\n/**\n * Check if a model family supports reasoning\n */\nfunction supportsReasoning(model: ModelEntry): boolean {\n const reasoningFamilies = [\"claude\", \"gpt-4\", \"o1\", \"o3\", \"deepseek\", \"gemini\", \"qwen\"];\n const family = model.family.toLowerCase();\n const name = model.name.toLowerCase();\n\n return (\n reasoningFamilies.some((f) => family.includes(f)) ||\n name.includes(\"reasoning\") ||\n name.includes(\"think\")\n );\n}\n\nfunction normalizeModelId(id: string): string {\n const parts = id.split(\"::\");\n return parts.length > 1 ? parts.slice(1).join(\"::\") : id;\n}\n\n/**\n * Select the best recommender model based on criteria\n */\nexport function selectBestRecommender(\n models: ModelEntry[],\n criteria: RecommenderCriteria = DEFAULT_RECOMMENDER_CRITERIA\n): ModelEntry | null {\n const candidates = models.filter((model) => {\n // Recommender requests are sent through OpenRouter chat completions.\n if (model.source !== \"openrouter\") return false;\n\n // Must be text modality\n if (model.modality !== criteria.modality) return false;\n\n if (model.pricing.type !== \"text\") return false;\n const pricing = model.pricing;\n\n // Must support reasoning\n if (!supportsReasoning(model)) return false;\n\n // Must meet minimum context length\n if ((model.contextLength ?? 0) < criteria.minContextLength) return false;\n\n // Check pricing\n if (pricing.promptPer1mTokens > criteria.maxPromptPricePer1m) return false;\n if (pricing.completionPer1mTokens > criteria.maxCompletionPricePer1m) return false;\n\n return true;\n });\n\n if (candidates.length === 0) {\n return null;\n }\n\n // Reuse the same fallback recommender tiering logic used by main `whichmodel`.\n const selection = generateFallbackRecommendation(RECOMMENDER_SELECTION_TASK, candidates, {\n modality: \"text\",\n });\n const selectedId = selection.recommendations.cheapest.id;\n\n return candidates.find((model) => model.id === selectedId) ?? candidates[0] ?? null;\n}\n\n/**\n * Get the config file path\n */\nfunction getConfigPath(): string {\n if (process.env.WHICHMODEL_CONFIG) {\n return process.env.WHICHMODEL_CONFIG;\n }\n\n if (process.platform === \"win32\") {\n const appData = process.env.APPDATA ?? path.join(os.homedir(), \"AppData\", \"Roaming\");\n return path.join(appData, \"whichmodel\", \"config.json\");\n }\n return path.join(os.homedir(), \".config\", \"whichmodel\", \"config.json\");\n}\n\ninterface ConfigFile {\n apiKey?: string;\n recommenderModel?: string;\n falApiKey?: string;\n replicateApiToken?: string;\n elevenLabsApiKey?: string;\n togetherApiKey?: string;\n cacheTtl?: number;\n}\n\n/**\n * Update the config file with a new recommender model\n */\nexport async function updateConfigFile(updates: Partial<ConfigFile>): Promise<void> {\n const configPath = getConfigPath();\n const configDir = path.dirname(configPath);\n\n // Read existing config or create empty\n let existing: ConfigFile = {};\n try {\n const content = await fs.readFile(configPath, \"utf-8\");\n existing = JSON.parse(content) as ConfigFile;\n } catch {\n // Config doesn't exist, use empty\n }\n\n // Merge updates\n const updated = { ...existing, ...updates };\n\n // Ensure directory exists\n await fs.mkdir(configDir, { recursive: true, mode: 0o700 });\n\n // Write atomically\n const tempPath = `${configPath}.tmp`;\n await fs.writeFile(tempPath, JSON.stringify(updated, null, 2), { mode: 0o600 });\n await fs.rename(tempPath, configPath);\n}\n\n/**\n * Update the default recommender model\n */\nexport async function updateRecommenderModel(\n models: ModelEntry[],\n currentModel: string,\n criteria: RecommenderCriteria = DEFAULT_RECOMMENDER_CRITERIA\n): Promise<RecommenderUpdate> {\n const normalizedCurrentModel = normalizeModelId(currentModel);\n const best = selectBestRecommender(models, criteria);\n\n if (!best) {\n return {\n currentModel,\n newModel: normalizedCurrentModel,\n newModelName: currentModel,\n changed: false,\n reasoning: \"No models meet the recommender criteria.\",\n newPricing: { promptPer1m: 0, completionPer1m: 0 },\n savings: null,\n };\n }\n\n const bestPricing = best.pricing as TextPricing;\n const normalizedBestModel = normalizeModelId(best.id);\n const changed = normalizedBestModel !== normalizedCurrentModel;\n\n // Find current model pricing for comparison\n let savings: RecommenderUpdate[\"savings\"] = null;\n const currentModelEntry = models.find(\n (m) => normalizeModelId(m.id) === normalizedCurrentModel\n );\n if (currentModelEntry && currentModelEntry.pricing.type === \"text\") {\n const currentPricing = currentModelEntry.pricing as TextPricing;\n savings = {\n promptPer1m: currentPricing.promptPer1mTokens - bestPricing.promptPer1mTokens,\n completionPer1m: currentPricing.completionPer1mTokens - bestPricing.completionPer1mTokens,\n };\n }\n\n // Update config file if changed\n if (changed) {\n await updateConfigFile({ recommenderModel: normalizedBestModel });\n }\n\n return {\n currentModel,\n newModel: normalizedBestModel,\n newModelName: best.name,\n changed,\n reasoning: changed\n ? `Found a better value model: ${best.name}`\n : \"Current recommender is already optimal.\",\n newPricing: {\n promptPer1m: bestPricing.promptPer1mTokens,\n completionPer1m: bestPricing.completionPer1mTokens,\n },\n savings,\n };\n}\n\n/**\n * Format the recommender update for terminal output\n */\nexport function formatRecommenderUpdate(update: RecommenderUpdate, noColor: boolean = false): string {\n const c = noColor ? new Chalk({ level: 0 }) : chalk;\n const lines: string[] = [];\n\n lines.push(c.cyan(\"Recommender Model Update\"));\n lines.push(\"\");\n\n if (update.changed) {\n lines.push(c.green(`New recommender: ${c.bold(update.newModelName)}`));\n lines.push(c.dim(` Previous: ${update.currentModel}`));\n } else {\n lines.push(c.green(`Current recommender: ${c.bold(update.newModelName)} (no change)`));\n lines.push(c.dim(` Model ID: ${update.newModel}`));\n }\n\n lines.push(\"\");\n lines.push(` Cost: $${update.newPricing.promptPer1m.toFixed(2)}/1M prompt, $${update.newPricing.completionPer1m.toFixed(2)}/1M completion`);\n\n if (update.savings) {\n if (update.savings.promptPer1m > 0 || update.savings.completionPer1m > 0) {\n lines.push(c.green(` Savings: $${update.savings.promptPer1m.toFixed(2)}/1M prompt, $${update.savings.completionPer1m.toFixed(2)}/1M completion`));\n } else if (update.savings.promptPer1m < 0 || update.savings.completionPer1m < 0) {\n lines.push(c.yellow(` Note: Previous model was cheaper but may have lower quality`));\n }\n }\n\n lines.push(\"\");\n lines.push(c.dim(update.reasoning));\n\n if (update.changed) {\n lines.push(\"\");\n lines.push(c.dim(`Config file updated: ${getConfigPath()}`));\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Recommender\",\n noColor,\n borderColor: \"cyan\",\n });\n}\n","import type {\n Constraints,\n Modality,\n ModelEntry,\n ModelPick,\n Recommendation,\n} from \"../types.js\";\nimport { getModelPrimaryPrice, hasUsablePrice } from \"../model-pricing.js\";\n\nconst TIER_KEYS = [\"cheapest\", \"balanced\", \"best\"] as const;\n\nexport function generateFallbackRecommendation(\n task: string,\n models: ModelEntry[],\n constraints?: Constraints\n): Recommendation {\n const detectedModality = constraints?.modality ?? detectTaskModality(task);\n const candidates = filterFallbackCandidates(models, detectedModality, constraints);\n\n const ordered = [...candidates].sort((a, b) => getPriceScore(a) - getPriceScore(b));\n const cheapest = ordered[0] ?? models[0];\n const balanced = ordered[Math.floor(Math.max(0, ordered.length - 1) / 2)] ?? cheapest;\n const best = pickBestCandidate(ordered) ?? balanced ?? cheapest;\n const defaultModel = cheapest ?? balanced ?? best;\n\n if (!defaultModel) {\n throw new Error(\"Fallback recommendation requires at least one model.\");\n }\n\n const picks = uniquePicks([cheapest, balanced, best].filter(isModelEntry));\n\n return {\n taskAnalysis: {\n summary: summarizeTask(task),\n detectedModality,\n modalityReasoning:\n constraints?.modality\n ? `Modality was forced by constraints to ${constraints.modality}.`\n : `Detected ${detectedModality} from task keywords and fallback heuristics.`,\n keyRequirements: inferKeyRequirements(task, detectedModality),\n costFactors: describeCostFactors(detectedModality),\n },\n recommendations: {\n cheapest: toPick(\n picks[0] ?? defaultModel,\n \"Lowest estimated price in the matched catalog subset.\"\n ),\n balanced: toPick(\n picks[1] ?? picks[0] ?? defaultModel,\n \"Good compromise between price and capabilities for this modality.\"\n ),\n best: toPick(\n picks[2] ?? picks[1] ?? picks[0] ?? defaultModel,\n \"Highest capability candidate in fallback selection.\"\n ),\n },\n alternativesInOtherModalities: null,\n };\n}\n\nexport function detectTaskModality(task: string): Modality {\n const text = task.toLowerCase();\n\n if (/(transcribe|caption|speech to text|stt)/.test(text)) return \"audio_stt\";\n if (/(voiceover|text to speech|tts|narration|clone (a )?voice|voice clone)/.test(text)) {\n return \"audio_tts\";\n }\n if (/(music|soundtrack|audio generation)/.test(text)) return \"audio_generation\";\n if (/(embedding|semantic search|vector|rag)/.test(text)) return \"embedding\";\n if (\n /(screenshot|ocr|analy[sz]e image|analy[sz]e .*website|vision|extract text from pdf)/.test(\n text\n )\n ) {\n return \"vision\";\n }\n if (/(video|clip|animation)/.test(text) && !/(script|outline|copy)/.test(text)) return \"video\";\n if (/(image|photo|logo|illustration|art|avatar)/.test(text)) return \"image\";\n\n return \"text\";\n}\n\nfunction filterFallbackCandidates(\n models: ModelEntry[],\n modality: Modality,\n constraints?: Constraints\n): ModelEntry[] {\n return models.filter((model) => {\n if (!hasUsablePrice(model)) {\n return false;\n }\n\n if (model.modality !== modality && !(modality === \"text\" && model.modality === \"vision\")) {\n return false;\n }\n\n if (typeof constraints?.minContext === \"number\") {\n if ((model.contextLength ?? 0) < constraints.minContext) {\n return false;\n }\n }\n\n if (typeof constraints?.maxPrice === \"number\") {\n if (getPriceScore(model) > constraints.maxPrice) {\n return false;\n }\n }\n\n return true;\n });\n}\n\nfunction pickBestCandidate(models: ModelEntry[]): ModelEntry | undefined {\n return [...models].sort((a, b) => {\n const contextA = a.contextLength ?? 0;\n const contextB = b.contextLength ?? 0;\n if (contextA !== contextB) {\n return contextB - contextA;\n }\n\n return getPriceScore(b) - getPriceScore(a);\n })[0];\n}\n\nfunction getPriceScore(model: ModelEntry): number {\n return getModelPrimaryPrice(model);\n}\n\nfunction toPick(model: ModelEntry, reason: string): ModelPick {\n return {\n id: model.id,\n reason,\n pricingSummary: summarizePricing(model),\n estimatedCost: estimateCost(model),\n };\n}\n\nfunction summarizePricing(model: ModelEntry): string {\n const pricing = model.pricing;\n\n switch (pricing.type) {\n case \"text\":\n return `$${pricing.promptPer1mTokens.toFixed(2)} / $${pricing.completionPer1mTokens.toFixed(2)} per 1M tokens (in/out)`;\n case \"embedding\":\n return `$${pricing.per1mTokens.toFixed(2)} per 1M tokens`;\n case \"image\":\n if (typeof pricing.perImage === \"number\") return `$${pricing.perImage.toFixed(3)} per image`;\n if (typeof pricing.perMegapixel === \"number\") return `$${pricing.perMegapixel.toFixed(3)} per megapixel`;\n if (typeof pricing.perStep === \"number\") return `$${pricing.perStep.toFixed(5)} per step`;\n return \"Pricing varies by provider\";\n case \"video\":\n if (typeof pricing.perSecond === \"number\") return `$${pricing.perSecond.toFixed(3)} per second`;\n if (typeof pricing.perGeneration === \"number\") return `$${pricing.perGeneration.toFixed(3)} per generation`;\n return \"Pricing varies by provider\";\n case \"audio\":\n if (typeof pricing.perMinute === \"number\") return `$${pricing.perMinute.toFixed(3)} per minute`;\n if (typeof pricing.perCharacter === \"number\") return `$${(pricing.perCharacter * 1000).toFixed(3)} per 1K chars`;\n if (typeof pricing.perSecond === \"number\") return `$${pricing.perSecond.toFixed(4)} per second`;\n return \"Pricing varies by provider\";\n default:\n return \"Pricing unavailable\";\n }\n}\n\nfunction estimateCost(model: ModelEntry): string {\n const pricing = model.pricing;\n\n switch (pricing.type) {\n case \"text\": {\n const monthly = (pricing.promptPer1mTokens * 3 + pricing.completionPer1mTokens * 1.5) / 100;\n return `~$${monthly.toFixed(2)}/mo for a light text workload`;\n }\n case \"image\":\n return \"~$5-25/mo depending on image volume and resolution\";\n case \"video\":\n return \"~$30-100/mo depending on duration and clip count\";\n case \"audio\":\n return \"~$5-40/mo depending on minutes generated/transcribed\";\n case \"embedding\":\n return \"~$1-15/mo depending on indexed corpus size\";\n default:\n return \"Cost depends on workload\";\n }\n}\n\nfunction summarizeTask(task: string): string {\n const trimmed = task.trim();\n if (trimmed.length <= 90) {\n return trimmed;\n }\n\n return `${trimmed.slice(0, 87)}...`;\n}\n\nfunction inferKeyRequirements(task: string, modality: Modality): string[] {\n const requirements = new Set<string>();\n\n if (/fast|quick|realtime|real-time/.test(task.toLowerCase())) {\n requirements.add(\"fast response time\");\n }\n if (/cheap|budget|low cost/.test(task.toLowerCase())) {\n requirements.add(\"low inference cost\");\n }\n\n if (modality === \"text\" || modality === \"vision\") {\n requirements.add(\"strong reasoning\");\n requirements.add(\"instruction following\");\n }\n\n if (modality === \"image\" || modality === \"video\") {\n requirements.add(\"high visual quality\");\n }\n\n if (requirements.size === 0) {\n requirements.add(\"reliable output quality\");\n requirements.add(\"cost-effectiveness\");\n }\n\n return [...requirements].slice(0, 4);\n}\n\nfunction describeCostFactors(modality: Modality): string {\n switch (modality) {\n case \"text\":\n case \"vision\":\n return \"Token volume (input and output) drives total cost.\";\n case \"image\":\n return \"Image count and resolution are the dominant cost drivers.\";\n case \"video\":\n return \"Video length and number of generations drive cost.\";\n case \"audio_tts\":\n case \"audio_stt\":\n case \"audio_generation\":\n return \"Audio duration and generation count drive cost.\";\n case \"embedding\":\n return \"Total indexed token count is the main cost factor.\";\n case \"multimodal\":\n return \"Mixed token and media usage determines total cost.\";\n default:\n return \"Workload volume drives cost.\";\n }\n}\n\nfunction uniquePicks(candidates: ModelEntry[]): ModelEntry[] {\n const seen = new Set<string>();\n const unique: ModelEntry[] = [];\n\n for (const candidate of candidates) {\n if (seen.has(candidate.id)) {\n continue;\n }\n\n unique.push(candidate);\n seen.add(candidate.id);\n }\n\n return unique;\n}\n\nfunction isModelEntry(value: ModelEntry | undefined): value is ModelEntry {\n return Boolean(value);\n}\n","import type {\n FalModel,\n ModelEntry,\n Modality,\n OpenRouterModel,\n ReplicateModel,\n} from \"../types.js\";\n\nconst FAMILY_PATTERNS: Array<[RegExp, string]> = [\n [/claude/, \"claude\"],\n [/gpt/, \"gpt\"],\n [/gemini/, \"gemini\"],\n [/deepseek/, \"deepseek\"],\n [/llama/, \"llama\"],\n [/qwen/, \"qwen\"],\n [/mistral|mixtral/, \"mistral\"],\n [/flux/, \"flux\"],\n [/dall-e|dalle/, \"dalle\"],\n [/stable-diffusion|sdxl/, \"stable-diffusion\"],\n [/whisper/, \"whisper\"],\n [/midjourney/, \"midjourney\"],\n [/runway/, \"runway\"],\n [/elevenlabs|eleven-/, \"elevenlabs\"],\n [/kling/, \"kling\"],\n [/ideogram/, \"ideogram\"],\n [/recraft/, \"recraft\"],\n];\n\nconst DEFAULT_MODALITIES = [\"text\"];\nconst IMAGE_KEYWORDS = [\"image\", \"photo\", \"picture\", \"mask\", \"jpg\", \"jpeg\", \"png\", \"webp\"];\nconst VIDEO_KEYWORDS = [\"video\", \"clip\", \"animation\", \"movie\", \"mp4\", \"webm\", \"gif\"];\nconst AUDIO_KEYWORDS = [\"audio\", \"speech\", \"voice\", \"music\", \"wav\", \"mp3\", \"flac\", \"transcript\"];\nconst EMBEDDING_KEYWORDS = [\"embedding\", \"embeddings\", \"vector\", \"vectors\"];\nconst TEXT_HINT_KEYWORDS = [\"text\", \"prompt\", \"instruction\", \"caption\", \"query\", \"message\"];\n\nexport function classifyModality(input: string[], output: string[]): Modality {\n const normalizedInput = normalizeModalities(input);\n const normalizedOutput = normalizeModalities(output);\n const allModalities = new Set([...normalizedInput, ...normalizedOutput]);\n\n // If both sides have multiple modalities, treat it as truly multimodal.\n if (normalizedInput.length > 1 && normalizedOutput.length > 1) {\n return \"multimodal\";\n }\n\n if (normalizedOutput.includes(\"image\")) return \"image\";\n if (normalizedOutput.includes(\"video\")) return \"video\";\n\n if (\n normalizedOutput.includes(\"music\") ||\n normalizedOutput.includes(\"sound\")\n ) {\n return \"audio_generation\";\n }\n\n if (normalizedOutput.includes(\"audio\")) {\n return normalizedInput.includes(\"audio\") ? \"audio_stt\" : \"audio_tts\";\n }\n\n if (normalizedOutput.includes(\"embedding\") || normalizedOutput.includes(\"vector\")) {\n return \"embedding\";\n }\n\n // Treat as STT only for pure audio->text pipelines, not broad multimodal models.\n if (\n normalizedInput.includes(\"audio\") &&\n normalizedInput.length === 1 &&\n normalizedOutput.includes(\"text\") &&\n normalizedOutput.length === 1\n ) {\n return \"audio_stt\";\n }\n\n if (normalizedInput.includes(\"image\") && normalizedOutput.includes(\"text\")) {\n return \"vision\";\n }\n\n if (allModalities.size > 2) {\n return \"multimodal\";\n }\n\n return \"text\";\n}\n\nexport function extractFamily(id: string, name?: string): string {\n const combined = `${id} ${name ?? \"\"}`.toLowerCase();\n\n for (const [pattern, family] of FAMILY_PATTERNS) {\n if (pattern.test(combined)) {\n return family;\n }\n }\n\n return \"other\";\n}\n\nexport function extractProvider(id: string): string {\n const withoutSourcePrefix = id.replace(/^[^:]+::/, \"\");\n const provider = withoutSourcePrefix.split(\"/\")[0];\n return provider && provider.length > 0 ? provider : \"unknown\";\n}\n\nexport function normalizeOpenRouterModel(raw: OpenRouterModel): ModelEntry | null {\n const promptPerToken = parsePrice(raw.pricing?.prompt);\n const completionPerToken = parsePrice(raw.pricing?.completion);\n\n if (promptPerToken < 0 || completionPerToken < 0) {\n return null;\n }\n\n if (promptPerToken === 0 && completionPerToken === 0) {\n return null;\n }\n\n const inputModalities = normalizeModalities(raw.architecture?.input_modalities);\n const outputModalities = normalizeModalities(\n raw.architecture?.output_modalities\n );\n\n return {\n id: `openrouter::${raw.id}`,\n source: \"openrouter\",\n name: raw.name,\n modality: classifyModality(inputModalities, outputModalities),\n inputModalities,\n outputModalities,\n pricing: {\n type: \"text\",\n promptPer1mTokens: round(promptPerToken * 1_000_000, 6),\n completionPer1mTokens: round(completionPerToken * 1_000_000, 6),\n },\n contextLength: toPositiveNumber(raw.context_length),\n provider: extractProvider(raw.id),\n family: extractFamily(raw.id, raw.name),\n };\n}\n\nexport function normalizeFalModel(raw: FalModel): ModelEntry | null {\n const modality = classifyFalCategory(raw.category);\n if (!modality) {\n return null;\n }\n\n const pricing = normalizeFalPricing(raw, modality);\n if (!pricing) {\n return null;\n }\n\n const inputModalities = falInputModalities(raw.category);\n const outputModalities = falOutputModalities(modality);\n\n return {\n id: `fal::${raw.id}`,\n source: \"fal\",\n name: raw.name,\n modality,\n inputModalities,\n outputModalities,\n pricing,\n provider: extractProvider(raw.id),\n family: extractFamily(raw.id, raw.name),\n };\n}\n\nexport function normalizeReplicateModel(raw: ReplicateModel): ModelEntry | null {\n const modelKey = toReplicateModelKey(raw);\n if (!modelKey) {\n return null;\n }\n\n const openApiSchema = extractReplicateOpenApiSchema(raw);\n let inputModalities = detectReplicateInputModalities(openApiSchema);\n let outputModalities = detectReplicateOutputModalities(openApiSchema, raw);\n let modality = classifyModality(inputModalities, outputModalities);\n\n if (modality === \"text\") {\n const inferred = inferReplicateModalityFromMetadata(raw);\n if (inferred !== \"text\") {\n const fallback = fallbackModalitiesForModality(inferred);\n inputModalities = fallback.inputModalities;\n outputModalities = fallback.outputModalities;\n modality = inferred;\n }\n }\n\n const pricing = normalizeReplicatePricing(raw, modality);\n if (!pricing) {\n return null;\n }\n\n return {\n id: `replicate::${modelKey}`,\n source: \"replicate\",\n name: raw.name,\n modality,\n inputModalities,\n outputModalities,\n pricing,\n provider: extractProvider(modelKey),\n family: extractFamily(modelKey, raw.name),\n };\n}\n\nfunction normalizeModalities(values?: string[] | null): string[] {\n const source = values && values.length > 0 ? values : DEFAULT_MODALITIES;\n const normalized = source\n .map((value) => value.trim().toLowerCase())\n .filter((value) => value.length > 0);\n\n if (normalized.length === 0) {\n return [...DEFAULT_MODALITIES];\n }\n\n return Array.from(new Set(normalized));\n}\n\nfunction normalizeReplicatePricing(\n raw: ReplicateModel,\n modality: Modality\n): ModelEntry[\"pricing\"] | null {\n const pricingSources = [raw.pricing, raw.latest_version?.pricing];\n\n if (modality === \"text\") {\n const promptEntryBase =\n extractFirstNumericByKey(pricingSources, [\n \"prompt_per_1m\",\n \"input_per_1m\",\n \"prompt\",\n \"input\",\n ]) ?? extractFirstNumericByKey(pricingSources, [\"per_token\", \"token\"]);\n const completionEntryBase =\n extractFirstNumericByKey(pricingSources, [\n \"completion_per_1m\",\n \"output_per_1m\",\n \"completion\",\n \"output\",\n ]) ??\n extractFirstNumericByKey(pricingSources, [\"per_token\", \"token\"]);\n const promptEntry = promptEntryBase ?? completionEntryBase;\n const completionEntry = completionEntryBase ?? promptEntryBase;\n const promptPer1mTokens = normalizeTokenPricePer1m(promptEntry);\n const completionPer1mTokens = normalizeTokenPricePer1m(completionEntry);\n if (\n typeof promptPer1mTokens !== \"number\" ||\n typeof completionPer1mTokens !== \"number\"\n ) {\n return null;\n }\n\n return {\n type: \"text\",\n promptPer1mTokens,\n completionPer1mTokens,\n };\n }\n\n if (modality === \"embedding\") {\n const embeddingEntry =\n extractFirstNumericByKey(pricingSources, [\"embedding_per_1m\", \"per_1m\"]) ??\n extractFirstNumericByKey(pricingSources, [\"embedding\", \"per_token\", \"token\"]);\n const per1mTokens = normalizeTokenPricePer1m(embeddingEntry);\n if (typeof per1mTokens !== \"number\") {\n return null;\n }\n\n return {\n type: \"embedding\",\n per1mTokens,\n };\n }\n\n if (modality === \"image\") {\n const perMegapixel = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\n \"output_per_megapixel\",\n \"per_megapixel\",\n \"input_per_megapixel\",\n \"image_megapixel\",\n \"megapixel\",\n ])\n );\n const perImage = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\n \"per_image\",\n \"image_output_count\",\n \"per_generation\",\n \"generation\",\n \"per_run\",\n \"run\",\n \"predict\",\n ])\n );\n\n if (perImage !== undefined && perMegapixel !== undefined) {\n return { type: \"image\", perImage, perMegapixel };\n }\n\n if (perImage !== undefined) {\n return { type: \"image\", perImage };\n }\n\n if (perMegapixel !== undefined) {\n return { type: \"image\", perMegapixel };\n }\n\n return { type: \"image\" };\n }\n\n if (modality === \"video\") {\n const perSecond = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\"per_second\", \"second\"])\n );\n const perGeneration = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\n \"per_generation\",\n \"generation\",\n \"per_run\",\n \"run\",\n \"predict\",\n ])\n );\n\n if (perSecond !== undefined) {\n return { type: \"video\", perSecond };\n }\n\n return perGeneration !== undefined\n ? { type: \"video\", perGeneration }\n : { type: \"video\" };\n }\n\n if (\n modality === \"audio_tts\" ||\n modality === \"audio_stt\" ||\n modality === \"audio_generation\"\n ) {\n const perMinute = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\"per_minute\", \"minute\"])\n );\n const perCharacter = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\"per_character\", \"character\"])\n );\n const perSecond = normalizeMoneyAmount(\n extractFirstNumericByKey(pricingSources, [\"per_second\", \"second\"])\n );\n\n if (perMinute !== undefined) {\n return { type: \"audio\", perMinute };\n }\n\n if (perCharacter !== undefined) {\n return { type: \"audio\", perCharacter };\n }\n\n return perSecond !== undefined ? { type: \"audio\", perSecond } : { type: \"audio\" };\n }\n\n return null;\n}\n\nfunction toReplicateModelKey(raw: ReplicateModel): string | null {\n const owner = typeof raw.owner === \"string\" ? raw.owner.trim() : \"\";\n const name = typeof raw.name === \"string\" ? raw.name.trim() : \"\";\n if (owner && name) {\n return `${owner}/${name}`;\n }\n\n if (typeof raw.url === \"string\" && raw.url.trim()) {\n try {\n const parsed = new URL(raw.url);\n const path = parsed.pathname.replace(/^\\/+/, \"\");\n return path || null;\n } catch {\n return raw.url.replace(/^https?:\\/\\/[^/]+\\//, \"\") || null;\n }\n }\n\n return null;\n}\n\nfunction extractReplicateOpenApiSchema(\n raw: ReplicateModel\n): Record<string, unknown> | null {\n const candidate = raw.latest_version?.openapi_schema;\n return isRecord(candidate) ? candidate : null;\n}\n\nfunction detectReplicateInputModalities(openApiSchema: Record<string, unknown> | null): string[] {\n const inputSchema = extractReplicateSchemaNode(openApiSchema, \"Input\");\n if (!inputSchema) {\n return [\"text\"];\n }\n\n const text = collectSchemaText(inputSchema);\n const modalities = new Set<string>();\n if (hasAnyKeyword(text, IMAGE_KEYWORDS)) {\n modalities.add(\"image\");\n }\n if (hasAnyKeyword(text, VIDEO_KEYWORDS)) {\n modalities.add(\"video\");\n }\n if (hasAnyKeyword(text, AUDIO_KEYWORDS)) {\n modalities.add(\"audio\");\n }\n if (hasAnyKeyword(text, TEXT_HINT_KEYWORDS) || modalities.size === 0) {\n modalities.add(\"text\");\n }\n\n return Array.from(modalities);\n}\n\nfunction detectReplicateOutputModalities(\n openApiSchema: Record<string, unknown> | null,\n raw: ReplicateModel\n): string[] {\n const outputSchema = extractReplicateSchemaNode(openApiSchema, \"Output\");\n if (!outputSchema) {\n return fallbackModalitiesForModality(inferReplicateModalityFromMetadata(raw)).outputModalities;\n }\n\n const text = collectSchemaText(outputSchema);\n const outputs = new Set<string>();\n\n if (hasAnyKeyword(text, EMBEDDING_KEYWORDS) || isNumericVectorArray(outputSchema)) {\n outputs.add(\"embedding\");\n }\n if (hasAnyKeyword(text, IMAGE_KEYWORDS)) {\n outputs.add(\"image\");\n }\n if (hasAnyKeyword(text, VIDEO_KEYWORDS)) {\n outputs.add(\"video\");\n }\n if (hasAnyKeyword(text, AUDIO_KEYWORDS)) {\n outputs.add(\"audio\");\n }\n\n if (outputs.size === 0 && hasUriLikeFormat(outputSchema)) {\n const inferred = inferReplicateModalityFromMetadata(raw);\n if (inferred === \"video\") {\n outputs.add(\"video\");\n } else if (\n inferred === \"audio_stt\" ||\n inferred === \"audio_tts\" ||\n inferred === \"audio_generation\"\n ) {\n outputs.add(inferred === \"audio_stt\" ? \"text\" : \"audio\");\n } else if (inferred === \"embedding\") {\n outputs.add(\"embedding\");\n } else {\n outputs.add(\"image\");\n }\n }\n\n if (outputs.size === 0) {\n outputs.add(\"text\");\n }\n\n return Array.from(outputs);\n}\n\nfunction inferReplicateModalityFromMetadata(raw: ReplicateModel): Modality {\n const combined = `${raw.owner ?? \"\"}/${raw.name ?? \"\"} ${raw.description ?? \"\"}`.toLowerCase();\n\n if (hasAnyKeyword(combined, EMBEDDING_KEYWORDS)) {\n return \"embedding\";\n }\n if (/(transcrib|speech[\\s-]?to[\\s-]?text|stt|whisper|caption)/.test(combined)) {\n return \"audio_stt\";\n }\n if (/(text[\\s-]?to[\\s-]?speech|tts|voiceover|voice synth|speech synth)/.test(combined)) {\n return \"audio_tts\";\n }\n if (/(music|sound effect|audio generation|text[\\s-]?to[\\s-]?audio)/.test(combined)) {\n return \"audio_generation\";\n }\n if (/(vision|ocr|image understanding|analy[sz]e image|vqa)/.test(combined)) {\n return \"vision\";\n }\n if (hasAnyKeyword(combined, VIDEO_KEYWORDS)) {\n return \"video\";\n }\n if (hasAnyKeyword(combined, IMAGE_KEYWORDS)) {\n return \"image\";\n }\n\n return \"text\";\n}\n\nfunction fallbackModalitiesForModality(modality: Modality): {\n inputModalities: string[];\n outputModalities: string[];\n} {\n switch (modality) {\n case \"image\":\n return { inputModalities: [\"text\"], outputModalities: [\"image\"] };\n case \"video\":\n return { inputModalities: [\"text\"], outputModalities: [\"video\"] };\n case \"audio_stt\":\n return { inputModalities: [\"audio\"], outputModalities: [\"text\"] };\n case \"audio_tts\":\n case \"audio_generation\":\n return { inputModalities: [\"text\"], outputModalities: [\"audio\"] };\n case \"vision\":\n return { inputModalities: [\"image\"], outputModalities: [\"text\"] };\n case \"embedding\":\n return { inputModalities: [\"text\"], outputModalities: [\"embedding\"] };\n case \"multimodal\":\n return { inputModalities: [\"text\", \"image\"], outputModalities: [\"text\", \"image\"] };\n case \"text\":\n default:\n return { inputModalities: [\"text\"], outputModalities: [\"text\"] };\n }\n}\n\nfunction extractReplicateSchemaNode(\n openApiSchema: Record<string, unknown> | null,\n schemaName: \"Input\" | \"Output\"\n): Record<string, unknown> | null {\n if (!openApiSchema) {\n return null;\n }\n\n const components = openApiSchema.components;\n if (!isRecord(components)) {\n return null;\n }\n\n const schemas = components.schemas;\n if (!isRecord(schemas)) {\n return null;\n }\n\n const node = schemas[schemaName];\n return isRecord(node) ? node : null;\n}\n\nfunction collectSchemaText(value: unknown): string {\n try {\n return JSON.stringify(value).toLowerCase();\n } catch {\n return \"\";\n }\n}\n\nfunction hasAnyKeyword(text: string, keywords: string[]): boolean {\n return keywords.some((keyword) => text.includes(keyword));\n}\n\nfunction hasUriLikeFormat(schema: Record<string, unknown>): boolean {\n const text = collectSchemaText(schema);\n return text.includes(\"\\\"format\\\":\\\"uri\\\"\") || text.includes(\"\\\"format\\\":\\\"url\\\"\");\n}\n\nfunction isNumericVectorArray(schema: Record<string, unknown>): boolean {\n const type = typeof schema.type === \"string\" ? schema.type.toLowerCase() : \"\";\n if (type !== \"array\") {\n return false;\n }\n\n const items = schema.items;\n if (!isRecord(items)) {\n return false;\n }\n\n const itemType = typeof items.type === \"string\" ? items.type.toLowerCase() : \"\";\n return itemType === \"number\" || itemType === \"integer\";\n}\n\ninterface NumericEntry {\n key: string;\n value: number;\n}\n\nfunction extractFirstNumericByKey(\n sources: Array<unknown>,\n keyHints: string[]\n): NumericEntry | undefined {\n const normalizedHints = keyHints.map((hint) => hint.toLowerCase());\n const allEntries = sources.flatMap((source) => collectNumericEntries(source));\n\n return allEntries.find((entry) =>\n normalizedHints.some((hint) => entry.key.includes(hint))\n );\n}\n\nfunction collectNumericEntries(\n value: unknown,\n parentKey = \"\",\n depth = 0\n): NumericEntry[] {\n if (depth > 5 || value === null || value === undefined) {\n return [];\n }\n\n if (typeof value === \"number\" && Number.isFinite(value)) {\n return [{ key: parentKey.toLowerCase(), value }];\n }\n\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (/^-?\\d+(\\.\\d+)?$/.test(trimmed)) {\n const parsed = Number.parseFloat(trimmed);\n if (Number.isFinite(parsed)) {\n return [{ key: parentKey.toLowerCase(), value: parsed }];\n }\n }\n return [];\n }\n\n if (Array.isArray(value)) {\n return value.flatMap((item, index) =>\n collectNumericEntries(item, `${parentKey}[${index}]`, depth + 1)\n );\n }\n\n if (!isRecord(value)) {\n return [];\n }\n\n return Object.entries(value).flatMap(([key, nested]) =>\n collectNumericEntries(\n nested,\n parentKey ? `${parentKey}.${key}` : key,\n depth + 1\n )\n );\n}\n\nfunction normalizeTokenPricePer1m(entry: NumericEntry | undefined): number | undefined {\n if (!entry || !Number.isFinite(entry.value) || entry.value <= 0) {\n return undefined;\n }\n\n const key = entry.key;\n let value = entry.value;\n if (key.includes(\"cent\")) {\n value = value / 100;\n }\n\n if (key.includes(\"1m\")) {\n return round(value, 6);\n }\n if (key.includes(\"1k\")) {\n return round(value * 1000, 6);\n }\n if (key.includes(\"token\")) {\n return round(value * 1_000_000, 6);\n }\n if (value < 0.01) {\n return round(value * 1_000_000, 6);\n }\n\n return round(value, 6);\n}\n\nfunction normalizeMoneyAmount(entry: NumericEntry | undefined): number | undefined {\n if (!entry || !Number.isFinite(entry.value) || entry.value <= 0) {\n return undefined;\n }\n\n const cents = entry.key.includes(\"cent\");\n return round(cents ? entry.value / 100 : entry.value, 6);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function classifyFalCategory(category: string): Modality | null {\n const normalized = category.trim().toLowerCase();\n\n if (normalized.includes(\"speech-to-text\") || normalized.includes(\"audio-to-text\")) {\n return \"audio_stt\";\n }\n\n if (normalized.includes(\"text-to-speech\")) {\n return \"audio_tts\";\n }\n\n if (\n normalized.includes(\"text-to-audio\") ||\n normalized.includes(\"audio-to-audio\") ||\n normalized.includes(\"speech-to-speech\") ||\n normalized.includes(\"video-to-audio\") ||\n normalized.includes(\"audio-generation\") ||\n normalized.includes(\"music\")\n ) {\n return \"audio_generation\";\n }\n\n if (\n normalized.includes(\"image-generation\") ||\n normalized.includes(\"text-to-image\") ||\n normalized.includes(\"image-to-image\")\n ) {\n return \"image\";\n }\n\n if (\n normalized.includes(\"image-to-video\") ||\n normalized.includes(\"text-to-video\") ||\n normalized.includes(\"video-generation\") ||\n normalized.includes(\"video-to-video\")\n ) {\n return \"video\";\n }\n\n return null;\n}\n\nfunction normalizeFalPricing(raw: FalModel, modality: Modality): ModelEntry[\"pricing\"] | null {\n const amount = raw.pricing?.amount;\n if (typeof amount !== \"number\" || !Number.isFinite(amount) || amount <= 0) {\n return null;\n }\n\n const priceType = raw.pricing?.type?.toLowerCase() ?? \"\";\n\n if (modality === \"image\") {\n if (priceType === \"per_image\" || priceType === \"per_generation\") {\n return {\n type: \"image\",\n perImage: round(amount, 6),\n };\n }\n\n return {\n type: \"image\",\n perImage: round(amount, 6),\n };\n }\n\n if (modality === \"video\") {\n if (priceType === \"per_second\") {\n return {\n type: \"video\",\n perSecond: round(amount, 6),\n };\n }\n\n return {\n type: \"video\",\n perGeneration: round(amount, 6),\n };\n }\n\n if (\n modality === \"audio_tts\" ||\n modality === \"audio_stt\" ||\n modality === \"audio_generation\"\n ) {\n if (priceType === \"per_minute\") {\n return {\n type: \"audio\",\n perMinute: round(amount, 6),\n };\n }\n\n if (priceType === \"per_character\") {\n return {\n type: \"audio\",\n perCharacter: round(amount, 6),\n };\n }\n\n return {\n type: \"audio\",\n perSecond: round(amount, 6),\n };\n }\n\n return null;\n}\n\nfunction falInputModalities(category: string): string[] {\n const normalized = category.trim().toLowerCase();\n if (normalized.includes(\"image-to-video\")) {\n return [\"image\"];\n }\n\n if (normalized.startsWith(\"image-to-\")) {\n return [\"image\"];\n }\n\n if (normalized.startsWith(\"video-to-\")) {\n return [\"video\"];\n }\n\n if (normalized.startsWith(\"audio-to-\") || normalized.startsWith(\"speech-to-\")) {\n return [\"audio\"];\n }\n\n return [\"text\"];\n}\n\nfunction falOutputModalities(modality: Modality): string[] {\n if (modality === \"image\") {\n return [\"image\"];\n }\n\n if (modality === \"video\") {\n return [\"video\"];\n }\n\n if (modality === \"audio_stt\") {\n return [\"text\"];\n }\n\n if (\n modality === \"audio_tts\" ||\n modality === \"audio_generation\"\n ) {\n return [\"audio\"];\n }\n\n return [\"text\"];\n}\n\nfunction parsePrice(raw: string | undefined): number {\n if (!raw) return 0;\n\n const parsed = Number.parseFloat(raw);\n return Number.isFinite(parsed) ? parsed : 0;\n}\n\nfunction toPositiveNumber(value: number | null | undefined): number | undefined {\n if (typeof value !== \"number\" || !Number.isFinite(value) || value <= 0) {\n return undefined;\n }\n\n return value;\n}\n\nfunction round(value: number, decimals: number): number {\n const factor = 10 ** decimals;\n return Math.round((value + Number.EPSILON) * factor) / factor;\n}\n","import fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport { ExitCode, WhichModelError, type Config } from \"./types.js\";\n\ninterface ConfigFile {\n apiKey?: string;\n recommenderModel?: string;\n falApiKey?: string;\n replicateApiToken?: string;\n elevenLabsApiKey?: string;\n togetherApiKey?: string;\n cacheTtl?: number;\n replicatePriceTtlSeconds?: number;\n replicatePriceMaxStaleSeconds?: number;\n replicatePriceFetchBudget?: number;\n replicatePriceConcurrency?: number;\n}\n\nexport const DEFAULT_RECOMMENDER_MODEL = \"deepseek/deepseek-v3.2\";\nexport const DEFAULT_CACHE_TTL_SECONDS = 3600;\nexport const DEFAULT_REPLICATE_PRICE_TTL_SECONDS = 86_400;\nexport const DEFAULT_REPLICATE_PRICE_MAX_STALE_SECONDS = 604_800;\nexport const DEFAULT_REPLICATE_PRICE_FETCH_BUDGET = 40;\nexport const DEFAULT_REPLICATE_PRICE_CONCURRENCY = 4;\n\nexport function getConfig(): Config {\n const configFile = loadConfigFile();\n\n return {\n apiKey: process.env.OPENROUTER_API_KEY ?? configFile?.apiKey ?? \"\",\n recommenderModel:\n process.env.WHICHMODEL_MODEL ??\n configFile?.recommenderModel ??\n DEFAULT_RECOMMENDER_MODEL,\n cacheTtl: parseIntegerEnv(\"WHICHMODEL_CACHE_TTL\") ?? configFile?.cacheTtl ?? DEFAULT_CACHE_TTL_SECONDS,\n falApiKey: process.env.FAL_API_KEY ?? configFile?.falApiKey,\n replicateApiToken: process.env.REPLICATE_API_TOKEN ?? configFile?.replicateApiToken,\n elevenLabsApiKey: process.env.ELEVENLABS_API_KEY ?? configFile?.elevenLabsApiKey,\n togetherApiKey: process.env.TOGETHER_API_KEY ?? configFile?.togetherApiKey,\n replicatePriceTtlSeconds: resolveIntegerSetting(\n \"WHICHMODEL_REPLICATE_PRICE_TTL_SECONDS\",\n configFile?.replicatePriceTtlSeconds,\n DEFAULT_REPLICATE_PRICE_TTL_SECONDS,\n 1\n ),\n replicatePriceMaxStaleSeconds: resolveIntegerSetting(\n \"WHICHMODEL_REPLICATE_PRICE_MAX_STALE_SECONDS\",\n configFile?.replicatePriceMaxStaleSeconds,\n DEFAULT_REPLICATE_PRICE_MAX_STALE_SECONDS,\n 1\n ),\n replicatePriceFetchBudget: resolveIntegerSetting(\n \"WHICHMODEL_REPLICATE_PRICE_FETCH_BUDGET\",\n configFile?.replicatePriceFetchBudget,\n DEFAULT_REPLICATE_PRICE_FETCH_BUDGET,\n 0\n ),\n replicatePriceConcurrency: resolveIntegerSetting(\n \"WHICHMODEL_REPLICATE_PRICE_CONCURRENCY\",\n configFile?.replicatePriceConcurrency,\n DEFAULT_REPLICATE_PRICE_CONCURRENCY,\n 1\n ),\n };\n}\n\nexport function validateConfig(config: Config): string | null {\n if (!config.apiKey) {\n return [\n \"Error: OPENROUTER_API_KEY is not set.\",\n \"\",\n \"Get your API key at: https://openrouter.ai/keys\",\n \"Then run:\",\n \" export OPENROUTER_API_KEY=sk-or-...\",\n ].join(\"\\n\");\n }\n\n if (!config.apiKey.startsWith(\"sk-or-v1-\")) {\n return \"Warning: API key doesn't look like an OpenRouter key (should start with sk-or-v1-)\";\n }\n\n return null;\n}\n\nexport function requireApiKey(config: Config): void {\n if (!config.apiKey) {\n throw new WhichModelError(\n \"OPENROUTER_API_KEY is not set.\",\n ExitCode.NO_API_KEY,\n \"Set OPENROUTER_API_KEY and retry.\"\n );\n }\n}\n\nfunction loadConfigFile(): ConfigFile | null {\n const configPath = process.env.WHICHMODEL_CONFIG ?? getDefaultConfigPath();\n\n try {\n const raw = fs.readFileSync(configPath, \"utf8\");\n const parsed = JSON.parse(raw) as ConfigFile;\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction getDefaultConfigPath(): string {\n if (process.platform === \"win32\") {\n const appData = process.env.APPDATA ?? os.homedir();\n return path.join(appData, \"whichmodel\", \"config.json\");\n }\n\n return path.join(os.homedir(), \".config\", \"whichmodel\", \"config.json\");\n}\n\nfunction parseIntegerEnv(name: string): number | undefined {\n const value = process.env[name];\n if (!value) {\n return undefined;\n }\n\n const parsed = Number.parseInt(value, 10);\n return Number.isFinite(parsed) ? parsed : undefined;\n}\n\nfunction resolveIntegerSetting(\n envName: string,\n fileValue: number | undefined,\n fallback: number,\n min: number\n): number {\n const envValue = parseIntegerEnv(envName);\n if (typeof envValue === \"number\" && envValue >= min) {\n return envValue;\n }\n\n const configValue =\n typeof fileValue === \"number\" && Number.isFinite(fileValue) ? Math.trunc(fileValue) : undefined;\n if (typeof configValue === \"number\" && configValue >= min) {\n return configValue;\n }\n\n return fallback;\n}\n","import { err, ok, type Result } from \"neverthrow\";\nimport { z } from \"zod\";\nimport { ExitCode, WhichModelError } from \"../types.js\";\n\nconst priceScalarSchema = z.union([z.string(), z.number()]).transform((value) => String(value));\n\nexport const openRouterModelSchema = z\n .object({\n id: z.string().min(1),\n name: z.string().min(1),\n description: z.string().optional(),\n context_length: z.union([z.number().int().nonnegative(), z.null()]).transform((value) => value ?? 0),\n pricing: z.object({\n prompt: priceScalarSchema,\n completion: priceScalarSchema,\n image: priceScalarSchema.optional(),\n request: priceScalarSchema.optional(),\n }),\n architecture: z\n .object({\n modality: z.string().nullable().optional(),\n tokenizer: z.string().nullable().optional(),\n instruct_type: z.string().nullable().optional(),\n input_modalities: z.array(z.string()).nullable().optional(),\n output_modalities: z.array(z.string()).nullable().optional(),\n })\n .nullable()\n .optional(),\n top_provider: z\n .object({\n context_length: z.number().int().nullable().optional(),\n max_completion_tokens: z.number().int().nullable().optional(),\n is_moderated: z.boolean().nullable().optional(),\n })\n .nullable()\n .optional(),\n per_request_limits: z\n .object({\n prompt_tokens: z.number().int().nullable().optional(),\n completion_tokens: z.number().int().nullable().optional(),\n })\n .nullable()\n .optional(),\n })\n .passthrough();\n\nexport const openRouterResponseSchema = z\n .object({\n data: z.array(openRouterModelSchema),\n })\n .passthrough();\n\nconst falPlatformModelSchema = z\n .object({\n endpoint_id: z.string().min(1),\n metadata: z\n .object({\n display_name: z.string().optional(),\n category: z.string().optional(),\n })\n .optional(),\n })\n .passthrough();\n\nexport const falModelsListResponseSchema = z\n .object({\n models: z.array(falPlatformModelSchema),\n has_more: z.boolean().optional(),\n next_cursor: z.string().nullable().optional(),\n })\n .passthrough();\n\nconst falPlatformPriceSchema = z\n .object({\n endpoint_id: z.string().min(1),\n unit_price: z.number(),\n unit: z.string().optional(),\n })\n .passthrough();\n\nexport const falPricingResponseSchema = z\n .object({\n prices: z.array(falPlatformPriceSchema),\n })\n .passthrough();\n\nconst replicateModelSchema = z\n .object({\n url: z.string().optional(),\n owner: z.string().optional().default(\"\"),\n name: z.string().optional().default(\"\"),\n description: z.string().nullable().optional(),\n visibility: z.enum([\"public\", \"private\"]).optional(),\n run_count: z.number().optional(),\n latest_version: z\n .object({\n id: z.string().optional(),\n created_at: z.string().optional(),\n openapi_schema: z.unknown().optional(),\n pricing: z.unknown().optional(),\n })\n .passthrough()\n .nullable()\n .optional(),\n pricing: z.unknown().optional(),\n })\n .passthrough();\n\nexport const replicateModelsResponseSchema = z\n .object({\n next: z.string().nullable().optional(),\n previous: z.string().nullable().optional(),\n results: z.array(replicateModelSchema),\n })\n .passthrough();\n\nexport type OpenRouterResponseParsed = z.infer<typeof openRouterResponseSchema>;\nexport type FalModelsListResponseParsed = z.infer<typeof falModelsListResponseSchema>;\nexport type FalPricingResponseParsed = z.infer<typeof falPricingResponseSchema>;\nexport type ReplicateModelsResponseParsed = z.infer<typeof replicateModelsResponseSchema>;\n\nfunction schemaFailure(label: string): WhichModelError {\n return new WhichModelError(\n `${label} response is invalid.`,\n ExitCode.NETWORK_ERROR,\n \"Retry in a few minutes.\"\n );\n}\n\nexport function parseOpenRouterResponse(\n payload: unknown\n): Result<OpenRouterResponseParsed, WhichModelError> {\n const parsed = openRouterResponseSchema.safeParse(payload);\n return parsed.success ? ok(parsed.data) : err(schemaFailure(\"OpenRouter catalog\"));\n}\n\nexport function parseFalModelsListResponse(\n payload: unknown\n): Result<FalModelsListResponseParsed, WhichModelError> {\n const parsed = falModelsListResponseSchema.safeParse(payload);\n return parsed.success ? ok(parsed.data) : err(schemaFailure(\"fal.ai catalog\"));\n}\n\nexport function parseFalPricingResponse(\n payload: unknown\n): Result<FalPricingResponseParsed, WhichModelError> {\n const parsed = falPricingResponseSchema.safeParse(payload);\n return parsed.success ? ok(parsed.data) : err(schemaFailure(\"fal.ai pricing\"));\n}\n\nexport function parseReplicateModelsResponse(\n payload: unknown\n): Result<ReplicateModelsResponseParsed, WhichModelError> {\n const parsed = replicateModelsResponseSchema.safeParse(payload);\n return parsed.success ? ok(parsed.data) : err(schemaFailure(\"Replicate catalog\"));\n}\n","import type { CatalogSource } from './source.js';\nimport { classifyFalCategory, normalizeFalModel } from './normalization.js';\nimport { readCache, writeCache } from './cache.js';\nimport { DEFAULT_CACHE_TTL_SECONDS } from '../config.js';\nimport {\n parseFalModelsListResponse,\n parseFalPricingResponse\n} from '../schemas/provider-schemas.js';\nimport {\n isAbortError,\n wait,\n withJitter,\n DEFAULT_RETRY_DELAYS_MS\n} from '../utils/common.js';\nimport { wrapResultAsync } from '../utils/result.js';\nimport {\n ExitCode,\n WhichModelError,\n type FalModel,\n type ModelEntry\n} from '../types.js';\n\nconst DEFAULT_MODELS_ENDPOINT = 'https://api.fal.ai/v1/models';\nconst DEFAULT_PRICING_ENDPOINT = 'https://api.fal.ai/v1/models/pricing';\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst DEFAULT_PAGE_SIZE = 200;\nconst PRICING_CHUNK_SIZE = 20;\nconst MAX_MODEL_PAGES = 8;\nconst MAX_CANDIDATE_MODELS = 300;\n\ntype Sleep = (ms: number) => Promise<void>;\n\nexport interface FalCatalogOptions {\n apiKey?: string;\n modelsEndpoint?: string;\n pricingEndpoint?: string;\n timeoutMs?: number;\n retryDelaysMs?: number[];\n fetchImpl?: typeof fetch;\n sleep?: Sleep;\n noCache?: boolean;\n cacheTtl?: number;\n}\n\ninterface FalPlatformModel {\n endpoint_id: string;\n metadata?: {\n display_name?: string;\n category?: string;\n };\n}\n\nexport class FalCatalog implements CatalogSource {\n readonly sourceId = 'fal';\n\n private readonly apiKey?: string;\n private readonly modelsEndpoint: string;\n private readonly pricingEndpoint: string;\n private readonly timeoutMs: number;\n private readonly retryDelaysMs: number[];\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: Sleep;\n private readonly noCache: boolean;\n private readonly cacheTtl: number;\n\n constructor(options: FalCatalogOptions = {}) {\n this.apiKey = options.apiKey;\n this.modelsEndpoint = options.modelsEndpoint ?? DEFAULT_MODELS_ENDPOINT;\n this.pricingEndpoint = options.pricingEndpoint ?? DEFAULT_PRICING_ENDPOINT;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.retryDelaysMs = options.retryDelaysMs ?? [...DEFAULT_RETRY_DELAYS_MS];\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.sleep = options.sleep ?? wait;\n this.noCache = options.noCache ?? false;\n this.cacheTtl = options.cacheTtl ?? DEFAULT_CACHE_TTL_SECONDS;\n }\n\n async fetch(): Promise<ModelEntry[]> {\n if (!this.apiKey) {\n throw new WhichModelError(\n 'FAL_API_KEY is not set.',\n ExitCode.NO_API_KEY,\n 'Set FAL_API_KEY and retry.'\n );\n }\n\n if (!this.noCache) {\n const cached = await readCache(this.sourceId);\n if (cached) {\n return cached;\n }\n }\n\n const platformModels = await this.fetchAllPlatformModels();\n if (platformModels.length === 0) {\n return [];\n }\n\n const priceMap = await this.fetchPricingMap(\n platformModels.map(model => model.endpoint_id)\n );\n const normalizedRaw: FalModel[] = platformModels\n .map(model => this.toFalModel(model, priceMap.get(model.endpoint_id)))\n .filter((model): model is FalModel => model !== null);\n\n const models = normalizedRaw\n .map(model => normalizeFalModel(model))\n .filter((model): model is ModelEntry => model !== null);\n\n if (models.length > 0) {\n await writeCache(this.sourceId, models, this.cacheTtl);\n }\n\n return models;\n }\n\n private async fetchAllPlatformModels(): Promise<FalPlatformModel[]> {\n const all: FalPlatformModel[] = [];\n let cursor: string | undefined;\n let pagesFetched = 0;\n\n for (;;) {\n const params = new URLSearchParams();\n params.set('limit', String(DEFAULT_PAGE_SIZE));\n if (cursor) {\n params.set('cursor', cursor);\n }\n\n const rawPayload = await this.requestJson<unknown>(\n `${this.modelsEndpoint}?${params.toString()}`\n );\n const payloadResult = parseFalModelsListResponse(rawPayload);\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n const payload = payloadResult.value;\n\n all.push(\n ...payload.models.filter(\n model => classifyFalCategory(model.metadata?.category ?? '') !== null\n )\n );\n pagesFetched += 1;\n\n if (\n pagesFetched >= MAX_MODEL_PAGES ||\n all.length >= MAX_CANDIDATE_MODELS\n ) {\n break;\n }\n\n if (!payload.has_more || !payload.next_cursor) {\n break;\n }\n\n cursor = payload.next_cursor;\n }\n\n return [...all]\n .sort((a, b) => a.endpoint_id.localeCompare(b.endpoint_id))\n .slice(0, MAX_CANDIDATE_MODELS);\n }\n\n private async fetchPricingMap(\n endpointIds: string[]\n ): Promise<Map<string, { amount: number; unit?: string }>> {\n const priceMap = new Map<string, { amount: number; unit?: string }>();\n const sortedEndpointIds = [...endpointIds].sort((a, b) =>\n a.localeCompare(b)\n );\n\n for (const chunk of chunked(sortedEndpointIds, PRICING_CHUNK_SIZE)) {\n await this.fetchPricingForChunk(chunk, priceMap);\n }\n\n return priceMap;\n }\n\n private toFalModel(\n model: FalPlatformModel,\n pricing: { amount: number; unit?: string } | undefined\n ): FalModel | null {\n const category = model.metadata?.category;\n if (!category || typeof category !== 'string') {\n return null;\n }\n\n if (\n !pricing ||\n typeof pricing.amount !== 'number' ||\n !Number.isFinite(pricing.amount) ||\n pricing.amount <= 0\n ) {\n return null;\n }\n\n return {\n id: model.endpoint_id,\n name: model.metadata?.display_name?.trim() || model.endpoint_id,\n category,\n pricing: {\n type: this.falUnitToPricingType(category, pricing.unit),\n amount: pricing.amount\n }\n };\n }\n\n private falUnitToPricingType(category: string, unit?: string): string {\n const normalizedUnit = unit?.toLowerCase() ?? '';\n if (normalizedUnit.includes('character')) {\n return 'per_character';\n }\n if (normalizedUnit.includes('minute')) {\n return 'per_minute';\n }\n if (normalizedUnit.includes('second')) {\n return 'per_second';\n }\n if (normalizedUnit.includes('image')) {\n return 'per_image';\n }\n\n const normalized = category.toLowerCase();\n if (normalized.includes('image')) {\n return 'per_image';\n }\n if (normalized.includes('video')) {\n return 'per_generation';\n }\n return 'per_generation';\n }\n\n private async requestJson<T>(url: string): Promise<T> {\n const maxAttempts = this.retryDelaysMs.length + 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n const response = await this.fetchWithTimeout(url);\n\n if (!response.ok) {\n if (\n this.shouldRetryStatus(response.status) &&\n attempt < maxAttempts - 1\n ) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.buildHttpError(response.status);\n }\n\n const payloadResult = await wrapResultAsync(\n () => response.json(),\n () =>\n new WhichModelError(\n 'fal.ai response body is invalid JSON.',\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n )\n );\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n\n return payloadResult.value as T;\n } catch (error) {\n lastError = error;\n\n if (this.shouldRetryError(error) && attempt < maxAttempts - 1) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.toNetworkError(error);\n }\n }\n\n throw this.toNetworkError(lastError);\n }\n\n private async fetchWithTimeout(url: string): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n return await this.fetchImpl(url, {\n method: 'GET',\n headers: {\n Authorization: `Key ${this.apiKey}`,\n 'Content-Type': 'application/json'\n },\n signal: controller.signal\n });\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private async fetchPricingForChunk(\n endpointIds: string[],\n priceMap: Map<string, { amount: number; unit?: string }>\n ): Promise<void> {\n if (endpointIds.length === 0) {\n return;\n }\n\n const params = new URLSearchParams();\n params.set('limit', String(DEFAULT_PAGE_SIZE));\n for (const endpointId of endpointIds) {\n params.append('endpoint_id', endpointId);\n }\n\n try {\n const rawPayload = await this.requestJson<unknown>(\n `${this.pricingEndpoint}?${params.toString()}`\n );\n const payloadResult = parseFalPricingResponse(rawPayload);\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n const payload = payloadResult.value;\n\n for (const price of payload.prices) {\n if (!price || typeof price.endpoint_id !== 'string') {\n continue;\n }\n if (\n typeof price.unit_price !== 'number' ||\n !Number.isFinite(price.unit_price)\n ) {\n continue;\n }\n priceMap.set(price.endpoint_id, {\n amount: price.unit_price,\n unit: price.unit\n });\n }\n } catch (error) {\n const isNotFound =\n error instanceof WhichModelError &&\n error.exitCode === ExitCode.NETWORK_ERROR &&\n /\\(status 404\\)/.test(error.message);\n const isRateLimited =\n error instanceof WhichModelError &&\n error.exitCode === ExitCode.NETWORK_ERROR &&\n /\\(status 429\\)/.test(error.message);\n\n if (isRateLimited) {\n return;\n }\n\n if (!isNotFound) {\n throw error;\n }\n\n if (endpointIds.length === 1) {\n return;\n }\n\n const middle = Math.floor(endpointIds.length / 2);\n await this.fetchPricingForChunk(endpointIds.slice(0, middle), priceMap);\n await this.fetchPricingForChunk(endpointIds.slice(middle), priceMap);\n }\n }\n\n private retryDelayForAttempt(attempt: number): number {\n return (\n this.retryDelaysMs[Math.min(attempt, this.retryDelaysMs.length - 1)] ?? 0\n );\n }\n\n private shouldRetryStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n }\n\n private shouldRetryError(error: unknown): boolean {\n if (error instanceof WhichModelError) {\n return false;\n }\n\n if (isAbortError(error)) {\n return true;\n }\n\n return error instanceof TypeError;\n }\n\n private buildHttpError(status: number): WhichModelError {\n if (status === 401 || status === 403) {\n return new WhichModelError(\n 'Invalid or unauthorized fal.ai API key.',\n ExitCode.NO_API_KEY,\n 'Check FAL_API_KEY at https://fal.ai/dashboard'\n );\n }\n\n if (status >= 500) {\n return new WhichModelError(\n `Unable to fetch fal.ai model catalog (status ${status}).`,\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n );\n }\n\n return new WhichModelError(\n `Unable to fetch fal.ai model catalog (status ${status}).`,\n ExitCode.NETWORK_ERROR,\n 'Check your fal.ai configuration and retry.'\n );\n }\n\n private toNetworkError(error: unknown): WhichModelError {\n if (error instanceof WhichModelError) {\n return error;\n }\n\n if (isAbortError(error)) {\n return new WhichModelError(\n 'Timeout fetching model catalog from fal.ai.',\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n );\n }\n\n const detail =\n error instanceof Error ? error.message : 'Unknown network failure.';\n return new WhichModelError(\n `Failed to fetch model catalog from fal.ai: ${detail}`,\n ExitCode.NETWORK_ERROR,\n 'Check your internet connection and retry.'\n );\n }\n}\nfunction chunked<T>(values: T[], size: number): T[][] {\n if (size <= 0) {\n return [values];\n }\n\n const chunks: T[][] = [];\n for (let i = 0; i < values.length; i += size) {\n chunks.push(values.slice(i, i + size));\n }\n\n return chunks;\n}\n","import type { ModelEntry } from \"../types.js\";\nimport { getModelPrimaryPrice } from \"../model-pricing.js\";\n\nexport function mergeCatalogModels(modelsBySource: ModelEntry[][]): ModelEntry[] {\n const merged = new Map<string, ModelEntry>();\n\n for (const sourceModels of modelsBySource) {\n for (const candidate of sourceModels) {\n const current = merged.get(candidate.id);\n if (!current) {\n merged.set(candidate.id, candidate);\n continue;\n }\n\n if (shouldReplaceModel(current, candidate)) {\n merged.set(candidate.id, candidate);\n }\n }\n }\n\n return [...merged.values()];\n}\n\nfunction shouldReplaceModel(current: ModelEntry, candidate: ModelEntry): boolean {\n const currentCompleteness = completenessScore(current);\n const candidateCompleteness = completenessScore(candidate);\n if (candidateCompleteness !== currentCompleteness) {\n return candidateCompleteness > currentCompleteness;\n }\n\n const currentPrice = primaryPrice(current);\n const candidatePrice = primaryPrice(candidate);\n if (currentPrice !== candidatePrice) {\n return candidatePrice < currentPrice;\n }\n\n return false;\n}\n\nfunction completenessScore(model: ModelEntry): number {\n let score = 0;\n if (typeof model.contextLength === \"number\") score += 1;\n if (typeof model.maxDuration === \"number\") score += 1;\n if (typeof model.maxResolution === \"string\") score += 1;\n if (typeof model.supportsStreaming === \"boolean\") score += 1;\n if (model.inputModalities.length > 0) score += 1;\n if (model.outputModalities.length > 0) score += 1;\n return score;\n}\n\nfunction primaryPrice(model: ModelEntry): number {\n return getModelPrimaryPrice(model);\n}\n","import type { CatalogSource } from './source.js';\nimport { normalizeOpenRouterModel } from './normalization.js';\nimport { readCache, writeCache } from './cache.js';\nimport { DEFAULT_CACHE_TTL_SECONDS } from '../config.js';\nimport { parseOpenRouterResponse } from '../schemas/provider-schemas.js';\nimport {\n isAbortError,\n wait,\n withJitter,\n DEFAULT_RETRY_DELAYS_MS\n} from '../utils/common.js';\nimport { wrapResultAsync } from '../utils/result.js';\nimport {\n ExitCode,\n WhichModelError,\n type ModelEntry\n} from '../types.js';\n\nconst DEFAULT_ENDPOINT = 'https://openrouter.ai/api/v1/models';\nconst DEFAULT_TIMEOUT_MS = 10_000;\n\ntype Sleep = (ms: number) => Promise<void>;\n\nexport interface OpenRouterCatalogOptions {\n endpoint?: string;\n timeoutMs?: number;\n retryDelaysMs?: number[];\n fetchImpl?: typeof fetch;\n sleep?: Sleep;\n noCache?: boolean;\n cacheTtl?: number;\n}\n\nexport class OpenRouterCatalog implements CatalogSource {\n readonly sourceId = 'openrouter';\n\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly retryDelaysMs: number[];\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: Sleep;\n private readonly noCache: boolean;\n private readonly cacheTtl: number;\n\n constructor(options: OpenRouterCatalogOptions = {}) {\n this.endpoint = options.endpoint ?? DEFAULT_ENDPOINT;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.retryDelaysMs = options.retryDelaysMs ?? [...DEFAULT_RETRY_DELAYS_MS];\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.sleep = options.sleep ?? wait;\n this.noCache = options.noCache ?? false;\n this.cacheTtl = options.cacheTtl ?? DEFAULT_CACHE_TTL_SECONDS;\n }\n\n async fetch(): Promise<ModelEntry[]> {\n if (!this.noCache) {\n const cached = await readCache(this.sourceId);\n if (cached) {\n return cached;\n }\n }\n\n const maxAttempts = this.retryDelaysMs.length + 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n const response = await this.fetchWithTimeout();\n\n if (!response.ok) {\n if (\n this.shouldRetryStatus(response.status) &&\n attempt < maxAttempts - 1\n ) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.buildHttpError(response.status);\n }\n\n const rawPayload = await wrapResultAsync(\n () => response.json(),\n () =>\n new WhichModelError(\n 'OpenRouter catalog response is invalid.',\n ExitCode.NETWORK_ERROR,\n 'Try again shortly. If this persists, check https://status.openrouter.ai.'\n )\n );\n if (rawPayload.isErr()) {\n throw rawPayload.error;\n }\n\n const payloadResult = parseOpenRouterResponse(rawPayload.value);\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n const payload = payloadResult.value;\n\n const models = payload.data\n .map(model => normalizeOpenRouterModel(model))\n .filter((model): model is ModelEntry => model !== null);\n\n if (models.length === 0) {\n throw new WhichModelError(\n \"OpenRouter catalog returned no usable models.\",\n ExitCode.NETWORK_ERROR,\n [\n \"This can happen if the upstream catalog schema changed.\",\n \"Retry in a few minutes. If it persists, update whichmodel.\",\n ].join(\"\\n\")\n );\n }\n\n await writeCache(this.sourceId, models, this.cacheTtl);\n\n return models;\n } catch (error) {\n lastError = error;\n\n if (this.shouldRetryError(error) && attempt < maxAttempts - 1) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.toNetworkError(error);\n }\n }\n\n throw this.toNetworkError(lastError);\n }\n\n private async fetchWithTimeout(): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n return await this.fetchImpl(this.endpoint, {\n method: 'GET',\n headers: { Accept: 'application/json' },\n signal: controller.signal\n });\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private retryDelayForAttempt(attempt: number): number {\n return (\n this.retryDelaysMs[Math.min(attempt, this.retryDelaysMs.length - 1)] ?? 0\n );\n }\n\n private shouldRetryStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n }\n\n private shouldRetryError(error: unknown): boolean {\n if (error instanceof WhichModelError) {\n return false;\n }\n\n if (isAbortError(error)) {\n return true;\n }\n\n return error instanceof TypeError;\n }\n\n private buildHttpError(status: number): WhichModelError {\n if (status >= 500) {\n return new WhichModelError(\n `Unable to fetch model catalog (OpenRouter returned ${status}).`,\n ExitCode.NETWORK_ERROR,\n [\n 'OpenRouter may be experiencing temporary issues.',\n 'Retry in a few minutes and check https://status.openrouter.ai.'\n ].join('\\n')\n );\n }\n\n if (status === 429) {\n return new WhichModelError(\n 'OpenRouter rate limit exceeded while fetching the model catalog.',\n ExitCode.NETWORK_ERROR,\n 'Wait a minute and retry.'\n );\n }\n\n return new WhichModelError(\n `Unable to fetch model catalog (OpenRouter returned ${status}).`,\n ExitCode.NETWORK_ERROR,\n 'Check your network connection and retry.'\n );\n }\n\n private toNetworkError(error: unknown): WhichModelError {\n if (error instanceof WhichModelError) {\n return error;\n }\n\n if (isAbortError(error)) {\n return new WhichModelError(\n 'Timeout fetching model catalog from OpenRouter.',\n ExitCode.NETWORK_ERROR,\n [\n 'This can be caused by a slow network or temporary API issues.',\n 'Retry in a few minutes and check https://status.openrouter.ai.'\n ].join('\\n')\n );\n }\n\n const detail =\n error instanceof Error ? error.message : 'Unknown network failure.';\n\n return new WhichModelError(\n `Failed to fetch model catalog from OpenRouter: ${detail}`,\n ExitCode.NETWORK_ERROR,\n 'Check your internet connection and retry. Status page: https://status.openrouter.ai'\n );\n }\n}\n","import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { getCacheDir } from \"./cache.js\";\nimport type {\n ReplicatePricingCacheFile,\n ReplicatePricingEntry,\n ReplicatePricingSource,\n} from \"../types.js\";\n\nexport const REPLICATE_PRICING_CACHE_FILENAME = \"replicate-pricing.json\";\nexport const DEFAULT_REPLICATE_PRICING_CACHE_MAX_ENTRIES = 2_000;\n\ninterface ReplicatePricingUpdate {\n modelKey: string;\n pricing: Record<string, number>;\n source: ReplicatePricingSource;\n}\n\nexport interface ReplicatePricingLookup {\n state: \"fresh\" | \"stale\" | \"expired\" | \"missing\";\n entry?: ReplicatePricingEntry;\n}\n\nexport function getReplicatePricingCachePath(): string {\n return path.join(getCacheDir(), REPLICATE_PRICING_CACHE_FILENAME);\n}\n\nexport async function readReplicatePricingCache(): Promise<ReplicatePricingCacheFile> {\n const cachePath = getReplicatePricingCachePath();\n\n try {\n const raw = await fs.readFile(cachePath, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<ReplicatePricingCacheFile>;\n if (!parsed || typeof parsed !== \"object\" || !parsed.entries) {\n return emptyReplicatePricingCache();\n }\n\n const entries = sanitizeEntries(parsed.entries);\n return {\n version: 1,\n updatedAt:\n typeof parsed.updatedAt === \"number\" && Number.isFinite(parsed.updatedAt)\n ? Math.trunc(parsed.updatedAt)\n : 0,\n entries,\n };\n } catch {\n return emptyReplicatePricingCache();\n }\n}\n\nexport async function writeReplicatePricingCache(\n cache: ReplicatePricingCacheFile,\n maxEntries = DEFAULT_REPLICATE_PRICING_CACHE_MAX_ENTRIES\n): Promise<void> {\n const pruned = pruneOldestEntries(cache, maxEntries);\n const cacheDir = getCacheDir();\n const cachePath = getReplicatePricingCachePath();\n\n await fs.mkdir(cacheDir, { recursive: true, mode: 0o700 });\n const tempPath = `${cachePath}.tmp`;\n await fs.writeFile(tempPath, JSON.stringify(pruned, null, 2), { mode: 0o600 });\n await fs.rename(tempPath, cachePath);\n}\n\nexport function resolveReplicatePricingEntry(\n cache: ReplicatePricingCacheFile,\n modelKey: string,\n nowEpochSeconds: number,\n maxStaleSeconds: number\n): ReplicatePricingLookup {\n const entry = cache.entries[modelKey];\n if (!entry) {\n return { state: \"missing\" };\n }\n\n if (entry.expiresAt > nowEpochSeconds) {\n return { state: \"fresh\", entry };\n }\n\n if (entry.fetchedAt + maxStaleSeconds >= nowEpochSeconds) {\n return { state: \"stale\", entry };\n }\n\n return { state: \"expired\" };\n}\n\nexport function applyReplicatePricingUpdates(\n cache: ReplicatePricingCacheFile,\n updates: ReplicatePricingUpdate[],\n ttlSeconds: number,\n nowEpochSeconds: number\n): ReplicatePricingCacheFile {\n if (updates.length === 0) {\n return cache;\n }\n\n const entries: Record<string, ReplicatePricingEntry> = { ...cache.entries };\n for (const update of updates) {\n if (!update.modelKey) {\n continue;\n }\n\n entries[update.modelKey] = {\n pricing: sanitizePricing(update.pricing),\n source: update.source,\n fetchedAt: nowEpochSeconds,\n expiresAt: nowEpochSeconds + ttlSeconds,\n };\n }\n\n return {\n version: 1,\n updatedAt: nowEpochSeconds,\n entries,\n };\n}\n\nfunction pruneOldestEntries(\n cache: ReplicatePricingCacheFile,\n maxEntries: number\n): ReplicatePricingCacheFile {\n if (maxEntries <= 0) {\n return {\n version: 1,\n updatedAt: cache.updatedAt,\n entries: {},\n };\n }\n\n const entries = Object.entries(cache.entries);\n if (entries.length <= maxEntries) {\n return cache;\n }\n\n entries.sort((a, b) => {\n const aFetched = a[1].fetchedAt;\n const bFetched = b[1].fetchedAt;\n if (aFetched !== bFetched) {\n return bFetched - aFetched;\n }\n return a[0].localeCompare(b[0]);\n });\n\n const kept = entries.slice(0, maxEntries);\n return {\n version: 1,\n updatedAt: cache.updatedAt,\n entries: Object.fromEntries(kept),\n };\n}\n\nfunction sanitizeEntries(\n entries: Record<string, unknown>\n): Record<string, ReplicatePricingEntry> {\n const result: Record<string, ReplicatePricingEntry> = {};\n for (const [key, value] of Object.entries(entries)) {\n if (!isRecord(value)) {\n continue;\n }\n\n const source =\n value.source === \"billingConfig\" || value.source === \"price-string\"\n ? value.source\n : null;\n const fetchedAt =\n typeof value.fetchedAt === \"number\" && Number.isFinite(value.fetchedAt)\n ? Math.trunc(value.fetchedAt)\n : null;\n const expiresAt =\n typeof value.expiresAt === \"number\" && Number.isFinite(value.expiresAt)\n ? Math.trunc(value.expiresAt)\n : null;\n if (!source || fetchedAt === null || expiresAt === null) {\n continue;\n }\n\n result[key] = {\n pricing: sanitizePricing(value.pricing),\n source,\n fetchedAt,\n expiresAt,\n };\n }\n\n return result;\n}\n\nfunction sanitizePricing(value: unknown): Record<string, number> {\n if (!isRecord(value)) {\n return {};\n }\n\n const result: Record<string, number> = {};\n for (const [key, nested] of Object.entries(value)) {\n if (typeof nested !== \"number\" || !Number.isFinite(nested) || nested <= 0) {\n continue;\n }\n result[key] = nested;\n }\n\n return result;\n}\n\nfunction emptyReplicatePricingCache(): ReplicatePricingCacheFile {\n return {\n version: 1,\n updatedAt: 0,\n entries: {},\n };\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import type { ReplicatePricingSource } from \"../types.js\";\n\nconst REPLICATE_PAGE_BASE_URL = \"https://replicate.com\";\nconst JSON_SCRIPT_PATTERN =\n /<script\\b[^>]*\\btype=[\"']application\\/json[\"'][^>]*>([\\s\\S]*?)<\\/script>/gi;\nconst DEFAULT_TIMEOUT_MS = 3_000;\nconst DEFAULT_MAX_BODY_BYTES = 2_000_000;\n\ntype PricingCategory = \"text\" | \"image\" | \"time\" | \"audio\";\n\nexport interface ReplicatePagePricingResult {\n pricing: Record<string, number>;\n source: ReplicatePricingSource;\n}\n\nexport interface FetchReplicatePagePricingOptions {\n fetchImpl?: typeof fetch;\n timeoutMs?: number;\n maxBodyBytes?: number;\n}\n\nexport async function fetchReplicatePagePricing(\n modelKey: string,\n options: FetchReplicatePagePricingOptions = {}\n): Promise<ReplicatePagePricingResult | null> {\n const fetchImpl = options.fetchImpl ?? fetch;\n const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n const maxBodyBytes = options.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;\n const url = buildReplicateModelUrl(modelKey);\n if (!url || !isAllowedReplicateUrl(url)) {\n return null;\n }\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), timeoutMs);\n\n try {\n const response = await fetchImpl(url.toString(), {\n method: \"GET\",\n headers: {\n Accept: \"text/html,application/xhtml+xml\",\n },\n signal: controller.signal,\n });\n if (!response.ok) {\n return null;\n }\n\n const html = await readResponseTextWithLimit(response, maxBodyBytes);\n if (!html) {\n return null;\n }\n\n return parseReplicatePagePricingFromHtml(html);\n } catch {\n return null;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n\nexport function parseReplicatePagePricingFromHtml(\n html: string\n): ReplicatePagePricingResult | null {\n const parsedScripts = extractJsonScripts(html);\n let foundBillingConfig = false;\n\n for (const script of parsedScripts) {\n const billingConfig = findBillingConfig(script);\n if (!billingConfig) {\n continue;\n }\n foundBillingConfig = true;\n\n const pricing = normalizeBillingConfigPricing(billingConfig);\n if (pricing) {\n return {\n pricing,\n source: \"billingConfig\",\n };\n }\n }\n\n if (foundBillingConfig) {\n // Avoid falling back to generic page-level `price` when structured billing\n // exists but cannot be mapped conservatively.\n return null;\n }\n\n for (const script of parsedScripts) {\n const pricing = normalizePriceStringFallback(script);\n if (pricing) {\n return {\n pricing,\n source: \"price-string\",\n };\n }\n }\n\n return null;\n}\n\nfunction buildReplicateModelUrl(modelKey: string): URL | null {\n const parts = modelKey.split(\"/\");\n if (parts.length !== 2) {\n return null;\n }\n\n const [owner, name] = parts;\n if (!owner || !name) {\n return null;\n }\n\n if (!isSafePathSegment(owner) || !isSafePathSegment(name)) {\n return null;\n }\n\n return new URL(`/${owner}/${name}`, REPLICATE_PAGE_BASE_URL);\n}\n\nfunction isSafePathSegment(value: string): boolean {\n return /^[a-z0-9._-]+$/i.test(value);\n}\n\nfunction isAllowedReplicateUrl(url: URL): boolean {\n return url.protocol === \"https:\" && url.hostname === \"replicate.com\";\n}\n\nfunction extractJsonScripts(html: string): unknown[] {\n const scripts: unknown[] = [];\n for (const match of html.matchAll(JSON_SCRIPT_PATTERN)) {\n const payload = match[1];\n if (!payload) {\n continue;\n }\n\n try {\n scripts.push(JSON.parse(payload));\n } catch {\n // Ignore malformed JSON script blocks.\n }\n }\n\n return scripts;\n}\n\nfunction findBillingConfig(value: unknown): Record<string, unknown> | null {\n if (!isRecord(value)) {\n return null;\n }\n\n const directCandidate = value.billingConfig;\n if (isRecord(directCandidate)) {\n return directCandidate;\n }\n\n for (const nested of Object.values(value)) {\n if (nested && typeof nested === \"object\") {\n const found = findBillingConfig(nested);\n if (found) {\n return found;\n }\n }\n }\n\n return null;\n}\n\nfunction normalizeBillingConfigPricing(\n billingConfig: Record<string, unknown>\n): Record<string, number> | null {\n const tiers = billingConfig.current_tiers;\n if (!Array.isArray(tiers)) {\n return null;\n }\n\n const normalized: Record<string, number> = {};\n let category: PricingCategory | null = null;\n\n for (const tier of tiers) {\n if (!isRecord(tier) || !Array.isArray(tier.prices)) {\n continue;\n }\n\n for (const priceEntry of tier.prices) {\n const mapped = normalizePriceEntry(priceEntry);\n if (!mapped) {\n continue;\n }\n\n if (category && category !== mapped.category) {\n return null;\n }\n category = mapped.category;\n\n if (!(mapped.key in normalized)) {\n normalized[mapped.key] = mapped.value;\n }\n }\n }\n\n return Object.keys(normalized).length > 0 ? normalized : null;\n}\n\nfunction normalizePriceStringFallback(value: unknown): Record<string, number> | null {\n if (!isRecord(value) || typeof value.price !== \"string\") {\n return null;\n }\n\n const parsedAmount = parseCurrencyAmount(value.price);\n if (parsedAmount === undefined) {\n return null;\n }\n\n const mapped = mapPriceTextToPricing(value.price, parsedAmount, \"\");\n if (!mapped) {\n return null;\n }\n\n return { [mapped.key]: mapped.value };\n}\n\nfunction normalizePriceEntry(\n entry: unknown\n): { category: PricingCategory; key: string; value: number } | null {\n if (!isRecord(entry)) {\n return null;\n }\n\n const rawPrice = typeof entry.price === \"string\" ? entry.price : \"\";\n const amount = parseCurrencyAmount(rawPrice);\n if (amount === undefined) {\n return null;\n }\n\n const metric = typeof entry.metric === \"string\" ? entry.metric.toLowerCase() : \"\";\n const title = typeof entry.title === \"string\" ? entry.title : \"\";\n const metricDisplay =\n typeof entry.metric_display === \"string\" ? entry.metric_display : \"\";\n const description = typeof entry.description === \"string\" ? entry.description : \"\";\n const hint = [title, metricDisplay, description].join(\" \").toLowerCase();\n\n return mapPriceTextToPricing(hint, amount, metric);\n}\n\nfunction mapPriceTextToPricing(\n text: string,\n amount: number,\n metric: string\n): { category: PricingCategory; key: string; value: number } | null {\n const normalizedText = text.toLowerCase();\n const hasPerMillion = normalizedText.includes(\"per million\");\n const hasPerThousand = normalizedText.includes(\"per thousand\");\n const hasPerCharacter = /\\bper (?:input |output )?character\\b/.test(normalizedText);\n\n const isInputToken =\n metric.includes(\"token_input\") || /\\binput token/.test(normalizedText);\n const isOutputToken =\n metric.includes(\"token_output\") || /\\boutput token/.test(normalizedText);\n\n if (isInputToken || isOutputToken) {\n if (!hasPerMillion && !hasPerThousand) {\n return null;\n }\n const tokenValue = hasPerThousand ? round(amount * 1000) : round(amount);\n return {\n category: \"text\",\n key: isInputToken ? \"input_per_1m\" : \"output_per_1m\",\n value: tokenValue,\n };\n }\n\n const isInputCharacter =\n metric.includes(\"character_input\") || /\\binput character/.test(normalizedText);\n const isOutputCharacter =\n metric.includes(\"character_output\") || /\\boutput character/.test(normalizedText);\n const isCharacter =\n isInputCharacter || isOutputCharacter || metric.includes(\"character\");\n if (isCharacter || hasPerCharacter) {\n if (!hasPerMillion && !hasPerThousand && !hasPerCharacter) {\n return null;\n }\n\n let perCharacter = amount;\n if (hasPerThousand) {\n perCharacter = amount / 1000;\n } else if (hasPerMillion) {\n perCharacter = amount / 1_000_000;\n }\n\n return {\n category: \"audio\",\n key: \"per_character\",\n value: round(perCharacter),\n };\n }\n\n const isInputImageMegapixel =\n metric.includes(\"image_input_megapixel\") ||\n /\\binput image megapixel\\b/.test(normalizedText);\n const isOutputImageMegapixel =\n metric.includes(\"image_output_megapixel\") ||\n /\\boutput image megapixel\\b/.test(normalizedText);\n const isImageMegapixel =\n isInputImageMegapixel ||\n isOutputImageMegapixel ||\n /\\bimage megapixel\\b/.test(normalizedText);\n if (isImageMegapixel) {\n const perMegapixel = hasPerThousand ? amount / 1000 : amount;\n return {\n category: \"image\",\n key: isOutputImageMegapixel\n ? \"output_per_megapixel\"\n : isInputImageMegapixel\n ? \"input_per_megapixel\"\n : \"per_megapixel\",\n value: round(perMegapixel),\n };\n }\n\n const isOutputImage =\n metric.includes(\"image_output\") || /\\boutput image/.test(normalizedText);\n if (isOutputImage) {\n if (hasPerThousand) {\n return {\n category: \"image\",\n key: \"per_image\",\n value: round(amount / 1000),\n };\n }\n return {\n category: \"image\",\n key: \"per_image\",\n value: round(amount),\n };\n }\n\n if (\n /\\bper second\\b/.test(normalizedText) ||\n /\\bsecond of output video\\b/.test(normalizedText)\n ) {\n return {\n category: \"time\",\n key: \"per_second\",\n value: round(amount),\n };\n }\n\n if (/\\bper minute\\b/.test(normalizedText)) {\n return {\n category: \"audio\",\n key: \"per_minute\",\n value: round(amount),\n };\n }\n\n return null;\n}\n\nfunction parseCurrencyAmount(raw: string): number | undefined {\n const match = raw.match(/\\$?\\s*([0-9]+(?:\\.[0-9]+)?)/);\n if (!match) {\n return undefined;\n }\n\n const amount = Number.parseFloat(match[1] ?? \"\");\n if (!Number.isFinite(amount) || amount <= 0) {\n return undefined;\n }\n\n return amount;\n}\n\nasync function readResponseTextWithLimit(\n response: Response,\n maxBodyBytes: number\n): Promise<string | null> {\n const contentLength = response.headers.get(\"content-length\");\n if (contentLength) {\n const parsed = Number.parseInt(contentLength, 10);\n if (Number.isFinite(parsed) && parsed > maxBodyBytes) {\n return null;\n }\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n const text = await response.text();\n return Buffer.byteLength(text, \"utf8\") > maxBodyBytes ? null : text;\n }\n\n const chunks: Uint8Array[] = [];\n let totalBytes = 0;\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n break;\n }\n if (!value) {\n continue;\n }\n\n totalBytes += value.byteLength;\n if (totalBytes > maxBodyBytes) {\n await reader.cancel();\n return null;\n }\n chunks.push(value);\n }\n\n const merged = new Uint8Array(totalBytes);\n let offset = 0;\n for (const chunk of chunks) {\n merged.set(chunk, offset);\n offset += chunk.byteLength;\n }\n\n return new TextDecoder().decode(merged);\n}\n\nfunction round(value: number): number {\n return Math.round(value * 1_000_000) / 1_000_000;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import type { CatalogSource } from './source.js';\nimport { normalizeReplicateModel } from './normalization.js';\nimport { readCache, writeCache } from './cache.js';\nimport {\n DEFAULT_CACHE_TTL_SECONDS,\n DEFAULT_REPLICATE_PRICE_CONCURRENCY,\n DEFAULT_REPLICATE_PRICE_FETCH_BUDGET,\n DEFAULT_REPLICATE_PRICE_MAX_STALE_SECONDS,\n DEFAULT_REPLICATE_PRICE_TTL_SECONDS\n} from '../config.js';\nimport { parseReplicateModelsResponse } from '../schemas/provider-schemas.js';\nimport {\n applyReplicatePricingUpdates,\n readReplicatePricingCache,\n resolveReplicatePricingEntry,\n writeReplicatePricingCache\n} from './replicate-pricing-cache.js';\nimport { fetchReplicatePagePricing } from './replicate-page-pricing.js';\nimport {\n isAbortError,\n wait,\n withJitter,\n DEFAULT_RETRY_DELAYS_MS\n} from '../utils/common.js';\nimport { wrapResultAsync } from '../utils/result.js';\nimport {\n ExitCode,\n WhichModelError,\n type ModelEntry,\n type ReplicateModel\n} from '../types.js';\n\nconst DEFAULT_ENDPOINT = 'https://api.replicate.com/v1/models';\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst MAX_MODEL_PAGES = 8;\nconst MAX_CANDIDATE_MODELS = 300;\nconst REPLICATE_PAGE_TIMEOUT_MS = 3_000;\n\ntype Sleep = (ms: number) => Promise<void>;\n\nexport interface ReplicateCatalogOptions {\n apiToken?: string;\n endpoint?: string;\n timeoutMs?: number;\n retryDelaysMs?: number[];\n fetchImpl?: typeof fetch;\n sleep?: Sleep;\n noCache?: boolean;\n cacheTtl?: number;\n replicatePriceTtlSeconds?: number;\n replicatePriceMaxStaleSeconds?: number;\n replicatePriceFetchBudget?: number;\n replicatePriceConcurrency?: number;\n}\n\nexport class ReplicateCatalog implements CatalogSource {\n readonly sourceId = 'replicate';\n\n private readonly apiToken?: string;\n private readonly endpoint: string;\n private readonly timeoutMs: number;\n private readonly retryDelaysMs: number[];\n private readonly fetchImpl: typeof fetch;\n private readonly sleep: Sleep;\n private readonly noCache: boolean;\n private readonly cacheTtl: number;\n private readonly replicatePriceTtlSeconds: number;\n private readonly replicatePriceMaxStaleSeconds: number;\n private readonly replicatePriceFetchBudget: number;\n private readonly replicatePriceConcurrency: number;\n\n constructor(options: ReplicateCatalogOptions = {}) {\n this.apiToken = options.apiToken;\n this.endpoint = options.endpoint ?? DEFAULT_ENDPOINT;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n this.retryDelaysMs = options.retryDelaysMs ?? [...DEFAULT_RETRY_DELAYS_MS];\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.sleep = options.sleep ?? wait;\n this.noCache = options.noCache ?? false;\n this.cacheTtl = options.cacheTtl ?? DEFAULT_CACHE_TTL_SECONDS;\n this.replicatePriceTtlSeconds =\n options.replicatePriceTtlSeconds ?? DEFAULT_REPLICATE_PRICE_TTL_SECONDS;\n this.replicatePriceMaxStaleSeconds =\n options.replicatePriceMaxStaleSeconds ??\n DEFAULT_REPLICATE_PRICE_MAX_STALE_SECONDS;\n this.replicatePriceFetchBudget =\n options.replicatePriceFetchBudget ?? DEFAULT_REPLICATE_PRICE_FETCH_BUDGET;\n this.replicatePriceConcurrency =\n options.replicatePriceConcurrency ?? DEFAULT_REPLICATE_PRICE_CONCURRENCY;\n }\n\n async fetch(): Promise<ModelEntry[]> {\n if (!this.apiToken) {\n throw new WhichModelError(\n 'REPLICATE_API_TOKEN is not set.',\n ExitCode.NO_API_KEY,\n 'Set REPLICATE_API_TOKEN and retry.'\n );\n }\n\n if (!this.noCache) {\n const cached = await readCache(this.sourceId);\n if (cached) {\n return cached;\n }\n }\n\n const rawModels = await this.fetchAllModels();\n const enrichedRawModels = await this.enrichMissingPricing(rawModels);\n const models = enrichedRawModels\n .map(model => normalizeReplicateModel(model))\n .filter((model): model is ModelEntry => model !== null);\n\n if (models.length > 0) {\n await writeCache(this.sourceId, models, this.cacheTtl);\n }\n\n return models;\n }\n\n private async enrichMissingPricing(\n rawModels: ReplicateModel[]\n ): Promise<ReplicateModel[]> {\n const budget = Math.max(0, this.replicatePriceFetchBudget);\n const concurrency = Math.max(1, this.replicatePriceConcurrency);\n if (budget === 0) {\n return rawModels;\n }\n\n const now = this.nowEpochSeconds();\n let cache = await readReplicatePricingCache();\n const refreshQueue: Array<{ key: string; model: ReplicateModel }> = [];\n\n for (const model of rawModels) {\n if (this.hasApiPricing(model)) {\n continue;\n }\n\n const key = this.modelKey(model);\n if (!key || key === '/') {\n continue;\n }\n\n const lookup = resolveReplicatePricingEntry(\n cache,\n key,\n now,\n this.replicatePriceMaxStaleSeconds\n );\n\n if (lookup.state === 'fresh' || lookup.state === 'stale') {\n this.applyEnrichedPricing(model, lookup.entry?.pricing);\n }\n\n if (lookup.state !== 'fresh' && refreshQueue.length < budget) {\n refreshQueue.push({ key, model });\n }\n }\n\n if (refreshQueue.length === 0) {\n return rawModels;\n }\n\n const updates = await this.runWithConcurrency(refreshQueue, concurrency, async item => {\n const result = await fetchReplicatePagePricing(item.key, {\n fetchImpl: this.fetchImpl,\n timeoutMs: REPLICATE_PAGE_TIMEOUT_MS\n });\n if (!result || Object.keys(result.pricing).length === 0) {\n return null;\n }\n\n this.applyEnrichedPricing(item.model, result.pricing);\n return {\n modelKey: item.key,\n pricing: result.pricing,\n source: result.source\n };\n });\n\n const validUpdates = updates.filter(\n (\n update\n ): update is {\n modelKey: string;\n pricing: Record<string, number>;\n source: 'billingConfig' | 'price-string';\n } => update !== null\n );\n\n if (validUpdates.length > 0) {\n cache = applyReplicatePricingUpdates(\n cache,\n validUpdates,\n this.replicatePriceTtlSeconds,\n now\n );\n await writeReplicatePricingCache(cache);\n }\n\n return rawModels;\n }\n\n private async fetchAllModels(): Promise<ReplicateModel[]> {\n const all: ReplicateModel[] = [];\n let nextUrl: string | null = this.endpoint;\n let pagesFetched = 0;\n\n while (\n nextUrl &&\n pagesFetched < MAX_MODEL_PAGES &&\n all.length < MAX_CANDIDATE_MODELS\n ) {\n const rawPayload = await this.requestJson<unknown>(nextUrl);\n const payloadResult = parseReplicateModelsResponse(rawPayload);\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n const payload = payloadResult.value;\n\n for (const model of payload.results) {\n if (model?.visibility === 'private') {\n continue;\n }\n all.push(model);\n if (all.length >= MAX_CANDIDATE_MODELS) {\n break;\n }\n }\n\n pagesFetched += 1;\n nextUrl = this.toNextUrl(payload.next);\n }\n\n return [...all]\n .sort((a, b) => {\n const runA = typeof a.run_count === 'number' ? a.run_count : -1;\n const runB = typeof b.run_count === 'number' ? b.run_count : -1;\n if (runA !== runB) {\n return runB - runA;\n }\n\n return this.modelKey(a).localeCompare(this.modelKey(b));\n })\n .slice(0, MAX_CANDIDATE_MODELS);\n }\n\n private modelKey(model: ReplicateModel): string {\n const owner = typeof model.owner === 'string' ? model.owner.trim() : '';\n const name = typeof model.name === 'string' ? model.name.trim() : '';\n return `${owner}/${name}`;\n }\n\n private hasApiPricing(model: ReplicateModel): boolean {\n return (\n this.hasNonEmptyPricing(model.pricing) ||\n this.hasNonEmptyPricing(model.latest_version?.pricing)\n );\n }\n\n private hasNonEmptyPricing(value: unknown): boolean {\n if (value === null || value === undefined) {\n return false;\n }\n if (typeof value === 'string') {\n return value.trim().length > 0;\n }\n if (typeof value === 'number') {\n return Number.isFinite(value);\n }\n if (Array.isArray(value)) {\n return value.length > 0;\n }\n if (typeof value === 'object') {\n return Object.keys(value as Record<string, unknown>).length > 0;\n }\n return false;\n }\n\n private applyEnrichedPricing(\n model: ReplicateModel,\n pricing: Record<string, number> | undefined\n ): void {\n if (!pricing || Object.keys(pricing).length === 0) {\n return;\n }\n model.pricing = { ...pricing };\n }\n\n private nowEpochSeconds(): number {\n return Math.floor(Date.now() / 1000);\n }\n\n private async runWithConcurrency<TItem, TResult>(\n items: TItem[],\n concurrency: number,\n worker: (item: TItem) => Promise<TResult>\n ): Promise<TResult[]> {\n if (items.length === 0) {\n return [];\n }\n\n const results = new Array<TResult>(items.length);\n let index = 0;\n const workers = Array.from({\n length: Math.min(Math.max(1, concurrency), items.length)\n }).map(async () => {\n while (true) {\n const current = index;\n index += 1;\n if (current >= items.length) {\n return;\n }\n\n results[current] = await worker(items[current] as TItem);\n }\n });\n\n await Promise.all(workers);\n return results;\n }\n\n private toNextUrl(next: string | null | undefined): string | null {\n if (!next) {\n return null;\n }\n\n if (/^https?:\\/\\//i.test(next)) {\n return next;\n }\n\n try {\n return new URL(next, this.endpoint).toString();\n } catch {\n return null;\n }\n }\n\n private async requestJson<T>(url: string): Promise<T> {\n const maxAttempts = this.retryDelaysMs.length + 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt += 1) {\n try {\n const response = await this.fetchWithTimeout(url);\n if (!response.ok) {\n if (\n this.shouldRetryStatus(response.status) &&\n attempt < maxAttempts - 1\n ) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.buildHttpError(response.status);\n }\n\n const payloadResult = await wrapResultAsync(\n () => response.json(),\n () =>\n new WhichModelError(\n 'Replicate response body is invalid JSON.',\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n )\n );\n if (payloadResult.isErr()) {\n throw payloadResult.error;\n }\n\n return payloadResult.value as T;\n } catch (error) {\n lastError = error;\n\n if (this.shouldRetryError(error) && attempt < maxAttempts - 1) {\n await this.sleep(withJitter(this.retryDelayForAttempt(attempt)));\n continue;\n }\n\n throw this.toNetworkError(error);\n }\n }\n\n throw this.toNetworkError(lastError);\n }\n\n private async fetchWithTimeout(url: string): Promise<Response> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n return await this.fetchImpl(url, {\n method: 'GET',\n headers: {\n Authorization: `Bearer ${this.apiToken}`,\n Accept: 'application/json'\n },\n signal: controller.signal\n });\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private retryDelayForAttempt(attempt: number): number {\n return (\n this.retryDelaysMs[Math.min(attempt, this.retryDelaysMs.length - 1)] ?? 0\n );\n }\n\n private shouldRetryStatus(status: number): boolean {\n return status === 408 || status === 429 || status >= 500;\n }\n\n private shouldRetryError(error: unknown): boolean {\n if (error instanceof WhichModelError) {\n return false;\n }\n\n if (isAbortError(error)) {\n return true;\n }\n\n return error instanceof TypeError;\n }\n\n private buildHttpError(status: number): WhichModelError {\n if (status === 401 || status === 403) {\n return new WhichModelError(\n 'Invalid or unauthorized Replicate API token.',\n ExitCode.NO_API_KEY,\n 'Check REPLICATE_API_TOKEN at https://replicate.com/account/api-tokens'\n );\n }\n\n if (status === 429) {\n return new WhichModelError(\n 'Replicate rate limit exceeded while fetching the model catalog.',\n ExitCode.NETWORK_ERROR,\n 'Wait a minute and retry.'\n );\n }\n\n if (status >= 500) {\n return new WhichModelError(\n `Unable to fetch Replicate model catalog (status ${status}).`,\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n );\n }\n\n return new WhichModelError(\n `Unable to fetch Replicate model catalog (status ${status}).`,\n ExitCode.NETWORK_ERROR,\n 'Check your network connection and retry.'\n );\n }\n\n private toNetworkError(error: unknown): WhichModelError {\n if (error instanceof WhichModelError) {\n return error;\n }\n\n if (isAbortError(error)) {\n return new WhichModelError(\n 'Timeout fetching model catalog from Replicate.',\n ExitCode.NETWORK_ERROR,\n 'Retry in a few minutes.'\n );\n }\n\n const detail =\n error instanceof Error ? error.message : 'Unknown network failure.';\n return new WhichModelError(\n `Failed to fetch model catalog from Replicate: ${detail}`,\n ExitCode.NETWORK_ERROR,\n 'Check your internet connection and retry.'\n );\n }\n}\n","import type { JSONOutput, Recommendation, RecommendationMeta } from \"../types.js\";\n\nexport function toJsonOutput(\n task: string,\n recommendation: Recommendation,\n meta: RecommendationMeta\n): JSONOutput {\n return {\n task,\n taskAnalysis: recommendation.taskAnalysis,\n recommendations: recommendation.recommendations,\n alternativesInOtherModalities: recommendation.alternativesInOtherModalities,\n meta,\n };\n}\n","import chalk, { Chalk } from \"chalk\";\nimport type { Recommendation } from \"../types.js\";\nimport { renderBox } from \"./box.js\";\n\nexport interface TerminalMeta {\n recommenderModel: string;\n cost: number;\n promptTokens?: number;\n completionTokens?: number;\n recommendationLatencyMs?: number;\n catalogFetchLatencyMs?: number;\n totalLatencyMs?: number;\n verbose?: boolean;\n noColor?: boolean;\n}\n\nexport function formatTerminal(rec: Recommendation, meta: TerminalMeta): string {\n const c = meta.noColor ? new Chalk({ level: 0 }) : chalk;\n const lines: string[] = [];\n\n lines.push(`${c.cyan(\"🔍 Task Analysis\")}`);\n lines.push(` Modality: ${c.bold(rec.taskAnalysis.detectedModality.toUpperCase())}`);\n lines.push(` ${rec.taskAnalysis.summary}`);\n lines.push(` ${c.dim(rec.taskAnalysis.modalityReasoning)}`);\n\n const tiers = [\n { key: \"cheapest\", icon: \"💰\", label: \"Cheapest\", color: c.green },\n { key: \"balanced\", icon: \"⚖️\", label: \"Balanced\", color: c.yellow },\n { key: \"best\", icon: \"🏆\", label: \"Best\", color: c.magenta },\n ] as const;\n\n for (const tier of tiers) {\n const pick = rec.recommendations[tier.key];\n lines.push(\"\");\n lines.push(`${tier.icon} ${tier.color(tier.label)} — ${c.bold(pick.id)}`);\n lines.push(` ${c.dim(pick.pricingSummary)}`);\n lines.push(` ${pick.reason}`);\n lines.push(` ${c.dim(`Est. ${pick.estimatedCost}`)}`);\n }\n\n if (rec.alternativesInOtherModalities) {\n lines.push(\"\");\n lines.push(`💡 Tip: ${c.dim(rec.alternativesInOtherModalities)}`);\n }\n\n lines.push(\"\");\n lines.push(\n `⚡ ${c.dim(`This recommendation cost $${meta.cost.toFixed(4)} (${meta.recommenderModel})`)}`\n );\n\n if (meta.verbose) {\n lines.push(\n c.dim(\n `Tokens: prompt=${meta.promptTokens ?? \"n/a\"}, completion=${meta.completionTokens ?? \"n/a\"}`\n )\n );\n\n const timingParts: string[] = [];\n if (typeof meta.catalogFetchLatencyMs === \"number\") {\n timingParts.push(`catalog=${meta.catalogFetchLatencyMs}ms`);\n }\n if (typeof meta.recommendationLatencyMs === \"number\") {\n timingParts.push(`recommend=${meta.recommendationLatencyMs}ms`);\n }\n if (typeof meta.totalLatencyMs === \"number\") {\n timingParts.push(`total=${meta.totalLatencyMs}ms`);\n }\n if (timingParts.length > 0) {\n lines.push(c.dim(`Timing: ${timingParts.join(\", \")}`));\n }\n }\n\n return renderBox(lines.join(\"\\n\"), {\n title: \"Recommendations\",\n noColor: meta.noColor,\n borderColor: \"cyan\",\n });\n}\n","import type { Constraints, CompressedModel } from \"../types.js\";\n\nconst SYSTEM_PROMPT = `You are an expert AI model selector with deep knowledge of models across ALL modalities — text, image generation, video generation, audio/speech, vision/understanding, embeddings, and multimodal.\n\n## Your Job\n\nGiven a task description and a catalog of available models, you must:\n\n1. **Detect the correct modality** for the task\n2. **Recommend exactly 3 models** in that modality:\n - **cheapest**: Cheapest model that can do the job acceptably\n - **balanced**: Best quality-to-price ratio for this specific task\n - **best**: Highest quality regardless of cost\n\n## Modality Detection Rules\n\nBe careful with ambiguous tasks:\n- \"write video scripts\" → TEXT (output is a script, not a video)\n- \"generate product photos\" → IMAGE\n- \"create a 15-second ad from product images\" → VIDEO\n- \"transcribe my podcast\" → AUDIO_STT\n- \"add voiceover to my blog\" → AUDIO_TTS\n- \"describe what's in these screenshots\" → VISION\n- \"find similar documents\" → EMBEDDING\n- \"build a chatbot\" → TEXT\n- \"generate background music for a video\" → AUDIO_GENERATION\n\nIf the task genuinely spans multiple modalities, recommend models for the PRIMARY modality and note the others in your analysis.\n\n## Pricing Analysis Per Modality\n\nDifferent modalities have different cost structures. Analyze accordingly:\n\n**Text models**: Consider prompt vs completion token pricing. Is the task input-heavy (analysis, summarization) or output-heavy (generation, writing)?\n\n**Image models**: Compare per-image or per-megapixel pricing. Consider resolution needs, style control, number of generations needed.\n\n**Video models**: Compare per-second or per-generation pricing. Consider duration needs, resolution, motion quality.\n\n**Audio models**: Compare per-minute, per-character, or per-second pricing. Consider voice quality, language support, real-time needs.\n\n**Embedding models**: Compare per-token pricing and dimensionality. Consider retrieval quality vs cost at scale.\n\n## Model Family Strengths\n\n**Text**: Claude (writing, nuance), GPT-4o (general, tools), Gemini (speed, long context), DeepSeek (code, math, cost), Llama (open, privacy), Qwen (multilingual, code), Mistral (speed, European compliance)\n\n**Image**: Flux (quality, prompt adherence), DALL·E 3 (ease of use, safety), Stable Diffusion (control, customization, cost), Midjourney (aesthetics), Ideogram (text rendering in images), Recraft (design, vectors)\n\n**Video**: Runway Gen-3 (quality, control), Kling (motion, duration), Sora (coming), Minimax (cost), Veo (Google quality), Pika (stylization)\n\n**Audio**: ElevenLabs (voice quality, cloning), OpenAI TTS (cost, quality), Whisper (transcription), Suno (music), Udio (music), Fish Audio (multilingual)\n\n## Output Format\n\nRespond with ONLY this JSON structure:\n{\n \"taskAnalysis\": {\n \"summary\": \"one-line description of what the task demands\",\n \"detectedModality\": \"text | image | video | audio_tts | audio_stt | audio_generation | vision | embedding | multimodal\",\n \"modalityReasoning\": \"why this modality was chosen\",\n \"keyRequirements\": [\"req1\", \"req2\", \"req3\"],\n \"costFactors\": \"what drives cost for this specific task\"\n },\n \"recommendations\": {\n \"cheapest\": {\n \"id\": \"source::provider/model-name\",\n \"reason\": \"2-3 sentence justification specific to this task\",\n \"pricingSummary\": \"human-readable pricing\",\n \"estimatedCost\": \"$X for Y units (describe a reasonable workload)\"\n },\n \"balanced\": { ... },\n \"best\": { ... }\n },\n \"alternativesInOtherModalities\": null or \"brief note if another modality could work\"\n}\n\nIMPORTANT:\n- Only recommend models that appear in the provided catalog\n- Use the exact model ID from the catalog (including the source:: prefix)\n- If the task is ambiguous, state assumptions in taskAnalysis\n- Never recommend a model you aren't confident can handle the task\n- Always respond with valid JSON only, no markdown formatting`;\n\nexport function buildSystemPrompt(): string {\n return SYSTEM_PROMPT;\n}\n\nexport function buildUserPrompt(\n task: string,\n groupedModels: Record<string, CompressedModel[]>,\n constraints?: Constraints\n): string {\n const constraintLines: string[] = [];\n\n if (typeof constraints?.maxPrice === \"number\") {\n constraintLines.push(`Max price: $${constraints.maxPrice} per unit`);\n }\n if (typeof constraints?.minContext === \"number\") {\n constraintLines.push(`Min context length: ${constraints.minContext.toLocaleString()} tokens`);\n }\n if (constraints?.modality) {\n constraintLines.push(`Force modality: ${constraints.modality}`);\n }\n\n const constraintStr = constraintLines.length > 0 ? constraintLines.join(\"\\n\") : \"None\";\n\n const sections = Object.entries(groupedModels)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([modality, models]) => {\n return `### ${modality.toUpperCase()} Models (${models.length})\\n\\`\\`\\`json\\n${JSON.stringify(\n models,\n null,\n 2\n )}\\n\\`\\`\\``;\n })\n .join(\"\\n\\n\");\n\n return `## Task Description\\n${task}\\n\\n## Constraints\\n${constraintStr}\\n\\n## Available Models (grouped by modality)\\n\\n${sections}`;\n}\n","import type { Recommendation, ValidationResult } from \"../types.js\";\n\nconst TIERS = [\"cheapest\", \"balanced\", \"best\"] as const;\n\nexport function validateRecommendation(\n recommendation: Recommendation,\n validIds: Set<string>\n): ValidationResult {\n const invalidIds: string[] = [];\n\n for (const tier of TIERS) {\n const candidateId = recommendation.recommendations[tier]?.id;\n if (!candidateId || !validIds.has(candidateId)) {\n invalidIds.push(candidateId ?? \"undefined\");\n }\n }\n\n return {\n valid: invalidIds.length === 0,\n invalidIds,\n };\n}\n\nexport function findClosestModelId(\n invalidId: string,\n validIds: Set<string>\n): string | null {\n if (!invalidId) {\n return null;\n }\n\n const normalizedInvalid = normalizeId(invalidId);\n let bestMatch: string | null = null;\n let bestScore = 0;\n\n for (const validId of validIds) {\n const score = similarity(normalizedInvalid, normalizeId(validId));\n if (score > bestScore) {\n bestScore = score;\n bestMatch = validId;\n }\n }\n\n return bestScore >= 0.3 ? bestMatch : null;\n}\n\nfunction normalizeId(id: string): string {\n return id.replace(/^[^:]+::/, \"\").toLowerCase();\n}\n\nfunction similarity(a: string, b: string): number {\n if (a === b) {\n return 1;\n }\n\n if (a.includes(b) || b.includes(a)) {\n const shortest = Math.min(a.length, b.length);\n const longest = Math.max(a.length, b.length);\n return shortest / longest;\n }\n\n const setA = new Set(a.split(/[\\/_\\-.]/g).filter(Boolean));\n const setB = new Set(b.split(/[\\/_\\-.]/g).filter(Boolean));\n if (setA.size === 0 || setB.size === 0) {\n return 0;\n }\n\n let intersection = 0;\n for (const token of setA) {\n if (setB.has(token)) {\n intersection += 1;\n }\n }\n\n const union = new Set([...setA, ...setB]).size;\n return intersection / union;\n}\n","export const APP_VERSION = \"1.0.0\";\n","import { compressForLLM, groupByModality } from \"../catalog/compressor.js\";\nimport { parseRecommendationPayload } from \"../schemas/llm-schemas.js\";\nimport { hasUsablePrice } from \"../model-pricing.js\";\nimport {\n ExitCode,\n WhichModelError,\n type Constraints,\n type ModelEntry,\n type Recommendation,\n type RecommendationMeta,\n} from \"../types.js\";\nimport { wrapResult } from \"../utils/result.js\";\nimport { generateFallbackRecommendation } from \"./fallback.js\";\nimport { requestRecommendationCompletion } from \"./llm-client.js\";\nimport { buildSystemPrompt, buildUserPrompt } from \"./prompts.js\";\nimport { findClosestModelId, validateRecommendation } from \"./validator.js\";\nimport { APP_VERSION } from \"../version.js\";\n\nconst RECOMMENDER_MODEL_PRICING_PER_1M: Record<\n string,\n { promptPer1mTokens: number; completionPer1mTokens: number }\n> = {\n \"deepseek/deepseek-v3.2\": {\n promptPer1mTokens: 0.25,\n completionPer1mTokens: 0.38,\n },\n \"openai/gpt-4o-mini\": {\n promptPer1mTokens: 0.15,\n completionPer1mTokens: 0.6,\n },\n};\n\nexport interface RecommendOptions {\n task: string;\n models: ModelEntry[];\n apiKey: string;\n recommenderModel: string;\n constraints?: Constraints;\n catalogSources: string[];\n}\n\nexport interface RecommendResult {\n recommendation: Recommendation;\n meta: RecommendationMeta;\n}\n\nexport async function recommend(options: RecommendOptions): Promise<RecommendResult> {\n const { task, models, apiKey, recommenderModel, constraints, catalogSources } = options;\n if (models.length === 0) {\n throw new WhichModelError(\n \"No models found from configured sources.\",\n ExitCode.NO_MODELS_FOUND,\n \"Check your source configuration and retry.\"\n );\n }\n const pricedModels = models.filter((model) => hasUsablePrice(model));\n if (pricedModels.length === 0) {\n throw new WhichModelError(\n \"No priced models found from configured sources.\",\n ExitCode.NO_MODELS_FOUND,\n \"Enable additional sources or retry later for updated pricing.\"\n );\n }\n\n const recommendationStartedAt = Date.now();\n const compressed = compressForLLM(pricedModels);\n const grouped = groupByModality(compressed);\n\n let recommendation: Recommendation;\n let promptTokens: number | undefined;\n let completionTokens: number | undefined;\n let recommendationCostUsd = 0;\n\n try {\n const completion = await requestRecommendationCompletion({\n apiKey,\n model: recommenderModel,\n systemPrompt: buildSystemPrompt(),\n userPrompt: buildUserPrompt(task, grouped, constraints),\n });\n\n recommendation = parseRecommendation(completion.content);\n promptTokens = completion.usage?.promptTokens;\n completionTokens = completion.usage?.completionTokens;\n recommendationCostUsd = estimateRecommendationCost(\n recommenderModel,\n promptTokens,\n completionTokens\n );\n\n const validation = validateRecommendation(\n recommendation,\n new Set(pricedModels.map((m) => m.id))\n );\n if (!validation.valid) {\n recommendation = repairRecommendationIds(\n recommendation,\n new Set(pricedModels.map((m) => m.id))\n );\n }\n\n const repairedValidation = validateRecommendation(\n recommendation,\n new Set(pricedModels.map((m) => m.id))\n );\n if (!repairedValidation.valid) {\n recommendation = generateFallbackRecommendation(task, pricedModels, constraints);\n }\n } catch (error) {\n if (error instanceof WhichModelError && error.exitCode !== ExitCode.LLM_FAILED) {\n throw error;\n }\n\n recommendation = generateFallbackRecommendation(task, pricedModels, constraints);\n }\n\n const detectedModality = recommendation.taskAnalysis.detectedModality;\n const catalogModelsInModality = pricedModels.filter(\n (model) => model.modality === detectedModality\n ).length;\n recommendation = attachMissingModalityGuidance(\n recommendation,\n catalogSources,\n catalogModelsInModality\n );\n\n return {\n recommendation,\n meta: {\n recommenderModel,\n recommendationCostUsd,\n promptTokens,\n completionTokens,\n recommendationLatencyMs: Date.now() - recommendationStartedAt,\n catalogSources,\n catalogTotalModels: pricedModels.length,\n catalogModelsInModality,\n timestamp: new Date().toISOString(),\n version: APP_VERSION,\n },\n };\n}\n\nfunction attachMissingModalityGuidance(\n recommendation: Recommendation,\n catalogSources: string[],\n catalogModelsInModality: number\n): Recommendation {\n if (catalogModelsInModality > 0) {\n return recommendation;\n }\n\n const detected = recommendation.taskAnalysis.detectedModality;\n const sourcesLabel = catalogSources.join(\", \");\n const guidanceLines = [\n `No '${detected}' models are available in configured sources (${sourcesLabel}).`,\n ];\n\n if (\n (detected === \"image\" ||\n detected === \"video\" ||\n detected === \"audio_tts\" ||\n detected === \"audio_stt\" ||\n detected === \"audio_generation\") &&\n !catalogSources.includes(\"fal\")\n ) {\n guidanceLines.push(\"Add fal media models with --sources openrouter,fal and set FAL_API_KEY.\");\n }\n\n if (\n (detected === \"image\" ||\n detected === \"video\" ||\n detected === \"audio_tts\" ||\n detected === \"audio_stt\" ||\n detected === \"audio_generation\") &&\n !catalogSources.includes(\"replicate\")\n ) {\n guidanceLines.push(\n \"Add Replicate media coverage with --sources openrouter,replicate and set REPLICATE_API_TOKEN.\"\n );\n }\n\n guidanceLines.push(\"Broaden sources or force a different modality with --modality.\");\n const guidance = guidanceLines.join(\" \");\n\n return {\n ...recommendation,\n alternativesInOtherModalities: recommendation.alternativesInOtherModalities\n ? `${recommendation.alternativesInOtherModalities} ${guidance}`\n : guidance,\n };\n}\n\nfunction parseRecommendation(rawContent: string): Recommendation {\n const sanitized = stripMarkdownFences(rawContent).trim();\n\n const parseResult = wrapResult(\n () => JSON.parse(sanitized),\n () =>\n new WhichModelError(\n \"LLM returned invalid JSON.\",\n ExitCode.LLM_FAILED,\n \"Retry in a few minutes or use fallback mode.\"\n )\n );\n if (parseResult.isErr()) {\n throw parseResult.error;\n }\n\n const recommendationResult = parseRecommendationPayload(parseResult.value);\n if (recommendationResult.isErr()) {\n throw recommendationResult.error;\n }\n\n return recommendationResult.value;\n}\n\nfunction repairRecommendationIds(\n recommendation: Recommendation,\n validIds: Set<string>\n): Recommendation {\n // Use structuredClone for safe deep copying, with JSON fallback for older environments\n let patched: Recommendation;\n try {\n patched = structuredClone(recommendation);\n } catch {\n // Fallback to JSON parse/stringify for environments without structuredClone\n patched = JSON.parse(JSON.stringify(recommendation)) as Recommendation;\n }\n\n for (const tier of [\"cheapest\", \"balanced\", \"best\"] as const) {\n const currentId = patched.recommendations[tier].id;\n if (validIds.has(currentId)) {\n continue;\n }\n\n const closest = findClosestModelId(currentId, validIds);\n if (closest) {\n patched.recommendations[tier].id = closest;\n }\n }\n\n return patched;\n}\n\nfunction stripMarkdownFences(content: string): string {\n return content.replace(/^```(?:json)?\\s*/i, \"\").replace(/\\s*```$/, \"\");\n}\n\nfunction estimateRecommendationCost(\n modelId: string,\n promptTokens?: number,\n completionTokens?: number\n): number {\n if (typeof promptTokens !== \"number\" || typeof completionTokens !== \"number\") {\n return 0;\n }\n\n const pricing = RECOMMENDER_MODEL_PRICING_PER_1M[modelId];\n if (!pricing) {\n return 0;\n }\n\n const inputCost = (promptTokens / 1_000_000) * pricing.promptPer1mTokens;\n const outputCost = (completionTokens / 1_000_000) * pricing.completionPer1mTokens;\n return inputCost + outputCost;\n}\n","#!/usr/bin/env node\n\nimport { program } from \"./cli.js\";\n\nprogram.parse();\n"],"mappings":"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","names":["chalk","Chalk","DEFAULT_TERMINAL_COLUMNS","MIN_CONTENT_WIDTH","getMaxContentWidth","truncateCell","buildSeparator","Chalk","chalk","chalk","Chalk","err","ok","ok","err","Chalk","chalk","chalk","Chalk","fs","path","os","estimateCost","path","os","fs","Chalk","chalk","path","fs","os","path","fs","os","path","err","ok","z","z","ok","err","DEFAULT_TIMEOUT_MS","DEFAULT_TIMEOUT_MS","fs","path","path","fs","isRecord","DEFAULT_TIMEOUT_MS","isRecord","round","DEFAULT_ENDPOINT","DEFAULT_TIMEOUT_MS","MAX_MODEL_PAGES","MAX_CANDIDATE_MODELS","chalk","Chalk","Chalk","chalk","stripMarkdownFences","config","spinner","sources"]}
|