Skip to content

Commit af510e6

Browse files
Document and demo @trigger.dev/ai useChat transport
Co-authored-by: Eric Allam <eric@trigger.dev>
1 parent 0f932eb commit af510e6

File tree

9 files changed

+365
-58
lines changed

9 files changed

+365
-58
lines changed

.changeset/curly-radios-visit.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
"@trigger.dev/ai": minor
3+
---
4+
5+
Add a new `@trigger.dev/ai` package with:
6+
7+
- `ai.tool(...)` and `ai.currentToolOptions()` helpers for AI SDK tool calling ergonomics
8+
- a typed `TriggerChatTransport` that plugs into AI SDK UI `useChat()` and runs chat backends as Trigger.dev tasks
9+
- rich default task payloads (`chatId`, trigger metadata, messages, request context) with optional payload mapping
10+
- reconnect-aware stream handling on top of Trigger.dev Realtime Streams v2

docs/tasks/schemaTask.mdx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ await myTask.trigger({ name: "Alice", age: 30, dob: "2020-01-01" }); // this is
8181
The `ai.tool` function allows you to create an AI tool from an existing `schemaTask` to use with the Vercel [AI SDK](https://vercel.com/docs/ai-sdk):
8282

8383
```ts
84-
import { ai } from "@trigger.dev/sdk/ai";
84+
import { ai } from "@trigger.dev/ai";
8585
import { schemaTask } from "@trigger.dev/sdk";
8686
import { z } from "zod";
8787
import { generateText } from "ai";
@@ -118,7 +118,7 @@ You can also pass the `experimental_toToolResultContent` option to the `ai.tool`
118118
```ts
119119
import { openai } from "@ai-sdk/openai";
120120
import { Sandbox } from "@e2b/code-interpreter";
121-
import { ai } from "@trigger.dev/sdk/ai";
121+
import { ai } from "@trigger.dev/ai";
122122
import { schemaTask } from "@trigger.dev/sdk";
123123
import { generateObject } from "ai";
124124
import { z } from "zod";
@@ -183,7 +183,7 @@ export const chartTool = ai.tool(chartTask, {
183183
You can access the current tool execution options inside the task run function using the `ai.currentToolOptions()` function:
184184

185185
```ts
186-
import { ai } from "@trigger.dev/sdk/ai";
186+
import { ai } from "@trigger.dev/ai";
187187
import { schemaTask } from "@trigger.dev/sdk";
188188
import { z } from "zod";
189189

docs/tasks/streams.mdx

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,95 @@ const { parts, error } = useRealtimeStream(streamDef, runId, {
517517
});
518518
```
519519

520+
## AI SDK `useChat` transport with Trigger.dev tasks
521+
522+
If you want to use AI SDK UI's `useChat()` on the frontend and run the backend as a Trigger.dev task,
523+
use the `@trigger.dev/ai` transport.
524+
525+
### Install
526+
527+
```bash
528+
npm add @trigger.dev/ai @ai-sdk/react ai
529+
```
530+
531+
### Define a typed stream
532+
533+
```ts
534+
// app/streams.ts
535+
import { streams } from "@trigger.dev/sdk";
536+
import { UIMessageChunk } from "ai";
537+
538+
export const aiStream = streams.define<UIMessageChunk>({
539+
id: "ai",
540+
});
541+
```
542+
543+
### Create a task that accepts rich chat transport payload
544+
545+
```ts
546+
// trigger/chat-task.ts
547+
import { openai } from "@ai-sdk/openai";
548+
import type { TriggerChatTransportPayload } from "@trigger.dev/ai";
549+
import { task } from "@trigger.dev/sdk";
550+
import { convertToModelMessages, streamText, UIMessage } from "ai";
551+
import { aiStream } from "@/app/streams";
552+
553+
type ChatPayload = TriggerChatTransportPayload<UIMessage>;
554+
555+
export const aiChatTask = task({
556+
id: "ai-chat",
557+
run: async (payload: ChatPayload) => {
558+
const result = streamText({
559+
model: openai("gpt-4o"),
560+
messages: convertToModelMessages(payload.messages),
561+
});
562+
563+
const { waitUntilComplete } = aiStream.pipe(result.toUIMessageStream());
564+
await waitUntilComplete();
565+
},
566+
});
567+
```
568+
569+
### Use `useChat()` with Trigger chat transport
570+
571+
```tsx
572+
"use client";
573+
574+
import { useChat } from "@ai-sdk/react";
575+
import { TriggerChatTransport } from "@trigger.dev/ai";
576+
import { aiStream } from "@/app/streams";
577+
578+
export function Chat({ triggerToken }: { triggerToken: string }) {
579+
const chat = useChat({
580+
transport: new TriggerChatTransport({
581+
task: "ai-chat",
582+
stream: aiStream,
583+
accessToken: triggerToken,
584+
timeoutInSeconds: 120,
585+
}),
586+
});
587+
588+
return (
589+
<form
590+
onSubmit={(event) => {
591+
event.preventDefault();
592+
chat.sendMessage({ text: "Hello!" });
593+
}}
594+
>
595+
<button type="submit">Send</button>
596+
</form>
597+
);
598+
}
599+
```
600+
601+
The default payload sent to your task is a rich, typed object that includes:
602+
603+
- `chatId`
604+
- `trigger` (`"submit-message"` or `"regenerate-message"`)
605+
- `messageId`
606+
- `messages`
607+
- `request` (`headers`, `body`, and `metadata`)
608+
520609
## Complete Example: AI Streaming
521610

522611
### Define the stream

0 commit comments

Comments
 (0)