@x12i/ai-tools 1.0.2
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/README.md +214 -0
- package/dist/AiModelsCatalogClient-4RF5BCDL.cjs +9 -0
- package/dist/AiModelsCatalogClient-4RF5BCDL.cjs.map +1 -0
- package/dist/AiModelsCatalogClient-B-dNLXX0.d.ts +29 -0
- package/dist/AiModelsCatalogClient-CSVlKql5.d.cts +29 -0
- package/dist/AiModelsCatalogClient-NUF3CBLW.js +9 -0
- package/dist/AiModelsCatalogClient-NUF3CBLW.js.map +1 -0
- package/dist/aliases/index.cjs +11 -0
- package/dist/aliases/index.cjs.map +1 -0
- package/dist/aliases/index.d.cts +21 -0
- package/dist/aliases/index.d.ts +21 -0
- package/dist/aliases/index.js +11 -0
- package/dist/aliases/index.js.map +1 -0
- package/dist/catalox/index.cjs +21 -0
- package/dist/catalox/index.cjs.map +1 -0
- package/dist/catalox/index.d.cts +23 -0
- package/dist/catalox/index.d.ts +23 -0
- package/dist/catalox/index.js +21 -0
- package/dist/catalox/index.js.map +1 -0
- package/dist/chunk-2PYACSZ5.cjs +1 -0
- package/dist/chunk-2PYACSZ5.cjs.map +1 -0
- package/dist/chunk-3E67S427.cjs +1 -0
- package/dist/chunk-3E67S427.cjs.map +1 -0
- package/dist/chunk-4NAY6HRP.js +137 -0
- package/dist/chunk-4NAY6HRP.js.map +1 -0
- package/dist/chunk-5HNFAYTO.cjs +254 -0
- package/dist/chunk-5HNFAYTO.cjs.map +1 -0
- package/dist/chunk-6QGDZTGH.js +127 -0
- package/dist/chunk-6QGDZTGH.js.map +1 -0
- package/dist/chunk-7Q742NI3.cjs +106 -0
- package/dist/chunk-7Q742NI3.cjs.map +1 -0
- package/dist/chunk-AJEKEWWB.js +106 -0
- package/dist/chunk-AJEKEWWB.js.map +1 -0
- package/dist/chunk-AV6OE2YQ.cjs +127 -0
- package/dist/chunk-AV6OE2YQ.cjs.map +1 -0
- package/dist/chunk-COK34C6P.js +1 -0
- package/dist/chunk-COK34C6P.js.map +1 -0
- package/dist/chunk-DJ5SWJDY.js +729 -0
- package/dist/chunk-DJ5SWJDY.js.map +1 -0
- package/dist/chunk-F2F4UEFD.cjs +75 -0
- package/dist/chunk-F2F4UEFD.cjs.map +1 -0
- package/dist/chunk-G2G4KSC5.js +30 -0
- package/dist/chunk-G2G4KSC5.js.map +1 -0
- package/dist/chunk-HHNHWYTP.cjs +105 -0
- package/dist/chunk-HHNHWYTP.cjs.map +1 -0
- package/dist/chunk-HN6UAQAE.cjs +83 -0
- package/dist/chunk-HN6UAQAE.cjs.map +1 -0
- package/dist/chunk-KHODXGPV.js +1 -0
- package/dist/chunk-KHODXGPV.js.map +1 -0
- package/dist/chunk-KQOALKKX.js +75 -0
- package/dist/chunk-KQOALKKX.js.map +1 -0
- package/dist/chunk-LYOU7CA2.cjs +30 -0
- package/dist/chunk-LYOU7CA2.cjs.map +1 -0
- package/dist/chunk-ML2FRR4L.js +105 -0
- package/dist/chunk-ML2FRR4L.js.map +1 -0
- package/dist/chunk-MLRHYOCD.js +160 -0
- package/dist/chunk-MLRHYOCD.js.map +1 -0
- package/dist/chunk-O2A6OVEH.js +240 -0
- package/dist/chunk-O2A6OVEH.js.map +1 -0
- package/dist/chunk-ONA73BU6.cjs +160 -0
- package/dist/chunk-ONA73BU6.cjs.map +1 -0
- package/dist/chunk-QCRLKVB3.cjs +137 -0
- package/dist/chunk-QCRLKVB3.cjs.map +1 -0
- package/dist/chunk-QWAX7VQO.cjs +240 -0
- package/dist/chunk-QWAX7VQO.cjs.map +1 -0
- package/dist/chunk-TF4L2NEC.cjs +729 -0
- package/dist/chunk-TF4L2NEC.cjs.map +1 -0
- package/dist/chunk-XRBZQQQU.js +254 -0
- package/dist/chunk-XRBZQQQU.js.map +1 -0
- package/dist/chunk-YHO57D2V.js +83 -0
- package/dist/chunk-YHO57D2V.js.map +1 -0
- package/dist/cli/index.cjs +403 -0
- package/dist/cli/index.cjs.map +1 -0
- package/dist/cli/index.d.cts +1 -0
- package/dist/cli/index.d.ts +1 -0
- package/dist/cli/index.js +403 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cost/index.cjs +7 -0
- package/dist/cost/index.cjs.map +1 -0
- package/dist/cost/index.d.cts +52 -0
- package/dist/cost/index.d.ts +52 -0
- package/dist/cost/index.js +7 -0
- package/dist/cost/index.js.map +1 -0
- package/dist/index.cjs +104 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +58 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/modelNameResolver-Bn8QnkSj.d.ts +80 -0
- package/dist/modelNameResolver-bZD-eBSJ.d.cts +80 -0
- package/dist/models/index.cjs +33 -0
- package/dist/models/index.cjs.map +1 -0
- package/dist/models/index.d.cts +75 -0
- package/dist/models/index.d.ts +75 -0
- package/dist/models/index.js +33 -0
- package/dist/models/index.js.map +1 -0
- package/dist/sync/index.cjs +38 -0
- package/dist/sync/index.cjs.map +1 -0
- package/dist/sync/index.d.cts +12 -0
- package/dist/sync/index.d.ts +12 -0
- package/dist/sync/index.js +38 -0
- package/dist/sync/index.js.map +1 -0
- package/dist/toolbox/index.cjs +7 -0
- package/dist/toolbox/index.cjs.map +1 -0
- package/dist/toolbox/index.d.cts +72 -0
- package/dist/toolbox/index.d.ts +72 -0
- package/dist/toolbox/index.js +7 -0
- package/dist/toolbox/index.js.map +1 -0
- package/dist/types-DdGB3YaA.d.cts +278 -0
- package/dist/types-DdGB3YaA.d.ts +278 -0
- package/package.json +115 -0
- package/schemas/aliases.json +28 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cache/modelCache.ts","../src/catalog/aiModelsCatalogDescriptor.ts","../src/sync/openRouterRoutingEnv.ts","../src/sync/modelNameResolver/constants.ts","../src/sync/modelNameResolver/normalize.ts","../src/sync/modelNameResolver/catalogIndexes.ts","../src/sync/modelNameResolver/ModelNameResolver.ts"],"sourcesContent":["import { createNxCache } from \"nx-cache\";\nimport type { AiModelRecord } from \"../cost/types.js\";\n\nconst cache = createNxCache<Map<string, AiModelRecord>, { cachedAt: string; count: number }>();\n\nexport const DEFAULT_MODEL_CACHE_TTL_MS = 60 * 60 * 1000;\n\nexport type ModelCacheMetadata = { cachedAt: string; count: number };\n\nexport function readCachedModels(\n appId: string,\n ttlMs = DEFAULT_MODEL_CACHE_TTL_MS,\n): Map<string, AiModelRecord> | null {\n const res = cache.read(\"ai-models\", { appId });\n if (!res.found) return null;\n\n const cachedAt = res.metadata?.cachedAt;\n if (cachedAt) {\n const age = Date.now() - new Date(cachedAt).getTime();\n if (age > ttlMs) return null;\n } else if (res.meta.isExpired) {\n return null;\n }\n\n return res.value;\n}\n\nexport function writeCachedModels(\n appId: string,\n models: Map<string, AiModelRecord>,\n ttlMs = DEFAULT_MODEL_CACHE_TTL_MS,\n): void {\n cache.write(\"ai-models\", models, {\n scope: { appId },\n ttlMs,\n metadata: { cachedAt: new Date().toISOString(), count: models.size },\n });\n}\n\nexport function invalidateModelsCache(appId: string): void {\n cache.resetKey(\"ai-models\", { appId });\n}\n","import type { CatalogDescriptor } from \"@x12i/catalox\";\n\nexport const AI_MODELS_CATALOG_ID = \"ai-models\";\nexport const AI_TOOLS_APP_ID = \"ai-tools\";\n\nexport const AI_MODELS_DESCRIPTOR: CatalogDescriptor = {\n catalogId: AI_MODELS_CATALOG_ID,\n label: \"AI Models\",\n description:\n \"Full mirror of OpenRouter Models API metadata and pricing, synced on a schedule.\",\n itemLabel: \"Model\",\n sourceMode: \"native\",\n status: \"active\",\n visibility: \"visible\",\n capabilities: {\n canList: true,\n canGet: true,\n canCreate: false,\n canEdit: false,\n canDelete: false,\n canExport: true,\n canValidate: true,\n },\n identity: {\n itemIdStrategy: \"natural\",\n itemIdField: \"modelId\",\n titleField: \"name\",\n subtitleField: \"providerId\",\n statusField: \"status\",\n updatedAtField: \"syncedAt\",\n },\n queryableFields: [\n { key: \"modelId\", label: \"Model ID\", type: \"string\", indexed: true, filterable: true },\n { key: \"providerId\", label: \"Provider\", type: \"string\", indexed: true, filterable: true },\n { key: \"name\", label: \"Name\", type: \"string\", filterable: true },\n { key: \"canonicalSlug\", label: \"Canonical Slug\", type: \"string\", indexed: true, filterable: true },\n { key: \"contextLength\", label: \"Context Length\", type: \"number\", sortable: true },\n {\n key: \"status\",\n label: \"Status\",\n type: \"enum\",\n indexed: true,\n filterable: true,\n enumValues: [\"active\", \"deprecated\", \"unknown\"],\n },\n {\n key: \"primaryOutputModality\",\n label: \"Primary Output\",\n type: \"string\",\n indexed: true,\n filterable: true,\n },\n { key: \"supportsTools\", label: \"Tools\", type: \"boolean\", indexed: true, filterable: true },\n {\n key: \"supportsReasoning\",\n label: \"Reasoning\",\n type: \"boolean\",\n indexed: true,\n filterable: true,\n },\n { key: \"supportsStreaming\", label: \"Streams\", type: \"boolean\", filterable: true },\n { key: \"isModerated\", label: \"Moderated\", type: \"boolean\", filterable: true },\n { key: \"syncedAt\", label: \"Synced At\", type: \"datetime\", sortable: true },\n ],\n defaultSort: { field: \"syncedAt\", direction: \"desc\" },\n};\n","import { loadDotenv } from \"@x12i/env\";\n\n/**\n * Env naming for vendor direct API keys: `{VENDOR}_API_KEY`\n * where VENDOR is the provider id in UPPER_SNAKE (hyphens → underscores).\n *\n * Examples: `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `META_LLAMA_API_KEY`, `X_AI_API_KEY`\n */\nexport function providerIdToEnvKeyPrefix(providerId: string): string {\n return providerId\n .trim()\n .toLowerCase()\n .replace(/-/g, \"_\")\n .toUpperCase();\n}\n\nexport function vendorApiKeyEnvName(providerId: string): string {\n return `${providerIdToEnvKeyPrefix(providerId)}_API_KEY`;\n}\n\nexport type OpenRouterRoutingConfig = {\n /** OPENROUTER_API_KEY is set and non-empty */\n hasOpenRouterKey: boolean;\n /** USE_OPENROUTER=true or USE_OPENROUTER=1 */\n useOpenRouterExplicit: boolean;\n /** Read `{PROVIDER}_API_KEY` for a catalog provider id */\n getVendorApiKey(providerId: string): string | undefined;\n};\n\n/**\n * Load routing hints from process env and optional `.env` (via @x12/env).\n */\nexport function loadOpenRouterRoutingEnv(\n env: Record<string, string | undefined> = process.env,\n): OpenRouterRoutingConfig {\n const dotenv = loadDotenv();\n const merged: Record<string, string> = {};\n for (const [k, v] of Object.entries(dotenv)) {\n if (v !== undefined) merged[k] = v;\n }\n for (const [k, v] of Object.entries(env)) {\n if (v !== undefined) merged[k] = v;\n }\n\n const openRouterKey = merged.OPENROUTER_API_KEY?.trim();\n const useRaw = merged.USE_OPENROUTER?.trim().toLowerCase();\n const useOpenRouterExplicit = useRaw === \"true\" || useRaw === \"1\";\n\n return {\n hasOpenRouterKey: Boolean(openRouterKey),\n useOpenRouterExplicit,\n getVendorApiKey(providerId: string) {\n const name = vendorApiKeyEnvName(providerId);\n const val = merged[name]?.trim();\n return val || undefined;\n },\n };\n}\n\n/**\n * Default route via OpenRouter when:\n * 1. OPENROUTER_API_KEY is set AND USE_OPENROUTER=true|1, or\n * 2. OPENROUTER_API_KEY is set AND the vendor's `{VENDOR}_API_KEY` is missing.\n */\nexport function shouldDefaultRouteViaOpenRouter(\n providerId: string | undefined,\n config: OpenRouterRoutingConfig,\n): boolean {\n if (!config.hasOpenRouterKey) return false;\n if (config.useOpenRouterExplicit) return true;\n if (providerId && providerId !== \"openrouter\") {\n return !config.getVendorApiKey(providerId);\n }\n return false;\n}\n","export const DEFAULT_CONFIDENCE_THRESHOLD = 0.6;\n\nexport const PROVIDER_NORMALISATION_MAP: Record<string, string> = {\n \"open-router\": \"openrouter\",\n or: \"openrouter\",\n oai: \"openai\",\n \"open-ai\": \"openai\",\n claude: \"anthropic\",\n ant: \"anthropic\",\n gemini: \"google\",\n gcp: \"google\",\n \"google-ai\": \"google\",\n vertex: \"google\",\n meta: \"meta-llama\",\n llama: \"meta-llama\",\n \"mistral-ai\": \"mistral\",\n \"cohere-ai\": \"cohere\",\n};\n\nexport const LOCAL_PROVIDERS = new Set([\n \"ollama\",\n \"lmstudio\",\n \"lm-studio\",\n \"localai\",\n \"local-ai\",\n \"llamacpp\",\n \"llama.cpp\",\n \"llamafile\",\n \"jan\",\n \"koboldcpp\",\n]);\n\nexport const PROVIDER_INFERENCE_MAP: Array<{\n pattern: RegExp;\n provider: string;\n notes?: string;\n}> = [\n { pattern: /^gpt-/, provider: \"openai\" },\n { pattern: /^o1($|-)/, provider: \"openai\" },\n { pattern: /^o3($|-)/, provider: \"openai\" },\n { pattern: /^o4($|-)/, provider: \"openai\" },\n { pattern: /^chatgpt-/, provider: \"openai\" },\n { pattern: /^text-davinci/, provider: \"openai\" },\n { pattern: /^dall-e/, provider: \"openai\" },\n { pattern: /^whisper/, provider: \"openai\" },\n { pattern: /^tts-/, provider: \"openai\" },\n { pattern: /^claude-/, provider: \"anthropic\" },\n { pattern: /^gemini-/, provider: \"google\" },\n { pattern: /^palm-/, provider: \"google\" },\n { pattern: /^bison/, provider: \"google\" },\n { pattern: /^llama-?[23]/, provider: \"meta-llama\" },\n { pattern: /^llama/, provider: \"meta-llama\" },\n { pattern: /^codellama/, provider: \"meta-llama\" },\n { pattern: /^mistral-/, provider: \"mistral\" },\n { pattern: /^mixtral-/, provider: \"mistral\" },\n { pattern: /^codestral/, provider: \"mistral\" },\n { pattern: /^ministral/, provider: \"mistral\" },\n { pattern: /^command-/, provider: \"cohere\" },\n { pattern: /^c4ai-/, provider: \"cohere\" },\n { pattern: /^deepseek-/, provider: \"deepseek\" },\n { pattern: /^grok-/, provider: \"x-ai\" },\n { pattern: /^qwen/, provider: \"qwen\" },\n { pattern: /^yi-/, provider: \"01-ai\" },\n { pattern: /^sonar/, provider: \"perplexity\" },\n { pattern: /^pplx-/, provider: \"perplexity\" },\n { pattern: /^titan-/, provider: \"amazon\" },\n { pattern: /^nova-/, provider: \"amazon\" },\n];\n\nexport const SHORTHAND_MAP: Record<string, string> = {\n gpt4: \"openai/gpt-4\",\n gpt4o: \"openai/gpt-4o\",\n \"gpt-4-omni\": \"openai/gpt-4o\",\n gpt4omni: \"openai/gpt-4o\",\n \"gpt4-turbo\": \"openai/gpt-4-turbo\",\n gpt4turbo: \"openai/gpt-4-turbo\",\n \"gpt4-mini\": \"openai/gpt-4o-mini\",\n \"gpt-4o-mini\": \"openai/gpt-4o-mini\",\n o1: \"openai/o1\",\n \"o1-mini\": \"openai/o1-mini\",\n o3: \"openai/o3\",\n \"o3-mini\": \"openai/o3-mini\",\n \"o4-mini\": \"openai/o4-mini\",\n \"3.5-turbo\": \"openai/gpt-3.5-turbo\",\n gpt35: \"openai/gpt-3.5-turbo\",\n gpt3: \"openai/gpt-3.5-turbo\",\n claude3: \"anthropic/claude-3-5-sonnet-20241022\",\n \"claude-3\": \"anthropic/claude-3-5-sonnet-20241022\",\n \"claude3-sonnet\": \"anthropic/claude-3-5-sonnet-20241022\",\n \"claude-sonnet\": \"anthropic/claude-3-5-sonnet-20241022\",\n \"claude-haiku\": \"anthropic/claude-3-5-haiku-20241022\",\n \"claude3-haiku\": \"anthropic/claude-3-5-haiku-20241022\",\n \"claude-opus\": \"anthropic/claude-opus-4\",\n \"claude3-opus\": \"anthropic/claude-3-opus-20240229\",\n claude4: \"anthropic/claude-opus-4\",\n \"claude4-sonnet\": \"anthropic/claude-sonnet-4\",\n \"claude4-opus\": \"anthropic/claude-opus-4\",\n sonnet: \"anthropic/claude-3-5-sonnet-20241022\",\n haiku: \"anthropic/claude-3-5-haiku-20241022\",\n opus: \"anthropic/claude-opus-4\",\n gemini: \"google/gemini-pro\",\n \"gemini-pro\": \"google/gemini-pro\",\n \"gemini-flash\": \"google/gemini-flash-1.5\",\n gemini2: \"google/gemini-2.0-flash-001\",\n \"gemini-2\": \"google/gemini-2.0-flash-001\",\n llama3: \"meta-llama/llama-3.1-8b-instruct\",\n \"llama-3\": \"meta-llama/llama-3.1-8b-instruct\",\n llama2: \"meta-llama/llama-2-13b-chat\",\n \"llama-2\": \"meta-llama/llama-2-13b-chat\",\n mistral: \"mistral/mistral-7b-instruct\",\n \"mistral-large\": \"mistral/mistral-large-latest\",\n mixtral: \"mistral/mixtral-8x7b-instruct\",\n deepseek: \"deepseek/deepseek-chat\",\n \"deepseek-r1\": \"deepseek/deepseek-r1\",\n};\n","import { PROVIDER_NORMALISATION_MAP } from \"./constants.js\";\n\nexport function normalizeString(input: string): string {\n let s = input.trim();\n s = s.replace(/\\s+/g, \" \").replace(/ /g, \"-\");\n s = s.toLowerCase();\n s = s.replace(/^\\/+|\\/+$/g, \"\");\n s = s.replace(/\\/+/g, \"/\");\n if (\n (s.startsWith('\"') && s.endsWith('\"')) ||\n (s.startsWith(\"'\") && s.endsWith(\"'\"))\n ) {\n s = s.slice(1, -1);\n }\n return s;\n}\n\nexport function normalizeProvider(provider: string | undefined): string | undefined {\n if (provider === undefined || provider === \"\") return undefined;\n const n = normalizeString(provider);\n return PROVIDER_NORMALISATION_MAP[n] ?? n;\n}\n\nexport function tokenise(s: string): string[] {\n return s.split(/[-_./]+/).filter(Boolean);\n}\n\nexport function modelSlug(modelId: string): string {\n const slash = modelId.indexOf(\"/\");\n return slash >= 0 ? modelId.slice(slash + 1) : modelId;\n}\n","import type { AiModelRecord } from \"../../models/types.js\";\nimport { normalizeString } from \"./normalize.js\";\nimport type { CatalogIndexes } from \"./types.js\";\n\nexport function buildCatalogIndexes(catalog: Map<string, AiModelRecord>): CatalogIndexes {\n const aliasIndex = new Map<string, string>();\n const slugIndex = new Map<string, string>();\n const prefixCounts = new Map<string, number>();\n\n for (const record of catalog.values()) {\n for (const alias of record.aliases) {\n aliasIndex.set(normalizeString(alias), record.modelId);\n }\n if (record.canonicalSlug) {\n slugIndex.set(normalizeString(record.canonicalSlug), record.modelId);\n }\n const pid = record.providerId;\n prefixCounts.set(pid, (prefixCounts.get(pid) ?? 0) + 1);\n }\n\n const providerPrefixesBySize = [...prefixCounts.entries()]\n .sort((a, b) => b[1] - a[1])\n .map(([p]) => p);\n\n return { aliasIndex, slugIndex, providerPrefixesBySize };\n}\n","import { ModelResolutionError } from \"../../errors.js\";\nimport type { AiModelRecord } from \"../../models/types.js\";\nimport {\n loadOpenRouterRoutingEnv,\n shouldDefaultRouteViaOpenRouter,\n} from \"../openRouterRoutingEnv.js\";\nimport { buildCatalogIndexes } from \"./catalogIndexes.js\";\nimport {\n DEFAULT_CONFIDENCE_THRESHOLD,\n LOCAL_PROVIDERS,\n PROVIDER_INFERENCE_MAP,\n SHORTHAND_MAP,\n} from \"./constants.js\";\nimport { modelSlug, normalizeProvider, normalizeString, tokenise } from \"./normalize.js\";\nimport type {\n CatalogIndexes,\n ModelResolutionInput,\n ModelResolutionNotFound,\n ModelResolutionResult,\n ModelResolutionSuccess,\n ModelResolverOptions,\n ResolutionStrategy,\n ResolverContext,\n} from \"./types.js\";\n\ntype MatchCandidate = {\n modelId: string;\n record: AiModelRecord | null;\n confidence: number;\n strategy: ResolutionStrategy;\n reason: string;\n};\n\nconst VERSION_STRIP_PATTERNS: Array<{ re: RegExp; label: string }> = [\n { re: /-\\d{4}-\\d{2}-\\d{2}$/, label: \"date YYYY-MM-DD\" },\n { re: /-\\d{8}$/, label: \"date YYYYMMDD\" },\n { re: /-v\\d+$/, label: \"version -vN\" },\n { re: /-\\d+\\.\\d+\\.\\d+$/, label: \"semver\" },\n { re: /:\\d+[a-z]?$/i, label: \"colon version\" },\n { re: /-\\d{4,}$/, label: \"build number\" },\n { re: /@\\d+$/, label: \"epoch @NNNN\" },\n];\n\nexport class ModelNameResolver {\n private readonly catalog: Map<string, AiModelRecord>;\n private readonly indexes: CatalogIndexes;\n private readonly ctx: ResolverContext;\n\n constructor(\n catalog: Map<string, AiModelRecord>,\n options: ModelResolverOptions = {},\n ) {\n this.catalog = catalog;\n this.indexes = buildCatalogIndexes(catalog);\n this.ctx = {\n catalog,\n indexes: this.indexes,\n options: {\n confidenceThreshold: options.confidenceThreshold ?? DEFAULT_CONFIDENCE_THRESHOLD,\n aliasRegistry: options.aliasRegistry,\n additionalShorthands: options.additionalShorthands ?? {},\n additionalProviderPatterns: options.additionalProviderPatterns ?? [],\n additionalLocalProviders: options.additionalLocalProviders ?? [],\n routingEnv: options.routingEnv ?? loadOpenRouterRoutingEnv(),\n },\n };\n }\n\n resolve(input: ModelResolutionInput): ModelResolutionResult {\n const attempted: ResolutionStrategy[] = [];\n const threshold = this.ctx.options.confidenceThreshold;\n\n let provider = normalizeProvider(input.provider);\n let model = normalizeString(input.model);\n const normalisedInput = model;\n\n // S0 — alias registry on model string\n if (this.ctx.options.aliasRegistry) {\n attempted.push(\"alias-registry\");\n const entry = this.ctx.options.aliasRegistry.get(model);\n if (entry) {\n model = normalizeString(entry.modelId);\n provider = normalizeProvider(entry.provider) ?? provider;\n }\n }\n\n // Alias used as provider name (e.g. provider=\"best\")\n if (this.ctx.options.aliasRegistry && provider) {\n const aliasAsProvider = this.ctx.options.aliasRegistry.get(provider);\n if (aliasAsProvider) {\n attempted.push(\"alias-as-provider-correction\");\n model = normalizeString(aliasAsProvider.modelId);\n provider = normalizeProvider(aliasAsProvider.provider) ?? provider;\n }\n }\n\n // S10 — local provider (before catalog strategies)\n const localProviders = new Set([\n ...LOCAL_PROVIDERS,\n ...this.ctx.options.additionalLocalProviders.map((p) => normalizeString(p)),\n ]);\n if (provider && localProviders.has(provider)) {\n attempted.push(\"local-provider-passthrough\");\n return this.success({\n modelId: model,\n record: null,\n confidence: 0.99,\n strategy: \"local-provider-passthrough\",\n reason: `Local provider \"${provider}\" — model not looked up in catalog`,\n resolvedVia: attempted,\n normalisedInput,\n provider,\n originalProvider: input.provider,\n });\n }\n\n const preCorrection = [...attempted];\n\n const { match, rejected } = this.runPipeline(model, provider, attempted, threshold, []);\n if (match) {\n const via = [\n ...preCorrection.filter((s) => !match.resolvedVia.includes(s)),\n ...match.resolvedVia,\n ];\n return this.success({\n modelId: match.modelId,\n record: match.record,\n confidence: match.confidence,\n strategy: match.strategy,\n reason: match.reason,\n resolvedVia: via,\n normalisedInput,\n provider,\n originalProvider: input.provider,\n });\n }\n\n const notFound: ModelResolutionNotFound = {\n found: false,\n modelId: null,\n record: null,\n attemptedStrategies: attempted,\n reason: \"No catalog entry matched after all strategies.\",\n bestRejectedCandidate: rejected,\n };\n return notFound;\n }\n\n resolveMany(inputs: ModelResolutionInput[]): ModelResolutionResult[] {\n return inputs.map((i) => this.resolve(i));\n }\n\n resolveOrThrow(input: ModelResolutionInput): ModelResolutionSuccess {\n const result = this.resolve(input);\n if (result.found) return result;\n throw new ModelResolutionError(input, result);\n }\n\n private runPipeline(\n model: string,\n provider: string | undefined,\n attempted: ResolutionStrategy[],\n threshold: number,\n resolvedVia: ResolutionStrategy[],\n depth = 0,\n ): {\n match: (MatchCandidate & { resolvedVia: ResolutionStrategy[] }) | null;\n rejected?: ModelResolutionNotFound[\"bestRejectedCandidate\"];\n } {\n if (depth > 12) return { match: null };\n\n const tryMatch = (\n strategy: ResolutionStrategy,\n fn: () => MatchCandidate | null,\n ): (MatchCandidate & { resolvedVia: ResolutionStrategy[] }) | null => {\n if (!attempted.includes(strategy)) attempted.push(strategy);\n const m = fn();\n if (m && m.confidence >= threshold) {\n return { ...m, resolvedVia: [...resolvedVia, strategy] };\n }\n return null;\n };\n\n let hit = tryMatch(\"exact-match\", () => this.exactMatch(model));\n if (hit) return { match: hit };\n\n hit = tryMatch(\"catalog-alias-match\", () => this.catalogAliasMatch(model));\n if (hit) return { match: hit };\n\n hit = tryMatch(\"canonical-slug-match\", () => this.slugMatch(model));\n if (hit) return { match: hit };\n\n hit = tryMatch(\"provider-prefix-injection\", () =>\n this.providerPrefixInjection(model, provider),\n );\n if (hit) return { match: hit };\n\n hit = tryMatch(\"cross-provider-correction\", () => this.crossProviderCorrection(model));\n if (hit) return { match: hit };\n\n const stripped = this.stripVersionSuffixes(model);\n if (stripped && stripped !== model) {\n if (!attempted.includes(\"version-suffix-strip\")) attempted.push(\"version-suffix-strip\");\n const inner = this.runPipeline(\n stripped,\n provider,\n attempted,\n threshold,\n [...resolvedVia, \"version-suffix-strip\"],\n depth + 1,\n );\n if (inner.match) {\n return {\n match: {\n ...inner.match,\n confidence: 0.85,\n strategy: \"version-suffix-strip\",\n reason: `Stripped version suffix from \"${model}\" → \"${stripped}\" then ${inner.match.reason}`,\n resolvedVia: [...resolvedVia, \"version-suffix-strip\", ...inner.match.resolvedVia],\n },\n };\n }\n }\n\n hit = tryMatch(\"date-suffix-strip\", () => this.dateSuffixMatch(model));\n if (hit) return { match: hit };\n\n const shorthand = this.shorthandMap()[model];\n if (shorthand) {\n if (!attempted.includes(\"shorthand-expansion\")) attempted.push(\"shorthand-expansion\");\n const inner = this.runPipeline(\n normalizeString(shorthand),\n provider,\n attempted,\n threshold,\n [...resolvedVia, \"shorthand-expansion\"],\n depth + 1,\n );\n if (inner.match) {\n return {\n match: {\n ...inner.match,\n confidence: 0.8,\n strategy: \"shorthand-expansion\",\n reason: `Expanded shorthand \"${model}\" → \"${shorthand}\" then ${inner.match.reason}`,\n resolvedVia: [...resolvedVia, \"shorthand-expansion\", ...inner.match.resolvedVia],\n },\n };\n }\n }\n\n const partial = this.partialMatch(model, provider);\n if (partial) {\n if (!attempted.includes(\"partial-name-match\")) attempted.push(\"partial-name-match\");\n if (partial.confidence >= threshold) {\n return {\n match: { ...partial, resolvedVia: [...resolvedVia, \"partial-name-match\"] },\n };\n }\n return {\n match: null,\n rejected: {\n modelId: partial.modelId,\n confidence: partial.confidence,\n reason: partial.reason,\n },\n };\n }\n\n return { match: null };\n }\n\n private exactMatch(model: string): MatchCandidate | null {\n const record = this.catalog.get(model);\n if (!record) return null;\n return {\n modelId: model,\n record,\n confidence: 1,\n strategy: \"exact-match\",\n reason: `Exact catalog match for \"${model}\"`,\n };\n }\n\n private catalogAliasMatch(model: string): MatchCandidate | null {\n const modelId = this.indexes.aliasIndex.get(model);\n if (!modelId) return null;\n const record = this.catalog.get(modelId);\n if (!record) return null;\n return {\n modelId,\n record,\n confidence: 1,\n strategy: \"catalog-alias-match\",\n reason: `Catalog alias \"${model}\" → \"${modelId}\"`,\n };\n }\n\n private slugMatch(model: string): MatchCandidate | null {\n const modelId = this.indexes.slugIndex.get(model);\n if (!modelId) return null;\n const record = this.catalog.get(modelId);\n if (!record) return null;\n return {\n modelId,\n record,\n confidence: 0.95,\n strategy: \"canonical-slug-match\",\n reason: `Canonical slug match \"${model}\" → \"${modelId}\"`,\n };\n }\n\n private inferProviderFromSlug(slug: string): string | undefined {\n const patterns = [\n ...this.ctx.options.additionalProviderPatterns,\n ...PROVIDER_INFERENCE_MAP,\n ];\n for (const { pattern, provider } of patterns) {\n if (pattern.test(slug)) return provider;\n }\n return undefined;\n }\n\n private providerPrefixInjection(\n model: string,\n provider: string | undefined,\n ): MatchCandidate | null {\n if (model.includes(\"/\")) return null;\n\n const prefixes: string[] = [];\n if (provider && provider !== \"openrouter\") {\n prefixes.push(provider);\n }\n const inferred = this.inferProviderFromSlug(model);\n if (inferred && !prefixes.includes(inferred)) prefixes.push(inferred);\n for (const p of this.indexes.providerPrefixesBySize) {\n if (!prefixes.includes(p)) prefixes.push(p);\n }\n\n for (const prefix of prefixes) {\n const candidate = `${prefix}/${model}`;\n let record = this.catalog.get(candidate);\n let modelId = candidate;\n if (!record) {\n const latest = this.findLatestVersioned(candidate);\n if (latest) {\n record = latest.record;\n modelId = latest.modelId;\n }\n }\n if (record) {\n const viaInference = inferred === prefix;\n return {\n modelId,\n record,\n confidence: 0.95,\n strategy: \"provider-prefix-injection\",\n reason: viaInference\n ? `Injected provider prefix \"${prefix}/\" inferred from model name pattern`\n : `Injected provider prefix \"${prefix}/\"`,\n };\n }\n }\n return null;\n }\n\n private crossProviderCorrection(model: string): MatchCandidate | null {\n if (!model.includes(\"/\")) return null;\n const [wrongPrefix, ...rest] = model.split(\"/\");\n const slug = rest.join(\"/\");\n const inferred = this.inferProviderFromSlug(slug);\n if (!inferred || inferred === wrongPrefix) return null;\n const candidate = `${inferred}/${slug}`;\n let record = this.catalog.get(candidate);\n let modelId = candidate;\n if (!record) {\n const latest = this.findLatestVersioned(candidate);\n if (!latest) return null;\n record = latest.record;\n modelId = latest.modelId;\n }\n return {\n modelId,\n record,\n confidence: 0.9,\n strategy: \"cross-provider-correction\",\n reason: `Corrected provider prefix from \"${wrongPrefix}\" to \"${inferred}\" based on model name pattern`,\n };\n }\n\n private stripVersionSuffixes(model: string): string | null {\n for (const { re } of VERSION_STRIP_PATTERNS) {\n if (re.test(model)) {\n return model.replace(re, \"\");\n }\n }\n return null;\n }\n\n private dateSuffixMatch(model: string): MatchCandidate | null {\n if (model.includes(\"/\")) {\n const [prefix, slug] = model.split(\"/\", 2);\n const stripped = this.stripVersionSuffixes(slug);\n if (stripped && stripped !== slug) {\n const candidate = `${prefix}/${stripped}`;\n const record = this.catalog.get(candidate);\n if (record) {\n return {\n modelId: candidate,\n record,\n confidence: 0.85,\n strategy: \"date-suffix-strip\",\n reason: `Stripped date from slug \"${slug}\" → \"${stripped}\"`,\n };\n }\n }\n }\n\n const latest = this.findLatestVersioned(model);\n if (latest) {\n return {\n modelId: latest.modelId,\n record: latest.record,\n confidence: 0.85,\n strategy: \"date-suffix-strip\",\n reason: `Matched \"${model}\" to versioned catalog entry \"${latest.modelId}\" (latest)`,\n };\n }\n return null;\n }\n\n private findLatestVersioned(\n baseModelId: string,\n ): { modelId: string; record: AiModelRecord } | null {\n const candidates: Array<{ modelId: string; record: AiModelRecord; suffix: string }> = [];\n for (const [modelId, record] of this.catalog) {\n if (modelId === baseModelId) continue;\n if (modelId.startsWith(`${baseModelId}-`)) {\n candidates.push({\n modelId,\n record,\n suffix: modelId.slice(baseModelId.length + 1),\n });\n }\n }\n if (candidates.length === 0) return null;\n candidates.sort((a, b) => b.suffix.localeCompare(a.suffix));\n const best = candidates[0]!;\n return { modelId: best.modelId, record: best.record };\n }\n\n private shorthandMap(): Record<string, string> {\n return { ...SHORTHAND_MAP, ...this.ctx.options.additionalShorthands };\n }\n\n private partialMatch(\n model: string,\n provider: string | undefined,\n ): (MatchCandidate & { resolvedVia?: ResolutionStrategy[] }) | null {\n let best: { modelId: string; record: AiModelRecord; score: number } | null = null;\n const inputTokens = tokenise(model);\n if (inputTokens.length === 0) return null;\n\n for (const record of this.catalog.values()) {\n const recordTokens = new Set([\n ...tokenise(record.modelId),\n ...tokenise(record.name ?? \"\"),\n ]);\n const intersection = inputTokens.filter((t) => recordTokens.has(t));\n const overlapRatio = intersection.length / inputTokens.length;\n let score = overlapRatio * 0.6;\n\n if (record.modelId.includes(model)) score += 0.3;\n const slug = modelSlug(record.modelId);\n if (model.includes(slug)) score += 0.2;\n\n if (provider && provider === record.providerId) score += 0.15;\n\n const lenPenalty =\n (Math.abs(model.length - slug.length) / Math.max(model.length, slug.length, 1)) * 0.1;\n score -= lenPenalty;\n\n if (!best || score > best.score) {\n best = { modelId: record.modelId, record, score };\n }\n }\n\n if (!best || best.score < 0.65) return null;\n return {\n modelId: best.modelId,\n record: best.record,\n confidence: 0.65,\n strategy: \"partial-name-match\",\n reason: `Partial token match (score ${best.score.toFixed(2)})`,\n };\n }\n\n private computeRoutedViaOpenRouter(\n modelId: string,\n record: AiModelRecord | null,\n provider: string | undefined,\n originalProvider: string | undefined,\n ): boolean {\n const norm = normalizeProvider(originalProvider) ?? provider;\n if (norm === \"openrouter\") return true;\n if (norm && norm !== \"openrouter\") {\n if (shouldDefaultRouteViaOpenRouter(norm, this.ctx.options.routingEnv)) return true;\n return false;\n }\n\n const recordProvider = record?.providerId;\n if (recordProvider && shouldDefaultRouteViaOpenRouter(recordProvider, this.ctx.options.routingEnv)) {\n return true;\n }\n\n if (record?.availableOnOpenRouter && modelId.includes(\"/\")) return true;\n return false;\n }\n\n private success(args: {\n modelId: string;\n record: AiModelRecord | null;\n confidence: number;\n strategy: ResolutionStrategy;\n reason: string;\n resolvedVia: ResolutionStrategy[];\n normalisedInput: string;\n provider?: string;\n originalProvider?: string;\n }): ModelResolutionSuccess {\n return {\n found: true,\n modelId: args.modelId,\n record: args.record,\n routedViaOpenRouter: this.computeRoutedViaOpenRouter(\n args.modelId,\n args.record,\n args.provider,\n args.originalProvider,\n ),\n confidence: args.confidence,\n resolvedVia: args.resolvedVia,\n resolvedReason: args.reason,\n normalisedInput: args.normalisedInput,\n };\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
var _chunkTF4L2NECcjs = require('./chunk-TF4L2NEC.cjs');
|
|
10
|
+
|
|
11
|
+
// src/catalox/AiModelsCatalogClient.ts
|
|
12
|
+
function recordFromItem(data) {
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
var AiModelsCatalogClient = class {
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.catalox = options.catalox;
|
|
23
|
+
this.appId = _nullishCoalesce(options.appId, () => ( _chunkTF4L2NECcjs.AI_TOOLS_APP_ID));
|
|
24
|
+
this.catalogId = _nullishCoalesce(options.catalogId, () => ( _chunkTF4L2NECcjs.AI_MODELS_CATALOG_ID));
|
|
25
|
+
this.cacheTtlMs = _nullishCoalesce(options.cacheTtlMs, () => ( _chunkTF4L2NECcjs.DEFAULT_MODEL_CACHE_TTL_MS));
|
|
26
|
+
this.resolverOptions = options.resolverOptions;
|
|
27
|
+
}
|
|
28
|
+
context() {
|
|
29
|
+
return { appId: this.appId, superAdmin: true };
|
|
30
|
+
}
|
|
31
|
+
async getAllModels() {
|
|
32
|
+
const cached = _chunkTF4L2NECcjs.readCachedModels.call(void 0, this.appId, this.cacheTtlMs);
|
|
33
|
+
if (cached) return cached;
|
|
34
|
+
const map = /* @__PURE__ */ new Map();
|
|
35
|
+
const pageSize = 500;
|
|
36
|
+
let offset = 0;
|
|
37
|
+
for (; ; ) {
|
|
38
|
+
const result = await this.catalox.listCatalogItems(this.context(), this.catalogId, {
|
|
39
|
+
limit: pageSize,
|
|
40
|
+
offset
|
|
41
|
+
});
|
|
42
|
+
for (const item of result.items) {
|
|
43
|
+
const record = recordFromItem(item.data);
|
|
44
|
+
if (record.modelId) map.set(record.modelId, record);
|
|
45
|
+
}
|
|
46
|
+
if (result.items.length < pageSize) break;
|
|
47
|
+
offset += pageSize;
|
|
48
|
+
}
|
|
49
|
+
_chunkTF4L2NECcjs.writeCachedModels.call(void 0, this.appId, map, this.cacheTtlMs);
|
|
50
|
+
return map;
|
|
51
|
+
}
|
|
52
|
+
resolver(models, options) {
|
|
53
|
+
return new (0, _chunkTF4L2NECcjs.ModelNameResolver)(models, { ...this.resolverOptions, ...options });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a (provider, model) pair to a canonical model id and catalog record.
|
|
57
|
+
*/
|
|
58
|
+
async resolveModel(input, options) {
|
|
59
|
+
const models = await this.getAllModels();
|
|
60
|
+
return this.resolver(models, options).resolve(input);
|
|
61
|
+
}
|
|
62
|
+
async getModel(modelId, provider, options) {
|
|
63
|
+
const result = await this.resolveModel({ model: modelId, provider }, options);
|
|
64
|
+
return result.found ? result.record : null;
|
|
65
|
+
}
|
|
66
|
+
async refresh() {
|
|
67
|
+
_chunkTF4L2NECcjs.invalidateModelsCache.call(void 0, this.appId);
|
|
68
|
+
await this.getAllModels();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
exports.AiModelsCatalogClient = AiModelsCatalogClient;
|
|
75
|
+
//# sourceMappingURL=chunk-F2F4UEFD.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-F2F4UEFD.cjs","../src/catalox/AiModelsCatalogClient.ts"],"names":[],"mappings":"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","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-F2F4UEFD.cjs","sourcesContent":[null,"import type { Catalox, CataloxContext } from \"@x12i/catalox\";\nimport {\n DEFAULT_MODEL_CACHE_TTL_MS,\n invalidateModelsCache,\n readCachedModels,\n writeCachedModels,\n} from \"../cache/modelCache.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { AI_MODELS_CATALOG_ID, AI_TOOLS_APP_ID } from \"../catalog/aiModelsCatalogDescriptor.js\";\nimport { ModelNameResolver } from \"../sync/modelNameResolver/ModelNameResolver.js\";\nimport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolverOptions,\n} from \"../sync/modelNameResolver/types.js\";\n\nexport type AiModelsCatalogClientOptions = {\n catalox: Catalox;\n appId?: string;\n catalogId?: string;\n cacheTtlMs?: number;\n resolverOptions?: Omit<ModelResolverOptions, \"aliasRegistry\">;\n};\n\nfunction recordFromItem(data: Record<string, unknown>): AiModelRecord {\n return data as unknown as AiModelRecord;\n}\n\nexport class AiModelsCatalogClient {\n private readonly catalox: Catalox;\n private readonly appId: string;\n private readonly catalogId: string;\n private readonly cacheTtlMs: number;\n private readonly resolverOptions: AiModelsCatalogClientOptions[\"resolverOptions\"];\n\n constructor(options: AiModelsCatalogClientOptions) {\n this.catalox = options.catalox;\n this.appId = options.appId ?? AI_TOOLS_APP_ID;\n this.catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;\n this.cacheTtlMs = options.cacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS;\n this.resolverOptions = options.resolverOptions;\n }\n\n private context(): CataloxContext {\n return { appId: this.appId, superAdmin: true };\n }\n\n async getAllModels(): Promise<Map<string, AiModelRecord>> {\n const cached = readCachedModels(this.appId, this.cacheTtlMs);\n if (cached) return cached;\n\n const map = new Map<string, AiModelRecord>();\n const pageSize = 500;\n let offset = 0;\n\n for (;;) {\n const result = await this.catalox.listCatalogItems(this.context(), this.catalogId, {\n limit: pageSize,\n offset,\n });\n\n for (const item of result.items) {\n const record = recordFromItem(item.data as Record<string, unknown>);\n if (record.modelId) map.set(record.modelId, record);\n }\n\n if (result.items.length < pageSize) break;\n offset += pageSize;\n }\n\n writeCachedModels(this.appId, map, this.cacheTtlMs);\n return map;\n }\n\n private resolver(models: Map<string, AiModelRecord>, options?: ModelResolverOptions): ModelNameResolver {\n return new ModelNameResolver(models, { ...this.resolverOptions, ...options });\n }\n\n /**\n * Resolve a (provider, model) pair to a canonical model id and catalog record.\n */\n async resolveModel(\n input: ModelResolutionInput,\n options?: ModelResolverOptions,\n ): Promise<ModelResolutionResult> {\n const models = await this.getAllModels();\n return this.resolver(models, options).resolve(input);\n }\n\n async getModel(\n modelId: string,\n provider?: string,\n options?: ModelResolverOptions,\n ): Promise<AiModelRecord | null> {\n const result = await this.resolveModel({ model: modelId, provider }, options);\n return result.found ? result.record : null;\n }\n\n async refresh(): Promise<void> {\n invalidateModelsCache(this.appId);\n await this.getAllModels();\n }\n}\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ModelNameResolver
|
|
3
|
+
} from "./chunk-DJ5SWJDY.js";
|
|
4
|
+
|
|
5
|
+
// src/sync/modelNameResolver.ts
|
|
6
|
+
function createModelNameResolver(catalog, options) {
|
|
7
|
+
return new ModelNameResolver(catalog, options);
|
|
8
|
+
}
|
|
9
|
+
function resolveModel(input, models, aliasRegistry, provider) {
|
|
10
|
+
const resolver = new ModelNameResolver(models, { aliasRegistry });
|
|
11
|
+
const result = resolver.resolve({ model: input, provider });
|
|
12
|
+
if (!result.found || !result.record) return null;
|
|
13
|
+
return {
|
|
14
|
+
catalogModel: result.record,
|
|
15
|
+
matchedAlias: result.modelId,
|
|
16
|
+
routedViaOpenRouter: result.routedViaOpenRouter
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function isRoutedViaOpenRouter(provider, model, matchedKey) {
|
|
20
|
+
if (provider === "openrouter") return true;
|
|
21
|
+
if (provider && provider !== "openrouter") return false;
|
|
22
|
+
return model.modelId.includes("/") && matchedKey.includes("/");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
createModelNameResolver,
|
|
27
|
+
resolveModel,
|
|
28
|
+
isRoutedViaOpenRouter
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=chunk-G2G4KSC5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/sync/modelNameResolver.ts"],"sourcesContent":["import type { AliasRegistry } from \"../aliases/AliasRegistry.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { ModelNameResolver } from \"./modelNameResolver/ModelNameResolver.js\";\nimport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolutionSuccess,\n ModelResolverOptions,\n ResolvedModel,\n} from \"./modelNameResolver/types.js\";\n\nexport { ModelNameResolver } from \"./modelNameResolver/ModelNameResolver.js\";\nexport { buildCatalogIndexes } from \"./modelNameResolver/catalogIndexes.js\";\nexport * from \"./modelNameResolver/types.js\";\nexport {\n loadOpenRouterRoutingEnv,\n shouldDefaultRouteViaOpenRouter,\n providerIdToEnvKeyPrefix,\n vendorApiKeyEnvName,\n} from \"./openRouterRoutingEnv.js\";\nexport type { OpenRouterRoutingConfig } from \"./openRouterRoutingEnv.js\";\nexport { normalizeString, normalizeProvider } from \"./modelNameResolver/normalize.js\";\n\nexport function createModelNameResolver(\n catalog: Map<string, AiModelRecord>,\n options?: ModelResolverOptions,\n): ModelNameResolver {\n return new ModelNameResolver(catalog, options);\n}\n\n/**\n * @deprecated Prefer `ModelNameResolver.resolve()` for full resolution metadata.\n */\nexport function resolveModel(\n input: string,\n models: Map<string, AiModelRecord>,\n aliasRegistry?: AliasRegistry,\n provider?: string,\n): ResolvedModel | null {\n const resolver = new ModelNameResolver(models, { aliasRegistry });\n const result = resolver.resolve({ model: input, provider });\n if (!result.found || !result.record) return null;\n return {\n catalogModel: result.record,\n matchedAlias: result.modelId,\n routedViaOpenRouter: result.routedViaOpenRouter,\n };\n}\n\nexport function isRoutedViaOpenRouter(\n provider: string | undefined,\n model: AiModelRecord,\n matchedKey: string,\n): boolean {\n if (provider === \"openrouter\") return true;\n if (provider && provider !== \"openrouter\") return false;\n return model.modelId.includes(\"/\") && matchedKey.includes(\"/\");\n}\n\nexport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolutionSuccess,\n ModelResolverOptions,\n};\n"],"mappings":";;;;;AAuBO,SAAS,wBACd,SACA,SACmB;AACnB,SAAO,IAAI,kBAAkB,SAAS,OAAO;AAC/C;AAKO,SAAS,aACd,OACA,QACA,eACA,UACsB;AACtB,QAAM,WAAW,IAAI,kBAAkB,QAAQ,EAAE,cAAc,CAAC;AAChE,QAAM,SAAS,SAAS,QAAQ,EAAE,OAAO,OAAO,SAAS,CAAC;AAC1D,MAAI,CAAC,OAAO,SAAS,CAAC,OAAO,OAAQ,QAAO;AAC5C,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,cAAc,OAAO;AAAA,IACrB,qBAAqB,OAAO;AAAA,EAC9B;AACF;AAEO,SAAS,sBACd,UACA,OACA,YACS;AACT,MAAI,aAAa,aAAc,QAAO;AACtC,MAAI,YAAY,aAAa,aAAc,QAAO;AAClD,SAAO,MAAM,QAAQ,SAAS,GAAG,KAAK,WAAW,SAAS,GAAG;AAC/D;","names":[]}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/catalox/modelDocId.ts
|
|
2
|
+
var CX = "cx~";
|
|
3
|
+
var MODEL_MARKER = "m~";
|
|
4
|
+
function encodeModelFirestoreDocId(modelId) {
|
|
5
|
+
if (!modelId.includes("/")) return modelId;
|
|
6
|
+
return `${CX}${MODEL_MARKER}${Buffer.from(modelId, "utf8").toString("base64url")}`;
|
|
7
|
+
}
|
|
8
|
+
function decodeModelFirestoreDocId(docId) {
|
|
9
|
+
const prefix = `${CX}${MODEL_MARKER}`;
|
|
10
|
+
if (docId.startsWith(prefix)) {
|
|
11
|
+
return Buffer.from(docId.slice(prefix.length), "base64url").toString("utf8");
|
|
12
|
+
}
|
|
13
|
+
return docId;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/catalox/upsertAiModelRecord.ts
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
var _firebase = require('@x12i/catalox/firebase');
|
|
22
|
+
function sanitizeForFirestore(value) {
|
|
23
|
+
return JSON.parse(JSON.stringify(value));
|
|
24
|
+
}
|
|
25
|
+
function buildIndexed(record) {
|
|
26
|
+
return {
|
|
27
|
+
modelId: record.modelId,
|
|
28
|
+
providerId: record.providerId,
|
|
29
|
+
name: record.name,
|
|
30
|
+
canonicalSlug: record.canonicalSlug,
|
|
31
|
+
contextLength: record.contextLength,
|
|
32
|
+
status: record.status,
|
|
33
|
+
primaryOutputModality: record.primaryOutputModality,
|
|
34
|
+
supportsTools: record.supportsTools,
|
|
35
|
+
supportsReasoning: record.supportsReasoning,
|
|
36
|
+
supportsStreaming: record.supportsStreaming,
|
|
37
|
+
isModerated: record.isModerated,
|
|
38
|
+
syncedAt: record.syncedAt
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function upsertAiModelRecord(options) {
|
|
42
|
+
const { record, catalogId, context, firestore } = options;
|
|
43
|
+
const appId = _nullishCoalesce(context.appId, () => ( "ai-tools"));
|
|
44
|
+
const layout = await _firebase.resolveNativeItemsLayout.call(void 0, firestore, catalogId);
|
|
45
|
+
const col = layout === "legacy" ? _firebase.legacyNativeItemsCollectionRef.call(void 0, firestore, catalogId) : _firebase.flatNativeItemsCollectionRef.call(void 0, firestore, catalogId);
|
|
46
|
+
const storageDocId = encodeModelFirestoreDocId(record.modelId);
|
|
47
|
+
const existing = await col.doc(storageDocId).get();
|
|
48
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
49
|
+
const data = sanitizeForFirestore(record);
|
|
50
|
+
const payload = sanitizeForFirestore({
|
|
51
|
+
itemId: record.modelId,
|
|
52
|
+
catalogId,
|
|
53
|
+
appScopedOwnerId: appId,
|
|
54
|
+
indexed: buildIndexed(record),
|
|
55
|
+
data,
|
|
56
|
+
metadata: {
|
|
57
|
+
createdAt: String(_nullishCoalesce(_optionalChain([existing, 'access', _ => _.data, 'call', _2 => _2(), 'optionalAccess', _3 => _3.metadata, 'optionalAccess', _4 => _4.createdAt]), () => ( now))),
|
|
58
|
+
lastUpdate: now,
|
|
59
|
+
domainIds: [],
|
|
60
|
+
agentIds: []
|
|
61
|
+
},
|
|
62
|
+
version: (_nullishCoalesce(_optionalChain([existing, 'access', _5 => _5.data, 'call', _6 => _6(), 'optionalAccess', _7 => _7.version]), () => ( 0))) + 1
|
|
63
|
+
});
|
|
64
|
+
await col.doc(storageDocId).set(payload, { merge: true });
|
|
65
|
+
}
|
|
66
|
+
var BATCH_SIZE = 400;
|
|
67
|
+
async function batchUpsertAiModelRecords(firestore, catalogId, context, records) {
|
|
68
|
+
const layout = await _firebase.resolveNativeItemsLayout.call(void 0, firestore, catalogId);
|
|
69
|
+
const col = layout === "legacy" ? _firebase.legacyNativeItemsCollectionRef.call(void 0, firestore, catalogId) : _firebase.flatNativeItemsCollectionRef.call(void 0, firestore, catalogId);
|
|
70
|
+
const appId = _nullishCoalesce(context.appId, () => ( "ai-tools"));
|
|
71
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
72
|
+
for (let i = 0; i < records.length; i += BATCH_SIZE) {
|
|
73
|
+
const chunk = records.slice(i, i + BATCH_SIZE);
|
|
74
|
+
const batch = firestore.batch();
|
|
75
|
+
for (const record of chunk) {
|
|
76
|
+
const storageDocId = encodeModelFirestoreDocId(record.modelId);
|
|
77
|
+
const data = sanitizeForFirestore(record);
|
|
78
|
+
const payload = sanitizeForFirestore({
|
|
79
|
+
itemId: record.modelId,
|
|
80
|
+
catalogId,
|
|
81
|
+
appScopedOwnerId: appId,
|
|
82
|
+
indexed: buildIndexed(record),
|
|
83
|
+
data,
|
|
84
|
+
metadata: {
|
|
85
|
+
createdAt: now,
|
|
86
|
+
lastUpdate: now,
|
|
87
|
+
domainIds: [],
|
|
88
|
+
agentIds: []
|
|
89
|
+
},
|
|
90
|
+
version: 1
|
|
91
|
+
});
|
|
92
|
+
batch.set(col.doc(storageDocId), payload, { merge: true });
|
|
93
|
+
}
|
|
94
|
+
await batch.commit();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
exports.encodeModelFirestoreDocId = encodeModelFirestoreDocId; exports.decodeModelFirestoreDocId = decodeModelFirestoreDocId; exports.sanitizeForFirestore = sanitizeForFirestore; exports.upsertAiModelRecord = upsertAiModelRecord; exports.batchUpsertAiModelRecords = batchUpsertAiModelRecords;
|
|
105
|
+
//# sourceMappingURL=chunk-HHNHWYTP.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-HHNHWYTP.cjs","../src/catalox/modelDocId.ts","../src/catalox/upsertAiModelRecord.ts"],"names":[],"mappings":"AAAA;ACIA,IAAM,GAAA,EAAK,KAAA;AACX,IAAM,aAAA,EAAe,IAAA;AAEd,SAAS,yBAAA,CAA0B,OAAA,EAAyB;AACjE,EAAA,GAAA,CAAI,CAAC,OAAA,CAAQ,QAAA,CAAS,GAAG,CAAA,EAAG,OAAO,OAAA;AACnC,EAAA,OAAO,CAAA,EAAA;AACT;AAEgB;AACR,EAAA;AACF,EAAA;AACF,IAAA;AACF,EAAA;AACO,EAAA;AACT;ADJU;AACA;AEbV;AACE;AACA;AACA;AACK;AAKS;AACP,EAAA;AACT;AAES;AACA,EAAA;AACL,IAAA;AACA,IAAA;AACM,IAAA;AACN,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;AAYA;AACU,EAAA;AACF,EAAA;AAEA,EAAA;AACA,EAAA;AAKA,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AAEA,EAAA;AACJ,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AACA,IAAA;AACD,EAAA;AAEK,EAAA;AACR;AAEM;AAEN;AAMQ,EAAA;AACA,EAAA;AAKA,EAAA;AACA,EAAA;AAEN,EAAA;AACQ,IAAA;AACA,IAAA;AAEN,IAAA;AACE,MAAA;AACA,MAAA;AACA,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACF,QAAA;AACA,QAAA;AACD,MAAA;AACD,MAAA;AACF,IAAA;AAEM,IAAA;AACR,EAAA;AACF;AFtBU;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-HHNHWYTP.cjs","sourcesContent":[null,"/**\n * Firestore document ids cannot contain `/`. OpenRouter model ids use `provider/model`.\n * We encode global item doc ids as `cx~m~<base64url(modelId)>` while keeping logical `modelId` in data.\n */\nconst CX = \"cx~\";\nconst MODEL_MARKER = \"m~\";\n\nexport function encodeModelFirestoreDocId(modelId: string): string {\n if (!modelId.includes(\"/\")) return modelId;\n return `${CX}${MODEL_MARKER}${Buffer.from(modelId, \"utf8\").toString(\"base64url\")}`;\n}\n\nexport function decodeModelFirestoreDocId(docId: string): string {\n const prefix = `${CX}${MODEL_MARKER}`;\n if (docId.startsWith(prefix)) {\n return Buffer.from(docId.slice(prefix.length), \"base64url\").toString(\"utf8\");\n }\n return docId;\n}\n\nexport function modelIdNeedsEncodedDocId(modelId: string): boolean {\n return modelId.includes(\"/\");\n}\n","import type { Firestore } from \"firebase-admin/firestore\";\nimport type { CataloxContext } from \"@x12i/catalox\";\nimport {\n flatNativeItemsCollectionRef,\n legacyNativeItemsCollectionRef,\n resolveNativeItemsLayout,\n} from \"@x12i/catalox/firebase\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { encodeModelFirestoreDocId } from \"./modelDocId.js\";\n\n/** Firestore rejects `undefined` — strip before write. */\nexport function sanitizeForFirestore<T>(value: T): T {\n return JSON.parse(JSON.stringify(value)) as T;\n}\n\nfunction buildIndexed(record: AiModelRecord): Record<string, string | number | boolean> {\n return {\n modelId: record.modelId,\n providerId: record.providerId,\n name: record.name,\n canonicalSlug: record.canonicalSlug,\n contextLength: record.contextLength,\n status: record.status,\n primaryOutputModality: record.primaryOutputModality,\n supportsTools: record.supportsTools,\n supportsReasoning: record.supportsReasoning,\n supportsStreaming: record.supportsStreaming,\n isModerated: record.isModerated,\n syncedAt: record.syncedAt,\n };\n}\n\nexport type UpsertAiModelRecordOptions = {\n firestore: Firestore;\n context: CataloxContext;\n catalogId: string;\n record: AiModelRecord;\n};\n\n/**\n * Upserts one ai-models row via Firestore (safe doc ids for `provider/model` ids).\n */\nexport async function upsertAiModelRecord(options: UpsertAiModelRecordOptions): Promise<void> {\n const { record, catalogId, context, firestore } = options;\n const appId = context.appId ?? \"ai-tools\";\n\n const layout = await resolveNativeItemsLayout(firestore, catalogId);\n const col =\n layout === \"legacy\"\n ? legacyNativeItemsCollectionRef(firestore, catalogId)\n : flatNativeItemsCollectionRef(firestore, catalogId);\n\n const storageDocId = encodeModelFirestoreDocId(record.modelId);\n const existing = await col.doc(storageDocId).get();\n const now = new Date().toISOString();\n const data = sanitizeForFirestore(record);\n\n const payload = sanitizeForFirestore({\n itemId: record.modelId,\n catalogId,\n appScopedOwnerId: appId,\n indexed: buildIndexed(record),\n data,\n metadata: {\n createdAt: String(existing.data()?.metadata?.createdAt ?? now),\n lastUpdate: now,\n domainIds: [],\n agentIds: [],\n },\n version: (existing.data()?.version ?? 0) + 1,\n });\n\n await col.doc(storageDocId).set(payload, { merge: true });\n}\n\nconst BATCH_SIZE = 400;\n\nexport async function batchUpsertAiModelRecords(\n firestore: Firestore,\n catalogId: string,\n context: CataloxContext,\n records: AiModelRecord[],\n): Promise<void> {\n const layout = await resolveNativeItemsLayout(firestore, catalogId);\n const col =\n layout === \"legacy\"\n ? legacyNativeItemsCollectionRef(firestore, catalogId)\n : flatNativeItemsCollectionRef(firestore, catalogId);\n\n const appId = context.appId ?? \"ai-tools\";\n const now = new Date().toISOString();\n\n for (let i = 0; i < records.length; i += BATCH_SIZE) {\n const chunk = records.slice(i, i + BATCH_SIZE);\n const batch = firestore.batch();\n\n for (const record of chunk) {\n const storageDocId = encodeModelFirestoreDocId(record.modelId);\n const data = sanitizeForFirestore(record);\n const payload = sanitizeForFirestore({\n itemId: record.modelId,\n catalogId,\n appScopedOwnerId: appId,\n indexed: buildIndexed(record),\n data,\n metadata: {\n createdAt: now,\n lastUpdate: now,\n domainIds: [],\n agentIds: [],\n },\n version: 1,\n });\n batch.set(col.doc(storageDocId), payload, { merge: true });\n }\n\n await batch.commit();\n }\n}\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/cost/CostCalculator.ts
|
|
2
|
+
var CostCalculator = class {
|
|
3
|
+
constructor(catalog, options = {}) {
|
|
4
|
+
this.catalog = catalog;
|
|
5
|
+
this.aliasRegistry = options.aliasRegistry;
|
|
6
|
+
this.includeBreakdown = _nullishCoalesce(options.includeBreakdown, () => ( true));
|
|
7
|
+
this.resolverOptions = options.resolverOptions;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
async calculate(input) {
|
|
14
|
+
const resolved = await this.catalog.resolveModel(
|
|
15
|
+
{ model: input.modelUsed, provider: input.provider },
|
|
16
|
+
{
|
|
17
|
+
...this.resolverOptions,
|
|
18
|
+
aliasRegistry: _nullishCoalesce(this.aliasRegistry, () => ( _optionalChain([this, 'access', _ => _.resolverOptions, 'optionalAccess', _2 => _2.aliasRegistry])))
|
|
19
|
+
}
|
|
20
|
+
);
|
|
21
|
+
if (!resolved.found || !resolved.record) {
|
|
22
|
+
console.warn(
|
|
23
|
+
`[ai-tools] Unknown model "${input.modelUsed}" \u2014 returning zero-cost fallback.`
|
|
24
|
+
);
|
|
25
|
+
const emptyPricing = {
|
|
26
|
+
promptUsdPerToken: 0,
|
|
27
|
+
completionUsdPerToken: 0,
|
|
28
|
+
imageUsdPerUnit: 0,
|
|
29
|
+
requestUsdPerRequest: 0,
|
|
30
|
+
pricedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
31
|
+
source: "manual"
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
cost: 0,
|
|
35
|
+
resolvedModelId: input.modelUsed,
|
|
36
|
+
routedViaOpenRouter: resolved.found ? resolved.routedViaOpenRouter : input.provider === "openrouter",
|
|
37
|
+
isAuthoritative: false,
|
|
38
|
+
pricingSnapshot: emptyPricing,
|
|
39
|
+
source: "estimate-fallback"
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const { record, routedViaOpenRouter, modelId } = resolved;
|
|
43
|
+
const pricing = record.pricing;
|
|
44
|
+
const { tokens } = input;
|
|
45
|
+
let promptCost = tokens.prompt * pricing.promptUsdPerToken;
|
|
46
|
+
let completionCost = tokens.completion * pricing.completionUsdPerToken;
|
|
47
|
+
const cachingCost = (_nullishCoalesce(tokens.cacheWrite, () => ( 0))) * (_nullishCoalesce(pricing.cacheWriteUsdPerToken, () => ( 0))) + (_nullishCoalesce(tokens.cached, () => ( 0))) * (_nullishCoalesce(pricing.cacheReadUsdPerToken, () => ( 0)));
|
|
48
|
+
const reasoningCost = (_nullishCoalesce(tokens.reasoning, () => ( 0))) * (_nullishCoalesce(pricing.reasoningUsdPerToken, () => ( pricing.promptUsdPerToken)));
|
|
49
|
+
const audioCost = (_nullishCoalesce(tokens.audio, () => ( 0))) * pricing.promptUsdPerToken;
|
|
50
|
+
const imageCost = (_nullishCoalesce(tokens.image, () => ( 0))) * (_nullishCoalesce(pricing.imageUsdPerUnit, () => ( 0)));
|
|
51
|
+
const requestFlat = pricing.requestUsdPerRequest;
|
|
52
|
+
if (routedViaOpenRouter) {
|
|
53
|
+
promptCost += tokens.prompt * (_nullishCoalesce(pricing.openRouterMarkupUsdPerInputToken, () => ( 0)));
|
|
54
|
+
completionCost += tokens.completion * (_nullishCoalesce(pricing.openRouterMarkupUsdPerOutputToken, () => ( 0)));
|
|
55
|
+
}
|
|
56
|
+
const cost = promptCost + completionCost + cachingCost + reasoningCost + audioCost + imageCost + requestFlat;
|
|
57
|
+
const result = {
|
|
58
|
+
cost,
|
|
59
|
+
resolvedModelId: modelId,
|
|
60
|
+
routedViaOpenRouter,
|
|
61
|
+
isAuthoritative: true,
|
|
62
|
+
pricingSnapshot: pricing,
|
|
63
|
+
source: "catalog"
|
|
64
|
+
};
|
|
65
|
+
if (this.includeBreakdown) {
|
|
66
|
+
result.breakdown = {
|
|
67
|
+
promptCostUsd: promptCost,
|
|
68
|
+
completionCostUsd: completionCost,
|
|
69
|
+
cachingCostUsd: cachingCost || void 0,
|
|
70
|
+
reasoningCostUsd: reasoningCost || void 0,
|
|
71
|
+
audioCostUsd: audioCost || void 0,
|
|
72
|
+
imageCostUsd: imageCost || void 0,
|
|
73
|
+
requestFlatCostUsd: requestFlat || void 0
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
exports.CostCalculator = CostCalculator;
|
|
83
|
+
//# sourceMappingURL=chunk-HN6UAQAE.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-HN6UAQAE.cjs","../src/cost/CostCalculator.ts"],"names":[],"mappings":"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","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-HN6UAQAE.cjs","sourcesContent":[null,"import type { AliasRegistry } from \"../aliases/AliasRegistry.js\";\nimport type { AiModelsCatalogClient } from \"../catalox/AiModelsCatalogClient.js\";\nimport type { ModelResolverOptions } from \"../sync/modelNameResolver/types.js\";\nimport type { AiCostResult, AiModelPricing, AiUsageInput } from \"./types.js\";\n\nexport type CostCalculatorOptions = {\n aliasRegistry?: AliasRegistry;\n includeBreakdown?: boolean;\n resolverOptions?: ModelResolverOptions;\n};\n\nexport class CostCalculator {\n private readonly aliasRegistry?: AliasRegistry;\n private readonly includeBreakdown: boolean;\n private readonly resolverOptions?: ModelResolverOptions;\n\n constructor(\n private readonly catalog: AiModelsCatalogClient,\n options: CostCalculatorOptions = {},\n ) {\n this.aliasRegistry = options.aliasRegistry;\n this.includeBreakdown = options.includeBreakdown ?? true;\n this.resolverOptions = options.resolverOptions;\n }\n\n async calculate(input: AiUsageInput): Promise<AiCostResult> {\n const resolved = await this.catalog.resolveModel(\n { model: input.modelUsed, provider: input.provider },\n {\n ...this.resolverOptions,\n aliasRegistry: this.aliasRegistry ?? this.resolverOptions?.aliasRegistry,\n },\n );\n\n if (!resolved.found || !resolved.record) {\n console.warn(\n `[ai-tools] Unknown model \"${input.modelUsed}\" — returning zero-cost fallback.`,\n );\n const emptyPricing: AiModelPricing = {\n promptUsdPerToken: 0,\n completionUsdPerToken: 0,\n imageUsdPerUnit: 0,\n requestUsdPerRequest: 0,\n pricedAt: new Date().toISOString(),\n source: \"manual\",\n };\n return {\n cost: 0,\n resolvedModelId: input.modelUsed,\n routedViaOpenRouter:\n resolved.found ? resolved.routedViaOpenRouter : input.provider === \"openrouter\",\n isAuthoritative: false,\n pricingSnapshot: emptyPricing,\n source: \"estimate-fallback\",\n };\n }\n\n const { record, routedViaOpenRouter, modelId } = resolved;\n const pricing = record.pricing;\n const { tokens } = input;\n\n let promptCost = tokens.prompt * pricing.promptUsdPerToken;\n let completionCost = tokens.completion * pricing.completionUsdPerToken;\n\n const cachingCost =\n (tokens.cacheWrite ?? 0) * (pricing.cacheWriteUsdPerToken ?? 0) +\n (tokens.cached ?? 0) * (pricing.cacheReadUsdPerToken ?? 0);\n\n const reasoningCost =\n (tokens.reasoning ?? 0) *\n (pricing.reasoningUsdPerToken ?? pricing.promptUsdPerToken);\n\n const audioCost = (tokens.audio ?? 0) * pricing.promptUsdPerToken;\n const imageCost = (tokens.image ?? 0) * (pricing.imageUsdPerUnit ?? 0);\n const requestFlat = pricing.requestUsdPerRequest;\n\n if (routedViaOpenRouter) {\n promptCost +=\n tokens.prompt * (pricing.openRouterMarkupUsdPerInputToken ?? 0);\n completionCost +=\n tokens.completion * (pricing.openRouterMarkupUsdPerOutputToken ?? 0);\n }\n\n const cost =\n promptCost +\n completionCost +\n cachingCost +\n reasoningCost +\n audioCost +\n imageCost +\n requestFlat;\n\n const result: AiCostResult = {\n cost,\n resolvedModelId: modelId,\n routedViaOpenRouter,\n isAuthoritative: true,\n pricingSnapshot: pricing,\n source: \"catalog\",\n };\n\n if (this.includeBreakdown) {\n result.breakdown = {\n promptCostUsd: promptCost,\n completionCostUsd: completionCost,\n cachingCostUsd: cachingCost || undefined,\n reasoningCostUsd: reasoningCost || undefined,\n audioCostUsd: audioCost || undefined,\n imageCostUsd: imageCost || undefined,\n requestFlatCostUsd: requestFlat || undefined,\n };\n }\n\n return result;\n }\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-KHODXGPV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AI_MODELS_CATALOG_ID,
|
|
3
|
+
AI_TOOLS_APP_ID,
|
|
4
|
+
DEFAULT_MODEL_CACHE_TTL_MS,
|
|
5
|
+
ModelNameResolver,
|
|
6
|
+
invalidateModelsCache,
|
|
7
|
+
readCachedModels,
|
|
8
|
+
writeCachedModels
|
|
9
|
+
} from "./chunk-DJ5SWJDY.js";
|
|
10
|
+
|
|
11
|
+
// src/catalox/AiModelsCatalogClient.ts
|
|
12
|
+
function recordFromItem(data) {
|
|
13
|
+
return data;
|
|
14
|
+
}
|
|
15
|
+
var AiModelsCatalogClient = class {
|
|
16
|
+
catalox;
|
|
17
|
+
appId;
|
|
18
|
+
catalogId;
|
|
19
|
+
cacheTtlMs;
|
|
20
|
+
resolverOptions;
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.catalox = options.catalox;
|
|
23
|
+
this.appId = options.appId ?? AI_TOOLS_APP_ID;
|
|
24
|
+
this.catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;
|
|
25
|
+
this.cacheTtlMs = options.cacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS;
|
|
26
|
+
this.resolverOptions = options.resolverOptions;
|
|
27
|
+
}
|
|
28
|
+
context() {
|
|
29
|
+
return { appId: this.appId, superAdmin: true };
|
|
30
|
+
}
|
|
31
|
+
async getAllModels() {
|
|
32
|
+
const cached = readCachedModels(this.appId, this.cacheTtlMs);
|
|
33
|
+
if (cached) return cached;
|
|
34
|
+
const map = /* @__PURE__ */ new Map();
|
|
35
|
+
const pageSize = 500;
|
|
36
|
+
let offset = 0;
|
|
37
|
+
for (; ; ) {
|
|
38
|
+
const result = await this.catalox.listCatalogItems(this.context(), this.catalogId, {
|
|
39
|
+
limit: pageSize,
|
|
40
|
+
offset
|
|
41
|
+
});
|
|
42
|
+
for (const item of result.items) {
|
|
43
|
+
const record = recordFromItem(item.data);
|
|
44
|
+
if (record.modelId) map.set(record.modelId, record);
|
|
45
|
+
}
|
|
46
|
+
if (result.items.length < pageSize) break;
|
|
47
|
+
offset += pageSize;
|
|
48
|
+
}
|
|
49
|
+
writeCachedModels(this.appId, map, this.cacheTtlMs);
|
|
50
|
+
return map;
|
|
51
|
+
}
|
|
52
|
+
resolver(models, options) {
|
|
53
|
+
return new ModelNameResolver(models, { ...this.resolverOptions, ...options });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Resolve a (provider, model) pair to a canonical model id and catalog record.
|
|
57
|
+
*/
|
|
58
|
+
async resolveModel(input, options) {
|
|
59
|
+
const models = await this.getAllModels();
|
|
60
|
+
return this.resolver(models, options).resolve(input);
|
|
61
|
+
}
|
|
62
|
+
async getModel(modelId, provider, options) {
|
|
63
|
+
const result = await this.resolveModel({ model: modelId, provider }, options);
|
|
64
|
+
return result.found ? result.record : null;
|
|
65
|
+
}
|
|
66
|
+
async refresh() {
|
|
67
|
+
invalidateModelsCache(this.appId);
|
|
68
|
+
await this.getAllModels();
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export {
|
|
73
|
+
AiModelsCatalogClient
|
|
74
|
+
};
|
|
75
|
+
//# sourceMappingURL=chunk-KQOALKKX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/catalox/AiModelsCatalogClient.ts"],"sourcesContent":["import type { Catalox, CataloxContext } from \"@x12i/catalox\";\nimport {\n DEFAULT_MODEL_CACHE_TTL_MS,\n invalidateModelsCache,\n readCachedModels,\n writeCachedModels,\n} from \"../cache/modelCache.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { AI_MODELS_CATALOG_ID, AI_TOOLS_APP_ID } from \"../catalog/aiModelsCatalogDescriptor.js\";\nimport { ModelNameResolver } from \"../sync/modelNameResolver/ModelNameResolver.js\";\nimport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolverOptions,\n} from \"../sync/modelNameResolver/types.js\";\n\nexport type AiModelsCatalogClientOptions = {\n catalox: Catalox;\n appId?: string;\n catalogId?: string;\n cacheTtlMs?: number;\n resolverOptions?: Omit<ModelResolverOptions, \"aliasRegistry\">;\n};\n\nfunction recordFromItem(data: Record<string, unknown>): AiModelRecord {\n return data as unknown as AiModelRecord;\n}\n\nexport class AiModelsCatalogClient {\n private readonly catalox: Catalox;\n private readonly appId: string;\n private readonly catalogId: string;\n private readonly cacheTtlMs: number;\n private readonly resolverOptions: AiModelsCatalogClientOptions[\"resolverOptions\"];\n\n constructor(options: AiModelsCatalogClientOptions) {\n this.catalox = options.catalox;\n this.appId = options.appId ?? AI_TOOLS_APP_ID;\n this.catalogId = options.catalogId ?? AI_MODELS_CATALOG_ID;\n this.cacheTtlMs = options.cacheTtlMs ?? DEFAULT_MODEL_CACHE_TTL_MS;\n this.resolverOptions = options.resolverOptions;\n }\n\n private context(): CataloxContext {\n return { appId: this.appId, superAdmin: true };\n }\n\n async getAllModels(): Promise<Map<string, AiModelRecord>> {\n const cached = readCachedModels(this.appId, this.cacheTtlMs);\n if (cached) return cached;\n\n const map = new Map<string, AiModelRecord>();\n const pageSize = 500;\n let offset = 0;\n\n for (;;) {\n const result = await this.catalox.listCatalogItems(this.context(), this.catalogId, {\n limit: pageSize,\n offset,\n });\n\n for (const item of result.items) {\n const record = recordFromItem(item.data as Record<string, unknown>);\n if (record.modelId) map.set(record.modelId, record);\n }\n\n if (result.items.length < pageSize) break;\n offset += pageSize;\n }\n\n writeCachedModels(this.appId, map, this.cacheTtlMs);\n return map;\n }\n\n private resolver(models: Map<string, AiModelRecord>, options?: ModelResolverOptions): ModelNameResolver {\n return new ModelNameResolver(models, { ...this.resolverOptions, ...options });\n }\n\n /**\n * Resolve a (provider, model) pair to a canonical model id and catalog record.\n */\n async resolveModel(\n input: ModelResolutionInput,\n options?: ModelResolverOptions,\n ): Promise<ModelResolutionResult> {\n const models = await this.getAllModels();\n return this.resolver(models, options).resolve(input);\n }\n\n async getModel(\n modelId: string,\n provider?: string,\n options?: ModelResolverOptions,\n ): Promise<AiModelRecord | null> {\n const result = await this.resolveModel({ model: modelId, provider }, options);\n return result.found ? result.record : null;\n }\n\n async refresh(): Promise<void> {\n invalidateModelsCache(this.appId);\n await this.getAllModels();\n }\n}\n"],"mappings":";;;;;;;;;;;AAwBA,SAAS,eAAe,MAA8C;AACpE,SAAO;AACT;AAEO,IAAM,wBAAN,MAA4B;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,SAAuC;AACjD,SAAK,UAAU,QAAQ;AACvB,SAAK,QAAQ,QAAQ,SAAS;AAC9B,SAAK,YAAY,QAAQ,aAAa;AACtC,SAAK,aAAa,QAAQ,cAAc;AACxC,SAAK,kBAAkB,QAAQ;AAAA,EACjC;AAAA,EAEQ,UAA0B;AAChC,WAAO,EAAE,OAAO,KAAK,OAAO,YAAY,KAAK;AAAA,EAC/C;AAAA,EAEA,MAAM,eAAoD;AACxD,UAAM,SAAS,iBAAiB,KAAK,OAAO,KAAK,UAAU;AAC3D,QAAI,OAAQ,QAAO;AAEnB,UAAM,MAAM,oBAAI,IAA2B;AAC3C,UAAM,WAAW;AACjB,QAAI,SAAS;AAEb,eAAS;AACP,YAAM,SAAS,MAAM,KAAK,QAAQ,iBAAiB,KAAK,QAAQ,GAAG,KAAK,WAAW;AAAA,QACjF,OAAO;AAAA,QACP;AAAA,MACF,CAAC;AAED,iBAAW,QAAQ,OAAO,OAAO;AAC/B,cAAM,SAAS,eAAe,KAAK,IAA+B;AAClE,YAAI,OAAO,QAAS,KAAI,IAAI,OAAO,SAAS,MAAM;AAAA,MACpD;AAEA,UAAI,OAAO,MAAM,SAAS,SAAU;AACpC,gBAAU;AAAA,IACZ;AAEA,sBAAkB,KAAK,OAAO,KAAK,KAAK,UAAU;AAClD,WAAO;AAAA,EACT;AAAA,EAEQ,SAAS,QAAoC,SAAmD;AACtG,WAAO,IAAI,kBAAkB,QAAQ,EAAE,GAAG,KAAK,iBAAiB,GAAG,QAAQ,CAAC;AAAA,EAC9E;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,OACA,SACgC;AAChC,UAAM,SAAS,MAAM,KAAK,aAAa;AACvC,WAAO,KAAK,SAAS,QAAQ,OAAO,EAAE,QAAQ,KAAK;AAAA,EACrD;AAAA,EAEA,MAAM,SACJ,SACA,UACA,SAC+B;AAC/B,UAAM,SAAS,MAAM,KAAK,aAAa,EAAE,OAAO,SAAS,SAAS,GAAG,OAAO;AAC5E,WAAO,OAAO,QAAQ,OAAO,SAAS;AAAA,EACxC;AAAA,EAEA,MAAM,UAAyB;AAC7B,0BAAsB,KAAK,KAAK;AAChC,UAAM,KAAK,aAAa;AAAA,EAC1B;AACF;","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true});
|
|
2
|
+
|
|
3
|
+
var _chunkTF4L2NECcjs = require('./chunk-TF4L2NEC.cjs');
|
|
4
|
+
|
|
5
|
+
// src/sync/modelNameResolver.ts
|
|
6
|
+
function createModelNameResolver(catalog, options) {
|
|
7
|
+
return new (0, _chunkTF4L2NECcjs.ModelNameResolver)(catalog, options);
|
|
8
|
+
}
|
|
9
|
+
function resolveModel(input, models, aliasRegistry, provider) {
|
|
10
|
+
const resolver = new (0, _chunkTF4L2NECcjs.ModelNameResolver)(models, { aliasRegistry });
|
|
11
|
+
const result = resolver.resolve({ model: input, provider });
|
|
12
|
+
if (!result.found || !result.record) return null;
|
|
13
|
+
return {
|
|
14
|
+
catalogModel: result.record,
|
|
15
|
+
matchedAlias: result.modelId,
|
|
16
|
+
routedViaOpenRouter: result.routedViaOpenRouter
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function isRoutedViaOpenRouter(provider, model, matchedKey) {
|
|
20
|
+
if (provider === "openrouter") return true;
|
|
21
|
+
if (provider && provider !== "openrouter") return false;
|
|
22
|
+
return model.modelId.includes("/") && matchedKey.includes("/");
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
exports.createModelNameResolver = createModelNameResolver; exports.resolveModel = resolveModel; exports.isRoutedViaOpenRouter = isRoutedViaOpenRouter;
|
|
30
|
+
//# sourceMappingURL=chunk-LYOU7CA2.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-LYOU7CA2.cjs","../src/sync/modelNameResolver.ts"],"names":[],"mappings":"AAAA;AACE;AACF,wDAA6B;AAC7B;AACA;ACmBO,SAAS,uBAAA,CACd,OAAA,EACA,OAAA,EACmB;AACnB,EAAA,OAAO,IAAI,wCAAA,CAAkB,OAAA,EAAS,OAAO,CAAA;AAC/C;AAKO,SAAS,YAAA,CACd,KAAA,EACA,MAAA,EACA,aAAA,EACA,QAAA,EACsB;AACtB,EAAA,MAAM,SAAA,EAAW,IAAI,wCAAA,CAAkB,MAAA,EAAQ,EAAE,cAAc,CAAC,CAAA;AAChE,EAAA,MAAM,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,EAAE,KAAA,EAAO,KAAA,EAAO,SAAS,CAAC,CAAA;AAC1D,EAAA,GAAA,CAAI,CAAC,MAAA,CAAO,MAAA,GAAS,CAAC,MAAA,CAAO,MAAA,EAAQ,OAAO,IAAA;AAC5C,EAAA,OAAO;AAAA,IACL,YAAA,EAAc,MAAA,CAAO,MAAA;AAAA,IACrB,YAAA,EAAc,MAAA,CAAO,OAAA;AAAA,IACrB,mBAAA,EAAqB,MAAA,CAAO;AAAA,EAC9B,CAAA;AACF;AAEO,SAAS,qBAAA,CACd,QAAA,EACA,KAAA,EACA,UAAA,EACS;AACT,EAAA,GAAA,CAAI,SAAA,IAAa,YAAA,EAAc,OAAO,IAAA;AACtC,EAAA,GAAA,CAAI,SAAA,GAAY,SAAA,IAAa,YAAA,EAAc,OAAO,KAAA;AAClD,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,GAAG,EAAA,GAAK,UAAA,CAAW,QAAA,CAAS,GAAG,CAAA;AAC/D;ADlCA;AACA;AACE;AACA;AACA;AACF,sJAAC","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-LYOU7CA2.cjs","sourcesContent":[null,"import type { AliasRegistry } from \"../aliases/AliasRegistry.js\";\nimport type { AiModelRecord } from \"../models/types.js\";\nimport { ModelNameResolver } from \"./modelNameResolver/ModelNameResolver.js\";\nimport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolutionSuccess,\n ModelResolverOptions,\n ResolvedModel,\n} from \"./modelNameResolver/types.js\";\n\nexport { ModelNameResolver } from \"./modelNameResolver/ModelNameResolver.js\";\nexport { buildCatalogIndexes } from \"./modelNameResolver/catalogIndexes.js\";\nexport * from \"./modelNameResolver/types.js\";\nexport {\n loadOpenRouterRoutingEnv,\n shouldDefaultRouteViaOpenRouter,\n providerIdToEnvKeyPrefix,\n vendorApiKeyEnvName,\n} from \"./openRouterRoutingEnv.js\";\nexport type { OpenRouterRoutingConfig } from \"./openRouterRoutingEnv.js\";\nexport { normalizeString, normalizeProvider } from \"./modelNameResolver/normalize.js\";\n\nexport function createModelNameResolver(\n catalog: Map<string, AiModelRecord>,\n options?: ModelResolverOptions,\n): ModelNameResolver {\n return new ModelNameResolver(catalog, options);\n}\n\n/**\n * @deprecated Prefer `ModelNameResolver.resolve()` for full resolution metadata.\n */\nexport function resolveModel(\n input: string,\n models: Map<string, AiModelRecord>,\n aliasRegistry?: AliasRegistry,\n provider?: string,\n): ResolvedModel | null {\n const resolver = new ModelNameResolver(models, { aliasRegistry });\n const result = resolver.resolve({ model: input, provider });\n if (!result.found || !result.record) return null;\n return {\n catalogModel: result.record,\n matchedAlias: result.modelId,\n routedViaOpenRouter: result.routedViaOpenRouter,\n };\n}\n\nexport function isRoutedViaOpenRouter(\n provider: string | undefined,\n model: AiModelRecord,\n matchedKey: string,\n): boolean {\n if (provider === \"openrouter\") return true;\n if (provider && provider !== \"openrouter\") return false;\n return model.modelId.includes(\"/\") && matchedKey.includes(\"/\");\n}\n\nexport type {\n ModelResolutionInput,\n ModelResolutionResult,\n ModelResolutionSuccess,\n ModelResolverOptions,\n};\n"]}
|