Skip to content

Commit 3a8d64a

Browse files
committed
fix(plugins/google-genai): tests
1 parent b9717e1 commit 3a8d64a

File tree

16 files changed

+503
-392
lines changed

16 files changed

+503
-392
lines changed

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,8 @@ export function defineModel(
483483
configSchema: ref.configSchema,
484484
use: middleware,
485485
},
486-
async (request, { streamingRequested, sendChunk, abortSignal }) => {
486+
async (request, options) => {
487+
const { streamingRequested, sendChunk, abortSignal } = options || {};
487488
const clientOpt = { ...clientOptions, signal: abortSignal };
488489

489490
// Make a copy so that modifying the request will not produce side-effects

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

Lines changed: 65 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616

1717
import { EmbedderReference, ModelReference, z } from 'genkit';
1818
import { GenkitPluginV2, genkitPluginV2 } from 'genkit/plugin';
19+
import type { ActionType } from 'genkit/registry';
1920

2021
// These are namespaced because they all intentionally have
2122
// functions of the same name with the same arguments.
2223
// (All exports from these files are used here)
24+
import { listModels } from './client.js';
2325
import * as embedder from './embedder.js';
2426
import * as gemini from './gemini.js';
2527
import * as imagen from './imagen.js';
2628
import { GoogleAIPluginOptions } from './types.js';
29+
import { getApiKeyFromEnvVar } from './utils.js';
2730
import * as veo from './veo.js';
2831

2932
export { type EmbeddingConfig } from './embedder.js';
@@ -37,6 +40,9 @@ export { type GoogleAIPluginOptions };
3740
export function googleAIPlugin(
3841
options?: GoogleAIPluginOptions
3942
): GenkitPluginV2 {
43+
// Cache for list function - per plugin instance
44+
let listCache: any[] | null = null;
45+
4046
return genkitPluginV2({
4147
name: 'googleai',
4248
init: async () => {
@@ -47,32 +53,85 @@ export function googleAIPlugin(
4753
...embedder.defineKnownModels(options),
4854
];
4955
},
56+
resolve: async (actionType: ActionType, name: string) => {
57+
// Extract the model name without the plugin prefix
58+
const modelName = name.replace(/^googleai\//, '');
59+
60+
if (actionType === 'model') {
61+
if (veo.isVeoModelName(modelName)) {
62+
return veo.defineModel(modelName, options);
63+
}
64+
if (imagen.isImagenModelName(modelName)) {
65+
return imagen.defineModel(modelName, options);
66+
}
67+
// For gemini, tts, gemma, and unknown model families
68+
return gemini.defineModel(modelName, options);
69+
} else if (actionType === 'embedder') {
70+
return embedder.defineEmbedder(modelName, options);
71+
} else if (actionType === 'background-model') {
72+
if (veo.isVeoModelName(modelName)) {
73+
return veo.defineModel(modelName, options);
74+
}
75+
}
76+
77+
return undefined;
78+
},
79+
list: async () => {
80+
// Return cached result if available
81+
if (listCache !== null) {
82+
return listCache;
83+
}
84+
85+
const apiKey = options?.apiKey || getApiKeyFromEnvVar();
86+
87+
if (!apiKey) {
88+
return [];
89+
}
90+
91+
try {
92+
const models = await listModels(apiKey, options);
93+
const result = [
94+
...imagen.listActions(models),
95+
...gemini.listActions(models),
96+
...veo.listActions(models),
97+
...embedder.listActions(models),
98+
];
99+
100+
// Cache the result
101+
listCache = result;
102+
return result;
103+
} catch (error) {
104+
// Handle API errors gracefully by returning empty array
105+
console.warn('GoogleAI plugin: Failed to fetch models list:', error);
106+
return [];
107+
}
108+
},
50109
});
51110
}
52111

53112
export type GoogleAIPlugin = {
54113
(pluginOptions?: GoogleAIPluginOptions): GenkitPluginV2;
55-
model(
114+
createModelRef(
56115
name: gemini.KnownGemmaModels | (gemini.GemmaModelName & {}),
57116
config: gemini.GemmaConfig
58117
): ModelReference<gemini.GemmaConfigSchemaType>;
59-
model(
118+
createModelRef(
60119
name: gemini.KnownTtsModels | (gemini.TTSModelName & {}),
61120
config: gemini.GeminiTtsConfig
62121
): ModelReference<gemini.GeminiTtsConfigSchemaType>;
63-
model(
122+
createModelRef(
64123
name: gemini.KnownGeminiModels | (gemini.GeminiModelName & {}),
65124
config?: gemini.GeminiConfig
66125
): ModelReference<gemini.GeminiConfigSchemaType>;
67-
model(
126+
createModelRef(
68127
name: imagen.KnownModels | (imagen.ImagenModelName & {}),
69128
config?: imagen.ImagenConfig
70129
): ModelReference<imagen.ImagenConfigSchemaType>;
71-
model(
130+
createModelRef(
72131
name: veo.KnownModels | (veo.VeoModelName & {}),
73132
config?: veo.VeoConfig
74133
): ModelReference<veo.VeoConfigSchemaType>;
75-
model(name: string, config?: any): ModelReference<z.ZodTypeAny>;
134+
createModelRef(name: string, config?: any): ModelReference<z.ZodTypeAny>;
76135

77136
embedder(
78137
name: string,

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

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

17-
import { z, type Document } from 'genkit';
17+
import {
18+
ActionMetadata,
19+
embedderActionMetadata,
20+
z,
21+
type Document,
22+
} from 'genkit';
1823
import {
1924
EmbedderInfo,
2025
embedderRef,
@@ -29,6 +34,7 @@ import {
2934
EmbeddingInstance,
3035
EmbeddingPrediction,
3136
EmbeddingResult,
37+
Model,
3238
TaskTypeSchema,
3339
VertexPluginOptions,
3440
isMultimodalEmbeddingPrediction,
@@ -108,6 +114,13 @@ export const KNOWN_MODELS = {
108114
supports: { input: ['text'] },
109115
}),
110116
} as const;
117+
export type KnownModels = keyof typeof KNOWN_MODELS;
118+
export type EmbedderModelName = `embedder=${string}`;
119+
export function isEmbedderModelName(
120+
value?: string
121+
): value is EmbedderModelName {
122+
return !!value?.includes('embedding');
123+
}
111124

112125
export function createModelRef(
113126
version: string,
@@ -146,6 +159,21 @@ export function createModelRef(
146159
});
147160
}
148161

162+
// Takes a full list of models, filters for current Veo models only
163+
// and returns a modelActionMetadata for each.
164+
export function listActions(models: Model[]): ActionMetadata[] {
165+
return models
166+
.filter((m: Model) => isEmbedderModelName(m.name))
167+
.map((m: Model) => {
168+
const ref = createModelRef(m.name);
169+
return embedderActionMetadata({
170+
name: ref.name,
171+
info: ref.info,
172+
configSchema: ref.configSchema,
173+
});
174+
});
175+
}
176+
149177
export function defineKnownModels(
150178
clientOptions: ClientOptions,
151179
pluginOptions?: VertexPluginOptions

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,8 @@ export function defineModel(
446446
configSchema: ref.configSchema,
447447
use: middlewares,
448448
},
449-
async (request, { streamingRequested, sendChunk, abortSignal }) => {
449+
async (request, options) => {
450+
const { streamingRequested, sendChunk, abortSignal } = options || {};
450451
let clientOpt = { ...clientOptions, signal: abortSignal };
451452

452453
// Make a copy of messages to avoid side-effects

js/plugins/google-genai/src/vertexai/index.ts

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ import * as imagen from './imagen.js';
2929
import * as lyria from './lyria.js';
3030
import * as veo from './veo.js';
3131

32+
import { ActionType } from 'genkit/registry';
33+
import { listModels } from './client.js';
3234
import { VertexPluginOptions } from './types.js';
3335
import { getDerivedOptions } from './utils.js';
3436

@@ -43,6 +45,9 @@ export { type VeoConfig } from './veo.js';
4345
* Add Google Cloud Vertex AI to Genkit. Includes Gemini and Imagen models and text embedder.
4446
*/
4547
function vertexAIPlugin(options?: VertexPluginOptions): GenkitPluginV2 {
48+
// Cache for list function - per plugin instance
49+
let listCache: any[] | null = null;
50+
4651
return genkitPluginV2({
4752
name: 'vertexai',
4853
init: async () => {
@@ -55,28 +60,66 @@ function vertexAIPlugin(options?: VertexPluginOptions): GenkitPluginV2 {
5560
...embedder.defineKnownModels(clientOptions, options),
5661
];
5762
},
63+
resolve: async (actionType: ActionType, name: string) => {
64+
const clientOptions = await getDerivedOptions(options);
65+
if (actionType === 'model') {
66+
return gemini.defineModel(name, clientOptions);
67+
} else if (actionType === 'embedder') {
68+
return embedder.defineEmbedder(name, clientOptions);
69+
} else if (actionType === 'background-model') {
70+
return veo.defineModel(name, clientOptions);
71+
}
72+
return undefined;
73+
},
74+
list: async () => {
75+
// Return cached result if available
76+
if (listCache !== null) {
77+
return listCache;
78+
}
79+
80+
try {
81+
// Allow undefined options for testing, but try to get derived options
82+
const clientOptions = await getDerivedOptions(options);
83+
const models = await listModels(clientOptions);
84+
const result = [
85+
...imagen.listActions(models),
86+
...lyria.listActions(models),
87+
...veo.listActions(models),
88+
...gemini.listActions(models),
89+
// Note: embedders are excluded from list() for VertexAI plugin
90+
];
91+
92+
// Cache the result
93+
listCache = result;
94+
return result;
95+
} catch (error) {
96+
// Handle errors gracefully by returning empty array
97+
console.warn('VertexAI plugin: Failed to fetch models list:', error);
98+
return [];
99+
}
100+
},
58101
});
59102
}
60103

61104
export type VertexAIPlugin = {
62105
(pluginOptions?: VertexPluginOptions): GenkitPluginV2;
63-
model(
106+
createModelRef(
64107
name: gemini.KnownModels | (gemini.GeminiModelName & {}),
65108
config?: gemini.GeminiConfig
66109
): ModelReference<gemini.GeminiConfigSchemaType>;
67-
model(
110+
createModelRef(
68111
name: imagen.KnownModels | (imagen.ImagenModelName & {}),
69112
config?: imagen.ImagenConfig
70113
): ModelReference<imagen.ImagenConfigSchemaType>;
71-
model(
114+
createModelRef(
72115
name: lyria.KnownModels | (lyria.LyriaModelName & {}),
73116
config: lyria.LyriaConfig
74117
): ModelReference<lyria.LyriaConfigSchemaType>;
75-
model(
118+
createModelRef(
76119
name: veo.KnownModels | (veo.VeoModelName & {}),
77120
config: veo.VeoConfig
78121
): ModelReference<veo.VeoConfigSchemaType>;
79-
model(name: string, config?: any): ModelReference<z.ZodTypeAny>;
122+
createModelRef(name: string, config?: any): ModelReference<z.ZodTypeAny>;
80123

81124
embedder(
82125
name: string,
@@ -90,7 +133,7 @@ export type VertexAIPlugin = {
90133
*/
91134
export const vertexAI = vertexAIPlugin as VertexAIPlugin;
92135
// provide generic implementation for the model function overloads.
93-
(vertexAI as any).model = (
136+
(vertexAI as any).createModelRef = (
94137
name: string,
95138
config?: any
96139
): ModelReference<z.ZodTypeAny> => {

0 commit comments

Comments
 (0)