The Cencori community adapter calls 14+ providers with one API key. It also applies security filters and records request cost. Cencori maintains it.
npm i @cencori/ai-sdkpnpm add @cencori/ai-sdkyarn add @cencori/ai-sdkbun add @cencori/ai-sdkCENCORI_API_KEY=csk_your_api_key_here// ignore: @cencori/ai-sdk/tanstack is a subpath export; kiira's paths["*"] wildcard maps it
// to a flat directory lookup and does not consult the package.json exports field,
// so the subpath cannot be resolved until kiira.config.ts adds an explicit path entry.
import { chat } from "@tanstack/ai";
import { cencori } from "@cencori/ai-sdk/tanstack";
const adapter = cencori("o1");
for await (const chunk of chat({
adapter,
messages: [{ role: "user", content: "Hello!" }],
threadId: "thread-1",
})) {
if (chunk.type === "TEXT_MESSAGE_CONTENT") {
console.log(chunk.delta);
}
}The answer prints in the terminal. To show the chat in a UI, return the stream from a route and use useChat. See Streaming.
Change the model id to reach another provider. The responses have the same shape for every provider:
// ignore: @cencori/ai-sdk/tanstack subpath not resolvable via kiira's paths["*"] wildcard.
import { cencori } from "@cencori/ai-sdk/tanstack";
// OpenAI-compatible
const openaiCompat = cencori("o1");
// Anthropic
const anthropic = cencori("claude-3-5-sonnet");
// Google
const google = cencori("gemini-2.5-flash");
// xAI
const grok = cencori("grok-3");
// DeepSeek
const deepseek = cencori("deepseek-v3.2");Tools work the same as with every adapter:
// ignore: @cencori/ai-sdk/tanstack subpath not resolvable via kiira's paths["*"] wildcard.
import { chat, toolDefinition } from "@tanstack/ai";
import { cencori } from "@cencori/ai-sdk/tanstack";
import { z } from "zod";
const adapter = cencori("o1");
const getWeatherDef = toolDefinition({
name: "getWeather",
description: "Get weather for a location",
inputSchema: z.object({ location: z.string() }),
});
const getWeather = getWeatherDef.server(async ({ location }) => {
// Look up the weather for `location`
return { temperature: 72, conditions: "Sunny" };
});
for await (const chunk of chat({
adapter,
messages: [{ role: "user", content: "What's the weather in NYC?" }],
threadId: "thread-1",
tools: [getWeather],
})) {
if (chunk.type === "TOOL_CALL_START") {
console.log("Tool call:", chunk.toolCallName);
} else if (chunk.type === "TOOL_CALL_END") {
console.log("Tool call finished:", chunk.toolCallId);
}
}See Tools.
See the Cencori dashboard and the Cencori docs.
| Provider | Models |
|---|---|
| OpenAI | gpt-5, gpt-4o, gpt-4o-mini, o3, o1 |
| Anthropic | claude-opus-4, claude-sonnet-4, claude-3-5-sonnet |
| gemini-3-pro, gemini-2.5-flash, gemini-2.0-flash | |
| xAI | grok-4, grok-3 |
| Mistral | mistral-large, codestral, devstral |
| DeepSeek | deepseek-v3.2, deepseek-reasoner |
| And more | Groq, Cohere, Perplexity, Together, Qwen, OpenRouter |
Note
Cencori is an external package, and its catalog changes over time. Compare the ids above with the current Cencori catalog before you use them.
Creates an adapter that reads CENCORI_API_KEY from the environment.
Creates an adapter factory with your own settings:
// ignore: @cencori/ai-sdk/tanstack subpath not resolvable via kiira's paths["*"] wildcard.
import { createCencori } from "@cencori/ai-sdk/tanstack";
const myCencori = createCencori({
apiKey: process.env.CENCORI_API_KEY!,
baseUrl: "https://cencori.com", // Optional
});
const adapter = myCencori("o1");It returns a function that creates an adapter for a model.
The SDK source is on GitHub.