本页还没有译文
本页 73 段还没译成Español,下面显示的是英文原文。Migration Guide
还没翻译译自英文(tanstack.com)本页 73 段都还没译
This guide helps you migrate from the previous version of TanStack AI to the latest version. The major changes focus on improved tree-shaking, clearer API naming, and simplified configuration.
Overview of Changes
The main breaking changes in this release are:
- Adapter functions split - Adapters are now split into activity-specific functions for optimal tree-shaking
- Common options flattened - Options are now flattened in the config instead of nested
providerOptionsrenamed - Now calledmodelOptionsfor claritytoResponseStreamrenamed - Now calledtoServerSentEventsStreamfor clarity- Embeddings removed, then reintroduced - The old
embedding()API was removed; embeddings are back as the newembed()activity with multimodal support - Provider tools moved to
/tools- Import provider tools from each adapter's/toolssubpath stream: falsereturns{ text, chunks }-chat({ stream: false })andstreamToText()resolve to an object, not a string
1. Adapter Functions Split
Adapters have been split into activity-specific functions to enable optimal tree-shaking. Instead of importing a monolithic adapter, you now import specific functions for each activity type.
Before
import { chat } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
const stream = chat({
adapter: openai(),
model: 'gpt-5.2',
messages: [{ role: 'user', content: 'Hello!' }],
})After
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages: [{ role: 'user', content: 'Hello!' }],
})Key Changes
- Model is passed to adapter factory - The model name is now passed directly to the adapter function (e.g.,
openaiText('gpt-5.2')) - No separate
modelparameter - The model is stored on the adapter, so you don't need to pass it separately tochat() - Activity-specific imports - Import only what you need (e.g.,
openaiText,openaiSummarize,openaiImage)
All Adapter Functions
Each provider package now exports activity-specific functions:
OpenAI
import {
openaiText, // Chat/text generation
openaiSummarize, // Summarization
openaiImage, // Image generation
openaiSpeech, // Text-to-speech
openaiTranscription, // Audio transcription
openaiVideo, // Video generation
} from '@tanstack/ai-openai'Anthropic
import {
anthropicText, // Chat/text generation
anthropicSummarize, // Summarization
} from '@tanstack/ai-anthropic'Gemini
import {
geminiText, // Chat/text generation
geminiSummarize, // Summarization
geminiImage, // Image generation
geminiSpeech, // Text-to-speech (experimental)
} from '@tanstack/ai-gemini'Ollama
import {
ollamaText, // Chat/text generation
ollamaSummarize, // Summarization
} from '@tanstack/ai-ollama'Migration Example
Here's a complete example of migrating adapter usage:
Before
import { chat } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
import { anthropic } from '@tanstack/ai-anthropic'
type Provider = 'openai' | 'anthropic'
function getAdapter(provider: Provider) {
switch (provider) {
case 'openai':
return openai()
case 'anthropic':
return anthropic()
}
}
const stream = chat({
adapter: getAdapter(provider),
model: provider === 'openai' ? 'gpt-5.2' : 'claude-sonnet-4-5',
messages,
})After
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { anthropicText } from '@tanstack/ai-anthropic'
type Provider = 'openai' | 'anthropic'
const messages = [{ role: 'user' as const, content: 'Hello!' }]
const adapters = {
openai: () => openaiText('gpt-5.2'),
anthropic: () => anthropicText('claude-sonnet-4-5'),
}
const provider: Provider = 'openai'
const stream = chat({
adapter: adapters[provider](),
messages,
})2. Common Options Flattened
Common options that were previously nested in an options object are now flattened directly in the config.
Before
const stream = chat({
adapter: openai(),
model: 'gpt-5.2',
messages,
options: {
temperature: 0.7,
maxTokens: 1000,
topP: 0.9,
},
})After
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages,
temperature: 0.7,
maxTokens: 1000,
topP: 0.9,
})Available Options
These options are now available at the top level:
temperature- Controls randomness (0.0 to 2.0)topP- Nucleus sampling parametermaxTokens- Maximum tokens to generatemetadata- Additional metadata to attach
Heads up — sampling has since moved (breaking). In a later release, the sampling props (
temperature,topP,maxTokens) were removed from the root ofchat()and now live in provider-nativemodelOptions. Passing them at the root no longer type-checks or takes effect. See Moving Sampling Options into modelOptions for the codemod and provider-native key names.metadatastays at the root.
3. providerOptions → modelOptions
The providerOptions parameter has been renamed to modelOptions for clarity. This parameter contains model-specific options that vary by provider and model.
Before
const stream = chat({
adapter: openai(),
model: 'gpt-5.2',
messages,
providerOptions: {
// OpenAI-specific options
responseFormat: { type: 'json_object' },
logitBias: { '123': 1.0 },
},
})After
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages,
modelOptions: {
// OpenAI-specific options
responseFormat: { type: 'json_object' },
logitBias: { '123': 1.0 },
},
})Type Safety
modelOptions is fully typed based on the adapter and model you're using:
import { openaiText } from '@tanstack/ai-openai'
const adapter = openaiText('gpt-5.2')
// TypeScript knows the exact modelOptions type for gpt-5.2
const stream = chat({
adapter,
messages,
modelOptions: {
// Autocomplete and type checking for gpt-5.2 options
responseFormat: { type: 'json_object' },
},
})4. toResponseStream → toServerSentEventsStream
The toResponseStream function has been renamed to toServerSentEventsStream to better reflect its purpose. Additionally, the API has changed slightly.
Before
import { chat, toResponseStream } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
export async function POST(request: Request) {
const { messages } = await request.json()
const abortController = new AbortController()
const stream = chat({
adapter: openai(),
model: 'gpt-5.2',
messages,
abortController,
})
return toResponseStream(stream, { abortController })
}After
import { chat, toServerSentEventsStream } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
export async function POST(request: Request) {
const { messages } = await request.json()
const abortController = new AbortController()
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages,
abortController,
})
const readableStream = toServerSentEventsStream(stream, abortController)
return new Response(readableStream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
},
})
}Key Changes
- Function renamed -
toResponseStream→toServerSentEventsStream - Returns ReadableStream - Now returns a
ReadableStreaminstead of aResponse - Manual Response creation - You create the
Responseobject yourself with appropriate headers - AbortController parameter - Passed as a separate parameter instead of in options
Alternative: HTTP Stream Format
If you need HTTP stream format (newline-delimited JSON) instead of SSE, use toHttpStream:
import { toHttpStream } from '@tanstack/ai'
const readableStream = toHttpStream(stream, abortController)
return new Response(readableStream, {
headers: {
'Content-Type': 'application/x-ndjson',
},
})5. Embeddings Removed, Then Reintroduced as embed()
The original embedding() function was removed from TanStack AI. Embeddings have since returned as a new activity with a different API: a single embed() function with multimodal input support and per-model type safety. The old embedding() name and adapter factories (like openaiEmbed()) are not coming back.
Before
import { embedding } from '@tanstack/ai'
import { openaiEmbed } from '@tanstack/ai-openai'
const result = await embedding({
adapter: openaiEmbed(),
model: 'text-embedding-3-small',
input: 'Hello, world!',
})After
import { embed } from '@tanstack/ai'
import { openaiEmbedding } from '@tanstack/ai-openai'
const result = await embed({
adapter: openaiEmbedding('text-embedding-3-small'),
input: 'Hello, world!',
})
console.log(result.embeddings[0]?.vector)Key differences from the old API:
- Model moves into the adapter factory -
openaiEmbedding('text-embedding-3-small')instead of a separatemodeloption, matching every other activity - Single function for one or many inputs -
inputaccepts a single item or an array; the result always has anembeddingsarray with one vector per input item - Multimodal inputs - models like Cohere embed-v4.0 and Amazon Titan Multimodal accept image parts and fused text+image items
- Top-level
dimensions- request Matryoshka dimensions without provider-specific options
See the Embeddings guide for full usage.
6. Provider Tools Moved to /tools Subpath
Provider-specific tools (web search, code execution, computer use, etc.) are now
exported from a dedicated /tools subpath on every adapter package. This keeps
tool imports tree-shakeable and avoids name collisions between providers.
The only breaking change is in @tanstack/ai-openrouter:
createWebSearchTool has been removed from the package root, renamed to
webSearchTool, and moved to @tanstack/ai-openrouter/tools. Every other
provider tool (Anthropic, OpenAI, Gemini) is newly exported — no existing
import breaks.
Before
import { createWebSearchTool } from '@tanstack/ai-openrouter'
const tools = [
createWebSearchTool({ engine: 'native', maxResults: 5 }),
]After
import { webSearchTool } from '@tanstack/ai-openrouter/tools'
const tools = [
webSearchTool({ engine: 'native', maxResults: 5 }),
]Key Changes
- Import path is now
/tools— matches the existing/adapterssubpath pattern used elsewhere in each provider package. - Factory renamed —
createWebSearchTool→webSearchTool. Thecreate*prefix has been dropped to align with every other provider (webSearchToolin@tanstack/ai-anthropic/tools,@tanstack/ai-openai/tools, etc.). - Runtime behavior is unchanged — the factory accepts the same config
object and returns a tool that works identically in
chat({ tools: [...] }). - Type-level gating is new — if you pass a provider tool to a model that
doesn't support it (per the model's
supports.toolsarray), you now get a type error on thetoolsarray. User-definedtoolDefinition()tools are unaffected.
For the full list of available provider tools and which models support each one, see Provider Tools.
7. stream: false Returns { text, chunks }
chat({ stream: false }) and streamToText(stream) now resolve to a ChatResult object, not a string. Take text from the result.
Before
import { chat, streamToText } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
const text = await chat({
adapter: openaiText('gpt-5.6'),
messages: [{ role: 'user', content: 'Hello!' }],
stream: false,
})
const stream = chat({
adapter: openaiText('gpt-5.6'),
messages: [{ role: 'user', content: 'Hello!' }],
})
const streamedText = await streamToText(stream)After
import { chat, streamToText } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
const { text } = await chat({
adapter: openaiText('gpt-5.6'),
messages: [{ role: 'user', content: 'Hello!' }],
stream: false,
})
const stream = chat({
adapter: openaiText('gpt-5.6'),
messages: [{ role: 'user', content: 'Hello!' }],
})
const { text: streamedText } = await streamToText(stream)text is the same string as before. The new chunks array holds every chunk of the run, so you can also read tool calls, usage, and interrupts. See chat() returns.
With outputSchema, stream: false still resolves to the parsed object.
Complete Migration Example
Here's a complete example showing all the changes together:
Before
import { chat, toResponseStream } from '@tanstack/ai'
import { openai } from '@tanstack/ai-openai'
export async function POST(request: Request) {
const { messages } = await request.json()
const abortController = new AbortController()
const stream = chat({
adapter: openai(),
model: 'gpt-5.2',
messages,
options: {
temperature: 0.7,
maxTokens: 1000,
},
providerOptions: {
responseFormat: { type: 'json_object' },
},
abortController,
})
return toResponseStream(stream, { abortController })
}After
import { chat, toServerSentEventsStream } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
export async function POST(request: Request) {
const { messages } = await request.json()
const abortController = new AbortController()
const stream = chat({
adapter: openaiText('gpt-5.2'),
messages,
// Sampling now lives in provider-native `modelOptions` (OpenAI Responses
// keys: `temperature`, `max_output_tokens`). `metadata` stays at the root.
modelOptions: {
temperature: 0.7,
max_output_tokens: 1000,
responseFormat: { type: 'json_object' },
},
abortController,
})
const readableStream = toServerSentEventsStream(stream, abortController)
return new Response(readableStream, {
headers: {
'Content-Type': 'text/event-stream',
'Cache-Control': 'no-cache',
Connection: 'keep-alive',
},
})
}Benefits of These Changes
- Better Tree-Shaking - Import only what you need, resulting in smaller bundle sizes
- Clearer API - Function names clearly indicate their purpose
- Type Safety - Model-specific options are fully typed
- Simpler Configuration - Flattened options are easier to work with
- Focused Scope - Removed features that are better handled elsewhere
Need Help?
If you encounter issues during migration:
- Check the Tree-Shaking Guide for details on the new adapter structure
- Review the API Reference for complete function signatures
- Look at the examples for working code samples