Skip to content

ai-gateway-provider: AiGatewayChatLanguageModel hardcodes supportedUrls = {}, defeating provider URL passthrough #545

@pawaca

Description

@pawaca

Summary

AiGatewayChatLanguageModel in [email protected] (dist/index.mjs:143) hardcodes supportedUrls = {} instead of forwarding the underlying wrapped provider's supportedUrls. This silently disables URL passthrough for every provider wrapped by createAiGateway, causing AI SDK to download every file URL and inline it as base64 in the request body.

For a wrapped Anthropic model serving a real PDF (4.4 MiB), this means:

  • AI SDK sees supportedUrls === {} from the gateway wrapper
  • isUrlSupported({ mediaType: 'application/pdf', supportedUrls: {} })false
  • AI SDK downloads the PDF via download()
  • convertPartToLanguageModelPart replaces URL with bytes
  • Anthropic provider falls into the base64 branch (~5.9 MiB after base64)
  • Final Anthropic request body is ~6 MB inline data per request

The same PDF, when sent direct to Anthropic without the gateway wrapper, goes through as source: { type: 'url', url: '...' } — Anthropic fetches it server-side, request body stays a few KB.

Reproducer

import { createAnthropic } from 'ai-gateway-provider/providers/anthropic'
import { createAiGateway } from 'ai-gateway-provider'

const anthropic = createAnthropic({ apiKey: 'sk-ant-...' })
const gw = createAiGateway({ accountId: '...', gateway: '...', apiKey: '...' })

const direct = anthropic('claude-sonnet-4-6')
const wrapped = gw(direct)

console.log('direct:',  await direct.supportedUrls)
// { 'image/*': [/^https?:\/\/.*$/], 'application/pdf': [/^https?:\/\/.*$/] }

console.log('wrapped:', await wrapped.supportedUrls)
// {}   ← bug

Real-world impact

We hit this in production with two symptoms before tracing both to this bug:

  1. PDF analysis triggered SessionDO (Cloudflare Durable Object) OOM: 128 MB isolate cap exceeded while AI SDK constructed the 6 MB request body around a 4.4 MiB PDF. Affected ~7 specific agents over a week, each in heavy use (~33 MiB VFS, dozens of accumulated sessions).
  2. Large image uploads hit Anthropic's 5 MiB base64 limit: a 4 MB JPEG that should have been URL-passed-through was downloaded by AI SDK, base64'd to 5.6 MB, rejected by Anthropic with messages.N.content.M.image.source.base64: image exceeds 5 MB maximum.

Both are downstream effects of supportedUrls = {}.

Expected behavior

AiGatewayChatLanguageModel.supportedUrls should forward the wrapped provider's supportedUrls, the same way modelId and provider already do via getters.

Existing fix in PR #409

The full rewrite in #409 already implements this correctly:

// packages/ai-gateway-provider/src/index.ts (PR #409 HEAD)
get supportedUrls() {
  return this.innerModel.supportedUrls;       // single-model wrapper
}

get supportedUrls() {
  return this.models[0]!.supportedUrls;        // fallback wrapper
}

PR #409 has been open since 2026-03-22 with no reviews. It's a large rewrite that introduces a new API surface with backward-compat shims — sound work, but in the meantime users wrapped by createAiGateway are paying real costs (network egress, billable token recompute via cache misses, isolate memory pressure, request latency).

Suggested resolution

Two reasonable options:

a) Minimal targeted fix on the current major (3.x): add a getter to the existing AiGatewayChatLanguageModel class in src/index.ts:

 var AiGatewayChatLanguageModel = class {
   get modelId() { ... }
   get provider() { ... }
+  get supportedUrls() {
+    return this.models[0]?.supportedUrls ?? {};
+  }
   constructor(models, config) {
     _defineProperty(this, "specificationVersion", "v3");
     _defineProperty(this, "defaultObjectGenerationMode", "json");
-    _defineProperty(this, "supportedUrls", {});
     _defineProperty(this, "models", void 0);
     ...
   }
 }

This is what we're currently shipping as a pnpm patch — verified to restore URL passthrough end-to-end (PDF source type goes from base64 to url; request body shrinks from 6 MB to a few KB). Three-line diff, zero behavior change for callers that don't supply file URLs.

b) Land PR #409, which already contains the equivalent fix and additional improvements.

Happy to send a PR with just (a) if it would help unblock affected users while #409 is in flight — just let me know.

Environment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions