@coder/ai-sdk-provider 0.4.14 → 0.4.16

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
@@ -5,7 +5,7 @@
5
5
  [![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](./LICENSE)
6
6
 
7
7
  A **Vercel AI SDK provider that routes requests through your Coder deployment's
8
- [AI Gateway](https://coder.com/docs/ai-coder/ai-gateway)** (formerly "AI Bridge" — the URL path is still `aibridge`). Point it
8
+ [AI Gateway](https://coder.com/docs/ai-coder/ai-gateway)** (formerly "AI Bridge"). Point it
9
9
  at your deployment URL, hand it a Coder API token, and use any model your
10
10
  deployment proxies with the AI SDK's `generateText` / `streamText` — the same way
11
11
  you'd use [OpenRouter](https://ai-sdk.dev/providers/community-providers/openrouter)
@@ -192,9 +192,8 @@ normal provider call:
192
192
 
193
193
  - **URL** — `POST <baseURL>/api/v2/aibridge/<provider>/v1/chat/completions`
194
194
  (OpenAI surface) or `…/v1/messages` (Anthropic surface). `/api/v2/aibridge`
195
- is this package's
196
- default; deployments also serve the post-rename alias `/api/v2/ai-gateway`
197
- (see `aiGatewayPath`).
195
+ is this package's default for compatibility. Use the canonical
196
+ `/api/v2/ai-gateway` path with Coder v2.35.0 or later (see `aiGatewayPath`).
198
197
  - **Auth headers** — per the mode matrix below.
199
198
  - **Body** — standard OpenAI-/Anthropic-format JSON: the model id (passed
200
199
  through unchanged), your full prompt/message content, tool definitions, and
package/dist/index.d.ts CHANGED
@@ -28,8 +28,7 @@ interface CoderProviderSettings {
28
28
  headers?: Record<string, string>;
29
29
  /**
30
30
  * Mount path of AI Gateway on the deployment. Defaults to `/api/v2/aibridge`.
31
- * Exposed because the `aibridge` path segment may change in a future Coder
32
- * release (the feature was renamed "AI Gateway").
31
+ * Set to the canonical `/api/v2/ai-gateway` path with Coder v2.35.0 or later.
33
32
  */
34
33
  aiGatewayPath?: string;
35
34
  /**
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/provider.ts"],"sourcesContent":["import { type AnthropicProvider, createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createOpenAICompatible, type OpenAICompatibleProvider } from \"@ai-sdk/openai-compatible\";\nimport {\n type EmbeddingModelV4,\n InvalidArgumentError,\n type LanguageModelV4,\n NoSuchModelError,\n} from \"@ai-sdk/provider\";\n\n/** Default mount path of AI Gateway on a Coder deployment. */\nconst DEFAULT_AI_GATEWAY_PATH = \"/api/v2/aibridge\";\n/** Default provider path segments (the admin-configured provider names). */\nconst DEFAULT_OPENAI_PROVIDER = \"openai\";\nconst DEFAULT_ANTHROPIC_PROVIDER = \"anthropic\";\n/**\n * AI Gateway's provider-name grammar: lowercase alphanumeric segments\n * separated by single hyphens. Names outside this grammar can never be\n * registered on a deployment, so they are rejected client-side.\n */\nconst PROVIDER_NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;\n/** Header that carries the Coder token to AI Gateway in bring-your-own-key mode. */\nconst CODER_TOKEN_HEADER = \"X-Coder-AI-Governance-Token\";\n\nexport interface CoderProviderSettings {\n /**\n * Base URL of your Coder deployment, e.g. `https://coder.example.com`. Do NOT\n * include the AI Gateway path (`/api/v2/aibridge/...`) — it is appended for you.\n */\n baseURL: string;\n /**\n * The credential sent to AI Gateway.\n *\n * - **Centralized mode (default):** your **Coder API token**. AI Gateway holds\n * the upstream provider keys and brokers the call, so this is all you need.\n * - **BYOK mode** (when {@link CoderProviderSettings.coderToken} is also set):\n * your **upstream provider key**, which AI Gateway forwards to the upstream.\n */\n apiKey?: string;\n /**\n * Enables bring-your-own-key (BYOK) mode. This Coder API token is sent in the\n * `X-Coder-AI-Governance-Token` header to authenticate you to the gateway,\n * while {@link CoderProviderSettings.apiKey} carries your upstream provider key.\n * Leave unset for the default centralized mode.\n */\n coderToken?: string;\n /** Extra headers merged into every request to both surfaces. */\n headers?: Record<string, string>;\n /**\n * Mount path of AI Gateway on the deployment. Defaults to `/api/v2/aibridge`.\n * Exposed because the `aibridge` path segment may change in a future Coder\n * release (the feature was renamed \"AI Gateway\").\n */\n aiGatewayPath?: string;\n /**\n * Override the provider path segments — the *admin-configured provider names*\n * on the deployment (e.g. `anthropic-corp`). Default to `openai` / `anthropic`.\n */\n providers?: {\n openai?: string;\n anthropic?: string;\n };\n /** Custom fetch implementation (useful for testing or middleware). */\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface CoderProvider {\n /** Route a model id to a surface by heuristic (Claude ids → Anthropic surface). */\n (modelId: string): LanguageModelV4;\n /** Route a model id to a surface by heuristic (Claude ids → Anthropic surface). */\n languageModel(modelId: string): LanguageModelV4;\n /**\n * AI Gateway's OpenAI-compatible surface (`/aibridge/openai/v1`). Reaches the\n * OpenAI / Azure / Google / OpenRouter / Vercel / openai-compat and Copilot\n * upstreams. Routing is by URL, so any model id sent here hits this surface.\n */\n openai: OpenAICompatibleProvider;\n /**\n * AI Gateway's Anthropic-compatible surface (`/aibridge/anthropic`). Reaches\n * native Claude and Bedrock-hosted Claude.\n */\n anthropic: AnthropicProvider;\n /** Shorthand for an {@link CoderProvider.openai} chat model. */\n chat(modelId: string): LanguageModelV4;\n /** Shorthand for an {@link CoderProvider.anthropic} messages model. */\n messages(modelId: string): LanguageModelV4;\n /**\n * An OpenAI-compatible sub-provider bound to the *named* gateway provider\n * (`<aiGatewayPath>/<name>/v1`). Use it to reach admin-defined providers\n * beyond the default pair, e.g.\n * `coder.openaiProvider(\"azure-openai\")(\"gpt-4o\")`. Throws the AI SDK's\n * `InvalidArgumentError` when `name` does not match the gateway's\n * provider-name grammar (`^[a-z0-9]+(-[a-z0-9]+)*$`); a well-formed name\n * that is not configured on the deployment fails at request time with the\n * gateway's 404.\n */\n openaiProvider(name: string): OpenAICompatibleProvider;\n /**\n * An Anthropic-compatible sub-provider bound to the *named* gateway\n * provider, e.g. `coder.anthropicProvider(\"anthropic-bedrock\")(\"claude-sonnet-4-6\")`.\n * Same name validation as {@link CoderProvider.openaiProvider}.\n */\n anthropicProvider(name: string): AnthropicProvider;\n /**\n * Text embeddings are not supported: AI Gateway does not yet intercept\n * `/v1/embeddings`, so this always throws {@link NoSuchModelError} instead of\n * emitting a request that the gateway rejects with a 404. Tracked in\n * https://github.com/coder/ai-sdk/issues/69.\n */\n textEmbeddingModel(modelId: string): EmbeddingModelV4;\n}\n\n/**\n * Heuristic for the bare {@link CoderProvider} call: which AI Gateway surface\n * should a model id route to? Claude / Anthropic ids go to the Anthropic\n * surface; everything else to the OpenAI-compatible surface. Use the explicit\n * `.openai(id)` / `.anthropic(id)` accessors to override (e.g. to reach Claude\n * through a Copilot-typed provider on the OpenAI surface).\n */\nexport function isAnthropicModelId(modelId: string): boolean {\n return /^(?:claude|anthropic[./:])/i.test(modelId);\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Fail fast at accessor time: AI Gateway intercepts only\n * `/v1/chat/completions`, `/v1/responses`, and `/v1/messages`, so an\n * embeddings request would always die with a 404 at request time.\n */\nfunction unsupportedEmbeddingModel(modelId: string): EmbeddingModelV4 {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n message:\n `Coder AI Gateway does not yet intercept /v1/embeddings, so the ` +\n `embedding model \"${modelId}\" cannot be reached through it. ` +\n `See https://github.com/coder/ai-sdk/issues/69 for status.`,\n });\n}\n\n/**\n * Fail fast at accessor time: a name outside the gateway's provider-name\n * grammar can never be registered on a deployment, so a request to it would\n * always die with a confusing 404. Same philosophy as the embeddings guard\n * (https://github.com/coder/ai-sdk/issues/69).\n */\nfunction assertValidProviderName(name: string): void {\n if (!PROVIDER_NAME_PATTERN.test(name)) {\n throw new InvalidArgumentError({\n argument: \"name\",\n message:\n `Invalid AI Gateway provider name \"${name}\": provider names are ` +\n `lowercase alphanumeric segments separated by single hyphens ` +\n `(${PROVIDER_NAME_PATTERN}). Ask your Coder admins for the provider ` +\n `names configured on your deployment.`,\n });\n }\n}\n\n/**\n * Create a {@link CoderProvider} that routes Vercel AI SDK calls through a Coder\n * deployment's AI Gateway (formerly \"AI Bridge\"). AI Gateway exposes two\n * provider-namespaced surfaces; this provider fronts both and selects between\n * them per model.\n *\n * @example\n * ```ts\n * import { generateText } from \"ai\";\n * import { createCoder } from \"@coder/ai-sdk-provider\";\n *\n * const coder = createCoder({\n * baseURL: \"https://coder.example.com\",\n * apiKey: process.env.CODER_API_TOKEN!,\n * });\n *\n * await generateText({ model: coder(\"gpt-4o\"), prompt: \"Hi\" }); // OpenAI surface\n * await generateText({ model: coder(\"claude-sonnet-4-6\"), prompt: \"Hi\" }); // Anthropic surface\n * ```\n */\nexport function createCoder(settings: CoderProviderSettings): CoderProvider {\n if (!settings.baseURL) {\n throw new Error(\n \"createCoder: `baseURL` is required (your Coder deployment URL, e.g. https://coder.example.com).\",\n );\n }\n\n const deployment = trimTrailingSlash(settings.baseURL);\n const gatewayPath = settings.aiGatewayPath ?? DEFAULT_AI_GATEWAY_PATH;\n\n // BYOK mode: the Coder token authenticates via a dedicated header and `apiKey`\n // carries the upstream key. Centralized mode (default): `apiKey` is the Coder\n // token itself, sent in the standard provider auth header.\n const byok = settings.coderToken !== undefined;\n const headers: Record<string, string> = {\n ...(byok ? { [CODER_TOKEN_HEADER]: settings.coderToken as string } : {}),\n ...settings.headers,\n };\n\n // Both sub-provider kinds append their route to a baseURL that INCLUDES `/v1`:\n // openai-compatible POSTs `${baseURL}/chat/completions`, and @ai-sdk/anthropic\n // POSTs `${baseURL}/messages`. AI Gateway's intercepted routes are\n // `/aibridge/<name>/v1/chat/completions` and `/aibridge/<name>/v1/messages`.\n const providerBaseURL = (name: string): string => `${deployment}${gatewayPath}/${name}/v1`;\n\n const openaiProvider = (name: string): OpenAICompatibleProvider => {\n assertValidProviderName(name);\n const provider = createOpenAICompatible({\n name: `coder.${name}`,\n baseURL: providerBaseURL(name),\n apiKey: settings.apiKey, // → `Authorization: Bearer <apiKey>`\n headers,\n fetch: settings.fetch,\n includeUsage: true,\n });\n // Sub-providers are public, so their embedding accessors must fail fast\n // too — otherwise they bypass the top-level guard and hit the gateway 404.\n provider.embeddingModel = unsupportedEmbeddingModel;\n provider.textEmbeddingModel = unsupportedEmbeddingModel;\n return provider;\n };\n\n const anthropicProvider = (name: string): AnthropicProvider => {\n assertValidProviderName(name);\n return createAnthropic({\n name: `coder.${name}`,\n baseURL: providerBaseURL(name),\n // Centralized: send the Coder token via `Authorization: Bearer` (the\n // documented path). BYOK: send the upstream key via `x-api-key`.\n ...(byok ? { apiKey: settings.apiKey } : { authToken: settings.apiKey }),\n headers,\n fetch: settings.fetch,\n });\n };\n\n // The default surfaces are ordinary named sub-providers — one code path.\n const openai = openaiProvider(settings.providers?.openai ?? DEFAULT_OPENAI_PROVIDER);\n const anthropic = anthropicProvider(settings.providers?.anthropic ?? DEFAULT_ANTHROPIC_PROVIDER);\n\n const languageModel = (modelId: string): LanguageModelV4 =>\n isAnthropicModelId(modelId) ? anthropic(modelId) : openai(modelId);\n\n return Object.assign(languageModel, {\n languageModel,\n openai,\n anthropic,\n chat: (modelId: string): LanguageModelV4 => openai(modelId),\n messages: (modelId: string): LanguageModelV4 => anthropic(modelId),\n openaiProvider,\n anthropicProvider,\n textEmbeddingModel: unsupportedEmbeddingModel,\n });\n}\n\n/** Convenience alias mirroring other AI SDK providers' `createX` naming. */\nexport const coder = createCoder;\n"],"mappings":";AAAA,SAAiC,uBAAuB;AACxD,SAAS,8BAA6D;AACtE;AAAA,EAEE;AAAA,EAEA;AAAA,OACK;AAGP,IAAM,0BAA0B;AAEhC,IAAM,0BAA0B;AAChC,IAAM,6BAA6B;AAMnC,IAAM,wBAAwB;AAE9B,IAAM,qBAAqB;AAiGpB,SAAS,mBAAmB,SAA0B;AAC3D,SAAO,8BAA8B,KAAK,OAAO;AACnD;AAEA,SAAS,kBAAkB,KAAqB;AAC9C,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAOA,SAAS,0BAA0B,SAAmC;AACpE,QAAM,IAAI,iBAAiB;AAAA,IACzB;AAAA,IACA,WAAW;AAAA,IACX,SACE,mFACoB,OAAO;AAAA,EAE/B,CAAC;AACH;AAQA,SAAS,wBAAwB,MAAoB;AACnD,MAAI,CAAC,sBAAsB,KAAK,IAAI,GAAG;AACrC,UAAM,IAAI,qBAAqB;AAAA,MAC7B,UAAU;AAAA,MACV,SACE,qCAAqC,IAAI,sFAErC,qBAAqB;AAAA,IAE7B,CAAC;AAAA,EACH;AACF;AAsBO,SAAS,YAAY,UAAgD;AAC1E,MAAI,CAAC,SAAS,SAAS;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,kBAAkB,SAAS,OAAO;AACrD,QAAM,cAAc,SAAS,iBAAiB;AAK9C,QAAM,OAAO,SAAS,eAAe;AACrC,QAAM,UAAkC;AAAA,IACtC,GAAI,OAAO,EAAE,CAAC,kBAAkB,GAAG,SAAS,WAAqB,IAAI,CAAC;AAAA,IACtE,GAAG,SAAS;AAAA,EACd;AAMA,QAAM,kBAAkB,CAAC,SAAyB,GAAG,UAAU,GAAG,WAAW,IAAI,IAAI;AAErF,QAAM,iBAAiB,CAAC,SAA2C;AACjE,4BAAwB,IAAI;AAC5B,UAAM,WAAW,uBAAuB;AAAA,MACtC,MAAM,SAAS,IAAI;AAAA,MACnB,SAAS,gBAAgB,IAAI;AAAA,MAC7B,QAAQ,SAAS;AAAA;AAAA,MACjB;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,cAAc;AAAA,IAChB,CAAC;AAGD,aAAS,iBAAiB;AAC1B,aAAS,qBAAqB;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,CAAC,SAAoC;AAC7D,4BAAwB,IAAI;AAC5B,WAAO,gBAAgB;AAAA,MACrB,MAAM,SAAS,IAAI;AAAA,MACnB,SAAS,gBAAgB,IAAI;AAAA;AAAA;AAAA,MAG7B,GAAI,OAAO,EAAE,QAAQ,SAAS,OAAO,IAAI,EAAE,WAAW,SAAS,OAAO;AAAA,MACtE;AAAA,MACA,OAAO,SAAS;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,QAAM,SAAS,eAAe,SAAS,WAAW,UAAU,uBAAuB;AACnF,QAAM,YAAY,kBAAkB,SAAS,WAAW,aAAa,0BAA0B;AAE/F,QAAM,gBAAgB,CAAC,YACrB,mBAAmB,OAAO,IAAI,UAAU,OAAO,IAAI,OAAO,OAAO;AAEnE,SAAO,OAAO,OAAO,eAAe;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,CAAC,YAAqC,OAAO,OAAO;AAAA,IAC1D,UAAU,CAAC,YAAqC,UAAU,OAAO;AAAA,IACjE;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,EACtB,CAAC;AACH;AAGO,IAAM,QAAQ;","names":[]}
1
+ {"version":3,"sources":["../src/provider.ts"],"sourcesContent":["import { type AnthropicProvider, createAnthropic } from \"@ai-sdk/anthropic\";\nimport { createOpenAICompatible, type OpenAICompatibleProvider } from \"@ai-sdk/openai-compatible\";\nimport {\n type EmbeddingModelV4,\n InvalidArgumentError,\n type LanguageModelV4,\n NoSuchModelError,\n} from \"@ai-sdk/provider\";\n\n/** Default mount path of AI Gateway on a Coder deployment. */\nconst DEFAULT_AI_GATEWAY_PATH = \"/api/v2/aibridge\";\n/** Default provider path segments (the admin-configured provider names). */\nconst DEFAULT_OPENAI_PROVIDER = \"openai\";\nconst DEFAULT_ANTHROPIC_PROVIDER = \"anthropic\";\n/**\n * AI Gateway's provider-name grammar: lowercase alphanumeric segments\n * separated by single hyphens. Names outside this grammar can never be\n * registered on a deployment, so they are rejected client-side.\n */\nconst PROVIDER_NAME_PATTERN = /^[a-z0-9]+(-[a-z0-9]+)*$/;\n/** Header that carries the Coder token to AI Gateway in bring-your-own-key mode. */\nconst CODER_TOKEN_HEADER = \"X-Coder-AI-Governance-Token\";\n\nexport interface CoderProviderSettings {\n /**\n * Base URL of your Coder deployment, e.g. `https://coder.example.com`. Do NOT\n * include the AI Gateway path (`/api/v2/aibridge/...`) — it is appended for you.\n */\n baseURL: string;\n /**\n * The credential sent to AI Gateway.\n *\n * - **Centralized mode (default):** your **Coder API token**. AI Gateway holds\n * the upstream provider keys and brokers the call, so this is all you need.\n * - **BYOK mode** (when {@link CoderProviderSettings.coderToken} is also set):\n * your **upstream provider key**, which AI Gateway forwards to the upstream.\n */\n apiKey?: string;\n /**\n * Enables bring-your-own-key (BYOK) mode. This Coder API token is sent in the\n * `X-Coder-AI-Governance-Token` header to authenticate you to the gateway,\n * while {@link CoderProviderSettings.apiKey} carries your upstream provider key.\n * Leave unset for the default centralized mode.\n */\n coderToken?: string;\n /** Extra headers merged into every request to both surfaces. */\n headers?: Record<string, string>;\n /**\n * Mount path of AI Gateway on the deployment. Defaults to `/api/v2/aibridge`.\n * Set to the canonical `/api/v2/ai-gateway` path with Coder v2.35.0 or later.\n */\n aiGatewayPath?: string;\n /**\n * Override the provider path segments — the *admin-configured provider names*\n * on the deployment (e.g. `anthropic-corp`). Default to `openai` / `anthropic`.\n */\n providers?: {\n openai?: string;\n anthropic?: string;\n };\n /** Custom fetch implementation (useful for testing or middleware). */\n fetch?: typeof globalThis.fetch;\n}\n\nexport interface CoderProvider {\n /** Route a model id to a surface by heuristic (Claude ids → Anthropic surface). */\n (modelId: string): LanguageModelV4;\n /** Route a model id to a surface by heuristic (Claude ids → Anthropic surface). */\n languageModel(modelId: string): LanguageModelV4;\n /**\n * AI Gateway's OpenAI-compatible surface (`/aibridge/openai/v1`). Reaches the\n * OpenAI / Azure / Google / OpenRouter / Vercel / openai-compat and Copilot\n * upstreams. Routing is by URL, so any model id sent here hits this surface.\n */\n openai: OpenAICompatibleProvider;\n /**\n * AI Gateway's Anthropic-compatible surface (`/aibridge/anthropic`). Reaches\n * native Claude and Bedrock-hosted Claude.\n */\n anthropic: AnthropicProvider;\n /** Shorthand for an {@link CoderProvider.openai} chat model. */\n chat(modelId: string): LanguageModelV4;\n /** Shorthand for an {@link CoderProvider.anthropic} messages model. */\n messages(modelId: string): LanguageModelV4;\n /**\n * An OpenAI-compatible sub-provider bound to the *named* gateway provider\n * (`<aiGatewayPath>/<name>/v1`). Use it to reach admin-defined providers\n * beyond the default pair, e.g.\n * `coder.openaiProvider(\"azure-openai\")(\"gpt-4o\")`. Throws the AI SDK's\n * `InvalidArgumentError` when `name` does not match the gateway's\n * provider-name grammar (`^[a-z0-9]+(-[a-z0-9]+)*$`); a well-formed name\n * that is not configured on the deployment fails at request time with the\n * gateway's 404.\n */\n openaiProvider(name: string): OpenAICompatibleProvider;\n /**\n * An Anthropic-compatible sub-provider bound to the *named* gateway\n * provider, e.g. `coder.anthropicProvider(\"anthropic-bedrock\")(\"claude-sonnet-4-6\")`.\n * Same name validation as {@link CoderProvider.openaiProvider}.\n */\n anthropicProvider(name: string): AnthropicProvider;\n /**\n * Text embeddings are not supported: AI Gateway does not yet intercept\n * `/v1/embeddings`, so this always throws {@link NoSuchModelError} instead of\n * emitting a request that the gateway rejects with a 404. Tracked in\n * https://github.com/coder/ai-sdk/issues/69.\n */\n textEmbeddingModel(modelId: string): EmbeddingModelV4;\n}\n\n/**\n * Heuristic for the bare {@link CoderProvider} call: which AI Gateway surface\n * should a model id route to? Claude / Anthropic ids go to the Anthropic\n * surface; everything else to the OpenAI-compatible surface. Use the explicit\n * `.openai(id)` / `.anthropic(id)` accessors to override (e.g. to reach Claude\n * through a Copilot-typed provider on the OpenAI surface).\n */\nexport function isAnthropicModelId(modelId: string): boolean {\n return /^(?:claude|anthropic[./:])/i.test(modelId);\n}\n\nfunction trimTrailingSlash(url: string): string {\n return url.replace(/\\/+$/, \"\");\n}\n\n/**\n * Fail fast at accessor time: AI Gateway intercepts only\n * `/v1/chat/completions`, `/v1/responses`, and `/v1/messages`, so an\n * embeddings request would always die with a 404 at request time.\n */\nfunction unsupportedEmbeddingModel(modelId: string): EmbeddingModelV4 {\n throw new NoSuchModelError({\n modelId,\n modelType: \"embeddingModel\",\n message:\n `Coder AI Gateway does not yet intercept /v1/embeddings, so the ` +\n `embedding model \"${modelId}\" cannot be reached through it. ` +\n `See https://github.com/coder/ai-sdk/issues/69 for status.`,\n });\n}\n\n/**\n * Fail fast at accessor time: a name outside the gateway's provider-name\n * grammar can never be registered on a deployment, so a request to it would\n * always die with a confusing 404. Same philosophy as the embeddings guard\n * (https://github.com/coder/ai-sdk/issues/69).\n */\nfunction assertValidProviderName(name: string): void {\n if (!PROVIDER_NAME_PATTERN.test(name)) {\n throw new InvalidArgumentError({\n argument: \"name\",\n message:\n `Invalid AI Gateway provider name \"${name}\": provider names are ` +\n `lowercase alphanumeric segments separated by single hyphens ` +\n `(${PROVIDER_NAME_PATTERN}). Ask your Coder admins for the provider ` +\n `names configured on your deployment.`,\n });\n }\n}\n\n/**\n * Create a {@link CoderProvider} that routes Vercel AI SDK calls through a Coder\n * deployment's AI Gateway (formerly \"AI Bridge\"). AI Gateway exposes two\n * provider-namespaced surfaces; this provider fronts both and selects between\n * them per model.\n *\n * @example\n * ```ts\n * import { generateText } from \"ai\";\n * import { createCoder } from \"@coder/ai-sdk-provider\";\n *\n * const coder = createCoder({\n * baseURL: \"https://coder.example.com\",\n * apiKey: process.env.CODER_API_TOKEN!,\n * });\n *\n * await generateText({ model: coder(\"gpt-4o\"), prompt: \"Hi\" }); // OpenAI surface\n * await generateText({ model: coder(\"claude-sonnet-4-6\"), prompt: \"Hi\" }); // Anthropic surface\n * ```\n */\nexport function createCoder(settings: CoderProviderSettings): CoderProvider {\n if (!settings.baseURL) {\n throw new Error(\n \"createCoder: `baseURL` is required (your Coder deployment URL, e.g. https://coder.example.com).\",\n );\n }\n\n const deployment = trimTrailingSlash(settings.baseURL);\n const gatewayPath = settings.aiGatewayPath ?? DEFAULT_AI_GATEWAY_PATH;\n\n // BYOK mode: the Coder token authenticates via a dedicated header and `apiKey`\n // carries the upstream key. Centralized mode (default): `apiKey` is the Coder\n // token itself, sent in the standard provider auth header.\n const byok = settings.coderToken !== undefined;\n const headers: Record<string, string> = {\n ...(byok ? { [CODER_TOKEN_HEADER]: settings.coderToken as string } : {}),\n ...settings.headers,\n };\n\n // Both sub-provider kinds append their route to a baseURL that INCLUDES `/v1`:\n // openai-compatible POSTs `${baseURL}/chat/completions`, and @ai-sdk/anthropic\n // POSTs `${baseURL}/messages`. AI Gateway's intercepted routes are\n // `/aibridge/<name>/v1/chat/completions` and `/aibridge/<name>/v1/messages`.\n const providerBaseURL = (name: string): string => `${deployment}${gatewayPath}/${name}/v1`;\n\n const openaiProvider = (name: string): OpenAICompatibleProvider => {\n assertValidProviderName(name);\n const provider = createOpenAICompatible({\n name: `coder.${name}`,\n baseURL: providerBaseURL(name),\n apiKey: settings.apiKey, // → `Authorization: Bearer <apiKey>`\n headers,\n fetch: settings.fetch,\n includeUsage: true,\n });\n // Sub-providers are public, so their embedding accessors must fail fast\n // too — otherwise they bypass the top-level guard and hit the gateway 404.\n provider.embeddingModel = unsupportedEmbeddingModel;\n provider.textEmbeddingModel = unsupportedEmbeddingModel;\n return provider;\n };\n\n const anthropicProvider = (name: string): AnthropicProvider => {\n assertValidProviderName(name);\n return createAnthropic({\n name: `coder.${name}`,\n baseURL: providerBaseURL(name),\n // Centralized: send the Coder token via `Authorization: Bearer` (the\n // documented path). BYOK: send the upstream key via `x-api-key`.\n ...(byok ? { apiKey: settings.apiKey } : { authToken: settings.apiKey }),\n headers,\n fetch: settings.fetch,\n });\n };\n\n // The default surfaces are ordinary named sub-providers — one code path.\n const openai = openaiProvider(settings.providers?.openai ?? DEFAULT_OPENAI_PROVIDER);\n const anthropic = anthropicProvider(settings.providers?.anthropic ?? DEFAULT_ANTHROPIC_PROVIDER);\n\n const languageModel = (modelId: string): LanguageModelV4 =>\n isAnthropicModelId(modelId) ? anthropic(modelId) : openai(modelId);\n\n return Object.assign(languageModel, {\n languageModel,\n openai,\n anthropic,\n chat: (modelId: string): LanguageModelV4 => openai(modelId),\n messages: (modelId: string): LanguageModelV4 => anthropic(modelId),\n openaiProvider,\n anthropicProvider,\n textEmbeddingModel: unsupportedEmbeddingModel,\n });\n}\n\n/** Convenience alias mirroring other AI SDK providers' `createX` naming. */\nexport const coder = createCoder;\n"],"mappings":";AAAA,SAAiC,uBAAuB;AACxD,SAAS,8BAA6D;AACtE;AAAA,EAEE;AAAA,EAEA;AAAA,OACK;AAGP,IAAM,0BAA0B;AAEhC,IAAM,0BAA0B;AAChC,IAAM,6BAA6B;AAMnC,IAAM,wBAAwB;AAE9B,IAAM,qBAAqB;AAgGpB,SAAS,mBAAmB,SAA0B;AAC3D,SAAO,8BAA8B,KAAK,OAAO;AACnD;AAEA,SAAS,kBAAkB,KAAqB;AAC9C,SAAO,IAAI,QAAQ,QAAQ,EAAE;AAC/B;AAOA,SAAS,0BAA0B,SAAmC;AACpE,QAAM,IAAI,iBAAiB;AAAA,IACzB;AAAA,IACA,WAAW;AAAA,IACX,SACE,mFACoB,OAAO;AAAA,EAE/B,CAAC;AACH;AAQA,SAAS,wBAAwB,MAAoB;AACnD,MAAI,CAAC,sBAAsB,KAAK,IAAI,GAAG;AACrC,UAAM,IAAI,qBAAqB;AAAA,MAC7B,UAAU;AAAA,MACV,SACE,qCAAqC,IAAI,sFAErC,qBAAqB;AAAA,IAE7B,CAAC;AAAA,EACH;AACF;AAsBO,SAAS,YAAY,UAAgD;AAC1E,MAAI,CAAC,SAAS,SAAS;AACrB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,QAAM,aAAa,kBAAkB,SAAS,OAAO;AACrD,QAAM,cAAc,SAAS,iBAAiB;AAK9C,QAAM,OAAO,SAAS,eAAe;AACrC,QAAM,UAAkC;AAAA,IACtC,GAAI,OAAO,EAAE,CAAC,kBAAkB,GAAG,SAAS,WAAqB,IAAI,CAAC;AAAA,IACtE,GAAG,SAAS;AAAA,EACd;AAMA,QAAM,kBAAkB,CAAC,SAAyB,GAAG,UAAU,GAAG,WAAW,IAAI,IAAI;AAErF,QAAM,iBAAiB,CAAC,SAA2C;AACjE,4BAAwB,IAAI;AAC5B,UAAM,WAAW,uBAAuB;AAAA,MACtC,MAAM,SAAS,IAAI;AAAA,MACnB,SAAS,gBAAgB,IAAI;AAAA,MAC7B,QAAQ,SAAS;AAAA;AAAA,MACjB;AAAA,MACA,OAAO,SAAS;AAAA,MAChB,cAAc;AAAA,IAChB,CAAC;AAGD,aAAS,iBAAiB;AAC1B,aAAS,qBAAqB;AAC9B,WAAO;AAAA,EACT;AAEA,QAAM,oBAAoB,CAAC,SAAoC;AAC7D,4BAAwB,IAAI;AAC5B,WAAO,gBAAgB;AAAA,MACrB,MAAM,SAAS,IAAI;AAAA,MACnB,SAAS,gBAAgB,IAAI;AAAA;AAAA;AAAA,MAG7B,GAAI,OAAO,EAAE,QAAQ,SAAS,OAAO,IAAI,EAAE,WAAW,SAAS,OAAO;AAAA,MACtE;AAAA,MACA,OAAO,SAAS;AAAA,IAClB,CAAC;AAAA,EACH;AAGA,QAAM,SAAS,eAAe,SAAS,WAAW,UAAU,uBAAuB;AACnF,QAAM,YAAY,kBAAkB,SAAS,WAAW,aAAa,0BAA0B;AAE/F,QAAM,gBAAgB,CAAC,YACrB,mBAAmB,OAAO,IAAI,UAAU,OAAO,IAAI,OAAO,OAAO;AAEnE,SAAO,OAAO,OAAO,eAAe;AAAA,IAClC;AAAA,IACA;AAAA,IACA;AAAA,IACA,MAAM,CAAC,YAAqC,OAAO,OAAO;AAAA,IAC1D,UAAU,CAAC,YAAqC,UAAU,OAAO;AAAA,IACjE;AAAA,IACA;AAAA,IACA,oBAAoB;AAAA,EACtB,CAAC;AACH;AAGO,IAAM,QAAQ;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coder/ai-sdk-provider",
3
- "version": "0.4.14",
3
+ "version": "0.4.16",
4
4
  "description": "Vercel AI SDK provider for Coder AI Gateway. Point the AI SDK at your Coder deployment with a Coder API token and use any model your deployment proxies — across AI Gateway's OpenAI- and Anthropic-compatible surfaces.",
5
5
  "keywords": [
6
6
  "ai",
@@ -47,21 +47,21 @@
47
47
  "provenance": true
48
48
  },
49
49
  "dependencies": {
50
- "@ai-sdk/anthropic": "^4.0.53",
51
- "@ai-sdk/openai-compatible": "^3.0.48",
52
- "@ai-sdk/provider": "4.0.14"
50
+ "@ai-sdk/anthropic": "^4.0.54",
51
+ "@ai-sdk/openai-compatible": "^3.0.49",
52
+ "@ai-sdk/provider": "4.0.15"
53
53
  },
54
54
  "devDependencies": {
55
55
  "@arethetypeswrong/cli": "^0.18.5",
56
- "@types/node": "^26.5.1",
57
- "@vitest/coverage-v8": "^5.0.0",
58
- "ai": "^7.0.99",
56
+ "@types/node": "^26.6.0",
57
+ "@vitest/coverage-v8": "^5.0.1",
58
+ "ai": "^7.0.102",
59
59
  "publint": "^0.3.24",
60
60
  "tsup": "^8.5.1",
61
61
  "tsx": "^4.23.13",
62
62
  "typescript": "^6.0.3",
63
- "vitest": "^5.0.0",
64
- "zod": "4.6.4"
63
+ "vitest": "^5.0.1",
64
+ "zod": "4.6.5"
65
65
  },
66
66
  "peerDependencies": {
67
67
  "ai": "^7.0.0",