Use fetchServerSentEvents (or matching adapter) to mirror the streaming response. citeturn0search0
Keep client tool names identical to definitions to avoid “tool not found” errors. citeturn0search7
The 4-Step Setup Process
Step 1: Choose provider + model safely
Add the correct adapter and set the matching API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY, or Ollama host).
Prefer per-model option typing from adapters to avoid invalid options (e.g., vision-only fields). citeturn1search3
Step 2: Define tools once, implement per runtime
// tools/definitions.ts
import { z, toolDefinition } from '@tanstack/ai'
export const getWeatherDef = toolDefinition({
name: 'getWeather',
description: 'Get current weather for a city',
inputSchema: z.object({ city: z.string() }),
needsApproval: true,
})
export const getWeather = getWeatherDef.server(async ({ city }) => {
const data = await fetch(`https://api.weather.gov/points?q=${city}`).then(r => r.json())
return { summary: data.properties?.relativeLocation?.properties?.city ?? city }
})
export const showToast = getWeatherDef.client(({ city }) => {
console.log(`Showing toast for ${city}`)
return { acknowledged: true }
})
Key Points:
needsApproval: true forces explicit user approval for sensitive actions. citeturn0search1
Keep tools single-purpose and idempotent; return structured objects instead of throwing errors. citeturn0search1
Step 3: Create connection adapter + chat options
Server: toStreamResponse(stream) for HTTP streaming; toServerSentEventsStream helper for Server-Sent Events. citeturn0search3turn0search4
Client: fetchServerSentEvents('/api/chat') or a custom adapter for websockets if needed. citeturn0search0
Configure agentLoopStrategy (e.g., maxIterations(8)) to cap tool recursion. citeturn1search4
Step 4: Add observability + guardrails
Log tool executions and stream chunks for debugging; alpha exposes hooks while devtools are in progress. citeturn0search1
Validate inputs with Zod; fail fast and return typed error objects.
Enforce timeouts on external API calls inside tools to prevent stuck agent loops.
Critical Rules
Always Do
✅ Stream responses; avoid waiting for full completions. citeturn0search1
✅ Pass definitions to the server and implementations to the correct runtime. citeturn0search7
✅ Use Zod schemas for tool inputs/outputs to keep type safety across providers. citeturn0search1
✅ Cap agent loops with maxIterations to prevent runaway tool calls. citeturn1search4
✅ Require needsApproval for destructive or billing-sensitive tools. citeturn0search1
Never Do
❌ Mix provider adapters in a single request—instantiate one adapter per call.
❌ Throw raw errors from tools; return structured error payloads.
❌ Send client tool implementations to the server (definitions only).
❌ Hardcode model capabilities; rely on adapter typings for per-model options. citeturn0search1
❌ Skip API key checks; fail fast with helpful messages on the server. citeturn0search1
Known Issues Prevention
This skill prevents 3 documented issues:
Issue #1: “tool not found” / silent tool failures
Why it happens: Definitions aren’t passed to chat(); only implementations exist locally. Prevention: Export definitions separately and include them in the server tools array; keep names stable. citeturn0search7
Issue #2: Streaming stalls in the UI
Why it happens: Mismatch between server response type and client adapter (HTTP chunked vs SSE). Prevention: Use toStreamResponse on the server + fetchServerSentEvents (or matching adapter) on the client. citeturn0search1turn0search0
Issue #3: Model option validation errors
Why it happens: Provider-specific options (e.g., vision params) sent to unsupported models. Prevention: Use adapter-provided types; rely on per-model option typing to surface invalid fields at compile time. citeturn1search3
When to use: When the model must both fetch data and mutate UI state in one loop. citeturn0search1
Using Bundled Resources
Scripts (scripts/)
scripts/check-ai-env.sh — verifies required provider keys are present before running dev servers.
Example Usage:
./scripts/check-ai-env.sh
References (references/)
references/tanstack-ai-cheatsheet.md — condensed server/client/tool patterns plus troubleshooting cues.
When Claude should load these: When debugging tool routing, streaming issues, or recalling exact API calls.
Assets (assets/)
assets/api-chat-route.ts — copy/paste API route template with streaming + tools.
assets/tool-definitions.ts — ready-to-use toolDefinition examples with approval + zod schemas.
When to Load References
Load reference files for specific implementation scenarios:
Adapter Comparison: Load references/adapter-matrix.md when choosing between OpenAI, Anthropic, Gemini, or Ollama adapters, or when debugging provider-specific quirks.
React Integration Details: Load references/react-integration.md when implementing useChat hooks, handling SSE streams in React components, or managing client-side tool state.
Routing Setup: Load references/start-vs-next-routing.md when setting up API routes in Next.js vs TanStack Start, or troubleshooting streaming response setup.
Streaming Issues: Load references/streaming-troubleshooting.md when debugging SSE connection problems, chunk delivery issues, or HTTP streaming configuration.
Quick Reference: Load references/tanstack-ai-cheatsheet.md for condensed API patterns, tool definition syntax, or rapid troubleshooting cues.
Tool Architecture: Load references/tool-patterns.md when implementing complex client/server tool workflows, approval flows, or hybrid tool patterns.
Type Safety Details: Load references/type-safety.md when working with per-model option typing, multimodal inputs, or debugging type errors across adapters.
Advanced Topics
Per-model type safety
Use adapter typings to pick valid options per model; avoid generic any options on chat(). citeturn1search3
For multimodal models, send parts with correct MIME types; unsupported modalities are caught at compile time. citeturn1search3
Tool approval UX
Surfaced via approval object in useChat; render approve/reject UI and persist decision per tool call. citeturn0search1
For auditable actions, log approval decisions alongside tool inputs.
Connection adapters
Default to fetchServerSentEvents (SSE) for minimal setup; switch to custom adapters for websockets or HTTP chunking. citeturn0search0
Use ImmediateStrategy in the client to emit every chunk for typing indicator UIs. citeturn0search0
Dependencies
Required:
@tanstack/ai@latest — core chat + tool engine
@tanstack/ai-react@latest — React bindings (skip for headless usage)
Solution: Run ./scripts/check-ai-env.sh and set the relevant provider key in .env.local. Fail fast in the route before invoking chat(). citeturn0search1
Problem: Streaming stops after first chunk
Solution: Confirm the server returns toStreamResponse(stream) (or SSE helper) and that any reverse proxy allows chunked transfer.
Complete Setup Checklist
Use this checklist to verify your setup:
Installed core + one adapter and zod
API route returns toStreamResponse(stream) with tool definitions included