@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/dist/index.js CHANGED
@@ -1055,13 +1055,12 @@ function unsafeTransportError(surface, remediation, exposedData) {
1055
1055
  }
1056
1056
 
1057
1057
  // src/providers/openai-compatible.ts
1058
- var OPENROUTER_IMAGE_MODEL = "openai/gpt-4o-mini";
1059
1058
  function compatibleImageBase64(source) {
1060
1059
  return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
1061
1060
  "base64"
1062
1061
  );
1063
1062
  }
1064
- function openRouterImageParts(parts) {
1063
+ function openRouterImageParts(parts, model) {
1065
1064
  const content = [];
1066
1065
  for (const part of parts) {
1067
1066
  if (part.type === "text") {
@@ -1072,7 +1071,7 @@ function openRouterImageParts(parts) {
1072
1071
  if (source.type === "provider-file") {
1073
1072
  throw new UnsupportedModelInputError({
1074
1073
  provider: "openrouter",
1075
- model: OPENROUTER_IMAGE_MODEL,
1074
+ model,
1076
1075
  modality: "image",
1077
1076
  source: "provider-file"
1078
1077
  });
@@ -1203,10 +1202,11 @@ function normalizeMessageContent(content) {
1203
1202
  var OpenAICompatibleProvider = class {
1204
1203
  name;
1205
1204
  inputCapabilities(model) {
1206
- return this.name === "openrouter" && model === OPENROUTER_IMAGE_MODEL ? { image: { sources: ["url", "bytes", "base64"] } } : {};
1205
+ return this.name === "openrouter" && model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64"] } } : {};
1207
1206
  }
1208
1207
  validateInput(request) {
1209
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
1208
+ const modelOverride = request.providerOptions?.model;
1209
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
1210
1210
  const fail = (source, feature) => {
1211
1211
  throw new UnsupportedModelInputError({
1212
1212
  provider: this.name,
@@ -1216,13 +1216,15 @@ var OpenAICompatibleProvider = class {
1216
1216
  ...feature ? { feature } : {}
1217
1217
  });
1218
1218
  };
1219
- if (this.name !== "openrouter" || effectiveModel !== OPENROUTER_IMAGE_MODEL) {
1219
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
1220
+ fail(void 0, "invalid model providerOptions");
1221
+ }
1222
+ if (this.name !== "openrouter" || effectiveModel.trim().length === 0) {
1220
1223
  fail(void 0, "image input for this model");
1221
1224
  }
1222
1225
  if (request.providerOptions && "messages" in request.providerOptions) {
1223
1226
  fail(void 0, "raw messages providerOptions");
1224
1227
  }
1225
- if (request.hasTools) fail(void 0, "tools with image input");
1226
1228
  for (const message of request.history) {
1227
1229
  if (!Array.isArray(message.content)) continue;
1228
1230
  if (message.role !== "user") fail(void 0, "rich non-user history");
@@ -1410,7 +1412,7 @@ var OpenAICompatibleProvider = class {
1410
1412
  formatMessage(msg, model) {
1411
1413
  const out = {
1412
1414
  role: this.profile.roleFor ? this.profile.roleFor(msg.role, model) : msg.role,
1413
- content: Array.isArray(msg.content) && this.name === "openrouter" && model === OPENROUTER_IMAGE_MODEL ? openRouterImageParts(msg.content) : msg.content
1415
+ content: Array.isArray(msg.content) && this.name === "openrouter" ? openRouterImageParts(msg.content, model) : msg.content
1414
1416
  };
1415
1417
  if (msg.name && (this.profile.capabilities?.emitsMessageName ?? true)) out.name = msg.name;
1416
1418
  if (msg.tool_calls) out.tool_calls = msg.tool_calls;
@@ -2157,13 +2159,6 @@ var OpenAIProvider = class extends OpenAICompatibleProvider {
2157
2159
  };
2158
2160
 
2159
2161
  // src/providers/openai-responses.ts
2160
- var OPENAI_RESPONSES_IMAGE_MODELS = /* @__PURE__ */ new Set([
2161
- "gpt-4o",
2162
- "gpt-4o-2024-08-06",
2163
- "gpt-4o-2024-11-20",
2164
- "gpt-4o-mini",
2165
- "gpt-4o-mini-2024-07-18"
2166
- ]);
2167
2162
  function base64FromSource(source) {
2168
2163
  return source.type === "base64" ? source.data : Buffer.from(source.data.buffer, source.data.byteOffset, source.data.byteLength).toString(
2169
2164
  "base64"
@@ -2202,10 +2197,11 @@ function responseImageParts(parts) {
2202
2197
  var OpenAIResponsesProvider = class {
2203
2198
  name = "openai-responses";
2204
2199
  inputCapabilities(model) {
2205
- return OPENAI_RESPONSES_IMAGE_MODELS.has(model) ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
2200
+ return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
2206
2201
  }
2207
2202
  validateInput(request) {
2208
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
2203
+ const modelOverride = request.providerOptions?.model;
2204
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
2209
2205
  const fail = (source, feature) => {
2210
2206
  throw new UnsupportedModelInputError({
2211
2207
  provider: this.name,
@@ -2215,7 +2211,10 @@ var OpenAIResponsesProvider = class {
2215
2211
  ...feature ? { feature } : {}
2216
2212
  });
2217
2213
  };
2218
- if (!OPENAI_RESPONSES_IMAGE_MODELS.has(effectiveModel)) {
2214
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
2215
+ fail(void 0, "invalid model providerOptions");
2216
+ }
2217
+ if (effectiveModel.trim().length === 0) {
2219
2218
  fail(void 0, "image input for this model");
2220
2219
  }
2221
2220
  if (request.providerOptions && "input" in request.providerOptions) {
@@ -2343,7 +2342,7 @@ var OpenAIResponsesProvider = class {
2343
2342
  const resolved = resolveThinkingOptions(options);
2344
2343
  const { includeThoughts } = resolved;
2345
2344
  const wireEffort = resolveOpenAIReasoningEffort(effectiveModel, resolved);
2346
- const stripTemp = oSeries || reasoningCapable && wireEffort !== void 0;
2345
+ const stripTemp = oSeries || supportsMaxReasoningEffort(effectiveModel) || reasoningCapable && wireEffort !== void 0;
2347
2346
  const systemMessages = messages.filter((m) => m.role === "system");
2348
2347
  const nonSystemMessages = messages.filter((m) => m.role !== "system");
2349
2348
  const body = {
@@ -2691,7 +2690,6 @@ function anthropicImageBlocks(parts) {
2691
2690
  }
2692
2691
  var ANTHROPIC_API_VERSION = "2023-06-01";
2693
2692
  var ANTHROPIC_FILES_BETA = "files-api-2025-04-14";
2694
- var ANTHROPIC_IMAGE_MODELS = /* @__PURE__ */ new Set(["claude-sonnet-4-5", "claude-opus-4-8"]);
2695
2693
  function hasAnthropicProviderFileImage(messages) {
2696
2694
  return messages.some(
2697
2695
  (message) => Array.isArray(message.content) && message.content.some(
@@ -2810,6 +2808,28 @@ var ANTHROPIC_RATES = {
2810
2808
  function isValidTokenCount(value) {
2811
2809
  return value !== void 0 && Number.isSafeInteger(value) && value >= 0;
2812
2810
  }
2811
+ function anthropicStreamErrorStatus(type) {
2812
+ switch (type) {
2813
+ case "invalid_request_error":
2814
+ return 400;
2815
+ case "authentication_error":
2816
+ return 401;
2817
+ case "permission_error":
2818
+ return 403;
2819
+ case "not_found_error":
2820
+ return 404;
2821
+ case "request_too_large":
2822
+ return 413;
2823
+ case "rate_limit_error":
2824
+ return 429;
2825
+ case "api_error":
2826
+ return 500;
2827
+ case "overloaded_error":
2828
+ return 529;
2829
+ default:
2830
+ return 0;
2831
+ }
2832
+ }
2813
2833
  function estimateAnthropicCost(model, usage, now = /* @__PURE__ */ new Date()) {
2814
2834
  if (!model || !isValidTokenCount(usage.inputTokens) || !isValidTokenCount(usage.outputTokens)) {
2815
2835
  return void 0;
@@ -3059,10 +3079,11 @@ function mergeAnthropicUsage(initial, update) {
3059
3079
  var AnthropicProvider = class {
3060
3080
  name = "anthropic";
3061
3081
  inputCapabilities(model) {
3062
- return ANTHROPIC_IMAGE_MODELS.has(model) ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
3082
+ return model.trim().length > 0 ? { image: { sources: ["url", "bytes", "base64", "provider-file"] } } : {};
3063
3083
  }
3064
3084
  validateInput(request) {
3065
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
3085
+ const modelOverride = request.providerOptions?.model;
3086
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
3066
3087
  const fail = (source, feature) => {
3067
3088
  throw new UnsupportedModelInputError({
3068
3089
  provider: this.name,
@@ -3072,7 +3093,10 @@ var AnthropicProvider = class {
3072
3093
  ...feature ? { feature } : {}
3073
3094
  });
3074
3095
  };
3075
- if (!ANTHROPIC_IMAGE_MODELS.has(effectiveModel)) {
3096
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
3097
+ fail(void 0, "invalid model providerOptions");
3098
+ }
3099
+ if (effectiveModel.trim().length === 0) {
3076
3100
  fail(void 0, "image input for this model");
3077
3101
  }
3078
3102
  if (request.providerOptions && "messages" in request.providerOptions) {
@@ -3197,7 +3221,7 @@ var AnthropicProvider = class {
3197
3221
  if (!res.body) {
3198
3222
  throw new Error("Anthropic stream response has no body");
3199
3223
  }
3200
- yield* this.parseSSEStream(res.body, pricingContext);
3224
+ yield* this.parseSSEStream(res.body, pricingContext, res.headers);
3201
3225
  }
3202
3226
  // ---------------------------------------------------------------------------
3203
3227
  // Internal: request building
@@ -3440,7 +3464,7 @@ ${jsonInstruction}` : jsonInstruction;
3440
3464
  // ---------------------------------------------------------------------------
3441
3465
  // Internal: SSE stream parsing
3442
3466
  // ---------------------------------------------------------------------------
3443
- async *parseSSEStream(body, pricingContext) {
3467
+ async *parseSSEStream(body, pricingContext, responseHeaders) {
3444
3468
  const reader = body.getReader();
3445
3469
  const decoder = new TextDecoder();
3446
3470
  let buffer = "";
@@ -3486,6 +3510,15 @@ ${jsonInstruction}` : jsonInstruction;
3486
3510
  continue;
3487
3511
  }
3488
3512
  switch (event.type) {
3513
+ case "error": {
3514
+ const status = anthropicStreamErrorStatus(event.error?.type);
3515
+ throw buildProviderError({
3516
+ provider: this.name,
3517
+ status,
3518
+ headers: responseHeaders,
3519
+ message: event.error?.message ?? "Anthropic stream failed"
3520
+ });
3521
+ }
3489
3522
  case "content_block_start": {
3490
3523
  const block = event.content_block;
3491
3524
  if (block?.type === "tool_use") {
@@ -3737,7 +3770,6 @@ var GEMINI_PRICING = {
3737
3770
  "gemini-3.5-flash-lite": { input: 3e-7, cached: 3e-8, output: 25e-7 },
3738
3771
  "gemini-3.6-flash": { input: 15e-7, cached: 15e-8, output: 75e-7 }
3739
3772
  };
3740
- var GEMINI_INTERACTIONS_IMAGE_MODELS = /* @__PURE__ */ new Set(["gemini-3.7-flash"]);
3741
3773
  function isValidTokenCount2(value) {
3742
3774
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
3743
3775
  }
@@ -3747,6 +3779,55 @@ function isStandardGeminiRequestTier(value) {
3747
3779
  function isDefinitiveStandardGeminiResponseTier(value) {
3748
3780
  return value === "SERVICE_TIER_UNSPECIFIED" || value === "SERVICE_TIER_STANDARD" || value === "standard";
3749
3781
  }
3782
+ function geminiInteractionErrorStatus(code) {
3783
+ if (typeof code === "number" && Number.isInteger(code) && code >= 100 && code <= 599) {
3784
+ return code;
3785
+ }
3786
+ switch (code) {
3787
+ case "invalid_request":
3788
+ case "invalid_argument":
3789
+ case "parameter_unknown":
3790
+ case "failed_precondition":
3791
+ return 400;
3792
+ case "authentication":
3793
+ case "unauthenticated":
3794
+ return 401;
3795
+ case "permission_denied":
3796
+ return 403;
3797
+ case "not_found":
3798
+ case "model_not_found":
3799
+ return 404;
3800
+ case "request_timeout":
3801
+ return 408;
3802
+ case "conflict":
3803
+ case "already_exists":
3804
+ return 409;
3805
+ case "request_too_large":
3806
+ return 413;
3807
+ case "out_of_range":
3808
+ return 416;
3809
+ case "quota_exceeded":
3810
+ case "resource_exhausted":
3811
+ case "rate_limit_exceeded":
3812
+ return 429;
3813
+ case "cancelled":
3814
+ return 499;
3815
+ case "api_error":
3816
+ case "internal":
3817
+ case "internal_server_error":
3818
+ return 500;
3819
+ case "bad_gateway":
3820
+ return 502;
3821
+ case "unavailable":
3822
+ case "service_unavailable":
3823
+ return 503;
3824
+ case "deadline_exceeded":
3825
+ case "gateway_timeout":
3826
+ return 504;
3827
+ default:
3828
+ return void 0;
3829
+ }
3830
+ }
3750
3831
  function isEligibleGeminiPricing(context, hasDefinitiveStandardResponseTier, hasInvalidResponseTier) {
3751
3832
  return context.eligibleRequest && isStandardGeminiRequestTier(context.serviceTier) && hasDefinitiveStandardResponseTier && !hasInvalidResponseTier;
3752
3833
  }
@@ -3828,7 +3909,9 @@ var GEMINI_3X_MIN_THINKING_LEVEL = /* @__PURE__ */ new Map([
3828
3909
  ["gemini-3.6-flash", "minimal"],
3829
3910
  // L4 live evidence: Interactions gemini-3.7-flash accepts low/medium/high,
3830
3911
  // but rejects minimal. Keep this exact entry isolated from legacy aliases.
3831
- ["gemini-3.7-flash", "low"]
3912
+ ["gemini-3.7-flash", "low"],
3913
+ // Current-model live evidence: gemini-3.8-flash has the same low floor.
3914
+ ["gemini-3.8-flash", "low"]
3832
3915
  ]);
3833
3916
  var GEMINI_MODELS_WITHOUT_PORTABLE_TEMPERATURE = /* @__PURE__ */ new Set([
3834
3917
  "gemini-3.5-flash-lite",
@@ -3856,10 +3939,11 @@ function warnGemini3xEffortNone(model) {
3856
3939
  var GeminiProvider = class {
3857
3940
  name = "google";
3858
3941
  inputCapabilities(model) {
3859
- return GEMINI_INTERACTIONS_IMAGE_MODELS.has(model) ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
3942
+ return model.trim().length > 0 ? { image: { sources: ["bytes", "base64", "provider-file"] } } : {};
3860
3943
  }
3861
3944
  validateInput(request) {
3862
- const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
3945
+ const modelOverride = request.providerOptions?.model;
3946
+ const effectiveModel = typeof modelOverride === "string" ? modelOverride : request.model;
3863
3947
  const fail = (source, feature) => {
3864
3948
  throw new UnsupportedModelInputError({
3865
3949
  provider: this.name,
@@ -3869,7 +3953,10 @@ var GeminiProvider = class {
3869
3953
  ...feature ? { feature } : {}
3870
3954
  });
3871
3955
  };
3872
- if (!GEMINI_INTERACTIONS_IMAGE_MODELS.has(effectiveModel)) {
3956
+ if (request.providerOptions && "model" in request.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
3957
+ fail(void 0, "invalid model providerOptions");
3958
+ }
3959
+ if (effectiveModel.trim().length === 0) {
3873
3960
  fail(void 0, "image input for this model");
3874
3961
  }
3875
3962
  if (request.providerOptions) {
@@ -4061,7 +4148,7 @@ var GeminiProvider = class {
4061
4148
  });
4062
4149
  }
4063
4150
  if (!res.body) throw new Error("Gemini Interactions stream has no body");
4064
- yield* this.parseInteractionSSEStream(res.body);
4151
+ yield* this.parseInteractionSSEStream(res.body, res.headers);
4065
4152
  }
4066
4153
  buildInteractionRequestBody(messages, options, stream) {
4067
4154
  const model = this.requestModel(options);
@@ -4131,6 +4218,7 @@ var GeminiProvider = class {
4131
4218
  return body;
4132
4219
  }
4133
4220
  assertSafeInteractionOptions(options) {
4221
+ const modelOverride = options.providerOptions?.model;
4134
4222
  const model = this.requestModel(options);
4135
4223
  const fail = (feature) => {
4136
4224
  throw new UnsupportedModelInputError({
@@ -4140,7 +4228,10 @@ var GeminiProvider = class {
4140
4228
  feature
4141
4229
  });
4142
4230
  };
4143
- if (!GEMINI_INTERACTIONS_IMAGE_MODELS.has(model)) fail("image input for this model");
4231
+ if (options.providerOptions && "model" in options.providerOptions && (typeof modelOverride !== "string" || modelOverride.trim().length === 0)) {
4232
+ fail("invalid model providerOptions");
4233
+ }
4234
+ if (model.trim().length === 0) fail("image input for this model");
4144
4235
  const forbidden = [
4145
4236
  "input",
4146
4237
  "contents",
@@ -4216,7 +4307,7 @@ var GeminiProvider = class {
4216
4307
  providerMetadata: json.steps?.length ? { geminiInteractionSteps: json.steps.filter(isGeminiInteractionStep) } : void 0
4217
4308
  };
4218
4309
  }
4219
- async *parseInteractionSSEStream(body) {
4310
+ async *parseInteractionSSEStream(body, responseHeaders) {
4220
4311
  const reader = body.getReader();
4221
4312
  const decoder = new TextDecoder();
4222
4313
  let buffer = "";
@@ -4242,7 +4333,22 @@ var GeminiProvider = class {
4242
4333
  continue;
4243
4334
  }
4244
4335
  if (event.event_type === "error") {
4245
- throw new Error(event.error?.message ?? "Gemini Interactions stream failed");
4336
+ const status = geminiInteractionErrorStatus(event.error?.code);
4337
+ const message = event.error?.message ?? "Gemini Interactions stream failed";
4338
+ if (status !== void 0) {
4339
+ throw buildProviderError({
4340
+ provider: this.name,
4341
+ status,
4342
+ headers: responseHeaders,
4343
+ message
4344
+ });
4345
+ }
4346
+ throw new ProviderError({
4347
+ provider: this.name,
4348
+ status: 0,
4349
+ retryable: false,
4350
+ message
4351
+ });
4246
4352
  }
4247
4353
  if (event.event_type === "step.start" && event.step) {
4248
4354
  const index = event.index;
@@ -5561,7 +5667,6 @@ function normalizeTranscriptionAccounting(usageValue, pricingValue) {
5561
5667
  // src/providers/transcription-utils.ts
5562
5668
  var OPENAI_TRANSCRIPTION_MODEL = "gpt-transcribe";
5563
5669
  var GEMINI_TRANSCRIPTION_MODEL = "gemini-3.5-transcribe";
5564
- var OPENROUTER_TRANSCRIPTION_MODEL = "openai/whisper-1";
5565
5670
  function requireExactTranscriptionModel(provider, model, expected) {
5566
5671
  if (model !== expected) {
5567
5672
  throw new UnsupportedTranscriptionInputError({
@@ -6212,10 +6317,16 @@ var OpenRouterTranscriptionProvider = class {
6212
6317
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
6213
6318
  }
6214
6319
  capabilities(model) {
6215
- return model === OPENROUTER_TRANSCRIPTION_MODEL ? { sources: ["bytes", "base64"] } : void 0;
6320
+ return model.trim().length > 0 ? { sources: ["bytes", "base64"] } : void 0;
6216
6321
  }
6217
6322
  async transcribe(request) {
6218
- requireExactTranscriptionModel(this.name, request.model, OPENROUTER_TRANSCRIPTION_MODEL);
6323
+ if (request.model.trim().length === 0) {
6324
+ throw new UnsupportedTranscriptionInputError({
6325
+ provider: this.name,
6326
+ model: request.model,
6327
+ feature: "this transcription model"
6328
+ });
6329
+ }
6219
6330
  requireNoProviderFile(request.audio, this.name, request.model);
6220
6331
  if (request.audio.type === "provider-file")
6221
6332
  throw new UnsupportedTranscriptionInputError({
@@ -6355,7 +6466,7 @@ var TranscriptionProviderRegistry = class {
6355
6466
  }
6356
6467
  resolve(uri, config = {}) {
6357
6468
  const colon = typeof uri === "string" ? uri.indexOf(":") : -1;
6358
- if (colon <= 0 || colon === uri.length - 1 || uri.indexOf(":", colon + 1) !== -1) {
6469
+ if (colon <= 0 || colon === uri.length - 1) {
6359
6470
  throw new UnsupportedTranscriptionInputError({
6360
6471
  provider: "unknown",
6361
6472
  model: "",