Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[prototype] provider error handling #2612

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions packages/ai/core/generate-text/generate-text.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import {
import { GenerateTextResult } from './generate-text-result';
import { ToToolCallArray, parseToolCall } from './tool-call';
import { ToToolResultArray } from './tool-result';
import { AISDKError } from '@ai-sdk/provider';
import { ProviderError } from '../../errors/provider-error';

/**
Generate a text and call tools for a given prompt using a language model.
Expand Down Expand Up @@ -215,14 +217,27 @@ By default, it's set to 0, which will disable the feature.
}),
tracer,
fn: async span => {
const result = await model.doGenerate({
mode,
...callSettings,
inputFormat: currentInputFormat,
prompt: promptMessages,
abortSignal,
headers,
});
let result: Awaited<ReturnType<LanguageModel['doGenerate']>>;

try {
result = await model.doGenerate({
mode,
...callSettings,
inputFormat: currentInputFormat,
prompt: promptMessages,
abortSignal,
headers,
});
} catch (error) {
if (error instanceof AISDKError) {
throw new ProviderError({
provider: model.provider,
message: error.message,
cause: error,
});
}
throw error;
}

// Add response information to the span:
span.setAttributes(
Expand Down
3 changes: 3 additions & 0 deletions packages/ai/errors/invalid-argument-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ export class InvalidArgumentError extends AISDKError {
);
}

/**
* @deprecated Do not use this method. It will be removed in the next major version.
*/
toJSON() {
return {
name: this.name,
Expand Down
33 changes: 33 additions & 0 deletions packages/ai/errors/provider-error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { AISDKError } from '@ai-sdk/provider';

const name = 'AI_ProviderError';
const marker = `vercel.ai.error.${name}`;
const symbol = Symbol.for(marker);

export class ProviderError extends AISDKError {
private readonly [symbol] = true; // used in isInstance

readonly provider: string;

constructor({
message,
cause,
provider,
}: {
message: string;
cause: unknown;
provider: string;
}) {
super({
name,
message: `${provider} provider: ${message}`,
cause,
});

this.provider = provider;
}

static isInstance(error: unknown): error is ProviderError {
return AISDKError.hasMarker(error, marker);
}
}
14 changes: 14 additions & 0 deletions packages/provider/src/errors/ai-sdk-error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ export class AISDKError extends Error {
*/
readonly cause?: unknown;

/**
* The provider that caused the error.
*
* Writable so it can be set by the AI SDK function on AI SDK errors
* that are thrown by providers.
*/
provider?: string;

/**
* Creates an AI SDK Error.
*
Expand All @@ -40,6 +48,12 @@ export class AISDKError extends Error {
this.cause = cause;
}

get message(): string {
return this.provider != null
? `${this.provider} provider error: ${super.message}`
: super.message;
}

/**
* Checks if the given error is an AI SDK Error.
* @param {unknown} error - The error to check.
Expand Down
Loading