AI Docs
Chat & Streaming
Transports
Tools
Middleware
Chat UI Recipes
Interrupts
MCP
Resumable Streams
Persistence
Persistence (Advanced)
Media
Embeddings
Reranking
Evaluate
Code Mode
Computer Use
Harness
- Build your first harness
- Host options
- Send and show media
- Connect clients
- Write a client in any language
- Access and tenants
- Run in the terminal
- Deploy a harness
- Send inputs safely
- Run a tool without a model
- Durable sessions
- Run background work on workers
- List, rename, and fork sessions
- Lifecycle and retention
- Run side effects once
- Wait for a person
- Build on the session log
- Control how a turn ends
- Store settings per thread
- Compact a long session
- Fork and reset a thread
- One log for a session tree
- Write a plugin
- Track usage and cost
- Ask before risky tool calls
- Give your agent coding tools
- Sandbox and extend the coding tools
- Run the coding tools for many threads
- Undo a turn
- Build a coding agent
- Delegate to coding agents
- Switch between agent profiles
- Auth and connectors
- Share a thread between people
- Connect model providers
- Build your own UI
- Code mode in a harness
- Work until a goal is met
- Run agents from a harness
- Hand off a conversation
- Add skills
- Use MCP servers
- Give your agent a computer
- Use from any MCP client
- Use a harness from an editor (ACP)
Sandboxes
- Overview
- Quick Start
- Providers
- Harnesses
- Harness Auth
- Workspace
- Tools
- Policy
- Lifecycle & Snapshots
- Portable Snapshots
- Keep Files After Reload
- Save a Named Version
- Branch From a Version
- Send a Frozen File
- Let the Agent Save and Fork
- Pick Which Files to Keep
- What a Snapshot Stores
- Instance Durability
- Durable Runs
- Events
Sandboxes (Advanced)
Advanced
- Runtime Context
- Bring Your Own Key
- Keep Keys on the Server
- Debug Logging
- Multimodal Content
- Files API
- Per-Model Type Safety
- Runtime Adapter Switching
- Tree-Shaking
- Extend Adapter
- Extend Adapter: Advanced
- Typed Pre-Configured Options
- Test with a Fake Model
- Prompt Caching
- Mid-Conversation Changes
- Approval Flow Processing
AI/LLM: This documentation page is available in plain markdown format at/ai/latest/docs/transports/websockets.md
Transports
WebSockets
webSocket() opens one socket for the conversation. A durable run reconnects on that socket.
Quick setup#
1. Accept the socket on the server#
On Cloudflare Workers or Durable Objects, use toWebSocketResponse:
ts
// worker.ts
import { chat, memoryStream, toWebSocketResponse } from "@tanstack/ai";
import { openaiText } from "@tanstack/ai-openai";
export default {
fetch(request: Request): Response {
return toWebSocketResponse(request, {
durability: (ctx) => memoryStream(ctx.request),
onRun: ({ messages, threadId, runId }) =>
chat({
adapter: openaiText("gpt-6.1-sol"),
messages,
threadId,
runId,
}),
});
},
};On other hosts, such as Node, accept the socket yourself. Then pass it to toWebSocketStream. See Resumable Streams: WebSockets.
2. Connect from the client#
tsx
import { useChat, webSocket } from "@tanstack/ai-react";
const connection = webSocket("/api/chat-ws");
export function Chat() {
const { messages, sendMessage } = useChat({ connection, threadId: "support-chat" });
return (
<div>
{messages.map((message) => (
<p key={message.id}>
{message.parts.map((part) =>
part.type === "text" ? part.content : "",
)}
</p>
))}
<button onClick={() => void sendMessage("Hello")}>Send</button>
</div>
);
}Send two messages. Both replies stream over the same socket.
How it works#
- webSocket() opens the socket on the first sendMessage.
- Each user message goes over the socket as one frame.
- The server runs one chat() turn for each frame, through onRun, and streams the chunks back.
- The socket stays open for the next message.
For the wire protocol, the onRun context, client options, and the reconnect details, see Resumable Streams: WebSockets.
Advanced#
Use your own wire format#
To use your own wire format or a server that you do not control, write a custom transport. See Custom Transports.