fix(plugins): isolate provider runtime rows

This commit is contained in:
Vincent Koc
2026-06-04 01:09:33 +02:00
parent 116bc2a0f0
commit bea6280cc2
2 changed files with 87 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ import {
resolveOwningPluginIdsForProviderRef,
withBundledProviderVitestCompat,
} from "./providers.js";
import type { PluginProviderRegistration } from "./registry-types.js";
import { getActivePluginRegistryWorkspaceDir } from "./runtime.js";
import {
buildPluginRuntimeLoadOptionsFromValues,
@@ -305,6 +306,31 @@ function resolveRuntimeProviderPluginLoadState(
return { loadOptions };
}
function projectPluginProviderRegistration(
entry: PluginProviderRegistration,
scope?: ReadonlySet<string>,
): ProviderPlugin | null {
try {
const pluginId = entry.pluginId;
if (scope && !scope.has(pluginId)) {
return null;
}
return Object.assign({}, entry.provider, { pluginId });
} catch {
return null;
}
}
function projectPluginProviderRegistrations(
entries: readonly PluginProviderRegistration[],
onlyPluginIds?: readonly string[],
): ProviderPlugin[] {
const scope = onlyPluginIds ? new Set(onlyPluginIds) : undefined;
return entries
.map((entry) => projectPluginProviderRegistration(entry, scope))
.filter((provider): provider is ProviderPlugin => provider !== null);
}
export function isPluginProvidersLoadInFlight(
params: Parameters<typeof resolvePluginProviders>[0],
): boolean {
@@ -349,8 +375,9 @@ export function resolvePluginProviders(params: {
return [];
}
const registry = loadOpenClawPlugins(loadState.loadOptions);
return registry.providers.map((entry) =>
Object.assign({}, entry.provider, { pluginId: entry.pluginId }),
return projectPluginProviderRegistrations(
registry.providers,
loadState.loadOptions.onlyPluginIds,
);
}
const loadState = resolveRuntimeProviderPluginLoadState(params, base, snapshot);
@@ -370,7 +397,8 @@ export function resolvePluginProviders(params: {
return [];
}
return registry.providers.map((entry) =>
Object.assign({}, entry.provider, { pluginId: entry.pluginId }),
return projectPluginProviderRegistrations(
registry.providers,
loadState.loadOptions.onlyPluginIds,
);
}

View File

@@ -787,6 +787,61 @@ describe("resolvePluginProviders", () => {
});
});
it("skips unreadable runtime provider rows while resolving plugin providers", () => {
setManifestPlugins([
createManifestProviderPlugin({
id: "healthy-plugin",
providerIds: ["healthy-provider"],
enabledByDefault: true,
}),
]);
const registry = createEmptyPluginRegistry();
const brokenRegistration = Object.defineProperty(
{
pluginId: "broken-plugin",
source: "test",
},
"provider",
{
get() {
throw new Error("provider row exploded");
},
},
);
const healthyProvider: ProviderPlugin = {
id: "healthy-provider",
label: "Healthy Provider",
auth: [],
};
const outOfScopeProvider: ProviderPlugin = {
id: "out-of-scope-provider",
label: "Out of Scope Provider",
auth: [],
};
registry.providers.push(
{ pluginId: "out-of-scope-plugin", provider: outOfScopeProvider, source: "test" },
brokenRegistration as never,
{
pluginId: "healthy-plugin",
provider: healthyProvider,
source: "test",
},
);
resolveRuntimePluginRegistryMock.mockReturnValue(registry);
expect(
resolvePluginProviders({
config: {},
onlyPluginIds: ["healthy-plugin"],
}),
).toEqual([
{
...healthyProvider,
pluginId: "healthy-plugin",
},
]);
});
it("keeps bundled provider plugins enabled when they default on outside Vitest compat", () => {
expect(resolveEnabledProviderPluginIds({ config: {}, env: {} as NodeJS.ProcessEnv })).toEqual([
"google",