| title | AI Agents |
|---|---|
| sidebarTitle | Overview |
| description | Durable multi-turn AI chats — one Trigger.dev task per conversation, surviving refreshes, deploys, and crashes. |
import RcBanner from "/snippets/ai-chat-rc-banner.mdx";
An AI chat isn't a request — it's a session. chat.agent runs every conversation as a single long-lived Trigger.dev task: you write the loop, it wakes up when a message arrives, freezes when none do, and the same in-memory state and on-disk workspace survive across page refreshes, deploys, idle gaps, and crashes. The substrate handles the parts most teams stitch together by hand — turn lifecycle, mid-stream resume, recovery from cancel/crash/OOM, HITL approvals, deploy upgrades — so your code is the loop you'd write anyway: messages in, streamText out.
A chat.agent task takes messages, calls streamText, and returns the result. The frontend wires the Vercel AI SDK's useChat to a TriggerChatTransport. No API routes.
import { chat } from "@trigger.dev/sdk/ai";
import { streamText, stepCountIs } from "ai";
import { anthropic } from "@ai-sdk/anthropic";
export const myChat = chat.agent({
id: "my-chat",
run: async ({ messages, signal }) =>
streamText({
model: anthropic("claude-sonnet-4-5"),
messages,
abortSignal: signal,
stopWhen: stepCountIs(15),
}),
});import { useChat } from "@ai-sdk/react";
import { useTriggerChatTransport } from "@trigger.dev/sdk/chat/react";
export function Chat() {
const transport = useTriggerChatTransport<typeof myChat>({
task: "my-chat",
accessToken: ({ chatId }) => mintChatAccessToken(chatId),
startSession: ({ chatId, clientData }) =>
startChatSession({ chatId, clientData }),
});
const { messages, sendMessage } = useChat({ transport });
// ... render UI
}See Quick Start for the matching server actions and a runnable project.
- Resume across refreshes, deploys, and crashes. A chat in progress when you redeploy keeps streaming on the new version. Mid-stream refreshes pick up where they left off.
- Native AI SDK support. Text, tool calls, reasoning, and custom
data-*parts all flow throughuseChatover a customChatTransport. No custom protocol to maintain. - Multi-turn for free. Each turn is a step inside the same durable task; conversation history accumulates server-side, so clients only ship the new message.
- Fast cold starts. Opt-in Head Start runs the first
streamTextstep in your warm Next.js / Hono / SvelteKit server while the agent boots in parallel — cuts time-to-first-chunk roughly in half. - Production primitives ship in the box. Stop generation, steering, edits, branching, sub-agents, HITL tool approvals, version upgrades, recovery from cancel/crash/OOM — all first-class.
- Observable. Every turn is a span in the Trigger.dev dashboard. Sessions are queryable via
sessions.listfor inbox-style UIs.
Three primitives, related but distinct:
- Chat agents — the SDK surface you define with
chat.agent(). Owns the turn loop, lifecycle hooks, and the response stream. - Sessions — the durable, bi-directional channel keyed on
chatIdthat holds the conversation across run boundaries. A chat agent runs on top of a Session. - Sub-agents — Delegate work from one agent to another via
AgentChat. The sub-agent runs as its own durable agent on its own session; its response streams back through the parent as preliminary tool results, so the frontend sees the sub-agent working inside the parent's tool card.