fix(plugins): preserve memory capability across snapshot plugin loads#69219
Conversation
Greptile SummaryThis PR fixes a memory capability wipe caused by missing Confidence Score: 5/5Safe to merge — targeted one-line fix with a red-green verified regression test covering the exact failure mode. The change is minimal and precise: it adds the missing No files require special attention. Reviews (1): Last reviewed commit: "fix(plugins): preserve memory capability..." | Re-trigger Greptile |
1322334 to
7791bb9
Compare
The loader per-plugin snapshot/rollback dance captured
`previousMemoryCorpusSupplements`, `previousMemoryPromptBuilder`, and
related memory-state fields, but never captured
`previousMemoryCapability`. Both restore sites (the post-register
`if (!shouldActivate)` branch and the register `catch` branch) called
`restoreMemoryPluginState({...})` without a `capability` field.
Because `restoreMemoryPluginState` treats `state.capability ? {...} : void 0`,
omitting the field was effectively a wipe. Any non-activating load
(e.g. `resolvePluginWebSearchProviders` calling
`loadOpenClawPlugins({ activate: false })`) would iterate every plugin,
re-register, then restore to the pre-snapshot state without
`capability` — clearing whatever capability the memory plugin had
registered. In practice this caused `listActiveMemoryPublicArtifacts`
to return `[]` and broke `wiki.bridge.import` after the first
non-activating load.
Fix: capture `previousMemoryCapability = getMemoryCapabilityRegistration()`
alongside the other previous-* snapshots and include
`capability: previousMemoryCapability` in both `restoreMemoryPluginState`
call sites. The cached-load site already did this correctly.
Adds a regression test that asserts the memory capability survives an
activate:false snapshot load after a prior active load.
7791bb9 to
e2ff6b6
Compare
|
Landed via temp rebase onto main.
Thanks @zeroaltitude! |
Problem
The plugin loader's per-plugin snapshot/rollback dance captures several
previousMemory*values to restore after a non-activating load — butpreviousMemoryCapabilitywas missing. Both restore sites (theif (!shouldActivate)branch post-register, and the register-catchbranch) calledrestoreMemoryPluginState({...})without acapabilityfield.Because
restoreMemoryPluginStatetreats the field as authoritative (state.capability ? {...} : void 0), omitting the field was effectively a wipe.Symptom
Any non-activating load — for example
resolvePluginWebSearchProviderscallingloadOpenClawPlugins({ activate: false })— iterates every plugin, re-registers, then restores to the pre-snapshot state withoutcapability. This clears whatever capability the memory plugin had registered on the live load.In practice:
listActiveMemoryPublicArtifactsreturns[]andwiki.bridge.importreturns 0 artifacts after the first non-activating load, even though memory plugins appearloadedand theirregister()runs correctly.Fix
previousMemoryCapability = getMemoryCapabilityRegistration()alongside the other per-plugin snapshotscapability: previousMemoryCapabilityin bothrestoreMemoryPluginStatecall sitesThe cached-load site (around line 1453 in current main) already did this correctly — it's the two per-plugin sites inside the iteration that were the outliers.
Testing
Added
preserves previously registered memory capability across activate:false snapshot loadsinsrc/plugins/loader.test.ts:publicArtifactscapabilitylistActiveMemoryPublicArtifactsreturns the artifactloadOpenClawPlugins({ activate: false })(same shape as the real secondary loaders)Red-green verified locally: without the fix the second
listActiveMemoryPublicArtifactsreturns[]; with the fix it returns the expected artifact. All 94 tests inloader.test.tspass.Discovery context
Found while debugging
wiki.bridge.importreturning 0 artifacts withmemory-coreinstalled and thevaultMode: "bridge"config. The misleading clue:getMemoryCapabilityRegistration()immediately afterregisterMemoryCapability()always returned the right value, because the wipe happened on a later iteration of the rollback loop (including repeated calls fromresolvePluginWebSearchProviders).