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:
Eric Allam
2023-07-08 22:14:23 +01:00
parent 61ed1fb202
commit c34a02c06f
6 changed files with 111 additions and 13 deletions
+6
View File
@@ -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",
+25
View File
@@ -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})` : ""}`);
}
+16 -1
View File
@@ -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);
},
+1 -1
View File
@@ -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: {
+19 -11
View File
@@ -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
);
}
}
}