fix(plugins): isolate full registry cache

This commit is contained in:
Ayaan Zaidi
2026-05-02 08:48:09 +05:30
parent 02d7ad4820
commit b4fd70bc48
2 changed files with 68 additions and 21 deletions

View File

@@ -1,5 +1,10 @@
import { afterEach, describe, expect, it } from "vitest";
import { __testing, clearPluginLoaderCache, resolveRuntimePluginRegistry } from "./loader.js";
import {
__testing,
clearPluginLoaderCache,
loadOpenClawPlugins,
resolveRuntimePluginRegistry,
} from "./loader.js";
import { resetPluginLoaderTestStateForTest } from "./loader.test-fixtures.js";
import {
getMemoryEmbeddingProvider,
@@ -392,6 +397,28 @@ describe("resolveRuntimePluginRegistry", () => {
expect(scopedEmpty).not.toBe(registry);
expect(scopedEmpty?.plugins).toEqual([]);
});
it("keeps the full workspace registry warm when scoped cron registries churn", () => {
__testing.setMaxPluginRegistryCacheEntriesForTest(2);
try {
const loadOptions = {
config: {
plugins: {
allow: ["alpha", "bravo", "charlie"],
},
},
workspaceDir: "/tmp/workspace-a",
};
const fullRegistry = loadOpenClawPlugins(loadOptions);
loadOpenClawPlugins({ ...loadOptions, onlyPluginIds: ["alpha"] });
loadOpenClawPlugins({ ...loadOptions, onlyPluginIds: ["bravo"] });
expect(resolveRuntimePluginRegistry(loadOptions)).toBe(fullRegistry);
} finally {
__testing.setMaxPluginRegistryCacheEntriesForTest();
}
});
});
describe("clearPluginLoaderCache", () => {

View File

@@ -249,6 +249,9 @@ const MAX_PLUGIN_REGISTRY_CACHE_ENTRIES = 128;
const pluginLoaderCacheState = new PluginLoaderCacheState<CachedPluginState>(
MAX_PLUGIN_REGISTRY_CACHE_ENTRIES,
);
const fullWorkspacePluginLoaderCacheState = new PluginLoaderCacheState<CachedPluginState>(
MAX_PLUGIN_REGISTRY_CACHE_ENTRIES,
);
const LAZY_RUNTIME_REFLECTION_KEYS = [
"version",
"config",
@@ -281,6 +284,7 @@ function createPluginCandidatesFromManifestRegistry(
export function clearPluginLoaderCache(): void {
pluginLoaderCacheState.clear();
fullWorkspacePluginLoaderCacheState.clear();
clearAgentHarnesses();
clearPluginCommands();
clearCompactionProviders();
@@ -525,15 +529,27 @@ export const __testing = {
},
setMaxPluginRegistryCacheEntriesForTest(value?: number) {
pluginLoaderCacheState.setMaxEntriesForTest(value);
fullWorkspacePluginLoaderCacheState.setMaxEntriesForTest(value);
},
};
function getCachedPluginRegistry(cacheKey: string): CachedPluginState | undefined {
return pluginLoaderCacheState.get(cacheKey);
function getPluginRegistryCache(onlyPluginIds?: string[]) {
return onlyPluginIds ? pluginLoaderCacheState : fullWorkspacePluginLoaderCacheState;
}
function setCachedPluginRegistry(cacheKey: string, state: CachedPluginState): void {
pluginLoaderCacheState.set(cacheKey, state);
function getCachedPluginRegistry(
cacheKey: string,
onlyPluginIds?: string[],
): CachedPluginState | undefined {
return getPluginRegistryCache(onlyPluginIds).get(cacheKey);
}
function setCachedPluginRegistry(
cacheKey: string,
state: CachedPluginState,
onlyPluginIds?: string[],
): void {
getPluginRegistryCache(onlyPluginIds).set(cacheKey, state);
}
function resolveBundledPackageRootForCache(stockRoot?: string): string | undefined {
@@ -1225,7 +1241,7 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
const cacheEnabled = options.cache !== false;
if (cacheEnabled) {
const cached = getCachedPluginRegistry(cacheKey);
const cached = getCachedPluginRegistry(cacheKey, onlyPluginIds);
if (cached) {
if (shouldActivate) {
restoreRegisteredAgentHarnesses(cached.agentHarnesses);
@@ -2142,21 +2158,25 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
}
if (cacheEnabled) {
setCachedPluginRegistry(cacheKey, {
commands: listRegisteredPluginCommands(),
detachedTaskRuntimeRegistration: getDetachedTaskLifecycleRuntimeRegistration(),
interactiveHandlers: listPluginInteractiveHandlers(),
memoryCapability: getMemoryCapabilityRegistration(),
memoryCorpusSupplements: listMemoryCorpusSupplements(),
registry,
agentHarnesses: listRegisteredAgentHarnesses(),
compactionProviders: listRegisteredCompactionProviders(),
memoryEmbeddingProviders: listRegisteredMemoryEmbeddingProviders(),
memoryFlushPlanResolver: getMemoryFlushPlanResolver(),
memoryPromptBuilder: getMemoryPromptSectionBuilder(),
memoryPromptSupplements: listMemoryPromptSupplements(),
memoryRuntime: getMemoryRuntime(),
});
setCachedPluginRegistry(
cacheKey,
{
commands: listRegisteredPluginCommands(),
detachedTaskRuntimeRegistration: getDetachedTaskLifecycleRuntimeRegistration(),
interactiveHandlers: listPluginInteractiveHandlers(),
memoryCapability: getMemoryCapabilityRegistration(),
memoryCorpusSupplements: listMemoryCorpusSupplements(),
registry,
agentHarnesses: listRegisteredAgentHarnesses(),
compactionProviders: listRegisteredCompactionProviders(),
memoryEmbeddingProviders: listRegisteredMemoryEmbeddingProviders(),
memoryFlushPlanResolver: getMemoryFlushPlanResolver(),
memoryPromptBuilder: getMemoryPromptSectionBuilder(),
memoryPromptSupplements: listMemoryPromptSupplements(),
memoryRuntime: getMemoryRuntime(),
},
onlyPluginIds,
);
}
if (shouldActivate) {
activatePluginRegistry(registry, cacheKey, runtimeSubagentMode, options.workspaceDir);