@axlsdk/axl 0.22.0 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -67,7 +67,7 @@ agent({ model: 'deepseek:deepseek-reasoner' }); // DEEPSEEK_API_KEY
67
67
  agent({ model: 'ollama:llama3' }); // local — no key, $0
68
68
  ```
69
69
 
70
- Presets: `openrouter`, `azure`, `xai`, `deepseek`, `mistral`, `groq`, `bedrock`, and self-hosted `ollama` / `vllm` / `lmstudio` / `llamacpp` / `sglang`. The unified `effort` knob and per-call cost tracking work across them. Build your own by cloning a `ProviderProfile`. See [docs/providers.md](../../docs/providers.md#openai-compatible-providers--presets).
70
+ Presets: `openrouter`, `azure`, `xai`, `deepseek`, `mistral`, `groq`, `bedrock`, and self-hosted `ollama` / `vllm` / `lmstudio` / `llamacpp` / `sglang`. The unified `effort` knob and per-call cost tracking work across them. OpenAI Responses, Anthropic, Google, and OpenRouter accept image input without hard-coding a model catalog; the selected upstream model remains authoritative. Completed-file transcription is a separate, narrower contract. Build your own compatible provider by cloning a `ProviderProfile`; see [provider details](../../docs/providers.md) and [multimodal input](../../docs/multimodal-input.md).
71
71
 
72
72
  Each provider also accepts an opt-in `rateLimit` (`{ maxConcurrent?, minIntervalMs?, acquireTimeoutMs? }`) for proactive client-side pacing on top of the automatic 429/503/529 backoff — useful when a large fan-out (e.g. an eval) shares one API key. It caps in-flight request concurrency (not token throughput) for that provider's chat calls. See [Providers → Rate limiting](../../docs/providers.md#rate-limiting-opt-in).
73
73
 
@@ -792,10 +792,12 @@ See [docs/providers.md](../../docs/providers.md) for the full model list includi
792
792
 
793
793
  Use `ctx.transcribe()` for finite recordings, then explicitly pass
794
794
  `Transcript.text` to an agent if analysis is needed. It is separate from chat
795
- history and chat providers. B1 supports exact OpenAI, Gemini, and OpenRouter
796
- transcription URIs; see [Multimodal input](../../docs/multimodal-input.md) for
797
- the 25 MiB inline bound, source types, options, transcript redaction, temporary
798
- Gemini Files cleanup, and live-verification commands.
795
+ history and chat providers. OpenAI and Gemini use their documented model
796
+ contracts; any nonblank `openrouter-transcription:<vendor/model>` URI can
797
+ dispatch supported bytes/base64 to OpenRouter, where the selected model/route
798
+ decides endpoint compatibility. See [Multimodal input](../../docs/multimodal-input.md)
799
+ for the 25 MiB inline bound, source types, options, transcript redaction,
800
+ temporary Gemini Files cleanup, and live-verification commands.
799
801
 
800
802
  ## License
801
803
 
package/dist/index.cjs CHANGED
@@ -1277,13 +1277,12 @@ function unsafeTransportError(surface, remediation, exposedData) {
1277
1277
  }
1278
1278
 
1279
1279
  // src/providers/openai-compatible.ts
1280
- var OPENROUTER_IMAGE_MODEL = "openai/gpt-4o-mini";
1281
1280
  function compatibleImageBase64(source) {
1282
1281
  return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
1283
1282
  "base64"
1284
1283
  );
1285
1284
  }
1286
- function openRouterImageParts(parts) {
1285
+ function openRouterImageParts(parts, model) {
1287
1286
  const content = [];
1288
1287
  for (const part of parts) {
1289
1288
  if (part.type === "text") {
@@ -1294,7 +1293,7 @@ function openRouterImageParts(parts) {
1294
1293
  if (source.type === "provider-file") {
1295
1294
  throw new UnsupportedModelInputError({
1296
1295
  provider: "openrouter",
1297
- model: OPENROUTER_IMAGE_MODEL,
1296
+ model,
1298
1297
  modality: "image",
1299
1298
  source: "provider-file"
1300
1299
  });
@@ -1425,10 +1424,11 @@ function normalizeMessageContent(content) {
1425
1424
  var OpenAICompatibleProvider = class {
1426
1425
  name;
1427
1426
  inputCapabilities(model) {
1428
- return this.name === "openrouter" && model === OPENROUTER_IMAGE_MODEL ? { image: { sources: ["url", "bytes", "base64"] } } : {};
1427
+ return this.name === "openrouter" && model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64"] } } : {};
1429
1428
  }
1430
1429
  validateInput(request) {
1431
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
1430
+ const modelOverride = request.providerOptions?.model;
1431
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
1432
1432
  const fail = (source, feature) => {
1433
1433
  throw new UnsupportedModelInputError({
1434
1434
  provider: this.name,
@@ -1438,13 +1438,15 @@ var OpenAICompatibleProvider = class {
1438
1438
  ...feature ? { feature } : {}
1439
1439
  });
1440
1440
  };
1441
- if (this.name !== "openrouter" || effectiveModel !== OPENROUTER_IMAGE_MODEL) {
1441
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
1442
+ fail(void 0, "invalid model providerOptions");
1443
+ }
1444
+ if (this.name !== "openrouter" || effectiveModel.trim().length === 0) {
1442
1445
  fail(void 0, "image input for this model");
1443
1446
  }
1444
1447
  if (request.providerOptions && "messages" in request.providerOptions) {
1445
1448
  fail(void 0, "raw messages providerOptions");
1446
1449
  }
1447
- if (request.hasTools) fail(void 0, "tools with image input");
1448
1450
  for (const message of request.history) {
1449
1451
  if (!Array.isArray(message.content)) continue;
1450
1452
  if (message.role !== "user") fail(void 0, "rich non-user history");
@@ -1632,7 +1634,7 @@ var OpenAICompatibleProvider = class {
1632
1634
  formatMessage(msg, model) {
1633
1635
  const out = {
1634
1636
  role: this.profile.roleFor ? this.profile.roleFor(msg.role, model) : msg.role,
1635
- content: Array.isArray(msg.content) && this.name === "openrouter" && model === OPENROUTER_IMAGE_MODEL ? openRouterImageParts(msg.content) : msg.content
1637
+ content: Array.isArray(msg.content) && this.name === "openrouter" ? openRouterImageParts(msg.content, model) : msg.content
1636
1638
  };
1637
1639
  if (msg.name && (this.profile.capabilities?.emitsMessageName ?? true)) out.name = msg.name;
1638
1640
  if (msg.tool_calls) out.tool_calls = msg.tool_calls;
@@ -2379,13 +2381,6 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
2379
2381
  };
2380
2382
 
2381
2383
  // src/providers/openai-responses.ts
2382
- var OPENAI_RESPONSES_IMAGE_MODELS = /* @__PURE__ */ new Set([
2383
- "gpt-4o",
2384
- "gpt-4o-2024-08-06",
2385
- "gpt-4o-2024-11-20",
2386
- "gpt-4o-mini",
2387
- "gpt-4o-mini-2024-07-18"
2388
- ]);
2389
2384
  function base64FromSource(source) {
2390
2385
  return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
2391
2386
  "base64"
@@ -2424,10 +2419,11 @@ function responseImageParts(parts) {
2424
2419
  var OpenAIResponsesProvider = class {
2425
2420
  name = "openai-responses";
2426
2421
  inputCapabilities(model) {
2427
- return OPENAI_RESPONSES_IMAGE_MODELS.has(model) ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
2422
+ return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
2428
2423
  }
2429
2424
  validateInput(request) {
2430
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
2425
+ const modelOverride = request.providerOptions?.model;
2426
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
2431
2427
  const fail = (source, feature) => {
2432
2428
  throw new UnsupportedModelInputError({
2433
2429
  provider: this.name,
@@ -2437,7 +2433,10 @@ var OpenAIResponsesProvider = class {
2437
2433
  ...feature ? { feature } : {}
2438
2434
  });
2439
2435
  };
2440
- if (!OPENAI_RESPONSES_IMAGE_MODELS.has(effectiveModel)) {
2436
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
2437
+ fail(void 0, "invalid model providerOptions");
2438
+ }
2439
+ if (effectiveModel.trim().length === 0) {
2441
2440
  fail(void 0, "image input for this model");
2442
2441
  }
2443
2442
  if (request.providerOptions && "input" in request.providerOptions) {
@@ -2565,7 +2564,7 @@ var OpenAIResponsesProvider = class {
2565
2564
  const resolved = resolveThinkingOptions(options);
2566
2565
  const { includeThoughts } = resolved;
2567
2566
  const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
2568
- const stripTemp = oSeries || reasoningCapable && wireEffort !== void 0;
2567
+ const stripTemp = oSeries || supportsMaxReasoningEffort(effectiveModel) || reasoningCapable && wireEffort !== void 0;
2569
2568
  const systemMessages = messages.filter((m) => m.role === "system");
2570
2569
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
2571
2570
  const body = {
@@ -2913,7 +2912,6 @@ function anthropicImageBlocks(parts) {
2913
2912
  }
2914
2913
  var ANTHROPIC_API_VERSION = "2023-06-01";
2915
2914
  var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
2916
- var ANTHROPIC_IMAGE_MODELS = /* @__PURE__ */ new Set(["claude-sonnet-4-5", "claude-opus-4-8"]);
2917
2915
  function hasAnthropicProviderFileImage(messages) {
2918
2916
  return messages.some(
2919
2917
  (message) => Array.isArray(message.content) && message.content.some(
@@ -3032,6 +3030,28 @@ var ANTHROPIC_RATES = {
3032
3030
  function isValidTokenCount(value) {
3033
3031
  return value !== void 0 && Number.isSafeInteger(value) && value >= 0;
3034
3032
  }
3033
+ function anthropicStreamErrorStatus(type) {
3034
+ switch (type) {
3035
+ case "invalid_request_error":
3036
+ return 400;
3037
+ case "authentication_error":
3038
+ return 401;
3039
+ case "permission_error":
3040
+ return 403;
3041
+ case "not_found_error":
3042
+ return 404;
3043
+ case "request_too_large":
3044
+ return 413;
3045
+ case "rate_limit_error":
3046
+ return 429;
3047
+ case "api_error":
3048
+ return 500;
3049
+ case "overloaded_error":
3050
+ return 529;
3051
+ default:
3052
+ return 0;
3053
+ }
3054
+ }
3035
3055
  function estimateAnthropicCost(model, usage, now = /* @__PURE__ */ new Date()) {
3036
3056
  if (!model || !isValidTokenCount(usage.inputTokens) || !isValidTokenCount(usage.outputTokens)) {
3037
3057
  return void 0;
@@ -3281,10 +3301,11 @@ function mergeAnthropicUsage(initial, update) {
3281
3301
  var AnthropicProvider = class {
3282
3302
  name = "anthropic";
3283
3303
  inputCapabilities(model) {
3284
- return ANTHROPIC_IMAGE_MODELS.has(model) ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
3304
+ return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
3285
3305
  }
3286
3306
  validateInput(request) {
3287
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
3307
+ const modelOverride = request.providerOptions?.model;
3308
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
3288
3309
  const fail = (source, feature) => {
3289
3310
  throw new UnsupportedModelInputError({
3290
3311
  provider: this.name,
@@ -3294,7 +3315,10 @@ var AnthropicProvider = class {
3294
3315
  ...feature ? { feature } : {}
3295
3316
  });
3296
3317
  };
3297
- if (!ANTHROPIC_IMAGE_MODELS.has(effectiveModel)) {
3318
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
3319
+ fail(void 0, "invalid model providerOptions");
3320
+ }
3321
+ if (effectiveModel.trim().length === 0) {
3298
3322
  fail(void 0, "image input for this model");
3299
3323
  }
3300
3324
  if (request.providerOptions && "messages" in request.providerOptions) {
@@ -3419,7 +3443,7 @@ var AnthropicProvider = class {
3419
3443
  if (!res.body) {
3420
3444
  throw new Error("Anthropic stream response has no body");
3421
3445
  }
3422
- yield* this.parseSSEStream(res.body, pricingContext);
3446
+ yield* this.parseSSEStream(res.body, pricingContext, res.headers);
3423
3447
  }
3424
3448
  // ---------------------------------------------------------------------------
3425
3449
  // Internal: request building
@@ -3662,7 +3686,7 @@ ${jsonInstruction}` : jsonInstruction;
3662
3686
  // ---------------------------------------------------------------------------
3663
3687
  // Internal: SSE stream parsing
3664
3688
  // ---------------------------------------------------------------------------
3665
- async *parseSSEStream(body, pricingContext) {
3689
+ async *parseSSEStream(body, pricingContext, responseHeaders) {
3666
3690
  const reader = body.getReader();
3667
3691
  const decoder = new TextDecoder();
3668
3692
  let buffer = "";
@@ -3708,6 +3732,15 @@ ${jsonInstruction}` : jsonInstruction;
3708
3732
  continue;
3709
3733
  }
3710
3734
  switch (event.type) {
3735
+ case "error": {
3736
+ const status = anthropicStreamErrorStatus(event.error?.type);
3737
+ throw buildProviderError({
3738
+ provider: this.name,
3739
+ status,
3740
+ headers: responseHeaders,
3741
+ message: event.error?.message ?? "Anthropic stream failed"
3742
+ });
3743
+ }
3711
3744
  case "content_block_start": {
3712
3745
  const block = event.content_block;
3713
3746
  if (block?.type === "tool_use") {
@@ -3959,7 +3992,6 @@ var GEMINI_PRICING = {
3959
3992
  "gemini-3.5-flash-lite": { input: 3e-7, cached: 3e-8, output: 25e-7 },
3960
3993
  "gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
3961
3994
  };
3962
- var GEMINI_INTERACTIONS_IMAGE_MODELS = /* @__PURE__ */ new Set(["gemini-3.7-flash"]);
3963
3995
  function isValidTokenCount2(value) {
3964
3996
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
3965
3997
  }
@@ -3969,6 +4001,55 @@ function isStandardGeminiRequestTier(value) {
3969
4001
  function isDefinitiveStandardGeminiResponseTier(value) {
3970
4002
  return value === "SERVICE_TIER_UNSPECIFIED" || value === "SERVICE_TIER_STANDARD" || value === "standard";
3971
4003
  }
4004
+ function geminiInteractionErrorStatus(code) {
4005
+ if (typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599) {
4006
+ return code;
4007
+ }
4008
+ switch (code) {
4009
+ case "invalid_request":
4010
+ case "invalid_argument":
4011
+ case "parameter_unknown":
4012
+ case "failed_precondition":
4013
+ return 400;
4014
+ case "authentication":
4015
+ case "unauthenticated":
4016
+ return 401;
4017
+ case "permission_denied":
4018
+ return 403;
4019
+ case "not_found":
4020
+ case "model_not_found":
4021
+ return 404;
4022
+ case "request_timeout":
4023
+ return 408;
4024
+ case "conflict":
4025
+ case "already_exists":
4026
+ return 409;
4027
+ case "request_too_large":
4028
+ return 413;
4029
+ case "out_of_range":
4030
+ return 416;
4031
+ case "quota_exceeded":
4032
+ case "resource_exhausted":
4033
+ case "rate_limit_exceeded":
4034
+ return 429;
4035
+ case "cancelled":
4036
+ return 499;
4037
+ case "api_error":
4038
+ case "internal":
4039
+ case "internal_server_error":
4040
+ return 500;
4041
+ case "bad_gateway":
4042
+ return 502;
4043
+ case "unavailable":
4044
+ case "service_unavailable":
4045
+ return 503;
4046
+ case "deadline_exceeded":
4047
+ case "gateway_timeout":
4048
+ return 504;
4049
+ default:
4050
+ return void 0;
4051
+ }
4052
+ }
3972
4053
  function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
3973
4054
  return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
3974
4055
  }
@@ -4050,7 +4131,9 @@ var GEMINI_3X_MIN_THINKING_LEVEL = /* @__PURE__ */ new Map([
4050
4131
  ["gemini-3.6-flash", "minimal"],
4051
4132
  // L4 live evidence: Interactions gemini-3.7-flash accepts low/medium/high,
4052
4133
  // but rejects minimal. Keep this exact entry isolated from legacy aliases.
4053
- ["gemini-3.7-flash", "low"]
4134
+ ["gemini-3.7-flash", "low"],
4135
+ // Current-model live evidence: gemini-3.8-flash has the same low floor.
4136
+ ["gemini-3.8-flash", "low"]
4054
4137
  ]);
4055
4138
  var GEMINI_MODELS_WITHOUT_PORTABLE_TEMPERATURE = /* @__PURE__ */ new Set([
4056
4139
  "gemini-3.5-flash-lite",
@@ -4078,10 +4161,11 @@ function warnGemini3xEffortNone(model) {
4078
4161
  var GeminiProvider = class {
4079
4162
  name = "google";
4080
4163
  inputCapabilities(model) {
4081
- return GEMINI_INTERACTIONS_IMAGE_MODELS.has(model) ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
4164
+ return model.trim().length > 0 ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
4082
4165
  }
4083
4166
  validateInput(request) {
4084
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
4167
+ const modelOverride = request.providerOptions?.model;
4168
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
4085
4169
  const fail = (source, feature) => {
4086
4170
  throw new UnsupportedModelInputError({
4087
4171
  provider: this.name,
@@ -4091,7 +4175,10 @@ var GeminiProvider = class {
4091
4175
  ...feature ? { feature } : {}
4092
4176
  });
4093
4177
  };
4094
- if (!GEMINI_INTERACTIONS_IMAGE_MODELS.has(effectiveModel)) {
4178
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
4179
+ fail(void 0, "invalid model providerOptions");
4180
+ }
4181
+ if (effectiveModel.trim().length === 0) {
4095
4182
  fail(void 0, "image input for this model");
4096
4183
  }
4097
4184
  if (request.providerOptions) {
@@ -4283,7 +4370,7 @@ var GeminiProvider = class {
4283
4370
  });
4284
4371
  }
4285
4372
  if (!res.body) throw new Error("Gemini Interactions stream has no body");
4286
- yield* this.parseInteractionSSEStream(res.body);
4373
+ yield* this.parseInteractionSSEStream(res.body, res.headers);
4287
4374
  }
4288
4375
  buildInteractionRequestBody(messages, options, stream) {
4289
4376
  const model = this.requestModel(options);
@@ -4353,6 +4440,7 @@ var GeminiProvider = class {
4353
4440
  return body;
4354
4441
  }
4355
4442
  assertSafeInteractionOptions(options) {
4443
+ const modelOverride = options.providerOptions?.model;
4356
4444
  const model = this.requestModel(options);
4357
4445
  const fail = (feature) => {
4358
4446
  throw new UnsupportedModelInputError({
@@ -4362,7 +4450,10 @@ var GeminiProvider = class {
4362
4450
  feature
4363
4451
  });
4364
4452
  };
4365
- if (!GEMINI_INTERACTIONS_IMAGE_MODELS.has(model)) fail("image input for this model");
4453
+ if (options.providerOptions && "model" in options.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
4454
+ fail("invalid model providerOptions");
4455
+ }
4456
+ if (model.trim().length === 0) fail("image input for this model");
4366
4457
  const forbidden = [
4367
4458
  "input",
4368
4459
  "contents",
@@ -4438,7 +4529,7 @@ var GeminiProvider = class {
4438
4529
  providerMetadata: json.steps?.length ? { geminiInteractionSteps: json.steps.filter(isGeminiInteractionStep) } : void 0
4439
4530
  };
4440
4531
  }
4441
- async *parseInteractionSSEStream(body) {
4532
+ async *parseInteractionSSEStream(body, responseHeaders) {
4442
4533
  const reader = body.getReader();
4443
4534
  const decoder = new TextDecoder();
4444
4535
  let buffer = "";
@@ -4464,7 +4555,22 @@ var GeminiProvider = class {
4464
4555
  continue;
4465
4556
  }
4466
4557
  if (event.event_type === "error") {
4467
- throw new Error(event.error?.message ?? "Gemini Interactions stream failed");
4558
+ const status = geminiInteractionErrorStatus(event.error?.code);
4559
+ const message = event.error?.message ?? "Gemini Interactions stream failed";
4560
+ if (status !== void 0) {
4561
+ throw buildProviderError({
4562
+ provider: this.name,
4563
+ status,
4564
+ headers: responseHeaders,
4565
+ message
4566
+ });
4567
+ }
4568
+ throw new ProviderError({
4569
+ provider: this.name,
4570
+ status: 0,
4571
+ retryable: false,
4572
+ message
4573
+ });
4468
4574
  }
4469
4575
  if (event.event_type === "step.start" && event.step) {
4470
4576
  const index = event.index;
@@ -5783,7 +5889,6 @@ function normalizeTranscriptionAccounting(usageValue, pricingValue) {
5783
5889
  // src/providers/transcription-utils.ts
5784
5890
  var OPENAI_TRANSCRIPTION_MODEL = "gpt-transcribe";
5785
5891
  var GEMINI_TRANSCRIPTION_MODEL = "gemini-3.5-transcribe";
5786
- var OPENROUTER_TRANSCRIPTION_MODEL = "openai/whisper-1";
5787
5892
  function requireExactTranscriptionModel(provider, model, expected) {
5788
5893
  if (model !== expected) {
5789
5894
  throw new UnsupportedTranscriptionInputError({
@@ -6434,10 +6539,16 @@ var OpenRouterTranscriptionProvider = class {
6434
6539
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
6435
6540
  }
6436
6541
  capabilities(model) {
6437
- return model === OPENROUTER_TRANSCRIPTION_MODEL ? { sources: ["bytes", "base64"] } : void 0;
6542
+ return model.trim().length > 0 ? { sources: ["bytes", "base64"] } : void 0;
6438
6543
  }
6439
6544
  async transcribe(request) {
6440
- requireExactTranscriptionModel(this.name, request.model, OPENROUTER_TRANSCRIPTION_MODEL);
6545
+ if (request.model.trim().length === 0) {
6546
+ throw new UnsupportedTranscriptionInputError({
6547
+ provider: this.name,
6548
+ model: request.model,
6549
+ feature: "this transcription model"
6550
+ });
6551
+ }
6441
6552
  requireNoProviderFile(request.audio, this.name, request.model);
6442
6553
  if (request.audio.type === "provider-file")
6443
6554
  throw new UnsupportedTranscriptionInputError({
@@ -6577,7 +6688,7 @@ var TranscriptionProviderRegistry = class {
6577
6688
  }
6578
6689
  resolve(uri, config = {}) {
6579
6690
  const colon = typeof uri === "string" ? uri.indexOf(":") : -1;
6580
- if (colon <= 0 || colon === uri.length - 1 || uri.indexOf(":", colon + 1) !== -1) {
6691
+ if (colon <= 0 || colon === uri.length - 1) {
6581
6692
  throw new UnsupportedTranscriptionInputError({
6582
6693
  provider: "unknown",
6583
6694
  model: "",