mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-17 00:20:43 +00:00
fix: cache capability provider manifest ids
This commit is contained in:
@@ -502,6 +502,27 @@ describe("resolvePluginCapabilityProviders", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("reuses manifest-derived capability plugin ids for the same config snapshot", () => {
|
||||
const { cfg, enablementCompat } = createCompatChainConfig();
|
||||
setBundledCapabilityFixture("mediaUnderstandingProviders");
|
||||
mocks.withBundledPluginEnablementCompat.mockReturnValue(enablementCompat);
|
||||
mocks.withBundledPluginVitestCompat.mockReturnValue(enablementCompat);
|
||||
|
||||
expectNoResolvedCapabilityProviders(
|
||||
resolvePluginCapabilityProviders({ key: "mediaUnderstandingProviders", cfg }),
|
||||
);
|
||||
expectNoResolvedCapabilityProviders(
|
||||
resolvePluginCapabilityProviders({ key: "mediaUnderstandingProviders", cfg }),
|
||||
);
|
||||
|
||||
expect(mocks.loadPluginManifestRegistry).toHaveBeenCalledOnce();
|
||||
expect(mocks.withBundledPluginAllowlistCompat).toHaveBeenCalledTimes(2);
|
||||
expect(mocks.withBundledPluginAllowlistCompat).toHaveBeenCalledWith({
|
||||
config: cfg,
|
||||
pluginIds: ["openai"],
|
||||
});
|
||||
});
|
||||
|
||||
it("reuses a compatible active registry even when the capability list is empty", () => {
|
||||
const active = createEmptyPluginRegistry();
|
||||
mocks.resolveRuntimePluginRegistry.mockReturnValue(active);
|
||||
|
||||
@@ -4,6 +4,11 @@ import {
|
||||
withBundledPluginEnablementCompat,
|
||||
withBundledPluginVitestCompat,
|
||||
} from "./bundled-compat.js";
|
||||
import {
|
||||
buildPluginSnapshotCacheEnvKey,
|
||||
resolvePluginSnapshotCacheTtlMs,
|
||||
shouldUsePluginSnapshotCache,
|
||||
} from "./cache-controls.js";
|
||||
import { hasExplicitPluginConfig } from "./config-policy.js";
|
||||
import { resolveRuntimePluginRegistry } from "./loader.js";
|
||||
import { loadPluginManifestRegistryForPluginRegistry } from "./plugin-registry.js";
|
||||
@@ -32,6 +37,11 @@ type CapabilityContractKey =
|
||||
type CapabilityProviderForKey<K extends CapabilityProviderRegistryKey> =
|
||||
PluginRegistry[K][number] extends { provider: infer T } ? T : never;
|
||||
|
||||
type CapabilityProviderPluginIdCacheEntry = {
|
||||
expiresAt: number;
|
||||
pluginIds: string[];
|
||||
};
|
||||
|
||||
const CAPABILITY_CONTRACT_KEY: Record<CapabilityProviderRegistryKey, CapabilityContractKey> = {
|
||||
memoryEmbeddingProviders: "memoryEmbeddingProviders",
|
||||
speechProviders: "speechProviders",
|
||||
@@ -43,15 +53,86 @@ const CAPABILITY_CONTRACT_KEY: Record<CapabilityProviderRegistryKey, CapabilityC
|
||||
musicGenerationProviders: "musicGenerationProviders",
|
||||
};
|
||||
|
||||
const capabilityProviderPluginIdCache = new WeakMap<
|
||||
OpenClawConfig,
|
||||
WeakMap<NodeJS.ProcessEnv, Map<string, CapabilityProviderPluginIdCacheEntry>>
|
||||
>();
|
||||
|
||||
function buildCapabilityProviderPluginIdCacheKey(params: {
|
||||
key: CapabilityProviderRegistryKey;
|
||||
env: NodeJS.ProcessEnv;
|
||||
providerId?: string;
|
||||
}): string {
|
||||
return JSON.stringify({
|
||||
key: params.key,
|
||||
providerId: params.providerId ?? "",
|
||||
env: buildPluginSnapshotCacheEnvKey(params.env),
|
||||
});
|
||||
}
|
||||
|
||||
function getCachedCapabilityProviderPluginIds(params: {
|
||||
key: CapabilityProviderRegistryKey;
|
||||
cfg?: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
providerId?: string;
|
||||
}): string[] | undefined {
|
||||
if (!params.cfg || !shouldUsePluginSnapshotCache(params.env)) {
|
||||
return undefined;
|
||||
}
|
||||
const envCache = capabilityProviderPluginIdCache.get(params.cfg)?.get(params.env);
|
||||
const cached = envCache?.get(buildCapabilityProviderPluginIdCacheKey(params));
|
||||
if (!cached || cached.expiresAt <= Date.now()) {
|
||||
return undefined;
|
||||
}
|
||||
return [...cached.pluginIds];
|
||||
}
|
||||
|
||||
function memoizeCapabilityProviderPluginIds(params: {
|
||||
key: CapabilityProviderRegistryKey;
|
||||
cfg?: OpenClawConfig;
|
||||
env: NodeJS.ProcessEnv;
|
||||
providerId?: string;
|
||||
pluginIds: string[];
|
||||
}): void {
|
||||
if (!params.cfg || !shouldUsePluginSnapshotCache(params.env)) {
|
||||
return;
|
||||
}
|
||||
let configCache = capabilityProviderPluginIdCache.get(params.cfg);
|
||||
if (!configCache) {
|
||||
configCache = new WeakMap<
|
||||
NodeJS.ProcessEnv,
|
||||
Map<string, CapabilityProviderPluginIdCacheEntry>
|
||||
>();
|
||||
capabilityProviderPluginIdCache.set(params.cfg, configCache);
|
||||
}
|
||||
let envCache = configCache.get(params.env);
|
||||
if (!envCache) {
|
||||
envCache = new Map<string, CapabilityProviderPluginIdCacheEntry>();
|
||||
configCache.set(params.env, envCache);
|
||||
}
|
||||
envCache.set(buildCapabilityProviderPluginIdCacheKey(params), {
|
||||
expiresAt: Date.now() + resolvePluginSnapshotCacheTtlMs(params.env),
|
||||
pluginIds: [...params.pluginIds],
|
||||
});
|
||||
}
|
||||
|
||||
function resolveBundledCapabilityCompatPluginIds(params: {
|
||||
key: CapabilityProviderRegistryKey;
|
||||
cfg?: OpenClawConfig;
|
||||
providerId?: string;
|
||||
}): string[] {
|
||||
const env = process.env;
|
||||
const cached = getCachedCapabilityProviderPluginIds({
|
||||
...params,
|
||||
env,
|
||||
});
|
||||
if (cached) {
|
||||
return cached;
|
||||
}
|
||||
const contractKey = CAPABILITY_CONTRACT_KEY[params.key];
|
||||
return loadPluginManifestRegistryForPluginRegistry({
|
||||
const pluginIds = loadPluginManifestRegistryForPluginRegistry({
|
||||
config: params.cfg,
|
||||
env: process.env,
|
||||
env,
|
||||
includeDisabled: true,
|
||||
})
|
||||
.plugins.filter(
|
||||
@@ -62,6 +143,12 @@ function resolveBundledCapabilityCompatPluginIds(params: {
|
||||
)
|
||||
.map((plugin) => plugin.id)
|
||||
.toSorted((left, right) => left.localeCompare(right));
|
||||
memoizeCapabilityProviderPluginIds({
|
||||
...params,
|
||||
env,
|
||||
pluginIds,
|
||||
});
|
||||
return pluginIds;
|
||||
}
|
||||
|
||||
function resolveCapabilityProviderConfig(params: {
|
||||
|
||||
Reference in New Issue
Block a user