TanStack
TanStack

AI

RC

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.

tools.ts · written once
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.

runs anywhere
provider
routes/api.chat.ts
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.

the types know the model

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

textimage

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.

tool contract

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.

message.parts

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
persistence.ts
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.

stream durability
routes/api.chat.ts
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.

Code Mode

@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.

Coding-agent harnesses

@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.

MCP + MCP Apps

@tanstack/ai-mcp

A typed MCP client with a CLI that generates the types, plus interactive widgets rendered from tool results.

Memory + compaction

@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.

Text, objects, reasoning

chat · outputSchema · summarize

Structured output that matches your schema exactly.

Speech, transcription, music

generateSpeech · generateTranscription · generateAudio

Transcription with word timestamps and diarization, plus music and sound effects.

Realtime voice

openaiRealtimeToken · RealtimeClient

OpenAI, Grok, and ElevenLabs with VAD modes and tool calling inside a live session.

Images + video

generateImage · generateVideo

Generate, edit, and stream progress to the user.

World models + live video

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.

tanstack devtools · ai

hooks

Support Chat

useChat · 12 msgs

Image Studio

useGenerateImage

Invoice Extract

useObject

Call Notes

useTranscription

run timeline

thread_7f2 · run_3

user turn"refund the duplicate charge"
memory recall3 facts injected · 214 tokens
tool calllookupInvoice { id: "inv_8841" }
tool result{ total: 4200, status: "paid" }
interruptchargeCard · awaiting approval
finish reasoninterrupt · run resumable

Start here

Pick the page that matches your next hour.

Each one is a short guide with copyable code, not a tour.

Partners

Gold
Cloudflare
Render
Railway
CodeRabbit
Lovable
Netlify
Vercel
Silver
Clerk
AG Grid
SerpApi
WorkOS
OpenRouter
Bronze
Sentry
Electric
Prisma
Unkey
OSS Sponsors

Sponsors get special perks like private discord channels, priority issue requests, and direct support!