Skip to content

Commit 1426112

Browse files
committed
fix: finalize memory slot warning
1 parent 0204c52 commit 1426112

3 files changed

Lines changed: 89 additions & 7 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ Docs: https://docs.openclaw.ai
9696
- Voice calls: persist rejected inbound-call replay keys so duplicate carrier webhook retries stay ignored after a Gateway restart.
9797
- Config/doctor: copy fallback-enabled channel `allowFrom` entries into explicit `groupAllowFrom` allowlists during `openclaw doctor --fix`, preserving current group access without adding runtime fallback-transition flags.
9898
- Config/doctor: replace source-only official Brave and Slack plugin installs from trusted catalog metadata during `openclaw doctor --fix`, unblocking externalized stock plugin recovery after upgrade. (#82425) Thanks @joshavant.
99+
- Config/memory: warn instead of rejecting configs that select the official external `memory-lancedb` slot before the plugin is installed, with an explicit no-persistent-memory startup warning and install hint. Fixes #82428. (#82438) Thanks @giodl73-repo.
99100
- Agents/bootstrap: ignore stale completed root `BOOTSTRAP.md` context after workspace setup cleanup fails, preventing channel agent turns from treating it as a directory. (#82463) Thanks @joshavant.
100101
- Update/doctor: re-enable the Codex plugin during `openclaw doctor --fix` when configured OpenAI agent models require the Codex runtime, preventing upgraded configs from failing with an unregistered Codex harness. Fixes #82368. (#82502) Thanks @joshavant.
101102
- Configure: show one OpenAI provider entry with ChatGPT/Codex sign-in and API key choices, and keep browsed Codex models in the saved `/model` picker allowlist.

src/config/config.plugin-validation.test.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,78 @@ describe("config plugin validation", () => {
350350
},
351351
);
352352

353+
expect(res.ok).toBe(true);
354+
const slotMessage =
355+
"plugin not installed: memory-lancedb — gateway will run without persistent memory until installed; install the official external plugin with: openclaw plugins install @openclaw/memory-lancedb";
356+
const entryMessage =
357+
"plugin not installed: memory-lancedb — install the official external plugin with: openclaw plugins install @openclaw/memory-lancedb";
358+
expectPathMessage(res.warnings, "plugins.slots.memory", slotMessage);
359+
expectPathMessage(res.warnings, "plugins.entries.memory-lancedb", entryMessage);
360+
});
361+
362+
it("keeps no-persistent-memory wording scoped to the selected missing memory slot", () => {
363+
const res = validateConfigObjectWithPlugins(
364+
{
365+
agents: { list: [{ id: "pi" }] },
366+
plugins: {
367+
slots: { memory: "none" },
368+
entries: { "memory-lancedb": { enabled: true } },
369+
allow: ["memory-lancedb"],
370+
},
371+
},
372+
{
373+
env: suiteEnv(),
374+
pluginMetadataSnapshot: {
375+
manifestRegistry: {
376+
plugins: [],
377+
diagnostics: [],
378+
},
379+
},
380+
},
381+
);
382+
353383
expect(res.ok).toBe(true);
354384
const message =
355385
"plugin not installed: memory-lancedb — install the official external plugin with: openclaw plugins install @openclaw/memory-lancedb";
356-
expectPathMessage(res.warnings, "plugins.slots.memory", message);
357386
expectPathMessage(res.warnings, "plugins.entries.memory-lancedb", message);
387+
expectPathMessage(res.warnings, "plugins.allow", message);
388+
expect(
389+
(res.warnings ?? []).some((warning) =>
390+
warning.message.includes("gateway will run without persistent memory"),
391+
),
392+
).toBe(false);
393+
});
394+
395+
it("keeps official external non-memory plugins fatal in the memory slot", () => {
396+
const res = validateConfigObjectWithPlugins(
397+
{
398+
agents: { list: [{ id: "pi" }] },
399+
plugins: {
400+
slots: { memory: "brave" },
401+
entries: { brave: { enabled: true } },
402+
},
403+
},
404+
{
405+
env: suiteEnv(),
406+
pluginMetadataSnapshot: {
407+
manifestRegistry: {
408+
plugins: [],
409+
diagnostics: [],
410+
},
411+
},
412+
},
413+
);
414+
415+
expect(res.ok).toBe(false);
416+
if (res.ok) {
417+
return;
418+
}
419+
expectPathMessage(res.issues, "plugins.slots.memory", "plugin not found: brave");
420+
expectPathMessage(
421+
res.warnings,
422+
"plugins.entries.brave",
423+
"plugin not installed: brave — install the official external plugin with: openclaw plugins install @openclaw/brave-plugin",
424+
);
358425
});
359426

360427
it("keeps blocked official external memory slot plugins fatal", () => {

src/config/validation.ts

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ function formatConfigPath(segments: readonly ConfigPathSegment[]): string {
9898
return segments.join(".");
9999
}
100100

101-
function formatMissingOfficialExternalPluginWarning(pluginId: string): string | null {
101+
function formatMissingOfficialExternalPluginWarning(
102+
pluginId: string,
103+
opts?: { selectedMissingMemorySlot?: boolean },
104+
): string | null {
102105
const catalogEntry = getOfficialExternalPluginCatalogEntry(pluginId);
103106
if (!catalogEntry) {
104107
return null;
@@ -111,6 +114,9 @@ function formatMissingOfficialExternalPluginWarning(pluginId: string): string |
111114
if (!installSpec) {
112115
return null;
113116
}
117+
if (pluginId === "memory-lancedb" && opts?.selectedMissingMemorySlot) {
118+
return `plugin not installed: ${pluginId} — gateway will run without persistent memory until installed; install the official external plugin with: openclaw plugins install ${installSpec}`;
119+
}
114120
return `plugin not installed: ${pluginId} — install the official external plugin with: openclaw plugins install ${installSpec}`;
115121
}
116122

@@ -1455,7 +1461,7 @@ function validateConfigObjectWithPluginsBase(
14551461
const pushMissingPluginIssue = (
14561462
path: string,
14571463
pluginId: string,
1458-
opts?: { warnOnly?: boolean; officialInstallHint?: boolean },
1464+
opts?: { warnOnly?: boolean; officialInstallHint?: boolean; missingMessage?: string | null },
14591465
) => {
14601466
if (LEGACY_REMOVED_PLUGIN_IDS.has(pluginId)) {
14611467
warnings.push({
@@ -1476,7 +1482,8 @@ function validateConfigObjectWithPluginsBase(
14761482
return;
14771483
}
14781484
if (opts?.warnOnly && opts.officialInstallHint !== false) {
1479-
const externalInstallWarning = formatMissingOfficialExternalPluginWarning(pluginId);
1485+
const externalInstallWarning =
1486+
opts.missingMessage ?? formatMissingOfficialExternalPluginWarning(pluginId);
14801487
if (externalInstallWarning) {
14811488
warnings.push({
14821489
path,
@@ -1557,11 +1564,18 @@ function validateConfigObjectWithPluginsBase(
15571564
memorySlot.trim() &&
15581565
!knownIds.has(memorySlot)
15591566
) {
1560-
const isMissingOfficialExternalMemorySlot = Boolean(
1561-
formatMissingOfficialExternalPluginWarning(memorySlot),
1562-
);
1567+
const isMissingOfficialExternalMemorySlot =
1568+
memorySlot === "memory-lancedb" &&
1569+
Boolean(
1570+
formatMissingOfficialExternalPluginWarning(memorySlot, {
1571+
selectedMissingMemorySlot: true,
1572+
}),
1573+
);
15631574
pushMissingPluginIssue("plugins.slots.memory", memorySlot, {
15641575
warnOnly: isMissingOfficialExternalMemorySlot && !findBlockedPluginDiagnostic(memorySlot),
1576+
missingMessage: formatMissingOfficialExternalPluginWarning(memorySlot, {
1577+
selectedMissingMemorySlot: true,
1578+
}),
15651579
});
15661580
}
15671581

0 commit comments

Comments
 (0)