AI
AI building blocks for TypeScript. We build the hard parts, you keep the stack.
TanStack AI is a TypeScript library for building AI features and agents. It ships the agent loop, provider adapters, durability, interrupts, sandboxes, and tools, and plugs into the server, database, and UI you already have.
Skills
Install the agent skills from the skills folder of https://github.com/TanStack/ai for my user, read them, then ask me what AI features I want to build, or suggest some.
import { toolDefinition } from '@tanstack/ai'
import { z } from 'zod'
export const lookupInvoice = toolDefinition({
name: 'lookup_invoice',
description: 'Find an invoice by id',
inputSchema: z.object({ id: z.string() }),
outputSchema: z.object({
total: z.number(),
status: z.enum(['draft', 'sent', 'paid']),
}),
})This file never changes. Everything on the right is a destination for it.
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { createFileRoute } from '@tanstack/react-router'
import { lookupInvoice } from './tools'
export const Route = createFileRoute('/api/chat')({
server: {
handlers: {
POST: async ({ request }) => {
const { messages } = await request.json()
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
tools: [lookupInvoice.server(findInvoice)],
})
return toServerSentEventsResponse(stream)
},
},
},
})Open protocol
AG-UI compliant, in both directions.
The client sends AG-UI requests and consumes AG-UI events, so the agent on the other end is replaceable: point the same client at a Python, Go, or PHP runtime and it keeps working. Bring your own transport.
AG-UI sits between your web app and your AI endpoint, with traffic in both directions. The server then talks to a provider such as OpenAI or Anthropic.
CLIENT
your web app
AG-UI
communication protocol
Server
your ai endpoint
Provider
openai, anthropic
Typesafe models
Typed options for every model.
Pick a model and TypeScript narrows the fields to what it supports. Input parts for chat. Pixel sizes on one image model and aspect ratio plus resolution on the next. Durations and tiers for video. Resolution for world models. The wrong value fails in the editor, not in production.
import { openaiText } from '@tanstack/ai-openai'
const result = await chat({
adapter: openaiText('gpt-6-astra'),
messages: [{ role: 'user', content: [{ type: 'image', source: receiptUrl }] }],
})
input for gpt-6-astra
Input parts are typed per model.
✓ no errors. 'image' is a valid input for gpt-6-astra.
We handle tools
Define a tool once. Run it on either side.
One schema gives you the input and output types on the server and the client. The loop calls the tool, pauses for approval when you ask it to, applies the user's edits, and feeds the result back to the model.
const lookupInvoice = toolDefinition({
name: 'lookup_invoice',
inputSchema: z.object({ id: z.string() }),
outputSchema: invoiceSchema,
needsApproval: true,
})
lookupInvoice.server(async ({ id }) => {
return db.invoices.update({
where: { id },
data: { lastViewedAt: new Date() },
})
})
The server implementation uses the same typed id to update a row in your database. The model never sees your credentials.
You own the UI
Typed parts, honest states, no components to fight.
A message is a list of parts, and every part carries its own lifecycle. Render them yourself or register one component per part type.
A message is a list of parts. A thinking part, then a tool call that moves from awaiting input through approval to complete, then the tool result and the streamed text reply.
You own persistence
Your database. Your schema.
Persistence is two functions: load a thread and save a thread. The ai-persistence skill ships with the package, so your coding agent can wire them to your tables and ORM in one pass.
- Postgres
- MySQL
- SQLite
- MongoDB
- Cloudflare D1
- Redis
- Drizzle
- Prisma
- localStorage
- IndexedDB
import { defineAIPersistence, defineMessageStore } from '@tanstack/ai-persistence'
import { db } from './db'
// The whole contract. Your tables, your columns, your types.
export const persistence = defineAIPersistence({
stores: {
messages: defineMessageStore({
loadThread: (threadId) => db.threads.messages(threadId),
saveThread: (threadId, messages) => db.threads.save(threadId, messages),
}),
},
})
// chat({ ..., middleware: [withPersistence(persistence)] })Durability you can move
Refresh mid-answer and nothing is lost.
Every chunk is written to a log before it is delivered. Drop the socket or refresh the page and the client replays from its last offset instead of paying for the model again.
import { chat, memoryStream, toServerSentEventsResponse } from '@tanstack/ai'
// Development and single-process apps. Zero setup.
export async function POST(request: Request) {
const stream = chat({ /* ... */ })
return toServerSentEventsResponse(stream, {
durability: { adapter: memoryStream(request) },
})
}We handle the hard parts
Sandboxes, Code Mode, MCP, memory, compaction.
Each one is a separate package with the same shape as the core. Reach for it when the task needs it, and leave it out of the bundle when it does not.
@tanstack/ai-code-mode
The model chains your tools into one script and runs it in an isolate, instead of one round-trip per call.
@tanstack/ai-sandbox
Run Claude Code, Codex, or any ACP agent as a chat backend in a local process or a sandbox. Its activity streams back as events your UI already renders.
@tanstack/ai-mcp
A typed MCP client with a CLI that generates the types, plus interactive widgets rendered from tool results.
@tanstack/ai-memory · @tanstack/ai-compaction
Recall across sessions through Redis, mem0, Honcho, or Hindsight. Compaction keeps long threads inside the model window.
Beyond chat
Images, video, speech, voice, and live worlds.
The same adapters and the same persistence cover every modality, with progress updates and cost tracking built in.
chat · outputSchema · summarize
Structured output that matches your schema exactly.
generateSpeech · generateTranscription · generateAudio
Transcription with word timestamps and diarization, plus music and sound effects.
openaiRealtimeToken · RealtimeClient
OpenAI, Grok, and ElevenLabs with VAD modes and tool calling inside a live session.
generateWorld · generateLiveVideo
Mint a session on the server and stream an explorable world or live video into the browser over WebRTC.
Devtools
See every action on both sides.
Every tool call, interrupt, memory recall, and finish reason, on the server and in the client, in one timeline.
hooks
Support Chat
useChat · 12 msgs
Image Studio
useGenerateImage
Invoice Extract
useObject
Call Notes
useTranscription
run timeline
thread_7f2 · run_3
Start here
Pick the page that matches your next hour.
Each one is a short guide with copyable code, not a tour.
Partners
Sponsors get special perks like private discord channels, priority issue requests, and direct support!