A Vercel AI SDK provider that routes requests through your Coder deployment's AI Gateway (formerly "AI Bridge"). Use any model your deployment proxies, the same way you'd use OpenRouter or any other provider.
import { generateText } from "ai";
import { createCoder } from "@coder/ai-sdk-provider";
const coder = createCoder({
baseURL: "https://coder.example.com",
apiKey: process.env.CODER_API_TOKEN!,
});
const { text } = await generateText({
model: coder("claude-sonnet-4-6"),
prompt: "What is Coder?",
});Why: in centralized mode (the default), developers authenticate with their Coder token and never handle raw provider keys. AI Gateway authenticates each request against a Coder identity, injects the centrally managed keys for the upstream providers (Anthropic, OpenAI, Bedrock, Copilot, …), and audits usage per user. In bring-your-own-key mode, developers supply their own upstream key instead (see Authentication). The deployment decides which models and providers are available.
Tip
This package is for plain model calls: generateText, streamText, and
generateObject (schema-constrained structured output). For Coder's
server-side agent (multi-step tool loop, built-in tools, MCP servers,
workspace file/shell tools), use @coder/ai-sdk-agent. They
compose: provider for pure text/JSON steps, Agent for tool-driven ones.
pnpm add @coder/ai-sdk-provider ai zodRequirements:
- Node ≥ 22 and
aiv7. - A Coder deployment with AI Gateway enabled: stable since Coder v2.29, GA in v2.30, on by default in v2.34. Requires the AI Governance Add-On.
Coder admins define AI Gateway providers: named routes on the deployment
(/api/v2/aibridge/<name>/v1/…). Each speaks one of two wire protocols,
set by its admin-configured type:
| Wire protocol | Provider types behind it | Default name |
|---|---|---|
| OpenAI-compatible | openai, azure, google, copilot, openai-compat, openrouter, vercel |
openai |
| Anthropic-compatible | anthropic (native Claude), bedrock (Bedrock-hosted Claude) |
anthropic |
Routing is by URL path, not by model id: the provider name in the URL decides which upstream handles the request.
createCoder fronts the default openai / anthropic pair. The bare call
coder(modelId) picks one by heuristic: ids starting with claude or
anthropic go to the Anthropic-protocol provider, everything else to the
OpenAI-protocol one. Explicit accessors override the heuristic, e.g. to reach
Claude through a Copilot-typed provider on the OpenAI protocol:
coder("gpt-4o"); // → `openai` provider
coder("claude-sonnet-4-6"); // → `anthropic` provider (heuristic)
coder.openai("claude-sonnet-4"); // → `openai` provider (e.g. Copilot)
coder.anthropic("claude-opus-4-5"); // → `anthropic` provider (explicit)Model ids pass through unchanged to the upstream provider (no
vendor/model namespacing). Use whatever ids your deployment's providers
accept.
Provider names are admin-chosen and match ^[a-z0-9]+(-[a-z0-9]+)*$. A
deployment may expose, say, an Azure-backed azure-openai next to a
Bedrock-backed anthropic-bedrock. There are two ways to reach them.
Sub-provider accessors. openaiProvider(name) / anthropicProvider(name)
return a full sub-provider bound to that gateway provider, so one createCoder
instance can target any number of providers. Pick the accessor that matches the
provider's wire protocol:
const azure = coder.openaiProvider("azure-openai"); // OpenAI-compatible type
const bedrock = coder.anthropicProvider("anthropic-bedrock"); // Anthropic-compatible type
await generateText({ model: azure("gpt-4o"), prompt: "Hi" });
await generateText({ model: bedrock("claude-sonnet-4-6"), prompt: "Hi" });| Name | Fails with |
|---|---|
| Outside the gateway's grammar | AI SDK InvalidArgumentError at accessor time |
| Well-formed but not configured on deployment | The gateway's 404 at request time |
A name outside the grammar can never be registered, so it fails early.
Re-pointing the defaults. If your deployment just names its one
OpenAI/Anthropic pair differently, override the names once and keep using the
bare call and the openai / anthropic accessors:
const renamed = createCoder({
baseURL: "https://coder.example.com",
apiKey: process.env.CODER_API_TOKEN!,
providers: { openai: "azure-openai", anthropic: "anthropic-bedrock" },
});Ask your Coder admins for provider names. Discovery is admin-only
server-side: GET /api/v2/ai/providers returns 403 for regular users, and
the models endpoint does not attribute models to providers.
coder.textEmbeddingModel(id) and the embedding accessors on coder.openai
throw the AI SDK's NoSuchModelError immediately.
Why embeddings throw instead of sending a request
AI Gateway does not intercept /v1/embeddings, so a request would be rejected
with a 404. Throwing up front avoids emitting it. The accessors stay so they
can light up without a breaking change once the gateway adds an embeddings
route. See coder/ai-sdk#69.
| Mode | Set | Upstream provider key |
|---|---|---|
| Centralized (default) | apiKey: your Coder API token |
Held by AI Gateway, which brokers the call |
| Bring-your-own-key | coderToken: Coder token; apiKey: your upstream key |
Yours, forwarded to the upstream |
Centralized mode is all most apps need:
createCoder({ baseURL: "https://coder.example.com", apiKey: coderToken });BYOK sends coderToken in the X-Coder-AI-Governance-Token header to
authenticate you to the gateway, and forwards apiKey to the upstream:
createCoder({
baseURL: "https://coder.example.com",
coderToken, // authenticates you to AI Gateway
apiKey: upstreamKey, // your own OpenAI/Anthropic key
});| Option | Type | Default | Description |
|---|---|---|---|
baseURL |
string |
— (required) | Your Coder deployment URL, e.g. https://coder.example.com. The AI Gateway path is appended for you. |
apiKey |
string |
— | Coder API token (centralized) or upstream key (BYOK). |
coderToken |
string |
— | Enables BYOK mode; sent in X-Coder-AI-Governance-Token. |
headers |
Record<string,string> |
— | Extra headers merged into every request. |
aiGatewayPath |
string |
/api/v2/aibridge |
Override if your deployment uses a different mount path. Use the canonical /api/v2/ai-gateway with Coder v2.35.0+. |
providers |
{ openai?, anthropic? } |
openai / anthropic |
Re-point the default pair at differently-named providers. |
fetch |
typeof fetch |
global fetch |
Custom fetch (testing / middleware). |
The full reference for security reviewers is in
docs/security.md: data flow, credential isolation,
audit capture, required permissions, and a security FAQ.
Key points:
- Client vs. gateway. What this package puts on the wire is verifiable in
src/provider.ts. Key custody, audit capture, and retention are enforced server-side by your Coder deployment. - One destination. The package only initiates requests to your
baseURL. It never contacts upstream vendors directly and adds no telemetry. - Use HTTPS outside trusted local environments. The client does not
enforce
https://; anhttp://URL sends tokens, keys, and prompts in plaintext. - Redirects are followed by default. A cross-origin redirect would resend
the prompt body and non-
Authorizationheaders (in BYOK mode, includingx-api-keyand the governance token) to the redirect target. Passfetch: (url, init) => fetch(url, { ...init, redirect: "error" })to forbid it. - Coder tokens are not AI-only. A token grants the user's full Coder API permissions. Treat a leak as a Coder account compromise (revoke the token) and prefer short-lived, dedicated tokens for AI workloads.
- Audit. Every request is attributed to the authenticating Coder user. The Gateway stores the last user prompt, tool calls (name and arguments), reasoning content when present, token usage, and metadata. Response text is discarded. Retention defaults to 60 days and is configurable.
Runnable scripts live in examples/; see its
README for setup.
pnpm example:generate # non-streaming generateText
pnpm example:stream # streaming streamText
pnpm example:anthropic # the Anthropic surface (native Claude)Apache-2.0 © Coder Technologies, Inc.