Compatibility
The
ai peer is optional — server-only setups that don’t call streamText (raw task() with chat primitives) can skip the AI SDK entirely.
AI SDK 7 telemetry
On AI SDK 7, model-call spans are emitted by@ai-sdk/otel rather than ai core. Install it alongside ai@7:
experimental_telemetry config wired up by chat.toStreamTextOptions() keeps producing spans in your run trace with no extra setup. On v5 and v6 nothing changes: ai core emits the spans and @ai-sdk/otel isn’t needed.
If you (or a library you import) already register @ai-sdk/otel yourself, the SDK detects the existing integration and skips its own registration, so you won’t get duplicate spans. To opt out of the auto-registration entirely, set TRIGGER_AI_SDK_OTEL_AUTOREGISTER=0.
ChatAgentOptions
Options forchat.agent().
Plus most standard TaskOptions —
queue, machine, maxDuration, onWait, onResume, onComplete, and other lifecycle hooks. Generic retry is not exposed on chat.agent; use oomMachine for OOM recovery, or drop down to a raw task() if you need richer retry semantics. Standard hooks use the same parameter shapes as on a normal task() (including ctx).
Task context (ctx)
All chat.agent lifecycle events (onBoot, onPreload, onChatStart, onTurnStart, onBeforeTurnComplete, onTurnComplete, onCompacted) and the object passed to run include ctx: the same TaskRunContext shape as the ctx in task({ run: (payload, { ctx }) => ... }).
onValidateMessages does not include ctx — it fires before message accumulation and is designed for pure validation/transformation of incoming messages.ctx for run metadata, tags, parent links, or any API that needs the full run record. The chat-specific string runId on events is always ctx.run.id; both are provided for convenience.
Prefer
import type { TaskRunContext } from "@trigger.dev/sdk" in application code. Do not depend on @trigger.dev/core directly.ChatTaskRunPayload
The payload passed to therun function.
BootEvent
Passed to theonBoot callback.
RecoveryBootEvent
Passed to theonRecoveryBoot callback. See Recovery boot for the full guide.
RecoveryBootResult
Return value ofonRecoveryBoot. Every field is optional — omit to accept the smart default.
RecoveryPendingToolCall
PreloadEvent
Passed to theonPreload callback.
ChatStartEvent
Passed to theonChatStart callback.
ValidateMessagesEvent
Passed to theonValidateMessages callback.
ResolveToolsEvent
Passed to thetools function form on chat.agent, once per turn, to resolve the tool set for that turn. See Tools.
HydrateMessagesEvent
Passed to thehydrateMessages callback. See hydrateMessages.
ActionEvent
Passed to theonAction callback. See Actions.
TurnStartEvent
Passed to theonTurnStart callback.
TurnCompleteEvent
Passed to theonTurnComplete callback.
BeforeTurnCompleteEvent
Passed to theonBeforeTurnComplete callback. Same fields as TurnCompleteEvent (including ctx) plus a writer.
ChatSuspendEvent
Passed to theonChatSuspend callback. A discriminated union on phase.
ChatResumeEvent
Passed to theonChatResume callback. Same discriminated union shape as ChatSuspendEvent.
ChatWriter
A stream writer passed to lifecycle callbacks. Write customUIMessageChunk parts (e.g. data-* parts) to the chat stream.
The writer is lazy — no stream is opened unless you call write() or merge(), so there’s zero overhead for callbacks that don’t use it.
ChatAgentCompactionOptions
Options for thecompaction field on chat.agent(). See Compaction for usage guide.
CompactMessagesEvent
Passed tocompactUIMessages and compactModelMessages callbacks.
CompactedEvent
Passed to theonCompacted callback.
PendingMessagesOptions
Options for thependingMessages field. See Pending Messages for usage guide.
PendingMessagesBatchEvent
Passed toshouldInject and prepare callbacks.
PendingMessagesInjectedEvent
Passed toonInjected callback.
UsePendingMessagesReturn
Return value ofusePendingMessages hook. See Pending Messages — Frontend.
ChatSessionOptions
Options forchat.createSession().
ChatTurn
Each turn yielded bychat.createSession().
HeadStartHandlerOptions
Options forchat.headStart(), the warm-server first-turn handler (@trigger.dev/sdk/chat-server).
chat.headStart(options) returns the handler (req: Request) => Promise<Response>. The run callback receives HeadStartRunArgs: { messages: UIMessage[], signal: AbortSignal, chat: HeadStartChatHelper }, where the helper exposes chat.toStreamTextOptions({ tools }) and a chat.session escape hatch. See Head Start for the full guide.
chat namespace
All methods available on thechat object from @trigger.dev/sdk/ai.
chat.withUIMessage
Returns a ChatBuilder with a fixed UIMessage subtype. Chain .withClientData(), hook methods, and .agent().
Use this when you need
InferChatUIMessage / typed data-* parts / InferUITools to line up across backend hooks and useChat. Full guide: Types.
chat.withClientData
Returns a ChatBuilder with a fixed client data schema. All hooks and run get typed clientData without passing clientDataSchema in .agent() options.
Full guide: Typed client data.
ChatWithUIMessageConfig
InferChatUIMessage
Type helper: extracts the UIMessage subtype from a chat agent’s wire payload.
useChat<Msg>({ transport }) when using chat.withUIMessage. For agents defined with plain chat.agent() (no custom generic), this resolves to the base UIMessage.
InferChatUIMessageFromTools
Type helper: derives the chat UIMessage type (with typed tool-${name} parts) directly from a tool set. Shorthand for UIMessage<unknown, UIDataTypes, InferUITools<typeof tools>>.
chat.withUIMessage<ChatUiMessage>() and reuse it on the client. See Tools.
AI helpers (ai from @trigger.dev/sdk/ai)
ChatUIMessageStreamOptions
Options for customizingtoUIMessageStream(). Set as static defaults via uiMessageStreamOptions on chat.agent(), or override per-turn via chat.setUIMessageStreamOptions(). See Stream options for usage examples.
Derived from the AI SDK’s UIMessageStreamOptions with onFinish and originalMessages omitted (managed internally — onFinish for response capture, originalMessages for cross-turn message ID reuse).
TriggerChatTransport options
Options for the frontend transport constructor anduseTriggerChatTransport hook.
Transport events
TheonEvent callback receives a ChatTransportEvent (exported from @trigger.dev/sdk/chat and @trigger.dev/sdk/chat/react) for each lifecycle moment the transport observes. All events carry chatId and timestamp.
source identifies the send path: "submit-message", "regenerate-message", "steer" (sendPendingMessage), "action" (sendAction), "stop" (stopGeneration), or "head-start".
messageId on the response-side events is client-side attribution: the id from the most recent turn-producing send (submit-message, regenerate-message, or head-start) on that chat.
See Monitoring message delivery for the metrics and watchdog patterns these enable.
accessToken callback
The transport invokes accessToken whenever it needs a fresh session-scoped PAT — initial use after no PAT is cached, or after a 401/403 from any session-PAT-authed request. The callback’s job is to return a token, not to start a run.
AccessTokenParams:
Customer implementation typically wraps
auth.createPublicToken server-side:
startSession callback
The transport invokes startSession when it needs to create the session — on transport.preload(chatId), and lazily on the first sendMessage for any chatId without a cached PAT. Concurrent and repeat calls dedupe via an in-flight promise, and the customer’s wrapped helper is idempotent on (env, externalId) so two tabs / two preload calls converge on the same session.
StartSessionParams<TClientData>:
Customer implementation wraps
chat.createStartSessionAction(taskId):
startSession is optional only when the customer fully manages the session lifecycle externally (e.g. by hydrating sessions: { [chatId]: ... } and never calling preload). Most customers should provide it.
multiTab
Enable multi-tab coordination. Whentrue, only one browser tab can send messages to a given chatId at a time. Other tabs enter read-only mode with real-time message updates via BroadcastChannel.
BroadcastChannel is unavailable (SSR, Node.js). See Multi-tab coordination.
Trigger configuration
Trigger config (machine, queue, tags, maxAttempts, idleTimeoutInSeconds) lives server-side inchat.createStartSessionAction(taskId, options?). The transport doesn’t accept these options directly — pass them when wrapping the action:
chat:{chatId} tag is automatically added to every run.
For per-call values that vary by chatId (e.g. plan-tier-driven machine), accept extra params on the customer’s server action and pass them into chat.createStartSessionAction(...)’s options at call time.
transport.stopGeneration()
Stop the current generation for a chat session. Sends a stop signal to the backend task and closes the active SSE connection.true if the stop signal was sent, false if there’s no active session. Works for both initial connections and reconnected streams (after page refresh with resume: true).
Use alongside useChat’s stop() for a complete stop experience:
transport.sendAction()
Send a custom action to the agent. Actions wake the agent from suspension and fireonAction. They are not turns — run() and turn lifecycle hooks do not fire. If onAction returns a StreamTextResult, the response is auto-piped to the frontend.
actionSchema on the backend.
transport.preload()
Eagerly trigger a run before the first message.preloadIdleTimeoutInSeconds on the agent, not by this call. See Preload for full details.
useTriggerChatTransport
React hook that creates and memoizes aTriggerChatTransport instance. Import from @trigger.dev/sdk/chat/react.
AgentChat options
Options for the server-side chat client constructor. ImportAgentChat from @trigger.dev/sdk/chat.
createStartSessionAction options
Second argument tochat.createStartSessionAction(taskId, options?). Controls how the server-mediated session-create call reaches the trigger.dev API.
useMultiTabChat
React hook for multi-tab message coordination. Import from@trigger.dev/sdk/chat/react.
Returns:
{ isReadOnly: boolean } — true when another tab is actively sending to this chatId.
The hook handles:
- Tracking read-only state from the transport’s
BroadcastChannelcoordinator - Broadcasting messages when this tab is the active sender
- Receiving messages from other tabs and updating via
setMessages
ChatSession
Persistable session state for the frontendTriggerChatTransport and the server-side AgentChat. The underlying Session row is keyed on chatId (durable across runs); the persistable shape is just the SSE resume cursor and a refresh token.
ChatInputChunk
The wire shape for records sent on.in. Consumed by chat.agent internally — you typically don’t write these yourself; transport.sendMessage, transport.stopGeneration, and transport.sendAction all serialize into this shape.
For the raw wire format, see Client Protocol — ChatInputChunk.
Session token scopes
Tokens minted forTriggerChatTransport and AgentChat are session-scoped — keyed on the chat’s externalId (the chatId you assign).
Tokens are produced by
auth.createPublicToken({ scopes: { read: { sessions: chatId }, write: { sessions: chatId } } }) (used by the customer’s accessToken server action) or returned automatically from chat.createStartSessionAction / POST /api/v1/sessions. Either form authorizes both URL forms (/sessions/{chatId}/... and /sessions/session_*/...) on every read and write route.
Related
- Realtime Streams — How streams work under the hood
- Using the Vercel AI SDK — Basic AI SDK usage with Trigger.dev
- Realtime React Hooks — Lower-level realtime hooks
- Authentication — Public access tokens and trigger tokens

