|
| 1 | +--- |
| 2 | +title: "Anatomy of an agent" |
| 3 | +sidebarTitle: "Anatomy" |
| 4 | +description: "The moving parts of a chat agent — the agent task, the session, the frontend transport — and which page covers each." |
| 5 | +--- |
| 6 | + |
| 7 | +import RcBanner from "/snippets/ai-chat-rc-banner.mdx"; |
| 8 | + |
| 9 | +<RcBanner /> |
| 10 | + |
| 11 | +**A chat agent is three parts: a long-lived agent task that runs the turn loop, a durable Session carrying messages in and the response stream out, and a frontend transport that plugs the session into `useChat`.** The pages in this section each own one part of that picture. This page is the map — if you'd rather read mechanics end to end, skip to [How it works](/ai-chat/how-it-works). |
| 12 | + |
| 13 | +```mermaid |
| 14 | +flowchart LR |
| 15 | + FE["Frontend<br/>useChat + transport"] -- "user messages" --> IN([Session .in]) |
| 16 | + IN --> AGENT["Agent task<br/>turn loop + hooks"] |
| 17 | + AGENT --> OUT([Session .out]) |
| 18 | + OUT -- "streamed response" --> FE |
| 19 | +``` |
| 20 | + |
| 21 | +Everything below maps onto one annotated agent: |
| 22 | + |
| 23 | +```ts trigger/my-agent.ts |
| 24 | +import { chat } from "@trigger.dev/sdk/ai"; |
| 25 | +import { streamText, stepCountIs } from "ai"; |
| 26 | +import { anthropic } from "@ai-sdk/anthropic"; |
| 27 | + |
| 28 | +export const myAgent = chat.agent({ |
| 29 | + id: "my-agent", |
| 30 | + |
| 31 | + // Tools declared on the config survive history re-conversion |
| 32 | + // across turns — see Tools. |
| 33 | + tools: { searchDocs }, |
| 34 | + |
| 35 | + // Hooks fire around each turn: validation, persistence, |
| 36 | + // post-turn work — see Lifecycle hooks. |
| 37 | + onTurnComplete: async ({ responseMessage }) => { |
| 38 | + await db.messages.save(responseMessage); |
| 39 | + }, |
| 40 | + |
| 41 | + // The turn loop. Messages arrive accumulated; you stream back. |
| 42 | + // Options, levels, and alternatives — see Backend. |
| 43 | + run: async ({ messages, tools, signal }) => |
| 44 | + streamText({ |
| 45 | + ...chat.toStreamTextOptions({ tools }), |
| 46 | + model: anthropic("claude-sonnet-4-5"), |
| 47 | + messages, |
| 48 | + abortSignal: signal, |
| 49 | + stopWhen: stepCountIs(15), |
| 50 | + }), |
| 51 | +}); |
| 52 | +``` |
| 53 | + |
| 54 | +The frontend side is one hook — `useTriggerChatTransport` connects `useChat` to the agent's session, no API routes ([Frontend](/ai-chat/frontend)). Underneath, the conversation lives on a [Session](/ai-chat/sessions): a pair of durable streams keyed on your `chatId` that survives refreshes, deploys, and run boundaries. |
| 55 | + |
| 56 | +## Where each part is covered |
| 57 | + |
| 58 | +| Part | Page | |
| 59 | +| ----------------------------------------------------- | ---------------------------------------------- | |
| 60 | +| `chat.agent()` options, the turn loop, piping | [Backend](/ai-chat/backend) | |
| 61 | +| Hooks around each turn (`onTurnComplete`, hydration) | [Lifecycle hooks](/ai-chat/lifecycle-hooks) | |
| 62 | +| Declaring tools, typed payloads, `toModelOutput` | [Tools](/ai-chat/tools) | |
| 63 | +| `useChat` wiring, tokens, starting sessions | [Frontend](/ai-chat/frontend) | |
| 64 | +| Driving a chat from your server instead of a browser | [Server-side chat](/ai-chat/server-chat) | |
| 65 | +| The durable substrate under every agent | [Sessions](/ai-chat/sessions) | |
| 66 | +| Per-run typed state inside the loop | [chat.local](/ai-chat/chat-local) | |
| 67 | +| Type-safe payloads, client data, and messages | [Types](/ai-chat/types) | |
| 68 | +| Building without the managed lifecycle | [Custom agents](/ai-chat/custom-agents) | |
| 69 | +| End-to-end mechanics: what survives a refresh and why | [How it works](/ai-chat/how-it-works) | |
| 70 | + |
| 71 | +Beyond this section: [Features](/ai-chat/fast-starts) covers opt-in capabilities (Head Start, compaction, steering, actions), and [Patterns](/ai-chat/patterns/sub-agents) covers production recipes (sub-agents, HITL approvals, persistence, recovery). |
0 commit comments