Improved OpenAI integration task errors
And also now allowing runTask.onError to also return an Error by itself if it wants to not retry the task
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@trigger.dev/sdk": patch
|
||||
"@trigger.dev/openai": patch
|
||||
---
|
||||
|
||||
Improved OpenAI task errors
|
||||
@@ -137,6 +137,50 @@ new Job(client, {
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "openai-errors",
|
||||
name: "OpenAI Errors",
|
||||
version: "0.0.1",
|
||||
enabled,
|
||||
trigger: eventTrigger({
|
||||
name: "openai.errors",
|
||||
}),
|
||||
integrations: {
|
||||
openai,
|
||||
},
|
||||
run: async (payload, io, ctx) => {
|
||||
await io.openai.createChatCompletion("chat-completion", {
|
||||
model: "gpt-3.5-turbo",
|
||||
messages: [
|
||||
{
|
||||
role: "system",
|
||||
content:
|
||||
"You are an AI assistant that is helpful, creative, clever, and very friendly.",
|
||||
},
|
||||
{
|
||||
role: "user",
|
||||
content:
|
||||
"Call the supplied function that will tweet a really funny joke",
|
||||
},
|
||||
],
|
||||
function_call: { name: "tweetFunnyJoke" },
|
||||
functions: [
|
||||
{
|
||||
name: "tweetFunnyJoke",
|
||||
description:
|
||||
"Tweets a really funny joke. The joke is so funny that it will make you laugh out loud.",
|
||||
parameters: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
new Job(client, {
|
||||
id: "on-missing-auth-connection",
|
||||
name: "On missing auth connection",
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
CreateCompletionResponseUsage,
|
||||
CreateEmbeddingResponseUsage,
|
||||
} from "openai";
|
||||
import { z } from "zod";
|
||||
|
||||
export function createTaskUsageProperties(
|
||||
usage:
|
||||
@@ -32,3 +33,27 @@ export function createTaskUsageProperties(
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
const OpenAIErrorSchema = z.object({
|
||||
response: z.object({
|
||||
data: z.object({
|
||||
error: z.object({
|
||||
code: z.string().nullable().optional(),
|
||||
message: z.string(),
|
||||
type: z.string(),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
export function onTaskError(error: unknown) {
|
||||
const openAIError = OpenAIErrorSchema.safeParse(error);
|
||||
|
||||
if (!openAIError.success) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { message, code, type } = openAIError.data.response.data.error;
|
||||
|
||||
return new Error(`${type}: ${message}${code ? ` (${code})` : ""}`);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
fileFromString,
|
||||
truncate,
|
||||
} from "@trigger.dev/integration-kit";
|
||||
import { createTaskUsageProperties } from "./taskUtils";
|
||||
import { createTaskUsageProperties, onTaskError } from "./taskUtils";
|
||||
|
||||
type OpenAIClientType = InstanceType<typeof OpenAIApi>;
|
||||
|
||||
@@ -32,6 +32,7 @@ export const retrieveModel: AuthenticatedTask<
|
||||
Prettify<RetrieveModelRequest>,
|
||||
RetrieveModelResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.retrieveModel(params.model).then((res) => res.data);
|
||||
},
|
||||
@@ -59,6 +60,7 @@ export const listModels: AuthenticatedTask<
|
||||
void,
|
||||
Prettify<ListModelsResponseData>
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.listModels().then((res) => res.data);
|
||||
},
|
||||
@@ -154,6 +156,7 @@ export const createChatCompletion: AuthenticatedTask<
|
||||
Prettify<CreateChatCompletionRequest>,
|
||||
Prettify<CreateChatCompetionResponseData>
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client, task) => {
|
||||
const response = await client.createChatCompletion(params);
|
||||
|
||||
@@ -245,6 +248,7 @@ export const createEdit: AuthenticatedTask<
|
||||
Prettify<CreateEditRequest>,
|
||||
CreateEditResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client, task) => {
|
||||
const response = await client.createEdit(params);
|
||||
|
||||
@@ -290,6 +294,7 @@ export const createImage: AuthenticatedTask<
|
||||
Prettify<CreateImageRequest>,
|
||||
CreateImageResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client, task) => {
|
||||
const response = await client.createImage(params);
|
||||
|
||||
@@ -342,6 +347,7 @@ export const createEmbedding: AuthenticatedTask<
|
||||
Prettify<CreateEmbeddingRequest>,
|
||||
CreateEmbeddingResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client, task) => {
|
||||
const response = await client.createEmbedding(params);
|
||||
|
||||
@@ -386,6 +392,7 @@ export const createFile: AuthenticatedTask<
|
||||
Prettify<CreateFileRequest>,
|
||||
Prettify<CreateFileResponseData>
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
let file: File;
|
||||
|
||||
@@ -428,6 +435,7 @@ export const listFiles: AuthenticatedTask<
|
||||
void,
|
||||
ListFilesResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.listFiles().then((res) => res.data);
|
||||
},
|
||||
@@ -454,6 +462,7 @@ export const createFineTuneFile: AuthenticatedTask<
|
||||
Prettify<CreateFineTuneFileRequest>,
|
||||
Prettify<CreateFileResponseData>
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
const file = (await fileFromString(
|
||||
params.examples.map((d) => JSON.stringify(d)).join("\n"),
|
||||
@@ -486,6 +495,7 @@ export const createFineTune: AuthenticatedTask<
|
||||
Prettify<CreateFineTuneRequest>,
|
||||
CreateFineTuneResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.createFineTune(params).then((res) => res.data);
|
||||
},
|
||||
@@ -529,6 +539,7 @@ export const listFineTunes: AuthenticatedTask<
|
||||
void,
|
||||
ListFineTunesResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.listFineTunes().then((res) => res.data);
|
||||
},
|
||||
@@ -555,6 +566,7 @@ export const retrieveFineTune: AuthenticatedTask<
|
||||
Prettify<SpecificFineTuneRequest>,
|
||||
RetrieveFineTuneResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.retrieveFineTune(params.fineTuneId).then((res) => res.data);
|
||||
},
|
||||
@@ -582,6 +594,7 @@ export const cancelFineTune: AuthenticatedTask<
|
||||
Prettify<SpecificFineTuneRequest>,
|
||||
CancelFineTuneResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.cancelFineTune(params.fineTuneId).then((res) => res.data);
|
||||
},
|
||||
@@ -609,6 +622,7 @@ export const listFineTuneEvents: AuthenticatedTask<
|
||||
Prettify<SpecificFineTuneRequest>,
|
||||
ListFineTuneEventsResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client
|
||||
.listFineTuneEvents(params.fineTuneId, false)
|
||||
@@ -642,6 +656,7 @@ export const deleteFineTune: AuthenticatedTask<
|
||||
Prettify<DeleteFineTunedModelRequest>,
|
||||
DeleteFineTuneResponseData
|
||||
> = {
|
||||
onError: onTaskError,
|
||||
run: async (params, client) => {
|
||||
return client.deleteModel(params.fineTunedModelId).then((res) => res.data);
|
||||
},
|
||||
|
||||
@@ -52,7 +52,7 @@ export type AuthenticatedTask<
|
||||
onError?: (
|
||||
error: unknown,
|
||||
task: ServerTask
|
||||
) => { retryAt: Date; error?: Error } | undefined | void;
|
||||
) => { retryAt: Date; error?: Error } | Error | undefined | void;
|
||||
};
|
||||
|
||||
export function authenticatedTask<TClient, TParams, TResult>(options: {
|
||||
|
||||
@@ -474,7 +474,11 @@ export class IO {
|
||||
error: unknown,
|
||||
task: IOTask,
|
||||
io: IO
|
||||
) => { retryAt: Date; error?: Error; jitter?: number } | undefined | void
|
||||
) =>
|
||||
| { retryAt: Date; error?: Error; jitter?: number }
|
||||
| Error
|
||||
| undefined
|
||||
| void
|
||||
): Promise<TResult> {
|
||||
const parentId = this._taskStorage.getStore()?.taskId;
|
||||
|
||||
@@ -571,17 +575,21 @@ export class IO {
|
||||
const onErrorResult = onError(error, task, this);
|
||||
|
||||
if (onErrorResult) {
|
||||
const parsedError = ErrorWithStackSchema.safeParse(
|
||||
onErrorResult.error
|
||||
);
|
||||
if (onErrorResult instanceof Error) {
|
||||
error = onErrorResult;
|
||||
} else {
|
||||
const parsedError = ErrorWithStackSchema.safeParse(
|
||||
onErrorResult.error
|
||||
);
|
||||
|
||||
throw new RetryWithTaskError(
|
||||
parsedError.success
|
||||
? parsedError.data
|
||||
: { message: "Unknown error" },
|
||||
task,
|
||||
onErrorResult.retryAt
|
||||
);
|
||||
throw new RetryWithTaskError(
|
||||
parsedError.success
|
||||
? parsedError.data
|
||||
: { message: "Unknown error" },
|
||||
task,
|
||||
onErrorResult.retryAt
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user