Model or dataset
OpenRouterTeam/ai-sdk-provider avatar
OpenRouterTeam/ai-sdk-provider

ai-sdk-provider: OpenRouter models inside the Vercel AI SDK

The OpenRouter provider for the Vercel AI SDK contains support for hundreds of models through the OpenRouter chat and completion APIs.

690 stars175 forksTypeScriptApache-2.0

At a glance

What is it?
@openrouter/ai-sdk-provider is the adapter that lets the Vercel AI SDK talk to OpenRouter, exposing over 300 chat and completion models plus embedding models through the same factory calls. It also carries an evaluation model for the OpenRouter Decisions API, whose alpha status and rounding rules shape what the SDK can promise you.
Who is it for?
ai-sdk-provider fits a team already using the AI SDK that wants one interface over many hosted models without writing a provider per vendor, and it does not fit a project that needs a stable evaluation contract, since the Decisions API behind the evaluation model is still in alpha and its shapes may change.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One factory, three hundred models behind one call

The package is the OpenRouter provider for the Vercel AI SDK, and it gives access to over 300 large language models through the OpenRouter chat and completion APIs. The integration surface is deliberately small. You import a default provider instance named openrouter, and you call it with a model identifier.

ts
import { openrouter } from '@openrouter/ai-sdk-provider';

The identifier is the OpenRouter model id, which carries the upstream vendor as a prefix, so a single string selects a specific model on a specific provider.

ts
import { openrouter } from '@openrouter/ai-sdk-provider';
import { generateText } from 'ai';

const { text } = await generateText({
  model: openrouter('openai/gpt-4o'),
  prompt: 'Write a vegetarian lasagna recipe for 4 people.',
});

The point for an adopter is that the model is a runtime argument rather than a build time choice. Swapping one hosted model for another is a string change in one place, and a codebase can even select per call. What the provider does not do is abstract the differences between those models. Capabilities such as tool calling, structured output and token limits vary by model, and the provider cannot smooth that over.

That last point is where the README's own caveat bites, and it is worth reading twice. The list of supported models is described as not definitive, since it changes constantly as models are added and deprecated, and the tool-supported model list is linked separately, with the note that this list may contain models that are not compatible with the AI SDK. So a model that OpenRouter serves is not the same thing as a model this provider can drive, and the set of both keeps moving.

Release lines are pinned to an AI SDK major version

The install instructions are split by SDK major, and picking the wrong one is the most common way to get a broken setup.

bash
npm install @openrouter/ai-sdk-provider

That is the current line, and the README states its requirements plainly: this release line supports ai@^7.0.0, requires Node.js 22 or newer, and is ESM-only. The ESM-only part has teeth in a CommonJS codebase, since there is no require entry in the package exports, only import and default conditions pointing at the ESM build.

The older lines are pinned to an exact version, because the provider major tracks the SDK major.

bash
npm install @openrouter/[email protected]

That version is the legacy line for AI SDK v6, and there is an earlier one still for AI SDK v5 at 1.5.4.

So there are three supported shapes in the documentation: the current release against ai v7, the 2.9.1 line against v6, and the 1.5.4 line against v5. The README labels the last two as legacy, which tells you the maintenance story, and the fact that the legacy pins are exact versions rather than ranges tells you the provider does not promise to work across SDK minors.

For a team deciding between upgrading the SDK and staying on the old provider line, the honest answer from this README is that the provider follows the SDK, and the two have to move together.

Embeddings come from a separate factory call

Embedding models are not reached through the same call as chat models. The provider exposes a textEmbeddingModel factory for them, and the AI SDK's embed function consumes it.

ts
import { embed } from 'ai';
import { openrouter } from '@openrouter/ai-sdk-provider';

const { embedding } = await embed({
  model: openrouter.textEmbeddingModel('openai/text-embedding-3-small'),
  value: 'sunny day at the beach',
});

console.log(embedding); // Array of numbers representing the embedding

Batches go through embedMany, with the same factory and an array of values.

ts
import { embedMany } from 'ai';
import { openrouter } from '@openrouter/ai-sdk-provider';

const { embeddings } = await embedMany({
  model: openrouter.textEmbeddingModel('openai/text-embedding-3-small'),
  values: [
    'sunny day at the beach',
    'rainy day in the city',
    'snowy mountain peak',
  ],
});

console.log(embeddings); // Array of embedding arrays

The named embedding models in the README are openai/text-embedding-3-small, openai/text-embedding-3-large and openai/text-embedding-ada-002, with more available through the OpenRouter models page filtered by the embeddings output modality.

The dimension question is the one to check before you build a vector store against this. The provider hands back the array the model produced, and the README does not document dimension counts, normalisation or pooling, so the shape of the vector is a property of the model you pick rather than of this package. If you already have an index with stored vectors, changing the embedding model is a re-indexing job rather than a config change.

The evaluation model maps SDK question types onto an alpha API

This is the most intricate part of the package. openrouter.decisionModel() implements the AI SDK evaluation model contract on top of the OpenRouter Decisions API, and openrouter.evaluationModel() is the same method under the name the AI SDK expects, so the AI SDK calls it when resolving string model IDs through a default provider. Both names share one implementation, and either can be passed to evaluate().

ts
import { openrouter } from '@openrouter/ai-sdk-provider';
import { experimental_evaluate as evaluate } from 'ai';

const result = await evaluate({
  model: openrouter.decisionModel('typesafe/jev-1.13'),
  state: {
    ticket: 'My checkout page shows a blank screen after I click Pay.',
    customer_tier: 'enterprise',
  },

The type mapping is where the friction is. An SDK boolean question becomes an OpenRouter noul question, and the returned noul value is exposed as probability, while choice and score map directly and keep their probability distributions. The Decisions API rounds probabilities and scores to two decimals, and the model declares that rounding on every result, so the SDK accepts a score that differs from the exact probability weighted mean by rounding alone.

Values that have no place in the SDK contract are preserved rather than dropped. Per answer confidence and score legend values are kept under result.providerMetadata.openrouter.answers[questionId], and the request cost is under result.providerMetadata.openrouter.usage.cost.

The client also refuses some inputs before sending anything, so nothing is billed. A score question whose criteria contains null is rejected, and so is a boolean question whose criteria describes only one of true and false, both raising InvalidArgumentError. A boolean question with no criteria descriptions at all is sent without criteria.

Option precedence decides who wins a conflicting setting

Model settings and call level options overlap, and the README spells out the order, which is the part you need when a setting silently does nothing.

Model settings accept user, provider for routing preferences, session_id, trace and extraBody. The call level providerOptions.openrouter accepts the same Decisions request fields plus arbitrary pass-through keys. Precedence, lowest to highest, is factory extraBody, then model extraBody, then typed model settings, then providerOptions.openrouter. Three things are exempt: model, state and questions always come from the call and cannot be overridden.

That ordering has a practical consequence. A provider-wide default set in the factory can still be beaten by a per model setting and again by the call, which is the sensible direction for a routing preference. But it also means a global default that looks authoritative may be shadowed by a model level value you set once and forgot about, and the only way to know which one is in force is to inspect the effective settings rather than the source of the setting you believe you are using.

The call level escape hatch is also worth noting for a security minded review. Arbitrary pass-through keys are forwarded, so providerOptions.openrouter is a path for request fields the typed settings do not model. Anything an application builds from user input should not be merged into that object without a schema in front of it.

The catalogue of models lives on OpenRouter, not in the repository

There is no model manifest in this repository, and the README is direct about why. The list is not definitive, it changes constantly as models are added and deprecated, and the current list lives on the OpenRouter models page, with a second page filtered to the tool supported models.

The consequence for an adopter is that a model identifier in your code is a promise about a remote catalogue, not about this package. Three things follow. A model id can be deprecated and your production prompt starts failing on a day you did not change anything. A model can be added that this provider cannot drive, since the README warns the tool supported list may include models that are not compatible with the AI SDK. And you cannot diff your model set at build time, because nothing in the package pins it.

The mitigation is on your side rather than the library's. Keep model ids in one configuration file, keep a fallback id for the calls that matter, and treat the OpenRouter model list as a dependency you check when something breaks, rather than as a one-time setup step. The alternative, a per-vendor provider written in house, gives you a pinned model set and a pinned SDK contract at the cost of maintaining several adapters and losing the single id space.

Apache 2.0, changesets, and a package that ships only its build output

The licence is Apache-2.0, with the LICENSE file at the top of the repository and the same value in the package.json. It permits use, modification and redistribution, including in proprietary products, provided the licence terms and notices travel with the code.

The release line moves regularly. The published versions are 3.1.0 on 2026-09-19, 3.0.0 on 2026-07-06 and 2.9.1 on 2026-06-10, and the last push was on 2026-09-19, which is the same day as the newest release. The repository is not archived.

Versioning is done with changesets, which is worth knowing because it explains the shape of the repository. There is a .changeset/ directory, a changeset script, a changeset-version script and a changeset-publish script that builds, tests and then publishes with provenance attestation. The CHANGELOG.md is generated from those changesets, so release notes accumulate in the repository rather than in a release page.

The package layout is minimal by design. The files field ships dist only, the exports map exposes the package root and an ./internal entry, and the build runs through tsup with a clean step, while typecheck and stylecheck are separate commands backed by tsc and biome. The test scripts split the suite into four vitest configurations, node, edge, e2e and issues, which is the shape you would expect from a package that has to work at the edge, in Node, and against a live API. There are also pnpm overrides in the package.json for glob and js-yaml, which pin transitive dependencies that would otherwise float.

Editorial conclusion

ai-sdk-provider fits a team already using the AI SDK that wants one interface over many hosted models without writing a provider per vendor, and it does not fit a project that needs a stable evaluation contract, since the Decisions API behind the evaluation model is still in alpha and its shapes may change. Before adopting it, install the line that matches your ai major version, call one model by its OpenRouter identifier, and check the provider metadata your application will read.

Frequently asked questions

How do I install the OpenRouter provider for the Vercel AI SDK?

Run npm install @openrouter/ai-sdk-provider for the current line, which supports ai@^7.0.0, requires Node.js 22 or newer and is ESM-only. Legacy lines are pinned to @openrouter/[email protected] for AI SDK v6 and @1.5.4 for AI SDK v5.

How do I call an OpenRouter model with ai-sdk-provider?

Import the openrouter instance and pass it a model identifier to generateText, for example model: openrouter('openai/gpt-4o'). The identifier carries the upstream vendor as a prefix and is the OpenRouter model id.

Does ai-sdk-provider support embedding models?

Yes, through a separate factory. The README shows openrouter.textEmbeddingModel('openai/text-embedding-3-small') passed to embed and embedMany, and names text-embedding-3-small, text-embedding-3-large and text-embedding-ada-002 among the supported embedding models.

What is openrouter.decisionModel in ai-sdk-provider?

It implements the AI SDK evaluation model contract on top of the OpenRouter Decisions API, and openrouter.evaluationModel() is the same implementation under the name the SDK expects. The Decisions API is served from the alpha path and its request and response shapes may change.

Which AI SDK version is needed for experimental_evaluate with OpenRouter?

The README states that experimental_evaluate ships in [email protected] and newer, while the rest of the package keeps working with any ai@7. The SDK boolean question type maps to an OpenRouter noul question whose value is exposed as probability.

Official sources

  1. License: Apache-2.0
  2. OpenRouterTeam/ai-sdk-provider on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/openrouterteam-ai-sdk-provider.svg)](https://hysenlabs.com/projects/openrouterteam-ai-sdk-provider)

Was this useful?