docs/ai-chat/overview.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.
data-* parts all flow through useChat over a custom ChatTransport. No custom protocol to maintain.streamText step in your warm Next.js / Hono / SvelteKit server while the agent boots in parallel — cuts time-to-first-chunk roughly in half.sessions.list for inbox-style UIs.Three primitives, related but distinct:
chat.agent(). Owns the turn loop, lifecycle hooks, and the response stream.chatId that holds the conversation across run boundaries. A chat agent runs on top of a Session.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.