Agent skill · triggerdotdev
trigger-authoring-chat-agent
Author and run a durable AI chat agent with chat.agent from @trigger.dev/sdk/ai: the per-turn run loop, why you MUST spread ...chat.toStreamTextOptions() first, returning a StreamTextResult vs calling chat.pipe(), the two server actions (chat.createStartSessionAction + auth.createPublicToken), and wiring useChat to useTriggerChatTransport. Load this when building, modifying, or debugging a chat backend (the agent task or its lifecycle hooks) or its React transport, when declaring typed tools or custom data parts, or when migrating a plain AI SDK streamText route to chat.agent.
What it needs
About 7k tokens when loaded.
What this skill does
Authoring a chat agent A chat.agent runs an entire conversation as one long-lived Trigger.dev task. It wakes when a message arrives, freezes when none do, and in-memory state survives page refreshes, deploys, idle gaps, and crashes. Your code is the loop you would write anyway: messages in, streamText out. There are no API routes. The frontend talks to the agent through a TriggerChatTransport, so history accumulates server-side and the client ships only the new message each turn. Works with Vercel AI SDK v5, v6, or v7. On v7 also install @ai-sdk/otel so model calls are traced (the SDK registers it for you). Setup Three pieces: the agent task, two server actions, and the frontend transport. 1. Define the agent run receives messages already converted to ModelMessage[] (the SDK converts the frontend's UIMessage[] for you) plus a signal that aborts on stop or cancel. Returning the StreamTextResult auto-pipes it to the frontend. 2. Add two server actions Both run on your server, so the browser never holds your environment secret key. This is also where per-user / per-plan authorization and any paired DB writes live. 3. Wire the frontend The transport is memoized (created once, reused across renders). Passing typeof myChat flows the agent's message type through useChat. Core patterns 1. Return vs pipe Return the streamText result from run for the simple case. When streamText is called deep inside nested helpers, call await chat.pipe(result) from anywhere in the task instead, and let run resolve void. 2. Typed tools (declare on config AND spread back) Declare tools on chat.agent({ tools }), read them back typed from the run() payload, and pass that set to chat.toStreamTextOptions({ tools }). One declaration flows everywhere. tools also accepts a function (event) => ToolSet resolved per turn, where event carries chatId, turn, continuation, and clientData. 3. …
How to use it
Reference it in AdaL, Claude Code, Cursor or any coding agent — nothing to install:
@skills triggerdotdev/trigger-authoring-chat-agent