llm-strings 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +339 -339
  3. package/dist/ai-sdk.cjs +1146 -117
  4. package/dist/ai-sdk.d.cts +1 -1
  5. package/dist/ai-sdk.d.ts +1 -1
  6. package/dist/ai-sdk.js +95 -58
  7. package/dist/{chunk-7HE4RH6X.js → chunk-4BE457QA.js} +16 -29
  8. package/dist/{chunk-TQJ2ABCT.js → chunk-6HQOCOQI.js} +1 -2
  9. package/dist/{chunk-NZR5DUX5.js → chunk-7Z7DCLZN.js} +14 -3
  10. package/dist/{chunk-OCJX4QFJ.js → chunk-PCJDQTOV.js} +520 -76
  11. package/dist/index.cjs +542 -95
  12. package/dist/index.d.cts +1 -1
  13. package/dist/index.d.ts +1 -1
  14. package/dist/index.js +4 -5
  15. package/dist/normalize.cjs +1065 -63
  16. package/dist/normalize.d.cts +1 -1
  17. package/dist/normalize.d.ts +1 -1
  18. package/dist/normalize.js +2 -3
  19. package/dist/parse.cjs +1075 -1
  20. package/dist/parse.d.cts +4 -4
  21. package/dist/parse.d.ts +4 -4
  22. package/dist/parse.js +2 -3
  23. package/dist/{provider-core-B934MuhJ.d.cts → provider-core-B1GMszQP.d.cts} +2 -3
  24. package/dist/{provider-core-B934MuhJ.d.ts → provider-core-B1GMszQP.d.ts} +2 -3
  25. package/dist/providers.cjs +542 -697
  26. package/dist/providers.d.cts +3 -8
  27. package/dist/providers.d.ts +3 -8
  28. package/dist/providers.js +25 -624
  29. package/dist/validate.cjs +542 -95
  30. package/dist/validate.d.cts +1 -1
  31. package/dist/validate.d.ts +1 -1
  32. package/dist/validate.js +4 -5
  33. package/package.json +16 -2
  34. package/dist/ai-sdk.cjs.map +0 -1
  35. package/dist/ai-sdk.js.map +0 -1
  36. package/dist/chunk-7HE4RH6X.js.map +0 -1
  37. package/dist/chunk-NZR5DUX5.js.map +0 -1
  38. package/dist/chunk-OCJX4QFJ.js.map +0 -1
  39. package/dist/chunk-TQJ2ABCT.js.map +0 -1
  40. package/dist/index.cjs.map +0 -1
  41. package/dist/index.js.map +0 -1
  42. package/dist/normalize.cjs.map +0 -1
  43. package/dist/normalize.js.map +0 -1
  44. package/dist/parse.cjs.map +0 -1
  45. package/dist/parse.js.map +0 -1
  46. package/dist/providers.cjs.map +0 -1
  47. package/dist/providers.js.map +0 -1
  48. package/dist/validate.cjs.map +0 -1
  49. package/dist/validate.js.map +0 -1
package/dist/validate.cjs CHANGED
@@ -139,44 +139,92 @@ function providerFromHostAlias(alias) {
139
139
  }
140
140
  return void 0;
141
141
  }
142
+ function canonicalHostName(host) {
143
+ return normalizeHostValue(host).toLowerCase().split(":")[0] ?? host;
144
+ }
145
+ function hostMatches(host, ...domains) {
146
+ return domains.some((domain) => {
147
+ const normalizedDomain = domain.toLowerCase();
148
+ return host === normalizedDomain || host.endsWith(`.${normalizedDomain}`);
149
+ });
150
+ }
151
+ function hostHasLabel(host, ...labels) {
152
+ const hostLabels = host.split(".");
153
+ return labels.some((label) => hostLabels.includes(label.toLowerCase()));
154
+ }
155
+ function hostHasLabelPrefix(host, ...prefixes) {
156
+ const hostLabels = host.split(".");
157
+ return prefixes.some(
158
+ (prefix) => hostLabels.some((label) => label.startsWith(prefix.toLowerCase()))
159
+ );
160
+ }
161
+ var MODEL_FAMILY_DELIMITERS = /* @__PURE__ */ new Set(["-", "."]);
162
+ function normalizeModelForMatching(model) {
163
+ return model.trim().toLowerCase();
164
+ }
165
+ function modelLeafName(model) {
166
+ const normalized = normalizeModelForMatching(model);
167
+ const slash = normalized.lastIndexOf("/");
168
+ return slash >= 0 ? normalized.slice(slash + 1) : normalized;
169
+ }
170
+ function modelMatchesFamily(model, family) {
171
+ const name = modelLeafName(model);
172
+ const normalizedFamily = normalizeModelForMatching(family);
173
+ if (!name || !normalizedFamily) return false;
174
+ if (name === normalizedFamily) return true;
175
+ const delimiter = name[normalizedFamily.length];
176
+ return name.startsWith(normalizedFamily) && delimiter !== void 0 && MODEL_FAMILY_DELIMITERS.has(delimiter);
177
+ }
142
178
  function detectProvider(host) {
143
- host = host.toLowerCase();
144
- if (host.includes("openrouter")) return "openrouter";
145
- if (host.includes("gateway.ai.vercel")) return "vercel";
146
- if (host.includes("amazonaws") || host.includes("bedrock")) return "bedrock";
147
- if (host.includes("aiplatform.googleapis")) return "google-vertex";
148
- if (host.includes("api.x.ai")) return "xai";
149
- if (host.includes("groq")) return "groq";
150
- if (host.includes("fal.run") || host.includes("fal.ai")) return "fal";
151
- if (host.includes("deepinfra")) return "deepinfra";
152
- if (host.includes("bfl.ai")) return "black-forest-labs";
153
- if (host.includes("together")) return "together";
154
- if (host.includes("fireworks")) return "fireworks";
155
- if (host.includes("deepseek")) return "deepseek";
156
- if (host.includes("moonshot")) return "moonshotai";
157
- if (host.includes("perplexity")) return "perplexity";
158
- if (host.includes("dashscope") || host.includes("aliyuncs")) return "alibaba";
159
- if (host.includes("cerebras")) return "cerebras";
160
- if (host.includes("replicate")) return "replicate";
161
- if (host.includes("prodia")) return "prodia";
162
- if (host.includes("lumalabs") || host.includes("luma")) return "luma";
163
- if (host.includes("volces") || host.includes("bytedance")) return "bytedance";
164
- if (host.includes("kling")) return "kling";
165
- if (host.includes("elevenlabs")) return "elevenlabs";
166
- if (host.includes("assemblyai")) return "assemblyai";
167
- if (host.includes("deepgram")) return "deepgram";
168
- if (host.includes("gladia")) return "gladia";
169
- if (host.includes("lmnt")) return "lmnt";
170
- if (host.includes("hume")) return "hume";
171
- if (host.includes("rev.ai")) return "revai";
172
- if (host.includes("baseten")) return "baseten";
173
- if (host.includes("huggingface")) return "huggingface";
174
- if (host.includes("azure")) return "azure";
175
- if (host.includes("openai")) return "openai";
176
- if (host.includes("anthropic") || host.includes("claude")) return "anthropic";
177
- if (host.includes("googleapis") || host.includes("google")) return "google";
178
- if (host.includes("mistral")) return "mistral";
179
- if (host.includes("cohere")) return "cohere";
179
+ host = canonicalHostName(host);
180
+ if (hostMatches(host, "openrouter", "openrouter.ai")) return "openrouter";
181
+ if (hostMatches(host, "vercel", "gateway.ai.vercel.app", "gateway.ai.vercel.sh")) {
182
+ return "vercel";
183
+ }
184
+ if (hostMatches(host, "bedrock", "amazonaws.com") || hostHasLabelPrefix(host, "bedrock")) {
185
+ return "bedrock";
186
+ }
187
+ if (hostMatches(host, "aiplatform.googleapis.com")) return "google-vertex";
188
+ if (hostMatches(host, "xai", "x.ai", "api.x.ai")) return "xai";
189
+ if (hostMatches(host, "groq", "groq.com", "api.groq.com")) return "groq";
190
+ if (hostMatches(host, "fal", "fal.run", "fal.ai")) return "fal";
191
+ if (hostMatches(host, "deepinfra", "deepinfra.com")) return "deepinfra";
192
+ if (hostMatches(host, "bfl", "bfl.ai", "api.bfl.ai")) {
193
+ return "black-forest-labs";
194
+ }
195
+ if (hostMatches(host, "together", "together.xyz")) return "together";
196
+ if (hostMatches(host, "fireworks", "fireworks.ai")) return "fireworks";
197
+ if (hostMatches(host, "deepseek", "deepseek.com")) return "deepseek";
198
+ if (hostMatches(host, "moonshot", "moonshot.ai")) return "moonshotai";
199
+ if (hostMatches(host, "perplexity", "perplexity.ai")) return "perplexity";
200
+ if (hostMatches(host, "alibaba", "aliyuncs.com") || hostHasLabelPrefix(host, "dashscope")) {
201
+ return "alibaba";
202
+ }
203
+ if (hostMatches(host, "cerebras", "cerebras.ai")) return "cerebras";
204
+ if (hostMatches(host, "replicate", "replicate.com")) return "replicate";
205
+ if (hostMatches(host, "prodia", "prodia.com")) return "prodia";
206
+ if (hostMatches(host, "luma", "lumalabs.ai")) return "luma";
207
+ if (hostMatches(host, "bytedance", "volces.com") || hostHasLabel(host, "bytedance")) {
208
+ return "bytedance";
209
+ }
210
+ if (hostMatches(host, "kling", "klingai.com")) return "kling";
211
+ if (hostMatches(host, "elevenlabs", "elevenlabs.io")) return "elevenlabs";
212
+ if (hostMatches(host, "assemblyai", "assemblyai.com")) return "assemblyai";
213
+ if (hostMatches(host, "deepgram", "deepgram.com")) return "deepgram";
214
+ if (hostMatches(host, "gladia", "gladia.io")) return "gladia";
215
+ if (hostMatches(host, "lmnt", "lmnt.com")) return "lmnt";
216
+ if (hostMatches(host, "hume", "hume.ai")) return "hume";
217
+ if (hostMatches(host, "revai", "rev.ai")) return "revai";
218
+ if (hostMatches(host, "baseten", "baseten.co")) return "baseten";
219
+ if (hostMatches(host, "huggingface", "huggingface.co")) return "huggingface";
220
+ if (hostMatches(host, "azure", "azure.com")) return "azure";
221
+ if (hostMatches(host, "openai", "openai.com")) return "openai";
222
+ if (hostMatches(host, "anthropic", "anthropic.com", "claude.ai")) {
223
+ return "anthropic";
224
+ }
225
+ if (hostMatches(host, "google", "googleapis.com")) return "google";
226
+ if (hostMatches(host, "mistral", "mistral.ai")) return "mistral";
227
+ if (hostMatches(host, "cohere", "cohere.com")) return "cohere";
180
228
  return void 0;
181
229
  }
182
230
  var ALIASES = {
@@ -219,7 +267,10 @@ var ALIASES = {
219
267
  num_completions: "n",
220
268
  // effort / reasoning
221
269
  reasoning_effort: "effort",
270
+ reasoningEffort: "effort",
222
271
  reasoning: "effort",
272
+ thinking_effort: "effort",
273
+ thinkingEffort: "effort",
223
274
  // cache
224
275
  cache_control: "cache",
225
276
  cacheControl: "cache",
@@ -229,6 +280,7 @@ var ALIASES = {
229
280
  var OPENAI_COMPATIBLE_PARAMS = {
230
281
  temperature: "temperature",
231
282
  max_tokens: "max_tokens",
283
+ max_completion_tokens: "max_completion_tokens",
232
284
  top_p: "top_p",
233
285
  top_k: "top_k",
234
286
  frequency_penalty: "frequency_penalty",
@@ -239,6 +291,90 @@ var OPENAI_COMPATIBLE_PARAMS = {
239
291
  stream: "stream",
240
292
  effort: "reasoning_effort"
241
293
  };
294
+ var COMMON_IMAGE_PARAMS = {
295
+ prompt: "prompt",
296
+ negative_prompt: "negative_prompt",
297
+ seed: "seed",
298
+ image_size: "image_size",
299
+ aspect_ratio: "aspect_ratio",
300
+ output_format: "output_format",
301
+ width: "width",
302
+ height: "height"
303
+ };
304
+ var FAL_PARAMS = {
305
+ ...COMMON_IMAGE_PARAMS,
306
+ num_images: "num_images",
307
+ enable_safety_checker: "enable_safety_checker",
308
+ enable_safety_checks: "enable_safety_checks",
309
+ enable_prompt_expansion: "enable_prompt_expansion",
310
+ expand_prompt: "expand_prompt"
311
+ };
312
+ var REPLICATE_PARAMS = {
313
+ ...COMMON_IMAGE_PARAMS,
314
+ input: "input",
315
+ version: "version",
316
+ num_outputs: "num_outputs",
317
+ num_inference_steps: "num_inference_steps",
318
+ guidance_scale: "guidance_scale",
319
+ stream: "stream",
320
+ webhook: "webhook",
321
+ webhook_events_filter: "webhook_events_filter"
322
+ };
323
+ var PRODIA_PARAMS = {
324
+ ...COMMON_IMAGE_PARAMS,
325
+ model: "model",
326
+ style_preset: "style_preset",
327
+ steps: "steps",
328
+ cfg_scale: "cfg_scale",
329
+ upscale: "upscale",
330
+ sampler: "sampler",
331
+ type: "type",
332
+ config: "config",
333
+ price: "price"
334
+ };
335
+ var LUMA_PARAMS = {
336
+ prompt: "prompt",
337
+ model: "model",
338
+ aspect_ratio: "aspect_ratio",
339
+ keyframes: "keyframes",
340
+ loop: "loop",
341
+ duration: "duration",
342
+ type: "type",
343
+ image_ref: "image_ref",
344
+ video: "video",
345
+ source: "source"
346
+ };
347
+ var OPENROUTER_ROUTING_PARAMS = {
348
+ provider: "provider",
349
+ order: "order",
350
+ "provider.order": "provider.order",
351
+ only: "only",
352
+ "provider.only": "provider.only",
353
+ ignore: "ignore",
354
+ "provider.ignore": "provider.ignore",
355
+ allow_fallbacks: "allow_fallbacks",
356
+ "provider.allow_fallbacks": "provider.allow_fallbacks",
357
+ require_parameters: "require_parameters",
358
+ "provider.require_parameters": "provider.require_parameters",
359
+ data_collection: "data_collection",
360
+ "provider.data_collection": "provider.data_collection",
361
+ zdr: "zdr",
362
+ "provider.zdr": "provider.zdr",
363
+ enforce_distillable_text: "enforce_distillable_text",
364
+ "provider.enforce_distillable_text": "provider.enforce_distillable_text",
365
+ quantizations: "quantizations",
366
+ "provider.quantizations": "provider.quantizations",
367
+ sort: "sort",
368
+ "provider.sort": "provider.sort",
369
+ preferred_min_throughput: "preferred_min_throughput",
370
+ "provider.preferred_min_throughput": "provider.preferred_min_throughput",
371
+ preferred_max_latency: "preferred_max_latency",
372
+ "provider.preferred_max_latency": "provider.preferred_max_latency",
373
+ max_price: "max_price",
374
+ "provider.max_price": "provider.max_price",
375
+ transforms: "transforms",
376
+ plugins: "plugins"
377
+ };
242
378
  var GOOGLE_COMPATIBLE_PARAMS = {
243
379
  temperature: "temperature",
244
380
  max_tokens: "maxOutputTokens",
@@ -257,6 +393,7 @@ var PROVIDER_PARAMS = {
257
393
  openai: {
258
394
  temperature: "temperature",
259
395
  max_tokens: "max_tokens",
396
+ max_completion_tokens: "max_completion_tokens",
260
397
  top_p: "top_p",
261
398
  frequency_penalty: "frequency_penalty",
262
399
  presence_penalty: "presence_penalty",
@@ -333,6 +470,7 @@ var PROVIDER_PARAMS = {
333
470
  // OpenAI-compatible API with extra routing params
334
471
  temperature: "temperature",
335
472
  max_tokens: "max_tokens",
473
+ max_completion_tokens: "max_completion_tokens",
336
474
  top_p: "top_p",
337
475
  top_k: "top_k",
338
476
  frequency_penalty: "frequency_penalty",
@@ -341,12 +479,14 @@ var PROVIDER_PARAMS = {
341
479
  n: "n",
342
480
  seed: "seed",
343
481
  stream: "stream",
344
- effort: "reasoning_effort"
482
+ effort: "reasoning_effort",
483
+ ...OPENROUTER_ROUTING_PARAMS
345
484
  },
346
485
  vercel: {
347
486
  // OpenAI-compatible gateway
348
487
  temperature: "temperature",
349
488
  max_tokens: "max_tokens",
489
+ max_completion_tokens: "max_completion_tokens",
350
490
  top_p: "top_p",
351
491
  top_k: "top_k",
352
492
  frequency_penalty: "frequency_penalty",
@@ -359,7 +499,7 @@ var PROVIDER_PARAMS = {
359
499
  },
360
500
  xai: OPENAI_COMPATIBLE_PARAMS,
361
501
  groq: OPENAI_COMPATIBLE_PARAMS,
362
- fal: {},
502
+ fal: FAL_PARAMS,
363
503
  deepinfra: OPENAI_COMPATIBLE_PARAMS,
364
504
  "black-forest-labs": {},
365
505
  together: OPENAI_COMPATIBLE_PARAMS,
@@ -369,9 +509,9 @@ var PROVIDER_PARAMS = {
369
509
  perplexity: OPENAI_COMPATIBLE_PARAMS,
370
510
  alibaba: OPENAI_COMPATIBLE_PARAMS,
371
511
  cerebras: OPENAI_COMPATIBLE_PARAMS,
372
- replicate: {},
373
- prodia: {},
374
- luma: {},
512
+ replicate: REPLICATE_PARAMS,
513
+ prodia: PRODIA_PARAMS,
514
+ luma: LUMA_PARAMS,
375
515
  bytedance: {},
376
516
  kling: {},
377
517
  elevenlabs: {},
@@ -384,6 +524,15 @@ var PROVIDER_PARAMS = {
384
524
  baseten: OPENAI_COMPATIBLE_PARAMS,
385
525
  huggingface: OPENAI_COMPATIBLE_PARAMS
386
526
  };
527
+ var REASONING_EFFORT_VALUES = [
528
+ "none",
529
+ "minimal",
530
+ "low",
531
+ "medium",
532
+ "high",
533
+ "xhigh",
534
+ "max"
535
+ ];
387
536
  var OPENAI_COMPATIBLE_PARAM_SPECS = {
388
537
  temperature: {
389
538
  type: "number",
@@ -398,6 +547,12 @@ var OPENAI_COMPATIBLE_PARAM_SPECS = {
398
547
  default: 4096,
399
548
  description: "Maximum output tokens"
400
549
  },
550
+ max_completion_tokens: {
551
+ type: "number",
552
+ min: 1,
553
+ default: 4096,
554
+ description: "Maximum completion tokens (reasoning models)"
555
+ },
401
556
  top_p: {
402
557
  type: "number",
403
558
  min: 0,
@@ -431,11 +586,221 @@ var OPENAI_COMPATIBLE_PARAM_SPECS = {
431
586
  stream: { type: "boolean", default: false, description: "Stream response" },
432
587
  reasoning_effort: {
433
588
  type: "string",
434
- values: ["none", "minimal", "low", "medium", "high", "xhigh"],
589
+ values: REASONING_EFFORT_VALUES,
435
590
  default: "medium",
436
591
  description: "Reasoning effort"
437
592
  }
438
593
  };
594
+ var OPENROUTER_ROUTING_PARAM_SPECS = {
595
+ provider: { type: "string", description: "Provider routing preferences" },
596
+ order: { type: "string", description: "Provider order" },
597
+ "provider.order": { type: "string", description: "Provider order" },
598
+ only: { type: "string", description: "Provider allowlist" },
599
+ "provider.only": { type: "string", description: "Provider allowlist" },
600
+ ignore: { type: "string", description: "Provider blocklist" },
601
+ "provider.ignore": { type: "string", description: "Provider blocklist" },
602
+ allow_fallbacks: {
603
+ type: "boolean",
604
+ default: true,
605
+ description: "Allow fallback providers"
606
+ },
607
+ "provider.allow_fallbacks": {
608
+ type: "boolean",
609
+ default: true,
610
+ description: "Allow fallback providers"
611
+ },
612
+ require_parameters: {
613
+ type: "boolean",
614
+ default: false,
615
+ description: "Only route to providers that support all request params"
616
+ },
617
+ "provider.require_parameters": {
618
+ type: "boolean",
619
+ default: false,
620
+ description: "Only route to providers that support all request params"
621
+ },
622
+ data_collection: {
623
+ type: "string",
624
+ values: ["allow", "deny"],
625
+ default: "allow",
626
+ description: "Provider data collection policy"
627
+ },
628
+ "provider.data_collection": {
629
+ type: "string",
630
+ values: ["allow", "deny"],
631
+ default: "allow",
632
+ description: "Provider data collection policy"
633
+ },
634
+ zdr: {
635
+ type: "boolean",
636
+ description: "Require zero data retention providers"
637
+ },
638
+ "provider.zdr": {
639
+ type: "boolean",
640
+ description: "Require zero data retention providers"
641
+ },
642
+ enforce_distillable_text: {
643
+ type: "boolean",
644
+ description: "Require providers that allow text distillation"
645
+ },
646
+ "provider.enforce_distillable_text": {
647
+ type: "boolean",
648
+ description: "Require providers that allow text distillation"
649
+ },
650
+ quantizations: {
651
+ type: "string",
652
+ description: "Allowed provider quantization levels"
653
+ },
654
+ "provider.quantizations": {
655
+ type: "string",
656
+ description: "Allowed provider quantization levels"
657
+ },
658
+ sort: {
659
+ type: "string",
660
+ values: ["price", "throughput", "latency", "cost", "ttft", "tps"],
661
+ description: "Provider sort strategy"
662
+ },
663
+ "provider.sort": {
664
+ type: "string",
665
+ values: ["price", "throughput", "latency", "cost", "ttft", "tps"],
666
+ description: "Provider sort strategy"
667
+ },
668
+ preferred_min_throughput: {
669
+ type: "number",
670
+ min: 0,
671
+ description: "Preferred minimum provider throughput"
672
+ },
673
+ "provider.preferred_min_throughput": {
674
+ type: "number",
675
+ min: 0,
676
+ description: "Preferred minimum provider throughput"
677
+ },
678
+ preferred_max_latency: {
679
+ type: "number",
680
+ min: 0,
681
+ description: "Preferred maximum provider latency"
682
+ },
683
+ "provider.preferred_max_latency": {
684
+ type: "number",
685
+ min: 0,
686
+ description: "Preferred maximum provider latency"
687
+ },
688
+ max_price: {
689
+ type: "string",
690
+ description: "Maximum provider price filter"
691
+ },
692
+ "provider.max_price": {
693
+ type: "string",
694
+ description: "Maximum provider price filter"
695
+ },
696
+ transforms: {
697
+ type: "string",
698
+ description: "Legacy OpenRouter message transforms"
699
+ },
700
+ plugins: {
701
+ type: "string",
702
+ description: "OpenRouter request plugins"
703
+ }
704
+ };
705
+ var FAL_PARAM_SPECS = {
706
+ prompt: { type: "string", description: "Prompt" },
707
+ negative_prompt: { type: "string", description: "Negative prompt" },
708
+ seed: { type: "number", description: "Random seed" },
709
+ num_images: {
710
+ type: "number",
711
+ min: 1,
712
+ description: "Number of images to generate"
713
+ },
714
+ image_size: { type: "string", description: "Output image size" },
715
+ aspect_ratio: { type: "string", description: "Output aspect ratio" },
716
+ enable_safety_checker: {
717
+ type: "boolean",
718
+ description: "Enable safety checker"
719
+ },
720
+ enable_safety_checks: {
721
+ type: "boolean",
722
+ description: "Enable safety checker"
723
+ },
724
+ enable_prompt_expansion: {
725
+ type: "boolean",
726
+ description: "Enable prompt expansion"
727
+ },
728
+ expand_prompt: {
729
+ type: "boolean",
730
+ description: "Enable prompt expansion"
731
+ },
732
+ output_format: {
733
+ type: "string",
734
+ values: ["jpeg", "jpg", "png", "webp", "gif"],
735
+ description: "Output image format"
736
+ },
737
+ width: { type: "number", min: 1, description: "Image width" },
738
+ height: { type: "number", min: 1, description: "Image height" }
739
+ };
740
+ var REPLICATE_PARAM_SPECS = {
741
+ prompt: { type: "string", description: "Prompt" },
742
+ negative_prompt: { type: "string", description: "Negative prompt" },
743
+ input: { type: "string", description: "Model input object" },
744
+ version: { type: "string", description: "Model version" },
745
+ seed: { type: "number", description: "Random seed" },
746
+ num_outputs: {
747
+ type: "number",
748
+ min: 1,
749
+ description: "Number of outputs to generate"
750
+ },
751
+ num_inference_steps: {
752
+ type: "number",
753
+ min: 1,
754
+ description: "Number of inference steps"
755
+ },
756
+ guidance_scale: {
757
+ type: "number",
758
+ min: 0,
759
+ description: "Guidance scale"
760
+ },
761
+ image_size: { type: "string", description: "Output image size" },
762
+ aspect_ratio: { type: "string", description: "Output aspect ratio" },
763
+ output_format: { type: "string", description: "Output format" },
764
+ width: { type: "number", min: 1, description: "Image width" },
765
+ height: { type: "number", min: 1, description: "Image height" },
766
+ stream: { type: "boolean", description: "Request streaming output" },
767
+ webhook: { type: "string", description: "Webhook URL" },
768
+ webhook_events_filter: {
769
+ type: "string",
770
+ description: "Webhook events filter"
771
+ }
772
+ };
773
+ var PRODIA_PARAM_SPECS = {
774
+ model: { type: "string", description: "Model name" },
775
+ prompt: { type: "string", description: "Prompt" },
776
+ negative_prompt: { type: "string", description: "Negative prompt" },
777
+ style_preset: { type: "string", description: "Style preset" },
778
+ steps: { type: "number", min: 1, description: "Generation steps" },
779
+ cfg_scale: { type: "number", min: 0, description: "CFG scale" },
780
+ seed: { type: "number", description: "Random seed" },
781
+ upscale: { type: "boolean", description: "Enable 2x upscale" },
782
+ sampler: { type: "string", description: "Sampler" },
783
+ width: { type: "number", min: 1, max: 1024, description: "Image width" },
784
+ height: { type: "number", min: 1, max: 1024, description: "Image height" },
785
+ image_size: { type: "string", description: "Output image size" },
786
+ aspect_ratio: { type: "string", description: "Output aspect ratio" },
787
+ output_format: { type: "string", description: "Output format" },
788
+ type: { type: "string", description: "Prodia v2 job type" },
789
+ config: { type: "string", description: "Prodia v2 job config" },
790
+ price: { type: "boolean", description: "Include Prodia v2 job price" }
791
+ };
792
+ var LUMA_PARAM_SPECS = {
793
+ prompt: { type: "string", description: "Prompt" },
794
+ model: { type: "string", description: "Model name" },
795
+ aspect_ratio: { type: "string", description: "Output aspect ratio" },
796
+ keyframes: { type: "string", description: "Generation keyframes" },
797
+ loop: { type: "boolean", description: "Generate a looping video" },
798
+ duration: { type: "string", description: "Generation duration" },
799
+ type: { type: "string", description: "Generation type" },
800
+ image_ref: { type: "string", description: "Image reference" },
801
+ video: { type: "string", description: "Video options" },
802
+ source: { type: "string", description: "Source generation or media" }
803
+ };
439
804
  var GOOGLE_COMPATIBLE_PARAM_SPECS = {
440
805
  temperature: {
441
806
  type: "number",
@@ -504,6 +869,12 @@ var PARAM_SPECS = {
504
869
  default: 4096,
505
870
  description: "Maximum output tokens"
506
871
  },
872
+ max_completion_tokens: {
873
+ type: "number",
874
+ min: 1,
875
+ default: 4096,
876
+ description: "Maximum completion tokens (reasoning models)"
877
+ },
507
878
  top_p: {
508
879
  type: "number",
509
880
  min: 0,
@@ -531,7 +902,7 @@ var PARAM_SPECS = {
531
902
  stream: { type: "boolean", default: false, description: "Stream response" },
532
903
  reasoning_effort: {
533
904
  type: "string",
534
- values: ["none", "minimal", "low", "medium", "high", "xhigh"],
905
+ values: REASONING_EFFORT_VALUES,
535
906
  default: "medium",
536
907
  description: "Reasoning effort"
537
908
  }
@@ -568,8 +939,8 @@ var PARAM_SPECS = {
568
939
  stream: { type: "boolean", default: false, description: "Stream response" },
569
940
  effort: {
570
941
  type: "string",
571
- values: ["low", "medium", "high", "max"],
572
- default: "medium",
942
+ values: REASONING_EFFORT_VALUES,
943
+ default: "low",
573
944
  description: "Thinking effort"
574
945
  },
575
946
  cache_control: {
@@ -794,6 +1165,12 @@ var PARAM_SPECS = {
794
1165
  default: 4096,
795
1166
  description: "Maximum output tokens"
796
1167
  },
1168
+ max_completion_tokens: {
1169
+ type: "number",
1170
+ min: 1,
1171
+ default: 4096,
1172
+ description: "Maximum completion tokens (reasoning models)"
1173
+ },
797
1174
  top_p: {
798
1175
  type: "number",
799
1176
  min: 0,
@@ -827,10 +1204,11 @@ var PARAM_SPECS = {
827
1204
  stream: { type: "boolean", default: false, description: "Stream response" },
828
1205
  reasoning_effort: {
829
1206
  type: "string",
830
- values: ["none", "minimal", "low", "medium", "high", "xhigh"],
1207
+ values: REASONING_EFFORT_VALUES,
831
1208
  default: "medium",
832
1209
  description: "Reasoning effort"
833
- }
1210
+ },
1211
+ ...OPENROUTER_ROUTING_PARAM_SPECS
834
1212
  },
835
1213
  vercel: {
836
1214
  // Loose validation — proxies to many providers with varying ranges
@@ -847,6 +1225,12 @@ var PARAM_SPECS = {
847
1225
  default: 4096,
848
1226
  description: "Maximum output tokens"
849
1227
  },
1228
+ max_completion_tokens: {
1229
+ type: "number",
1230
+ min: 1,
1231
+ default: 4096,
1232
+ description: "Maximum completion tokens (reasoning models)"
1233
+ },
850
1234
  top_p: {
851
1235
  type: "number",
852
1236
  min: 0,
@@ -880,14 +1264,70 @@ var PARAM_SPECS = {
880
1264
  stream: { type: "boolean", default: false, description: "Stream response" },
881
1265
  reasoning_effort: {
882
1266
  type: "string",
883
- values: ["none", "minimal", "low", "medium", "high", "xhigh"],
1267
+ values: REASONING_EFFORT_VALUES,
884
1268
  default: "medium",
885
1269
  description: "Reasoning effort"
1270
+ },
1271
+ order: { type: "string", description: "Gateway provider order" },
1272
+ only: { type: "string", description: "Gateway provider allowlist" },
1273
+ models: { type: "string", description: "Gateway fallback models" },
1274
+ tags: { type: "string", description: "Gateway usage tags" },
1275
+ sort: {
1276
+ type: "string",
1277
+ values: ["cost", "ttft", "tps"],
1278
+ description: "Gateway provider sort strategy"
1279
+ },
1280
+ caching: {
1281
+ type: "string",
1282
+ values: ["auto"],
1283
+ description: "Gateway automatic caching strategy"
1284
+ },
1285
+ user: { type: "string", description: "Gateway usage user identifier" },
1286
+ byok: { type: "string", description: "Gateway BYOK credentials" },
1287
+ zero_data_retention: {
1288
+ type: "boolean",
1289
+ description: "Gateway zero data retention routing"
1290
+ },
1291
+ zeroDataRetention: {
1292
+ type: "boolean",
1293
+ description: "Gateway zero data retention routing"
1294
+ },
1295
+ disallow_prompt_training: {
1296
+ type: "boolean",
1297
+ description: "Gateway prompt training opt-out routing"
1298
+ },
1299
+ disallowPromptTraining: {
1300
+ type: "boolean",
1301
+ description: "Gateway prompt training opt-out routing"
1302
+ },
1303
+ hipaa_compliant: {
1304
+ type: "boolean",
1305
+ description: "Gateway HIPAA-compliant routing"
1306
+ },
1307
+ hipaaCompliant: {
1308
+ type: "boolean",
1309
+ description: "Gateway HIPAA-compliant routing"
1310
+ },
1311
+ quota_entity_id: {
1312
+ type: "string",
1313
+ description: "Gateway quota entity identifier"
1314
+ },
1315
+ quotaEntityId: {
1316
+ type: "string",
1317
+ description: "Gateway quota entity identifier"
1318
+ },
1319
+ provider_timeouts: {
1320
+ type: "string",
1321
+ description: "Gateway provider timeouts"
1322
+ },
1323
+ providerTimeouts: {
1324
+ type: "string",
1325
+ description: "Gateway provider timeouts"
886
1326
  }
887
1327
  },
888
1328
  xai: OPENAI_COMPATIBLE_PARAM_SPECS,
889
1329
  groq: OPENAI_COMPATIBLE_PARAM_SPECS,
890
- fal: {},
1330
+ fal: FAL_PARAM_SPECS,
891
1331
  deepinfra: OPENAI_COMPATIBLE_PARAM_SPECS,
892
1332
  "black-forest-labs": {},
893
1333
  together: OPENAI_COMPATIBLE_PARAM_SPECS,
@@ -897,9 +1337,9 @@ var PARAM_SPECS = {
897
1337
  perplexity: OPENAI_COMPATIBLE_PARAM_SPECS,
898
1338
  alibaba: OPENAI_COMPATIBLE_PARAM_SPECS,
899
1339
  cerebras: OPENAI_COMPATIBLE_PARAM_SPECS,
900
- replicate: {},
901
- prodia: {},
902
- luma: {},
1340
+ replicate: REPLICATE_PARAM_SPECS,
1341
+ prodia: PRODIA_PARAM_SPECS,
1342
+ luma: LUMA_PARAM_SPECS,
903
1343
  bytedance: {},
904
1344
  kling: {},
905
1345
  elevenlabs: {},
@@ -913,11 +1353,13 @@ var PARAM_SPECS = {
913
1353
  huggingface: OPENAI_COMPATIBLE_PARAM_SPECS
914
1354
  };
915
1355
  function isReasoningModel(model) {
916
- const name = model.includes("/") ? model.split("/").pop() : model;
917
- return /^o[134]/.test(name);
1356
+ const name = modelLeafName(model);
1357
+ const oSeries = name.match(/^o\d+/)?.[0];
1358
+ const gptSeries = name.match(/^gpt-[5-9]/)?.[0];
1359
+ return (oSeries ? modelMatchesFamily(name, oSeries) : false) || (gptSeries ? modelMatchesFamily(name, gptSeries) : false);
918
1360
  }
919
1361
  function canHostOpenAIModels(provider) {
920
- return provider === "openai" || provider === "openrouter" || provider === "vercel";
1362
+ return provider === "openai" || provider === "azure" || provider === "openrouter" || provider === "vercel";
921
1363
  }
922
1364
  function isGatewayProvider(provider) {
923
1365
  return provider === "openrouter" || provider === "vercel";
@@ -925,29 +1367,27 @@ function isGatewayProvider(provider) {
925
1367
  function detectGatewaySubProvider(model) {
926
1368
  const slash = model.indexOf("/");
927
1369
  if (slash < 1) return void 0;
928
- const prefix = model.slice(0, slash);
929
- const direct = [
930
- "openai",
931
- "anthropic",
932
- "google",
933
- "mistral",
934
- "cohere"
935
- ];
936
- return direct.find((p) => p === prefix);
1370
+ const prefix = normalizeModelForMatching(model.slice(0, slash));
1371
+ const direct = {
1372
+ openai: "openai",
1373
+ anthropic: "anthropic",
1374
+ google: "google",
1375
+ vertex: "google",
1376
+ "google-vertex": "google",
1377
+ mistral: "mistral",
1378
+ cohere: "cohere"
1379
+ };
1380
+ return direct[prefix];
937
1381
  }
938
1382
  var REASONING_MODEL_UNSUPPORTED = /* @__PURE__ */ new Set([
939
1383
  "temperature",
940
1384
  "top_p",
1385
+ "top_k",
941
1386
  "frequency_penalty",
942
1387
  "presence_penalty",
943
1388
  "n"
944
1389
  ]);
945
1390
  function detectBedrockModelFamily(model) {
946
- const parts = model.split(".");
947
- let prefix = parts[0];
948
- if (["us", "eu", "apac", "global"].includes(prefix) && parts.length > 1) {
949
- prefix = parts[1];
950
- }
951
1391
  const families = [
952
1392
  "anthropic",
953
1393
  "meta",
@@ -956,12 +1396,18 @@ function detectBedrockModelFamily(model) {
956
1396
  "cohere",
957
1397
  "ai21"
958
1398
  ];
959
- return families.find((f) => prefix === f);
1399
+ const parts = modelLeafName(model).split(".");
1400
+ return families.find((family) => parts.includes(family));
960
1401
  }
961
1402
  function bedrockSupportsCaching(model) {
962
1403
  const family = detectBedrockModelFamily(model);
963
1404
  if (family === "anthropic") return true;
964
- if (family === "amazon" && model.includes("nova")) return true;
1405
+ if (family === "amazon") {
1406
+ const parts = modelLeafName(model).split(".");
1407
+ const amazonIndex = parts.indexOf("amazon");
1408
+ const modelName = amazonIndex >= 0 ? parts[amazonIndex + 1] : void 0;
1409
+ return modelName ? modelMatchesFamily(modelName, "nova") : false;
1410
+ }
965
1411
  return false;
966
1412
  }
967
1413
  var CACHE_VALUES = {
@@ -1046,7 +1492,6 @@ var CACHE_TTLS = {
1046
1492
  baseten: void 0,
1047
1493
  huggingface: void 0
1048
1494
  };
1049
- var DURATION_RE = /^\d+[mh]$/;
1050
1495
 
1051
1496
  // src/parse.ts
1052
1497
  function parse(connectionString) {
@@ -1076,6 +1521,7 @@ function parse(connectionString) {
1076
1521
  }
1077
1522
 
1078
1523
  // src/normalize.ts
1524
+ var DURATION_RE = /^\d+[mh]$/;
1079
1525
  function normalize(config, options = {}) {
1080
1526
  const provider = (config.hostAlias ? providerFromHostAlias(config.hostAlias) : void 0) ?? detectProvider(config.host);
1081
1527
  const subProvider = provider && isGatewayProvider(provider) ? detectGatewaySubProvider(config.model) : void 0;
@@ -1163,6 +1609,17 @@ function normalize(config, options = {}) {
1163
1609
  }
1164
1610
  key = "max_completion_tokens";
1165
1611
  }
1612
+ if (provider && canHostOpenAIModels(provider) && isReasoningModel(config.model) && REASONING_MODEL_UNSUPPORTED.has(key)) {
1613
+ if (options.verbose) {
1614
+ changes.push({
1615
+ from: key,
1616
+ to: "(dropped)",
1617
+ value,
1618
+ reason: `${provider} reasoning model "${config.model}" does not support "${key}"`
1619
+ });
1620
+ }
1621
+ continue;
1622
+ }
1166
1623
  params[key] = value;
1167
1624
  }
1168
1625
  return {
@@ -1221,15 +1678,8 @@ function validate(connectionString, options = {}) {
1221
1678
  const gatewayReverseMap = subProvider ? buildReverseParamMap(provider) : void 0;
1222
1679
  const knownParams = subProvider ? buildSubProviderKnownParams(provider, subProvider) : new Set(Object.values(PROVIDER_PARAMS[provider]));
1223
1680
  for (const [key, value] of Object.entries(config.params)) {
1224
- if (canHostOpenAIModels(provider) && isReasoningModel(config.model) && REASONING_MODEL_UNSUPPORTED.has(key)) {
1225
- issues.push({
1226
- param: key,
1227
- value,
1228
- message: `"${key}" is not supported by OpenAI reasoning model "${config.model}". Use "reasoning_effort" instead of temperature for controlling output.`,
1229
- severity: "error"
1230
- });
1231
- continue;
1232
- }
1681
+ const subProviderSpecResult = subProvider && gatewayReverseMap ? lookupSubProviderSpec(key, gatewayReverseMap, subProvider) : void 0;
1682
+ const gatewayOwnSpec = subProvider && !subProviderSpecResult?.spec ? PARAM_SPECS[provider]?.[key] : void 0;
1233
1683
  if (provider === "bedrock") {
1234
1684
  const family = detectBedrockModelFamily(config.model);
1235
1685
  if (key === "topK" && family && family !== "anthropic" && family !== "cohere" && family !== "mistral") {
@@ -1251,20 +1701,18 @@ function validate(connectionString, options = {}) {
1251
1701
  continue;
1252
1702
  }
1253
1703
  }
1254
- if (!knownParams.has(key) && !specs[key]) {
1255
- issues.push({
1256
- param: key,
1257
- value,
1258
- message: `Unknown param "${key}" for ${effectiveProvider}.`,
1259
- severity: options.strict ? "error" : "warning"
1260
- });
1704
+ if (!knownParams.has(key) && !specs[key] && !gatewayOwnSpec) {
1705
+ if (options.strict) {
1706
+ issues.push({
1707
+ param: key,
1708
+ value,
1709
+ message: `Unknown param "${key}" for ${effectiveProvider}.`,
1710
+ severity: "error"
1711
+ });
1712
+ }
1261
1713
  continue;
1262
1714
  }
1263
- let spec = specs[key];
1264
- if (subProvider && gatewayReverseMap && !spec) {
1265
- const result = lookupSubProviderSpec(key, gatewayReverseMap, subProvider);
1266
- spec = result.spec;
1267
- }
1715
+ const spec = subProviderSpecResult?.spec ?? gatewayOwnSpec ?? specs[key];
1268
1716
  if (!spec) continue;
1269
1717
  if ((effectiveProvider === "anthropic" || provider === "bedrock" && detectBedrockModelFamily(config.model) === "anthropic") && (key === "temperature" || key === "top_p" || key === "topP")) {
1270
1718
  const otherKey = key === "temperature" ? provider === "bedrock" ? "topP" : "top_p" : "temperature";
@@ -1332,4 +1780,3 @@ function validate(connectionString, options = {}) {
1332
1780
  0 && (module.exports = {
1333
1781
  validate
1334
1782
  });
1335
- //# sourceMappingURL=validate.cjs.map