feat: AI SDK 5.0 support (#2396)
* feat: AI SDK 5.0 support * Add changeset
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
---
|
||||
|
||||
feat: Support AI SDK 5.0. `ai.tool` now accepts either a schemaTask or a task with a provided jsonSchema
|
||||
@@ -547,6 +547,8 @@ export interface Task<TIdentifier extends string, TInput = void, TOutput = any>
|
||||
|
||||
description?: string;
|
||||
|
||||
jsonSchema?: JSONSchema;
|
||||
|
||||
/**
|
||||
* Trigger a task with the given payload, and continue without waiting for the result. If you want to wait for the result, use `triggerAndWait`. Returns the id of the triggered task run.
|
||||
* @param payload
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
"@types/slug": "^5.0.3",
|
||||
"@types/uuid": "^9.0.0",
|
||||
"@types/ws": "^8.5.3",
|
||||
"ai": "^4.2.0",
|
||||
"ai": "^5.0.0",
|
||||
"encoding": "^0.1.13",
|
||||
"rimraf": "^3.0.2",
|
||||
"tshy": "^3.0.2",
|
||||
@@ -78,7 +78,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"zod": "^3.0.0 || ^4.0.0",
|
||||
"ai": "^4.2.0"
|
||||
"ai": "^4.2.0 || ^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"ai": {
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
import {
|
||||
AnyTask,
|
||||
isSchemaZodEsque,
|
||||
Task,
|
||||
type inferSchemaIn,
|
||||
type TaskSchema,
|
||||
type TaskWithSchema,
|
||||
} from "@trigger.dev/core/v3";
|
||||
import { jsonSchema, Schema, tool, ToolExecutionOptions, zodSchema } from "ai";
|
||||
import { dynamicTool, jsonSchema, JSONSchema7, Schema, Tool, ToolCallOptions, zodSchema } from "ai";
|
||||
import { metadata } from "./metadata.js";
|
||||
|
||||
const METADATA_KEY = "tool.execute.options";
|
||||
|
||||
export type ToolCallExecutionOptions = Omit<ToolExecutionOptions, "abortSignal">;
|
||||
export type ToolCallExecutionOptions = Omit<ToolCallOptions, "abortSignal">;
|
||||
|
||||
type ToolResultContent = Array<
|
||||
| {
|
||||
@@ -27,25 +29,43 @@ export type ToolOptions<TResult> = {
|
||||
experimental_toToolResultContent?: (result: TResult) => ToolResultContent;
|
||||
};
|
||||
|
||||
function toolFromTask<TIdentifier extends string, TInput = void, TOutput = unknown>(
|
||||
task: Task<TIdentifier, TInput, TOutput>,
|
||||
options?: ToolOptions<TOutput>
|
||||
): Tool<TInput, TOutput>;
|
||||
function toolFromTask<
|
||||
TIdentifier extends string,
|
||||
TTaskSchema extends TaskSchema | undefined = undefined,
|
||||
TOutput = unknown,
|
||||
>(task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput>, options?: ToolOptions<TOutput>) {
|
||||
if (!task.schema) {
|
||||
>(
|
||||
task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput>,
|
||||
options?: ToolOptions<TOutput>
|
||||
): Tool<inferSchemaIn<TTaskSchema>, TOutput>;
|
||||
function toolFromTask<
|
||||
TIdentifier extends string,
|
||||
TTaskSchema extends TaskSchema | undefined = undefined,
|
||||
TInput = void,
|
||||
TOutput = unknown,
|
||||
>(
|
||||
task: TaskWithSchema<TIdentifier, TTaskSchema, TOutput> | Task<TIdentifier, TInput, TOutput>,
|
||||
options?: ToolOptions<TOutput>
|
||||
): TTaskSchema extends TaskSchema
|
||||
? Tool<inferSchemaIn<TTaskSchema>, TOutput>
|
||||
: Tool<TInput, TOutput> {
|
||||
if (("schema" in task && !task.schema) || ("jsonSchema" in task && !task.jsonSchema)) {
|
||||
throw new Error(
|
||||
"Cannot convert schemaTask to a tool because the task has no schema. Make sure the schema used in the task is either zod, arktype, or another supported schema."
|
||||
"Cannot convert this task to to a tool because the task has no schema. Make sure to either use schemaTask or a task with an input jsonSchema."
|
||||
);
|
||||
}
|
||||
|
||||
return tool({
|
||||
const toolDefinition = dynamicTool({
|
||||
description: task.description,
|
||||
parameters: convertTaskSchemaToToolParameters(task.schema),
|
||||
execute: async (args, options) => {
|
||||
inputSchema: convertTaskSchemaToToolParameters(task),
|
||||
execute: async (input, options) => {
|
||||
const serializedOptions = options ? JSON.parse(JSON.stringify(options)) : undefined;
|
||||
|
||||
return await task
|
||||
.triggerAndWait(args, {
|
||||
.triggerAndWait(input as inferSchemaIn<TTaskSchema>, {
|
||||
metadata: {
|
||||
[METADATA_KEY]: serializedOptions,
|
||||
},
|
||||
@@ -54,6 +74,10 @@ function toolFromTask<
|
||||
},
|
||||
...options,
|
||||
});
|
||||
|
||||
return toolDefinition as TTaskSchema extends TaskSchema
|
||||
? Tool<inferSchemaIn<TTaskSchema>, TOutput>
|
||||
: Tool<TInput, TOutput>;
|
||||
}
|
||||
|
||||
function getToolOptionsFromMetadata(): ToolCallExecutionOptions | undefined {
|
||||
@@ -64,21 +88,27 @@ function getToolOptionsFromMetadata(): ToolCallExecutionOptions | undefined {
|
||||
return tool as ToolCallExecutionOptions;
|
||||
}
|
||||
|
||||
function convertTaskSchemaToToolParameters<TTaskSchema extends TaskSchema>(
|
||||
schema: TTaskSchema
|
||||
): Schema<inferSchemaIn<TTaskSchema>> {
|
||||
// If TaskSchema is ZodEsque, use ai.zodSchema to convert it to a Schema
|
||||
if (isSchemaZodEsque(schema)) {
|
||||
return zodSchema(schema as any);
|
||||
function convertTaskSchemaToToolParameters(
|
||||
task: AnyTask | TaskWithSchema<any, any, any>
|
||||
): Schema<unknown> {
|
||||
if ("schema" in task) {
|
||||
// If TaskSchema is ArkTypeEsque, use ai.jsonSchema to convert it to a Schema
|
||||
if ("toJsonSchema" in task.schema && typeof task.schema.toJsonSchema === "function") {
|
||||
return jsonSchema((task.schema as any).toJsonSchema());
|
||||
}
|
||||
|
||||
// If TaskSchema is ZodEsque, use ai.zodSchema to convert it to a Schema
|
||||
if (isSchemaZodEsque(task.schema)) {
|
||||
return zodSchema(task.schema as any);
|
||||
}
|
||||
}
|
||||
|
||||
// If TaskSchema is ArkTypeEsque, use ai.jsonSchema to convert it to a Schema
|
||||
if ("toJsonSchema" in schema && typeof schema.toJsonSchema === "function") {
|
||||
return jsonSchema((schema as any).toJsonSchema());
|
||||
if ("jsonSchema" in task) {
|
||||
return jsonSchema(task.jsonSchema as JSONSchema7);
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
"Cannot convert schemaTask to a tool. Make sure the schema used in the task is either zod, arktype, or another supported schema."
|
||||
"Cannot convert task to a tool. Make sure to use a task with a schema or jsonSchema."
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -161,6 +161,7 @@ export function createTask<
|
||||
const task: Task<TIdentifier, TInput, TOutput> = {
|
||||
id: params.id,
|
||||
description: params.description,
|
||||
jsonSchema: params.jsonSchema,
|
||||
trigger: async (payload, options) => {
|
||||
return await trigger_internal<RunTypes<TIdentifier, TInput, TOutput>>(
|
||||
"trigger()",
|
||||
|
||||
Generated
+70
-62
@@ -1902,8 +1902,8 @@ importers:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.4
|
||||
ai:
|
||||
specifier: ^4.2.0
|
||||
version: 4.2.5(react@18.3.1)(zod@3.25.76)
|
||||
specifier: ^5.0.0
|
||||
version: 5.0.14(zod@3.25.76)
|
||||
encoding:
|
||||
specifier: ^0.1.13
|
||||
version: 0.1.13
|
||||
@@ -1939,11 +1939,11 @@ importers:
|
||||
references/d3-chat:
|
||||
dependencies:
|
||||
'@ai-sdk/anthropic':
|
||||
specifier: ^1.2.4
|
||||
version: 1.2.4(zod@3.25.76)
|
||||
specifier: 2.0.4
|
||||
version: 2.0.4(zod@3.25.76)
|
||||
'@ai-sdk/openai':
|
||||
specifier: 1.3.3
|
||||
version: 1.3.3(zod@3.25.76)
|
||||
specifier: 2.0.14
|
||||
version: 2.0.14(zod@3.25.76)
|
||||
'@e2b/code-interpreter':
|
||||
specifier: ^1.1.0
|
||||
version: 1.1.0
|
||||
@@ -1993,8 +1993,8 @@ importers:
|
||||
specifier: ^0.10.0
|
||||
version: 0.10.0
|
||||
ai:
|
||||
specifier: 4.2.5
|
||||
version: 4.2.5(react@19.0.0)(zod@3.25.76)
|
||||
specifier: 5.0.14
|
||||
version: 5.0.14(zod@3.25.76)
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.1
|
||||
version: 0.7.1
|
||||
@@ -2599,17 +2599,27 @@ packages:
|
||||
resolution: {integrity: sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ==}
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/anthropic@1.2.4(zod@3.25.76):
|
||||
resolution: {integrity: sha512-dAN6MXvLffeFVAr2gz3RGvOTgX1KL/Yn5q1l4/Dt0TUeDjQgCt4AbbYxZZB2qIAYzQvoyAFPhlw0sB3nNizG/g==}
|
||||
/@ai-sdk/anthropic@2.0.4(zod@3.25.76):
|
||||
resolution: {integrity: sha512-ii2bZEUPwBitUiK1dpX+HsOarcDGY71G9TVdSJqbfXSVqa+speJNZ8PA/bjuNMml0NyX8VxNsaMg3SwBUCZspA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.0.0
|
||||
zod: ^3.25.76 || ^4
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.0
|
||||
'@ai-sdk/provider-utils': 2.2.3(zod@3.25.76)
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.3(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/gateway@1.0.6(zod@3.25.76):
|
||||
resolution: {integrity: sha512-JuSj1MtTr4vw2VBBth4wlbciQnQIV0o1YV9qGLFA+r85nR5H+cJp3jaYE0nprqfzC9rYG8w9c6XGHB3SDKgcgA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.3(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
|
||||
/@ai-sdk/openai@1.0.1(zod@3.25.76):
|
||||
resolution: {integrity: sha512-snZge8457afWlosVNUn+BG60MrxAPOOm3zmIMxJZih8tneNSiRbTVCbSzAtq/9vsnOHDe5RR83PRl85juOYEnA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2643,6 +2653,17 @@ packages:
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/openai@2.0.14(zod@3.25.76):
|
||||
resolution: {integrity: sha512-u/wi1ixcvcg29wAJySjO803HlXpyCl6mkcOHn+Zn7DA+CtjuQNkKikJ4pZBc7I3Qhi90kA4XnOfKikhBXh4c4Q==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.3(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider-utils@1.0.17(zod@3.25.76):
|
||||
resolution: {integrity: sha512-2VyeTH5DQ6AxqvwdyytKIeiZyYTyJffpufWjE67zM2sXMIHgYl7fivo8m5wVl6Cbf1dFPSGKq//C9s+lz+NHrQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2701,17 +2722,6 @@ packages:
|
||||
nanoid: 3.3.8
|
||||
secure-json-parse: 2.7.0
|
||||
zod: 3.25.76
|
||||
|
||||
/@ai-sdk/provider-utils@2.2.3(zod@3.25.76):
|
||||
resolution: {integrity: sha512-o3fWTzkxzI5Af7U7y794MZkYNEsxbjLam2nxyoUZSScqkacb7vZ3EYHLh21+xCcSSzEC161C7pZAGHtC0hTUMw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.23.8
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.0
|
||||
nanoid: 3.3.8
|
||||
secure-json-parse: 2.7.0
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider-utils@2.2.8(zod@3.25.76):
|
||||
@@ -2726,6 +2736,18 @@ packages:
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider-utils@3.0.3(zod@3.25.76):
|
||||
resolution: {integrity: sha512-kAxIw1nYmFW1g5TvE54ZB3eNtgZna0RnLjPUp1ltz1+t9xkXJIuDT4atrwfau9IbS0BOef38wqrI8CjFfQrxhw==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@standard-schema/spec': 1.0.0
|
||||
eventsource-parser: 3.0.3
|
||||
zod: 3.25.76
|
||||
zod-to-json-schema: 3.24.5(zod@3.25.76)
|
||||
|
||||
/@ai-sdk/provider@0.0.22:
|
||||
resolution: {integrity: sha512-smZ1/2jL/JSKnbhC6ama/PxI2D/psj+YAe0c0qpd5ComQCNFltg72VFf0rpUSFMmFuj1pCCNoBOCrvyl8HTZHQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2752,6 +2774,7 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider@1.1.3:
|
||||
resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==}
|
||||
@@ -2760,6 +2783,12 @@ packages:
|
||||
json-schema: 0.4.0
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/provider@2.0.0:
|
||||
resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==}
|
||||
engines: {node: '>=18'}
|
||||
dependencies:
|
||||
json-schema: 0.4.0
|
||||
|
||||
/@ai-sdk/react@0.0.53(react@19.0.0-rc.0)(zod@3.25.76):
|
||||
resolution: {integrity: sha512-sIsmTFoR/QHvUUkltmHwP4bPjwy2vko6j/Nj8ayxLhEHs04Ug+dwXQyfA7MwgimEE3BcDQpWL8ikVj0m3ZILWQ==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2837,24 +2866,6 @@ packages:
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/react@1.2.2(react@18.3.1)(zod@3.25.76):
|
||||
resolution: {integrity: sha512-rxyNTFjUd3IilVOJFuUJV5ytZBYAIyRi50kFS2gNmSEiG4NHMBBm31ddrxI/i86VpY8gzZVp1/igtljnWBihUA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19 || ^19.0.0-rc
|
||||
zod: ^3.23.8
|
||||
peerDependenciesMeta:
|
||||
zod:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider-utils': 2.2.1(zod@3.25.76)
|
||||
'@ai-sdk/ui-utils': 1.2.1(zod@3.25.76)
|
||||
react: 18.3.1
|
||||
swr: 2.2.5(react@18.3.1)
|
||||
throttleit: 2.1.0
|
||||
zod: 3.25.76
|
||||
dev: true
|
||||
|
||||
/@ai-sdk/react@1.2.2(react@19.0.0)(zod@3.25.76):
|
||||
resolution: {integrity: sha512-rxyNTFjUd3IilVOJFuUJV5ytZBYAIyRi50kFS2gNmSEiG4NHMBBm31ddrxI/i86VpY8gzZVp1/igtljnWBihUA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -2996,6 +3007,7 @@ packages:
|
||||
'@ai-sdk/provider-utils': 2.2.1(zod@3.25.76)
|
||||
zod: 3.25.76
|
||||
zod-to-json-schema: 3.24.5(zod@3.25.76)
|
||||
dev: false
|
||||
|
||||
/@ai-sdk/ui-utils@1.2.11(zod@3.25.76):
|
||||
resolution: {integrity: sha512-3zcwCc8ezzFlwp3ZD15wAPjf2Au4s3vAbKsXQVyhxODHcmu0iyPO2Eua6D/vicq/AUm/BAo60r97O6HU+EI0+w==}
|
||||
@@ -21677,26 +21689,6 @@ packages:
|
||||
zod-to-json-schema: 3.24.5(zod@3.25.76)
|
||||
dev: false
|
||||
|
||||
/ai@4.2.5(react@18.3.1)(zod@3.25.76):
|
||||
resolution: {integrity: sha512-URJEslI3cgF/atdTJHtz+Sj0W1JTmiGmD3znw9KensL3qV605odktDim+GTazNJFPR4QaIu1lUio5b8RymvOjA==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
react: ^18 || ^19 || ^19.0.0-rc
|
||||
zod: ^3.23.8
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
dependencies:
|
||||
'@ai-sdk/provider': 1.1.0
|
||||
'@ai-sdk/provider-utils': 2.2.1(zod@3.25.76)
|
||||
'@ai-sdk/react': 1.2.2(react@18.3.1)(zod@3.25.76)
|
||||
'@ai-sdk/ui-utils': 1.2.1(zod@3.25.76)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
jsondiffpatch: 0.6.0
|
||||
react: 18.3.1
|
||||
zod: 3.25.76
|
||||
dev: true
|
||||
|
||||
/ai@4.2.5(react@19.0.0)(zod@3.25.76):
|
||||
resolution: {integrity: sha512-URJEslI3cgF/atdTJHtz+Sj0W1JTmiGmD3znw9KensL3qV605odktDim+GTazNJFPR4QaIu1lUio5b8RymvOjA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -21737,6 +21729,18 @@ packages:
|
||||
zod: 3.25.76
|
||||
dev: false
|
||||
|
||||
/ai@5.0.14(zod@3.25.76):
|
||||
resolution: {integrity: sha512-xiujFa879skB7YxGzbeHAxepsr6AEaWcHPXrc5a9MRM6p4WdVAwn6mGwVZkBnhqGfZtXFr4LUnU2ayvcjWp5ig==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.25.76 || ^4
|
||||
dependencies:
|
||||
'@ai-sdk/gateway': 1.0.6(zod@3.25.76)
|
||||
'@ai-sdk/provider': 2.0.0
|
||||
'@ai-sdk/provider-utils': 3.0.3(zod@3.25.76)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
zod: 3.25.76
|
||||
|
||||
/ajv-formats@2.1.1(ajv@8.17.1):
|
||||
resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==}
|
||||
peerDependencies:
|
||||
@@ -25816,6 +25820,10 @@ packages:
|
||||
engines: {node: '>=18.0.0'}
|
||||
dev: false
|
||||
|
||||
/eventsource-parser@3.0.3:
|
||||
resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==}
|
||||
engines: {node: '>=20.0.0'}
|
||||
|
||||
/eventsource@3.0.5:
|
||||
resolution: {integrity: sha512-LT/5J605bx5SNyE+ITBDiM3FxffBiq9un7Vx0EwMDM3vg8sWKx/tO2zC+LMqZ+smAM0F2hblaDZUVZF0te2pSw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
"db:migrate:down": "tsx -r dotenv/config src/lib/migrate.ts down"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^1.2.4",
|
||||
"@ai-sdk/openai": "1.3.3",
|
||||
"@ai-sdk/anthropic": "2.0.4",
|
||||
"@ai-sdk/openai": "2.0.14",
|
||||
"@e2b/code-interpreter": "^1.1.0",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/api-logs": "^0.203.0",
|
||||
@@ -37,7 +37,7 @@
|
||||
"@trigger.dev/sdk": "workspace:*",
|
||||
"@vercel/otel": "^1.13.0",
|
||||
"@vercel/postgres": "^0.10.0",
|
||||
"ai": "4.2.5",
|
||||
"ai": "5.0.14",
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"lucide-react": "^0.486.0",
|
||||
|
||||
@@ -61,17 +61,17 @@ function getMessagesFromRun(
|
||||
id: `tool-${part.toolCallId}`,
|
||||
role: "tool",
|
||||
name: part.toolName,
|
||||
input: part.args,
|
||||
input: part.input,
|
||||
};
|
||||
toolCalls.set(part.toolCallId, toolMessage);
|
||||
messages.push(toolMessage);
|
||||
} else if (part.type === "tool-result") {
|
||||
const toolMessage = toolCalls.get(part.toolCallId);
|
||||
if (toolMessage) {
|
||||
toolMessage.output = part.result;
|
||||
toolMessage.output = part.output;
|
||||
}
|
||||
} else if (part.type === "text-delta") {
|
||||
currentAssistantContent += part.textDelta;
|
||||
currentAssistantContent += part.text;
|
||||
|
||||
// Find or create the assistant message
|
||||
const lastMessage = messages[messages.length - 1];
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { anthropic } from "@ai-sdk/anthropic";
|
||||
import { openai } from "@ai-sdk/openai";
|
||||
import { ai } from "@trigger.dev/sdk/ai";
|
||||
import { logger, metadata, runs, schemaTask, tasks, wait, otel } from "@trigger.dev/sdk/v3";
|
||||
import { logger, metadata, runs, schemaTask, tasks, wait, otel, task } from "@trigger.dev/sdk/v3";
|
||||
import { sql } from "@vercel/postgres";
|
||||
import {
|
||||
CoreMessage,
|
||||
createDataStream,
|
||||
DataStreamWriter,
|
||||
ModelMessage,
|
||||
streamText,
|
||||
TextStreamPart,
|
||||
tool,
|
||||
stepCountIs,
|
||||
createUIMessageStream,
|
||||
UIMessageStreamWriter,
|
||||
} from "ai";
|
||||
import { nanoid } from "nanoid";
|
||||
import { z } from "zod";
|
||||
@@ -80,9 +81,57 @@ const queryApprovalTask = schemaTask({
|
||||
|
||||
const queryApproval = ai.tool(queryApprovalTask);
|
||||
|
||||
// const queryApprovalTask = task({
|
||||
// id: "query-approval",
|
||||
// description: "Get approval for a SQL query from an admin",
|
||||
// jsonSchema: {
|
||||
// type: "object",
|
||||
// properties: {
|
||||
// userId: { type: "string", description: "The user_id to get approval for" },
|
||||
// input: { type: "string", description: "The input to get approval for" },
|
||||
// query: { type: "string", description: "The SQL query to execute" },
|
||||
// },
|
||||
// required: ["userId", "input", "query"],
|
||||
// additionalProperties: false,
|
||||
// },
|
||||
// run: async ({ userId, input, query }: { userId: string; input: string; query: string }) => {
|
||||
// logger.info("queryApproval: starting", { projectRef: process.env.TRIGGER_PROJECT_REF });
|
||||
|
||||
// await callNextjsApp();
|
||||
|
||||
// const token = await wait.createToken({
|
||||
// tags: [`user:${userId}`, "approval"],
|
||||
// timeout: "5m", // timeout in 5 minutes
|
||||
// });
|
||||
|
||||
// await sendSQLApprovalMessage({
|
||||
// query,
|
||||
// userId,
|
||||
// tokenId: token.id,
|
||||
// publicAccessToken: token.publicAccessToken,
|
||||
// input,
|
||||
// });
|
||||
|
||||
// const result = await wait.forToken<QueryApproval>(token);
|
||||
|
||||
// // result.ok === false if the token timed out
|
||||
// if (!result.ok) {
|
||||
// logger.debug("queryApproval: token timed out");
|
||||
|
||||
// return {
|
||||
// approved: false,
|
||||
// };
|
||||
// } else {
|
||||
// return result.output;
|
||||
// }
|
||||
// },
|
||||
// });
|
||||
|
||||
// const queryApproval = ai.tool(queryApprovalTask);
|
||||
|
||||
const executeSql = tool({
|
||||
description: "Use this tool to execute a SQL query",
|
||||
parameters: z.object({
|
||||
inputSchema: z.object({
|
||||
query: z.string().describe("The SQL query to execute"),
|
||||
}),
|
||||
execute: async ({ query }) => {
|
||||
@@ -95,7 +144,7 @@ const executeSql = tool({
|
||||
|
||||
const generateId = tool({
|
||||
description: "Use this tool to generate a unique ID for a todo",
|
||||
parameters: z.object({
|
||||
inputSchema: z.object({
|
||||
prefix: z.string().describe("The prefix for the ID (defaults to 'todo')").default("todo"),
|
||||
}),
|
||||
execute: async ({ prefix }) => {
|
||||
@@ -105,7 +154,7 @@ const generateId = tool({
|
||||
|
||||
const getUserTodos = tool({
|
||||
description: "Use this tool to get all todos for a user",
|
||||
parameters: z.object({
|
||||
inputSchema: z.object({
|
||||
userId: z.string().describe("The user_id to get todos for"),
|
||||
}),
|
||||
execute: async ({ userId }) => {
|
||||
@@ -117,7 +166,7 @@ const getUserTodos = tool({
|
||||
|
||||
const getUserId = tool({
|
||||
description: "Use this tool to get the user_id for the current user",
|
||||
parameters: z.object({}),
|
||||
inputSchema: z.object({}),
|
||||
execute: async () => {
|
||||
const userId = metadata.get("user_id");
|
||||
|
||||
@@ -202,7 +251,7 @@ export const todoChat = schemaTask({
|
||||
model: getModel(),
|
||||
system,
|
||||
prompt,
|
||||
maxSteps: 10,
|
||||
stopWhen: stepCountIs(10),
|
||||
tools: {
|
||||
queryApproval,
|
||||
executeSql,
|
||||
@@ -227,7 +276,7 @@ export const todoChat = schemaTask({
|
||||
|
||||
for await (const part of stream) {
|
||||
if (part.type === "text-delta") {
|
||||
textParts.push(part.textDelta);
|
||||
textParts.push(part.text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,7 +358,7 @@ export const interruptibleChat = schemaTask({
|
||||
|
||||
async function createStreamWithProvider(params: {
|
||||
model: ReturnType<typeof anthropic> | ReturnType<typeof openai>;
|
||||
messages: CoreMessage[];
|
||||
messages: ModelMessage[];
|
||||
message_request_id: string;
|
||||
chat_id: string;
|
||||
userId?: string;
|
||||
@@ -317,14 +366,13 @@ async function createStreamWithProvider(params: {
|
||||
const { model, messages, message_request_id, chat_id, userId } = params;
|
||||
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
const dataStreamResponse = createDataStream({
|
||||
const dataStreamResponse = createUIMessageStream({
|
||||
execute: async (dataStream) => {
|
||||
const result = streamText({
|
||||
model,
|
||||
system: "This is the system prompt, please be nice.",
|
||||
messages,
|
||||
maxSteps: 20,
|
||||
toolCallStreaming: true,
|
||||
stopWhen: stepCountIs(20),
|
||||
onError: (error) => {
|
||||
logger.error("Error in chatStream task (streamText)", {
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
@@ -336,7 +384,7 @@ async function createStreamWithProvider(params: {
|
||||
onChunk: async (chunk) => {
|
||||
console.log("Chunk:", chunk);
|
||||
},
|
||||
onFinish: async ({ response, reasoning }) => {
|
||||
onFinish: async ({ response, reasoningText }) => {
|
||||
metadata.flush();
|
||||
logger.info("AI stream finished", {
|
||||
chat_id,
|
||||
@@ -372,9 +420,7 @@ async function createStreamWithProvider(params: {
|
||||
|
||||
result.consumeStream();
|
||||
|
||||
result.mergeIntoDataStream(dataStream, {
|
||||
sendReasoning: true,
|
||||
});
|
||||
dataStream.writer.merge(result.toUIMessageStream());
|
||||
},
|
||||
onError: (error) => {
|
||||
logger.error("Error in chatStream task (createDataStream)", {
|
||||
@@ -431,7 +477,7 @@ export const chatStream = schemaTask({
|
||||
// First try with Anthropic
|
||||
return await createStreamWithProvider({
|
||||
model: anthropic(model),
|
||||
messages: messages as CoreMessage[],
|
||||
messages: messages as ModelMessage[],
|
||||
message_request_id,
|
||||
chat_id,
|
||||
userId,
|
||||
@@ -449,7 +495,7 @@ export const chatStream = schemaTask({
|
||||
// Fallback to OpenAI
|
||||
return await createStreamWithProvider({
|
||||
model: openai("gpt-4"),
|
||||
messages: messages as CoreMessage[],
|
||||
messages: messages as ModelMessage[],
|
||||
message_request_id,
|
||||
chat_id,
|
||||
userId,
|
||||
@@ -534,12 +580,12 @@ export const chatStream2 = schemaTask({
|
||||
message_request_id,
|
||||
});
|
||||
|
||||
const dataStreamResponse = createDataStream({
|
||||
execute: async (dataStream) => {
|
||||
const dataStreamResponse = createUIMessageStream({
|
||||
execute: async ({ writer }) => {
|
||||
streamTextWithModel(
|
||||
dataStream,
|
||||
writer,
|
||||
anthropic(model),
|
||||
messages as CoreMessage[],
|
||||
messages as ModelMessage[],
|
||||
chat_id,
|
||||
openai("gpt-4"),
|
||||
userId
|
||||
@@ -556,9 +602,9 @@ export const chatStream2 = schemaTask({
|
||||
});
|
||||
|
||||
function streamTextWithModel(
|
||||
dataStream: DataStreamWriter,
|
||||
writer: UIMessageStreamWriter,
|
||||
model: ReturnType<typeof anthropic> | ReturnType<typeof openai>,
|
||||
messages: CoreMessage[],
|
||||
messages: ModelMessage[],
|
||||
chat_id: string,
|
||||
fallbackModel?: ReturnType<typeof anthropic> | ReturnType<typeof openai>,
|
||||
userId?: string
|
||||
@@ -567,8 +613,7 @@ function streamTextWithModel(
|
||||
model,
|
||||
system: "This is the system prompt, please be nice.",
|
||||
messages,
|
||||
maxSteps: 20,
|
||||
toolCallStreaming: true,
|
||||
stopWhen: stepCountIs(20),
|
||||
onError: (error) => {
|
||||
logger.error("Error in chatStream task (streamText)", {
|
||||
error: error instanceof Error ? error.message : "Unknown error",
|
||||
@@ -577,13 +622,13 @@ function streamTextWithModel(
|
||||
});
|
||||
|
||||
if (fallbackModel) {
|
||||
streamTextWithModel(dataStream, fallbackModel, messages, chat_id, undefined, userId);
|
||||
streamTextWithModel(writer, fallbackModel, messages, chat_id, undefined, userId);
|
||||
}
|
||||
},
|
||||
onChunk: async (chunk) => {
|
||||
console.log("Chunk:", chunk);
|
||||
},
|
||||
onFinish: async ({ response, reasoning }) => {
|
||||
onFinish: async ({ response, reasoningText }) => {
|
||||
metadata.flush();
|
||||
logger.info("AI stream finished", {
|
||||
chat_id,
|
||||
@@ -619,9 +664,7 @@ function streamTextWithModel(
|
||||
|
||||
result.consumeStream();
|
||||
|
||||
result.mergeIntoDataStream(dataStream, {
|
||||
sendReasoning: true,
|
||||
});
|
||||
writer.merge(result.toUIMessageStream());
|
||||
}
|
||||
|
||||
export const chatStreamCaller2 = schemaTask({
|
||||
|
||||
Reference in New Issue
Block a user