Skip to content

Commit b153a34

Browse files
committed
chat example
1 parent 2b44a1b commit b153a34

File tree

1 file changed

+62
-5
lines changed
  • references/d3-chat/src/trigger

1 file changed

+62
-5
lines changed

references/d3-chat/src/trigger/chat.ts

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { anthropic } from "@ai-sdk/anthropic";
22
import { openai } from "@ai-sdk/openai";
33
import { ai } from "@trigger.dev/sdk/ai";
4-
import { logger, metadata, schemaTask, wait } from "@trigger.dev/sdk/v3";
4+
import { logger, metadata, schemaTask, tasks, wait } from "@trigger.dev/sdk/v3";
55
import { sql } from "@vercel/postgres";
66
import { streamText, TextStreamPart, tool } from "ai";
77
import { nanoid } from "nanoid";
@@ -159,10 +159,6 @@ export const todoChat = schemaTask({
159159

160160
const chunks: TextStreamPart<TOOLS>[] = [];
161161

162-
tasks.onCancel(async () => {
163-
logger.info("todo-chat: task cancelled with chunks", { chunks });
164-
});
165-
166162
const result = streamText({
167163
model: getModel(),
168164
system,
@@ -223,3 +219,64 @@ function getModel() {
223219
return anthropic("claude-3-5-sonnet-latest");
224220
}
225221
}
222+
223+
export const interruptibleChat = schemaTask({
224+
id: "interruptible-chat",
225+
description: "Chat with the AI",
226+
schema: z.object({
227+
prompt: z.string().describe("The prompt to chat with the AI"),
228+
}),
229+
run: async ({ prompt }, { signal }) => {
230+
const chunks: TextStreamPart<{}>[] = [];
231+
232+
// 👇 This is a global onCancel hook, but it's inside of the run function
233+
tasks.onCancel(async () => {
234+
logger.info("interruptible-chat: task cancelled with chunks", { chunks });
235+
});
236+
237+
try {
238+
const result = streamText({
239+
model: getModel(),
240+
prompt,
241+
experimental_telemetry: {
242+
isEnabled: true,
243+
},
244+
tools: {},
245+
abortSignal: signal,
246+
onChunk: ({ chunk }) => {
247+
chunks.push(chunk);
248+
},
249+
onError: ({ error }) => {
250+
if (error instanceof Error && error.name === "AbortError") {
251+
logger.info("interruptible-chat: streamText aborted", { error });
252+
} else {
253+
logger.error("interruptible-chat: streamText error", { error });
254+
}
255+
},
256+
onFinish: ({ finishReason }) => {
257+
logger.info("interruptible-chat: streamText finished", { finishReason });
258+
},
259+
});
260+
261+
const textParts = [];
262+
263+
for await (const part of result.textStream) {
264+
textParts.push(part);
265+
}
266+
267+
return textParts.join("");
268+
} catch (error) {
269+
if (error instanceof Error && error.name === "AbortError") {
270+
logger.info("interruptible-chat: streamText aborted (inside catch)", { error });
271+
} else {
272+
logger.error("interruptible-chat: streamText error (inside catch)", { error });
273+
}
274+
}
275+
},
276+
onCancel: async ({ runPromise }) => {
277+
// 👇 output is typed as `string` because that's the return type of the run function
278+
const output = await runPromise;
279+
280+
logger.info("interruptible-chat: task cancelled with output", { output });
281+
},
282+
});

0 commit comments

Comments
 (0)