diff --git a/common/api-review/vertexai.api.md b/common/api-review/vertexai.api.md index 0a925cf580c..14177f133f4 100644 --- a/common/api-review/vertexai.api.md +++ b/common/api-review/vertexai.api.md @@ -721,6 +721,7 @@ export class VertexAIError extends FirebaseError { // @public export const enum VertexAIErrorCode { + API_NOT_ENABLED = "api-not-enabled", ERROR = "error", FETCH_ERROR = "fetch-error", INVALID_CONTENT = "invalid-content", diff --git a/packages/vertexai/src/constants.ts b/packages/vertexai/src/constants.ts index 97f6d813abc..3ff894f354b 100644 --- a/packages/vertexai/src/constants.ts +++ b/packages/vertexai/src/constants.ts @@ -21,9 +21,9 @@ export const VERTEX_TYPE = 'vertexAI'; export const DEFAULT_LOCATION = 'us-central1'; -export const DEFAULT_BASE_URL = 'https://firebaseml.googleapis.com'; +export const DEFAULT_BASE_URL = 'https://firebasevertexai.googleapis.com'; -export const DEFAULT_API_VERSION = 'v2beta'; +export const DEFAULT_API_VERSION = 'v1beta'; export const PACKAGE_VERSION = version; diff --git a/packages/vertexai/src/methods/generate-content.test.ts b/packages/vertexai/src/methods/generate-content.test.ts index 51fa82dccc9..fd12964c4bc 100644 --- a/packages/vertexai/src/methods/generate-content.test.ts +++ b/packages/vertexai/src/methods/generate-content.test.ts @@ -220,4 +220,18 @@ describe('generateContent()', () => { ).to.be.rejectedWith(/400.*invalid argument/); expect(mockFetch).to.be.called; }); + it('api not enabled (403)', async () => { + const mockResponse = getMockResponse( + 'unary-failure-firebasevertexai-api-not-enabled.json' + ); + const mockFetch = stub(globalThis, 'fetch').resolves({ + ok: false, + status: 403, + json: mockResponse.json + } as Response); + await expect( + generateContent(fakeApiSettings, 'model', fakeRequestParams) + ).to.be.rejectedWith(/firebasevertexai\.googleapis.*my-project/); + expect(mockFetch).to.be.called; + }); }); diff --git a/packages/vertexai/src/requests/request.test.ts b/packages/vertexai/src/requests/request.test.ts index 16a1ece2c7e..95e37631472 100644 --- a/packages/vertexai/src/requests/request.test.ts +++ b/packages/vertexai/src/requests/request.test.ts @@ -24,6 +24,7 @@ import { ApiSettings } from '../types/internal'; import { DEFAULT_API_VERSION } from '../constants'; import { VertexAIErrorCode } from '../types'; import { VertexAIError } from '../errors'; +import { getMockResponse } from '../../test-utils/mock-response'; use(sinonChai); use(chaiAsPromised); @@ -357,4 +358,28 @@ describe('request methods', () => { expect(fetchStub).to.be.calledOnce; }); }); + it('Network error, API not enabled', async () => { + const mockResponse = getMockResponse( + 'unary-failure-firebasevertexai-api-not-enabled.json' + ); + const fetchStub = stub(globalThis, 'fetch').resolves( + mockResponse as Response + ); + try { + await makeRequest( + 'models/model-name', + Task.GENERATE_CONTENT, + fakeApiSettings, + false, + '' + ); + } catch (e) { + expect((e as VertexAIError).code).to.equal( + VertexAIErrorCode.API_NOT_ENABLED + ); + expect((e as VertexAIError).message).to.include('my-project'); + expect((e as VertexAIError).message).to.include('googleapis.com'); + } + expect(fetchStub).to.be.calledOnce; + }); }); diff --git a/packages/vertexai/src/requests/request.ts b/packages/vertexai/src/requests/request.ts index eac99a23038..a81e2d32d89 100644 --- a/packages/vertexai/src/requests/request.ts +++ b/packages/vertexai/src/requests/request.ts @@ -15,7 +15,7 @@ * limitations under the License. */ -import { RequestOptions, VertexAIErrorCode } from '../types'; +import { ErrorDetails, RequestOptions, VertexAIErrorCode } from '../types'; import { VertexAIError } from '../errors'; import { ApiSettings } from '../types/internal'; import { @@ -151,6 +151,34 @@ export async function makeRequest( } catch (e) { // ignored } + if ( + response.status === 403 && + errorDetails.some( + (detail: ErrorDetails) => detail.reason === 'SERVICE_DISABLED' + ) && + errorDetails.some((detail: ErrorDetails) => + ( + detail.links as Array> + )?.[0]?.description.includes( + 'Google developers console API activation' + ) + ) + ) { + throw new VertexAIError( + VertexAIErrorCode.API_NOT_ENABLED, + `The Vertex AI for Firebase SDK requires the Firebase Vertex AI API ` + + `firebasevertexai.googleapis.com to be enabled for your ` + + `project. Get started in the Firebase Console` + + ` (https://console.firebase.google.com/project/${url.apiSettings.project}/genai/vertex)` + + ` or verify that the API is enabled in the Google Cloud` + + ` Console (https://console.developers.google.com/apis/api/firebasevertexai.googleapis.com/overview?project=${url.apiSettings.project}).`, + { + status: response.status, + statusText: response.statusText, + errorDetails + } + ); + } throw new VertexAIError( VertexAIErrorCode.FETCH_ERROR, `Error fetching from ${url}: [${response.status} ${response.statusText}] ${message}`, @@ -165,6 +193,7 @@ export async function makeRequest( let err = e as Error; if ( (e as VertexAIError).code !== VertexAIErrorCode.FETCH_ERROR && + (e as VertexAIError).code !== VertexAIErrorCode.API_NOT_ENABLED && e instanceof Error ) { err = new VertexAIError( diff --git a/packages/vertexai/src/types/error.ts b/packages/vertexai/src/types/error.ts index d624e64fa07..aaaf19f05b3 100644 --- a/packages/vertexai/src/types/error.ts +++ b/packages/vertexai/src/types/error.ts @@ -78,6 +78,9 @@ export const enum VertexAIErrorCode { /** An error associated with a Content object. */ INVALID_CONTENT = 'invalid-content', + /** An error due to the Firebase API not being enabled in the Console. */ + API_NOT_ENABLED = 'api-not-enabled', + /** An error due to invalid Schema input. */ INVALID_SCHEMA = 'invalid-schema',