workers-ai-provider 3.3.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { C as GatewayDelegateError, S as headersToObject, _ as detectProviderByUrl, a as WORKERS_AI_ERROR_CODE_TO_STATUS, b as asText, c as parseWorkersAIErrorCode, d as isForcedToolChoice, f as normalizeMessagesForBinding$1, g as GATEWAY_PROVIDERS, h as createResumableStream, i as WorkersAIGatewayError, l as SSEDecoder, m as processText, n as createGatewayProvider, o as isAbortError, p as parseLeakedToolCalls$1, r as WorkersAIFallbackError, s as messageOf, t as createGatewayFetch, u as getToolNames, v as findProviderBySlug, w as _defineProperty, x as buildGatewayEntry, y as wireableProviders } from "./gateway-provider-BjPLZLob.mjs";
1
+ import { C as GatewayDelegateError, S as headersToObject, _ as detectProviderByUrl, a as WORKERS_AI_ERROR_CODE_TO_STATUS, b as asText, c as parseWorkersAIErrorCode, d as isForcedToolChoice, f as normalizeMessagesForBinding$1, g as GATEWAY_PROVIDERS, h as createResumableStream, i as WorkersAIGatewayError, l as SSEDecoder, m as processText, n as createGatewayProvider, o as isAbortError, p as parseLeakedToolCalls$1, r as WorkersAIFallbackError, s as messageOf, t as createGatewayFetch, u as getToolNames, v as findProviderBySlug, w as _defineProperty, x as buildGatewayEntry, y as wireableProviders } from "./gateway-provider-BIZ2bimW.mjs";
2
2
  import { APICallError, TooManyEmbeddingValuesForCallError, UnsupportedFunctionalityError } from "@ai-sdk/provider";
3
3
  import { generateId } from "ai";
4
4
  //#region src/workersai-error.ts
@@ -294,7 +294,7 @@ function processToolCalls(output) {
294
294
  *
295
295
  * The recovery logic (which JSON shapes count as a leaked call) lives in
296
296
  * `@cloudflare/gateway-core`; this wrapper only layers the framework id on each
297
- * neutral result so the existing `LanguageModelV3ToolCall` shape is preserved.
297
+ * neutral result so the existing `LanguageModelV4ToolCall` shape is preserved.
298
298
  */
299
299
  function parseLeakedToolCalls(text, knownToolNames) {
300
300
  return parseLeakedToolCalls$1(text, knownToolNames).map((call) => ({
@@ -341,28 +341,41 @@ function salvageToolCallsFromText(output, context) {
341
341
  //#endregion
342
342
  //#region src/convert-to-workersai-chat-messages.ts
343
343
  /**
344
- * Normalise any LanguageModelV3DataContent value to a Uint8Array.
344
+ * Normalise a tagged `SharedV4FileData` value to a Uint8Array.
345
345
  *
346
346
  * Handles:
347
- * - Uint8Array → returned as-is
348
- * - string → decoded from base64 (with or without data-URL prefix)
349
- * - URL → not supported (Workers AI needs raw bytes, not a reference)
347
+ * - { type: 'data' } Uint8Array returned as-is; string decoded from
348
+ * base64 (with or without data-URL prefix)
349
+ * - { type: 'url' } → not supported (Workers AI needs raw bytes, not a reference)
350
+ * - { type: 'reference' } → not supported (Workers AI has no file store to resolve it)
351
+ * - { type: 'text' } → not supported for image parts
350
352
  */
351
- function toUint8Array$2(data) {
352
- if (data instanceof Uint8Array) return data;
353
- if (typeof data === "string") {
354
- let base64 = data;
355
- if (base64.startsWith("data:")) {
356
- const commaIndex = base64.indexOf(",");
357
- if (commaIndex >= 0) base64 = base64.slice(commaIndex + 1);
353
+ function toUint8Array$2(fileData) {
354
+ switch (fileData.type) {
355
+ case "data": {
356
+ const data = fileData.data;
357
+ if (data instanceof Uint8Array) return data;
358
+ let base64 = data;
359
+ if (base64.startsWith("data:")) {
360
+ const commaIndex = base64.indexOf(",");
361
+ if (commaIndex >= 0) base64 = base64.slice(commaIndex + 1);
362
+ }
363
+ const binaryString = atob(base64);
364
+ const bytes = new Uint8Array(binaryString.length);
365
+ for (let i = 0; i < binaryString.length; i++) bytes[i] = binaryString.charCodeAt(i);
366
+ return bytes;
358
367
  }
359
- const binaryString = atob(base64);
360
- const bytes = new Uint8Array(binaryString.length);
361
- for (let i = 0; i < binaryString.length; i++) bytes[i] = binaryString.charCodeAt(i);
362
- return bytes;
368
+ case "url": throw new Error("URL image sources are not supported by Workers AI. Provide image data as a Uint8Array or base64 string instead.");
369
+ case "reference": throw new UnsupportedFunctionalityError({
370
+ functionality: "file-part-provider-reference",
371
+ message: "Provider file references are not supported by Workers AI. Provide image data as a Uint8Array or base64 string instead."
372
+ });
373
+ case "text": throw new UnsupportedFunctionalityError({
374
+ functionality: "file-part-inline-text",
375
+ message: "Inline text file parts are not supported by Workers AI chat. Pass text as a regular text part instead."
376
+ });
377
+ default: throw new Error(`Unsupported file data type: ${fileData.type}`);
363
378
  }
364
- if (data instanceof URL) throw new Error("URL image sources are not supported by Workers AI. Provide image data as a Uint8Array or base64 string instead.");
365
- return null;
366
379
  }
367
380
  function assertImageMediaType(mediaType) {
368
381
  if (!mediaType) throw new UnsupportedFunctionalityError({
@@ -445,6 +458,8 @@ function convertToWorkersAIChatMessages(prompt) {
445
458
  reasoning += part.text;
446
459
  break;
447
460
  case "file": break;
461
+ case "reasoning-file": break;
462
+ case "custom": break;
448
463
  case "tool-call":
449
464
  toolCalls.push({
450
465
  function: {
@@ -511,7 +526,7 @@ function convertToWorkersAIChatMessages(prompt) {
511
526
  //#endregion
512
527
  //#region src/map-workersai-usage.ts
513
528
  /**
514
- * Map Workers AI usage data to the AI SDK V3 usage format.
529
+ * Map Workers AI usage data to the AI SDK v4 usage format.
515
530
  * Accepts any object that may have a `usage` property with token counts.
516
531
  *
517
532
  * Workers AI mirrors the OpenAI usage shape, including
@@ -595,7 +610,7 @@ function mapWorkersAIFinishReason(finishReasonOrResponse) {
595
610
  //#endregion
596
611
  //#region src/streaming.ts
597
612
  /**
598
- * Prepend a stream-start event to an existing LanguageModelV3 stream.
613
+ * Prepend a stream-start event to an existing LanguageModelV4 stream.
599
614
  * Uses pipeThrough for proper backpressure and error propagation.
600
615
  */
601
616
  function prependStreamStart(source, warnings) {
@@ -629,7 +644,7 @@ function isNullFinalizationChunk(tc) {
629
644
  return !(tc.id ?? null) && !name && (!args || args === "");
630
645
  }
631
646
  /**
632
- * Maps a Workers AI SSE stream into AI SDK V3 LanguageModelV3StreamPart events.
647
+ * Maps a Workers AI SSE stream into AI SDK LanguageModelV4StreamPart events.
633
648
  *
634
649
  * Uses a TransformStream pipeline for proper backpressure — chunks are emitted
635
650
  * one at a time as the downstream consumer pulls, not buffered eagerly.
@@ -949,7 +964,7 @@ function getMappedStream(response, salvageContext) {
949
964
  //#region src/aisearch-chat-language-model.ts
950
965
  var AISearchChatLanguageModel = class {
951
966
  constructor(modelId, settings, config) {
952
- _defineProperty(this, "specificationVersion", "v3");
967
+ _defineProperty(this, "specificationVersion", "v4");
953
968
  _defineProperty(this, "defaultObjectGenerationMode", "json");
954
969
  _defineProperty(this, "supportedUrls", {});
955
970
  _defineProperty(this, "modelId", void 0);
@@ -1042,7 +1057,7 @@ var WorkersAIEmbeddingModel = class {
1042
1057
  return this.settings.supportsParallelCalls ?? true;
1043
1058
  }
1044
1059
  constructor(modelId, settings, config) {
1045
- _defineProperty(this, "specificationVersion", "v3");
1060
+ _defineProperty(this, "specificationVersion", "v4");
1046
1061
  _defineProperty(this, "modelId", void 0);
1047
1062
  _defineProperty(this, "config", void 0);
1048
1063
  _defineProperty(this, "settings", void 0);
@@ -1079,9 +1094,26 @@ var WorkersAIEmbeddingModel = class {
1079
1094
  };
1080
1095
  //#endregion
1081
1096
  //#region src/workersai-chat-language-model.ts
1097
+ /**
1098
+ * Map the unified `reasoning` call option (spec v4) to Workers AI's
1099
+ * `reasoning_effort`. Workers AI accepts "low" | "medium" | "high" | null
1100
+ * (null disables reasoning), so `minimal` and `xhigh` are clamped to the
1101
+ * nearest supported effort. `provider-default` (and absence) returns
1102
+ * undefined so the settings-level `reasoning_effort` still applies.
1103
+ */
1104
+ function mapUnifiedReasoningEffort(reasoning) {
1105
+ switch (reasoning) {
1106
+ case void 0:
1107
+ case "provider-default": return;
1108
+ case "none": return null;
1109
+ case "minimal": return "low";
1110
+ case "xhigh": return "high";
1111
+ default: return reasoning;
1112
+ }
1113
+ }
1082
1114
  var WorkersAIChatLanguageModel = class {
1083
1115
  constructor(modelId, settings, config) {
1084
- _defineProperty(this, "specificationVersion", "v3");
1116
+ _defineProperty(this, "specificationVersion", "v4");
1085
1117
  _defineProperty(this, "defaultObjectGenerationMode", "json");
1086
1118
  _defineProperty(this, "supportedUrls", {});
1087
1119
  _defineProperty(this, "modelId", void 0);
@@ -1094,7 +1126,7 @@ var WorkersAIChatLanguageModel = class {
1094
1126
  get provider() {
1095
1127
  return this.config.provider;
1096
1128
  }
1097
- getArgs({ responseFormat, tools, toolChoice, maxOutputTokens, temperature, topP, frequencyPenalty, presencePenalty, seed }) {
1129
+ getArgs({ responseFormat, tools, toolChoice, maxOutputTokens, temperature, topP, frequencyPenalty, presencePenalty, seed, reasoning }) {
1098
1130
  const type = responseFormat?.type ?? "text";
1099
1131
  const warnings = [];
1100
1132
  if (frequencyPenalty != null) warnings.push({
@@ -1105,6 +1137,11 @@ var WorkersAIChatLanguageModel = class {
1105
1137
  feature: "presencePenalty",
1106
1138
  type: "unsupported"
1107
1139
  });
1140
+ if (reasoning === "minimal" || reasoning === "xhigh") warnings.push({
1141
+ type: "compatibility",
1142
+ feature: "reasoning",
1143
+ details: `Workers AI supports reasoning_effort "low" | "medium" | "high"; "${reasoning}" was mapped to "${reasoning === "minimal" ? "low" : "high"}".`
1144
+ });
1108
1145
  const baseArgs = {
1109
1146
  max_tokens: maxOutputTokens,
1110
1147
  model: this.modelId,
@@ -1157,11 +1194,17 @@ var WorkersAIChatLanguageModel = class {
1157
1194
  *
1158
1195
  * `reasoning_effort: null` is a valid value ("disable reasoning"), so we
1159
1196
  * check `!== undefined` rather than truthiness.
1197
+ *
1198
+ * The unified `reasoning` call option (spec v4) is mapped onto
1199
+ * `reasoning_effort` between the two: an explicit per-call
1200
+ * `providerOptions["workers-ai"].reasoning_effort` wins, then the unified
1201
+ * option, then settings.
1160
1202
  */
1161
1203
  buildRunInputs(args, messages, options) {
1162
1204
  const rawPerCall = options?.providerOptions?.["workers-ai"];
1163
1205
  const perCall = rawPerCall !== null && typeof rawPerCall === "object" && !Array.isArray(rawPerCall) ? rawPerCall : {};
1164
- const reasoningEffort = "reasoning_effort" in perCall ? perCall.reasoning_effort : this.settings.reasoning_effort;
1206
+ const unifiedReasoningEffort = mapUnifiedReasoningEffort(options?.reasoning);
1207
+ const reasoningEffort = "reasoning_effort" in perCall ? perCall.reasoning_effort : unifiedReasoningEffort !== void 0 ? unifiedReasoningEffort : this.settings.reasoning_effort;
1165
1208
  const chatTemplateKwargs = "chat_template_kwargs" in perCall ? perCall.chat_template_kwargs : this.settings.chat_template_kwargs;
1166
1209
  return {
1167
1210
  max_tokens: args.max_tokens,
@@ -1230,7 +1273,10 @@ var WorkersAIChatLanguageModel = class {
1230
1273
  async doGenerate(options) {
1231
1274
  const { args, warnings } = this.getArgs(options);
1232
1275
  const { messages } = convertToWorkersAIChatMessages(options.prompt);
1233
- const inputs = this.buildRunInputs(args, messages, { providerOptions: options.providerOptions });
1276
+ const inputs = this.buildRunInputs(args, messages, {
1277
+ providerOptions: options.providerOptions,
1278
+ reasoning: options.reasoning
1279
+ });
1234
1280
  const runOptions = this.getRunOptions();
1235
1281
  let output;
1236
1282
  try {
@@ -1269,7 +1315,8 @@ var WorkersAIChatLanguageModel = class {
1269
1315
  const { messages } = convertToWorkersAIChatMessages(options.prompt);
1270
1316
  const inputs = this.buildRunInputs(args, messages, {
1271
1317
  stream: true,
1272
- providerOptions: options.providerOptions
1318
+ providerOptions: options.providerOptions,
1319
+ reasoning: options.reasoning
1273
1320
  });
1274
1321
  const runOptions = this.getRunOptions();
1275
1322
  let response;
@@ -1352,7 +1399,7 @@ var WorkersAIImageModel = class {
1352
1399
  this.modelId = modelId;
1353
1400
  this.settings = settings;
1354
1401
  this.config = config;
1355
- _defineProperty(this, "specificationVersion", "v3");
1402
+ _defineProperty(this, "specificationVersion", "v4");
1356
1403
  }
1357
1404
  async doGenerate({ prompt, n, size, aspectRatio, seed, abortSignal }) {
1358
1405
  const { width, height } = getDimensionsFromSizeString(size);
@@ -1448,7 +1495,7 @@ async function toUint8Array$1(output) {
1448
1495
  //#endregion
1449
1496
  //#region src/workersai-transcription-model.ts
1450
1497
  /**
1451
- * Workers AI transcription model implementing the AI SDK's `TranscriptionModelV3` interface.
1498
+ * Workers AI transcription model implementing the AI SDK's `TranscriptionModelV4` interface.
1452
1499
  *
1453
1500
  * Supports:
1454
1501
  * - Whisper models (`@cf/openai/whisper`, `whisper-tiny-en`, `whisper-large-v3-turbo`)
@@ -1462,7 +1509,7 @@ var WorkersAITranscriptionModel = class {
1462
1509
  this.modelId = modelId;
1463
1510
  this.settings = settings;
1464
1511
  this.config = config;
1465
- _defineProperty(this, "specificationVersion", "v3");
1512
+ _defineProperty(this, "specificationVersion", "v4");
1466
1513
  }
1467
1514
  async doGenerate(options) {
1468
1515
  const { audio, mediaType, abortSignal } = options;
@@ -1561,7 +1608,7 @@ function uint8ArrayToBase64(bytes) {
1561
1608
  //#endregion
1562
1609
  //#region src/workersai-speech-model.ts
1563
1610
  /**
1564
- * Workers AI speech (text-to-speech) model implementing the AI SDK's `SpeechModelV3` interface.
1611
+ * Workers AI speech (text-to-speech) model implementing the AI SDK's `SpeechModelV4` interface.
1565
1612
  *
1566
1613
  * Currently supports Deepgram Aura-1 (`@cf/deepgram/aura-1`).
1567
1614
  * The model accepts `{ text, voice?, speed? }` and returns raw audio bytes.
@@ -1574,7 +1621,7 @@ var WorkersAISpeechModel = class {
1574
1621
  this.modelId = modelId;
1575
1622
  this.settings = settings;
1576
1623
  this.config = config;
1577
- _defineProperty(this, "specificationVersion", "v3");
1624
+ _defineProperty(this, "specificationVersion", "v4");
1578
1625
  }
1579
1626
  async doGenerate(options) {
1580
1627
  const { text, voice, speed, abortSignal } = options;
@@ -1662,7 +1709,7 @@ async function toUint8Array(output) {
1662
1709
  //#endregion
1663
1710
  //#region src/workersai-reranking-model.ts
1664
1711
  /**
1665
- * Workers AI reranking model implementing the AI SDK's `RerankingModelV3` interface.
1712
+ * Workers AI reranking model implementing the AI SDK's `RerankingModelV4` interface.
1666
1713
  *
1667
1714
  * Supports BGE reranker models (`@cf/baai/bge-reranker-base`, `bge-reranker-v2-m3`).
1668
1715
  *
@@ -1678,7 +1725,7 @@ var WorkersAIRerankingModel = class {
1678
1725
  this.modelId = modelId;
1679
1726
  this.settings = settings;
1680
1727
  this.config = config;
1681
- _defineProperty(this, "specificationVersion", "v3");
1728
+ _defineProperty(this, "specificationVersion", "v4");
1682
1729
  }
1683
1730
  async doRerank(options) {
1684
1731
  const { documents, query, topN, abortSignal } = options;
@@ -1773,7 +1820,7 @@ function createClientFallbackModel(legs) {
1773
1820
  throw new WorkersAIFallbackError(attempts);
1774
1821
  }
1775
1822
  return {
1776
- specificationVersion: "v3",
1823
+ specificationVersion: "v4",
1777
1824
  provider: primary.provider,
1778
1825
  modelId: primary.modelId,
1779
1826
  supportedUrls: primary.supportedUrls,
@@ -1825,7 +1872,7 @@ function selectTransport(opts, resumeExplicitlyTrue, runCatalog = true, gatewayA
1825
1872
  const wantsCaching = opts.cacheTtl !== void 0 || opts.skipCache === true;
1826
1873
  const gatewayOnly = wantsServerFallback || wantsCaching;
1827
1874
  const feature = wantsServerFallback ? "fallback.mode:\"server\"" : "caching (cacheTtl/skipCache)";
1828
- if (runCatalog && !gatewayAvailable && (opts.transport === "gateway" || gatewayOnly)) throw new GatewayDelegateError("config", `${opts.transport === "gateway" ? "transport:\"gateway\"" : feature} is unavailable: this provider is on the unified run catalog but is not a native gateway provider, so it has no gateway path (no caching, server-side fallback, or transport:"gateway"). Use the default run path, or fallback.mode:"client".`);
1875
+ if (runCatalog && !gatewayAvailable && (opts.transport === "gateway" || opts.byok || gatewayOnly)) throw new GatewayDelegateError("config", `${opts.transport === "gateway" ? "transport:\"gateway\"" : opts.byok ? "byok" : feature} is unavailable: this provider is on the unified run catalog but is not a native gateway provider, so it has no gateway path (no caching, server-side fallback, BYOK, or transport:"gateway"). Use the default run path, or fallback.mode:"client".`);
1829
1876
  if (!runCatalog) {
1830
1877
  if (opts.transport === "run") throw new GatewayDelegateError("config", "transport:\"run\" is unavailable: this provider is not on the unified-billing run catalog, so it can only be reached through the gateway path (BYOK).");
1831
1878
  if (resumeExplicitlyTrue) throw new GatewayDelegateError("config", "resume:true is unavailable: this provider is not on the resumable run catalog (cf-aig-run-id requires the unified-billing run path).");
@@ -1835,6 +1882,15 @@ function selectTransport(opts, resumeExplicitlyTrue, runCatalog = true, gatewayA
1835
1882
  warnings
1836
1883
  };
1837
1884
  }
1885
+ if (opts.byok) {
1886
+ if (opts.transport === "run") throw new GatewayDelegateError("config", "transport:\"run\" cannot forward a BYOK key — BYOK is a gateway-path feature. Drop transport:\"run\" (or set transport:\"gateway\").");
1887
+ if (resumeExplicitlyTrue) throw new GatewayDelegateError("config", "byok cannot provide resume — cf-aig-run-id is only on the unified-billing run path.");
1888
+ return {
1889
+ transport: "gateway",
1890
+ resumeEnabled: false,
1891
+ warnings
1892
+ };
1893
+ }
1838
1894
  if (opts.transport === "run" && gatewayOnly) throw new GatewayDelegateError("config", `transport:"run" cannot satisfy ${feature}: those features are only available on the gateway path. Use the gateway transport, or fallback.mode:"client".`);
1839
1895
  if (opts.transport === "gateway" && resumeExplicitlyTrue) throw new GatewayDelegateError("config", "transport:\"gateway\" cannot provide resume — cf-aig-run-id is only on the run path.");
1840
1896
  if (gatewayOnly) {
@@ -2146,7 +2202,7 @@ function makeServerFallbackModel(params) {
2146
2202
  })[method](options);
2147
2203
  };
2148
2204
  return {
2149
- specificationVersion: "v3",
2205
+ specificationVersion: "v4",
2150
2206
  provider: refModel.provider,
2151
2207
  modelId: refModel.modelId,
2152
2208
  supportedUrls: refModel.supportedUrls,
@@ -2189,8 +2245,11 @@ function createWorkersAI(options) {
2189
2245
  isBinding
2190
2246
  });
2191
2247
  const toGatewayOptions = (gateway) => typeof gateway === "string" ? { id: gateway } : gateway;
2192
- const createDynamicRouteModel = (modelId, settings = {}) => {
2193
- if (settings.fallback || settings.transport === "gateway" || settings.resume === true || settings.onProgress || settings.onResumeExpired || settings.byok) throw new Error(`"${modelId}" is an AI Gateway dynamic route. Dynamic routes use AI.run with OpenAI-compatible chat-completions wire format; fallback, gateway transport, resume, BYOK, and resume callbacks must be configured on the dynamic route or gateway instead of per call.`);
2248
+ const createRunPathModel = (modelId, settings = {}, kind) => {
2249
+ if (settings.fallback || settings.transport === "gateway" || settings.resume === true || settings.onProgress || settings.onResumeExpired || settings.byok) {
2250
+ const subject = kind === "dynamic" ? `"${modelId}" is an AI Gateway dynamic route` : `"${modelId}" routes through the bare unified-billing run path because no \`providers\` are configured`;
2251
+ throw new Error(`${subject}. It uses AI.run with OpenAI-compatible chat-completions wire format; fallback, gateway transport, resume, BYOK, and resume callbacks are gateway-delegate features — configure provider plugins to use them (createWorkersAI({ binding: env.AI, providers: [openai] })), and for dynamic routes set caching/fallback on the route or gateway instead of per call.`);
2252
+ }
2194
2253
  const gateway = { ...toGatewayOptions(settings.gateway) ?? options.gateway ?? { id: DEFAULT_GATEWAY_ID } };
2195
2254
  if (settings.metadata) gateway.metadata = {
2196
2255
  ...gateway.metadata ?? {},
@@ -2216,7 +2275,7 @@ function createWorkersAI(options) {
2216
2275
  delete chatSettings.byok;
2217
2276
  const plugin = options.providers?.find((p) => p.wireFormat === DYNAMIC_ROUTE_WIRE_FORMAT);
2218
2277
  if (!plugin) {
2219
- if (options.providers?.length) throw new Error(`"${modelId}" is an AI Gateway dynamic route. Dynamic routes return OpenAI-compatible chat-completions wire format on the AI.run path, so configure the OpenAI provider plugin: import { openai } from "workers-ai-provider/openai"; createWorkersAI({ binding: env.AI, providers: [openai] }).`);
2278
+ if (kind === "dynamic" && options.providers?.length) throw new Error(`"${modelId}" is an AI Gateway dynamic route. Dynamic routes return OpenAI-compatible chat-completions wire format on the AI.run path, so configure the OpenAI provider plugin: import { openai } from "workers-ai-provider/openai"; createWorkersAI({ binding: env.AI, providers: [openai] }).`);
2220
2279
  return createChatModel(modelId, chatSettings);
2221
2280
  }
2222
2281
  const fetchImpl = (async (_input, init) => {
@@ -2263,8 +2322,11 @@ A gateway defaults to "default" but can be set via \`gateway\`. Otherwise use a
2263
2322
  };
2264
2323
  const isGatewaySlug = (id) => typeof id === "string" && !id.startsWith("@") && !id.startsWith("dynamic/") && id.includes("/");
2265
2324
  const buildChat = (modelId, settings) => {
2266
- if (typeof modelId === "string" && modelId.startsWith("dynamic/")) return createDynamicRouteModel(modelId, settings);
2267
- if (isGatewaySlug(modelId)) return getDelegate(modelId)(modelId, settings);
2325
+ if (typeof modelId === "string" && modelId.startsWith("dynamic/")) return createRunPathModel(modelId, settings, "dynamic");
2326
+ if (isGatewaySlug(modelId)) {
2327
+ if (!options.providers?.length) return createRunPathModel(modelId, settings, "catalog");
2328
+ return getDelegate(modelId)(modelId, settings);
2329
+ }
2268
2330
  return createChatModel(modelId, settings);
2269
2331
  };
2270
2332
  const createImageModel = (modelId, settings = {}) => new WorkersAIImageModel(modelId, settings, {