TanStack AI 1.0 Is Here. The Upgrade Is the Part That Bites
The TypeScript agent SDK hit 1.0 with one tool definition for every provider. Here is what changes in your code, and the one-line grep that tells you when you are done.
Most AI apps are welded to one model provider. The tool definitions are written in that provider's format, the streaming code expects its events, and switching to a cheaper or better model means rewriting the parts you least want to touch.
TanStack AI is one of the more serious attempts to cut that weld in TypeScript, and on October 22 it tagged its 1.0.0 packages. The pitch is simple: define a tool once, run it on your server or in the browser, and point the same chat code at OpenAI, Anthropic, Gemini, a local Ollama model or a few hundred models through OpenRouter. (TanStack/ai README)
But "1.0" here means something specific. The release notes open with this line: "This release removes every API that was deprecated in 0.x." (release notes) So for anyone already on 0.x, 1.0 is a migration with a few traps. For anyone new, it is the first version where the rules stop moving. Both groups need the same short map.
What TanStack AI is, quickly
TanStack is the open-source group behind TanStack Query, Router and Table, libraries a lot of React developers already use. TanStack AI applies the same idea to AI apps: a small core (@tanstack/ai), plus separate packages you add only when you need them. It is MIT-licensed.
Three pieces matter for most builders:
- Adapters. An adapter is a small translator between the library and one provider. Each provider gets a package, such as
@tanstack/ai-openaior@tanstack/ai-anthropic, and you import only the activity you use (openaiTextfor chat,openaiImagefor images). The README lists OpenRouter, OpenAI, Anthropic, Gemini and Vertex AI, Ollama, Grok, Groq, Cloudflare Workers AI and others. - Framework clients. Hooks for React, Solid, Vue, Svelte and Preact, plus a headless client if you use none of them.
- Typed tools. You describe a tool once with
toolDefinition(), using a schema library like Zod for its inputs and outputs, and then attach an implementation.
That last one is the heart of it, so it gets its own section.
The big idea: one tool contract, two places to run it
A "tool" is a function the model can ask your app to run, like "look up the weather" or "add this item to the cart." Most SDKs make you describe each tool in the provider's format and then write the code that runs it somewhere else. The description and the code drift apart, and the model gets told one thing while your function expects another.
TanStack's answer is a single contract with two possible implementations. Per the tools guide:
- Call
.server()on the definition and the tool runs on your backend. You pass it tochat(), and the library runs it automatically when the model asks. - Call
.client()and the tool runs in the browser. The server passes only the definition tochat(), and the browser does the work. This is how you let a model update your UI directly. - Define both, and the server decides per request where it runs, by passing either the plain definition (browser runs it) or the server version (server runs it).
Think of it like a restaurant order ticket. The ticket format is fixed, and the kitchen or the bar can fill it, but everyone reads the same ticket. Because the schema is shared, TypeScript catches a mismatch before your users do.
The 1.0 migration guide makes this stricter on purpose: client tools now "must share identical schemas, including outputSchema, between server and browser." (migration guide) If you have been loosely duplicating tool types between front end and back end, 1.0 will make you stop.
What changed in 1.0 (the parts that bite)
The full list is long. Four changes will hit most apps.
1. threadId is now required, and you have to supply it. A thread ID is the name tag for one conversation. Before, the library could make one up for you. Now threadId is required in useChat, the other chat hooks, chat(), summarize() and more, and the release notes say the library no longer generates thread IDs. The migration guide is blunt about the trap: use a stable ID, "not a random one generated on each render." A React component that calls crypto.randomUUID() inline would hand every render a brand-new conversation. Store the ID with the chat, in your database or the URL.
2. Tool approvals moved to "interrupts." If your app asks a human to approve a tool call before it runs (a good idea for anything that sends email or spends money), the old addToolApprovalResponse() is gone. Approvals now arrive as interrupts, pauses the run waits on, and you answer them with resolveInterrupt. From the migration guide:
const { interrupts } = useChat(chatOptions)
const approval = interrupts.find((item) => item.kind === 'tool-approval')
if (approval?.kind === 'tool-approval') approval.resolveInterrupt(true)
One detail worth knowing before you build on it: the release notes say @tanstack/ai-sandbox refuses tools that set needsApproval. If you planned to run approval-gated tools inside a sandbox, check that combination first.
3. Client and server must both be 1.0. The old wire formats are removed. In the release notes' words: "Use a 1.0 client with a 1.0 server." Upgrade every @tanstack/ai* package together. If your front end and back end deploy separately, plan one coordinated release.
4. Saved data needs attention before you deploy. This is the step people skip. The migration guide says to finish or clear in-progress runs and remove old rec: records (the old migration helper is gone), resolve or drop pending interrupts, add a blobKey to artifact records (stored files a run produced, like a generated image), and make your client persistence getItem return { messages }. If you deploy 1.0 over a database full of half-finished 0.x runs, you are asking for a confusing week.
Two smaller ones: the separate UI packages (@tanstack/ai-react-ui, ai-solid-ui, ai-vue-ui) get no 1.0 release, so import from @tanstack/ai-react/ui and friends instead, and retired provider model IDs were removed from the types, so an old model name may stop compiling.
Put this into practice
If you are new, start clean on 1.0. The README's minimal setup is:
pnpm add @tanstack/ai@^1 @tanstack/ai-openai@^1
The README shows these without versions; adding @^1 keeps a later major release from sneaking in while you follow a 1.0 guide. Add @tanstack/ai-client and @tanstack/ai-react for a React chat UI, or @tanstack/ai-openrouter to reach many providers with one key (you still need an OpenRouter account, and each model bills at its own rate). Write one tool with toolDefinition(), give it a .server() implementation, pass it to chat(), and stream the result. Then swap the adapter for a second provider and see how much of your code changes. That test is the whole reason to pick this library, so run it on day one.
If you are on 0.x, follow the migration guide's order. It is short and it works as a checklist:
-
Run the codemod (a script that rewrites your source files for you). It handles the common renames (
bodytoforwardedProps, theconversationIdkey tothreadId):npx jscodeshift --parser=tsx -t https://raw.githubusercontent.com/TanStack/ai/main/codemods/ag-ui-compliance/transform.ts "src/**/*.{ts,tsx}"Add
--dry --printfirst to preview. The command pulls the transform from themainbranch, which can change; for a repeatable migration, swapmainin that URL for the release tag (%40tanstack%2Fai%401.0.0), where the same file exists. The guide says it does not changebody.datareads,threadIdvalues orcreateChatHookoptions, so those are on you. -
Upgrade every
@tanstack/ai*package to 1.0 at once, and remove the three old UI packages. -
Run your type checker and fix what it flags. Most of the work shows up here.
-
Drain or clean saved runs before deploying, as above.
-
Run the done check. The guide's search should come back empty:
grep -rnE "pendingInterrupts|resumeInterrupts\(|addToolApprovalResponse|conversationId|getVideoUrl|durationSeconds|unitsBilled|body\.data" srcThen confirm a chat streams a reply and a saved chat loads after a reload.
That grep is the most useful line in the whole release. It turns "did we finish the upgrade?" into a yes or no.
Honest limitations
A few things to know before you commit.
There is no 1.0 launch post yet, as far as this run could find. The last big write-up is the August 21 release-candidate post, which said the architecture was locked and the provider count had grown "from four providers to 24." (TanStack blog) The 1.0 story lives in release notes and the migration guide for now.
The releases are per package. GitHub's release feed for the repo shows separate 1.0.0 entries for packages like ai-utils and ai-svelte, so check the notes for the exact packages you depend on rather than assuming one changelog covers all of them.
"Provider-agnostic" does not mean "provider-identical." One schema can describe a tool for every adapter, but models still differ in how well they call tools, how they stream and what they cost. The adapter saves you a rewrite. It does not save you an evaluation.
And it is TypeScript-first. If your agents run in Python, this is not your library.
Where this leaves you
TanStack AI 1.0 is a good sign for anyone tired of welding their app to one model vendor: a typed tool contract, a small core and adapters you can swap. The price of admission is a migration that asks you to name every conversation, answer approvals as interrupts and clean up old runs before you ship.
If you are starting fresh, start on 1.0 and run the provider-swap test in your first hour. If you are on 0.x, block an afternoon, run the codemod with --dry --print, and keep going until the done-check grep comes back empty. Either way, you will know quickly whether one tool definition really holds up across the models you care about, and that is the only test that matters.
Sources: TanStack/ai README; @tanstack/ai 1.0.0 release notes, October 22, 2026; TanStack AI 1.0 migration guide; TanStack AI tools guide; TanStack AI RC post, August 21, 2026; npm @tanstack/ai. Reviewed at @tanstack/ai 1.0.0.