Skip to content
4 changes: 4 additions & 0 deletions js/core/src/background-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,3 +353,7 @@ export function backgroundAction<

return new BackgroundActionImpl(startAction, checkAction, cancelAction);
}

export function isBackgroundAction(a: unknown): a is BackgroundAction {
return a instanceof BackgroundActionImpl;
}
1 change: 1 addition & 0 deletions js/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export {
OperationSchema,
backgroundAction,
defineBackgroundAction,
isBackgroundAction,
registerBackgroundAction,
type BackgroundAction,
type BackgroundActionFnArg,
Expand Down
94 changes: 72 additions & 22 deletions js/genkit/src/genkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,10 @@ import {
defineJsonSchema,
defineSchema,
getContext,
isAction,
isBackgroundAction,
isDevEnv,
registerBackgroundAction,
run,
type Action,
type ActionContext,
Expand All @@ -121,7 +124,11 @@ import { Channel } from '@genkit-ai/core/async';
import type { HasRegistry } from '@genkit-ai/core/registry';
import type { BaseEvalDataPointSchema } from './evaluator.js';
import { logger } from './logging.js';
import type { GenkitPlugin } from './plugin.js';
import {
isPluginV2,
type GenkitPlugin,
type GenkitPluginV2,
} from './plugin.js';
import { Registry, type ActionType } from './registry.js';
import { SPAN_TYPE_ATTR, runInNewSpan } from './tracing.js';

Expand All @@ -138,7 +145,7 @@ export type PromptFn<
*/
export interface GenkitOptions {
/** List of plugins to load. */
plugins?: GenkitPlugin[];
plugins?: (GenkitPlugin | GenkitPluginV2)[];
/** Directory where dotprompts are stored. */
promptDir?: string;
/** Default model to use if no model is specified. */
Expand Down Expand Up @@ -916,26 +923,69 @@ export class Genkit implements HasRegistry {
);
}
plugins.forEach((plugin) => {
const loadedPlugin = plugin(this);
logger.debug(`Registering plugin ${loadedPlugin.name}...`);
activeRegistry.registerPluginProvider(loadedPlugin.name, {
name: loadedPlugin.name,
async initializer() {
logger.debug(`Initializing plugin ${loadedPlugin.name}:`);
await loadedPlugin.initializer();
},
async resolver(action: ActionType, target: string) {
if (loadedPlugin.resolver) {
await loadedPlugin.resolver(action, target);
}
},
async listActions() {
if (loadedPlugin.listActions) {
return await loadedPlugin.listActions();
}
return [];
},
});
if (isPluginV2(plugin)) {
logger.debug(`Registering v2 plugin ${plugin.name}...`);
activeRegistry.registerPluginProvider(plugin.name, {
name: plugin.name,
async initializer() {
logger.debug(`Initializing plugin ${plugin.name}:`);
},
async resolver(action: ActionType, target: string) {
const resolvedAction = await plugin.resolve(action, target);
if (resolvedAction) {
if (isBackgroundAction(resolvedAction)) {
registerBackgroundAction(activeRegistry, resolvedAction);
} else if (isAction(resolvedAction)) {
if (!resolvedAction.__action.actionType) {
throw new GenkitError({
status: 'INVALID_ARGUMENT',
message:
'Action type is missing for ' +
resolvedAction.__action.name,
});
}
activeRegistry.registerAction(
resolvedAction.__action.actionType,
resolvedAction
);
} else {
throw new GenkitError({
status: 'INVALID_ARGUMENT',
message:
'Unkown action type returned from plugin ' + plugin.name,
});
}
}
},
async listActions() {
if (typeof plugin.list === 'function') {
return await plugin.list();
}
return [];
},
});
} else {
const loadedPlugin = (plugin as GenkitPlugin)(this);
logger.debug(`Registering plugin ${loadedPlugin.name}...`);
activeRegistry.registerPluginProvider(loadedPlugin.name, {
name: loadedPlugin.name,
async initializer() {
logger.debug(`Initializing plugin ${loadedPlugin.name}:`);
await loadedPlugin.initializer();
},
async resolver(action: ActionType, target: string) {
if (loadedPlugin.resolver) {
await loadedPlugin.resolver(action, target);
}
},
async listActions() {
if (loadedPlugin.listActions) {
return await loadedPlugin.listActions();
}
return [];
},
});
}
});
}

Expand Down
31 changes: 30 additions & 1 deletion js/genkit/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@
* limitations under the License.
*/

import type { ActionMetadata } from '@genkit-ai/core';
import type { Action, ActionMetadata, BackgroundAction } from '@genkit-ai/core';
import type { Genkit } from './genkit.js';
import type { ActionType } from './registry.js';
export { embedder, embedderActionMetadata } from '@genkit-ai/ai/embedder';
export { evaluator } from '@genkit-ai/ai/evaluator';
export {
backgroundModel,
model,
modelActionMetadata,
} from '@genkit-ai/ai/model';

export interface PluginProvider {
name: string;
Expand All @@ -25,6 +32,18 @@ export interface PluginProvider {
listActions?: () => Promise<ActionMetadata[]>;
}

export type ResolvableAction = Action | BackgroundAction;

export interface GenkitPluginV2 {
version: 'v2';
name: string;
resolve: (
actionType: ActionType,
name: string
) => ResolvableAction | undefined | Promise<ResolvableAction | undefined>;
list?: () => ActionMetadata[] | Promise<ActionMetadata[]>;
}

export type GenkitPlugin = (genkit: Genkit) => PluginProvider;

export type PluginInit = (genkit: Genkit) => void | Promise<void>;
Expand Down Expand Up @@ -62,3 +81,13 @@ export function genkitPlugin<T extends PluginInit>(
},
});
}

export function genkitPluginV2(
options: Omit<GenkitPluginV2, 'version'>
): GenkitPluginV2 {
return { ...options, version: 'v2' };
}

export function isPluginV2(plugin: unknown): plugin is GenkitPluginV2 {
return (plugin as GenkitPluginV2).version === 'v2';
}
Loading