AI
The headless agent framework. Bring your own stack.
TanStack AI runs the agent loop as typed TypeScript primitives you compose yourself: tool calls, reasoning, human-in-the-loop interrupts, sandboxed code execution, memory, and streaming state. Eleven provider adapters, seven UI framework bindings on top of a framework-free core, native AG-UI over the wire. No hosted gateway, no proprietary stream format, no platform to buy into.
Two files
An agent on your own server, end to end.
One route on the server, one hook in the client, and the transport between them is yours. Nothing here is a wrapper around a service we run.
import { chat, toServerSentEventsResponse } from '@tanstack/ai'
import { openRouterText } from '@tanstack/ai-openrouter'
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/api/chat')({
server: {
handlers: {
POST: async ({ request }) => {
const { messages } = await request.json()
const stream = chat({
adapter: openRouterText('anthropic/claude-sonnet-4.5'),
messages,
tools: [lookupInvoice],
})
// your route, your auth, your deploy target
return toServerSentEventsResponse(stream)
},
},
},
})
import { useChat, fetchServerSentEvents } from '@tanstack/ai-react'
export function Chat() {
const { messages, sendMessage, interrupts } = useChat({
connection: fetchServerSentEvents('/api/chat'),
})
// typed state and events. no components, no styles.
return (
<>
{messages.map((message) => (
<Bubble key={message.id} {...message} />
))}
{/* the loop paused. you decide when it continues. */}
{interrupts.map((interrupt) => (
<button key={interrupt.id}
onClick={() => interrupt.resolveInterrupt(true)}>
Approve {interrupt.toolName}
</button>
))}
</>
)
}
Swap ai-react for ai-vue, ai-solid, ai-svelte, ai-preact, ai-angular, or the framework-free ai-client. The server route never changes.
The agent loop
An agent loop you can read, and stop where you want.
chat() runs the cycle: the model calls a tool, the result goes back, it keeps reasoning. You decide the boundary. Client tools touch local UI state, server tools use your credentials, isomorphic tools share one definition. Stop conditions are plain (state) => boolean functions you compose. Mark a tool needsApproval and the run ends as an interrupt your UI resolves, then resumes exactly where it stopped, on a stateless server, no database required.
const lookupInvoice = toolDefinition({
name: 'lookup_invoice',
inputSchema: z.object({ id: z.string() }),
outputSchema: invoiceSchema,
needsApproval: true,
})
lookupInvoice.server(readPrivateLedger)
Runs behind your server boundary with private credentials and data. The model never sees them.
selected model
any of 300+ models
Types narrow to this exact model: its options, its capabilities, its input modalities. Pass an image to a text-only model and it fails at compile time, not in production.
Provider types
Swap the model. Keep the agent.
OpenRouter, OpenAI, Anthropic, Gemini, Bedrock, Mistral, Groq, Grok, Ollama, ElevenLabs, and fal.ai ship as official adapters, and openaiCompatible covers any endpoint that speaks the same shape, including a model on your own hardware. Switching is a line of config, not a migration. And no adapter pretends every model is identical: write openaiText('gpt-5.5') and TypeScript narrows to that model's real options, capabilities, and input modalities.
Open protocol
AG-UI compliant, in both directions.
The client sends AG-UI requests and consumes AG-UI events, with no proprietary stream format and no translation layer in between. That is what makes the agent on the other end replaceable: point the same client at a Python, Go, or PHP AG-UI runtime and it keeps working. The transport is yours too, whether that is SSE, HTTP streams, XHR, RPC, a raw async iterable, or a fetcher you wrote. Nothing to sign up for, no key to hand over, no traffic through us.
UI
headless client
AG-UI
request + events
Agent loop
your server
Provider
typed adapter
The rest of the agent stack
Sandboxes, code mode, MCP, memory. Shipped, not planned.
An agent framework is more than a loop around a model. Each of these is a separate package you opt into, running on infrastructure you already own. Each ships an Agent Skill so your coding assistant wires it up correctly.
Code Mode
@tanstack/ai-code-mode
The model writes one TypeScript program that calls your tools with loops and Promise.all, instead of a round trip per call. It runs in a V8 isolate, QuickJS WASM, or a Cloudflare Worker, with no host filesystem, network, or process.
Coding-agent harnesses
@tanstack/ai-sandbox
Run Claude Code, Codex, OpenCode, Grok Build, or any ACP agent as a chat backend, inside a local process, Docker, Daytona, Vercel, Sprites, or Cloudflare sandbox. Their tool activity streams back as AG-UI events your UI already renders.
MCP + MCP Apps
@tanstack/ai-mcp
A host-side MCP client with a type-generating CLI, provider-routed mcpTool(), and interactive ui:// widgets rendered from tool results across multiple servers.
Memory + persistence
@tanstack/ai-memory · -persistence
memoryMiddleware recalls across sessions through Redis, mem0, Honcho, or Hindsight adapters. Persistence keeps an authoritative server thread, resumes a stream through a dropped connection, and survives a reload.
Beyond chat
Not a chatbot library. Every modality, one runtime.
Text and structured output sit beside image, video, speech, transcription, music, and realtime voice. One hook per activity, each a separate tree-shakeable import, none of it wrapped in a chat UI you have to accept. Middleware, devtools, and OpenTelemetry observe every run at the activity level.
Text, objects, reasoning
chat · outputSchema · summarize
Structured output streams as a typed message part beside tool calls and is preserved per turn in history, not a separate one-shot call.
Speech, transcription, music
generateSpeech · generateTranscription · generateAudio
Six speech formats with speed control, 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
Per-model typed options across OpenAI, Gemini, Grok, OpenRouter, and fal.ai, with an async job lifecycle for video.
Devtools
Watch the loop run instead of guessing.
Agent bugs live between the turns: which tool ran, what came back, what memory injected, where the run stopped. The TanStack Devtools panel finds every AI hook on the page and gives each one a turn-by-turn timeline with tool inputs and outputs, state snapshots, and errors. You can even replay a tool from a saved fixture instead of prompting your way back to the same state.
hooks
Support Chat
useChat · 12 msgs
Image Studio
useGenerateImage
Invoice Extract
useObject
Call Notes
useTranscription
run timeline
thread_7f2 · run_3
Partners
Sponsors get special perks like private discord channels, priority issue requests, and direct support!