diff --git a/docs/comparison/vercel-ai-sdk.md b/docs/comparison/vercel-ai-sdk.md index eb12dc21fd..184ed462a6 100644 --- a/docs/comparison/vercel-ai-sdk.md +++ b/docs/comparison/vercel-ai-sdk.md @@ -2,7 +2,7 @@ title: TanStack AI vs Vercel AI SDK id: vercel-ai-sdk order: 1 -description: "How TanStack AI compares to the Vercel AI SDK — feature matrix, philosophy, type safety, tool calling, streaming, and framework support." +description: "How TanStack AI compares to the Vercel AI SDK: persistence, resumable streams, durable sandbox runs, code mode, harnesses, and LLM adapters." keywords: - tanstack ai - vercel ai sdk @@ -12,6 +12,11 @@ keywords: - typescript ai sdk - tool calling - llm + - persistence + - resumable streams + - durable runs + - code mode + - sandbox --- Both TanStack AI and Vercel AI SDK are open-source TypeScript toolkits for building AI-powered applications. They share common ground - streaming chat, tool calling, multi-provider support, and deploy-anywhere flexibility - but they approach the problem from fundamentally different directions. @@ -24,17 +29,21 @@ This article compares the two SDKs from TanStack AI's perspective, with honest a ## Feature Comparison -Versions referenced below: TanStack AI as of this writing; Vercel AI SDK `ai@6.x` (v6.0.0 shipped December 2025; v7 is in pre-release at the time of writing). +Versions referenced below: TanStack AI as of this writing; Vercel AI SDK `ai@7.x` (v7 is current). | Feature | TanStack AI | Vercel AI SDK | |---------|------------|---------------| | License | MIT | Apache 2.0 | | Hosting | Works anywhere | Works anywhere | -| Providers | 9 official + community; OpenRouter and the first-party Vercel AI Gateway adapter route to 100s of models, and `openaiCompatible` connects to any OpenAI-compatible endpoint | ~38 first-party provider packages (plus community providers); 100+ models via AI Gateway | -| Framework Hooks | React, Solid, Svelte, Vue, Preact (+ React Native) | React, Vue, Svelte, Angular (Solid is community-maintained) | +| Providers | 15 official LLM adapters (OpenAI, Anthropic, Gemini, Grok, Groq, OpenRouter, Ollama, Bedrock, BytePlus, Mistral, Cohere, ElevenLabs, fal, Vercel Gateway, `openaiCompatible`) plus 5 harness adapters; community adapters for more | ~38 first-party provider packages (plus community); 100+ models via AI Gateway | +| Framework Hooks | React, Solid, Svelte, Vue, Preact, Angular (+ React Native) | React, Vue, Svelte, Angular (Solid is community-maintained) | | Generation UI Hooks | One hook per activity: chat, structured output, image, audio, speech, transcription, summarize, video, realtime | `useChat`, `useCompletion`, `useObject` | | Wire Protocol | Native AG-UI events end to end | Proprietary UI Message Stream; AG-UI via external translation layer | | Streaming | Built-in with configurable chunk strategies | Built-in with progressive delivery | +| Chat Persistence | `withPersistence` middleware + `reconstructChat`; server store or browser stores (`localStorage`, `sessionStorage`, IndexedDB) | Guide: you own `saveChat` / `loadChat` / `validateUIMessages` | +| Generation Persistence | `withGenerationPersistence` restores long media runs into the same hook fields | - | +| Resumable Streams | `StreamDurability` in core; `memoryStream` or `durableStream`; `useChat` reconnects on its own | Redis + `resumable-stream` + `activeStreamId`; you wire POST and GET | +| Durable Sandbox Runs | Detach, journal, takeover, reaper; the agent keeps working after the tab closes | `HarnessAgent` + Workflow SDK (experimental); centered on Vercel Sandbox | | Tool Calling | Isomorphic `.server()` / `.client()` system | `tool()` objects; client execution via `onToolCall` | | Agent Loop Control | Composable strategy functions `(state) => boolean` | `stopWhen` conditions + `Agent` (`ToolLoopAgent`) class | | Tool Approval | Per-tool `needsApproval` with batched approval flow | Per-tool `needsApproval` (human-in-the-loop) | @@ -51,10 +60,10 @@ Versions referenced below: TanStack AI as of this writing; Vercel AI SDK `ai@6.x | Transcription | Stable API with word timestamps and diarization (OpenAI, Grok, ElevenLabs, fal.ai) | `transcribe()` (experimental) | | Audio / Music Generation | `generateAudio()` for music & sound effects (Gemini, ElevenLabs, fal.ai) | - | | Summarization | Dedicated `summarize()` with streaming and style options | - | -| Code Execution | Node.js, Cloudflare Workers, QuickJS (WASM + Bun-native) sandboxes you run yourself | Provider-hosted code-execution tools (Anthropic, xAI, OpenAI) | -| Code Mode Skills | LLM-writable persistent skill library | - | -| Coding Agent Sandboxes | First-party Grok Build, Claude Code, Codex, OpenCode harnesses **+ any ACP agent** via `acpCompatible`; runs on local-process, Docker, Daytona, Vercel, Sprites, or Cloudflare | `HarnessAgent` (experimental) — Claude Code, Codex, Pi, OpenCode, Deep Agents; centered on Vercel Sandbox | -| Realtime Voice | OpenAI, Grok, and ElevenLabs with VAD modes and tool support | - | +| Code Mode | 5 isolate drivers you run yourself: Node `isolated-vm`, QuickJS WASM, QuickJS Bun, Cloudflare, Daytona | Experimental `@ai-sdk/code-mode` (QuickJS only, Node 22+, not browser or edge); also provider-hosted code-execution tools | +| Code Mode Skills | LLM-writable persistent skill library | Static skill uploads; no model-built library | +| Coding Agent Sandboxes | First-party Grok Build, Claude Code, Codex, OpenCode + any ACP agent via `acpCompatible`; local-process, Docker, Docker Sandboxes (`sbx`), Daytona, Vercel, Sprites, Cloudflare | `HarnessAgent` (experimental): Claude Code, Codex, Grok Build, OpenCode, Deep Agents, Pi; centered on Vercel Sandbox | +| Realtime Voice | Stable: OpenAI, Grok, and ElevenLabs with VAD modes and tool support | Experimental `experimental_useRealtime` (OpenAI, Google, xAI + Gateway) | | DevTools | Isomorphic in-app panel via TanStack DevTools (all frameworks, media previews) | `devToolsMiddleware` + local inspector (server-side, dev-only) | | Debug Logging | One flag, per-category toggles, pluggable logger | Warning logs + experimental telemetry hooks | | MCP Client | Standalone host-side client (`@tanstack/ai-mcp`) + provider-routed `mcpTool()` | Built-in (`@ai-sdk/mcp`, stable) | @@ -300,11 +309,152 @@ Vercel AI SDK 7 covers the core flow and adds one thing TanStack AI doesn't: `sp - `@tanstack/ai-vue` - `useChat` composable wraps `ChatClient` - `@tanstack/ai-svelte` - `createChat` wraps `ChatClient` (Svelte 5 runes) - `@tanstack/ai-preact` - `useChat` hook wraps `ChatClient` +- `@tanstack/ai-angular` - `injectChat` wraps `ChatClient` No framework-specific logic in the core. If a new framework emerges, it only needs a thin reactive wrapper. `ChatClient` also accepts a persistence adapter (`ChatClientPersistence`) for saving and restoring conversations client-side, and a typed runtime `context` that flows through to tools and middleware. +### Persistence + +A reload or a second device must not wipe the conversation. TanStack AI treats that as a first-class layer, not a guide you implement by hand. + +`withPersistence` writes the transcript, run status, and pending approvals into your store. The client has two modes: + +- **`persistence: true`** puts the server in charge. The browser caches nothing and asks the server for the thread on mount. +- **`persistence: `** puts the browser in charge, with `localStoragePersistence()`, `sessionStoragePersistence()`, or `indexedDBPersistence()`. + +```ts +import { chat, chatParamsFromRequest, toServerSentEventsResponse } from '@tanstack/ai' +import { openaiText } from '@tanstack/ai-openai' +import { withPersistence } from '@tanstack/ai-persistence' +import { persistence } from './persistence' + +export async function POST(request: Request) { + const params = await chatParamsFromRequest(request) + const stream = chat({ + adapter: openaiText('gpt-5.5'), + messages: params.messages, + threadId: params.threadId, + runId: params.runId, + middleware: [withPersistence(persistence)], + }) + return toServerSentEventsResponse(stream) +} +``` + +```tsx +import { fetchServerSentEvents, useChat } from '@tanstack/ai-react' + +function Chat() { + const { messages, sendMessage } = useChat({ + threadId: 'support-chat', + connection: fetchServerSentEvents('/api/chat'), + persistence: true, + }) + return +} +``` + +With `persistence: true`, add a `GET` that calls `reconstructChat`. That handler returns the stored transcript. If you also pass a durability adapter, the same `GET` can resume a run that is still streaming. See [Persistence](../persistence/overview). + +Vercel AI SDK documents message persistence as a pattern. You write `saveChat`, `loadChat`, and `validateUIMessages`. There is no middleware that owns the transcript for you. + +Long media runs (video, batch images) use a second middleware, `withGenerationPersistence`. A reload restores `status`, `result`, and `error` into the same generation hook. See [Generation Persistence](../persistence/generation-persistence). + +### Resumable Streams + +A dropped socket is a different problem from a missing transcript. The model already ran. You want the rest of the tokens, not a second bill. + +Pass a durability adapter to `toServerSentEventsResponse`. The adapter records every chunk before delivery. On reconnect the client sends the last offset and the server replays the log. + +- **`memoryStream`** from `@tanstack/ai` keeps the log in process memory. Use it in development. +- **`durableStream`** from `@tanstack/ai-durable-stream` writes to an external [Durable Streams](https://durablestreams.com) backend. Use it in production. + +`useChat` reconnects on its own. You add a `GET` that calls `resumeServerSentEventsResponse`. + +```ts +import { + chat, + chatParamsFromRequest, + memoryStream, + resumeServerSentEventsResponse, + toServerSentEventsResponse, +} from '@tanstack/ai' +import { openaiText } from '@tanstack/ai-openai' + +export async function POST(request: Request) { + const { messages, threadId, runId } = await chatParamsFromRequest(request) + const stream = chat({ + adapter: openaiText('gpt-5.5'), + messages, + threadId, + runId, + }) + return toServerSentEventsResponse(stream, { + durability: { adapter: memoryStream(request) }, + }) +} + +export function GET(request: Request) { + return resumeServerSentEventsResponse({ adapter: memoryStream(request) }) +} +``` + +In production, swap `memoryStream(request)` for `durableStream(request, options)`. Everything else stays the same. See [Resumable Streams](../resumable-streams/overview). + +Vercel AI SDK resume needs Redis, the `resumable-stream` package, an `activeStreamId` you store, and two routes you write. The SDK gives `resume` on `useChat` and a `consumeSseStream` callback. The store and the wiring stay yours. + +### Durable Sandbox Runs + +A coding agent can run for ten minutes. The tab will close. The wifi will drop. The next request can land on a different host. + +Without durability, TanStack AI destroys the sandbox on disconnect. That stops a runaway bill. With durability, the agent detaches, writes a journal at `/tmp/tanstack-runs/.ndjson`, and a later `GET` can take the run over. + +Turn it on with both `runs` and `durability` on `withSandbox`. Passing only one leaves the default destroy-on-disconnect behavior. + +```ts +import { + chat, + chatParamsFromRequest, + memoryStream, + toServerSentEventsResponse, +} from '@tanstack/ai' +import { withLocks } from '@tanstack/ai/locks' +import { claudeCodeText } from '@tanstack/ai-claude-code' +import { withPersistence } from '@tanstack/ai-persistence' +import { withSandbox } from '@tanstack/ai-sandbox' +import { locks } from './locks' +import { persistence } from './persistence' +import { sandbox } from './sandbox' + +export async function POST(request: Request) { + const { messages, threadId, runId } = await chatParamsFromRequest(request) + const adapter = memoryStream(request) + + const stream = chat({ + adapter: claudeCodeText('claude-opus-4-8'), + messages, + threadId, + runId, + middleware: [ + withPersistence(persistence), + withLocks(locks), + withSandbox(sandbox, { + runs: persistence.stores.runs, + durability: { adapter }, + }), + ], + }) + + return toServerSentEventsResponse(stream, { durability: { adapter } }) +} +``` + +Schedule the reaper, or sandboxes keep billing after no reader is left. Use a distributed lock across hosts. See [Durable Runs](../sandbox/durable-runs). + +Vercel AI SDK runs long harness work through experimental `HarnessAgent` and the Workflow SDK, centered on Vercel Sandbox. TanStack AI uses the same `chat()` + `withSandbox` path on every provider: local process, Docker, Docker Sandboxes, Daytona, Vercel, Sprites, or Cloudflare. + ### Connection Adapters TanStack AI ships six built-in connection adapters plus a custom adapter interface: @@ -438,22 +588,33 @@ TanStack AI is a pure library. There's no optional platform layer, no gateway ab This isn't just philosophical - it means no accidental dependencies on platform-specific features, no gateway abstractions that subtly encourage vendor adoption, and no marketing surface embedded in your technical stack. -### Code Execution Sandboxes +### Code Mode + +Code Mode lets the model write TypeScript that calls your tools inside a sandbox. One `execute_typescript` call can loop, branch, and `Promise.all` instead of one tool per turn. -TanStack AI provides four isolate drivers for safe code execution in AI workflows: +TanStack AI ships five isolate drivers behind one `IsolateDriver` interface: - **`@tanstack/ai-isolate-node`** - Node.js sandbox via `isolated-vm` -- **`@tanstack/ai-isolate-cloudflare`** - Cloudflare Workers sandbox -- **`@tanstack/ai-isolate-quickjs`** - QuickJS lightweight sandbox -- **`@tanstack/ai-isolate-quickjs-bun`** - Native QuickJS sandbox for Bun via `bun:ffi` +- **`@tanstack/ai-isolate-quickjs`** - QuickJS WASM (browsers and edge) +- **`@tanstack/ai-isolate-quickjs-bun`** - Native QuickJS on Bun via `bun:ffi` +- **`@tanstack/ai-isolate-cloudflare`** - Cloudflare Workers +- **`@tanstack/ai-isolate-daytona`** - Remote Daytona sandbox -All four implement the same `IsolateDriver` interface, so you can swap execution environments without changing application code. This powers TanStack AI's code mode - where the LLM writes and executes code as part of the agent loop. A companion `@tanstack/ai-code-mode-skills` package lets you give code mode a persistent, reusable library of runtime skills. Skills are LLM-writable: the model can save working TypeScript snippets, list and reuse them across sessions, with trust strategies controlling what gets promoted to a first-class tool. The closest AI SDK analogues - Anthropic's provider-hosted code execution and developer-uploaded skills, or pre-authored file skills loaded into a sandbox - are provider-specific and static; none give the model a persistent, provider-agnostic skill library it builds itself. +Swap the driver without changing application code. A companion `@tanstack/ai-code-mode-skills` package gives the model a persistent skill library. The model can save working TypeScript snippets, list them, and reuse them across sessions. Trust strategies control what gets promoted to a first-class tool. -Vercel AI SDK does not provide built-in code execution sandboxes (though some providers expose their own server-side code execution as provider-executed tools). +Vercel AI SDK now ships experimental `@ai-sdk/code-mode`. It runs QuickJS only, needs Node 22 or newer, and does not run in the browser or on the edge. Nested tool approvals are rejected. Provider-hosted code execution (Anthropic, xAI, OpenAI) is still a separate path. None of those give the model a persistent, provider-agnostic skill library it builds itself. See [Code Mode](../code-mode/code-mode). ### Coding Agent Sandboxes -Separately from the JS isolates above, TanStack AI can put a full **coding-agent CLI** — Claude Code, Codex, Grok Build, OpenCode, or any ACP-compliant agent — inside an isolated sandbox with a real filesystem, shell, and a cloned repo, and stream its work back through `chat()` like any other run. A sandboxed run composes three swappable pieces: a **provider** (where it runs), a **workspace** (what the agent sees), and a **harness adapter** (which agent runs). The sandbox is a `chat()` middleware, so the agent's edits and commands arrive as the same AG-UI stream every `useChat` UI already renders. +Separately from the JS isolates above, TanStack AI can put a full coding-agent CLI inside an isolated sandbox with a real filesystem, a shell, and a cloned repo. The agent can be Claude Code, Codex, Grok Build, OpenCode, or any ACP-compliant agent. Its work streams back through `chat()` like any other run. + +A sandboxed run composes three swappable pieces: + +- a **provider** (where it runs) +- a **workspace** (what the agent sees) +- a **harness adapter** (which agent runs) + +The sandbox is a `chat()` middleware, so the agent's edits and commands arrive as the same AG-UI stream every `useChat` UI already renders. ```ts import { chat } from '@tanstack/ai' @@ -481,10 +642,10 @@ const stream = chat({ Two axes are open where the AI SDK's is narrower: -- **Any agent, not a fixed list.** Grok Build, Claude Code, Codex, and OpenCode ship as first-party harness packages, and `acpCompatible` (from `@tanstack/ai-acp`) turns *any* [Agent Client Protocol](https://agentclientprotocol.com) agent — `pi`, `gemini --acp`, and [dozens of others](https://agentclientprotocol.com/get-started/agents) — into a harness by describing how to launch it. Adding an agent doesn't require a dedicated adapter to exist. -- **Any sandbox, not one cloud.** The same run executes on `localProcessSandbox` (host dev loop), `dockerSandbox` (real container isolation), Daytona, Vercel Sandbox, Sprites, or Cloudflare — swap the provider without touching the harness or workspace. Providers declare their `capabilities()` (`fs`, `exec`, `ports`, `snapshots`, `fork`, `durableFilesystem`, …) so code degrades gracefully across them. +- **Any agent, not a fixed list.** Grok Build, Claude Code, Codex, and OpenCode ship as first-party harness packages, and `acpCompatible` (from `@tanstack/ai-acp`) turns *any* [Agent Client Protocol](https://agentclientprotocol.com) agent (`pi`, `gemini --acp`, and [dozens of others](https://agentclientprotocol.com/get-started/agents)) into a harness by describing how to launch it. Adding an agent does not require a dedicated adapter to exist. +- **Any sandbox, not one cloud.** The same run executes on `localProcessSandbox` (host dev loop), `dockerSandbox` (container), `sbxSandbox` (Docker Sandboxes microVM), Daytona, Vercel Sandbox, Sprites, or Cloudflare. Swap the provider without touching the harness or workspace. Providers declare their `capabilities()` (`fs`, `exec`, `ports`, `snapshots`, `fork`, `durableFilesystem`, and more) so code degrades across them. -Vercel AI SDK 7 added a `HarnessAgent` API for the same idea — running a coding-agent harness in a sandbox and returning AI SDK-compatible `generate()` / `stream()` results. It's marked experimental, ships harnesses for Claude Code, Codex, Pi, OpenCode, and Deep Agents, and the documented path runs them in Vercel Sandbox. There's no generic ACP-compatible escape hatch (each supported harness is its own dedicated package), and sandbox support centers on Vercel's own microVM rather than a provider-swappable contract. +Vercel AI SDK 7 added an experimental `HarnessAgent` API for the same idea: run a coding-agent harness in a sandbox and return AI SDK `generate()` / `stream()` results. It ships adapters for Claude Code, Codex, Grok Build, OpenCode, Deep Agents, and Pi. The documented path runs them in Vercel Sandbox, with long work on the Workflow SDK. There is no generic ACP escape hatch (each supported harness is its own package), and sandbox support centers on Vercel's own microVM rather than a provider-swappable contract. See [Sandbox providers](../sandbox/providers) and [Harnesses](../sandbox/harnesses). ### Media Generation @@ -563,7 +724,7 @@ const result = await generateTranscription({ **Summarization** - `summarize()` is a dedicated activity with style control (`bullet-points`, `paragraph`, `concise`), focus topics, and streaming support. Vercel AI SDK has no equivalent - summarization requires calling `generateText()` with a prompt. -**Realtime voice** - `realtimeToken()` enables bidirectional audio streaming with Voice Activity Detection modes (server, semantic, manual), tool calling during voice sessions, and simultaneous audio + text output. Three providers ship realtime adapters: OpenAI (Realtime API), Grok, and ElevenLabs. Vercel AI SDK has no realtime/bidirectional voice primitive - its audio support is batch-only (`generateSpeech` and `transcribe`). +**Realtime voice** - `realtimeToken()` enables bidirectional audio streaming with Voice Activity Detection modes (server, semantic, manual), tool calling during voice sessions, and simultaneous audio + text output. Three providers ship realtime adapters: OpenAI (Realtime API), Grok, and ElevenLabs. Vercel AI SDK now ships experimental `experimental_useRealtime` for OpenAI, Google, and xAI (plus AI Gateway). TanStack AI's realtime adapters are stable and include ElevenLabs. All media activities follow the same adapter pattern as chat - tree-shakeable imports, per-model type safety, and streaming support. If your app only uses chat, none of this media code enters your bundle. @@ -575,7 +736,7 @@ Vercel AI SDK streams its own proprietary UI Message Stream protocol. AG-UI inte ### Hooks for Every Activity -Chat isn't the only activity with a hook. Every activity ships one - `useGeneration` (streaming structured output), `useGenerateImage`, `useGenerateAudio`, `useGenerateSpeech`, `useTranscription`, `useSummarize`, `useGenerateVideo`, and `useRealtimeChat` - with the same connection-adapter wiring and devtools integration as `useChat`, across React, Solid, Vue, Svelte, and Preact. +Chat isn't the only activity with a hook. Every activity ships one - `useGeneration` (streaming structured output), `useGenerateImage`, `useGenerateAudio`, `useGenerateSpeech`, `useTranscription`, `useSummarize`, `useGenerateVideo`, and `useRealtimeChat` - with the same connection-adapter wiring and devtools integration as `useChat`, across React, Solid, Vue, Svelte, Preact, and Angular. Vercel AI SDK's UI layer has three hooks: `useChat`, `useCompletion`, and `useObject`. Its media functions (`generateImage()`, `experimental_generateVideo()`, speech, transcription) are server-side only - surfacing them in a UI means hand-rolling your own routes and client state. @@ -591,17 +752,23 @@ Set `debug: true` on any activity and the pipeline prints itself: raw provider c ### Community Adapter Ecosystem -TanStack AI publishes an open adapter specification. The community has already built adapters for Decart, Cencori, Cloudflare, Soniox, and Mynth - with a [guide for building your own](../community-adapters/guide). The adapter interface is simple enough that adding a new provider is a focused, self-contained task. +TanStack AI publishes an open adapter specification. Official LLM adapters: + +- OpenAI, Anthropic, Gemini, Grok, Groq, OpenRouter, Ollama +- Bedrock, BytePlus, Mistral, Cohere, ElevenLabs, fal +- Vercel AI Gateway, and any OpenAI-compatible endpoint via `openaiCompatible` + +Harness adapters: Grok Build, Claude Code, Codex, OpenCode, and any ACP agent via `acpCompatible`. The community has already built adapters for Decart, Cencori, Cloudflare, Soniox, and Mynth, with a [guide for building your own](../community-adapters/guide). ## Where Vercel AI SDK Excels -**Provider breadth.** Vercel AI SDK ships ~38 first-party, individually typed provider packages, plus a large community list. If you want a specific provider as a dedicated, maintained package without writing an adapter, their coverage is broader today. Raw model *count* is not the differentiator, though - TanStack AI's OpenRouter adapter reaches OpenRouter's full catalog (several hundred models), and the `openaiCompatible` adapter connects to any OpenAI-compatible endpoint. +**Provider breadth.** Vercel AI SDK ships ~38 first-party, individually typed provider packages, plus a large community list. If you want a specific provider as a dedicated, maintained package without writing an adapter, their coverage is still broader today. Raw model *count* is not the differentiator: TanStack AI's OpenRouter adapter reaches OpenRouter's full catalog, the first-party Vercel Gateway adapter routes with one key, and `openaiCompatible` connects to any OpenAI-compatible endpoint. -**Angular support.** Vercel AI SDK has an official Angular integration. TanStack AI supports React, Solid, Svelte, Vue, and Preact, but not Angular. (Solid now cuts the other way: AI SDK's Solid package is community-maintained and pinned to an older SDK major, while TanStack AI ships an official, current Solid integration.) +**Solid vs Angular.** Both SDKs now ship official Angular. Solid still cuts the other way: AI SDK's Solid package is community-maintained and pinned to an older SDK major, while TanStack AI ships an official, current Solid integration. -**Agent abstraction.** Vercel AI SDK v6 ships a dedicated `Agent` abstraction (the `ToolLoopAgent` class) that packages a model, tools, instructions, and loop settings into a reusable object with `.generate()` and `.stream()` methods, plus `InferAgentUIMessage` for end-to-end type safety. TanStack AI composes these pieces per call rather than offering a single agent class. +**Agent abstraction.** Vercel AI SDK ships a dedicated `Agent` abstraction (the `ToolLoopAgent` class) that packages a model, tools, instructions, and loop settings into a reusable object with `.generate()` and `.stream()` methods, plus `InferAgentUIMessage` for end-to-end type safety. TanStack AI composes these pieces per call rather than offering a single agent class. -**AI Gateway.** Vercel's optional AI Gateway adds centralized provider management - failover routing, caching, and a single key across providers - integrated with the Vercel platform (and used by default when no provider is configured). TanStack AI ships no gateway of its own; for the same centralized routing across a large model catalog, it recommends its first-class OpenRouter adapter, with no platform association attached. +**AI Gateway.** Vercel's optional AI Gateway adds centralized provider management: failover routing, caching, and a single key across providers, integrated with the Vercel platform (and used by default when no provider is configured). TanStack AI ships no gateway of its own. For the same centralized routing, use the first-class [OpenRouter](../adapters/openrouter) adapter or the [Vercel AI Gateway](../adapters/vercel-gateway) adapter. Neither attaches a platform layer to the rest of your stack. **React Server Components.** Vercel AI SDK has an RSC integration via `@ai-sdk/rsc` (`AIState`, `StreamableValue`, `streamUI`). Note that Vercel documents this as experimental and recommends AI SDK UI for production - so it's an option for Next.js RSC apps rather than the primary path. @@ -662,6 +829,68 @@ const result = await generateText({ The TanStack approach separates the tool contract from its implementation, making tools reusable across server and client contexts. +### Persistence + +**TanStack AI** - Middleware writes the transcript. The client reloads it. + +```ts +import { chat, chatParamsFromRequest, toServerSentEventsResponse } from '@tanstack/ai' +import { openaiText } from '@tanstack/ai-openai' +import { withPersistence } from '@tanstack/ai-persistence' +import { persistence } from './persistence' + +export async function POST(request: Request) { + const params = await chatParamsFromRequest(request) + const stream = chat({ + adapter: openaiText('gpt-5.5'), + messages: params.messages, + threadId: params.threadId, + runId: params.runId, + middleware: [withPersistence(persistence)], + }) + return toServerSentEventsResponse(stream) +} +``` + +```tsx +import { fetchServerSentEvents, useChat } from '@tanstack/ai-react' + +const { messages, sendMessage } = useChat({ + threadId: 'support-chat', + connection: fetchServerSentEvents('/api/chat'), + persistence: true, +}) +``` + +**Vercel AI SDK** - You own `saveChat` / `loadChat` and call them from `onEnd`: + +```ts +import { convertToModelMessages, createUIMessageStreamResponse, streamText, toUIMessageStream } from 'ai' +import { loadChat, saveChat } from './chat-store' + +export async function POST(req: Request) { + const { message, id } = await req.json() + const messages = [...(await loadChat(id)), message] + + const result = streamText({ + model: 'openai/gpt-5.5', + messages: await convertToModelMessages(messages), + }) + + return createUIMessageStreamResponse({ + stream: toUIMessageStream({ + stream: result.stream, + originalMessages: messages, + onEnd: ({ messages: next }) => { + saveChat({ chatId: id, messages: next }) + }, + }), + }) +} +``` + +TanStack AI also persists run status and pending approvals, and it can restore a long media generation into the same hook fields. Vercel AI SDK leaves that wiring to you. Resume of a live stream is a separate layer on both sides: TanStack AI uses `StreamDurability`, Vercel AI SDK uses Redis plus `resumable-stream`. + ### Agent Loop Control **TanStack AI** - Composable strategies: @@ -726,25 +955,28 @@ In TanStack AI, each activity (chat, image, speech, video, transcription, summar - **Bundle size matters** - Tree-shakeable adapters per activity mean smaller bundles - **AG-UI native** - The wire protocol is AG-UI end to end; interoperate with the agent-UI ecosystem and non-TypeScript agent servers without a translation layer -- **Solid, Preact, or React Native** - One headless core covers React, Solid, Vue, Svelte, Preact, and React Native (via XHR adapters), all officially maintained +- **Solid, Preact, Angular, or React Native** - One headless core covers React, Solid, Vue, Svelte, Preact, Angular, and React Native (via XHR adapters), all officially maintained - **Hooks beyond chat** - `useGeneration`, `useGenerateImage`, `useSummarize`, and the rest of the generation hook family across every supported framework - **Isomorphic tools** - Define a tool once and derive `.server()` / `.client()` implementations from one contract - **App-level middleware** - Lifecycle hooks for chunks, tool calls, usage, and errors - not just model wrapping -- **Realtime voice** - Bidirectional audio across OpenAI, Grok, and ElevenLabs +- **Chat and generation persistence** - `withPersistence` plus `reconstructChat`, or a browser store; long media runs restore through `withGenerationPersistence` +- **Resumable streams** - A durability adapter on the response; `useChat` reconnects without Redis +- **Durable sandbox runs** - Detach, journal, takeover, and reaper so a coding agent survives a closed tab +- **Realtime voice** - Stable bidirectional audio across OpenAI, Grok, and ElevenLabs - **No vendor association** - Pure library with no platform layer - **Per-model type safety** - TypeScript narrows options per model, not per provider -- **Code execution** - Built-in sandboxed execution environments -- **Coding agent sandboxes** - Run Claude Code, Codex, Grok Build, OpenCode, or any ACP agent in a swappable sandbox (local, Docker, Daytona, Vercel, Sprites, Cloudflare), streamed through `chat()` +- **Code Mode** - Five isolate drivers (Node, QuickJS WASM, QuickJS Bun, Cloudflare, Daytona) plus an LLM-writable skill library +- **Coding agent sandboxes** - Run Claude Code, Codex, Grok Build, OpenCode, or any ACP agent in a swappable sandbox (local, Docker, Docker Sandboxes, Daytona, Vercel, Sprites, Cloudflare), streamed through `chat()` - **Flexible transport** - SSE, HTTP streams, XHR, RPC, direct iterables, or custom adapters - **MCP, two ways** - A standalone host-side client (`@tanstack/ai-mcp`) with pools, codegen, and managed `chat()` lifecycle, plus a provider-routed `mcpTool()` ## When to Choose Vercel AI SDK -- **Need a first-party package for a specific provider** - ~38 dedicated, individually typed provider packages today (TanStack reaches comparable model breadth via OpenRouter + `openaiCompatible`) -- **Angular support** - Official Angular integration +- **Need a first-party package for a specific provider** - ~38 dedicated, individually typed provider packages today (TanStack reaches comparable model breadth via OpenRouter, Vercel Gateway, and `openaiCompatible`) - **Agent abstraction** - A reusable `Agent` (`ToolLoopAgent`) class with end-to-end UI message types - **Vercel platform** - AI Gateway, observability, and deployment optimization - **React Server Components** - RSC primitives via `@ai-sdk/rsc` (experimental; AI SDK UI is the recommended production path) +- **Workflow-backed long runs on Vercel** - experimental `HarnessAgent` plus the Workflow SDK, if your stack is already that platform ## Getting Started diff --git a/kiira.config.ts b/kiira.config.ts index 159fba800a..6e1fb6c393 100644 --- a/kiira.config.ts +++ b/kiira.config.ts @@ -27,12 +27,13 @@ export default defineConfig({ // AI SDK migration, community adapters, redis/pino/otel/express/hono, other // schema libs) are validated instead of `ignore`d. externalPackages: { - // Vercel AI SDK (migration / comparison "before" examples) - ai: '^6.0.0', - '@ai-sdk/openai': '^3.0.0', - '@ai-sdk/anthropic': '^3.0.0', - '@ai-sdk/google': '^3.0.0', - '@ai-sdk/react': '^3.0.0', + // Vercel AI SDK (comparison is v7; migration "before" fences stay on + // APIs that v7 still exports, including deprecated aliases) + ai: '^7.0.0', + '@ai-sdk/openai': '^4.0.0', + '@ai-sdk/anthropic': '^4.0.0', + '@ai-sdk/google': '^4.0.0', + '@ai-sdk/react': '^4.0.0', // Provider SDKs / schema libraries shown in examples openai: '^6.0.0', arktype: '^2.0.0',