You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`clientData` contains custom data from the frontend — either the `metadata` option on the transport constructor (sent with every message) or the `metadata` option on `sendMessage()` (per-message). See [Client data and metadata](#client-data-and-metadata).
259
+
`clientData` contains custom data from the frontend — either the `clientData` option on the transport constructor (sent with every message) or the `metadata` option on `sendMessage()` (per-message). See [Client data and metadata](#client-data-and-metadata).
260
260
</Tip>
261
261
262
262
### onTurnStart
@@ -501,13 +501,17 @@ Putting it all together — a complete chat app with server-side persistence, se
501
501
import { chat } from"@trigger.dev/sdk/ai";
502
502
import { streamText } from"ai";
503
503
import { openai } from"@ai-sdk/openai";
504
+
import { z } from"zod";
504
505
import { db } from"@/lib/db";
505
506
506
507
exportconst myChat =chat.task({
507
508
id: "my-chat",
508
-
onChatStart: async ({ chatId }) => {
509
+
clientDataSchema: z.object({
510
+
userId: z.string(),
511
+
}),
512
+
onChatStart: async ({ chatId, clientData }) => {
509
513
awaitdb.chat.create({
510
-
data: { id: chatId, title: "New chat", messages: [] },
Set default metadata on the transport that's included in every request:
686
+
Set default client data on the transport that's included in every request. When the task uses `clientDataSchema`, this is type-checked to match:
682
687
683
688
```ts
684
-
const transport =useTriggerChatTransport({
689
+
const transport =useTriggerChatTransport<typeofmyChat>({
685
690
task: "my-chat",
686
691
accessToken: getChatToken,
687
-
metadata: { userId: currentUser.id },
692
+
clientData: { userId: currentUser.id },
688
693
});
689
694
```
690
695
691
696
### Per-message metadata
692
697
693
-
Pass metadata with individual messages. Per-message values are merged with transport-level metadata (per-message wins on conflicts):
698
+
Pass metadata with individual messages via `sendMessage`. Per-message values are merged with transport-level client data (per-message wins on conflicts):
694
699
695
700
```ts
696
701
sendMessage(
@@ -699,30 +704,52 @@ sendMessage(
699
704
);
700
705
```
701
706
702
-
### Accessing client data in the task
707
+
### Typed client data with `clientDataSchema`
703
708
704
-
Both transport-level and per-message metadata are available as `clientData` in the `run` function and in `onChatStart`:
709
+
Instead of manually parsing `clientData` with Zod in every hook, pass a `clientDataSchema` to `chat.task`. The schema validates the data once per turn, and `clientData` is typed in all hooks and `run`:
705
710
706
711
```ts
712
+
import { chat } from"@trigger.dev/sdk/ai";
713
+
import { streamText } from"ai";
714
+
import { openai } from"@ai-sdk/openai";
707
715
import { z } from"zod";
708
716
709
717
exportconst myChat =chat.task({
710
718
id: "my-chat",
719
+
clientDataSchema: z.object({
720
+
model: z.string().optional(),
721
+
userId: z.string(),
722
+
}),
723
+
onChatStart: async ({ chatId, clientData }) => {
724
+
// clientData is typed as { model?: string; userId: string }
725
+
awaitdb.chat.create({
726
+
data: { id: chatId, userId: clientData.userId },
727
+
});
728
+
},
711
729
run: async ({ messages, clientData, signal }) => {
712
-
const { model, userId } =z.object({
713
-
model: z.string().optional(),
714
-
userId: z.string(),
715
-
}).parse(clientData);
716
-
730
+
// Same typed clientData — no manual parsing needed
717
731
returnstreamText({
718
-
model: openai(model??"gpt-4o"),
732
+
model: openai(clientData?.model??"gpt-4o"),
719
733
messages,
720
734
abortSignal: signal,
721
735
});
722
736
},
723
737
});
724
738
```
725
739
740
+
The schema also types the `clientData` option on the frontend transport:
741
+
742
+
```ts
743
+
// TypeScript enforces that clientData matches the schema
744
+
const transport =useTriggerChatTransport<typeofmyChat>({
745
+
task: "my-chat",
746
+
accessToken: getChatToken,
747
+
clientData: { userId: currentUser.id },
748
+
});
749
+
```
750
+
751
+
Supports Zod, ArkType, Valibot, and other schema libraries supported by the SDK.
0 commit comments