Skip to content
Open
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
24 changes: 24 additions & 0 deletions js/core/src/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,27 @@ export class Registry {
return [];
}

/**
* Ensures all plugins are initialized when the lookup key has no plugin
* segment, so that plugin-registered entries are visible. Called by
* lookupAction and lookupValue to match list* behavior.
*/
private async ensurePluginsInitializedForLookup(
key: string,
kind: 'action' | 'value'
): Promise<void> {
if (kind === 'action') {
const parsedKey = parseRegistryKey(key);
if (parsedKey && !parsedKey.pluginName && !parsedKey.dynamicActionHost) {
await this.initializeAllPlugins();
}
} else {
if (key && !parsePluginName(key)) {
await this.initializeAllPlugins();
}
}
}

/**
* Looks up an action in the registry.
* @param key The key of the action to lookup.
Expand All @@ -222,6 +243,8 @@ export class Registry {
R extends Action<I, O>,
>(key: string): Promise<R> {
const parsedKey = parseRegistryKey(key);
await this.ensurePluginsInitializedForLookup(key, 'action');

if (
parsedKey?.dynamicActionHost &&
this.actionsById[
Expand Down Expand Up @@ -533,6 +556,7 @@ export class Registry {
type: string,
key: string
): Promise<T | undefined> {
await this.ensurePluginsInitializedForLookup(key, 'value');
const pluginName = parsePluginName(key);
if (!this.valueByTypeAndName[type]?.[key] && pluginName) {
await this.initializePlugin(pluginName);
Expand Down
57 changes: 57 additions & 0 deletions js/core/tests/registry_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -567,6 +567,25 @@ describe('registry class', () => {
);
});

it('returns action registered by plugin with 3-segment key (no plugin in path)', async () => {
// Keys like /flow/foo have no plugin segment; without initializing
// all plugins first, lookupAction would skip plugin init and miss the action.
const flowAction = action(
{ name: 'foo', actionType: 'flow' },
async () => null
);
registry.registerPluginProvider('myPlugin', {
name: 'myPlugin',
async initializer() {
registry.registerAction('flow', flowAction);
return {};
},
});

const found = await registry.lookupAction('/flow/foo');
assert.strictEqual(found, flowAction);
});

it('returns undefined for unknown action', async () => {
assert.strictEqual(
await registry.lookupAction('/model/foo/something'),
Expand Down Expand Up @@ -608,4 +627,42 @@ describe('registry class', () => {
);
});
});

describe('lookupValue', () => {
it('returns value registered by plugin with key that has no plugin segment', async () => {
const testValue = { configured: true };
registry.registerPluginProvider('myPlugin', {
name: 'myPlugin',
async initializer() {
registry.registerValue('defaultModel', 'defaultModel', testValue);
return {};
},
});

const found = await registry.lookupValue('defaultModel', 'defaultModel');
assert.strictEqual(found, testValue);
});

it('returns directly registered value', async () => {
const value = { foo: 1 };
registry.registerValue('myType', 'myKey', value);
assert.strictEqual(await registry.lookupValue('myType', 'myKey'), value);
});

it('initializes plugin when key has plugin segment', async () => {
let inited = false;
// parsePluginName(key) returns the third segment; for 'a/b/c/d' that is 'c'
registry.registerPluginProvider('baz', {
name: 'baz',
async initializer() {
inited = true;
registry.registerValue('config', 'foo/bar/baz/qux', { ok: true });
return {};
},
});
const found = await registry.lookupValue('config', 'foo/bar/baz/qux');
assert.strictEqual(inited, true);
assert.deepStrictEqual(found, { ok: true });
});
});
});
2 changes: 1 addition & 1 deletion js/plugins/vertexai/tests/rerankers/v2/index_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ describe('vertexRerankersPlugin', () => {

it('should not resolve other action types', async () => {
const ai = genkit({
plugins: [vertexRerankers({})],
plugins: [vertexRerankers({ projectId: 'test-project' })],
});

const model = await ai.registry.lookupAction(
Expand Down
Loading