Skip to content

Commit a26f4c7

Browse files
authored
genkit: support for unified plugin (google-genai) (#8957)
1 parent 7124ad0 commit a26f4c7

File tree

4 files changed

+191
-116
lines changed

4 files changed

+191
-116
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- [Added] support for new google-genai plugin during `init genkit` (#8957)

src/init/features/genkit/index.ts

Lines changed: 118 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
interface GenkitInfo {
4040
genkitVersion: string;
4141
cliVersion: string;
42+
genaiVersion: string;
4243
vertexVersion: string;
4344
googleAiVersion: string;
4445
templateVersion: string;
@@ -47,7 +48,8 @@ interface GenkitInfo {
4748

4849
// This is the next breaking change version past the latest template.
4950
const UNKNOWN_VERSION_TOO_HIGH = "2.0.0";
50-
const MIN_VERSION = "0.6.0";
51+
const MIN_VERSION = "1.0.0-rc.1";
52+
const UNIFIED_PLUGIN_VERSION = "1.18.0"; // also rename template if you change this
5153

5254
// This is the latest template. It is the default.
5355
const LATEST_TEMPLATE = "1.0.0";
@@ -92,6 +94,7 @@ async function getGenkitInfo(): Promise<GenkitInfo> {
9294

9395
const genkitVersion = await getPackageVersion("genkit", "GENKIT_DEV_VERSION");
9496
const cliVersion = await getPackageVersion("genkit-cli", "GENKIT_CLI_DEV_VERSION");
97+
const genaiVersion = await getPackageVersion("@genkit-ai/google-genai", "GENKIT_GENAI_VERSION");
9598
const vertexVersion = await getPackageVersion("@genkit-ai/vertexai", "GENKIT_VERTEX_VERSION");
9699
const googleAiVersion = await getPackageVersion("@genkit-ai/googleai", "GENKIT_GOOGLEAI_VERSION");
97100

@@ -110,11 +113,14 @@ async function getGenkitInfo(): Promise<GenkitInfo> {
110113
if (!continueInstall) {
111114
stopInstall = true;
112115
}
113-
} else if (semver.gte(genkitVersion, "1.0.0-rc.1")) {
114-
// 1.0.0-rc.1 < 1.0.0
115-
templateVersion = "1.0.0";
116+
} else if (
117+
semver.gte(genkitVersion, UNIFIED_PLUGIN_VERSION) &&
118+
semver.gte(genaiVersion, "0.0.2-rc.1")
119+
) {
120+
// Unified plugin template
121+
templateVersion = UNIFIED_PLUGIN_VERSION;
116122
} else if (semver.gte(genkitVersion, MIN_VERSION)) {
117-
templateVersion = "0.9.0";
123+
templateVersion = "1.0.0";
118124
} else {
119125
throw new FirebaseError(
120126
`The requested version of Genkit (${genkitVersion}) is no ` +
@@ -127,6 +133,7 @@ async function getGenkitInfo(): Promise<GenkitInfo> {
127133
cliVersion,
128134
vertexVersion,
129135
googleAiVersion,
136+
genaiVersion,
130137
templateVersion,
131138
stopInstall,
132139
};
@@ -241,55 +248,105 @@ export async function ensureVertexApiEnabled(options: Options): Promise<void> {
241248
}
242249

243250
interface PluginInfo {
251+
// The name of the plugin
252+
plugin: string;
244253
// Imported items from `name` (can be comma list).
245254
imports: string;
246255
// Comment for 'the model import line.
247256
modelImportComment?: string;
248257
// Initializer call.
249258
init: string;
250-
// Model name as an imported reference.
259+
// Model definition
251260
model?: string;
252-
// Model name as a string reference.
253-
modelStr?: string;
254261
}
255262

256-
interface PromptOption {
263+
interface ModelOption {
257264
// Label for prompt option.
258265
label: string;
266+
// Provider (e.g. googleAI, vertexAI)
267+
provider?: string;
259268
// Plugin name.
260269
plugin?: string;
261270
// Package including version
262271
package?: string;
263272
}
264273

265274
/** Model to plugin name. */
266-
function getModelOptions(genkitInfo: GenkitInfo): Record<ModelProvider, PromptOption> {
267-
const modelOptions: Record<ModelProvider, PromptOption> = {
268-
vertexai: {
269-
label: "Google Cloud Vertex AI",
270-
plugin: "@genkit-ai/vertexai",
271-
package: `@genkit-ai/vertexai@${genkitInfo.vertexVersion}`,
272-
},
273-
googleai: {
274-
label: "Google AI",
275-
plugin: "@genkit-ai/googleai",
276-
package: `@genkit-ai/googleai@${genkitInfo.googleAiVersion}`,
277-
},
278-
none: { label: "None", plugin: undefined, package: undefined },
279-
};
275+
function getModelOptions(genkitInfo: GenkitInfo): Record<ModelProvider, ModelOption> {
276+
let modelOptions: Record<ModelProvider, ModelOption>;
277+
if (semver.gte(genkitInfo.templateVersion, UNIFIED_PLUGIN_VERSION)) {
278+
modelOptions = {
279+
vertexai: {
280+
label: "Google Cloud Vertex AI",
281+
provider: "vertexai",
282+
plugin: "@genkit-ai/google-genai",
283+
package: `@genkit-ai/google-genai@${genkitInfo.genaiVersion}`,
284+
},
285+
googleai: {
286+
label: "Google AI",
287+
provider: "googleai",
288+
plugin: "@genkit-ai/google-genai",
289+
package: `@genkit-ai/google-genai@${genkitInfo.genaiVersion}`,
290+
},
291+
none: { label: "None" },
292+
};
293+
} else {
294+
modelOptions = {
295+
vertexai: {
296+
label: "Google Cloud Vertex AI",
297+
plugin: "@genkit-ai/vertexai",
298+
package: `@genkit-ai/vertexai@${genkitInfo.vertexVersion}`,
299+
},
300+
googleai: {
301+
label: "Google AI",
302+
plugin: "@genkit-ai/googleai",
303+
package: `@genkit-ai/googleai@${genkitInfo.googleAiVersion}`,
304+
},
305+
none: { label: "None" },
306+
};
307+
}
308+
280309
return modelOptions;
281310
}
282311

283312
/** Plugin name to descriptor. */
284313
const pluginToInfo: Record<string, PluginInfo> = {
285314
"@genkit-ai/firebase": {
315+
plugin: "@genkit-ai/firebase",
286316
imports: "firebase",
287317
init: `
288318
// Load the Firebase plugin, which provides integrations with several
289319
// Firebase services.
290320
firebase()`.trimStart(),
291321
},
322+
"@genkit-ai/google-genai(vertexai)": {
323+
plugin: "@genkit-ai/google-genai",
324+
imports: "vertexAI",
325+
modelImportComment: `
326+
// Import vertexAI provider from the unified plugin. The Vertex AI API provides
327+
// access to many models.`,
328+
init: ` // Load the VertexAI provider. You can optionally specify your location
329+
// and projectID by passing in a config object; if you don't, the provider
330+
// uses the value from environment variables like GCLOUD_PROJECT and GCLOUD_LOCATION.
331+
// If you want to use Vertex Express Mode, you can specify apiKey instead.
332+
vertexAI({location: "global"})`,
333+
model: 'vertexAI.model("gemini-2.5-flash")',
334+
},
335+
"@genkit-ai/google-genai(googleai)": {
336+
plugin: "@genkit-ai/google-genai",
337+
imports: "googleAI",
338+
modelImportComment: `
339+
// Import googleAI provider from the unified plugin. The Gemini Developer API
340+
// provides access to several generative models.`,
341+
init: ` // Load the GoogleAI provider. You can optionally specify your API key by
342+
// passing in a config object; if you don't, the provider uses the value
343+
// from the GOOGLE_GENAI_API_KEY environment variable, which is the
344+
// recommended practice.
345+
googleAI()`,
346+
model: 'googleAI.model("gemini-2.5-flash")',
347+
},
292348
"@genkit-ai/vertexai": {
349+
plugin: "@genkit-ai/vertexai",
293350
imports: "vertexAI",
294351
modelImportComment: `
295352
// Import models from the Vertex AI plugin. The Vertex AI API provides access to
@@ -299,9 +356,10 @@ const pluginToInfo: Record<string, PluginInfo> = {
299356
// by passing in a config object; if you don't, the Vertex AI plugin uses
300357
// the value from the GCLOUD_PROJECT environment variable.
301358
vertexAI({location: "us-central1"})`.trimStart(),
302-
model: "gemini20Flash",
359+
model: 'vertexAI.model("gemini-2.5-flash")',
303360
},
304361
"@genkit-ai/googleai": {
362+
plugin: "@genkit-ai/googleai",
305363
imports: "googleAI",
306364
modelImportComment: `
307365
// Import models from the Google AI plugin. The Google AI API provides access to
@@ -312,10 +370,24 @@ const pluginToInfo: Record<string, PluginInfo> = {
312370
// the value from the GOOGLE_GENAI_API_KEY environment variable, which is
313371
// the recommended practice.
314372
googleAI()`.trimStart(),
315-
model: "gemini20Flash",
373+
model: 'googleAI.model("gemini-2.5-flash")',
316374
},
317375
};
318376

377+
function getPluginInfo(option?: ModelOption): PluginInfo {
378+
if (option?.provider && option.plugin) {
379+
return pluginToInfo[`${option.plugin}(${option.provider})`];
380+
}
381+
if (option?.plugin) {
382+
return pluginToInfo[option.plugin];
383+
}
384+
return {
385+
plugin: "",
386+
imports: "",
387+
init: "",
388+
};
389+
}
390+
319391
/** Basic packages required to use Genkit. */
320392
function getBasePackages(genkitVersion: string): string[] {
321393
const basePackages = ["express", `genkit@${genkitVersion}`];
@@ -352,13 +424,8 @@ export async function genkitSetup(
352424
}
353425

354426
// Compile plugins list.
355-
const plugins: string[] = [];
356427
const pluginPackages: string[] = [];
357428
pluginPackages.push(`@genkit-ai/firebase@${genkitInfo.genkitVersion}`);
358-
359-
if (modelOptions[model]?.plugin) {
360-
plugins.push(modelOptions[model].plugin || "");
361-
}
362429
if (modelOptions[model]?.package) {
363430
pluginPackages.push(modelOptions[model].package || "");
364431
}
@@ -393,8 +460,7 @@ export async function genkitSetup(
393460
}));
394461

395462
generateSampleFile(
396-
modelOptions[model].plugin,
397-
plugins,
463+
modelOptions[model],
398464
projectDir,
399465
genkitInfo.templateVersion,
400466
enableTelemetry,
@@ -515,25 +581,25 @@ async function installNpmPackages(
515581

516582
/**
517583
* Generates a sample index.ts file.
518-
* @param modelPlugin Model plugin name.
519-
* @param configPlugins config plugins.
584+
* @param modelOption Information about the model/plugin
585+
* @param projectDir Where to put the sample
586+
* @param templateVersion Which template the use
587+
* @param enableTelemetry If telemetry is enabled or not.
520588
*/
521589
function generateSampleFile(
522-
modelPlugin: string | undefined,
523-
configPlugins: string[],
590+
modelOption: ModelOption | undefined,
524591
projectDir: string,
525592
templateVersion: string,
526593
enableTelemetry: boolean,
527594
): void {
528595
let modelImport = "";
529-
if (modelPlugin && pluginToInfo[modelPlugin].model) {
530-
const modelInfo = pluginToInfo[modelPlugin].model || "";
531-
modelImport = "\n" + generateImportStatement(modelInfo, modelPlugin) + "\n";
596+
const pluginInfo = getPluginInfo(modelOption);
597+
if (pluginInfo.imports) {
598+
modelImport = "\n" + generateImportStatement(pluginInfo) + "\n";
532599
}
533600
let modelImportComment = "";
534-
if (modelPlugin && pluginToInfo[modelPlugin].modelImportComment) {
535-
const comment = pluginToInfo[modelPlugin].modelImportComment || "";
536-
modelImportComment = `\n${comment}`;
601+
if (pluginInfo.modelImportComment) {
602+
modelImportComment = `\n${pluginInfo.modelImportComment}`;
537603
}
538604
const commentedModelImport = `${modelImportComment}${modelImport}`;
539605
const templatePath = path.join(
@@ -542,15 +608,10 @@ function generateSampleFile(
542608
);
543609
const template = fs.readFileSync(templatePath, "utf8");
544610
const sample = renderConfig(
545-
configPlugins,
611+
pluginInfo,
546612
template
547613
.replace("$GENKIT_MODEL_IMPORT\n", commentedModelImport)
548-
.replace(
549-
"$GENKIT_MODEL",
550-
modelPlugin
551-
? pluginToInfo[modelPlugin].model || pluginToInfo[modelPlugin].modelStr || ""
552-
: "'' /* TODO: Set a model. */",
553-
),
614+
.replace("$GENKIT_MODEL", pluginInfo.model ?? "'' /* TODO: Set a model. */"),
554615
enableTelemetry,
555616
);
556617
logLabeledBullet("genkit", "Generating sample file");
@@ -640,21 +701,19 @@ async function updatePackageJson(nonInteractive: boolean, projectDir: string): P
640701
}
641702
}
642703

643-
function renderConfig(pluginNames: string[], template: string, enableTelemetry: boolean): string {
644-
const imports = pluginNames
645-
.map((pluginName) => generateImportStatement(pluginToInfo[pluginName].imports, pluginName))
646-
.join("\n");
647-
const plugins =
648-
pluginNames.map((pluginName) => ` ${pluginToInfo[pluginName].init},`).join("\n") ||
649-
" /* Add your plugins here. */";
704+
function renderConfig(pluginInfo: PluginInfo, template: string, enableTelemetry: boolean): string {
705+
const plugins = pluginInfo.init || " /* Add your plugins here. */";
650706
return template
651-
.replace("$GENKIT_CONFIG_IMPORTS", imports)
707+
.replace("$GENKIT_CONFIG_IMPORTS", generateImportStatement(pluginInfo))
652708
.replace("$GENKIT_CONFIG_PLUGINS", plugins)
653709
.replaceAll("$TELEMETRY_COMMENT", enableTelemetry ? "" : "// ");
654710
}
655711

656-
function generateImportStatement(imports: string, name: string): string {
657-
return `import {${imports}} from "${name}";`;
712+
function generateImportStatement(pluginInfo: PluginInfo): string {
713+
if (pluginInfo.imports && pluginInfo.plugin) {
714+
return `import {${pluginInfo.imports}} from "${pluginInfo.plugin}";`;
715+
}
716+
return "";
658717
}
659718

660719
/**

templates/genkit/firebase.0.9.0.template

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)