@x12i/ai-tools 2.0.7 → 2.1.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.
Files changed (92) hide show
  1. package/dist/catalog/index.cjs +6 -6
  2. package/dist/catalog/index.js +5 -5
  3. package/dist/chunk-2KPWVOOT.cjs +32 -0
  4. package/dist/chunk-2KPWVOOT.cjs.map +1 -0
  5. package/dist/chunk-4ILJWO64.js +143 -0
  6. package/dist/chunk-4ILJWO64.js.map +1 -0
  7. package/dist/{chunk-KSJSLKYI.js → chunk-5RW5ARLO.js} +8 -2
  8. package/dist/chunk-5RW5ARLO.js.map +1 -0
  9. package/dist/{chunk-ZPUZ7DBO.js → chunk-7VGEQTJA.js} +2 -2
  10. package/dist/{chunk-PN4FF6YF.js → chunk-DSDN65JH.js} +3 -3
  11. package/dist/{chunk-WSUFQR3D.cjs → chunk-GNOZFRKR.cjs} +45 -44
  12. package/dist/chunk-GNOZFRKR.cjs.map +1 -0
  13. package/dist/{chunk-DDRWORUU.cjs → chunk-H6HDETJK.cjs} +19 -19
  14. package/dist/{chunk-DDRWORUU.cjs.map → chunk-H6HDETJK.cjs.map} +1 -1
  15. package/dist/{chunk-VBROBIVI.js → chunk-IA4HCHJV.js} +3 -3
  16. package/dist/{chunk-VBROBIVI.js.map → chunk-IA4HCHJV.js.map} +1 -1
  17. package/dist/{chunk-76FHWQH3.cjs → chunk-IJTDND4V.cjs} +9 -3
  18. package/dist/chunk-IJTDND4V.cjs.map +1 -0
  19. package/dist/{chunk-X42KFOUO.cjs → chunk-JDOFFZJA.cjs} +6 -6
  20. package/dist/{chunk-X42KFOUO.cjs.map → chunk-JDOFFZJA.cjs.map} +1 -1
  21. package/dist/chunk-LQLSD26Y.cjs +1 -0
  22. package/dist/chunk-LQLSD26Y.cjs.map +1 -0
  23. package/dist/{chunk-54GKLIDW.js → chunk-OB44D7RG.js} +232 -45
  24. package/dist/chunk-OB44D7RG.js.map +1 -0
  25. package/dist/{chunk-RSHI4OOY.cjs → chunk-OZE336BL.cjs} +251 -64
  26. package/dist/chunk-OZE336BL.cjs.map +1 -0
  27. package/dist/{chunk-HEB73GKJ.js → chunk-RNSXRGIA.js} +30 -26
  28. package/dist/chunk-RNSXRGIA.js.map +1 -0
  29. package/dist/{chunk-75ZVXZAV.cjs → chunk-RVQPQI63.cjs} +7 -7
  30. package/dist/{chunk-75ZVXZAV.cjs.map → chunk-RVQPQI63.cjs.map} +1 -1
  31. package/dist/chunk-SQ6NOF4Z.js +32 -0
  32. package/dist/chunk-SQ6NOF4Z.js.map +1 -0
  33. package/dist/chunk-SYDW33AL.cjs +143 -0
  34. package/dist/chunk-SYDW33AL.cjs.map +1 -0
  35. package/dist/{chunk-D6OIUYNC.js → chunk-TZHPZGDB.js} +5 -5
  36. package/dist/chunk-UQ4NSEXF.js +41 -0
  37. package/dist/chunk-UQ4NSEXF.js.map +1 -0
  38. package/dist/{chunk-HBNYVRLZ.cjs → chunk-UY2VLJN6.cjs} +16 -16
  39. package/dist/{chunk-HBNYVRLZ.cjs.map → chunk-UY2VLJN6.cjs.map} +1 -1
  40. package/dist/{chunk-MOLWV5LV.js → chunk-VDNKQRDG.js} +2 -2
  41. package/dist/chunk-XUUPJ7WO.js +1 -0
  42. package/dist/{chunk-TMA6QSNH.cjs → chunk-YO7AJ5Z3.cjs} +3 -3
  43. package/dist/{chunk-TMA6QSNH.cjs.map → chunk-YO7AJ5Z3.cjs.map} +1 -1
  44. package/dist/chunk-ZHRU337O.cjs +41 -0
  45. package/dist/chunk-ZHRU337O.cjs.map +1 -0
  46. package/dist/cli/index.cjs +36 -16
  47. package/dist/cli/index.cjs.map +1 -1
  48. package/dist/cli/index.js +27 -7
  49. package/dist/cli/index.js.map +1 -1
  50. package/dist/cost/index.cjs +21 -5
  51. package/dist/cost/index.cjs.map +1 -1
  52. package/dist/cost/index.d.cts +3 -2
  53. package/dist/cost/index.d.ts +3 -2
  54. package/dist/cost/index.js +20 -4
  55. package/dist/index.cjs +27 -11
  56. package/dist/index.cjs.map +1 -1
  57. package/dist/index.d.cts +2 -1
  58. package/dist/index.d.ts +2 -1
  59. package/dist/index.js +27 -11
  60. package/dist/models/index.cjs +9 -7
  61. package/dist/models/index.cjs.map +1 -1
  62. package/dist/models/index.d.cts +2 -0
  63. package/dist/models/index.d.ts +2 -0
  64. package/dist/models/index.js +8 -6
  65. package/dist/resolveModelVendor-B0t5nq-v.d.cts +22 -0
  66. package/dist/{resolveUsageModel-DrFuiuIW.d.ts → resolveModelVendor-DQpJpk0w.d.ts} +5 -1
  67. package/dist/{resolveUsageModel-xKZ2QpHy.d.cts → resolveModelVendor-XvmXsVzo.d.cts} +5 -1
  68. package/dist/resolveModelVendor-uphYBFMY.d.ts +22 -0
  69. package/dist/sync/index.cjs +16 -5
  70. package/dist/sync/index.cjs.map +1 -1
  71. package/dist/sync/index.d.cts +1 -0
  72. package/dist/sync/index.d.ts +1 -0
  73. package/dist/sync/index.js +17 -6
  74. package/package.json +2 -2
  75. package/dist/chunk-54GKLIDW.js.map +0 -1
  76. package/dist/chunk-56R4XA2S.js +0 -1
  77. package/dist/chunk-5GUKLOEK.cjs +0 -1
  78. package/dist/chunk-5GUKLOEK.cjs.map +0 -1
  79. package/dist/chunk-76FHWQH3.cjs.map +0 -1
  80. package/dist/chunk-BCX5CLJJ.cjs +0 -238
  81. package/dist/chunk-BCX5CLJJ.cjs.map +0 -1
  82. package/dist/chunk-HEB73GKJ.js.map +0 -1
  83. package/dist/chunk-KSJSLKYI.js.map +0 -1
  84. package/dist/chunk-RSHI4OOY.cjs.map +0 -1
  85. package/dist/chunk-SLSKQRMI.js +0 -238
  86. package/dist/chunk-SLSKQRMI.js.map +0 -1
  87. package/dist/chunk-WSUFQR3D.cjs.map +0 -1
  88. /package/dist/{chunk-ZPUZ7DBO.js.map → chunk-7VGEQTJA.js.map} +0 -0
  89. /package/dist/{chunk-PN4FF6YF.js.map → chunk-DSDN65JH.js.map} +0 -0
  90. /package/dist/{chunk-D6OIUYNC.js.map → chunk-TZHPZGDB.js.map} +0 -0
  91. /package/dist/{chunk-MOLWV5LV.js.map → chunk-VDNKQRDG.js.map} +0 -0
  92. /package/dist/{chunk-56R4XA2S.js.map → chunk-XUUPJ7WO.js.map} +0 -0
@@ -1,20 +1,191 @@
1
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; }
2
2
 
3
+ var _chunkPADNCGZBcjs = require('./chunk-PADNCGZB.cjs');
3
4
 
5
+ // src/sync/modelNameResolver/constants.ts
6
+ var DEFAULT_CONFIDENCE_THRESHOLD = 0.6;
7
+ var PROVIDER_NORMALISATION_MAP = {
8
+ "open-router": "openrouter",
9
+ or: "openrouter",
10
+ oai: "openai",
11
+ "open-ai": "openai",
12
+ claude: "anthropic",
13
+ ant: "anthropic",
14
+ gemini: "google",
15
+ gcp: "google",
16
+ "google-ai": "google",
17
+ vertex: "google",
18
+ meta: "meta-llama",
19
+ llama: "meta-llama",
20
+ "mistral-ai": "mistral",
21
+ "cohere-ai": "cohere"
22
+ };
23
+ var LOCAL_PROVIDERS = /* @__PURE__ */ new Set([
24
+ "ollama",
25
+ "lmstudio",
26
+ "lm-studio",
27
+ "localai",
28
+ "local-ai",
29
+ "llamacpp",
30
+ "llama.cpp",
31
+ "llamafile",
32
+ "jan",
33
+ "koboldcpp"
34
+ ]);
35
+ var PROVIDER_INFERENCE_MAP = [
36
+ { pattern: /^gpt-/, provider: "openai" },
37
+ { pattern: /^o1($|-)/, provider: "openai" },
38
+ { pattern: /^o3($|-)/, provider: "openai" },
39
+ { pattern: /^o4($|-)/, provider: "openai" },
40
+ { pattern: /^chatgpt-/, provider: "openai" },
41
+ { pattern: /^text-davinci/, provider: "openai" },
42
+ { pattern: /^dall-e/, provider: "openai" },
43
+ { pattern: /^whisper/, provider: "openai" },
44
+ { pattern: /^tts-/, provider: "openai" },
45
+ { pattern: /^claude-/, provider: "anthropic" },
46
+ { pattern: /^gemini-/, provider: "google" },
47
+ { pattern: /^palm-/, provider: "google" },
48
+ { pattern: /^bison/, provider: "google" },
49
+ { pattern: /^llama-?[23]/, provider: "meta-llama" },
50
+ { pattern: /^llama/, provider: "meta-llama" },
51
+ { pattern: /^codellama/, provider: "meta-llama" },
52
+ { pattern: /^mistral-/, provider: "mistral" },
53
+ { pattern: /^mixtral-/, provider: "mistral" },
54
+ { pattern: /^codestral/, provider: "mistral" },
55
+ { pattern: /^ministral/, provider: "mistral" },
56
+ { pattern: /^command-/, provider: "cohere" },
57
+ { pattern: /^c4ai-/, provider: "cohere" },
58
+ { pattern: /^deepseek-/, provider: "deepseek" },
59
+ { pattern: /^grok-/, provider: "x-ai" },
60
+ { pattern: /^qwen/, provider: "qwen" },
61
+ { pattern: /^yi-/, provider: "01-ai" },
62
+ { pattern: /^sonar/, provider: "perplexity" },
63
+ { pattern: /^pplx-/, provider: "perplexity" },
64
+ { pattern: /^titan-/, provider: "amazon" },
65
+ { pattern: /^nova-/, provider: "amazon" }
66
+ ];
67
+ var SHORTHAND_MAP = {
68
+ gpt4: "openai/gpt-4",
69
+ gpt4o: "openai/gpt-4o",
70
+ "gpt-4-omni": "openai/gpt-4o",
71
+ gpt4omni: "openai/gpt-4o",
72
+ "gpt4-turbo": "openai/gpt-4-turbo",
73
+ gpt4turbo: "openai/gpt-4-turbo",
74
+ "gpt4-mini": "openai/gpt-4o-mini",
75
+ "gpt-4o-mini": "openai/gpt-4o-mini",
76
+ o1: "openai/o1",
77
+ "o1-mini": "openai/o1-mini",
78
+ o3: "openai/o3",
79
+ "o3-mini": "openai/o3-mini",
80
+ "o4-mini": "openai/o4-mini",
81
+ "3.5-turbo": "openai/gpt-3.5-turbo",
82
+ gpt35: "openai/gpt-3.5-turbo",
83
+ gpt3: "openai/gpt-3.5-turbo",
84
+ claude3: "anthropic/claude-3-5-sonnet-20241022",
85
+ "claude-3": "anthropic/claude-3-5-sonnet-20241022",
86
+ "claude3-sonnet": "anthropic/claude-3-5-sonnet-20241022",
87
+ "claude-sonnet": "anthropic/claude-3-5-sonnet-20241022",
88
+ "claude-haiku": "anthropic/claude-3-5-haiku-20241022",
89
+ "claude3-haiku": "anthropic/claude-3-5-haiku-20241022",
90
+ "claude-opus": "anthropic/claude-opus-4",
91
+ "claude3-opus": "anthropic/claude-3-opus-20240229",
92
+ claude4: "anthropic/claude-opus-4",
93
+ "claude4-sonnet": "anthropic/claude-sonnet-4",
94
+ "claude4-opus": "anthropic/claude-opus-4",
95
+ sonnet: "anthropic/claude-3-5-sonnet-20241022",
96
+ haiku: "anthropic/claude-3-5-haiku-20241022",
97
+ opus: "anthropic/claude-opus-4",
98
+ gemini: "google/gemini-pro",
99
+ "gemini-pro": "google/gemini-pro",
100
+ "gemini-flash": "google/gemini-flash-1.5",
101
+ gemini2: "google/gemini-2.0-flash-001",
102
+ "gemini-2": "google/gemini-2.0-flash-001",
103
+ llama3: "meta-llama/llama-3.1-8b-instruct",
104
+ "llama-3": "meta-llama/llama-3.1-8b-instruct",
105
+ llama2: "meta-llama/llama-2-13b-chat",
106
+ "llama-2": "meta-llama/llama-2-13b-chat",
107
+ mistral: "mistral/mistral-7b-instruct",
108
+ "mistral-large": "mistral/mistral-large-latest",
109
+ mixtral: "mistral/mixtral-8x7b-instruct",
110
+ deepseek: "deepseek/deepseek-chat",
111
+ "deepseek-r1": "deepseek/deepseek-r1"
112
+ };
4
113
 
114
+ // src/sync/modelNameResolver/normalize.ts
115
+ function normalizeString(input) {
116
+ let s = input.trim();
117
+ s = s.replace(/\s+/g, " ").replace(/ /g, "-");
118
+ s = s.toLowerCase();
119
+ s = s.replace(/^\/+|\/+$/g, "");
120
+ s = s.replace(/\/+/g, "/");
121
+ if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) {
122
+ s = s.slice(1, -1);
123
+ }
124
+ return s;
125
+ }
126
+ function normalizeProvider(provider) {
127
+ if (provider === void 0 || provider === "") return void 0;
128
+ const n = normalizeString(provider);
129
+ return _nullishCoalesce(PROVIDER_NORMALISATION_MAP[n], () => ( n));
130
+ }
131
+ function tokenise(s) {
132
+ return s.split(/[-_./]+/).filter(Boolean);
133
+ }
134
+ function modelSlug(modelId) {
135
+ const slash = modelId.indexOf("/");
136
+ return slash >= 0 ? modelId.slice(slash + 1) : modelId;
137
+ }
5
138
 
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
- var _chunkBCX5CLJJcjs = require('./chunk-BCX5CLJJ.cjs');
15
-
16
-
17
- var _chunkPADNCGZBcjs = require('./chunk-PADNCGZB.cjs');
139
+ // src/sync/openRouterRoutingEnv.ts
140
+ var _env = require('@x12i/env');
141
+ function providerIdToEnvKeyPrefix(providerId) {
142
+ return providerId.trim().toLowerCase().replace(/-/g, "_").toUpperCase();
143
+ }
144
+ function vendorApiKeyEnvName(providerId) {
145
+ return `${providerIdToEnvKeyPrefix(providerId)}_API_KEY`;
146
+ }
147
+ function loadOpenRouterRoutingEnv(env = process.env) {
148
+ const dotenv = _env.loadDotenv.call(void 0, );
149
+ const merged = {};
150
+ for (const [k, v] of Object.entries(dotenv)) {
151
+ if (v !== void 0) merged[k] = v;
152
+ }
153
+ for (const [k, v] of Object.entries(env)) {
154
+ if (v !== void 0) merged[k] = v;
155
+ }
156
+ const openRouterKey = _optionalChain([merged, 'access', _ => _.OPENROUTER_API_KEY, 'optionalAccess', _2 => _2.trim, 'call', _3 => _3()]);
157
+ const useRaw = _optionalChain([merged, 'access', _4 => _4.USE_OPENROUTER, 'optionalAccess', _5 => _5.trim, 'call', _6 => _6(), 'access', _7 => _7.toLowerCase, 'call', _8 => _8()]);
158
+ const useOpenRouterExplicit = useRaw === "true" || useRaw === "1";
159
+ return {
160
+ hasOpenRouterKey: Boolean(openRouterKey),
161
+ useOpenRouterExplicit,
162
+ getVendorApiKey(providerId) {
163
+ const name = vendorApiKeyEnvName(providerId);
164
+ const val = _optionalChain([merged, 'access', _9 => _9[name], 'optionalAccess', _10 => _10.trim, 'call', _11 => _11()]);
165
+ return val || void 0;
166
+ }
167
+ };
168
+ }
169
+ function shouldDefaultRouteViaOpenRouter(providerId, config) {
170
+ if (!config.hasOpenRouterKey) return false;
171
+ if (config.useOpenRouterExplicit) return true;
172
+ if (providerId && providerId !== "openrouter") {
173
+ return !config.getVendorApiKey(providerId);
174
+ }
175
+ return false;
176
+ }
177
+ function isEffectiveOpenRouterTransport(config, input = {}) {
178
+ if (input.routeViaOpenRouter === true) return true;
179
+ if (input.routeViaOpenRouter === false) return false;
180
+ const provider = _optionalChain([input, 'access', _12 => _12.provider, 'optionalAccess', _13 => _13.trim, 'call', _14 => _14(), 'access', _15 => _15.toLowerCase, 'call', _16 => _16()]);
181
+ if (provider === "openrouter") return true;
182
+ const vendor = _optionalChain([input, 'access', _17 => _17.modelId, 'optionalAccess', _18 => _18.includes, 'call', _19 => _19("/")]) === true ? input.modelId.split("/")[0].trim().toLowerCase() : provider;
183
+ if (vendor && vendor !== "openrouter") {
184
+ return shouldDefaultRouteViaOpenRouter(vendor, config);
185
+ }
186
+ if (config.hasOpenRouterKey && config.useOpenRouterExplicit) return true;
187
+ return false;
188
+ }
18
189
 
19
190
  // src/sync/modelNameResolver/catalogIndexes.ts
20
191
  function buildCatalogIndexes(catalog) {
@@ -23,10 +194,10 @@ function buildCatalogIndexes(catalog) {
23
194
  const prefixCounts = /* @__PURE__ */ new Map();
24
195
  for (const record of catalog.values()) {
25
196
  for (const alias of record.aliases) {
26
- aliasIndex.set(_chunkBCX5CLJJcjs.normalizeString.call(void 0, alias), record.modelId);
197
+ aliasIndex.set(normalizeString(alias), record.modelId);
27
198
  }
28
199
  if (record.canonicalSlug) {
29
- slugIndex.set(_chunkBCX5CLJJcjs.normalizeString.call(void 0, record.canonicalSlug), record.modelId);
200
+ slugIndex.set(normalizeString(record.canonicalSlug), record.modelId);
30
201
  }
31
202
  const pid = record.providerId;
32
203
  prefixCounts.set(pid, (_nullishCoalesce(prefixCounts.get(pid), () => ( 0))) + 1);
@@ -35,6 +206,41 @@ function buildCatalogIndexes(catalog) {
35
206
  return { aliasIndex, slugIndex, providerPrefixesBySize };
36
207
  }
37
208
 
209
+ // src/sync/modelNameResolver/stripVersionSuffix.ts
210
+ var VERSION_STRIP_PATTERNS = [
211
+ { re: /-\d{4}-\d{2}-\d{2}$/, label: "date YYYY-MM-DD" },
212
+ { re: /-\d{8}$/, label: "date YYYYMMDD" },
213
+ { re: /-v\d+$/, label: "version -vN" },
214
+ { re: /-\d+\.\d+\.\d+$/, label: "semver" },
215
+ { re: /:\d+[a-z]?$/i, label: "colon version" },
216
+ { re: /-\d{4,}$/, label: "build number" },
217
+ { re: /@\d+$/, label: "epoch @NNNN" }
218
+ ];
219
+ function stripModelSlugSuffix(slug) {
220
+ for (const { re } of VERSION_STRIP_PATTERNS) {
221
+ if (re.test(slug)) {
222
+ return slug.replace(re, "");
223
+ }
224
+ }
225
+ return null;
226
+ }
227
+ function stripModelVersionSuffix(model) {
228
+ const normalized = normalizeString(model);
229
+ if (!normalized) return null;
230
+ if (normalized.includes("/")) {
231
+ const slash = normalized.indexOf("/");
232
+ const prefix = normalized.slice(0, slash);
233
+ const slug = normalized.slice(slash + 1);
234
+ const stripped2 = stripModelSlugSuffix(slug);
235
+ if (stripped2 && stripped2 !== slug) {
236
+ return `${prefix}/${stripped2}`;
237
+ }
238
+ return null;
239
+ }
240
+ const stripped = stripModelSlugSuffix(normalized);
241
+ return stripped && stripped !== normalized ? stripped : null;
242
+ }
243
+
38
244
  // src/sync/modelNameResolver/ModelNameResolver.ts
39
245
  var ModelNameResolver = class {
40
246
 
@@ -47,12 +253,12 @@ var ModelNameResolver = class {
47
253
  catalog,
48
254
  indexes: this.indexes,
49
255
  options: {
50
- confidenceThreshold: _nullishCoalesce(options.confidenceThreshold, () => ( _chunkBCX5CLJJcjs.DEFAULT_CONFIDENCE_THRESHOLD)),
256
+ confidenceThreshold: _nullishCoalesce(options.confidenceThreshold, () => ( DEFAULT_CONFIDENCE_THRESHOLD)),
51
257
  aliasRegistry: options.aliasRegistry,
52
258
  additionalShorthands: _nullishCoalesce(options.additionalShorthands, () => ( {})),
53
259
  additionalProviderPatterns: _nullishCoalesce(options.additionalProviderPatterns, () => ( [])),
54
260
  additionalLocalProviders: _nullishCoalesce(options.additionalLocalProviders, () => ( [])),
55
- routingEnv: _nullishCoalesce(options.routingEnv, () => ( _chunkBCX5CLJJcjs.loadOpenRouterRoutingEnv.call(void 0, ))),
261
+ routingEnv: _nullishCoalesce(options.routingEnv, () => ( loadOpenRouterRoutingEnv())),
56
262
  routeViaOpenRouter: options.routeViaOpenRouter
57
263
  }
58
264
  };
@@ -60,28 +266,28 @@ var ModelNameResolver = class {
60
266
  resolve(input) {
61
267
  const attempted = [];
62
268
  const threshold = this.ctx.options.confidenceThreshold;
63
- let provider = _chunkBCX5CLJJcjs.normalizeProvider.call(void 0, input.provider);
64
- let model = _chunkBCX5CLJJcjs.normalizeString.call(void 0, input.model);
269
+ let provider = normalizeProvider(input.provider);
270
+ let model = normalizeString(input.model);
65
271
  const normalisedInput = model;
66
272
  if (this.ctx.options.aliasRegistry) {
67
273
  attempted.push("alias-registry");
68
274
  const entry = this.ctx.options.aliasRegistry.get(model);
69
275
  if (entry) {
70
- model = _chunkBCX5CLJJcjs.normalizeString.call(void 0, entry.modelId);
71
- provider = _nullishCoalesce(_chunkBCX5CLJJcjs.normalizeProvider.call(void 0, entry.provider), () => ( provider));
276
+ model = normalizeString(entry.modelId);
277
+ provider = _nullishCoalesce(normalizeProvider(entry.provider), () => ( provider));
72
278
  }
73
279
  }
74
280
  if (this.ctx.options.aliasRegistry && provider) {
75
281
  const aliasAsProvider = this.ctx.options.aliasRegistry.get(provider);
76
282
  if (aliasAsProvider) {
77
283
  attempted.push("alias-as-provider-correction");
78
- model = _chunkBCX5CLJJcjs.normalizeString.call(void 0, aliasAsProvider.modelId);
79
- provider = _nullishCoalesce(_chunkBCX5CLJJcjs.normalizeProvider.call(void 0, aliasAsProvider.provider), () => ( provider));
284
+ model = normalizeString(aliasAsProvider.modelId);
285
+ provider = _nullishCoalesce(normalizeProvider(aliasAsProvider.provider), () => ( provider));
80
286
  }
81
287
  }
82
288
  const localProviders = /* @__PURE__ */ new Set([
83
- ..._chunkBCX5CLJJcjs.LOCAL_PROVIDERS,
84
- ...this.ctx.options.additionalLocalProviders.map((p) => _chunkBCX5CLJJcjs.normalizeString.call(void 0, p))
289
+ ...LOCAL_PROVIDERS,
290
+ ...this.ctx.options.additionalLocalProviders.map((p) => normalizeString(p))
85
291
  ]);
86
292
  if (provider && localProviders.has(provider)) {
87
293
  attempted.push("local-provider-passthrough");
@@ -157,7 +363,7 @@ var ModelNameResolver = class {
157
363
  if (hit) return { match: hit };
158
364
  hit = tryMatch("cross-provider-correction", () => this.crossProviderCorrection(model));
159
365
  if (hit) return { match: hit };
160
- const stripped = _chunkBCX5CLJJcjs.stripModelVersionSuffix.call(void 0, model);
366
+ const stripped = stripModelVersionSuffix(model);
161
367
  if (stripped && stripped !== model) {
162
368
  if (!attempted.includes("version-suffix-strip")) attempted.push("version-suffix-strip");
163
369
  const inner = this.runPipeline(
@@ -186,7 +392,7 @@ var ModelNameResolver = class {
186
392
  if (shorthand) {
187
393
  if (!attempted.includes("shorthand-expansion")) attempted.push("shorthand-expansion");
188
394
  const inner = this.runPipeline(
189
- _chunkBCX5CLJJcjs.normalizeString.call(void 0, shorthand),
395
+ normalizeString(shorthand),
190
396
  provider,
191
397
  attempted,
192
398
  threshold,
@@ -264,7 +470,7 @@ var ModelNameResolver = class {
264
470
  inferProviderFromSlug(slug) {
265
471
  const patterns = [
266
472
  ...this.ctx.options.additionalProviderPatterns,
267
- ..._chunkBCX5CLJJcjs.PROVIDER_INFERENCE_MAP
473
+ ...PROVIDER_INFERENCE_MAP
268
474
  ];
269
475
  for (const { pattern, provider } of patterns) {
270
476
  if (pattern.test(slug)) return provider;
@@ -332,7 +538,7 @@ var ModelNameResolver = class {
332
538
  dateSuffixMatch(model) {
333
539
  if (model.includes("/")) {
334
540
  const [prefix, slug] = model.split("/", 2);
335
- const stripped = _chunkBCX5CLJJcjs.stripModelSlugSuffix.call(void 0, slug);
541
+ const stripped = stripModelSlugSuffix(slug);
336
542
  if (stripped && stripped !== slug) {
337
543
  const candidate = `${prefix}/${stripped}`;
338
544
  const record = this.catalog.get(candidate);
@@ -377,22 +583,22 @@ var ModelNameResolver = class {
377
583
  return { modelId: best.modelId, record: best.record };
378
584
  }
379
585
  shorthandMap() {
380
- return { ..._chunkBCX5CLJJcjs.SHORTHAND_MAP, ...this.ctx.options.additionalShorthands };
586
+ return { ...SHORTHAND_MAP, ...this.ctx.options.additionalShorthands };
381
587
  }
382
588
  partialMatch(model, provider) {
383
589
  let best = null;
384
- const inputTokens = _chunkBCX5CLJJcjs.tokenise.call(void 0, model);
590
+ const inputTokens = tokenise(model);
385
591
  if (inputTokens.length === 0) return null;
386
592
  for (const record of this.catalog.values()) {
387
593
  const recordTokens = /* @__PURE__ */ new Set([
388
- ..._chunkBCX5CLJJcjs.tokenise.call(void 0, record.modelId),
389
- ..._chunkBCX5CLJJcjs.tokenise.call(void 0, _nullishCoalesce(record.name, () => ( "")))
594
+ ...tokenise(record.modelId),
595
+ ...tokenise(_nullishCoalesce(record.name, () => ( "")))
390
596
  ]);
391
597
  const intersection = inputTokens.filter((t) => recordTokens.has(t));
392
598
  const overlapRatio = intersection.length / inputTokens.length;
393
599
  let score = overlapRatio * 0.6;
394
600
  if (record.modelId.includes(model)) score += 0.3;
395
- const slug = _chunkBCX5CLJJcjs.modelSlug.call(void 0, record.modelId);
601
+ const slug = modelSlug(record.modelId);
396
602
  if (model.includes(slug)) score += 0.2;
397
603
  if (provider && provider === record.providerId) score += 0.15;
398
604
  const lenPenalty = Math.abs(model.length - slug.length) / Math.max(model.length, slug.length, 1) * 0.1;
@@ -414,22 +620,22 @@ var ModelNameResolver = class {
414
620
  const override = this.ctx.options.routeViaOpenRouter;
415
621
  if (override === true) return true;
416
622
  if (override === false) return false;
417
- const norm = _nullishCoalesce(_chunkBCX5CLJJcjs.normalizeProvider.call(void 0, originalProvider), () => ( provider));
623
+ const norm = _nullishCoalesce(normalizeProvider(originalProvider), () => ( provider));
418
624
  if (norm === "openrouter") return true;
419
625
  if (norm && norm !== "openrouter") {
420
- if (_chunkBCX5CLJJcjs.shouldDefaultRouteViaOpenRouter.call(void 0, norm, this.ctx.options.routingEnv)) return true;
626
+ if (shouldDefaultRouteViaOpenRouter(norm, this.ctx.options.routingEnv)) return true;
421
627
  return false;
422
628
  }
423
- const recordProvider = _optionalChain([record, 'optionalAccess', _ => _.providerId]);
424
- if (recordProvider && _chunkBCX5CLJJcjs.shouldDefaultRouteViaOpenRouter.call(void 0, recordProvider, this.ctx.options.routingEnv)) {
629
+ const recordProvider = _optionalChain([record, 'optionalAccess', _20 => _20.providerId]);
630
+ if (recordProvider && shouldDefaultRouteViaOpenRouter(recordProvider, this.ctx.options.routingEnv)) {
425
631
  return true;
426
632
  }
427
- if (_optionalChain([record, 'optionalAccess', _2 => _2.availableOnOpenRouter]) && modelId.includes("/")) return true;
633
+ if (_optionalChain([record, 'optionalAccess', _21 => _21.availableOnOpenRouter]) && modelId.includes("/")) return true;
428
634
  return false;
429
635
  }
430
636
  toOpenRouterSlug(modelId, provider, record) {
431
637
  if (modelId.includes("/")) return modelId;
432
- const vendor = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _3 => _3.providerId]), () => ( (provider && provider !== "openrouter" ? provider : void 0)));
638
+ const vendor = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _22 => _22.providerId]), () => ( (provider && provider !== "openrouter" ? provider : void 0)));
433
639
  if (!vendor || vendor === "openrouter") return modelId;
434
640
  return `${vendor}/${modelId}`;
435
641
  }
@@ -454,29 +660,6 @@ var ModelNameResolver = class {
454
660
  }
455
661
  };
456
662
 
457
- // src/models/reasoningModel.ts
458
- var REASONING_SUPPORTED_PARAMETERS = ["reasoning", "include_reasoning"];
459
- function supportsReasoningParameter(model) {
460
- return model.supportedParameters.some(
461
- (p) => REASONING_SUPPORTED_PARAMETERS.includes(p)
462
- );
463
- }
464
- function hasReasoningPricing(model) {
465
- const raw = _optionalChain([model, 'access', _4 => _4.openRouterPricing, 'optionalAccess', _5 => _5.internal_reasoning]);
466
- if (raw !== void 0 && raw !== null && String(raw).trim() !== "") {
467
- return true;
468
- }
469
- return model.pricing.reasoningUsdPerToken !== void 0;
470
- }
471
- function computeSupportsReasoning(model) {
472
- return supportsReasoningParameter(model) || hasReasoningPricing(model);
473
- }
474
- function isReasoningModel(model) {
475
- if (model.supportsReasoning !== void 0) {
476
- return model.supportsReasoning;
477
- }
478
- return computeSupportsReasoning(model);
479
- }
480
663
 
481
664
 
482
665
 
@@ -486,5 +669,9 @@ function isReasoningModel(model) {
486
669
 
487
670
 
488
671
 
489
- exports.buildCatalogIndexes = buildCatalogIndexes; exports.ModelNameResolver = ModelNameResolver; exports.REASONING_SUPPORTED_PARAMETERS = REASONING_SUPPORTED_PARAMETERS; exports.supportsReasoningParameter = supportsReasoningParameter; exports.hasReasoningPricing = hasReasoningPricing; exports.computeSupportsReasoning = computeSupportsReasoning; exports.isReasoningModel = isReasoningModel;
490
- //# sourceMappingURL=chunk-RSHI4OOY.cjs.map
672
+
673
+
674
+
675
+
676
+ exports.LOCAL_PROVIDERS = LOCAL_PROVIDERS; exports.PROVIDER_INFERENCE_MAP = PROVIDER_INFERENCE_MAP; exports.normalizeString = normalizeString; exports.normalizeProvider = normalizeProvider; exports.stripModelVersionSuffix = stripModelVersionSuffix; exports.providerIdToEnvKeyPrefix = providerIdToEnvKeyPrefix; exports.vendorApiKeyEnvName = vendorApiKeyEnvName; exports.loadOpenRouterRoutingEnv = loadOpenRouterRoutingEnv; exports.shouldDefaultRouteViaOpenRouter = shouldDefaultRouteViaOpenRouter; exports.isEffectiveOpenRouterTransport = isEffectiveOpenRouterTransport; exports.buildCatalogIndexes = buildCatalogIndexes; exports.ModelNameResolver = ModelNameResolver;
677
+ //# sourceMappingURL=chunk-OZE336BL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-OZE336BL.cjs","../src/sync/modelNameResolver/constants.ts","../src/sync/modelNameResolver/normalize.ts","../src/sync/openRouterRoutingEnv.ts","../src/sync/modelNameResolver/catalogIndexes.ts","../src/sync/modelNameResolver/stripVersionSuffix.ts","../src/sync/modelNameResolver/ModelNameResolver.ts"],"names":["stripped"],"mappings":"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","file":"/Users/ami/Documents/prometheus/x12i/ai-tools/dist/chunk-OZE336BL.cjs","sourcesContent":[null,"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 { 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\nexport type EffectiveOpenRouterTransportInput = {\n provider?: string;\n modelId?: string;\n routeViaOpenRouter?: boolean;\n};\n\n/**\n * Whether the effective runtime transport is OpenRouter.\n * Honors explicit gateway override, then env defaults from {@link loadOpenRouterRoutingEnv}.\n */\nexport function isEffectiveOpenRouterTransport(\n config: OpenRouterRoutingConfig,\n input: EffectiveOpenRouterTransportInput = {},\n): boolean {\n if (input.routeViaOpenRouter === true) return true;\n if (input.routeViaOpenRouter === false) return false;\n\n const provider = input.provider?.trim().toLowerCase();\n if (provider === \"openrouter\") return true;\n\n const vendor =\n input.modelId?.includes(\"/\") === true\n ? input.modelId.split(\"/\")[0]!.trim().toLowerCase()\n : provider;\n\n if (vendor && vendor !== \"openrouter\") {\n return shouldDefaultRouteViaOpenRouter(vendor, config);\n }\n\n if (config.hasOpenRouterKey && config.useOpenRouterExplicit) return true;\n return false;\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 { normalizeString } from \"./normalize.js\";\n\n/** Patterns stripped when resolving versioned runtime model ids to catalog entries. */\nexport const VERSION_STRIP_PATTERNS: ReadonlyArray<{ 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\n/** Strip version/date suffix from a bare slug (no `provider/` prefix). */\nexport function stripModelSlugSuffix(slug: string): string | null {\n for (const { re } of VERSION_STRIP_PATTERNS) {\n if (re.test(slug)) {\n return slug.replace(re, \"\");\n }\n }\n return null;\n}\n\n/**\n * Strip a version/date suffix from a model id (`gpt-5.5-2026-04-23` → `gpt-5.5`,\n * `openai/gpt-4o-2024-08-06` → `openai/gpt-4o`). Returns null when nothing was stripped.\n */\nexport function stripModelVersionSuffix(model: string): string | null {\n const normalized = normalizeString(model);\n if (!normalized) return null;\n\n if (normalized.includes(\"/\")) {\n const slash = normalized.indexOf(\"/\");\n const prefix = normalized.slice(0, slash);\n const slug = normalized.slice(slash + 1);\n const stripped = stripModelSlugSuffix(slug);\n if (stripped && stripped !== slug) {\n return `${prefix}/${stripped}`;\n }\n return null;\n }\n\n const stripped = stripModelSlugSuffix(normalized);\n return stripped && stripped !== normalized ? stripped : null;\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 { stripModelSlugSuffix, stripModelVersionSuffix } from \"./stripVersionSuffix.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\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 routeViaOpenRouter: options.routeViaOpenRouter,\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 = stripModelVersionSuffix(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 dateSuffixMatch(model: string): MatchCandidate | null {\n if (model.includes(\"/\")) {\n const [prefix, slug] = model.split(\"/\", 2);\n const stripped = stripModelSlugSuffix(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 override = this.ctx.options.routeViaOpenRouter;\n if (override === true) return true;\n if (override === false) return false;\n\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 toOpenRouterSlug(\n modelId: string,\n provider: string | undefined,\n record: AiModelRecord | null,\n ): string {\n if (modelId.includes(\"/\")) return modelId;\n const vendor =\n record?.providerId ??\n (provider && provider !== \"openrouter\" ? provider : undefined);\n if (!vendor || vendor === \"openrouter\") return modelId;\n return `${vendor}/${modelId}`;\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 const routedViaOpenRouter = this.computeRoutedViaOpenRouter(\n args.modelId,\n args.record,\n args.provider,\n args.originalProvider,\n );\n const modelId = routedViaOpenRouter\n ? this.toOpenRouterSlug(args.modelId, args.provider, args.record)\n : args.modelId;\n\n return {\n found: true,\n modelId,\n record: args.record,\n routedViaOpenRouter,\n confidence: args.confidence,\n resolvedVia: args.resolvedVia,\n resolvedReason: args.reason,\n normalisedInput: args.normalisedInput,\n };\n }\n}\n"]}