Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions src/_api_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,15 +178,6 @@ export class ApiClient {

this.customBaseUrl = opts.httpOptions?.baseUrl;

if (this.clientOptions.vertexai) {
if (this.clientOptions.project && this.clientOptions.location) {
this.clientOptions.apiKey = undefined;
} else if (this.clientOptions.apiKey) {
this.clientOptions.project = undefined;
this.clientOptions.location = undefined;
}
}

const initHttpOptions: types.HttpOptions = {};

if (this.clientOptions.vertexai) {
Expand Down Expand Up @@ -216,7 +207,7 @@ export class ApiClient {
this.clientOptions.project = undefined;
this.clientOptions.location = undefined;
} else if (
this.clientOptions.apiKey ||
(this.clientOptions.apiKey && !this.clientOptions.project) ||
this.clientOptions.location === 'global'
) {
// Vertex Express or global endpoint case.
Expand Down Expand Up @@ -382,10 +373,10 @@ export class ApiClient {
) {
return false;
}
if (this.clientOptions.apiKey) {
if (!this.clientOptions.vertexai) {
return false;
}
if (!this.clientOptions.vertexai) {
if (!this.clientOptions.project || !this.clientOptions.location) {
return false;
}
if (request.path.startsWith('projects/')) {
Expand Down
30 changes: 23 additions & 7 deletions src/node/node_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,15 +207,17 @@ export class GoogleGenAI {
this._triggers = new GeminiNextGenTriggers(this.apiClient);
return this._triggers;
}

constructor(options: GoogleGenAIOptions) {
this.vertexai = resolveCloudFlag(options);

// Validate explicitly set initializer values.
if ((options.project || options.location) && options.apiKey) {
if ((options.project || options.location) && !this.vertexai) {
throw new Error(
'Project/location and API key are mutually exclusive in the client initializer.',
'Project and location are not supported for Gemini API backend.',
);
}

this.vertexai = resolveCloudFlag(options);
const envApiKey = getApiKeyFromEnv();
const envProject = getEnv('GOOGLE_CLOUD_PROJECT');
const envLocation = getEnv('GOOGLE_CLOUD_LOCATION');
Expand All @@ -238,23 +240,37 @@ export class GoogleGenAI {
);
this.apiKey = undefined;
}
// Explicit api_key and explicit project/location already handled above.
if ((envProject || envLocation) && options.apiKey) {
if (
!options.project &&
!options.location &&
(envProject || envLocation) &&
options.apiKey
) {
// Explicit api_key takes precedence over implicit project/location.
console.debug(
'The user provided Vertex AI API key will take precedence over' +
' the project/location from the environment variables.',
);
this.project = undefined;
this.location = undefined;
} else if ((options.project || options.location) && envApiKey) {
} else if (
(options.project || options.location) &&
!options.apiKey &&
envApiKey
) {
// Explicit project/location takes precedence over implicit api_key.
console.debug(
'The user provided project/location will take precedence over' +
' the API key from the environment variables.',
);
this.apiKey = undefined;
} else if ((envProject || envLocation) && envApiKey) {
} else if (
!options.project &&
!options.location &&
!options.apiKey &&
(envProject || envLocation) &&
envApiKey
) {
// Implicit project/location takes precedence over implicit api_key.
console.debug(
'The project/location from the environment variables will take' +
Expand Down
12 changes: 6 additions & 6 deletions test/unit/api_client_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ describe('ApiClient', () => {
expect(client.isVertexAI()).toBe(true);
expect(client.getProject()).toBe('vertex-project');
expect(client.getLocation()).toBe('vertex-location');
expect(client.getApiKey()).toBeUndefined(); // API key is ignored when setting opts.vertexai
expect(client.getApiKey()).toBe('apikey-from-opts');
expect(client.getRequestUrl()).toBe(
'https://vertex-location-aiplatform.googleapis.com/v1beta1',
);
Expand All @@ -478,7 +478,7 @@ describe('ApiClient', () => {
expect(client.isVertexAI()).toBe(true);
expect(client.getProject()).toBe('vertex-project');
expect(client.getLocation()).toBe('us');
expect(client.getApiKey()).toBeUndefined();
expect(client.getApiKey()).toBe('apikey-from-opts');
expect(client.getRequestUrl()).toBe(
'https://aiplatform.us.rep.googleapis.com/v1beta1',
);
Expand All @@ -500,7 +500,7 @@ describe('ApiClient', () => {
expect(client.isVertexAI()).toBe(true);
expect(client.getProject()).toBe('vertex-project');
expect(client.getLocation()).toBe('eu');
expect(client.getApiKey()).toBeUndefined();
expect(client.getApiKey()).toBe('apikey-from-opts');
expect(client.getRequestUrl()).toBe(
'https://aiplatform.eu.rep.googleapis.com/v1beta1',
);
Expand All @@ -523,12 +523,12 @@ describe('ApiClient', () => {
expect(client.isVertexAI()).toBe(true);
expect(client.getProject()).toBe('vertex-project');
expect(client.getLocation()).toBe('us');
expect(client.getApiKey()).toBeUndefined();
expect(client.getApiKey()).toBe('apikey-from-opts');
expect(client.getRequestUrl()).toBe('https://my-custom-url.com/v1beta1');
expect(client.getApiVersion()).toBe('v1beta1');
});

it('should not have api key if project/location is provided for vertexai', () => {
it('should preserve api key if project/location is provided for vertexai', () => {
const client = new ApiClient({
auth: new FakeAuth(),
project: 'vertex-project',
Expand All @@ -542,7 +542,7 @@ describe('ApiClient', () => {
expect(client.isVertexAI()).toBe(true);
expect(client.getProject()).toBe('vertex-project');
expect(client.getLocation()).toBe('vertex-location');
expect(client.getApiKey()).toBeUndefined();
expect(client.getApiKey()).toBe('apikey-from-opts');
expect(client.getRequestUrl()).toBe(
'https://vertex-location-aiplatform.googleapis.com/v1beta1',
);
Expand Down
20 changes: 16 additions & 4 deletions test/unit/node/client_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,18 +123,30 @@ describe('Client', () => {
expect(client['project']).toBe('constructor_project');
expect(client['location']).toBe('constructor_location');
});
it('should not allow both project and apikey in constructor', () => {
it('should not allow project or location for Gemini API backend', () => {
expect(() => {
new GoogleGenAI({
apiKey: 'constructor_api_key',
vertexai: true,
vertexai: false,
project: 'constructor_project',
location: 'constructor_location',
});
}).toThrowError(
'Project/location and API key are mutually exclusive in the client initializer.',
'Project and location are not supported for Gemini API backend.',
);
});
it('should allow explicit apiKey with project and location when vertexai is true', () => {
const client = new GoogleGenAI({
apiKey: 'constructor_api_key',
vertexai: true,
project: 'constructor_project',
location: 'constructor_location',
});
expect(client.vertexai).toBe(true);
expect(client['apiKey']).toBe('constructor_api_key');
expect(client['project']).toBe('constructor_project');
expect(client['location']).toBe('constructor_location');
});
it('should prioritize credentials over implicit api key', () => {
process.env['GOOGLE_API_KEY'] = '';

Expand Down Expand Up @@ -604,7 +616,7 @@ describe('Client', () => {
it('env enterprise should take precedence over env vertexai', () => {
process.env['GOOGLE_GENAI_USE_ENTERPRISE'] = 'false';
process.env['GOOGLE_GENAI_USE_VERTEXAI'] = 'true';
const client = new GoogleGenAI({project: 'p', location: 'l'});
const client = new GoogleGenAI({apiKey: 'key'});
expect(client.vertexai).toBeFalse();
});

Expand Down
Loading