Skip to content

Commit 35e066c

Browse files
authored
feat(js/plugins/google-genai): Added Veo models (#3193)
1 parent 9b49b85 commit 35e066c

File tree

11 files changed

+1063
-130
lines changed

11 files changed

+1063
-130
lines changed

js/plugins/google-genai/src/common/utils.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { JSONSchema, ModelReference } from 'genkit';
17+
import { GenkitError, JSONSchema, ModelReference } from 'genkit';
1818
import { GenerateRequest, GenerationCommonConfigSchema } from 'genkit/model';
1919
import { ImagenInstance } from './types';
2020

@@ -50,6 +50,23 @@ export function modelName(name?: string): string | undefined {
5050
return name?.split('/').at(-1);
5151
}
5252

53+
/**
54+
* Gets the suffix of a model string.
55+
* Throws if the string is empty.
56+
* @param name A string containing the model string
57+
* @returns the model string stripped of prefixes and guaranteed not empty.
58+
*/
59+
export function checkModelName(name?: string): string {
60+
const version = modelName(name);
61+
if (!version) {
62+
throw new GenkitError({
63+
status: 'INVALID_ARGUMENT',
64+
message: 'Model name is required.',
65+
});
66+
}
67+
return version;
68+
}
69+
5370
export function extractText(request: GenerateRequest) {
5471
return request.messages
5572
.at(-1)!

js/plugins/google-genai/src/googleai/client.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import {
2929
ListModelsResponse,
3030
Model,
3131
Part,
32+
VeoOperation,
33+
VeoPredictRequest,
3234
} from './types';
3335

3436
/**
@@ -174,6 +176,46 @@ export async function imagenPredict(
174176
return response.json() as Promise<ImagenPredictResponse>;
175177
}
176178

179+
export async function veoPredict(
180+
apiKey: string,
181+
model: string,
182+
veoPredictRequest: VeoPredictRequest,
183+
clientOptions?: ClientOptions
184+
): Promise<VeoOperation> {
185+
const url = getGoogleAIUrl({
186+
resourcePath: `models/${model}`,
187+
resourceMethod: 'predictLongRunning',
188+
clientOptions,
189+
});
190+
191+
const fetchOptions: RequestInit = {
192+
method: 'POST',
193+
headers: await getHeaders(apiKey, clientOptions),
194+
body: JSON.stringify(veoPredictRequest),
195+
};
196+
197+
const response = await makeRequest(url, fetchOptions);
198+
return response.json() as Promise<VeoOperation>;
199+
}
200+
201+
export async function checkVeoOperation(
202+
apiKey: string,
203+
operation: string,
204+
clientOptions?: ClientOptions
205+
): Promise<VeoOperation> {
206+
const url = getGoogleAIUrl({
207+
resourcePath: operation,
208+
clientOptions,
209+
});
210+
const fetchOptions: RequestInit = {
211+
method: 'GET',
212+
headers: await getHeaders(apiKey, clientOptions),
213+
};
214+
215+
const response = await makeRequest(url, fetchOptions);
216+
return response.json() as Promise<VeoOperation>;
217+
}
218+
177219
/**
178220
* Generates a Google AI URL.
179221
*

js/plugins/google-genai/src/googleai/embedder.ts

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ import {
2121
EmbedderInfo,
2222
EmbedderReference,
2323
Genkit,
24-
GenkitError,
2524
z,
2625
} from 'genkit';
2726
import { embedderRef } from 'genkit/embedder';
@@ -32,7 +31,7 @@ import {
3231
Model,
3332
TaskTypeSchema,
3433
} from './types';
35-
import { calculateApiKey, checkApiKey, modelName } from './utils';
34+
import { calculateApiKey, checkApiKey, checkModelName } from './utils';
3635

3736
export const EmbeddingConfigSchema = z
3837
.object({
@@ -80,26 +79,17 @@ function commonRef(
8079

8180
const GENERIC_MODEL = commonRef('embedder');
8281

83-
// TODO(ifielker): Update embedders to be current models.
84-
// (textEmbeddingGecko001 is outdated).
85-
8682
const KNOWN_MODELS = {
8783
'text-embedding-004': commonRef('text-embedding-004'),
84+
'gemini-embedding-exp': commonRef('gemini-embedding-exp'),
8885
};
8986
export type KnownModels = keyof typeof KNOWN_MODELS; // For autocomplete
9087

9188
export function model(
9289
version: string,
9390
config: EmbeddingConfig = {}
9491
): EmbedderReference<ConfigSchemaType> {
95-
const name = modelName(version);
96-
if (!name) {
97-
throw new GenkitError({
98-
status: 'INVALID_ARGUMENT',
99-
message: 'Not able to create embedderReference for empty model version',
100-
});
101-
}
102-
92+
const name = checkModelName(version);
10393
return embedderRef({
10494
name: `googleai/${name}`,
10595
version: name,

js/plugins/google-genai/src/googleai/gemini.ts

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ import {
5959
Tool,
6060
ToolConfig,
6161
} from './types';
62-
import { calculateApiKey, checkApiKey, modelName } from './utils';
62+
import { calculateApiKey, checkApiKey, checkModelName } from './utils';
6363

6464
/**
6565
* See https://ai.google.dev/gemini-api/docs/safety-settings#safety-filters.
@@ -298,14 +298,28 @@ const GENERIC_GEMMA_MODEL = commonRef(
298298
GemmaConfigSchema
299299
);
300300

301-
const KNOWN_MODELS = {
301+
const KNOWN_GEMINI_MODELS = {
302+
'gemini-2.5-pro': commonRef('gemini-2.5-pro'),
303+
'gemini-2.5-flash': commonRef('gemini-2.5-flash'),
304+
'gemini-2.5-flash-lite-preview-06-17': commonRef(
305+
'gemini-2.5-flash-lite-preview-06-17'
306+
),
302307
'gemini-2.0-flash': commonRef('gemini-2.0-flash'),
308+
'gemini-2.0-flash-preview-image-generation': commonRef(
309+
'gemini-2.0-flash-preview-image-generation'
310+
),
303311
'gemini-2.0-flash-lite': commonRef('gemini-2.0-flash-lite'),
304-
'gemini-2.0-pro-exp-02-05': commonRef('gemini-2.0-pro-exp-02-05'),
305-
'gemini-2.0-flash-exp': commonRef('gemini-2.0-flash-exp'),
306-
'gemini-2.5-pro-exp-03-25': commonRef('gemini-2.5-pro-exp-03-25'),
307-
'gemini-2.5-pro-preview-03-25': commonRef('gemini-2.5-pro-preview-03-25'),
308-
'gemini-2.5-flash-preview-04-17': commonRef('gemini-2.5-flash-preview-04-17'),
312+
'gemini-1.5-flash': commonRef('gemini-1.5-flash'),
313+
'gemini-1.5-flash-8b': commonRef('gemini-1.5-flash-8b'),
314+
'gemini-1.5-pro': commonRef('gemini-1.5-pro'),
315+
};
316+
export type KnownGeminiModels = keyof typeof KNOWN_GEMINI_MODELS;
317+
export type GeminiModelName = `gemini-${string}`;
318+
export function isGeminiModelName(value: string): value is GeminiModelName {
319+
return value.startsWith('gemini-') && !value.endsWith('-tts');
320+
}
321+
322+
const KNOWN_TTS_MODELS = {
309323
'gemini-2.5-flash-preview-tts': commonRef(
310324
'gemini-2.5-flash-preview-tts',
311325
{ ...GENERIC_TTS_MODEL.info },
@@ -316,36 +330,37 @@ const KNOWN_MODELS = {
316330
{ ...GENERIC_TTS_MODEL.info },
317331
GeminiTtsConfigSchema
318332
),
333+
};
334+
export type KnownTtsModels = keyof typeof KNOWN_TTS_MODELS;
335+
export type TTSModelName = `gemini-${string}-tts`;
336+
export function isTTSModelName(value: string): value is TTSModelName {
337+
return value.startsWith('gemini-') && value.endsWith('-tts');
338+
}
339+
340+
const KNOWN_GEMMA_MODELS = {
319341
'gemma-3-12b-it': commonRef('gemma-3-12b-it', undefined, GemmaConfigSchema),
320342
'gemma-3-1b-it': commonRef('gemma-3-1b-it', undefined, GemmaConfigSchema),
321343
'gemma-3-27b-it': commonRef('gemma-3-27b-it', undefined, GemmaConfigSchema),
322344
'gemma-3-4b-it': commonRef('gemma-3-4b-it', undefined, GemmaConfigSchema),
323345
'gemma-3n-e4b-it': commonRef('gemma-3n-e4b-it', undefined, GemmaConfigSchema),
324346
} as const;
325-
export type KnownModels = keyof typeof KNOWN_MODELS; // For autocomplete
326-
327-
// For conditional types in index.ts model()
328-
export type TTSModelName = `gemini-${string}-tts`;
329-
export function isTTSModelName(value: string): value is TTSModelName {
330-
return value.startsWith('gemini-') && value.endsWith('-tts');
331-
}
332-
347+
export type KnownGemmaModels = keyof typeof KNOWN_GEMMA_MODELS;
333348
export type GemmaModelName = `gemma-${string}`;
334349
export function isGemmaModelName(value: string): value is GemmaModelName {
335350
return value.startsWith('gemma-');
336351
}
337352

353+
const KNOWN_MODELS = {
354+
...KNOWN_GEMINI_MODELS,
355+
...KNOWN_TTS_MODELS,
356+
...KNOWN_GEMMA_MODELS,
357+
};
358+
338359
export function model(
339360
version: string,
340361
config: GeminiConfig | GeminiTtsConfig = {}
341362
): ModelReference<ConfigSchemaType> {
342-
const name = modelName(version);
343-
if (!name) {
344-
throw new GenkitError({
345-
status: 'INVALID_ARGUMENT',
346-
message: 'Not able to create modelReference for empty model version',
347-
});
348-
}
363+
const name = checkModelName(version);
349364

350365
if (isTTSModelName(name)) {
351366
return modelRef({
@@ -411,6 +426,10 @@ export function defineModel(
411426
): ModelAction {
412427
checkApiKey(pluginOptions?.apiKey);
413428
const ref = model(name);
429+
const clientOptions: ClientOptions = {
430+
apiVersion: pluginOptions?.apiVersion,
431+
baseUrl: pluginOptions?.baseUrl,
432+
};
414433

415434
const middleware: ModelMiddleware[] = [];
416435
if (ref.info?.supports?.media) {
@@ -447,11 +466,6 @@ export function defineModel(
447466
use: middleware,
448467
},
449468
async (request, sendChunk) => {
450-
const clientOptions: ClientOptions = {
451-
apiVersion: pluginOptions?.apiVersion,
452-
baseUrl: pluginOptions?.baseUrl,
453-
};
454-
455469
// Make a copy so that modifying the request will not produce side-effects
456470
const messages = [...request.messages];
457471
if (messages.length === 0) throw new Error('No messages provided.');

js/plugins/google-genai/src/googleai/imagen.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
import {
1818
ActionMetadata,
19-
GenkitError,
2019
MediaPart,
2120
MessageData,
2221
modelActionMetadata,
@@ -43,6 +42,7 @@ import type {
4342
import {
4443
calculateApiKey,
4544
checkApiKey,
45+
checkModelName,
4646
extractImagenImage,
4747
extractText,
4848
modelName,
@@ -116,6 +116,12 @@ const GENERIC_MODEL = commonRef('imagen', {
116116

117117
const KNOWN_MODELS = {
118118
'imagen-3.0-generate-002': commonRef('imagen-3.0-generate-002'),
119+
'imagen-4.0-generate-preview-06-06': commonRef(
120+
'imagen-4.0-generate-preview-06-06'
121+
),
122+
'imagen-4.0-ultra-generate-preview-06-06': commonRef(
123+
'imagen-4.0-ultra-generate-preview-06-06'
124+
),
119125
} as const;
120126
export type KnownModels = keyof typeof KNOWN_MODELS; // For autocomplete
121127

@@ -129,13 +135,7 @@ export function model(
129135
version: string,
130136
config: ImagenConfig = {}
131137
): ModelReference<ConfigSchemaType> {
132-
const name = modelName(version);
133-
if (!name) {
134-
throw new GenkitError({
135-
status: 'INVALID_ARGUMENT',
136-
message: 'Not able to create modelReference for empty model version',
137-
});
138-
}
138+
const name = checkModelName(version);
139139
if (KNOWN_MODELS[name]) {
140140
return KNOWN_MODELS[name].withConfig(config);
141141
}

0 commit comments

Comments
 (0)