From 56bd30fd4e8521ac1cf547c0a299540b97dd1e05 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 6 May 2024 14:56:58 -0400 Subject: [PATCH 01/19] Add a new VertexAI error type --- .changeset/light-cheetahs-arrive.md | 5 + common/api-review/vertexai-preview.api.md | 40 +++++++ docs-devsite/vertexai-preview.errordetails.md | 66 +++++++++++ docs-devsite/vertexai-preview.md | 27 +++++ .../vertexai-preview.vertexaierror.md | 107 +++++++++++++++++ packages/vertexai/src/api.test.ts | 36 ++++-- packages/vertexai/src/api.ts | 13 ++- packages/vertexai/src/errors.ts | 63 ---------- .../src/methods/chat-session-helpers.ts | 52 +++++---- .../vertexai/src/models/generative-model.ts | 15 ++- .../vertexai/src/requests/request-helpers.ts | 24 ++-- .../vertexai/src/requests/request.test.ts | 69 ++++++++--- packages/vertexai/src/requests/request.ts | 34 ++++-- .../vertexai/src/requests/response-helpers.ts | 41 +++---- .../vertexai/src/requests/stream-reader.ts | 19 +-- packages/vertexai/src/types/error.ts | 110 ++++++++++++++++++ packages/vertexai/src/types/index.ts | 1 + 17 files changed, 556 insertions(+), 166 deletions(-) create mode 100644 .changeset/light-cheetahs-arrive.md create mode 100644 docs-devsite/vertexai-preview.errordetails.md create mode 100644 docs-devsite/vertexai-preview.vertexaierror.md delete mode 100644 packages/vertexai/src/errors.ts create mode 100644 packages/vertexai/src/types/error.ts diff --git a/.changeset/light-cheetahs-arrive.md b/.changeset/light-cheetahs-arrive.md new file mode 100644 index 00000000000..a5636bd5a97 --- /dev/null +++ b/.changeset/light-cheetahs-arrive.md @@ -0,0 +1,5 @@ +--- +'@firebase/vertexai-preview': patch +--- + +Add a new VertexAI error type diff --git a/common/api-review/vertexai-preview.api.md b/common/api-review/vertexai-preview.api.md index b3ae09e8dc7..38de1d80ae3 100644 --- a/common/api-review/vertexai-preview.api.md +++ b/common/api-review/vertexai-preview.api.md @@ -7,6 +7,7 @@ import { AppCheckTokenResult } from '@firebase/app-check-interop-types'; import { FirebaseApp } from '@firebase/app'; import { FirebaseAuthTokenData } from '@firebase/auth-interop-types'; +import { FirebaseError } from '@firebase/util'; // @public export interface BaseParams { @@ -102,6 +103,16 @@ export interface EnhancedGenerateContentResponse extends GenerateContentResponse text: () => string; } +// @public +export interface ErrorDetails { + // (undocumented) + '@type'?: string; + [key: string]: unknown; + domain?: string; + metadata?: Record; + reason?: string; +} + // @public export interface FileData { // (undocumented) @@ -590,6 +601,35 @@ export interface VertexAI { location: string; } +// @public +export class VertexAIError extends FirebaseError { + constructor(code: VertexAIErrorCode, message: string, status?: number | undefined, statusText?: string | undefined, errorDetails?: ErrorDetails[] | undefined); + // (undocumented) + readonly code: VertexAIErrorCode; + // (undocumented) + readonly errorDetails?: ErrorDetails[] | undefined; + // (undocumented) + readonly message: string; + readonly stack?: string; + // (undocumented) + readonly status?: number | undefined; + // (undocumented) + readonly statusText?: string | undefined; +} + +// @public +export const enum VertexAIErrorCode { + ERROR = "error", + FETCH_ERROR = "fetch-error", + INVALID_CONTENT = "invalid-content", + NO_API_KEY = "no-api-key", + NO_MODEL = "no-model", + NO_PROJECT_ID = "no-project-id", + PARSE_FAILED = "parse-failed", + REQUEST_ERROR = "request-error", + RESPONSE_ERROR = "response-error" +} + // @public export interface VertexAIOptions { // (undocumented) diff --git a/docs-devsite/vertexai-preview.errordetails.md b/docs-devsite/vertexai-preview.errordetails.md new file mode 100644 index 00000000000..ad080a09595 --- /dev/null +++ b/docs-devsite/vertexai-preview.errordetails.md @@ -0,0 +1,66 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# ErrorDetails interface +Details object that may be included in an error response. + +Signature: + +```typescript +export interface ErrorDetails +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| ["@type"](./vertexai-preview.errordetails.md#errordetails"@type") | string | | +| [domain](./vertexai-preview.errordetails.md#errordetailsdomain) | string | The domain where the error occured. | +| [metadata](./vertexai-preview.errordetails.md#errordetailsmetadata) | Record<string, unknown> | Additonal metadata about the error. | +| [reason](./vertexai-preview.errordetails.md#errordetailsreason) | string | The reason for the error. | + +## ErrorDetails."@type" + +Signature: + +```typescript +'@type'?: string; +``` + +## ErrorDetails.domain + +The domain where the error occured. + +Signature: + +```typescript +domain?: string; +``` + +## ErrorDetails.metadata + +Additonal metadata about the error. + +Signature: + +```typescript +metadata?: Record; +``` + +## ErrorDetails.reason + +The reason for the error. + +Signature: + +```typescript +reason?: string; +``` diff --git a/docs-devsite/vertexai-preview.md b/docs-devsite/vertexai-preview.md index 1aba07d3719..078f57fd63d 100644 --- a/docs-devsite/vertexai-preview.md +++ b/docs-devsite/vertexai-preview.md @@ -27,6 +27,7 @@ The Vertex AI For Firebase Web SDK. | --- | --- | | [ChatSession](./vertexai-preview.chatsession.md#chatsession_class) | ChatSession class that enables sending chat messages and stores history of sent and received messages so far. | | [GenerativeModel](./vertexai-preview.generativemodel.md#generativemodel_class) | Class for generative model APIs. | +| [VertexAIError](./vertexai-preview.vertexaierror.md#vertexaierror_class) | Error class for the Firebase VertexAI SDK. | ## Enumerations @@ -41,6 +42,7 @@ The Vertex AI For Firebase Web SDK. | [HarmCategory](./vertexai-preview.md#harmcategory) | Harm categories that would cause prompts or candidates to be blocked. | | [HarmProbability](./vertexai-preview.md#harmprobability) | Probability that a prompt or candidate matches a harm category. | | [HarmSeverity](./vertexai-preview.md#harmseverity) | Harm severity levels. | +| [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | Standardized error codes that [VertexAIError](./vertexai-preview.vertexaierror.md#vertexaierror_class) can have. | ## Interfaces @@ -54,6 +56,7 @@ The Vertex AI For Firebase Web SDK. | [CountTokensResponse](./vertexai-preview.counttokensresponse.md#counttokensresponse_interface) | Response from calling [GenerativeModel.countTokens()](./vertexai-preview.generativemodel.md#generativemodelcounttokens). | | [Date\_2](./vertexai-preview.date_2.md#date_2_interface) | Protobuf google.type.Date | | [EnhancedGenerateContentResponse](./vertexai-preview.enhancedgeneratecontentresponse.md#enhancedgeneratecontentresponse_interface) | Response object wrapped with helper methods. | +| [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface) | Details object that may be included in an error response. | | [FileData](./vertexai-preview.filedata.md#filedata_interface) | Data pointing to a file uploaded on Google Cloud Storage. | | [FileDataPart](./vertexai-preview.filedatapart.md#filedatapart_interface) | Content part interface if the part represents [FileData](./vertexai-preview.filedata.md#filedata_interface) | | [FunctionCall](./vertexai-preview.functioncall.md#functioncall_interface) | A predicted [FunctionCall](./vertexai-preview.functioncall.md#functioncall_interface) returned from the model that contains a string representing the [FunctionDeclaration.name](./vertexai-preview.functiondeclaration.md#functiondeclarationname) and a structured JSON object containing the parameters and their values. | @@ -367,3 +370,27 @@ export declare enum HarmSeverity | HARM\_SEVERITY\_NEGLIGIBLE | "HARM_SEVERITY_NEGLIGIBLE" | | | HARM\_SEVERITY\_UNSPECIFIED | "HARM_SEVERITY_UNSPECIFIED" | | +## VertexAIErrorCode + +Standardized error codes that [VertexAIError](./vertexai-preview.vertexaierror.md#vertexaierror_class) can have. + +Signature: + +```typescript +export declare const enum VertexAIErrorCode +``` + +## Enumeration Members + +| Member | Value | Description | +| --- | --- | --- | +| ERROR | "error" | A generic error occured. | +| FETCH\_ERROR | "fetch-error" | An error occurred while performing a fetch. | +| INVALID\_CONTENT | "invalid-content" | An error associated with a Content object. | +| NO\_API\_KEY | "no-api-key" | An error occured due to a missing api key. | +| NO\_MODEL | "no-model" | An error occurred due to a missing model. | +| NO\_PROJECT\_ID | "no-project-id" | An error occured due to a missing project id. | +| PARSE\_FAILED | "parse-failed" | An error occured while parsing. | +| REQUEST\_ERROR | "request-error" | An error occurred in a request. | +| RESPONSE\_ERROR | "response-error" | An error occured in a response. | + diff --git a/docs-devsite/vertexai-preview.vertexaierror.md b/docs-devsite/vertexai-preview.vertexaierror.md new file mode 100644 index 00000000000..9d8c5376728 --- /dev/null +++ b/docs-devsite/vertexai-preview.vertexaierror.md @@ -0,0 +1,107 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# VertexAIError class +Error class for the Firebase VertexAI SDK. + +Signature: + +```typescript +export declare class VertexAIError extends FirebaseError +``` +Extends: [FirebaseError](./util.firebaseerror.md#firebaseerror_class) + +## Constructors + +| Constructor | Modifiers | Description | +| --- | --- | --- | +| [(constructor)(code, message, status, statusText, errorDetails)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | + +## Properties + +| Property | Modifiers | Type | Description | +| --- | --- | --- | --- | +| [code](./vertexai-preview.vertexaierror.md#vertexaierrorcode) | | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | | +| [errorDetails](./vertexai-preview.vertexaierror.md#vertexaierrorerrordetails) | | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] \| undefined | | +| [message](./vertexai-preview.vertexaierror.md#vertexaierrormessage) | | string | | +| [stack](./vertexai-preview.vertexaierror.md#vertexaierrorstack) | | string | Stack trace of the error. | +| [status](./vertexai-preview.vertexaierror.md#vertexaierrorstatus) | | number \| undefined | | +| [statusText](./vertexai-preview.vertexaierror.md#vertexaierrorstatustext) | | string \| undefined | | + +## VertexAIError.(constructor) + +Creates a new VertexAIError instance. + +Signature: + +```typescript +constructor(code: VertexAIErrorCode, message: string, status?: number | undefined, statusText?: string | undefined, errorDetails?: ErrorDetails[] | undefined); +``` + +#### Parameters + +| Parameter | Type | Description | +| --- | --- | --- | +| code | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | The error code from [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode). | +| message | string | A human-readable message describing the error. | +| status | number \| undefined | Optional HTTP status code of the error response. | +| statusText | string \| undefined | Optional HTTP status text of the error response. | +| errorDetails | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] \| undefined | Optional additional details about the error. | + +## VertexAIError.code + +Signature: + +```typescript +readonly code: VertexAIErrorCode; +``` + +## VertexAIError.errorDetails + +Signature: + +```typescript +readonly errorDetails?: ErrorDetails[] | undefined; +``` + +## VertexAIError.message + +Signature: + +```typescript +readonly message: string; +``` + +## VertexAIError.stack + +Stack trace of the error. + +Signature: + +```typescript +readonly stack?: string; +``` + +## VertexAIError.status + +Signature: + +```typescript +readonly status?: number | undefined; +``` + +## VertexAIError.statusText + +Signature: + +```typescript +readonly statusText?: string | undefined; +``` diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 5c25cce7ef9..2a06c867174 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -14,12 +14,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ModelParams } from './types'; +import { ModelParams, VertexAIError, VertexAIErrorCode } from './types'; import { getGenerativeModel } from './api'; import { expect } from 'chai'; import { VertexAI } from './public-types'; import { GenerativeModel } from './models/generative-model'; -import { VertexError } from './errors'; const fakeVertexAI: VertexAI = { app: { @@ -35,27 +34,42 @@ const fakeVertexAI: VertexAI = { describe('Top level API', () => { it('getGenerativeModel throws if no model is provided', () => { - expect(() => getGenerativeModel(fakeVertexAI, {} as ModelParams)).to.throw( - VertexError.NO_MODEL - ); + try { + getGenerativeModel(fakeVertexAI, {} as ModelParams); + } catch (e) { + expect((e as VertexAIError).code).includes(VertexAIErrorCode.NO_MODEL); + expect((e as VertexAIError).message).equals('Missing model parameter'); + } }); it('getGenerativeModel throws if no apiKey is provided', () => { const fakeVertexNoApiKey = { ...fakeVertexAI, app: { options: { projectId: 'my-project' } } } as VertexAI; - expect(() => - getGenerativeModel(fakeVertexNoApiKey, { model: 'my-model' }) - ).to.throw(VertexError.NO_API_KEY); + try { + getGenerativeModel(fakeVertexNoApiKey, { model: 'my-model' }); + } catch (e) { + expect((e as VertexAIError).code).includes(VertexAIErrorCode.NO_API_KEY); + expect((e as VertexAIError).message).equals( + 'Missing Firebase app API key' + ); + } }); it('getGenerativeModel throws if no projectId is provided', () => { const fakeVertexNoProject = { ...fakeVertexAI, app: { options: { apiKey: 'my-key' } } } as VertexAI; - expect(() => - getGenerativeModel(fakeVertexNoProject, { model: 'my-model' }) - ).to.throw(VertexError.NO_PROJECT_ID); + try { + getGenerativeModel(fakeVertexNoProject, { model: 'my-model' }); + } catch (e) { + expect((e as VertexAIError).code).includes( + VertexAIErrorCode.NO_PROJECT_ID + ); + expect((e as VertexAIError).message).equals( + 'Missing Firebase app project ID' + ); + } }); it('getGenerativeModel gets a GenerativeModel', () => { const genModel = getGenerativeModel(fakeVertexAI, { model: 'my-model' }); diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 5b9620969b8..c9d62680dc1 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -21,8 +21,12 @@ import { getModularInstance } from '@firebase/util'; import { DEFAULT_LOCATION, VERTEX_TYPE } from './constants'; import { VertexAIService } from './service'; import { VertexAI, VertexAIOptions } from './public-types'; -import { ERROR_FACTORY, VertexError } from './errors'; -import { ModelParams, RequestOptions } from './types'; +import { + ModelParams, + RequestOptions, + VertexAIError, + VertexAIErrorCode +} from './types'; import { GenerativeModel } from './models/generative-model'; export { ChatSession } from './methods/chat-session'; @@ -67,7 +71,10 @@ export function getGenerativeModel( requestOptions?: RequestOptions ): GenerativeModel { if (!modelParams.model) { - throw ERROR_FACTORY.create(VertexError.NO_MODEL); + throw new VertexAIError( + VertexAIErrorCode.NO_MODEL, + 'Missing model parameter' + ); } return new GenerativeModel(vertexAI, modelParams, requestOptions); } diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts deleted file mode 100644 index c0b9d83aaeb..00000000000 --- a/packages/vertexai/src/errors.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * @license - * Copyright 2024 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { ErrorFactory, ErrorMap } from '@firebase/util'; -import { GenerateContentResponse } from './types'; - -export const enum VertexError { - FETCH_ERROR = 'fetch-error', - INVALID_CONTENT = 'invalid-content', - NO_API_KEY = 'no-api-key', - NO_MODEL = 'no-model', - NO_PROJECT_ID = 'no-project-id', - PARSE_FAILED = 'parse-failed', - RESPONSE_ERROR = 'response-error' -} - -const ERRORS: ErrorMap = { - [VertexError.FETCH_ERROR]: `Error fetching from {$url}: {$message}`, - [VertexError.INVALID_CONTENT]: `Content formatting error: {$message}`, - [VertexError.NO_API_KEY]: - `The "apiKey" field is empty in the local Firebase config. Firebase VertexAI requires this field to` + - `contain a valid API key.`, - [VertexError.NO_PROJECT_ID]: - `The "projectId" field is empty in the local Firebase config. Firebase VertexAI requires this field to` + - `contain a valid project ID.`, - [VertexError.NO_MODEL]: - `Must provide a model name. ` + - `Example: getGenerativeModel({ model: 'my-model-name' })`, - [VertexError.PARSE_FAILED]: `Parsing failed: {$message}`, - [VertexError.RESPONSE_ERROR]: - `Response error: {$message}. Response body stored in ` + - `error.customData.response` -}; - -interface ErrorParams { - [VertexError.FETCH_ERROR]: { url: string; message: string }; - [VertexError.INVALID_CONTENT]: { message: string }; - [VertexError.PARSE_FAILED]: { message: string }; - [VertexError.RESPONSE_ERROR]: { - message: string; - response: GenerateContentResponse; - }; -} - -export const ERROR_FACTORY = new ErrorFactory( - 'vertexAI', - 'VertexAI', - ERRORS -); diff --git a/packages/vertexai/src/methods/chat-session-helpers.ts b/packages/vertexai/src/methods/chat-session-helpers.ts index 0ac00ad0a1c..c558d8685e6 100644 --- a/packages/vertexai/src/methods/chat-session-helpers.ts +++ b/packages/vertexai/src/methods/chat-session-helpers.ts @@ -15,8 +15,14 @@ * limitations under the License. */ -import { Content, POSSIBLE_ROLES, Part, Role } from '../types'; -import { ERROR_FACTORY, VertexError } from '../errors'; +import { + Content, + POSSIBLE_ROLES, + Part, + Role, + VertexAIError, + VertexAIErrorCode +} from '../types'; // https://ai.google.dev/api/rest/v1beta/Content#part @@ -48,28 +54,32 @@ export function validateChatHistory(history: Content[]): void { for (const currContent of history) { const { role, parts } = currContent; if (!prevContent && role !== 'user') { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: `First content should be with role 'user', got ${role}` - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `First content should be with role 'user', got ${role}` + ); } if (!POSSIBLE_ROLES.includes(role)) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: `Each item should include role field. Got ${role} but valid roles are: ${JSON.stringify( + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `Each item should include role field. Got ${role} but valid roles are: ${JSON.stringify( POSSIBLE_ROLES )}` - }); + ); } if (!Array.isArray(parts)) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: "Content should have 'parts' property with an array of Parts" - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `Content should have 'parts' but property with an array of Parts` + ); } if (parts.length === 0) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: 'Each Content should have at least one part' - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `Each content should have at least one part` + ); } const countFields: Record = { @@ -89,22 +99,24 @@ export function validateChatHistory(history: Content[]): void { const validParts = VALID_PARTS_PER_ROLE[role]; for (const key of VALID_PART_FIELDS) { if (!validParts.includes(key) && countFields[key] > 0) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: `Content with role '${role}' can't contain '${key}' part` - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `Content with role '${role}' can't contain '${key}' part` + ); } } if (prevContent) { const validPreviousContentRoles = VALID_PREVIOUS_CONTENT_ROLES[role]; if (!validPreviousContentRoles.includes(prevContent.role)) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: `Content with role '${role}' can't follow '${ + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + `Content with role '${role} can't follow '${ prevContent.role }'. Valid previous roles: ${JSON.stringify( VALID_PREVIOUS_CONTENT_ROLES )}` - }); + ); } } prevContent = currContent; diff --git a/packages/vertexai/src/models/generative-model.ts b/packages/vertexai/src/models/generative-model.ts index efd6719661b..1deb8e2ae85 100644 --- a/packages/vertexai/src/models/generative-model.ts +++ b/packages/vertexai/src/models/generative-model.ts @@ -33,7 +33,9 @@ import { SafetySetting, StartChatParams, Tool, - ToolConfig + ToolConfig, + VertexAIError, + VertexAIErrorCode } from '../types'; import { ChatSession } from '../methods/chat-session'; import { countTokens } from '../methods/count-tokens'; @@ -42,7 +44,6 @@ import { formatSystemInstruction } from '../requests/request-helpers'; import { VertexAI } from '../public-types'; -import { ERROR_FACTORY, VertexError } from '../errors'; import { ApiSettings } from '../types/internal'; import { VertexAIService } from '../service'; @@ -66,9 +67,15 @@ export class GenerativeModel { requestOptions?: RequestOptions ) { if (!vertexAI.app?.options?.apiKey) { - throw ERROR_FACTORY.create(VertexError.NO_API_KEY); + throw new VertexAIError( + VertexAIErrorCode.NO_API_KEY, + 'Missing Firebase app API key' + ); } else if (!vertexAI.app?.options?.projectId) { - throw ERROR_FACTORY.create(VertexError.NO_PROJECT_ID); + throw new VertexAIError( + VertexAIErrorCode.NO_PROJECT_ID, + 'Missing Firebase app project ID' + ); } else { this._apiSettings = { apiKey: vertexAI.app.options.apiKey, diff --git a/packages/vertexai/src/requests/request-helpers.ts b/packages/vertexai/src/requests/request-helpers.ts index 0b7ce4ed4d2..412ce26429b 100644 --- a/packages/vertexai/src/requests/request-helpers.ts +++ b/packages/vertexai/src/requests/request-helpers.ts @@ -15,8 +15,13 @@ * limitations under the License. */ -import { Content, GenerateContentRequest, Part } from '../types'; -import { ERROR_FACTORY, VertexError } from '../errors'; +import { + Content, + GenerateContentRequest, + Part, + VertexAIError, + VertexAIErrorCode +} from '../types'; export function formatSystemInstruction( input?: string | Part | Content @@ -81,16 +86,17 @@ function assignRoleToPartsAndValidateSendMessageRequest( } if (hasUserContent && hasFunctionContent) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: - 'Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.' - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + 'Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.' + ); } if (!hasUserContent && !hasFunctionContent) { - throw ERROR_FACTORY.create(VertexError.INVALID_CONTENT, { - message: 'No content is provided for sending chat message.' - }); + throw new VertexAIError( + VertexAIErrorCode.INVALID_CONTENT, + 'No content is provided for sending chat message.' + ); } if (hasUserContent) { diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index d27c4e41252..b8ae9d12c25 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -22,6 +22,7 @@ import chaiAsPromised from 'chai-as-promised'; import { RequestUrl, Task, getHeaders, makeRequest } from './request'; import { ApiSettings } from '../types/internal'; import { DEFAULT_API_VERSION } from '../constants'; +import { VertexAIError, VertexAIErrorCode } from '../types'; use(sinonChai); use(chaiAsPromised); @@ -233,8 +234,8 @@ describe('request methods', () => { statusText: 'AbortError' } as Response); - await expect( - makeRequest( + try { + await makeRequest( 'models/model-name', Task.GENERATE_CONTENT, fakeApiSettings, @@ -243,8 +244,16 @@ describe('request methods', () => { { timeout: 0 } - ) - ).to.be.rejectedWith('500 AbortError'); + ); + } catch (e) { + expect((e as VertexAIError).code).to.equal( + VertexAIErrorCode.FETCH_ERROR + ); + expect((e as VertexAIError).status).to.equal(500); + expect((e as VertexAIError).statusText).to.equal('AbortError'); + expect((e as VertexAIError).message).to.include('500 AbortError'); + } + expect(fetchStub).to.be.calledOnce; }); it('Network error, no response.json()', async () => { @@ -253,15 +262,22 @@ describe('request methods', () => { status: 500, statusText: 'Server Error' } as Response); - await expect( - makeRequest( + try { + await makeRequest( 'models/model-name', Task.GENERATE_CONTENT, fakeApiSettings, false, '' - ) - ).to.be.rejectedWith(/500 Server Error/); + ); + } catch (e) { + expect((e as VertexAIError).code).to.equal( + VertexAIErrorCode.FETCH_ERROR + ); + expect((e as VertexAIError).status).to.equal(500); + expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).message).to.include('500 Server Error'); + } expect(fetchStub).to.be.calledOnce; }); it('Network error, includes response.json()', async () => { @@ -271,15 +287,23 @@ describe('request methods', () => { statusText: 'Server Error', json: () => Promise.resolve({ error: { message: 'extra info' } }) } as Response); - await expect( - makeRequest( + try { + await makeRequest( 'models/model-name', Task.GENERATE_CONTENT, fakeApiSettings, false, '' - ) - ).to.be.rejectedWith(/500 Server Error.*extra info/); + ); + } catch (e) { + expect((e as VertexAIError).code).to.equal( + VertexAIErrorCode.FETCH_ERROR + ); + expect((e as VertexAIError).status).to.equal(500); + expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).message).to.include('500 Server Error'); + expect((e as VertexAIError).message).to.include('extra info'); + } expect(fetchStub).to.be.calledOnce; }); it('Network error, includes response.json() and details', async () => { @@ -301,17 +325,26 @@ describe('request methods', () => { } }) } as Response); - await expect( - makeRequest( + try { + await makeRequest( 'models/model-name', Task.GENERATE_CONTENT, fakeApiSettings, false, '' - ) - ).to.be.rejectedWith( - /500 Server Error.*extra info.*generic::invalid_argument/ - ); + ); + } catch (e) { + expect((e as VertexAIError).code).to.equal( + VertexAIErrorCode.FETCH_ERROR + ); + expect((e as VertexAIError).status).to.equal(500); + expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).message).to.include('500 Server Error'); + expect((e as VertexAIError).message).to.include('extra info'); + expect((e as VertexAIError).message).to.include( + 'generic::invalid_argument' + ); + } expect(fetchStub).to.be.calledOnce; }); }); diff --git a/packages/vertexai/src/requests/request.ts b/packages/vertexai/src/requests/request.ts index ca78c16a383..3649e95756a 100644 --- a/packages/vertexai/src/requests/request.ts +++ b/packages/vertexai/src/requests/request.ts @@ -15,8 +15,7 @@ * limitations under the License. */ -import { RequestOptions } from '../types'; -import { ERROR_FACTORY, VertexError } from '../errors'; +import { RequestOptions, VertexAIError, VertexAIErrorCode } from '../types'; import { ApiSettings } from '../types/internal'; import { DEFAULT_API_VERSION, @@ -24,6 +23,7 @@ import { LANGUAGE_TAG, PACKAGE_VERSION } from '../constants'; +import { FirebaseError } from '@firebase/util'; export enum Task { GENERATE_CONTENT = 'generateContent', @@ -140,24 +140,38 @@ export async function makeRequest( response = await fetch(request.url, request.fetchOptions); if (!response.ok) { let message = ''; + let errorDetails; try { const json = await response.json(); message = json.error.message; if (json.error.details) { message += ` ${JSON.stringify(json.error.details)}`; + errorDetails = json.error.details; } } catch (e) { // ignored } - throw new Error(`[${response.status} ${response.statusText}] ${message}`); + throw new VertexAIError( + VertexAIErrorCode.FETCH_ERROR, + `Error fetching from ${url}: [${response.status} ${response.statusText}] ${message}`, + response.status, + response.statusText, + errorDetails + ); } - } catch (caughtError) { - const e = caughtError as Error; - const err = ERROR_FACTORY.create(VertexError.FETCH_ERROR, { - url: url.toString(), - message: e.message - }); - err.stack = e.stack; + } catch (e) { + let err = e as Error; + if ( + (e as FirebaseError).code !== VertexAIErrorCode.FETCH_ERROR && + e instanceof Error + ) { + err = new VertexAIError( + VertexAIErrorCode.ERROR, + `Error fetching from ${url.toString()}: ${e.message}` + ); + err.stack = e.stack; + } + throw err; } return response; diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index dc49123420f..2327222f1a5 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -20,9 +20,10 @@ import { FinishReason, FunctionCall, GenerateContentCandidate, - GenerateContentResponse + GenerateContentResponse, + VertexAIError, + VertexAIErrorCode } from '../types'; -import { ERROR_FACTORY, VertexError } from '../errors'; /** * Adds convenience helper methods to a response object, including stream @@ -41,17 +42,19 @@ export function addHelpers( ); } if (hadBadFinishReason(response.candidates[0])) { - throw ERROR_FACTORY.create(VertexError.RESPONSE_ERROR, { - message: `${formatBlockErrorMessage(response)}`, - response - }); + throw new VertexAIError( + VertexAIErrorCode.REQUEST_ERROR, + `Response error: ${formatBlockErrorMessage( + response + )}. Response body stored in error.customData.response` + ); } return getText(response); } else if (response.promptFeedback) { - throw ERROR_FACTORY.create(VertexError.RESPONSE_ERROR, { - message: `Text not available. ${formatBlockErrorMessage(response)}`, - response - }); + throw new VertexAIError( + VertexAIErrorCode.RESPONSE_ERROR, + `Text not available. ${formatBlockErrorMessage(response)}` + ); } return ''; }; @@ -65,19 +68,17 @@ export function addHelpers( ); } if (hadBadFinishReason(response.candidates[0])) { - throw ERROR_FACTORY.create(VertexError.RESPONSE_ERROR, { - message: `${formatBlockErrorMessage(response)}`, - response - }); + throw new VertexAIError( + VertexAIErrorCode.RESPONSE_ERROR, + `${formatBlockErrorMessage(response)}` + ); } return getFunctionCalls(response); } else if (response.promptFeedback) { - throw ERROR_FACTORY.create(VertexError.RESPONSE_ERROR, { - message: `Function call not available. ${formatBlockErrorMessage( - response - )}`, - response - }); + throw new VertexAIError( + VertexAIErrorCode.RESPONSE_ERROR, + `Function call not available. ${formatBlockErrorMessage(response)}` + ); } return undefined; }; diff --git a/packages/vertexai/src/requests/stream-reader.ts b/packages/vertexai/src/requests/stream-reader.ts index 0c070cfe0f2..77a2ccd504e 100644 --- a/packages/vertexai/src/requests/stream-reader.ts +++ b/packages/vertexai/src/requests/stream-reader.ts @@ -20,9 +20,10 @@ import { GenerateContentCandidate, GenerateContentResponse, GenerateContentStreamResult, - Part + Part, + VertexAIError, + VertexAIErrorCode } from '../types'; -import { ERROR_FACTORY, VertexError } from '../errors'; import { addHelpers } from './response-helpers'; const responseLineRE = /^data\: (.*)(?:\n\n|\r\r|\r\n\r\n)/; @@ -93,9 +94,10 @@ export function getResponseStream( if (done) { if (currentText.trim()) { controller.error( - ERROR_FACTORY.create(VertexError.PARSE_FAILED, { - message: 'Failed to parse stream' - }) + new VertexAIError( + VertexAIErrorCode.PARSE_FAILED, + 'Failed to parse stream' + ) ); return; } @@ -111,9 +113,10 @@ export function getResponseStream( parsedResponse = JSON.parse(match[1]); } catch (e) { controller.error( - ERROR_FACTORY.create(VertexError.PARSE_FAILED, { - message: `Error parsing JSON response: "${match[1]}"` - }) + new VertexAIError( + VertexAIErrorCode.PARSE_FAILED, + `Error parsing JSON response: "${match[1]}` + ) ); return; } diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts new file mode 100644 index 00000000000..fc70961db8f --- /dev/null +++ b/packages/vertexai/src/types/error.ts @@ -0,0 +1,110 @@ +import { FirebaseError } from "@firebase/util"; + +/** + * Details object that may be included in an error response. + * + * @public + */ +export interface ErrorDetails { + '@type'?: string; + + /** The reason for the error. */ + reason?: string; + + /** The domain where the error occured. */ + domain?: string; + + /** Additonal metadata about the error. */ + metadata?: Record; + + /** Any other relevant information about the error. */ + [key: string]: unknown; +} + +/** + * Standardized error codes that {@link VertexAIError} can have. + * + * @public + */ +export const enum VertexAIErrorCode { + /** A generic error occured. */ + ERROR = 'error', + + /** An error occurred in a request. */ + REQUEST_ERROR = 'request-error', + + /** An error occured in a response. */ + RESPONSE_ERROR = 'response-error', + + /** An error occurred while performing a fetch. */ + FETCH_ERROR = 'fetch-error', + + /** An error associated with a Content object. */ + INVALID_CONTENT = 'invalid-content', + + /** An error occured due to a missing api key. */ + NO_API_KEY = 'no-api-key', + + /** An error occurred due to a missing model. */ + NO_MODEL = 'no-model', + + /** An error occured due to a missing project id. */ + NO_PROJECT_ID = 'no-project-id', + + /** An error occured while parsing. */ + PARSE_FAILED = 'parse-failed' +} + + +/** + * Error class for the Firebase VertexAI SDK. + * + * @public + */ +export class VertexAIError extends FirebaseError { + /** + * Stack trace of the error. + */ + readonly stack?: string; + + /** + * Creates a new VertexAIError instance. + * + * @param code - The error code from {@link VertexAIErrorCode}. + * @param message - A human-readable message describing the error. + * @param status - Optional HTTP status code of the error response. + * @param statusText - Optional HTTP status text of the error response. + * @param errorDetails - Optional additional details about the error. + */ + constructor( + readonly code: VertexAIErrorCode, + readonly message: string, + readonly status?: number, + readonly statusText?: string, + readonly errorDetails?: ErrorDetails[] + ) { + // Match error format used by FirebaseError from ErrorFactory + const service = 'vertex-ai'; + const serviceName = 'VertexAI'; + const fullCode = `${service}/${code}`; + const fullMessage = `${serviceName}: ${message} (${fullCode})`; + super(fullCode, fullMessage); + + // FirebaseError initializes a stack trace, but it assumes the error is created from the error + // factory. Since we break this assumption, we set the stack trace to be originating from this + // constructor. + // This is only supported in V8. + if (Error.captureStackTrace) { + // Allows us to initialize the stack trace without including the constructor itself at the + // top level of the stack trace. + Error.captureStackTrace(this, VertexAIError); + } + + // Allows instanceof VertexAIError in ES5/ES6 + // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work + Object.setPrototypeOf(this, VertexAIError.prototype); + + // Since Error is an interface, we don't inherit toString and so we define it ourselves. + this.toString = () => fullMessage; + } +} \ No newline at end of file diff --git a/packages/vertexai/src/types/index.ts b/packages/vertexai/src/types/index.ts index 3782a66cc36..45365c39037 100644 --- a/packages/vertexai/src/types/index.ts +++ b/packages/vertexai/src/types/index.ts @@ -19,3 +19,4 @@ export * from './content'; export * from './enums'; export * from './requests'; export * from './responses'; +export * from './error'; From 30cbf280051fad294a90cfadb020ea85ff077225 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 09:38:51 -0400 Subject: [PATCH 02/19] Move VertexAIError implementation away from types --- packages/vertexai/src/errors.ts | 55 +++++++++++++++++++++++++++ packages/vertexai/src/types/error.ts | 56 +--------------------------- 2 files changed, 56 insertions(+), 55 deletions(-) create mode 100644 packages/vertexai/src/errors.ts diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts new file mode 100644 index 00000000000..68c6ac4b07b --- /dev/null +++ b/packages/vertexai/src/errors.ts @@ -0,0 +1,55 @@ +import { FirebaseError } from "@firebase/util"; +import { VertexAIErrorCode, ErrorDetails } from "./types"; + +/** + * Error class for the Firebase VertexAI SDK. + * + * @public + */ +export class VertexAIError extends FirebaseError { + /** + * Stack trace of the error. + */ + readonly stack?: string; + + /** + * Creates a new VertexAIError instance. + * + * @param code - The error code from {@link VertexAIErrorCode}. + * @param message - A human-readable message describing the error. + * @param status - Optional HTTP status code of the error response. + * @param statusText - Optional HTTP status text of the error response. + * @param errorDetails - Optional additional details about the error. + */ + constructor( + readonly code: VertexAIErrorCode, + readonly message: string, + readonly status?: number, + readonly statusText?: string, + readonly errorDetails?: ErrorDetails[] + ) { + // Match error format used by FirebaseError from ErrorFactory + const service = 'vertex-ai'; + const serviceName = 'VertexAI'; + const fullCode = `${service}/${code}`; + const fullMessage = `${serviceName}: ${message} (${fullCode})`; + super(fullCode, fullMessage); + + // FirebaseError initializes a stack trace, but it assumes the error is created from the error + // factory. Since we break this assumption, we set the stack trace to be originating from this + // constructor. + // This is only supported in V8. + if (Error.captureStackTrace) { + // Allows us to initialize the stack trace without including the constructor itself at the + // top level of the stack trace. + Error.captureStackTrace(this, VertexAIError); + } + + // Allows instanceof VertexAIError in ES5/ES6 + // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work + Object.setPrototypeOf(this, VertexAIError.prototype); + + // Since Error is an interface, we don't inherit toString and so we define it ourselves. + this.toString = () => fullMessage; + } +} \ No newline at end of file diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index fc70961db8f..3e59d67df74 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -1,5 +1,3 @@ -import { FirebaseError } from "@firebase/util"; - /** * Details object that may be included in an error response. * @@ -55,56 +53,4 @@ export const enum VertexAIErrorCode { PARSE_FAILED = 'parse-failed' } - -/** - * Error class for the Firebase VertexAI SDK. - * - * @public - */ -export class VertexAIError extends FirebaseError { - /** - * Stack trace of the error. - */ - readonly stack?: string; - - /** - * Creates a new VertexAIError instance. - * - * @param code - The error code from {@link VertexAIErrorCode}. - * @param message - A human-readable message describing the error. - * @param status - Optional HTTP status code of the error response. - * @param statusText - Optional HTTP status text of the error response. - * @param errorDetails - Optional additional details about the error. - */ - constructor( - readonly code: VertexAIErrorCode, - readonly message: string, - readonly status?: number, - readonly statusText?: string, - readonly errorDetails?: ErrorDetails[] - ) { - // Match error format used by FirebaseError from ErrorFactory - const service = 'vertex-ai'; - const serviceName = 'VertexAI'; - const fullCode = `${service}/${code}`; - const fullMessage = `${serviceName}: ${message} (${fullCode})`; - super(fullCode, fullMessage); - - // FirebaseError initializes a stack trace, but it assumes the error is created from the error - // factory. Since we break this assumption, we set the stack trace to be originating from this - // constructor. - // This is only supported in V8. - if (Error.captureStackTrace) { - // Allows us to initialize the stack trace without including the constructor itself at the - // top level of the stack trace. - Error.captureStackTrace(this, VertexAIError); - } - - // Allows instanceof VertexAIError in ES5/ES6 - // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work - Object.setPrototypeOf(this, VertexAIError.prototype); - - // Since Error is an interface, we don't inherit toString and so we define it ourselves. - this.toString = () => fullMessage; - } -} \ No newline at end of file +export { VertexAIError } from '../errors'; \ No newline at end of file From d3b1c9cb215183b0786883862f8584c0073a4b22 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 09:59:04 -0400 Subject: [PATCH 03/19] Minor fixes from review --- packages/vertexai/src/api.ts | 2 +- packages/vertexai/src/errors.ts | 12 ++++-------- .../vertexai/src/methods/chat-session-helpers.ts | 4 ++-- packages/vertexai/src/models/generative-model.ts | 4 ++-- packages/vertexai/src/requests/request-helpers.ts | 4 ++-- packages/vertexai/src/requests/request.ts | 3 +-- packages/vertexai/src/requests/response-helpers.ts | 6 ++++-- 7 files changed, 16 insertions(+), 19 deletions(-) diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index c9d62680dc1..e9e7645c404 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -73,7 +73,7 @@ export function getGenerativeModel( if (!modelParams.model) { throw new VertexAIError( VertexAIErrorCode.NO_MODEL, - 'Missing model parameter' + `Must provide a model name. Example: getGenerativeModel({ model: 'my-model-name' })` ); } return new GenerativeModel(vertexAI, modelParams, requestOptions); diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index 68c6ac4b07b..512c8a4ddbe 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -1,17 +1,13 @@ import { FirebaseError } from "@firebase/util"; import { VertexAIErrorCode, ErrorDetails } from "./types"; +import { VERTEX_TYPE } from "./constants"; /** - * Error class for the Firebase VertexAI SDK. + * Error class for the Vertex AI for Firebase SDK. * * @public */ export class VertexAIError extends FirebaseError { - /** - * Stack trace of the error. - */ - readonly stack?: string; - /** * Creates a new VertexAIError instance. * @@ -29,10 +25,10 @@ export class VertexAIError extends FirebaseError { readonly errorDetails?: ErrorDetails[] ) { // Match error format used by FirebaseError from ErrorFactory - const service = 'vertex-ai'; + const service = VERTEX_TYPE; const serviceName = 'VertexAI'; const fullCode = `${service}/${code}`; - const fullMessage = `${serviceName}: ${message} (${fullCode})`; + const fullMessage = `${serviceName}: ${message} (${fullCode}).`; super(fullCode, fullMessage); // FirebaseError initializes a stack trace, but it assumes the error is created from the error diff --git a/packages/vertexai/src/methods/chat-session-helpers.ts b/packages/vertexai/src/methods/chat-session-helpers.ts index c558d8685e6..255f6394c69 100644 --- a/packages/vertexai/src/methods/chat-session-helpers.ts +++ b/packages/vertexai/src/methods/chat-session-helpers.ts @@ -56,7 +56,7 @@ export function validateChatHistory(history: Content[]): void { if (!prevContent && role !== 'user') { throw new VertexAIError( VertexAIErrorCode.INVALID_CONTENT, - `First content should be with role 'user', got ${role}` + `First Content should be with role 'user', got ${role}` ); } if (!POSSIBLE_ROLES.includes(role)) { @@ -78,7 +78,7 @@ export function validateChatHistory(history: Content[]): void { if (parts.length === 0) { throw new VertexAIError( VertexAIErrorCode.INVALID_CONTENT, - `Each content should have at least one part` + `Each Content should have at least one part` ); } diff --git a/packages/vertexai/src/models/generative-model.ts b/packages/vertexai/src/models/generative-model.ts index 1deb8e2ae85..682e7ecf247 100644 --- a/packages/vertexai/src/models/generative-model.ts +++ b/packages/vertexai/src/models/generative-model.ts @@ -69,12 +69,12 @@ export class GenerativeModel { if (!vertexAI.app?.options?.apiKey) { throw new VertexAIError( VertexAIErrorCode.NO_API_KEY, - 'Missing Firebase app API key' + `The "apiKey" field is empty in the local Firebase config. Firebase VertexAI requires this field to contain a valid API key.` ); } else if (!vertexAI.app?.options?.projectId) { throw new VertexAIError( VertexAIErrorCode.NO_PROJECT_ID, - 'Missing Firebase app project ID' + `The "projectId" field is empty in the local Firebase config. Firebase VertexAI requires this field to contain a valid project ID.` ); } else { this._apiSettings = { diff --git a/packages/vertexai/src/requests/request-helpers.ts b/packages/vertexai/src/requests/request-helpers.ts index 412ce26429b..a84ca2cd343 100644 --- a/packages/vertexai/src/requests/request-helpers.ts +++ b/packages/vertexai/src/requests/request-helpers.ts @@ -88,14 +88,14 @@ function assignRoleToPartsAndValidateSendMessageRequest( if (hasUserContent && hasFunctionContent) { throw new VertexAIError( VertexAIErrorCode.INVALID_CONTENT, - 'Within a single message, FunctionResponse cannot be mixed with other type of part in the request for sending chat message.' + 'Within a single message, FunctionResponse cannot be mixed with other type of Part in the request for sending chat message.' ); } if (!hasUserContent && !hasFunctionContent) { throw new VertexAIError( VertexAIErrorCode.INVALID_CONTENT, - 'No content is provided for sending chat message.' + 'No Content is provided for sending chat message.' ); } diff --git a/packages/vertexai/src/requests/request.ts b/packages/vertexai/src/requests/request.ts index 3649e95756a..a0569d92daa 100644 --- a/packages/vertexai/src/requests/request.ts +++ b/packages/vertexai/src/requests/request.ts @@ -23,7 +23,6 @@ import { LANGUAGE_TAG, PACKAGE_VERSION } from '../constants'; -import { FirebaseError } from '@firebase/util'; export enum Task { GENERATE_CONTENT = 'generateContent', @@ -162,7 +161,7 @@ export async function makeRequest( } catch (e) { let err = e as Error; if ( - (e as FirebaseError).code !== VertexAIErrorCode.FETCH_ERROR && + (e as VertexAIError).code !== VertexAIErrorCode.FETCH_ERROR && e instanceof Error ) { err = new VertexAIError( diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index 2327222f1a5..e0a58dd3046 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -43,7 +43,7 @@ export function addHelpers( } if (hadBadFinishReason(response.candidates[0])) { throw new VertexAIError( - VertexAIErrorCode.REQUEST_ERROR, + VertexAIErrorCode.RESPONSE_ERROR, `Response error: ${formatBlockErrorMessage( response )}. Response body stored in error.customData.response` @@ -70,7 +70,9 @@ export function addHelpers( if (hadBadFinishReason(response.candidates[0])) { throw new VertexAIError( VertexAIErrorCode.RESPONSE_ERROR, - `${formatBlockErrorMessage(response)}` + `Response error: ${formatBlockErrorMessage( + response + )}. Response body stored in error.customData.response` ); } return getFunctionCalls(response); From 4eba38293e29dab4f44283faef59d583a6044741 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 10:03:33 -0400 Subject: [PATCH 04/19] Fixed formatting --- packages/vertexai/src/errors.ts | 35 +++++++++++++++++++++------- packages/vertexai/src/types/error.ts | 19 ++++++++++++++- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index 512c8a4ddbe..d625c73da33 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -1,6 +1,23 @@ -import { FirebaseError } from "@firebase/util"; -import { VertexAIErrorCode, ErrorDetails } from "./types"; -import { VERTEX_TYPE } from "./constants"; +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { FirebaseError } from '@firebase/util'; +import { VertexAIErrorCode, ErrorDetails } from './types'; +import { VERTEX_TYPE } from './constants'; /** * Error class for the Vertex AI for Firebase SDK. @@ -30,17 +47,17 @@ export class VertexAIError extends FirebaseError { const fullCode = `${service}/${code}`; const fullMessage = `${serviceName}: ${message} (${fullCode}).`; super(fullCode, fullMessage); - + // FirebaseError initializes a stack trace, but it assumes the error is created from the error // factory. Since we break this assumption, we set the stack trace to be originating from this // constructor. // This is only supported in V8. if (Error.captureStackTrace) { - // Allows us to initialize the stack trace without including the constructor itself at the - // top level of the stack trace. - Error.captureStackTrace(this, VertexAIError); + // Allows us to initialize the stack trace without including the constructor itself at the + // top level of the stack trace. + Error.captureStackTrace(this, VertexAIError); } - + // Allows instanceof VertexAIError in ES5/ES6 // https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work Object.setPrototypeOf(this, VertexAIError.prototype); @@ -48,4 +65,4 @@ export class VertexAIError extends FirebaseError { // Since Error is an interface, we don't inherit toString and so we define it ourselves. this.toString = () => fullMessage; } -} \ No newline at end of file +} diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index 3e59d67df74..f279610622e 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -1,3 +1,20 @@ +/** + * @license + * Copyright 2024 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + /** * Details object that may be included in an error response. * @@ -53,4 +70,4 @@ export const enum VertexAIErrorCode { PARSE_FAILED = 'parse-failed' } -export { VertexAIError } from '../errors'; \ No newline at end of file +export { VertexAIError } from '../errors'; From aff2da288b24fdfa279bfe963643fa8b2a5f1801 Mon Sep 17 00:00:00 2001 From: dlarocque Date: Mon, 13 May 2024 14:17:38 +0000 Subject: [PATCH 05/19] Update API reports --- common/api-review/vertexai-preview.api.md | 1 - 1 file changed, 1 deletion(-) diff --git a/common/api-review/vertexai-preview.api.md b/common/api-review/vertexai-preview.api.md index 38de1d80ae3..33235999763 100644 --- a/common/api-review/vertexai-preview.api.md +++ b/common/api-review/vertexai-preview.api.md @@ -610,7 +610,6 @@ export class VertexAIError extends FirebaseError { readonly errorDetails?: ErrorDetails[] | undefined; // (undocumented) readonly message: string; - readonly stack?: string; // (undocumented) readonly status?: number | undefined; // (undocumented) From 69db6dde73dd3dd88260ca640bed01ec7b50e1e1 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 10:23:06 -0400 Subject: [PATCH 06/19] Refactor VertexAIError constructor --- packages/vertexai/src/api.test.ts | 8 +++++--- packages/vertexai/src/errors.ts | 16 +++++++++------- packages/vertexai/src/requests/request.test.ts | 16 ++++++++-------- packages/vertexai/src/requests/request.ts | 8 +++++--- packages/vertexai/src/types/error.ts | 16 ++++++++++++++++ 5 files changed, 43 insertions(+), 21 deletions(-) diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 2a06c867174..6add7192c61 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -38,7 +38,9 @@ describe('Top level API', () => { getGenerativeModel(fakeVertexAI, {} as ModelParams); } catch (e) { expect((e as VertexAIError).code).includes(VertexAIErrorCode.NO_MODEL); - expect((e as VertexAIError).message).equals('Missing model parameter'); + expect((e as VertexAIError).message).equals( + `Must provide a model name. Example: getGenerativeModel({ model: 'my-model-name' })` + ); } }); it('getGenerativeModel throws if no apiKey is provided', () => { @@ -51,7 +53,7 @@ describe('Top level API', () => { } catch (e) { expect((e as VertexAIError).code).includes(VertexAIErrorCode.NO_API_KEY); expect((e as VertexAIError).message).equals( - 'Missing Firebase app API key' + `The "apiKey" field is empty in the local Firebase config. Firebase VertexAI requires this field to contain a valid API key.` ); } }); @@ -67,7 +69,7 @@ describe('Top level API', () => { VertexAIErrorCode.NO_PROJECT_ID ); expect((e as VertexAIError).message).equals( - 'Missing Firebase app project ID' + `The "projectId" field is empty in the local Firebase config. Firebase VertexAI requires this field to contain a valid project ID.` ); } }); diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index d625c73da33..7a07f05ad95 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -16,7 +16,11 @@ */ import { FirebaseError } from '@firebase/util'; -import { VertexAIErrorCode, ErrorDetails } from './types'; +import { + VertexAIErrorCode, + GenerateContentResponse, + HTTPErrorDetails +} from './types'; import { VERTEX_TYPE } from './constants'; /** @@ -30,16 +34,14 @@ export class VertexAIError extends FirebaseError { * * @param code - The error code from {@link VertexAIErrorCode}. * @param message - A human-readable message describing the error. - * @param status - Optional HTTP status code of the error response. - * @param statusText - Optional HTTP status text of the error response. - * @param errorDetails - Optional additional details about the error. + * @param HTTPErrorDetails - Optional HTTP details from a bad response. + * @param generateContentResponse - Optional response from a {@link GenerateContentRequest}. */ constructor( readonly code: VertexAIErrorCode, readonly message: string, - readonly status?: number, - readonly statusText?: string, - readonly errorDetails?: ErrorDetails[] + readonly httpErrorDetails?: HTTPErrorDetails, + readonly generateContentResponse?: GenerateContentResponse ) { // Match error format used by FirebaseError from ErrorFactory const service = VERTEX_TYPE; diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index b8ae9d12c25..b60fbc876ac 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -249,8 +249,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).status).to.equal(500); - expect((e as VertexAIError).statusText).to.equal('AbortError'); + expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('AbortError'); expect((e as VertexAIError).message).to.include('500 AbortError'); } @@ -274,8 +274,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).status).to.equal(500); - expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); expect((e as VertexAIError).message).to.include('500 Server Error'); } expect(fetchStub).to.be.calledOnce; @@ -299,8 +299,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).status).to.equal(500); - expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); expect((e as VertexAIError).message).to.include('500 Server Error'); expect((e as VertexAIError).message).to.include('extra info'); } @@ -337,8 +337,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).status).to.equal(500); - expect((e as VertexAIError).statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); expect((e as VertexAIError).message).to.include('500 Server Error'); expect((e as VertexAIError).message).to.include('extra info'); expect((e as VertexAIError).message).to.include( diff --git a/packages/vertexai/src/requests/request.ts b/packages/vertexai/src/requests/request.ts index a0569d92daa..9f3e6083e18 100644 --- a/packages/vertexai/src/requests/request.ts +++ b/packages/vertexai/src/requests/request.ts @@ -153,9 +153,11 @@ export async function makeRequest( throw new VertexAIError( VertexAIErrorCode.FETCH_ERROR, `Error fetching from ${url}: [${response.status} ${response.statusText}] ${message}`, - response.status, - response.statusText, - errorDetails + { + status: response.status, + statusText: response.statusText, + errorDetails + } ); } } catch (e) { diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index f279610622e..b92a1a1740e 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -36,6 +36,22 @@ export interface ErrorDetails { [key: string]: unknown; } +/** + * Details object that contains data originating from a bad HTTP response. + * + * @public + */ +export interface HTTPErrorDetails { + /** HTTP status code of the error response. */ + status: number; + + /** HTTP status text of the error response. */ + statusText: string; + + /** Optional additional details about the error. */ + errorDetails?: ErrorDetails[]; +} + /** * Standardized error codes that {@link VertexAIError} can have. * From 0140b898535bba008fa106c526191ea98c0228d1 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 10:37:45 -0400 Subject: [PATCH 07/19] Fix tests --- packages/vertexai/src/requests/request.test.ts | 16 ++++++++++++---- .../vertexai/src/requests/response-helpers.ts | 16 ++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index b60fbc876ac..ea1ce73652f 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -250,7 +250,9 @@ describe('request methods', () => { VertexAIErrorCode.FETCH_ERROR ); expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('AbortError'); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + 'AbortError' + ); expect((e as VertexAIError).message).to.include('500 AbortError'); } @@ -275,7 +277,9 @@ describe('request methods', () => { VertexAIErrorCode.FETCH_ERROR ); expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + 'Server Error' + ); expect((e as VertexAIError).message).to.include('500 Server Error'); } expect(fetchStub).to.be.calledOnce; @@ -300,7 +304,9 @@ describe('request methods', () => { VertexAIErrorCode.FETCH_ERROR ); expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + 'Server Error' + ); expect((e as VertexAIError).message).to.include('500 Server Error'); expect((e as VertexAIError).message).to.include('extra info'); } @@ -338,7 +344,9 @@ describe('request methods', () => { VertexAIErrorCode.FETCH_ERROR ); expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal('Server Error'); + expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + 'Server Error' + ); expect((e as VertexAIError).message).to.include('500 Server Error'); expect((e as VertexAIError).message).to.include('extra info'); expect((e as VertexAIError).message).to.include( diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index e0a58dd3046..e1a3a50fe0e 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -46,14 +46,18 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Response error: ${formatBlockErrorMessage( response - )}. Response body stored in error.customData.response` + )}. Response body stored in error.generateContentResponse`, + undefined, + response ); } return getText(response); } else if (response.promptFeedback) { throw new VertexAIError( VertexAIErrorCode.RESPONSE_ERROR, - `Text not available. ${formatBlockErrorMessage(response)}` + `Text not available. ${formatBlockErrorMessage(response)}`, + undefined, + response ); } return ''; @@ -72,14 +76,18 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Response error: ${formatBlockErrorMessage( response - )}. Response body stored in error.customData.response` + )}. Response body stored in error.generateContentResponse`, + undefined, + response ); } return getFunctionCalls(response); } else if (response.promptFeedback) { throw new VertexAIError( VertexAIErrorCode.RESPONSE_ERROR, - `Function call not available. ${formatBlockErrorMessage(response)}` + `Function call not available. ${formatBlockErrorMessage(response)}`, + undefined, + response ); } return undefined; From 021bd88dac5c30fa3a7fe2032e6c22d7b090a808 Mon Sep 17 00:00:00 2001 From: dlarocque Date: Mon, 13 May 2024 14:51:47 +0000 Subject: [PATCH 08/19] Update API reports --- common/api-review/vertexai-preview.api.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/common/api-review/vertexai-preview.api.md b/common/api-review/vertexai-preview.api.md index 33235999763..cf9dfd5d329 100644 --- a/common/api-review/vertexai-preview.api.md +++ b/common/api-review/vertexai-preview.api.md @@ -457,6 +457,13 @@ export enum HarmSeverity { HARM_SEVERITY_UNSPECIFIED = "HARM_SEVERITY_UNSPECIFIED" } +// @public +export interface HTTPErrorDetails { + errorDetails?: ErrorDetails[]; + status: number; + statusText: string; +} + // @public export interface InlineDataPart { // (undocumented) @@ -603,17 +610,15 @@ export interface VertexAI { // @public export class VertexAIError extends FirebaseError { - constructor(code: VertexAIErrorCode, message: string, status?: number | undefined, statusText?: string | undefined, errorDetails?: ErrorDetails[] | undefined); + constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErrorDetails | undefined, generateContentResponse?: GenerateContentResponse | undefined); // (undocumented) readonly code: VertexAIErrorCode; // (undocumented) - readonly errorDetails?: ErrorDetails[] | undefined; + readonly generateContentResponse?: GenerateContentResponse | undefined; // (undocumented) - readonly message: string; - // (undocumented) - readonly status?: number | undefined; + readonly httpErrorDetails?: HTTPErrorDetails | undefined; // (undocumented) - readonly statusText?: string | undefined; + readonly message: string; } // @public From 0bc60236cccda2c557e899cb44ba6e0527424e47 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 13 May 2024 11:21:17 -0400 Subject: [PATCH 09/19] Regenerate reference docs --- .../vertexai-preview.httperrordetails.md | 57 +++++++++++++++++++ docs-devsite/vertexai-preview.md | 3 +- .../vertexai-preview.vertexaierror.md | 47 +++++---------- 3 files changed, 72 insertions(+), 35 deletions(-) create mode 100644 docs-devsite/vertexai-preview.httperrordetails.md diff --git a/docs-devsite/vertexai-preview.httperrordetails.md b/docs-devsite/vertexai-preview.httperrordetails.md new file mode 100644 index 00000000000..d328b226daa --- /dev/null +++ b/docs-devsite/vertexai-preview.httperrordetails.md @@ -0,0 +1,57 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# HTTPErrorDetails interface +Details object that contains data originating from a bad HTTP response. + +Signature: + +```typescript +export interface HTTPErrorDetails +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [errorDetails](./vertexai-preview.httperrordetails.md#httperrordetailserrordetails) | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] | Optional additional details about the error. | +| [status](./vertexai-preview.httperrordetails.md#httperrordetailsstatus) | number | HTTP status code of the error response. | +| [statusText](./vertexai-preview.httperrordetails.md#httperrordetailsstatustext) | string | HTTP status text of the error response. | + +## HTTPErrorDetails.errorDetails + +Optional additional details about the error. + +Signature: + +```typescript +errorDetails?: ErrorDetails[]; +``` + +## HTTPErrorDetails.status + +HTTP status code of the error response. + +Signature: + +```typescript +status: number; +``` + +## HTTPErrorDetails.statusText + +HTTP status text of the error response. + +Signature: + +```typescript +statusText: string; +``` diff --git a/docs-devsite/vertexai-preview.md b/docs-devsite/vertexai-preview.md index 078f57fd63d..550ba88d7e5 100644 --- a/docs-devsite/vertexai-preview.md +++ b/docs-devsite/vertexai-preview.md @@ -27,7 +27,7 @@ The Vertex AI For Firebase Web SDK. | --- | --- | | [ChatSession](./vertexai-preview.chatsession.md#chatsession_class) | ChatSession class that enables sending chat messages and stores history of sent and received messages so far. | | [GenerativeModel](./vertexai-preview.generativemodel.md#generativemodel_class) | Class for generative model APIs. | -| [VertexAIError](./vertexai-preview.vertexaierror.md#vertexaierror_class) | Error class for the Firebase VertexAI SDK. | +| [VertexAIError](./vertexai-preview.vertexaierror.md#vertexaierror_class) | Error class for the Vertex AI for Firebase SDK. | ## Enumerations @@ -77,6 +77,7 @@ The Vertex AI For Firebase Web SDK. | [GenerativeContentBlob](./vertexai-preview.generativecontentblob.md#generativecontentblob_interface) | Interface for sending an image. | | [GroundingAttribution](./vertexai-preview.groundingattribution.md#groundingattribution_interface) | | | [GroundingMetadata](./vertexai-preview.groundingmetadata.md#groundingmetadata_interface) | Metadata returned to client when grounding is enabled. | +| [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) | Details object that contains data originating from a bad HTTP response. | | [InlineDataPart](./vertexai-preview.inlinedatapart.md#inlinedatapart_interface) | Content part interface if the part represents an image. | | [ModelParams](./vertexai-preview.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai-preview.md#getgenerativemodel_e3037c9). | | [PromptFeedback](./vertexai-preview.promptfeedback.md#promptfeedback_interface) | If the prompt was blocked, this will be populated with blockReason and the relevant safetyRatings. | diff --git a/docs-devsite/vertexai-preview.vertexaierror.md b/docs-devsite/vertexai-preview.vertexaierror.md index 9d8c5376728..07761eb2edf 100644 --- a/docs-devsite/vertexai-preview.vertexaierror.md +++ b/docs-devsite/vertexai-preview.vertexaierror.md @@ -10,7 +10,7 @@ https://github.com/firebase/firebase-js-sdk {% endcomment %} # VertexAIError class -Error class for the Firebase VertexAI SDK. +Error class for the Vertex AI for Firebase SDK. Signature: @@ -23,18 +23,16 @@ export declare class VertexAIError extends FirebaseError | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(code, message, status, statusText, errorDetails)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | +| [(constructor)(code, message, httpErrorDetails, generateContentResponse)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | ## Properties | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [code](./vertexai-preview.vertexaierror.md#vertexaierrorcode) | | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | | -| [errorDetails](./vertexai-preview.vertexaierror.md#vertexaierrorerrordetails) | | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] \| undefined | | +| [generateContentResponse](./vertexai-preview.vertexaierror.md#vertexaierrorgeneratecontentresponse) | | [GenerateContentResponse](./vertexai-preview.generatecontentresponse.md#generatecontentresponse_interface) \| undefined | | +| [httpErrorDetails](./vertexai-preview.vertexaierror.md#vertexaierrorhttperrordetails) | | [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) \| undefined | | | [message](./vertexai-preview.vertexaierror.md#vertexaierrormessage) | | string | | -| [stack](./vertexai-preview.vertexaierror.md#vertexaierrorstack) | | string | Stack trace of the error. | -| [status](./vertexai-preview.vertexaierror.md#vertexaierrorstatus) | | number \| undefined | | -| [statusText](./vertexai-preview.vertexaierror.md#vertexaierrorstatustext) | | string \| undefined | | ## VertexAIError.(constructor) @@ -43,7 +41,7 @@ Creates a new VertexAIError instance. Signature: ```typescript -constructor(code: VertexAIErrorCode, message: string, status?: number | undefined, statusText?: string | undefined, errorDetails?: ErrorDetails[] | undefined); +constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErrorDetails | undefined, generateContentResponse?: GenerateContentResponse | undefined); ``` #### Parameters @@ -52,9 +50,8 @@ constructor(code: VertexAIErrorCode, message: string, status?: number | undefine | --- | --- | --- | | code | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | The error code from [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode). | | message | string | A human-readable message describing the error. | -| status | number \| undefined | Optional HTTP status code of the error response. | -| statusText | string \| undefined | Optional HTTP status text of the error response. | -| errorDetails | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] \| undefined | Optional additional details about the error. | +| httpErrorDetails | [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) \| undefined | | +| generateContentResponse | [GenerateContentResponse](./vertexai-preview.generatecontentresponse.md#generatecontentresponse_interface) \| undefined | Optional response from a [GenerateContentRequest](./vertexai-preview.generatecontentrequest.md#generatecontentrequest_interface). | ## VertexAIError.code @@ -64,44 +61,26 @@ constructor(code: VertexAIErrorCode, message: string, status?: number | undefine readonly code: VertexAIErrorCode; ``` -## VertexAIError.errorDetails +## VertexAIError.generateContentResponse Signature: ```typescript -readonly errorDetails?: ErrorDetails[] | undefined; +readonly generateContentResponse?: GenerateContentResponse | undefined; ``` -## VertexAIError.message - -Signature: - -```typescript -readonly message: string; -``` - -## VertexAIError.stack - -Stack trace of the error. +## VertexAIError.httpErrorDetails Signature: ```typescript -readonly stack?: string; +readonly httpErrorDetails?: HTTPErrorDetails | undefined; ``` -## VertexAIError.status - -Signature: - -```typescript -readonly status?: number | undefined; -``` - -## VertexAIError.statusText +## VertexAIError.message Signature: ```typescript -readonly statusText?: string | undefined; +readonly message: string; ``` From 4772cde6519e91484d3b688afb788e584edfe519 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Wed, 22 May 2024 16:27:18 -0400 Subject: [PATCH 10/19] Rename httpErrorData to customErrorData to make more future-proof --- packages/vertexai/src/errors.ts | 9 +++------ .../vertexai/src/requests/request.test.ts | 16 +++++++-------- .../vertexai/src/requests/response-helpers.ts | 20 +++++++++++-------- packages/vertexai/src/types/error.ts | 11 +++++++--- 4 files changed, 31 insertions(+), 25 deletions(-) diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index 7a07f05ad95..308b17d6087 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -18,8 +18,7 @@ import { FirebaseError } from '@firebase/util'; import { VertexAIErrorCode, - GenerateContentResponse, - HTTPErrorDetails + CustomErrorData } from './types'; import { VERTEX_TYPE } from './constants'; @@ -34,14 +33,12 @@ export class VertexAIError extends FirebaseError { * * @param code - The error code from {@link VertexAIErrorCode}. * @param message - A human-readable message describing the error. - * @param HTTPErrorDetails - Optional HTTP details from a bad response. - * @param generateContentResponse - Optional response from a {@link GenerateContentRequest}. + * @param customErrorData - Optional error data. */ constructor( readonly code: VertexAIErrorCode, readonly message: string, - readonly httpErrorDetails?: HTTPErrorDetails, - readonly generateContentResponse?: GenerateContentResponse + readonly customErrorData?: CustomErrorData, ) { // Match error format used by FirebaseError from ErrorFactory const service = VERTEX_TYPE; diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index ea1ce73652f..117b776dbc1 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -249,8 +249,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + expect((e as VertexAIError).customErrorData?.status).to.equal(500); + expect((e as VertexAIError).customErrorData?.statusText).to.equal( 'AbortError' ); expect((e as VertexAIError).message).to.include('500 AbortError'); @@ -276,8 +276,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + expect((e as VertexAIError).customErrorData?.status).to.equal(500); + expect((e as VertexAIError).customErrorData?.statusText).to.equal( 'Server Error' ); expect((e as VertexAIError).message).to.include('500 Server Error'); @@ -303,8 +303,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + expect((e as VertexAIError).customErrorData?.status).to.equal(500); + expect((e as VertexAIError).customErrorData?.statusText).to.equal( 'Server Error' ); expect((e as VertexAIError).message).to.include('500 Server Error'); @@ -343,8 +343,8 @@ describe('request methods', () => { expect((e as VertexAIError).code).to.equal( VertexAIErrorCode.FETCH_ERROR ); - expect((e as VertexAIError).httpErrorDetails?.status).to.equal(500); - expect((e as VertexAIError).httpErrorDetails?.statusText).to.equal( + expect((e as VertexAIError).customErrorData?.status).to.equal(500); + expect((e as VertexAIError).customErrorData?.statusText).to.equal( 'Server Error' ); expect((e as VertexAIError).message).to.include('500 Server Error'); diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index e1a3a50fe0e..4ff3dbfbd0e 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -47,8 +47,9 @@ export function addHelpers( `Response error: ${formatBlockErrorMessage( response )}. Response body stored in error.generateContentResponse`, - undefined, - response + { + generateContentResponse: response + } ); } return getText(response); @@ -56,8 +57,9 @@ export function addHelpers( throw new VertexAIError( VertexAIErrorCode.RESPONSE_ERROR, `Text not available. ${formatBlockErrorMessage(response)}`, - undefined, - response + { + generateContentResponse: response + } ); } return ''; @@ -77,8 +79,9 @@ export function addHelpers( `Response error: ${formatBlockErrorMessage( response )}. Response body stored in error.generateContentResponse`, - undefined, - response + { + generateContentResponse: response + } ); } return getFunctionCalls(response); @@ -86,8 +89,9 @@ export function addHelpers( throw new VertexAIError( VertexAIErrorCode.RESPONSE_ERROR, `Function call not available. ${formatBlockErrorMessage(response)}`, - undefined, - response + { + generateContentResponse: response + } ); } return undefined; diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index b92a1a1740e..7be38b086a5 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -15,6 +15,8 @@ * limitations under the License. */ +import { GenerateContentResponse } from './responses'; + /** * Details object that may be included in an error response. * @@ -41,12 +43,15 @@ export interface ErrorDetails { * * @public */ -export interface HTTPErrorDetails { +export interface CustomErrorData { /** HTTP status code of the error response. */ - status: number; + status?: number; /** HTTP status text of the error response. */ - statusText: string; + statusText?: string; + + /** Response from a {@link GenerateContentRequest} */ + generateContentResponse?: GenerateContentResponse; /** Optional additional details about the error. */ errorDetails?: ErrorDetails[]; From 5d3210583193de257ee03afc3c6f358f6731c3cf Mon Sep 17 00:00:00 2001 From: dlarocque Date: Thu, 23 May 2024 13:44:56 +0000 Subject: [PATCH 11/19] Update API reports --- common/api-review/vertexai-preview.api.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/common/api-review/vertexai-preview.api.md b/common/api-review/vertexai-preview.api.md index cf9dfd5d329..7b187e729b7 100644 --- a/common/api-review/vertexai-preview.api.md +++ b/common/api-review/vertexai-preview.api.md @@ -84,6 +84,14 @@ export interface CountTokensResponse { totalTokens: number; } +// @public +export interface CustomErrorData { + errorDetails?: ErrorDetails[]; + generateContentResponse?: GenerateContentResponse; + status?: number; + statusText?: string; +} + // @public interface Date_2 { // (undocumented) @@ -457,13 +465,6 @@ export enum HarmSeverity { HARM_SEVERITY_UNSPECIFIED = "HARM_SEVERITY_UNSPECIFIED" } -// @public -export interface HTTPErrorDetails { - errorDetails?: ErrorDetails[]; - status: number; - statusText: string; -} - // @public export interface InlineDataPart { // (undocumented) @@ -610,13 +611,11 @@ export interface VertexAI { // @public export class VertexAIError extends FirebaseError { - constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErrorDetails | undefined, generateContentResponse?: GenerateContentResponse | undefined); + constructor(code: VertexAIErrorCode, message: string, customErrorData?: CustomErrorData | undefined); // (undocumented) readonly code: VertexAIErrorCode; // (undocumented) - readonly generateContentResponse?: GenerateContentResponse | undefined; - // (undocumented) - readonly httpErrorDetails?: HTTPErrorDetails | undefined; + readonly customErrorData?: CustomErrorData | undefined; // (undocumented) readonly message: string; } From 5e021c787e02c698d81fcccf9fcf1446dd22dbaa Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Wed, 29 May 2024 15:50:41 -0400 Subject: [PATCH 12/19] Export `VertexAIError` from api instead of public types --- packages/vertexai/src/api.test.ts | 3 ++- packages/vertexai/src/api.ts | 4 +++- packages/vertexai/src/methods/chat-session-helpers.ts | 2 +- packages/vertexai/src/models/generative-model.ts | 2 +- packages/vertexai/src/requests/request-helpers.ts | 2 +- packages/vertexai/src/requests/request.test.ts | 3 ++- packages/vertexai/src/requests/request.ts | 3 ++- packages/vertexai/src/requests/response-helpers.ts | 2 +- packages/vertexai/src/requests/stream-reader.ts | 2 +- packages/vertexai/src/types/error.ts | 2 -- 10 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/vertexai/src/api.test.ts b/packages/vertexai/src/api.test.ts index 6add7192c61..794c5045012 100644 --- a/packages/vertexai/src/api.test.ts +++ b/packages/vertexai/src/api.test.ts @@ -14,7 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { ModelParams, VertexAIError, VertexAIErrorCode } from './types'; +import { ModelParams, VertexAIErrorCode } from './types'; +import { VertexAIError } from './errors'; import { getGenerativeModel } from './api'; import { expect } from 'chai'; import { VertexAI } from './public-types'; diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index e9e7645c404..0caa9caaf8c 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -24,15 +24,17 @@ import { VertexAI, VertexAIOptions } from './public-types'; import { ModelParams, RequestOptions, - VertexAIError, VertexAIErrorCode } from './types'; +import { VertexAIError } from './errors'; import { GenerativeModel } from './models/generative-model'; export { ChatSession } from './methods/chat-session'; export { GenerativeModel }; +export { VertexAIError } from './errors'; + declare module '@firebase/component' { interface NameServiceMapping { [VERTEX_TYPE]: VertexAIService; diff --git a/packages/vertexai/src/methods/chat-session-helpers.ts b/packages/vertexai/src/methods/chat-session-helpers.ts index 255f6394c69..899db4f626a 100644 --- a/packages/vertexai/src/methods/chat-session-helpers.ts +++ b/packages/vertexai/src/methods/chat-session-helpers.ts @@ -20,9 +20,9 @@ import { POSSIBLE_ROLES, Part, Role, - VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; // https://ai.google.dev/api/rest/v1beta/Content#part diff --git a/packages/vertexai/src/models/generative-model.ts b/packages/vertexai/src/models/generative-model.ts index 682e7ecf247..88be3ee6436 100644 --- a/packages/vertexai/src/models/generative-model.ts +++ b/packages/vertexai/src/models/generative-model.ts @@ -34,9 +34,9 @@ import { StartChatParams, Tool, ToolConfig, - VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; import { ChatSession } from '../methods/chat-session'; import { countTokens } from '../methods/count-tokens'; import { diff --git a/packages/vertexai/src/requests/request-helpers.ts b/packages/vertexai/src/requests/request-helpers.ts index a84ca2cd343..9e525b2a875 100644 --- a/packages/vertexai/src/requests/request-helpers.ts +++ b/packages/vertexai/src/requests/request-helpers.ts @@ -19,9 +19,9 @@ import { Content, GenerateContentRequest, Part, - VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; export function formatSystemInstruction( input?: string | Part | Content diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index 117b776dbc1..16a1ece2c7e 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -22,7 +22,8 @@ import chaiAsPromised from 'chai-as-promised'; import { RequestUrl, Task, getHeaders, makeRequest } from './request'; import { ApiSettings } from '../types/internal'; import { DEFAULT_API_VERSION } from '../constants'; -import { VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; use(sinonChai); use(chaiAsPromised); diff --git a/packages/vertexai/src/requests/request.ts b/packages/vertexai/src/requests/request.ts index 9f3e6083e18..eac99a23038 100644 --- a/packages/vertexai/src/requests/request.ts +++ b/packages/vertexai/src/requests/request.ts @@ -15,7 +15,8 @@ * limitations under the License. */ -import { RequestOptions, VertexAIError, VertexAIErrorCode } from '../types'; +import { RequestOptions, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; import { ApiSettings } from '../types/internal'; import { DEFAULT_API_VERSION, diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index 4ff3dbfbd0e..d62792e38ad 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -21,9 +21,9 @@ import { FunctionCall, GenerateContentCandidate, GenerateContentResponse, - VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; /** * Adds convenience helper methods to a response object, including stream diff --git a/packages/vertexai/src/requests/stream-reader.ts b/packages/vertexai/src/requests/stream-reader.ts index 77a2ccd504e..c4163d26b60 100644 --- a/packages/vertexai/src/requests/stream-reader.ts +++ b/packages/vertexai/src/requests/stream-reader.ts @@ -21,9 +21,9 @@ import { GenerateContentResponse, GenerateContentStreamResult, Part, - VertexAIError, VertexAIErrorCode } from '../types'; +import { VertexAIError } from '../errors'; import { addHelpers } from './response-helpers'; const responseLineRE = /^data\: (.*)(?:\n\n|\r\r|\r\n\r\n)/; diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index 7be38b086a5..eb09e4268a1 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -90,5 +90,3 @@ export const enum VertexAIErrorCode { /** An error occured while parsing. */ PARSE_FAILED = 'parse-failed' } - -export { VertexAIError } from '../errors'; From 906b4fa6cecc7e32f9526513f84f5cf2ff4ac4a0 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Fri, 31 May 2024 15:13:40 -0500 Subject: [PATCH 13/19] Respond to comments --- .changeset/light-cheetahs-arrive.md | 2 +- packages/vertexai/src/api.ts | 2 +- packages/vertexai/src/types/error.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/light-cheetahs-arrive.md b/.changeset/light-cheetahs-arrive.md index a5636bd5a97..d395a78db05 100644 --- a/.changeset/light-cheetahs-arrive.md +++ b/.changeset/light-cheetahs-arrive.md @@ -2,4 +2,4 @@ '@firebase/vertexai-preview': patch --- -Add a new VertexAI error type +Add a publicly exported `VertexAIError` class. \ No newline at end of file diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index 0caa9caaf8c..a5bef3cbdad 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -33,7 +33,7 @@ export { ChatSession } from './methods/chat-session'; export { GenerativeModel }; -export { VertexAIError } from './errors'; +export { VertexAIError }; declare module '@firebase/component' { interface NameServiceMapping { diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index eb09e4268a1..15baaf70043 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -51,7 +51,7 @@ export interface CustomErrorData { statusText?: string; /** Response from a {@link GenerateContentRequest} */ - generateContentResponse?: GenerateContentResponse; + response?: GenerateContentResponse; /** Optional additional details about the error. */ errorDetails?: ErrorDetails[]; From 071b510866a52ebf3b23ac2b6da567cb0f81ab48 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Fri, 31 May 2024 15:17:03 -0500 Subject: [PATCH 14/19] Run formatter --- packages/vertexai/src/api.ts | 6 +----- packages/vertexai/src/errors.ts | 7 ++----- packages/vertexai/src/types/error.ts | 2 +- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/packages/vertexai/src/api.ts b/packages/vertexai/src/api.ts index a5bef3cbdad..92d5aac7144 100644 --- a/packages/vertexai/src/api.ts +++ b/packages/vertexai/src/api.ts @@ -21,11 +21,7 @@ import { getModularInstance } from '@firebase/util'; import { DEFAULT_LOCATION, VERTEX_TYPE } from './constants'; import { VertexAIService } from './service'; import { VertexAI, VertexAIOptions } from './public-types'; -import { - ModelParams, - RequestOptions, - VertexAIErrorCode -} from './types'; +import { ModelParams, RequestOptions, VertexAIErrorCode } from './types'; import { VertexAIError } from './errors'; import { GenerativeModel } from './models/generative-model'; diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index 308b17d6087..44ad849dd9b 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -16,10 +16,7 @@ */ import { FirebaseError } from '@firebase/util'; -import { - VertexAIErrorCode, - CustomErrorData -} from './types'; +import { VertexAIErrorCode, CustomErrorData } from './types'; import { VERTEX_TYPE } from './constants'; /** @@ -38,7 +35,7 @@ export class VertexAIError extends FirebaseError { constructor( readonly code: VertexAIErrorCode, readonly message: string, - readonly customErrorData?: CustomErrorData, + readonly customErrorData?: CustomErrorData ) { // Match error format used by FirebaseError from ErrorFactory const service = VERTEX_TYPE; diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index 15baaf70043..07aed862e55 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -49,7 +49,7 @@ export interface CustomErrorData { /** HTTP status text of the error response. */ statusText?: string; - + /** Response from a {@link GenerateContentRequest} */ response?: GenerateContentResponse; From 20a93d01cb9ad349f76f9661584eb2332d554ccb Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Fri, 31 May 2024 15:31:08 -0500 Subject: [PATCH 15/19] Fix tests that reference generateContentResponse --- packages/vertexai/src/requests/response-helpers.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/vertexai/src/requests/response-helpers.ts b/packages/vertexai/src/requests/response-helpers.ts index d62792e38ad..1b43602b0cb 100644 --- a/packages/vertexai/src/requests/response-helpers.ts +++ b/packages/vertexai/src/requests/response-helpers.ts @@ -46,9 +46,9 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Response error: ${formatBlockErrorMessage( response - )}. Response body stored in error.generateContentResponse`, + )}. Response body stored in error.response`, { - generateContentResponse: response + response } ); } @@ -58,7 +58,7 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Text not available. ${formatBlockErrorMessage(response)}`, { - generateContentResponse: response + response } ); } @@ -78,9 +78,9 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Response error: ${formatBlockErrorMessage( response - )}. Response body stored in error.generateContentResponse`, + )}. Response body stored in error.response`, { - generateContentResponse: response + response } ); } @@ -90,7 +90,7 @@ export function addHelpers( VertexAIErrorCode.RESPONSE_ERROR, `Function call not available. ${formatBlockErrorMessage(response)}`, { - generateContentResponse: response + response } ); } From b9caefe820f2ec633b40d090b420ce3ff7bf7f4a Mon Sep 17 00:00:00 2001 From: dlarocque Date: Fri, 31 May 2024 20:45:46 +0000 Subject: [PATCH 16/19] Update API reports --- common/api-review/vertexai-preview.api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/api-review/vertexai-preview.api.md b/common/api-review/vertexai-preview.api.md index 7b187e729b7..c965bdde432 100644 --- a/common/api-review/vertexai-preview.api.md +++ b/common/api-review/vertexai-preview.api.md @@ -87,7 +87,7 @@ export interface CountTokensResponse { // @public export interface CustomErrorData { errorDetails?: ErrorDetails[]; - generateContentResponse?: GenerateContentResponse; + response?: GenerateContentResponse; status?: number; statusText?: string; } From af865bb76a5f03268a91554feb116bca78a5c625 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 3 Jun 2024 11:55:47 -0500 Subject: [PATCH 17/19] Update reference documentation --- .../vertexai-preview.customerrordata.md | 68 +++++++++++++++++++ .../vertexai-preview.httperrordetails.md | 57 ---------------- docs-devsite/vertexai-preview.md | 2 +- .../vertexai-preview.vertexaierror.md | 22 ++---- 4 files changed, 75 insertions(+), 74 deletions(-) create mode 100644 docs-devsite/vertexai-preview.customerrordata.md delete mode 100644 docs-devsite/vertexai-preview.httperrordetails.md diff --git a/docs-devsite/vertexai-preview.customerrordata.md b/docs-devsite/vertexai-preview.customerrordata.md new file mode 100644 index 00000000000..f0af0574161 --- /dev/null +++ b/docs-devsite/vertexai-preview.customerrordata.md @@ -0,0 +1,68 @@ +Project: /docs/reference/js/_project.yaml +Book: /docs/reference/_book.yaml +page_type: reference + +{% comment %} +DO NOT EDIT THIS FILE! +This is generated by the JS SDK team, and any local changes will be +overwritten. Changes should be made in the source code at +https://github.com/firebase/firebase-js-sdk +{% endcomment %} + +# CustomErrorData interface +Details object that contains data originating from a bad HTTP response. + +Signature: + +```typescript +export interface CustomErrorData +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [errorDetails](./vertexai-preview.customerrordata.md#customerrordataerrordetails) | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] | Optional additional details about the error. | +| [response](./vertexai-preview.customerrordata.md#customerrordataresponse) | [GenerateContentResponse](./vertexai-preview.generatecontentresponse.md#generatecontentresponse_interface) | Response from a [GenerateContentRequest](./vertexai-preview.generatecontentrequest.md#generatecontentrequest_interface) | +| [status](./vertexai-preview.customerrordata.md#customerrordatastatus) | number | HTTP status code of the error response. | +| [statusText](./vertexai-preview.customerrordata.md#customerrordatastatustext) | string | HTTP status text of the error response. | + +## CustomErrorData.errorDetails + +Optional additional details about the error. + +Signature: + +```typescript +errorDetails?: ErrorDetails[]; +``` + +## CustomErrorData.response + +Response from a [GenerateContentRequest](./vertexai-preview.generatecontentrequest.md#generatecontentrequest_interface) + +Signature: + +```typescript +response?: GenerateContentResponse; +``` + +## CustomErrorData.status + +HTTP status code of the error response. + +Signature: + +```typescript +status?: number; +``` + +## CustomErrorData.statusText + +HTTP status text of the error response. + +Signature: + +```typescript +statusText?: string; +``` diff --git a/docs-devsite/vertexai-preview.httperrordetails.md b/docs-devsite/vertexai-preview.httperrordetails.md deleted file mode 100644 index d328b226daa..00000000000 --- a/docs-devsite/vertexai-preview.httperrordetails.md +++ /dev/null @@ -1,57 +0,0 @@ -Project: /docs/reference/js/_project.yaml -Book: /docs/reference/_book.yaml -page_type: reference - -{% comment %} -DO NOT EDIT THIS FILE! -This is generated by the JS SDK team, and any local changes will be -overwritten. Changes should be made in the source code at -https://github.com/firebase/firebase-js-sdk -{% endcomment %} - -# HTTPErrorDetails interface -Details object that contains data originating from a bad HTTP response. - -Signature: - -```typescript -export interface HTTPErrorDetails -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [errorDetails](./vertexai-preview.httperrordetails.md#httperrordetailserrordetails) | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface)\[\] | Optional additional details about the error. | -| [status](./vertexai-preview.httperrordetails.md#httperrordetailsstatus) | number | HTTP status code of the error response. | -| [statusText](./vertexai-preview.httperrordetails.md#httperrordetailsstatustext) | string | HTTP status text of the error response. | - -## HTTPErrorDetails.errorDetails - -Optional additional details about the error. - -Signature: - -```typescript -errorDetails?: ErrorDetails[]; -``` - -## HTTPErrorDetails.status - -HTTP status code of the error response. - -Signature: - -```typescript -status: number; -``` - -## HTTPErrorDetails.statusText - -HTTP status text of the error response. - -Signature: - -```typescript -statusText: string; -``` diff --git a/docs-devsite/vertexai-preview.md b/docs-devsite/vertexai-preview.md index 550ba88d7e5..1ac53d7f2b1 100644 --- a/docs-devsite/vertexai-preview.md +++ b/docs-devsite/vertexai-preview.md @@ -54,6 +54,7 @@ The Vertex AI For Firebase Web SDK. | [Content](./vertexai-preview.content.md#content_interface) | Content type for both prompts and response candidates. | | [CountTokensRequest](./vertexai-preview.counttokensrequest.md#counttokensrequest_interface) | Params for calling [GenerativeModel.countTokens()](./vertexai-preview.generativemodel.md#generativemodelcounttokens) | | [CountTokensResponse](./vertexai-preview.counttokensresponse.md#counttokensresponse_interface) | Response from calling [GenerativeModel.countTokens()](./vertexai-preview.generativemodel.md#generativemodelcounttokens). | +| [CustomErrorData](./vertexai-preview.customerrordata.md#customerrordata_interface) | Details object that contains data originating from a bad HTTP response. | | [Date\_2](./vertexai-preview.date_2.md#date_2_interface) | Protobuf google.type.Date | | [EnhancedGenerateContentResponse](./vertexai-preview.enhancedgeneratecontentresponse.md#enhancedgeneratecontentresponse_interface) | Response object wrapped with helper methods. | | [ErrorDetails](./vertexai-preview.errordetails.md#errordetails_interface) | Details object that may be included in an error response. | @@ -77,7 +78,6 @@ The Vertex AI For Firebase Web SDK. | [GenerativeContentBlob](./vertexai-preview.generativecontentblob.md#generativecontentblob_interface) | Interface for sending an image. | | [GroundingAttribution](./vertexai-preview.groundingattribution.md#groundingattribution_interface) | | | [GroundingMetadata](./vertexai-preview.groundingmetadata.md#groundingmetadata_interface) | Metadata returned to client when grounding is enabled. | -| [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) | Details object that contains data originating from a bad HTTP response. | | [InlineDataPart](./vertexai-preview.inlinedatapart.md#inlinedatapart_interface) | Content part interface if the part represents an image. | | [ModelParams](./vertexai-preview.modelparams.md#modelparams_interface) | Params passed to [getGenerativeModel()](./vertexai-preview.md#getgenerativemodel_e3037c9). | | [PromptFeedback](./vertexai-preview.promptfeedback.md#promptfeedback_interface) | If the prompt was blocked, this will be populated with blockReason and the relevant safetyRatings. | diff --git a/docs-devsite/vertexai-preview.vertexaierror.md b/docs-devsite/vertexai-preview.vertexaierror.md index 07761eb2edf..4365715da29 100644 --- a/docs-devsite/vertexai-preview.vertexaierror.md +++ b/docs-devsite/vertexai-preview.vertexaierror.md @@ -23,15 +23,14 @@ export declare class VertexAIError extends FirebaseError | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(code, message, httpErrorDetails, generateContentResponse)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | +| [(constructor)(code, message, customErrorData)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | ## Properties | Property | Modifiers | Type | Description | | --- | --- | --- | --- | | [code](./vertexai-preview.vertexaierror.md#vertexaierrorcode) | | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | | -| [generateContentResponse](./vertexai-preview.vertexaierror.md#vertexaierrorgeneratecontentresponse) | | [GenerateContentResponse](./vertexai-preview.generatecontentresponse.md#generatecontentresponse_interface) \| undefined | | -| [httpErrorDetails](./vertexai-preview.vertexaierror.md#vertexaierrorhttperrordetails) | | [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) \| undefined | | +| [customErrorData](./vertexai-preview.vertexaierror.md#vertexaierrorcustomerrordata) | | [CustomErrorData](./vertexai-preview.customerrordata.md#customerrordata_interface) \| undefined | | | [message](./vertexai-preview.vertexaierror.md#vertexaierrormessage) | | string | | ## VertexAIError.(constructor) @@ -41,7 +40,7 @@ Creates a new VertexAIError instance. Signature: ```typescript -constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErrorDetails | undefined, generateContentResponse?: GenerateContentResponse | undefined); +constructor(code: VertexAIErrorCode, message: string, customErrorData?: CustomErrorData | undefined); ``` #### Parameters @@ -50,8 +49,7 @@ constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErr | --- | --- | --- | | code | [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode) | The error code from [VertexAIErrorCode](./vertexai-preview.md#vertexaierrorcode). | | message | string | A human-readable message describing the error. | -| httpErrorDetails | [HTTPErrorDetails](./vertexai-preview.httperrordetails.md#httperrordetails_interface) \| undefined | | -| generateContentResponse | [GenerateContentResponse](./vertexai-preview.generatecontentresponse.md#generatecontentresponse_interface) \| undefined | Optional response from a [GenerateContentRequest](./vertexai-preview.generatecontentrequest.md#generatecontentrequest_interface). | +| customErrorData | [CustomErrorData](./vertexai-preview.customerrordata.md#customerrordata_interface) \| undefined | Optional error data. | ## VertexAIError.code @@ -61,20 +59,12 @@ constructor(code: VertexAIErrorCode, message: string, httpErrorDetails?: HTTPErr readonly code: VertexAIErrorCode; ``` -## VertexAIError.generateContentResponse +## VertexAIError.customErrorData Signature: ```typescript -readonly generateContentResponse?: GenerateContentResponse | undefined; -``` - -## VertexAIError.httpErrorDetails - -Signature: - -```typescript -readonly httpErrorDetails?: HTTPErrorDetails | undefined; +readonly customErrorData?: CustomErrorData | undefined; ``` ## VertexAIError.message From c6ad517a22f6b54eb9d7d45a541c382f88ccc7a6 Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 24 Jun 2024 12:45:58 -0400 Subject: [PATCH 18/19] Fix reference docs --- docs-devsite/vertexai-preview.md | 12 ++++++------ docs-devsite/vertexai-preview.vertexaierror.md | 4 ++-- packages/vertexai/src/errors.ts | 2 +- packages/vertexai/src/types/error.ts | 12 ++++++------ 4 files changed, 15 insertions(+), 15 deletions(-) diff --git a/docs-devsite/vertexai-preview.md b/docs-devsite/vertexai-preview.md index 1ac53d7f2b1..57fbab35909 100644 --- a/docs-devsite/vertexai-preview.md +++ b/docs-devsite/vertexai-preview.md @@ -385,13 +385,13 @@ export declare const enum VertexAIErrorCode | Member | Value | Description | | --- | --- | --- | -| ERROR | "error" | A generic error occured. | +| ERROR | "error" | A generic error occurred. | | FETCH\_ERROR | "fetch-error" | An error occurred while performing a fetch. | | INVALID\_CONTENT | "invalid-content" | An error associated with a Content object. | -| NO\_API\_KEY | "no-api-key" | An error occured due to a missing api key. | -| NO\_MODEL | "no-model" | An error occurred due to a missing model. | -| NO\_PROJECT\_ID | "no-project-id" | An error occured due to a missing project id. | -| PARSE\_FAILED | "parse-failed" | An error occured while parsing. | +| NO\_API\_KEY | "no-api-key" | An error occurred due to a missing Firebase API key. | +| NO\_MODEL | "no-model" | An error occurred due to a model name not being specified during initialization. | +| NO\_PROJECT\_ID | "no-project-id" | An error occurred due to a missing project ID. | +| PARSE\_FAILED | "parse-failed" | An error occurred while parsing. | | REQUEST\_ERROR | "request-error" | An error occurred in a request. | -| RESPONSE\_ERROR | "response-error" | An error occured in a response. | +| RESPONSE\_ERROR | "response-error" | An error occurred in a response. | diff --git a/docs-devsite/vertexai-preview.vertexaierror.md b/docs-devsite/vertexai-preview.vertexaierror.md index 4365715da29..05a12c62b8e 100644 --- a/docs-devsite/vertexai-preview.vertexaierror.md +++ b/docs-devsite/vertexai-preview.vertexaierror.md @@ -23,7 +23,7 @@ export declare class VertexAIError extends FirebaseError | Constructor | Modifiers | Description | | --- | --- | --- | -| [(constructor)(code, message, customErrorData)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Creates a new VertexAIError instance. | +| [(constructor)(code, message, customErrorData)](./vertexai-preview.vertexaierror.md#vertexaierrorconstructor) | | Constructs a new instance of the VertexAIError class. | ## Properties @@ -35,7 +35,7 @@ export declare class VertexAIError extends FirebaseError ## VertexAIError.(constructor) -Creates a new VertexAIError instance. +Constructs a new instance of the `VertexAIError` class. Signature: diff --git a/packages/vertexai/src/errors.ts b/packages/vertexai/src/errors.ts index 44ad849dd9b..7cb7a30020b 100644 --- a/packages/vertexai/src/errors.ts +++ b/packages/vertexai/src/errors.ts @@ -26,7 +26,7 @@ import { VERTEX_TYPE } from './constants'; */ export class VertexAIError extends FirebaseError { /** - * Creates a new VertexAIError instance. + * Constructs a new instance of the `VertexAIError` class. * * @param code - The error code from {@link VertexAIErrorCode}. * @param message - A human-readable message describing the error. diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index 07aed862e55..ecc30de5a3e 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -63,13 +63,13 @@ export interface CustomErrorData { * @public */ export const enum VertexAIErrorCode { - /** A generic error occured. */ + /** A generic error occurred. */ ERROR = 'error', /** An error occurred in a request. */ REQUEST_ERROR = 'request-error', - /** An error occured in a response. */ + /** An error occurred in a response. */ RESPONSE_ERROR = 'response-error', /** An error occurred while performing a fetch. */ @@ -78,15 +78,15 @@ export const enum VertexAIErrorCode { /** An error associated with a Content object. */ INVALID_CONTENT = 'invalid-content', - /** An error occured due to a missing api key. */ + /** An error occurred due to a missing Firebase API key. */ NO_API_KEY = 'no-api-key', - /** An error occurred due to a missing model. */ + /** An error occurred due to a model name not being specified during initialization. */ NO_MODEL = 'no-model', - /** An error occured due to a missing project id. */ + /** An error occurred due to a missing project ID. */ NO_PROJECT_ID = 'no-project-id', - /** An error occured while parsing. */ + /** An error occurred while parsing. */ PARSE_FAILED = 'parse-failed' } From 93588d78f5ea410944bcfa8abab7ecfbfd8384dc Mon Sep 17 00:00:00 2001 From: Daniel La Rocque Date: Mon, 24 Jun 2024 13:23:41 -0400 Subject: [PATCH 19/19] Update TOC --- docs-devsite/_toc.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs-devsite/_toc.yaml b/docs-devsite/_toc.yaml index 43ec97cda56..7412d572013 100644 --- a/docs-devsite/_toc.yaml +++ b/docs-devsite/_toc.yaml @@ -468,10 +468,14 @@ toc: path: /docs/reference/js/vertexai-preview.counttokensrequest.md - title: CountTokensResponse path: /docs/reference/js/vertexai-preview.counttokensresponse.md + - title: CustomErrorData + path: /docs/reference/js/vertexai-preview.customerrordata.md - title: Date_2 path: /docs/reference/js/vertexai-preview.date_2.md - title: EnhancedGenerateContentResponse path: /docs/reference/js/vertexai-preview.enhancedgeneratecontentresponse.md + - title: ErrorDetails + path: /docs/reference/js/vertexai-preview.errordetails.md - title: FileData path: /docs/reference/js/vertexai-preview.filedata.md - title: FileDataPart @@ -541,6 +545,8 @@ toc: path: /docs/reference/js/vertexai-preview.usagemetadata.md - title: VertexAI path: /docs/reference/js/vertexai-preview.vertexai.md + - title: VertexAIError + path: /docs/reference/js/vertexai-preview.vertexaierror.md - title: VertexAIOptions path: /docs/reference/js/vertexai-preview.vertexaioptions.md - title: VideoMetadata