본문으로 건너뛰기

TanStack AI와 Vercel AI SDK 비교

TanStack AI와 Vercel AI SDK는 모두 AI 기반 애플리케이션을 구축하기 위한 오픈 소스 TypeScript 툴킷입니다. 스트리밍 채팅, 도구 호출, 다중 프로바이더 지원, 어디서나 배포할 수 있는 유연성을 공유하지만, 문제에 접근하는 방향은 근본적으로 다릅니다.

TanStack AI는 AI를 라이브러리 조합 문제로 다룹니다. 어댑터, 도구, 에이전트 루프, 전송, UI 등 모든 요소가 조합 가능한 구성 블록입니다. 필요한 것을 가져와 원하는 방식으로 조합하고 원하는 곳에 배포합니다. 플랫폼 계층, 게이트웨이 추상화, 암묵적인 연계가 없습니다.

Vercel AI SDK는 AI를 풀스택 플랫폼 문제로 다룹니다. 게이트웨이 라우팅, 옵저버빌리티, 배포 최적화를 위한 선택적 플랫폼 통합과 함께 폭넓은 기본 요소를 제공합니다.

이 문서에서는 TanStack AI의 관점에서 두 SDK를 비교하고, 각각이 뛰어난 부분을 솔직하게 설명합니다.

기능 비교

아래에서 참조하는 버전은 이 문서를 작성한 시점의 TanStack AI와 Vercel AI SDK ai@7.x(현재 v7)입니다.

기능TanStack AIVercel AI SDK
라이선스MITApache 2.0
호스팅어디서나 작동어디서나 작동
프로바이더공식 LLM 어댑터 16개(OpenAI, Anthropic, Gemini, Vertex, Grok, Groq, OpenRouter, Ollama, Bedrock, BytePlus, Mistral, Cohere, ElevenLabs, fal, Vercel Gateway, openaiCompatible)와 하네스 어댑터 5개, 그리고 추가 커뮤니티 어댑터퍼스트파티 프로바이더 패키지 약 38개(커뮤니티 패키지 포함), AI Gateway를 통한 100개 이상의 모델
프레임워크 훅React, Solid, Svelte, Vue, Preact, Angular (+ React Native)React, Vue, Svelte, Angular (Solid는 커뮤니티에서 유지 관리)
생성 UI 훅활동별 훅 하나: 채팅, 구조화된 출력, 이미지, 오디오, 음성, 전사, 요약, 비디오, 실시간useChat, useCompletion, useObject
유선 프로토콜종단 간 네이티브 AG-UI 이벤트독점 UI Message Stream; 외부 변환 계층을 통한 AG-UI
스트리밍청크 전략을 설정할 수 있는 기본 제공 기능점진적 전달을 지원하는 기본 제공 기능
채팅 영속성withPersistence 미들웨어 + reconstructChat, 서버 저장소 또는 브라우저 저장소(localStorage, sessionStorage, IndexedDB)가이드: saveChat / loadChat / validateUIMessages를 직접 구현합니다
생성 영속성withGenerationPersistence가 장시간 미디어 실행을 동일한 훅 필드로 복원합니다-
재개 가능한 스트림코어의 StreamDurability, memoryStream 또는 durableStream, useChat의 자체 재연결Redis + resumable-stream + activeStreamId, POST와 GET을 직접 연결합니다
내구성 있는 샌드박스 실행분리, 저널, 인계, 리퍼를 지원하며 탭이 닫힌 뒤에도 에이전트가 계속 작업합니다HarnessAgent + Workflow SDK(실험적), Vercel Sandbox 중심
도구 호출동형 .server() / .client() 시스템tool() 객체; onToolCall을 통한 클라이언트 실행
에이전트 루프 제어조합 가능한 전략 함수 (state) => booleanstopWhen 조건 + Agent (ToolLoopAgent) 클래스
도구 승인도구별 needsApproval 및 일괄 승인 흐름도구별 needsApproval (human-in-the-loop)
타입 안전성모델별 타입 좁히기프로바이더별 타입
트리 셰이킹활동별 별도 어댑터(텍스트, 이미지, 음성 등)단일형 프로바이더 패키지
지연 도구 탐색기본 제공되며 모든 프로바이더에서 작동합니다deferLoading을 사용하는 Anthropic 전용 도구 검색(프로바이더 호스팅)
연결 어댑터SSE, HTTP 스트림, XHR(SSE/스트림), RPC, 직접 async iterable, fetcher, 사용자 지정SSE 기반 데이터 스트림 프로토콜(ChatTransport)
미들웨어앱 수준 수명 주기 훅(구성, 반복, 청크, 도구 호출, 사용량, 오류)wrapLanguageModel()을 통한 모델 수준 래핑
어댑터 확장모델별 타입 좁히기를 적용한 사용자 지정/파인튜닝 모델 추가customProvider() / createProviderRegistry()(문자열 모델 ID)
구조화된 출력타입이 지정된 StructuredOutputPart를 도구와 함께 스트리밍하고 메시지 기록에 턴별로 보존generateObject() / streamObject() / Output API(호출별, 구조화된 출력을 위한 메시지 파트 없음)
이미지 생성모델별 타입 안전성을 제공하는 안정적인 API(OpenAI, Gemini, Grok, OpenRouter, fal.ai)generateImage()(안정적)
비디오 생성비동기 작업 수명 주기를 제공하는 안정적인 API(OpenAI, fal.ai)experimental_generateVideo()
텍스트 음성 변환안정적인 API, 6개 출력 형식, 속도 제어(OpenAI, Gemini, Grok, ElevenLabs, fal.ai)generateSpeech()(실험적)
전사단어 타임스탬프와 화자 분리를 제공하는 안정적인 API(OpenAI, Grok, ElevenLabs, fal.ai)transcribe()(실험적)
오디오 / 음악 생성음악 및 음향 효과를 위한 generateAudio()(Gemini, ElevenLabs, fal.ai)-
요약스트리밍과 스타일 옵션을 제공하는 전용 summarize()-
코드 모드직접 실행하는 격리 드라이버 5개: Node isolated-vm, QuickJS WASM, QuickJS Bun, Cloudflare, Daytona실험적인 @ai-sdk/code-mode(QuickJS 전용, Node 22 이상, 브라우저나 엣지에서는 실행되지 않음), 프로바이더 호스팅 코드 실행 도구도 제공
코드 모드 스킬LLM이 작성할 수 있는 영속적 스킬 라이브러리정적 스킬 업로드, 모델이 구축하는 라이브러리 없음
코딩 에이전트 샌드박스퍼스트파티 Grok Build, Claude Code, Codex, OpenCode + acpCompatible을 통한 모든 ACP 에이전트, 로컬 프로세스, Docker, Docker Sandboxes(sbx), Daytona, Vercel, Sprites, CloudflareHarnessAgent(실험적): Claude Code, Codex, Grok Build, OpenCode, Deep Agents, Pi, Vercel Sandbox 중심
실시간 음성안정적: VAD 모드와 도구 지원을 제공하는 OpenAI, Grok, ElevenLabs실험적인 experimental_useRealtime(OpenAI, Google, xAI + Gateway)
DevToolsTanStack DevTools를 통한 동형 인앱 패널(모든 프레임워크, 미디어 미리 보기)devToolsMiddleware + 로컬 인스펙터(서버 측, 개발 전용)
디버그 로깅플래그 하나, 카테고리별 토글, 플러그형 로거경고 로그 + 실험적 텔레메트리 훅
MCP 클라이언트독립형 호스트 측 클라이언트(@tanstack/ai-mcp) + 프로바이더 라우팅 mcpTool()기본 제공(@ai-sdk/mcp, 안정적)
MCP 앱(대화형 위젯)ui:// 위젯을 @mcp-ui/client를 통해 제공하며, React + Preact + 프레임워크 독립 브리지, 다중 서버 라우팅, 플러그형 세션 저장소, 링크 스킴 강화를 지원합니다experimental_MCPAppRenderer(React 전용), 모델용 도구와 앱용 도구 분리, iframe 샌드박스 + 허용 목록
플랫폼 연계없음 - 순수 라이브러리선택적 Vercel 통합

TanStack AI가 뛰어난 부분

모델별 타입 안전성

프로바이더와 모델을 선택하면 TypeScript가 프로바이더가 지원하는 모든 항목의 유니온이 아니라 해당 모델에서 사용할 수 있는 정확한 옵션, 기능, 입력 양식으로 타입을 좁힙니다.

각 프로바이더 어댑터에는 모든 모델을 지원되는 입력 양식, 컨텍스트 윈도우, 프로바이더별 옵션 등의 기능에 매핑하는 포괄적인 model-meta.ts가 포함됩니다. openaiText('gpt-5.5')를 작성하면 타입 시스템이 해당 모델이 정확히 무엇을 할 수 있는지 파악합니다.

import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// TypeScript knows gpt-5.5 supports text + image input
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages: [{
role: 'user',
content: [
{ type: 'text', content: 'What is in this image?' },
{ type: 'image', source: { type: 'url', value: 'https://example.com/photo.jpg' } },
],
}],
})

텍스트 전용 모델에 이미지 콘텐츠 파트를 전달하면 TypeScript가 컴파일 시점에 이를 감지합니다.

트리 셰이킹 가능한 어댑터

각 AI 활동(채팅, 요약, 이미지 생성, 음성, 전사, 비디오)은 별도의 import입니다. 각 프로바이더는 활동별로 별도의 어댑터 함수를 제공합니다. 앱에서 채팅만 사용하면 이미지 생성 코드는 번들에 포함되지 않습니다.

// Only chat code is bundled - nothing else
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

// vs. importing activities you actually need
import { chat, generateImage } from '@tanstack/ai'
import { openaiText, openaiImage } from '@tanstack/ai-openai'

이는 우연한 동작이 아니라 아키텍처에 따른 동작입니다. 각 어댑터는 특정 인터페이스(TextAdapter, ImageAdapter, TTSAdapter 등)를 구현하고 자체 모듈에 존재합니다. 최신 번들러는 import하지 않은 모든 항목을 제거합니다.

동형 도구

toolDefinition()은 이름, 설명, 입력 스키마, 출력 스키마로 구성된 공유 계약을 만들며, 이를 다양한 런타임에 구현할 수 있습니다. .server()는 데이터베이스와 API에 접근하는 서버 측 구현을 추가합니다. .client()는 브라우저에서 실행되는 클라이언트 측 구현을 추가합니다.

import { toolDefinition } from '@tanstack/ai'
import { z } from 'zod'
import { db } from './db'

// Define once - shared validation contract
const addToCartDef = toolDefinition({
name: 'addToCart',
description: 'Add an item to the shopping cart',
inputSchema: z.object({
itemId: z.string(),
quantity: z.number(),
}),
outputSchema: z.object({
success: z.boolean(),
cartId: z.string(),
}),
})

// Server implementation - database access
const addToCartServer = addToCartDef.server(async ({ itemId, quantity }) => {
const cart = await db.carts.addItem(itemId, quantity)
return { success: true, cartId: cart.id }
})

// Client implementation - runs in the browser
const addToCartClient = addToCartDef.client(async ({ itemId, quantity }) => {
const res = await fetch(`/api/cart`, {
method: 'POST',
body: JSON.stringify({ itemId, quantity }),
})
return res.json()
})

동일한 스키마가 양쪽의 입력과 출력을 검증합니다. 타입 시스템은 컴파일 시점에 도구가 ServerTool인지 ClientTool인지 추적합니다.

Vercel AI SDK는 tool() 헬퍼로 도구를 정의하며 클라이언트 측 실행도 지원합니다. execute 함수가 없는 도구는 UI 훅의 onToolCall 콜백을 통해 브라우저에서 처리되고, 결과는 addToolOutput을 통해 반환됩니다(v6에서 addToolResult에서 이름이 변경됨). 다만 하나의 공유 계약에서 별도의 .server().client() 구현을 생성하는 기능은 없습니다. 서버와 클라이언트 도구 코드는 하나의 정의에서 파생되지 않고 독립적으로 선언됩니다.

조합 가능한 에이전트 루프 전략

TanStack AI는 조합 가능한 순수 함수로 에이전트 루프를 제어합니다. 각 전략은 (state) => boolean이며, 계속하려면 true, 중지하려면 false를 반환합니다.

import { chat, maxIterations, untilFinishReason, combineStrategies } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { tools } from './tools'

const messages = [{ role: 'user' as const, content: 'Help me plan a trip.' }]

const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
tools,
agentLoopStrategy: combineStrategies([
maxIterations(10),
untilFinishReason(['stop', 'length']),
]),
})

combineStrategies는 AND 논리로 전략을 조합하므로 모든 전략이 계속하는 데 동의해야 합니다. 기본 제공 전략과 함께 사용자 지정 전략을 추가할 수 있습니다.

import { maxIterations, untilFinishReason, combineStrategies } from '@tanstack/ai'
import { estimatedCost, budget } from './cost'

combineStrategies([
maxIterations(10),
untilFinishReason(['stop']),
// Custom: stop if budget exceeded
({ iterationCount }) => estimatedCost(iterationCount) < budget,
])

Vercel AI SDK(v5+)는 stopWhen을 통해 에이전트 루프를 제어합니다. stopWhen은 stepCountIs(n)hasToolCall(name)과 같은 조합 가능한 중지 조건을 받으며(기본값은 stepCountIs(20)), v6에서는 모델, 도구, 지침, 루프 설정을 재사용 가능한 객체로 묶는 전용 Agent 추상화(ToolLoopAgent 클래스)를 추가합니다. 남은 차이는 조합 모델에 있습니다. TanStack AI의 전략은 인라인으로 작성하고 combineStrategies로 결합하는 임의의 (state) => boolean 조건자이므로, 기본 제공 조건을 기다리지 않고 중지 조건에 모든 비즈니스 로직(토큰 예산, 비용 상한, 사용자 지정 상태 검사)을 표현할 수 있습니다. Vercel의 stopWhen도 사용자 지정 함수를 받으므로 이 차이는 예전보다 작습니다.

지연 도구 탐색

애플리케이션에 도구가 수십 개 있으면 모든 요청에서 해당 스키마를 LLM에 보내는 일이 토큰을 낭비합니다. TanStack AI는 지연 도구 탐색으로 이 문제를 해결합니다.

도구를 lazy: true로 표시하면 처음에는 LLM에 전송되지 않습니다. 대신 LLM이 필요할 때 도구 스키마를 요청할 수 있도록 합성 탐색 도구가 주입됩니다.

import { toolDefinition } from '@tanstack/ai'
import { z } from 'zod'

const searchProducts = toolDefinition({
name: 'searchProducts',
description: 'Search the product catalog',
lazy: true, // Not sent to LLM initially
inputSchema: z.object({ query: z.string() }),
outputSchema: z.array(z.object({ id: z.string(), name: z.string() })),
})

LLM에는 사용 가능한 도구 이름을 나열하는 가벼운 __lazy__tool__discovery__ 도구가 표시됩니다. 도구가 필요하면 탐색 도구를 호출해 전체 스키마를 가져온 다음 실제 도구를 사용합니다. 도구 목록이 큰 애플리케이션에서는 요청별 토큰 비용을 크게 줄입니다.

Vercel AI SDK 6은 Anthropic을 위한 프로바이더별 유사 기능인 도구 검색 프로바이더 도구(toolSearchBm25 / toolSearchRegex)를 추가했습니다. 도구별 deferLoading을 사용하며, 지연된 도구는 초기 프롬프트에서 제외되고 필요할 때 탐색됩니다. 이는 Anthropic 전용이며 프로바이더 측에서 실행됩니다. TanStack AI의 지연 탐색은 모든 프로바이더에서 작동하고 자체 에이전트 루프에서 실행됩니다.

모델 컨텍스트 프로토콜 (MCP)

TanStack AI는 두 가지 방식으로 MCP 서버에 연결하며, 하나의 chat() 실행에서 두 방식을 함께 사용할 수 있습니다.

  • 호스트 측 클라이언트 (@tanstack/ai-mcp) - 서버가 모든 MCP 서버에 직접 연결합니다. createMCPClient(단일 서버)와 createMCPClients(다중 서버 풀)는 OAuth 2.1(authProvider) 및 정적 토큰 인증과 함께 Streamable HTTP, SSE 또는 stdio 전송을 통해 도구를 탐색하고 실행하며 리소스를 읽고 프롬프트를 가져옵니다.
  • 프로바이더 라우팅 (mcpTool()) - 프로바이더가 서버를 대신해 MCP 서버에 연결하므로(OpenAI Responses API, Anthropic) MCP 트래픽이 서버를 전혀 통과하지 않습니다.

호스트 측 클라이언트는 기본 탐색 이상의 기능을 제공합니다.

  • 관리되는 수명 주기 - mcp 옵션을 통해 클라이언트를 chat()에 전달하면 도구를 탐색하고 실행 종료 시 연결을 닫으므로 경로마다 try/finally를 작성할 필요가 없습니다.
  • 다중 서버 풀 - createMCPClients는 여러 서버에 병렬로 연결하고 이름 충돌을 방지하도록 각 서버의 도구에 자동으로 접두사를 붙입니다.
  • 세 가지 타입 안전성 모드 - 타입이 지정되지 않은 자동 탐색, Zod 검증을 적용한 toolDefinition() 기반 허용 목록, 또는 tanstack-ai-mcp CLI를 통한 서버별 완전 생성 타입을 제공합니다.
  • 지연 탐색 - tools({ lazy: true })는 도구 스키마 전송을 LLM에 지연하고 TanStack AI의 지연 도구 탐색과 연결하여 도구가 많은 서버의 토큰 사용량을 줄입니다.
  • 리소스 및 프롬프트 - mcpResourceToContentPartmcpPromptToMessages를 사용해 MCP 리소스와 프롬프트를 실행에 주입합니다.
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { createMCPClient } from '@tanstack/ai-mcp'

const messages = [{ role: 'user' as const, content: 'What tools are available?' }]

const mcp = await createMCPClient({
transport: { type: 'http', url: 'https://my-mcp-server.example.com/mcp' },
})

// chat() discovers the tools and closes the client when the run ends
const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
mcp: { clients: [mcp] },
})

Vercel AI SDK의 @ai-sdk/mcp(createMCPClient)는 HTTP/SSE 전송, OAuth, 리소스 읽기, 프롬프트 템플릿을 제공하는 안정적인 호스트 측 클라이언트입니다. TanStack AI의 @tanstack/ai-mcp는 이 기능 범위를 제공하면서 생성된 엔드투엔드 타입, 다중 서버 풀, 지연 탐색, 관리되는 chat() 수명 주기, 프로바이더 라우팅 mcpTool() 대안을 추가합니다.

MCP 앱(대화형 위젯)

두 SDK 모두 MCP Apps를 구현합니다. 이는 서버가 ui:// 리소스를 반환하여 도구 결과를 원시 JSON 대신 샌드박스 iframe의 대화형 위젯으로 렌더링하는 비준된 MCP 확장(2026-01-26 표준화)입니다. 두 SDK 모두 위젯 HTML을 모델 입력에서 제외하고 도구 허용 목록과 안전한 링크 처리를 적용한 샌드박스 iframe에 렌더링합니다. TanStack AI 구현은 다음 세 가지 측면에서 더 확장되어 있습니다.

  • 둘 이상의 프레임워크. 위젯은 @tanstack/ai-react/mcp-apps@tanstack/ai-preact/mcp-apps를 통해 렌더링되며, 위젯 동작을 라우팅하는 브리지(createMcpAppBridge)는 프레임워크 독립적인 @tanstack/ai-client에 있으므로 새 프레임워크에는 얇은 렌더러만 필요합니다. Vercel의 experimental_MCPAppRenderer와 브리지는 @ai-sdk/react에 있으며 React만 지원합니다.
  • 다중 서버 라우팅.UIResourcePartserverId(createMCPClients의 풀 접두사)를 포함하며, 대화형 호출은 위젯을 생성한 정확한 서버로 돌아갑니다. 다중 서버 풀을 실행하면 자동으로 처리됩니다. 호출 핸들러는 선택적 allowTool 제한을 추가로 AND 적용하면서 무조건적인 동일 서버 노출 검사도 시행합니다(toolName은 해당 서버가 실제로 노출하는 도구여야 함).
  • 세션 영속성 및 서버리스 안전성. 호출 핸들러는 전송 설명자에서 호출마다 재연결하며(상태 비저장, 기본적으로 서버리스 안전), 상태 저장 전송은 플러그형 McpSessionStore를 선택할 수 있습니다. inMemoryMcpSessionStore가 제공되며 SQL/KV 백엔드는 동일한 인터페이스 뒤에 연결됩니다.
import { useChat, useMcpAppBridge } from '@tanstack/ai-react'
import { fetchServerSentEvents } from '@tanstack/ai-client'
import { MCPAppResource } from '@tanstack/ai-react/mcp-apps'

export function Chat() {
const { messages, sendMessage } = useChat({
connection: fetchServerSentEvents('/api/chat'),
})

// Routes widget tool-calls to /api/mcp-apps/call by serverId; only http/https/mailto links pass through.
const bridge = useMcpAppBridge({
threadId: 'weather-chat',
callEndpoint: '/api/mcp-apps/call',
chat: { sendMessage: async (content) => void sendMessage({ content }) },
onLink: (url) => window.open(url, '_blank', 'noopener'),
})

return (
<>
{messages.map((m) =>
m.parts.map((part, i) =>
part.type === 'ui-resource' ? (
<MCPAppResource
key={i}
part={part}
bridge={bridge}
sandbox={{ url: new URL('https://your-app.example.com/mcp-sandbox.html') }}
/>
) : null,
),
)}
</>
)
}

Vercel AI SDK 7은 핵심 흐름을 지원하고 TanStack AI에는 없는 기능인 splitMCPAppTools를 추가합니다. 이 기능은 위젯이 호출할 수 있지만 모델에는 표시되지 않는 앱 전용 도구와 모델에 표시되는 도구를 분리합니다. 두 구현 모두 새 기능입니다. Vercel은 렌더러를 experimental_로 표시하며, TanStack AI에서 위젯 도구 호출을 채팅 기록에 다시 기록하는 기능은 아직 범위에 포함되지 않습니다. 전체 API는 MCP Apps 가이드를 참조하세요.

헤드리스 클라이언트 아키텍처

ChatClient는 스트리밍, 메시지 상태, 도구 실행, 승인 흐름, 연결 관리를 비롯한 전체 채팅 수명 주기를 관리하는 프레임워크 독립 클래스입니다. 모든 프레임워크 통합은 이 단일 클라이언트를 래핑합니다.

  • @tanstack/ai-react - useChat 훅이 ChatClient 를 감쌉니다
  • @tanstack/ai-solid - useChat 훅이 ChatClient 를 감쌉니다
  • @tanstack/ai-vue - useChat 컴포저블이 ChatClient 를 감쌉니다
  • @tanstack/ai-svelte - createChatChatClient 을 감쌉니다 (Svelte 5 runes)
  • @tanstack/ai-preact - useChat 훅이 ChatClient 를 감쌉니다
  • @tanstack/ai-angular - injectChatChatClient 를 감쌉니다

코어에는 프레임워크별 로직이 없습니다. 새로운 프레임워크가 등장하면 얇은 반응형 래퍼만 추가하면 됩니다.

ChatClient는 클라이언트 측에서 대화를 저장하고 복원하기 위한 영속성 어댑터(ChatClientPersistence)와 도구 및 미들웨어로 전달되는 타입 지정 런타임 context도 받습니다.

영속성

새로고침이나 두 번째 기기 사용으로 대화가 삭제되어서는 안 됩니다. TanStack AI는 이를 직접 구현해야 하는 가이드가 아니라 핵심 계층으로 취급합니다.

withPersistence는 대화 기록, 실행 상태, 대기 중인 승인을 저장소에 기록합니다. 클라이언트에는 두 가지 모드가 있습니다.

  • **persistence: true**는 서버가 관리하도록 합니다. 브라우저는 아무것도 캐시하지 않고 마운트 시 서버에 스레드를 요청합니다.
  • **persistence: <adapter>**는 브라우저가 관리하도록 하며 localStoragePersistence(), sessionStoragePersistence(), indexedDBPersistence()를 사용할 수 있습니다.
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)
}
import { fetchServerSentEvents, useChat } from '@tanstack/ai-react'

function Chat() {
const { messages, sendMessage } = useChat({
threadId: 'support-chat',
connection: fetchServerSentEvents('/api/chat'),
persistence: true,
})
return <button onClick={() => sendMessage('hi')}>{messages.length}</button>
}

persistence: true를 사용하면 reconstructChat을 호출하는 GET을 추가합니다. 이 핸들러는 저장된 대화 기록을 반환합니다. 내구성 어댑터도 전달하면 동일한 GET으로 아직 스트리밍 중인 실행을 재개할 수 있습니다. 영속성을 참조하세요.

Vercel AI SDK는 메시지 영속성을 패턴으로 문서화합니다. saveChat, loadChat, validateUIMessages를 직접 작성해야 하며, 대화 기록을 대신 관리하는 미들웨어는 없습니다.

장시간 미디어 실행(비디오, 이미지 일괄 처리)에는 두 번째 미들웨어인 withGenerationPersistence를 사용합니다. 새로고침하면 동일한 생성 훅에 status, result, error가 복원됩니다. 생성 영속성을 참조하세요.

재개 가능한 스트림

끊어진 소켓은 누락된 대화 기록과는 다른 문제입니다. 모델 실행은 이미 완료되었습니다. 두 번째 비용이 발생하는 재실행이 아니라 남은 토큰을 원하게 됩니다.

toServerSentEventsResponse에 내구성 어댑터를 전달합니다. 어댑터는 전달 전에 모든 청크를 기록합니다. 재연결 시 클라이언트가 마지막 오프셋을 보내면 서버가 로그를 재생합니다.

  • **memoryStream**은 @tanstack/ai에서 제공하며 로그를 프로세스 메모리에 보관합니다. 개발 환경에서 사용하세요.
  • **durableStream**은 @tanstack/ai-durable-stream에서 제공하며 외부 Durable Streams 백엔드에 기록합니다. 프로덕션에서 사용하세요.

useChat은 자체적으로 재연결합니다. resumeServerSentEventsResponse를 호출하는 GET을 추가합니다.

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) })
}

프로덕션에서는 memoryStream(request)durableStream(request, options)으로 교체합니다. 나머지는 동일합니다. 재개 가능한 스트림을 참조하세요.

Vercel AI SDK에서 재개하려면 Redis, resumable-stream 패키지, 저장할 activeStreamId, 직접 작성하는 두 개의 경로가 필요합니다. SDK는 useChatresumeconsumeSseStream 콜백을 제공합니다. 저장소와 연결 작업은 직접 관리해야 합니다.

내구성 있는 샌드박스 실행

코딩 에이전트는 10분 동안 실행될 수 있습니다. 탭은 닫히고 Wi-Fi는 끊기며 다음 요청은 다른 호스트에 도착할 수 있습니다.

내구성이 없으면 TanStack AI는 연결이 끊길 때 샌드박스를 삭제합니다. 이를 통해 통제되지 않는 비용 발생을 막습니다. 내구성을 사용하면 에이전트가 분리되고 /tmp/tanstack-runs/<runId>.ndjson에 저널을 기록하며, 이후의 GET이 실행을 인계할 수 있습니다.

withSandboxrunsdurability를 모두 설정해 활성화합니다. 하나만 전달하면 연결 해제 시 삭제되는 기본 동작이 유지됩니다.

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 } })
}

리퍼를 예약하지 않으면 읽는 주체가 없어도 샌드박스에 계속 비용이 청구됩니다. 호스트 간에 분산 잠금을 사용하세요. 내구성 있는 실행을 참조하세요.

Vercel AI SDK는 Vercel Sandbox를 중심으로 실험적인 HarnessAgent와 Workflow SDK를 통해 장시간 하네스 작업을 실행합니다. TanStack AI는 모든 프로바이더에서 동일한 chat() + withSandbox 경로를 사용합니다. 로컬 프로세스, Docker, Docker Sandboxes, Daytona, Vercel, Sprites 또는 Cloudflare에서 실행할 수 있습니다.

연결 어댑터

TanStack AI는 6개의 기본 제공 연결 어댑터와 사용자 지정 어댑터 인터페이스를 제공합니다.

import {
fetchServerSentEvents,
fetchHttpStream,
xhrServerSentEvents,
xhrHttpStream,
stream,
rpcStream,
} from '@tanstack/ai-client'
import { chatOnServer } from './server'
import { api } from './api'

// Server-Sent Events (standard)
fetchServerSentEvents('/api/chat')

// Raw HTTP streaming (newline-delimited JSON)
fetchHttpStream('/api/chat')

// XHR-based SSE / HTTP streaming (React Native / Expo, where fetch streaming is unavailable)
xhrServerSentEvents('/api/chat')
xhrHttpStream('/api/chat')

// Direct async iterables (TanStack Start server functions)
stream((messages) => chatOnServer({ messages }))

// RPC-based transport
rpcStream((messages, data) => api.streamResponse(messages, data))

// Or implement your own ConnectionAdapter

각 어댑터는 정적 또는 동적(함수 기반) URL과 옵션을 받습니다. 전체 어댑터 없이 서버 함수를 직접 연결할 수 있도록 ChatClient / useChat에 더 가벼운 fetcher 옵션도 있습니다. 애플리케이션 코드를 변경하지 않고 전송을 교체할 수 있습니다. Vercel AI SDK는 SSE 기반 데이터 스트림 프로토콜과 확장성을 위한 ChatTransport 인터페이스를 중심으로 하지만 동일한 폭의 기본 제공 어댑터, 특히 React Native용 XHR 변형은 제공하지 않습니다.

어댑터 확장

파인튜닝 모델, OpenAI 호환 프록시 또는 사용자 지정 모델 엔드포인트를 사용할 때 extendAdapter()를 사용하면 완전한 타입 안전성을 유지하면서 모든 프로바이더 어댑터에 이를 추가할 수 있습니다.

import { extendAdapter, createModel } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

const customModels = [
createModel('my-fine-tuned-gpt4', ['text', 'image']),
createModel('company-internal-llm', ['text']),
] as const

const myOpenai = extendAdapter(openaiText, customModels)

// Full autocomplete - original models + custom models
const adapter = myOpenai('my-fine-tuned-gpt4')

사용자 지정 모델은 공식 모델과 함께 자동 완성에 표시됩니다. Vercel AI SDK는 이제 안정적인 customProvider()(사용자 지정 및 별칭 모델 ID, 설정 재정의)와 createProviderRegistry()로 등록 기능을 제공합니다. 차이는 타입 안전성의 깊이입니다. 레지스트리 모델 ID는 일반 문자열인 반면 extendAdapter()는 사용자 지정 모델에 공식 모델과 동일한 리터럴 타입 좁히기 및 모델별 옵션 제한을 제공합니다.

미들웨어

TanStack AI의 미들웨어 시스템은 chat() 수명 주기의 모든 단계(구성, 스트리밍, 도구 실행, 사용량 추적, 완료)에 연결됩니다. 각 미들웨어는 특정 단계에서 실행되는 이름 있는 훅을 포함한 일반 객체입니다.

import { chat, EventType, type ChatMiddleware, type StreamChunk } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

const messages = [{ role: 'user' as const, content: 'Hello' }]

const logger: ChatMiddleware = {
name: 'logger',
onStart: (ctx) => {
console.log(`[${ctx.requestId}] Chat started`)
},
onChunk: (ctx, chunk) => {
// Transform, expand, or drop chunks. `type` is the discriminant, so it
// narrows `chunk` to the matching event and types `delta` as `string`.
if (chunk.type === EventType.TEXT_MESSAGE_CONTENT) {
return { ...chunk, delta: chunk.delta.replace(/\b\d{3}-\d{2}-\d{4}\b/g, '[REDACTED]') }
}
},
onBeforeToolCall: (ctx, hookCtx) => {
// Intercept tool calls: transform args, skip, or abort
if (hookCtx.toolName === 'deleteDatabase') {
return { type: 'abort', reason: 'Dangerous operation blocked' }
}
},
onAfterToolCall: (ctx, info) => {
console.log(`${info.toolName}: ${info.ok ? 'success' : 'failed'} in ${info.duration}ms`)
},
onFinish: (ctx, info) => {
console.log(`Done in ${info.duration}ms, ${info.usage?.totalTokens} tokens`)
},
}

const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
middleware: [logger],
})

사용 가능한 훅은 전체 수명 주기를 다룹니다.

Hook용도
onConfig반복마다 메시지, 도구, temperature, 시스템 프롬프트를 변환합니다
onStructuredOutputConfig호출 전에 구조화된 출력 스키마/구성을 변환합니다
onStart설정 작업 (타이머, 로깅)
onIteration에이전트 루프의 각 반복을 관찰합니다
onChunk개별 스트림 조각을 변환하거나 확장하거나 삭제합니다
onBeforeToolCall도구 호출을 가로채 인수를 변환하거나 실행을 건너뛰거나 실행을 중단합니다
onAfterToolCall도구 결과, 타이밍, 및 오류를 관찰합니다
onToolPhaseComplete반복에 대한 전체 도구 결과 일괄 처리를 관찰합니다(예: 승인 상태 집계)
onUsage각 반복당 토큰 사용량을 추적합니다
onFinish / onAbort / onError종료 훅입니다(실행마다 정확히 하나가 실행됨)

미들웨어는 자연스럽게 조합됩니다. onConfig은 각 미들웨어를 순서대로 통과합니다. onChunk는 각 미들웨어를 통해 청크를 전달하며(하나가 청크를 버리면 이후 미들웨어에는 표시되지 않음), onBeforeToolCall은 최초 승리 의미론을 사용합니다. 결정을 반환한 첫 번째 미들웨어가 나머지 처리를 단락시킵니다.

TanStack AI는 여러 기본 제공 미들웨어를 제공합니다. toolCacheMiddlewarecontentGuardMiddleware@tanstack/ai/middlewares 서브 경로에서, otelMiddleware@tanstack/ai/middlewares/otel에서 제공합니다(@opentelemetry/api를 선택적 피어로 유지하기 위해 자체 서브 경로에 둠). toolCacheMiddleware는 설정 가능한 TTL, LRU 제거, 플러그형 저장소 백엔드(Redis, localStorage 등)를 사용해 이름과 인수별로 도구 결과를 캐시합니다.

import { toolCacheMiddleware, contentGuardMiddleware } from '@tanstack/ai/middlewares'
import { otelMiddleware } from '@tanstack/ai/middlewares/otel'

Vercel AI SDK는 다른 접근 방식을 취합니다. wrapLanguageModel()은 호출을 가로채고 변환할 수 있는 미들웨어로 모델 인스턴스를 래핑하며(v6에서는 wrapEmbeddingModel()도 추가), 여러 기본 제공 미들웨어(extractReasoningMiddleware, simulateStreamingMiddleware, defaultSettingsMiddleware, 새로운 devToolsMiddleware)를 제공합니다. 그러나 이들은 모두 애플리케이션 수준이 아니라 모델 수준에서 작동합니다. v6은 이 범위의 일부를 다루는 호출별 옵션도 노출합니다: 스트림 변환을 위한 experimental_transform, experimental_onToolCallStart / experimental_onToolCallFinish 콜백, 단계별 구성 변경을 위한 prepareStep, experimental_repairToolCall입니다. 애플리케이션 수준에서 전체 수명 주기에 걸쳐 훅을 실행하고 순서대로 조합되며 최초 승리 의미론으로 도구 호출을 단락시킬 수 있는 이름 있는 재사용 미들웨어 객체로 구성된 통합 시스템은 제공하지 않습니다.

플랫폼 연계 없음

TanStack AI는 순수 라이브러리입니다. 선택적 플랫폼 계층, 게이트웨이 추상화, 호스팅별 기능, 배포별 최적화가 없습니다. AI 코드에는 어떤 배포 플랫폼과도 암묵적인 연계가 없습니다.

이는 단순한 철학적 입장이 아닙니다. 플랫폼별 기능에 대한 우발적 종속성, 공급업체 도입을 은연중에 유도하는 게이트웨이 추상화, 기술 스택에 내장된 마케팅 영역이 없다는 의미입니다.

코드 모드

코드 모드를 사용하면 모델이 샌드박스 안에서 도구를 호출하는 TypeScript를 작성할 수 있습니다. 한 번의 execute_typescript 호출로 턴마다 도구 하나를 호출하는 대신 반복, 분기, Promise.all을 사용할 수 있습니다.

TanStack AI는 하나의 IsolateDriver 인터페이스 뒤에 5개의 격리 드라이버를 제공합니다.

  • @tanstack/ai-isolate-node - isolated-vm 을 통한 Node.js 샌드박스
  • @tanstack/ai-isolate-quickjs - 브라우저 및 엣지를 위한 QuickJS WASM
  • @tanstack/ai-isolate-quickjs-bun - bun:ffi 를 통한 Bun 의 네이티브 QuickJS
  • @tanstack/ai-isolate-cloudflare - Cloudflare Workers
  • @tanstack/ai-isolate-daytona - 원격 Daytona 샌드박스

애플리케이션 코드를 변경하지 않고 드라이버를 교체할 수 있습니다. 함께 사용하는 @tanstack/ai-code-mode-snippets 패키지는 모델에 영속적인 스니펫 라이브러리를 제공합니다. 모델은 작동하는 TypeScript 스니펫을 저장하고 목록을 확인하며 세션 간에 재사용할 수 있습니다. 신뢰 전략은 무엇을 일급 도구로 승격할지 제어합니다.

Vercel AI SDK는 이제 실험적인 @ai-sdk/code-mode를 제공합니다. QuickJS만 실행하고 Node 22 이상이 필요하며 브라우저나 엣지에서는 실행되지 않습니다. 중첩된 도구 승인은 거부됩니다. 프로바이더 호스팅 코드 실행(Anthropic, xAI, OpenAI)은 여전히 별도의 경로입니다. 이 중 어느 것도 모델이 직접 구축하는 영속적이고 프로바이더 독립적인 스킬 라이브러리를 제공하지 않습니다. 코드 모드를 참조하세요.

코딩 에이전트 샌드박스

앞서 설명한 JS 격리 환경과 별도로 TanStack AI는 실제 파일 시스템, 셸, 복제된 저장소를 갖춘 격리 샌드박스 안에 완전한 코딩 에이전트 CLI를 배치할 수 있습니다. 에이전트는 Claude Code, Codex, Grok Build, OpenCode 또는 ACP 호환 에이전트일 수 있습니다. 작업 결과는 다른 실행과 마찬가지로 chat()을 통해 다시 스트리밍됩니다.

샌드박스 실행은 교체 가능한 세 부분으로 구성됩니다.

  • 프로바이더(실행 위치)
  • 워크스페이스(에이전트가 보는 내용)
  • 하네스 어댑터(어떤 에이전트가 실행되는지)

샌드박스는 chat() 미들웨어이므로 에이전트의 편집과 명령은 모든 useChat UI가 이미 렌더링하는 것과 동일한 AG-UI 스트림으로 도착합니다.

import { chat } from '@tanstack/ai'
import { grokBuildText } from '@tanstack/ai-grok-build'
import { defineSandbox, defineWorkspace, githubRepo, withSandbox } from '@tanstack/ai-sandbox'
import { dockerSandbox } from '@tanstack/ai-sandbox-docker'
import { messages, threadId } from './chat-context'

const sandbox = defineSandbox({
id: 'repo-agent',
provider: dockerSandbox({ image: 'node:22' }),
workspace: defineWorkspace({
source: githubRepo({ repo: 'TanStack/ai' }),
packageManager: 'pnpm',
}),
})

const stream = chat({
threadId,
adapter: grokBuildText('grok-build'),
messages,
middleware: [withSandbox(sandbox)],
})

AI SDK의 범위가 더 좁은 두 가지 측면에서 선택지가 열려 있습니다.

  • 고정된 목록이 아닌 모든 에이전트. Grok Build, Claude Code, Codex, OpenCode는 퍼스트파티 하네스 패키지로 제공되며, @tanstack/ai-acpacpCompatible은 실행 방법을 설명해 모든 Agent Client Protocol 에이전트(pi, gemini --acp, 수십 가지 기타 에이전트)를 하네스로 변환합니다. 에이전트를 추가하기 위해 전용 어댑터가 있어야 할 필요는 없습니다.
  • 하나의 클라우드가 아닌 모든 샌드박스. 동일한 실행을 localProcessSandbox(호스트 개발 루프), dockerSandbox(컨테이너), sbxSandbox(Docker Sandboxes microVM), Daytona, Vercel Sandbox, Sprites 또는 Cloudflare에서 실행할 수 있습니다. 하네스나 작업 공간을 건드리지 않고 프로바이더를 교체합니다. 프로바이더는 capabilities()(fs, exec, ports, snapshots, fork, durableFilesystem 등)를 선언하므로 코드가 각 환경에 맞게 기능을 축소할 수 있습니다.

Vercel AI SDK 7은 같은 개념을 위한 실험적인 HarnessAgent API를 추가했습니다. 샌드박스에서 코딩 에이전트 하네스를 실행하고 AI SDK generate() / stream() 결과를 반환합니다. Claude Code, Codex, Grok Build, OpenCode, Deep Agents, Pi용 어댑터를 제공합니다. 문서화된 경로는 Vercel Sandbox에서 이를 실행하며, 장시간 작업에는 Workflow SDK를 사용합니다. 일반적인 ACP 탈출구는 없고(지원되는 각 하네스가 자체 패키지임), 샌드박스 지원은 프로바이더 교체 가능한 계약이 아니라 Vercel 자체 microVM을 중심으로 합니다. 샌드박스 프로바이더하네스를 참조하세요.

미디어 생성

TanStack AI는 모든 미디어 생성 활동(이미지, 비디오, 음성, 전사, 요약)을 위한 안정적인 전용 API를 제공합니다. 각 API는 프로바이더별 자체 어댑터를 사용하는 별도의 트리 셰이킹 가능 함수입니다.

Vercel AI SDK는 이러한 기능 중 일부를 추가했습니다. v6부터 generateImage()는 안정적이며, 비디오 생성은 여전히 실험적이고(experimental_generateVideo()), generateSpeech() / transcribe()experimental_ 접두사 없이 export되지만 여전히 실험적 기능으로 문서화되어 있습니다. TanStack AI의 미디어 API는 모두 안정적이며 여러 측면에서 더 많은 기능을 제공합니다.

이미지 생성 - 모델별 타입 안전성을 제공하는 generateImage()입니다. TypeScript는 gpt-image-2dall-e-3가 서로 다른 크기 제약을 노출한다는 것을 알고 있습니다. 5개 프로바이더가 어댑터를 제공합니다: OpenAI(GPT Image, DALL-E), Gemini(Imagen), Grok, OpenRouter, fal.ai(Flux, SDXL 등을 포함한 600개 이상의 커뮤니티 모델).

import { generateImage } from '@tanstack/ai'
import { openaiImage } from '@tanstack/ai-openai'

const result = await generateImage({
adapter: openaiImage('gpt-image-2'),
prompt: 'A sunset over mountains',
size: '1536x1024',
numberOfImages: 1,
})

비디오 생성 - generateVideo()가 전체 비동기 작업 수명 주기를 자동으로 처리합니다. 비디오 생성 API는 본질적으로 비동기이므로 작업을 제출하고 상태를 폴링한 후 결과를 받습니다. TanStack AI는 설정 가능한 폴링 간격과 시간 제한으로 전체 수명 주기를 관리하고 상태 업데이트를 클라이언트로 스트리밍합니다.

import { generateVideo } from '@tanstack/ai'
import { openaiVideo } from '@tanstack/ai-openai'

const stream = generateVideo({
adapter: openaiVideo('sora-2'),
prompt: 'A cat playing piano',
size: '1280x720',
duration: 8,
stream: true, // Stream job lifecycle events
pollingInterval: 2000, // Poll every 2 seconds
})

for await (const chunk of stream) {
// Receive: job created → status updates → final video URL
}

Vercel AI SDK의 experimental_generateVideo()는 작업 수명 주기나 스트리밍 상태 업데이트를 노출하지 않고 비디오를 직접 반환합니다.

텍스트 음성 변환 - generateSpeech()는 6개 오디오 출력 형식(mp3, opus, aac, flac, wav, pcm), 속도 제어(0.25x~4x), 5개 프로바이더를 지원합니다: OpenAI(11개 음성), Gemini(언어 힌트가 있는 30개 이상의 음성), Grok, ElevenLabs, fal.ai입니다.

import { generateSpeech } from '@tanstack/ai'
import { openaiSpeech } from '@tanstack/ai-openai'

const result = await generateSpeech({
adapter: openaiSpeech('tts-1-hd'),
text: 'Hello, world!',
voice: 'nova',
format: 'opus',
speed: 1.2,
})

전사 - generateTranscription()은 일반적인 출력 형식(json, text, srt, verbose_json, vtt), 신뢰도 점수가 포함된 단어 단위 타임스탬프, 4개 프로바이더(OpenAI, Grok, ElevenLabs, fal.ai)를 지원하며 OpenAI의 gpt-4o-transcribe-diarize 모델을 통한 화자 분리를 제공합니다.

import { generateTranscription } from '@tanstack/ai'
import { openaiTranscription } from '@tanstack/ai-openai'
import { audioFile } from './audio'

const result = await generateTranscription({
adapter: openaiTranscription('gpt-4o-transcribe'),
audio: audioFile,
responseFormat: 'verbose_json', // Includes word-level timestamps
})

// result.words → [{ word: 'Hello', start: 0.0, end: 0.42 }, ...]

오디오 및 음악 생성 - generateAudio()는 Gemini(Lyria), ElevenLabs(음악 + 음향 효과), fal.ai에서 음악과 음향 효과를 생성합니다. Vercel AI SDK에는 동등한 기능이 없습니다.

요약 - summarize()는 스타일 제어(bullet-points, paragraph, concise), 집중 주제, 스트리밍을 지원하는 전용 활동입니다. Vercel AI SDK에는 동등한 기능이 없으므로 프롬프트와 함께 generateText()를 호출해야 요약할 수 있습니다.

실시간 음성 - realtimeToken()은 음성 활동 감지 모드(server, semantic, manual)를 사용하는 양방향 오디오 스트리밍, 음성 세션 중 도구 호출, 오디오 + 텍스트 동시 출력을 지원합니다. 3개 프로바이더가 실시간 어댑터를 제공합니다: OpenAI(Realtime API), Grok, ElevenLabs입니다. Vercel AI SDK는 이제 OpenAI, Google, xAI(AI Gateway 포함)를 위한 실험적인 experimental_useRealtime을 제공합니다. TanStack AI의 실시간 어댑터는 안정적이며 ElevenLabs를 포함합니다.

모든 미디어 활동은 채팅과 동일한 어댑터 패턴(트리 셰이킹 가능한 import, 모델별 타입 안전성, 스트리밍 지원)을 따릅니다. 앱에서 채팅만 사용하면 이 미디어 코드는 번들에 포함되지 않습니다.

네이티브 AG-UI 프로토콜

TanStack AI가 서버와 클라이언트 사이에서 스트리밍하는 이벤트는 @ag-ui/core에서 직접 가져오는 AG-UI 이벤트(RUN_STARTED, TEXT_MESSAGE_*, TOOL_CALL_*, RUN_FINISHED)입니다. AG-UI 내보내기를 덧붙인 독자 형식이 아닙니다. AG-UI를 지원하는 무엇이든 전송의 양쪽에 둘 수 있습니다. TanStack AI 프론트엔드 뒤에 AG-UI 호환 에이전트 프레임워크를 두거나, 전혀 다른 언어로 작성된 에이전트 서버 앞에 TanStack AI 클라이언트를 둘 수 있습니다.

Vercel AI SDK는 자체 독점 UI Message Stream 프로토콜을 스트리밍합니다. AG-UI 상호 운용에는 외부 변환 계층(@ag-ui/vercel-ai-sdk, AG-UI 프로젝트가 구축하고 유지 관리)을 필요로 하며, 네이티브 지원은 여전히 AI SDK 저장소의 미해결 기능 요청입니다.

모든 활동을 위한 훅

훅을 사용하는 활동은 채팅뿐이 아닙니다. 모든 활동에 훅이 제공됩니다. useGeneration(구조화된 출력 스트리밍), useGenerateImage, useGenerateAudio, useGenerateSpeech, useTranscription, useSummarize, useGenerateVideo, useRealtimeChat가 React, Solid, Vue, Svelte, Preact, Angular에서 useChat과 동일한 연결 어댑터 연결 및 DevTools 통합을 제공합니다.

Vercel AI SDK의 UI 계층에는 useChat, useCompletion, useObject라는 세 가지 훅이 있습니다. 미디어 함수(generateImage(), experimental_generateVideo(), 음성, 전사)는 서버 측 전용이므로 UI에 표시하려면 자체 경로와 클라이언트 상태를 직접 작성해야 합니다.

다중 턴 구조화된 출력

TanStack AI는 구조화된 출력을 호출 결과에만 남기지 않고 대화 기록에 보존합니다. 프로바이더는 에이전트 루프 또는 별도의 최종화를 통해 이를 생성할 수 있으며, 두 경로 모두 타입이 지정된 StructuredOutputPart를 만들고 partial로 스트리밍한 뒤 final로 완료합니다. 스키마 제네릭은 messages[i].parts[j].data까지 전달됩니다.

Vercel AI SDK의 구조화된 출력(generateObject / streamObject / Output)은 호출별입니다. 타입이 지정된 객체는 호출 결과에 존재하고 메시지 파트 유니온에는 구조화된 출력 타입이 없으므로, useChat과 타입이 지정된 구조화된 출력을 함께 사용하려면 모델 텍스트를 사용자 지정 데이터 파트로 수동 파싱해야 합니다.

디버그 로깅

어떤 활동에서든 debug: true를 설정하면 파이프라인 자체가 출력됩니다. 원시 프로바이더 청크, 미들웨어 이후 출력, 미들웨어 훅 입력과 출력, 도구 실행, 에이전트 루프 반복, 구성 변환, 요청 메타데이터를 확인할 수 있으며 각 카테고리를 개별적으로 토글하고 구조화된 출력을 위한 플러그형 logger를 사용할 수 있습니다. Vercel AI SDK의 기본 로깅은 프로바이더 경고를 다루며, 더 풍부한 옵저버빌리티는 어디서나 켤 수 있는 디버그 로그가 아니라 실험적 텔레메트리 훅 또는 개발 전용 DevTools 레코더를 통해 제공됩니다.

커뮤니티 어댑터 생태계

TanStack AI는 개방형 어댑터 사양을 공개합니다. 공식 LLM 어댑터는 다음과 같습니다.

  • OpenAI, Anthropic, Gemini, Vertex, Grok, Groq, OpenRouter, Ollama
  • Bedrock, BytePlus, Mistral, Cohere, ElevenLabs, fal
  • Vercel AI Gateway 및 openaiCompatible 를 통한 모든 OpenAI 호환 엔드포인트

하네스 어댑터는 Grok Build, Claude Code, Codex, OpenCode 및 acpCompatible을 통한 모든 ACP 에이전트입니다. 커뮤니티는 이미 Decart, Cencori, Cloudflare, Soniox, Mynth용 어댑터를 구축했으며, 직접 구축하는 가이드도 제공합니다.

Vercel AI SDK가 뛰어난 부분

프로바이더 범위. Vercel AI SDK는 개별적으로 타입이 지정된 퍼스트파티 프로바이더 패키지 약 38개와 대규모 커뮤니티 목록을 제공합니다. 어댑터를 직접 작성하지 않고 특정 프로바이더를 전용 유지 관리 패키지로 사용하려는 경우 현재 Vercel의 지원 범위가 더 넓습니다. 단순한 모델 개수가 차이를 만들지는 않습니다. TanStack AI의 OpenRouter 어댑터는 OpenRouter 전체 카탈로그에 접근하고, 퍼스트파티 Vercel Gateway 어댑터는 키 하나로 라우팅하며, openaiCompatible는 모든 OpenAI 호환 엔드포인트에 연결합니다.

Solid와 Angular. 이제 두 SDK 모두 공식 Angular를 제공합니다. Solid는 여전히 반대입니다. AI SDK의 Solid 패키지는 커뮤니티가 유지 관리하며 이전 SDK 메이저 버전에 고정되어 있지만, TanStack AI는 공식 최신 Solid 통합을 제공합니다.

에이전트 추상화. Vercel AI SDK는 모델, 도구, 지침, 루프 설정을 .generate().stream() 메서드가 있는 재사용 가능한 객체로 묶는 전용 Agent 추상화(ToolLoopAgent 클래스)와 엔드투엔드 타입 안전성을 위한 InferAgentUIMessage를 제공합니다. TanStack AI는 단일 에이전트 클래스 대신 호출별로 이 요소들을 조합합니다.

AI Gateway. Vercel의 선택적 AI Gateway는 Vercel 플랫폼과 통합된 중앙 집중식 프로바이더 관리(장애 조치 라우팅, 캐싱, 프로바이더 간 단일 키)를 추가하며 프로바이더가 구성되지 않으면 기본적으로 사용됩니다. TanStack AI에는 자체 게이트웨이가 없습니다. 동일한 중앙 집중식 라우팅에는 퍼스트클래스 OpenRouter 어댑터 또는 Vercel AI Gateway 어댑터를 사용하세요. 어느 쪽도 나머지 스택에 플랫폼 계층을 연결하지 않습니다.

React Server Components. Vercel AI SDK는 @ai-sdk/rsc(AIState, StreamableValue, streamUI)를 통한 RSC 통합을 제공합니다. Vercel은 이를 실험적 기능으로 문서화하고 프로덕션에는 AI SDK UI를 권장하므로, 이는 기본 경로가 아니라 Next.js RSC 앱을 위한 선택지입니다.

나란히 비교하기: 주요 차이점

도구 정의

TanStack AI - 별도의 런타임 구현을 사용하는 동형 정의입니다.

import { toolDefinition } from '@tanstack/ai'
import { z } from 'zod'
import { weatherApi } from './weather'

const getWeather = toolDefinition({
name: 'getWeather',
description: 'Get current weather for a location',
inputSchema: z.object({ city: z.string() }),
outputSchema: z.object({ temp: z.number(), condition: z.string() }),
})

// Server implementation
const getWeatherServer = getWeather.server(async ({ city }) => {
const data = await weatherApi.get(city)
return { temp: data.temperature, condition: data.condition }
})

// Client implementation
const getWeatherClient = getWeather.client(async ({ city }) => {
const res = await fetch(`/api/weather?city=${city}`)
return res.json()
})

Vercel AI SDK - tool() 헬퍼를 통한 도구 객체입니다.

import { generateText, tool } from 'ai'
import { openai } from '@ai-sdk/openai'
import { z } from 'zod'
import { weatherApi } from './weather'

const result = await generateText({
model: openai('gpt-5.5'),
tools: {
getWeather: tool({
description: 'Get current weather for a location',
inputSchema: z.object({ city: z.string() }),
execute: async ({ city }) => {
const data = await weatherApi.get(city)
return { temp: data.temperature, condition: data.condition }
},
}),
},
prompt: "What's the weather in Tokyo?",
})

TanStack 방식은 도구 계약과 구현을 분리하므로 서버와 클라이언트 컨텍스트에서 도구를 재사용할 수 있습니다.

영속성

TanStack AI - 미들웨어가 대화 기록을 작성하고 클라이언트가 이를 다시 로드합니다.

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)
}
import { fetchServerSentEvents, useChat } from '@tanstack/ai-react'

const { messages, sendMessage } = useChat({
threadId: 'support-chat',
connection: fetchServerSentEvents('/api/chat'),
persistence: true,
})

Vercel AI SDK - saveChat / loadChat을 직접 관리하고 onEnd에서 호출합니다.

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는 실행 상태와 대기 중인 승인도 영속화하며 장시간 미디어 생성을 동일한 훅 필드로 복원할 수 있습니다. Vercel AI SDK에서는 이 연결 작업을 직접 수행해야 합니다. 라이브 스트림 재개는 양쪽 모두 별도 계층입니다. TanStack AI는 StreamDurability를 사용하고 Vercel AI SDK는 Redis와 resumable-stream을 사용합니다.

에이전트 루프 제어

TanStack AI - 조합 가능한 전략입니다.

import { chat, combineStrategies, maxIterations, untilFinishReason } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'
import { tools } from './tools'
import { estimatedTokens } from './cost'

const messages = [{ role: 'user' as const, content: 'Help me plan a trip.' }]

const stream = chat({
adapter: openaiText('gpt-5.5'),
messages,
tools,
agentLoopStrategy: combineStrategies([
maxIterations(10),
untilFinishReason(['stop']),
({ iterationCount }) => estimatedTokens(iterationCount) < 50_000,
]),
})

Vercel AI SDK - stopWhen 조건(v5+)입니다.

import { generateText, stepCountIs } from 'ai'
import { openai } from '@ai-sdk/openai'
import { tools } from './tools'

const result = await generateText({
model: openai('gpt-5.5'),
tools,
stopWhen: stepCountIs(10), // also: hasToolCall('name'), or a custom function
prompt: 'Help me plan a trip.',
})

두 SDK 모두 여러 중지 조건을 조합할 수 있습니다. stopWhen은 사용자 지정 함수를 포함한 조건 배열을 받고 v6에서는 재사용 가능한 Agent 클래스를 추가합니다. 남은 차이는 사용성입니다. TanStack AI의 전략은 combineStrategies로 결합하는 일반 (state) => boolean 조건자이므로 기본 제공 조건을 찾지 않고도 토큰 예산과 사용자 지정 비즈니스 로직을 일급 기능으로 사용할 수 있습니다.

트리 셰이킹

TanStack AI - 활동별 별도 어댑터입니다.

// Only bundles chat + OpenAI text adapter
import { chat } from '@tanstack/ai'
import { openaiText } from '@tanstack/ai-openai'

Vercel AI SDK - 단일 프로바이더 import입니다.

// Provider package includes all model types
import { openai } from '@ai-sdk/openai'

TanStack AI에서 각 활동(채팅, 이미지, 음성, 비디오, 전사, 요약)은 별도의 어댑터 함수입니다. 채팅에는 openaiText, 이미지 생성에는 openaiImage를 import하며 두 함수는 독립적인 모듈입니다. Vercel AI SDK의 프로바이더 패키지는 더 단일체에 가깝습니다.

TanStack AI를 선택할 때

  • 번들 크기가 중요함 - 활동별 트리 셰이킹 가능한 어댑터로 번들 크기가 작아집니다.
  • AG-UI 네이티브 - 유선 프로토콜이 엔드투엔드 AG-UI이므로 변환 계층 없이 에이전트 UI 생태계 및 비 TypeScript 에이전트 서버와 상호 운용할 수 있습니다.
  • Solid, Preact, Angular 또는 React Native - 공식 유지 관리되는 하나의 헤드리스 코어가 React, Solid, Vue, Svelte, Preact, Angular, React Native(XHR 어댑터를 통해)을 지원합니다.
  • 채팅을 넘어서는 훅 - 지원되는 모든 프레임워크에서 useGeneration, useGenerateImage, useSummarize 및 나머지 생성 훅 제품군을 제공합니다.
  • 동형 도구 - 도구를 한 번 정의하고 하나의 계약에서 .server() / .client() 구현을 파생합니다.
  • 앱 수준 미들웨어 - 단순한 모델 래핑이 아니라 청크, 도구 호출, 사용량, 오류를 위한 수명 주기 훅을 제공합니다.
  • 채팅 및 생성 영속성 - withPersistencereconstructChat 또는 브라우저 저장소를 사용하며, 장시간 미디어 실행은 withGenerationPersistence를 통해 복원합니다.
  • 재개 가능한 스트림 - 응답에 내구성 어댑터를 사용하며 Redis 없이 useChat이 재연결합니다.
  • 내구성 있는 샌드박스 실행 - 분리, 저널, 인계, 리퍼를 통해 탭이 닫혀도 코딩 에이전트가 유지됩니다.
  • 실시간 음성 - OpenAI, Grok, ElevenLabs에서 안정적인 양방향 오디오를 제공합니다.
  • 공급업체 연계 없음 - 플랫폼 계층이 없는 순수 라이브러리입니다.
  • 모델별 타입 안전성 - TypeScript가 프로바이더가 아니라 모델별로 옵션을 좁힙니다.
  • 코드 모드 - 5개의 격리 드라이버(Node, QuickJS WASM, QuickJS Bun, Cloudflare, Daytona)와 LLM이 작성할 수 있는 스킬 라이브러리를 제공합니다.
  • 코딩 에이전트 샌드박스 - Claude Code, Codex, Grok Build, OpenCode 또는 ACP 에이전트를 교체 가능한 샌드박스(로컬, Docker, Docker Sandboxes, Daytona, Vercel, Sprites, Cloudflare)에서 실행하고 chat()을 통해 스트리밍합니다.
  • 유연한 전송 - SSE, HTTP 스트림, XHR, RPC, 직접 iterable 또는 사용자 지정 어댑터를 지원합니다.
  • 두 가지 MCP 방식 - 풀, 코드 생성, 관리되는 chat() 수명 주기를 갖춘 독립형 호스트 측 클라이언트(@tanstack/ai-mcp)와 프로바이더 라우팅 mcpTool()을 제공합니다.

Vercel AI SDK를 선택할 때

  • 특정 프로바이더를 위한 퍼스트파티 패키지 필요 - 현재 전용 개별 타입 프로바이더 패키지 약 38개를 제공합니다(TanStack은 OpenRouter, Vercel Gateway, openaiCompatible를 통해 비슷한 모델 범위에 도달합니다).
  • 에이전트 추상화 - 엔드투엔드 UI 메시지 타입을 갖춘 재사용 가능한 Agent(ToolLoopAgent) 클래스입니다.
  • Vercel 플랫폼 - AI Gateway, 옵저버빌리티, 배포 최적화를 제공합니다.
  • React Server Components - @ai-sdk/rsc를 통한 RSC 기본 요소(실험적이며 AI SDK UI가 권장되는 프로덕션 경로)입니다.
  • Vercel에서 Workflow 기반 장시간 실행 - 스택이 이미 해당 플랫폼에 있다면 실험적인 HarnessAgent와 Workflow SDK를 사용할 수 있습니다.

시작하기

npm install @tanstack/ai @tanstack/ai-openai
# or
pnpm add @tanstack/ai @tanstack/ai-openai

빠른 시작 가이드를 통해 첫 채팅 애플리케이션을 구축하거나 전체 문서를 살펴보세요.