@axlsdk/axl 0.22.0 → 0.22.1

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. OpenRouter passes image input through to the selected model/route, but Axl does not claim every catalog model supports images, tools, or transcription. Build your own by cloning a `ProviderProfile`; see [provider details](../../docs/providers.md#openai-compatible-providers--presets) 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,7 +1424,7 @@ 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
1430
  const effectiveModel = typeof request.providerOptions?.model === "string" ? request.providerOptions.model : request.model;
@@ -1438,13 +1437,12 @@ var OpenAICompatibleProvider = class {
1438
1437
  ...feature ? { feature } : {}
1439
1438
  });
1440
1439
  };
1441
- if (this.name !== "openrouter" || effectiveModel !== OPENROUTER_IMAGE_MODEL) {
1440
+ if (this.name !== "openrouter" || effectiveModel.trim().length === 0) {
1442
1441
  fail(void 0, "image input for this model");
1443
1442
  }
1444
1443
  if (request.providerOptions && "messages" in request.providerOptions) {
1445
1444
  fail(void 0, "raw messages providerOptions");
1446
1445
  }
1447
- if (request.hasTools) fail(void 0, "tools with image input");
1448
1446
  for (const message of request.history) {
1449
1447
  if (!Array.isArray(message.content)) continue;
1450
1448
  if (message.role !== "user") fail(void 0, "rich non-user history");
@@ -1632,7 +1630,7 @@ var OpenAICompatibleProvider = class {
1632
1630
  formatMessage(msg, model) {
1633
1631
  const out = {
1634
1632
  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
1633
+ content: Array.isArray(msg.content) && this.name === "openrouter" ? openRouterImageParts(msg.content, model) : msg.content
1636
1634
  };
1637
1635
  if (msg.name && (this.profile.capabilities?.emitsMessageName ?? true)) out.name = msg.name;
1638
1636
  if (msg.tool_calls) out.tool_calls = msg.tool_calls;
@@ -5783,7 +5781,6 @@ function normalizeTranscriptionAccounting(usageValue, pricingValue) {
5783
5781
  // src/providers/transcription-utils.ts
5784
5782
  var OPENAI_TRANSCRIPTION_MODEL = "gpt-transcribe";
5785
5783
  var GEMINI_TRANSCRIPTION_MODEL = "gemini-3.5-transcribe";
5786
- var OPENROUTER_TRANSCRIPTION_MODEL = "openai/whisper-1";
5787
5784
  function requireExactTranscriptionModel(provider, model, expected) {
5788
5785
  if (model !== expected) {
5789
5786
  throw new UnsupportedTranscriptionInputError({
@@ -6434,10 +6431,16 @@ var OpenRouterTranscriptionProvider = class {
6434
6431
  this.governor = options.rateLimit ? new RateLimiter(options.rateLimit) : void 0;
6435
6432
  }
6436
6433
  capabilities(model) {
6437
- return model === OPENROUTER_TRANSCRIPTION_MODEL ? { sources: ["bytes", "base64"] } : void 0;
6434
+ return model.trim().length > 0 ? { sources: ["bytes", "base64"] } : void 0;
6438
6435
  }
6439
6436
  async transcribe(request) {
6440
- requireExactTranscriptionModel(this.name, request.model, OPENROUTER_TRANSCRIPTION_MODEL);
6437
+ if (request.model.trim().length === 0) {
6438
+ throw new UnsupportedTranscriptionInputError({
6439
+ provider: this.name,
6440
+ model: request.model,
6441
+ feature: "this transcription model"
6442
+ });
6443
+ }
6441
6444
  requireNoProviderFile(request.audio, this.name, request.model);
6442
6445
  if (request.audio.type === "provider-file")
6443
6446
  throw new UnsupportedTranscriptionInputError({
@@ -6577,7 +6580,7 @@ var TranscriptionProviderRegistry = class {
6577
6580
  }
6578
6581
  resolve(uri, config = {}) {
6579
6582
  const colon = typeof uri === "string" ? uri.indexOf(":") : -1;
6580
- if (colon <= 0 || colon === uri.length - 1 || uri.indexOf(":", colon + 1) !== -1) {
6583
+ if (colon <= 0 || colon === uri.length - 1) {
6581
6584
  throw new UnsupportedTranscriptionInputError({
6582
6585
  provider: "unknown",
6583
6586
  model: "",