mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:40:44 +00:00
fix: load default memory plugin at startup
This commit is contained in:
@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Plugins/startup: load the default `memory-core` slot during Gateway startup when permitted so active-memory recall can call `memory_search` and `memory_get` without requiring an explicit `plugins.slots.memory` entry, while preserving `plugins.slots.memory: "none"`. Thanks @codex.
|
||||
- Plugins/CLI: prefer native require for compiled bundled plugin JavaScript before jiti so read-only config, status, device, and node commands avoid unnecessary transform overhead on slow hosts. Fixes #62842. Thanks @Effet.
|
||||
- Plugins/compat: add missing dated compatibility records for legacy extension-api, memory registration, provider hook/type aliases, runtime aliases, channel SDK helpers, and approval/test utility shims. Thanks @vincentkoc.
|
||||
- Plugins/CLI: refresh the persisted registry after managed plugin files are removed so ClawHub uninstall cannot leave stale `plugins list` entries. Thanks @codex.
|
||||
|
||||
@@ -419,26 +419,26 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
enabledPluginIds: ["voice-call"],
|
||||
modelId: "demo-cli/demo-model",
|
||||
}),
|
||||
["demo-channel", "browser", "voice-call"],
|
||||
["demo-channel", "browser", "voice-call", "memory-core"],
|
||||
],
|
||||
[
|
||||
"keeps bundled startup sidecars with enabledByDefault at idle startup",
|
||||
{} as OpenClawConfig,
|
||||
["demo-channel", "browser"],
|
||||
["demo-channel", "browser", "memory-core"],
|
||||
],
|
||||
[
|
||||
"keeps provider plugins out of idle startup when only provider config references them",
|
||||
createStartupConfig({
|
||||
providerIds: ["demo-provider"],
|
||||
}),
|
||||
["demo-channel", "browser"],
|
||||
["demo-channel", "browser", "memory-core"],
|
||||
],
|
||||
[
|
||||
"includes explicitly enabled non-channel sidecars in startup scope",
|
||||
createStartupConfig({
|
||||
enabledPluginIds: ["demo-global-sidecar", "voice-call"],
|
||||
}),
|
||||
["demo-channel", "browser", "voice-call", "demo-global-sidecar"],
|
||||
["demo-channel", "browser", "voice-call", "memory-core", "demo-global-sidecar"],
|
||||
],
|
||||
[
|
||||
"keeps default-enabled startup sidecars when a restrictive allowlist permits them",
|
||||
@@ -453,7 +453,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
createStartupConfig({
|
||||
channelIds: ["demo-channel", "demo-other-channel"],
|
||||
}),
|
||||
["demo-channel", "demo-other-channel", "browser"],
|
||||
["demo-channel", "demo-other-channel", "browser", "memory-core"],
|
||||
],
|
||||
] as const)("%s", (_name, config, expected) => {
|
||||
expectStartupPluginIdsCase({ config, expected });
|
||||
@@ -501,7 +501,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
env: {
|
||||
DEMO_CHANNEL_ANYTHING: "1",
|
||||
} as NodeJS.ProcessEnv,
|
||||
expected: ["demo-channel", "browser"],
|
||||
expected: ["demo-channel", "browser", "memory-core"],
|
||||
});
|
||||
expect(
|
||||
resolveConfiguredDeferredChannelPluginIds({
|
||||
@@ -564,7 +564,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
env: {},
|
||||
expected: ["browser"],
|
||||
expected: ["browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -582,7 +582,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
env: {
|
||||
OPENCLAW_STATE_DIR: "/tmp/openclaw-with-persisted-demo-channel",
|
||||
} as NodeJS.ProcessEnv,
|
||||
expected: ["browser"],
|
||||
expected: ["browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -657,12 +657,22 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("includes the default memory slot plugin when the allowlist permits it", () => {
|
||||
expectStartupPluginIdsCase({
|
||||
config: createStartupConfig({
|
||||
allowPluginIds: ["browser", "memory-core"],
|
||||
noConfiguredChannels: true,
|
||||
}),
|
||||
expected: ["browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
it("does not include non-selected memory plugins only because they are enabled", () => {
|
||||
expectStartupPluginIdsCase({
|
||||
config: createStartupConfig({
|
||||
enabledPluginIds: ["memory-lancedb"],
|
||||
}),
|
||||
expected: ["demo-channel", "browser"],
|
||||
expected: ["demo-channel", "browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -672,7 +682,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
agentRuntimeId: "codex",
|
||||
enabledPluginIds: ["codex"],
|
||||
}),
|
||||
expected: ["demo-channel", "browser", "codex"],
|
||||
expected: ["demo-channel", "browser", "codex", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -682,7 +692,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
agentRuntimeIds: ["codex"],
|
||||
enabledPluginIds: ["codex"],
|
||||
}),
|
||||
expected: ["demo-channel", "browser", "codex"],
|
||||
expected: ["demo-channel", "browser", "codex", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -692,7 +702,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
enabledPluginIds: ["codex"],
|
||||
}),
|
||||
env: { OPENCLAW_AGENT_RUNTIME: "codex" },
|
||||
expected: ["demo-channel", "browser", "codex"],
|
||||
expected: ["demo-channel", "browser", "codex", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -702,7 +712,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
agentRuntimeId: "demo-cli",
|
||||
enabledPluginIds: ["demo-provider-plugin"],
|
||||
}),
|
||||
expected: ["demo-channel", "browser", "demo-provider-plugin"],
|
||||
expected: ["demo-channel", "browser", "demo-provider-plugin", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -715,7 +725,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
config: createStartupConfig({
|
||||
agentRuntimeId: runtime,
|
||||
}),
|
||||
expected: ["demo-channel", "browser", pluginId],
|
||||
expected: ["demo-channel", "browser", pluginId, "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -738,7 +748,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expected: ["demo-channel", "browser"],
|
||||
expected: ["demo-channel", "browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
|
||||
@@ -761,7 +771,7 @@ describe("resolveGatewayStartupPluginIds", () => {
|
||||
},
|
||||
},
|
||||
} as OpenClawConfig,
|
||||
expected: ["demo-channel", "browser"],
|
||||
expected: ["demo-channel", "browser", "memory-core"],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -65,21 +65,36 @@ function resolveGatewayStartupDreamingPluginIds(config: OpenClawConfig): Set<str
|
||||
return new Set([DEFAULT_MEMORY_DREAMING_PLUGIN_ID, resolveMemoryDreamingPluginId(config)]);
|
||||
}
|
||||
|
||||
function resolveExplicitMemorySlotStartupPluginId(
|
||||
config: OpenClawConfig,
|
||||
normalizePluginId: (pluginId: string) => string,
|
||||
): string | undefined {
|
||||
const configuredSlot = config.plugins?.slots?.memory?.trim();
|
||||
if (!configuredSlot || configuredSlot.toLowerCase() === "none") {
|
||||
function resolveMemorySlotStartupPluginId(params: {
|
||||
activationSourceConfig: OpenClawConfig;
|
||||
activationSourcePlugins: ReturnType<typeof normalizePluginsConfigWithRegistry>;
|
||||
normalizePluginId: (pluginId: string) => string;
|
||||
}): string | undefined {
|
||||
const { activationSourceConfig, activationSourcePlugins, normalizePluginId } = params;
|
||||
const configuredSlot = activationSourceConfig.plugins?.slots?.memory?.trim();
|
||||
if (configuredSlot?.toLowerCase() === "none") {
|
||||
return undefined;
|
||||
}
|
||||
if (!configuredSlot) {
|
||||
const defaultSlot = activationSourcePlugins.slots.memory;
|
||||
if (typeof defaultSlot !== "string") {
|
||||
return undefined;
|
||||
}
|
||||
if (
|
||||
activationSourcePlugins.allow.length > 0 &&
|
||||
!activationSourcePlugins.allow.includes(defaultSlot)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return defaultSlot;
|
||||
}
|
||||
return normalizePluginId(configuredSlot);
|
||||
}
|
||||
|
||||
function shouldConsiderForGatewayStartup(params: {
|
||||
plugin: InstalledPluginIndexRecord;
|
||||
startupDreamingPluginIds: ReadonlySet<string>;
|
||||
explicitMemorySlotStartupPluginId?: string;
|
||||
memorySlotStartupPluginId?: string;
|
||||
}): boolean {
|
||||
if (isGatewayStartupSidecar(params.plugin)) {
|
||||
return true;
|
||||
@@ -90,7 +105,7 @@ function shouldConsiderForGatewayStartup(params: {
|
||||
if (params.startupDreamingPluginIds.has(params.plugin.pluginId)) {
|
||||
return true;
|
||||
}
|
||||
return params.explicitMemorySlotStartupPluginId === params.plugin.pluginId;
|
||||
return params.memorySlotStartupPluginId === params.plugin.pluginId;
|
||||
}
|
||||
|
||||
function hasConfiguredStartupChannel(params: {
|
||||
@@ -246,18 +261,23 @@ export function resolveGatewayStartupPluginIds(params: {
|
||||
// not the auto-enabled effective snapshot, or configured-only channels can be
|
||||
// misclassified as explicit enablement.
|
||||
const activationSourceConfig = params.activationSourceConfig ?? params.config;
|
||||
const activationSourcePlugins = normalizePluginsConfigWithRegistry(
|
||||
activationSourceConfig.plugins,
|
||||
index,
|
||||
);
|
||||
const activationSource = {
|
||||
plugins: normalizePluginsConfigWithRegistry(activationSourceConfig.plugins, index),
|
||||
plugins: activationSourcePlugins,
|
||||
rootConfig: activationSourceConfig,
|
||||
};
|
||||
const requiredAgentHarnessRuntimes = new Set(
|
||||
collectConfiguredAgentHarnessRuntimes(activationSourceConfig, params.env),
|
||||
);
|
||||
const startupDreamingPluginIds = resolveGatewayStartupDreamingPluginIds(params.config);
|
||||
const explicitMemorySlotStartupPluginId = resolveExplicitMemorySlotStartupPluginId(
|
||||
const memorySlotStartupPluginId = resolveMemorySlotStartupPluginId({
|
||||
activationSourceConfig,
|
||||
createPluginRegistryIdNormalizer(index),
|
||||
);
|
||||
activationSourcePlugins,
|
||||
normalizePluginId: createPluginRegistryIdNormalizer(index),
|
||||
});
|
||||
return index.plugins
|
||||
.filter((plugin) => {
|
||||
if (hasConfiguredStartupChannel({ plugin, manifestRegistry, configuredChannelIds })) {
|
||||
@@ -286,7 +306,7 @@ export function resolveGatewayStartupPluginIds(params: {
|
||||
!shouldConsiderForGatewayStartup({
|
||||
plugin,
|
||||
startupDreamingPluginIds,
|
||||
explicitMemorySlotStartupPluginId,
|
||||
memorySlotStartupPluginId,
|
||||
})
|
||||
) {
|
||||
return false;
|
||||
|
||||
@@ -65,14 +65,14 @@ describe("resolveManifestDeclaredWebProviderCandidatePluginIds", () => {
|
||||
expect(mocks.loadPluginManifestRegistryForInstalledIndex).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("keeps runtime fallback for scoped plugins with no declared web candidates", () => {
|
||||
it("keeps scoped plugins with no declared web candidates scoped-empty", () => {
|
||||
expect(
|
||||
resolveManifestDeclaredWebProviderCandidatePluginIds({
|
||||
contract: "webSearchProviders",
|
||||
configKey: "webSearch",
|
||||
onlyPluginIds: ["missing-plugin"],
|
||||
}),
|
||||
).toBeUndefined();
|
||||
).toEqual([]);
|
||||
expect(mocks.loadPluginManifestRegistryForInstalledIndex).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
pluginIds: ["missing-plugin"],
|
||||
@@ -80,6 +80,29 @@ describe("resolveManifestDeclaredWebProviderCandidatePluginIds", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("keeps origin filters with no declared web candidates scoped-empty", () => {
|
||||
mocks.loadPluginManifestRegistryForInstalledIndex.mockReturnValue({
|
||||
plugins: [
|
||||
{
|
||||
id: "workspace-tool",
|
||||
origin: "workspace",
|
||||
configSchema: {
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
],
|
||||
diagnostics: [],
|
||||
});
|
||||
|
||||
expect(
|
||||
resolveManifestDeclaredWebProviderCandidatePluginIds({
|
||||
contract: "webSearchProviders",
|
||||
configKey: "webSearch",
|
||||
origin: "bundled",
|
||||
}),
|
||||
).toEqual([]);
|
||||
});
|
||||
|
||||
it("derives provider candidates from a single manifest-registry read", () => {
|
||||
expect(
|
||||
resolveManifestDeclaredWebProviderCandidatePluginIds({
|
||||
|
||||
@@ -105,6 +105,9 @@ export function resolveManifestDeclaredWebProviderCandidatePluginIds(params: {
|
||||
if (ids.length > 0) {
|
||||
return ids;
|
||||
}
|
||||
if (params.origin || scopedPluginIds !== undefined) {
|
||||
return [];
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user