fix(plugins): harden provider metadata snapshot reuse

This commit is contained in:
Peter Steinberger
2026-05-31 17:36:20 +01:00
parent 7a6c62b92b
commit f3728a6a5b
3 changed files with 27 additions and 26 deletions
@@ -283,6 +283,7 @@ vi.mock("../../../plugins/plugin-metadata-snapshot.js", () => ({
isPluginMetadataSnapshotCompatible: () => true,
listPluginOriginsFromMetadataSnapshot: () => new Map(),
loadPluginMetadataSnapshot: () => emptyPluginMetadataSnapshot,
resolvePluginMetadataSnapshot: () => emptyPluginMetadataSnapshot,
}));
vi.mock("../../../trajectory/metadata.js", () => ({
@@ -14,11 +14,9 @@ import {
} from "./plugin-metadata-snapshot.js";
import { resetPluginRuntimeStateForTest } from "./runtime.js";
// Mock the persisted-registry loaders so a direct disk load is observable as a
// loader call. B2-core routes SITE A/B/C through the consult-first
// resolvePluginMetadataSnapshot: when a compatible current snapshot is
// registered, these loaders must not run; otherwise the fallback load keeps the
// pre-existing behavior.
// Mock the persisted-registry loaders so direct metadata loads are observable.
// Provider hot paths should reuse a compatible current snapshot and only fall
// back to the loader when no compatible lifecycle-owned snapshot exists.
const loadPluginRegistrySnapshotWithMetadata = vi.hoisted(() => vi.fn());
const loadPluginManifestRegistryForInstalledIndex = vi.hoisted(() => vi.fn());
@@ -139,7 +137,7 @@ describe("provider runtime consults the current plugin metadata snapshot", () =>
resetPluginRuntimeStateForTest();
});
describe("SITE A: isPluginProvidersLoadInFlight", () => {
describe("isPluginProvidersLoadInFlight", () => {
it("reuses a compatible current snapshot without a direct disk load", () => {
const config: OpenClawConfig = {};
registerCurrentSnapshot(config);
@@ -185,7 +183,7 @@ describe("provider runtime consults the current plugin metadata snapshot", () =>
});
});
describe("SITE B: resolvePluginProviders", () => {
describe("resolvePluginProviders", () => {
it("reuses a compatible current snapshot without a direct disk load", () => {
const config: OpenClawConfig = {};
registerCurrentSnapshot(config);
@@ -220,7 +218,7 @@ describe("provider runtime consults the current plugin metadata snapshot", () =>
});
});
describe("SITE C: resolveExternalAuthProfilesWithPlugins", () => {
describe("resolveExternalAuthProfilesWithPlugins", () => {
it("reuses a compatible current snapshot without a direct disk load", () => {
const config: OpenClawConfig = {};
registerCurrentSnapshot(config);
+20 -18
View File
@@ -159,6 +159,24 @@ function resolvePluginProviderLoadBase(
};
}
function resolveProviderMetadataLookup(params: {
config?: PluginLoadOptions["config"];
workspaceDir?: string;
env?: PluginLoadOptions["env"];
pluginMetadataSnapshot?: PluginMetadataRegistryView;
}) {
const env = params.env ?? process.env;
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir();
const snapshot =
params.pluginMetadataSnapshot ??
resolvePluginMetadataSnapshot({
config: params.config ?? {},
workspaceDir,
env,
});
return { env, workspaceDir, snapshot };
}
function resolveSetupProviderPluginLoadState(
params: Parameters<typeof resolvePluginProviders>[0],
base: ReturnType<typeof resolvePluginProviderLoadBase>,
@@ -290,15 +308,7 @@ function resolveRuntimeProviderPluginLoadState(
export function isPluginProvidersLoadInFlight(
params: Parameters<typeof resolvePluginProviders>[0],
): boolean {
const env = params.env ?? process.env;
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir();
const snapshot =
params.pluginMetadataSnapshot ??
resolvePluginMetadataSnapshot({
config: params.config ?? {},
workspaceDir,
env,
});
const { env, workspaceDir, snapshot } = resolveProviderMetadataLookup(params);
const base = resolvePluginProviderLoadBase({ ...params, workspaceDir, env }, snapshot);
const loadState =
params.mode === "setup"
@@ -327,15 +337,7 @@ export function resolvePluginProviders(params: {
includeUntrustedWorkspacePlugins?: boolean;
pluginMetadataSnapshot?: PluginMetadataRegistryView;
}): ProviderPlugin[] {
const env = params.env ?? process.env;
const workspaceDir = params.workspaceDir ?? getActivePluginRegistryWorkspaceDir();
const snapshot =
params.pluginMetadataSnapshot ??
resolvePluginMetadataSnapshot({
config: params.config ?? {},
workspaceDir,
env,
});
const { env, workspaceDir, snapshot } = resolveProviderMetadataLookup(params);
const base = resolvePluginProviderLoadBase({ ...params, workspaceDir, env }, snapshot);
if (params.mode === "setup") {
const loadState = resolveSetupProviderPluginLoadState(params, base, snapshot);