Skip to content

fix(memory): release memory_get/memory_search from OpenClaw memory-core - #3222

Merged
ikunkun-sys merged 1 commit into
mainfrom
fix/AGE-7144-openclaw-memory-tool-name-conflict
Sep 18, 2026
Merged

ikunkun-sys merged 1 commit into
mainfrom
fix/AGE-7144-openclaw-memory-tool-name-conflict

Conversation

@Forrest-ly

@Forrest-ly Forrest-ly commented Sep 10, 2026

Copy link
Copy Markdown
Collaborator

What

install.sh now runs openclaw plugins disable memory-core after installing the plugin, and uninstall.sh re-enables it — but only when install.sh is what disabled it.

Fixes #3218

Why the plugin's memory_get / memory_search were dropped

The issue report attributed the conflict to "built-in" memory_get / memory_search tools added in OpenClaw 2026.9.2. Those two names do appear in OpenClaw's core tool catalog (src/agents/tool-catalog.ts, sectionId: "memory", includeInOpenClawGroup: true), but the catalog is pure data — it drives profile allowlists, group expansion and Control-UI metadata, not tool construction. The tools themselves come from the bundled memory-core plugin (dist/extensions/memory-core/openclaw.plugin.json, contracts.tools: ["intent", "memory_get", "memory_search"]).

So this is a slot-exclusivity gap, not a new core tool:

  1. plugins.slots.memory = "memory-anolisa" does disable memory-core for memory purposes — openclaw plugins list reports it disabled.
  2. But the loader exempts it from that decision when it is the authorized dreaming sidecar (resolveAuthorizedDreamingSidecar / resolveDreamingSidecarEngineId: any pinned slot other than memory-core + dreaming.enabled, which defaults to true). openclaw plugins doctor says exactly this: memory-core: memory plugin not selected for the memory slot; skipping its indexing runtime and recall registration (consolidation lifecycle preserved).
  3. memory-core therefore still registers memory_get / memory_search, and OpenClaw's plugin tool registry is first-wins — it logs plugin tool name conflict (memory-anolisa): memory_get and continues, so this plugin's tools never reach the agent.
  4. Calls bind to memory-core's reader. With no corpus argument, executeMemoryReadResult only tries the workspace builtin read and never consults corpus supplements; that read throws for a ~/.anolisa/memory path, and the catch returns {path, text: "", disabled: true, error} — the reported symptom.

Reproduced and verified on real OpenClaw 2026.9.2

Installed the built plugin into a scratch OPENCLAW_STATE_DIR and captured the tool array actually sent to the model (stub OpenAI-compatible endpoint), so the assertion is on the agent's real tool set rather than on a log line.

Before (slot pinned to memory-anolisa, stock install):

[plugins] plugin tool name conflict (memory-anolisa): memory_search
[plugins] plugin tool name conflict (memory-anolisa): memory_get
tools: 57 → intent memory_get memory_get_context memory_observe memory_search
memory_get description: "Safe exact excerpt read from MEMORY.md, USER.md, Markdown files recursively under memory/..."   ← memory-core's

After (install.sh from this PR):

no conflict lines
tools: 56 → memory_get memory_get_context memory_observe memory_search
memory_get description: "Read a memory file by path. Returns full UTF-8 content. Path is relative to the mount root."   ← this plugin's

All four contract tools now reach the agent, and memory_get is ours.

Full lifecycle on 2026.9.2:

step plugins.slots.memory plugins.entries.memory-core marker
install.sh memory-anolisa {enabled: false} written
install.sh again (upgrade) memory-anolisa {enabled: false} kept
uninstall.sh {} (host default = memory-core) {enabled: true} removed
uninstall.sh with no marker untouched untouched (false)

Also checked on the locally installed OpenClaw 2026.5.22: plugins disable exists there too and is idempotent (rc=0 on repeat, rc=1 only for an unknown plugin), so the step is safe on the older hosts the manifest still claims.

Design notes

  • Why disable rather than rename the tools (the issue's direction B): renaming would keep the host's memory_get bound to memory-core, so an agent calling memory_get — including the nightly's own repro prompt — would still get disabled: true. The contract names in openclaw.plugin.json also stay untouched, so nothing downstream of the contract changes.
  • Why a marker instead of probing the host: openclaw config get is not a reliable oracle — on a host whose openclaw.json fails validation it prints nothing on stdout and exits 1 (reproduced: OpenClaw rejects the meta key it wrote itself). Recording our own action is exact, and it makes uninstall.sh restore only what install.sh changed.
  • Why a failed disable is a WARNING, not a failure: the rest of the plugin (memory_observe, memory_get_context, auto-recall, auto-capture, the MCP transport) is unaffected, so failing the whole install would be worse. The warning names openclaw plugins disable memory-core as the manual completion step.
  • Visible trade-off, documented in en/zh: while this plugin owns memory, openclaw memory subcommands and MEMORY.md dreaming/consolidation (both memory-core-provided) are unavailable. That is the same trade-off OpenClaw's own docs describe for a memory-slot plugin ("only one plugin owns the active memory slot at a time"), and it is what openclaw plugins uninstall already implies by resetting the slot to memory-core.

Worth reporting upstream: a slot plugin cannot take over memory_get / memory_search while the dreaming sidecar keeps memory-core's tools registered. Either the sidecar should not contribute tools, or the registry should let the slot owner win.

Tests

  • src/agent-memory/tests/test-openclaw-adapter-install.sh — extended (runs in CI via make test-openclaw-install):
    • every successful-install scenario now asserts exactly one plugins disable memory-core and a written marker; every failed-install scenario asserts neither (no host mutation after a failed install).
    • new: disable failure warns without failing the install, and writes no marker.
    • new: re-install keeps the disable and the marker.
    • new: uninstall.sh re-enables memory-core and clears the marker when marked, and leaves an unmarked memory-core alone.
    • Verified the assertions bite: swapping the disable for a no-op call fails with expected exactly one 'plugins disable memory-core', got 0.
    • Full suite green (48 PASS).
  • shellcheck -x clean on both scripts and the test.
  • bash scripts/docs-lint.sh and python3 scripts/docs-link-check.py green.
  • npm test in the plugin dir unchanged (126 pass) — no TypeScript touched.

Docs

docs/user-guide/{en,zh}/token-saving/agent-memory.md: one paragraph in the OpenClaw install section explaining the disable, the marker, the restore and the trade-offs, plus a troubleshooting row keyed on the two observable symptoms (disabled: true and the plugin tool name conflict log line).

@github-actions github-actions Bot added component:memory src/memory scope:documentation ./docs/|./*.md|./NOTICE labels Sep 10, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7c8396208e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/agent-memory/adapters/agent-memory/openclaw/scripts/install.sh
Comment thread src/agent-memory/adapters/agent-memory/openclaw/scripts/install.sh Outdated
Comment thread src/agent-memory/adapters/agent-memory/openclaw/scripts/uninstall.sh Outdated
@Forrest-ly

Copy link
Copy Markdown
Collaborator Author

All three review threads answered; head is now 9599000c (amended — the commit body described marker semantics the code did not actually implement, so it needed rewriting too).

Fixed here

  • P1 — marker claimed a transition it never verified (install.sh). plugins disable is idempotent and exits 0 either way, so the branch wrote the marker even when an operator had already disabled memory-core, and uninstall.sh then re-enabled it against their intent. install.sh now reads plugins.entries.memory-core.enabled via openclaw config get first and records the disable only when it caused the transition.
  • P2 — restore ignored OPENCLAW_BIN (uninstall.sh). Now resolves the CLI exactly as install.sh does for the availability check, plugins uninstall, and the plugins enable restore; both warnings name the value they tried, and the unresolvable branch keeps the marker.

src/agent-memory/tests/test-openclaw-adapter-install.sh grows from 44 to 59 scenarios: all eight false-ish renderings of the prior-state answer, the positive and unreadable cases, an end-to-end install→uninstall pair over a pre-disabled memory-core, and both OPENCLAW_BIN directions over a PATH with no openclaw on it. Reverting either script fails at the scenario pinning it. shellcheck -S warning clean on all three files; docs-lint.sh and docs-link-check.py pass.

Deferred — #3225

Resolving the deferred thread rather than leaving it open, since the repo's required_review_thread_resolution gate would otherwise block the two fixes above indefinitely; #3225 is the durable record and carries priority:p1. Flag it if you'd rather it stayed unresolved.

@ikunkun-sys ikunkun-sys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 AI review by codex-runner · Agent: Reviewer · 判定:REQUEST_CHANGES

  1. 变更概述
    审查 head:9599000c。安装脚本禁用 memory-core,释放两个同名工具;卸载时依据标记恢复,并补充 OPENCLAW_BIN 支持、测试及中英文说明。

  2. 正确性
    [P2] 卸载会覆盖用户后来选择的 memory 插件。
    uninstall.sh:80–82 仅凭标记调用 plugins enable memory-core,没有检查当前 slot。如果用户安装后切换至 memory-lancedb,再卸载 memory-anolisa,该调用会把 slot 强制切回 memory-core。通过只读调用本机 OpenClaw 的实际 slot 选择函数,已复现这一覆盖。现有测试只检查 enable 调用和标记,没有验证其他 slot 所有者是否保留。需要保护用户后续选择,并补充此生命周期用例。

  3. 风格与一致性
    中英文说明一致,脚本延续现有约定。bash -n、ShellCheck 和 git diff --check 均通过,未发现阻塞性风格问题。

  4. 风险
    上述覆盖会使用户切换后的记忆后端停止承担检索。另,adapter-manager 路径仍未修复,已明确记录于文档及 #3225。完整安装测试和 OpenClaw 2026.9.2 端到端验证未在本次只读环境重跑;作者测试报告与本地检查应分别看待。

  5. 合并建议
    建议修复卸载覆盖当前 slot 的问题后再合并。

结论:REQUEST_CHANGES

@Forrest-ly
Forrest-ly force-pushed the fix/AGE-7144-openclaw-memory-tool-name-conflict branch from 9599000 to 34eca98 Compare September 11, 2026 02:47
@Forrest-ly

Copy link
Copy Markdown
Collaborator Author

@ikunkun-sys Fixed in 34eca985 (amended onto the same single commit; head was 9599000c).

P2 — uninstall overwrote a memory plugin the operator chose later

Confirmed against the code before touching it. The restore was gated on RESTORE_MEMORY_CORE=1 — the marker alone — and then ran plugins enable memory-core unconditionally, which the code's own comment already said "also re-runs OpenClaw's exclusive slot selection". Two paths reached the overwrite, and both are now closed:

  1. plugins.slots.memory naming a third backend (memory-lancedb): the config cleanup only deletes entries whose value is memory-anolisa, so the slot survived cleanup — and plugins enable memory-core took it back anyway.
  2. plugins.slots.memory naming memory-anolisa: cleanup deletes that entry, the slot reads empty, and plugins enable memory-core filled it — again without asking who the operator wanted there.

uninstall.sh now reads plugins.slots.memory before plugins uninstall and before the config cleanup, because after them "this plugin owned it" and "nobody owns it" are indistinguishable and only the former is a slot this script may hand back. Source order: openclaw config get, then openclaw.json via jq/python3 for a CLI that cannot answer — the same file the cleanup already edits. The value goes through the same reduction install.sh applies to plugins.entries.memory-core.enabled (last line, lower-cased, trailing token after any =/:, quoting stripped), so one host's rendering classifies identically in both scripts.

Only a positively identified third owner blocks the restore. Empty / null / none / undefined / (empty) / memory-anolisa / memory-core all restore exactly as before — that is install.sh's asymmetry again: the slot is then either this plugin's (about to be vacated) or nobody's, and skipping the restore there strands the host with no memory backend at all, since plugins uninstall vacates the slot while config still says enabled=false, whereas an unwanted restore costs one plugins disable.

On a skip the script prints the owner, why it will not override it, and the command that does (openclaw plugins enable memory-core), and keeps the marker: it still records that memory-core is off because of an anolisa install, and dropping it would leave a host that later removes memory-lancedb with no memory backend and no record of why.

Testssrc/agent-memory/tests/test-openclaw-adapter-install.sh, 59 → 63 scenarios. The stub now answers config get plugins.slots.memory (TEST_MEMORY_SLOT, absent by default, so every pre-existing scenario keeps its prior behaviour):

  • the lifecycle you named, end to end and against a real openclaw.json rather than only a stubbed answer: install with memory-core enabled (marker written) → slot moved to memory-lancedb → uninstall. Asserts zero plugins enable memory-core, that plugins.slots.memory still reads memory-lancedb in the file afterwards, that memory-anolisa's own keys are still cleaned, that the marker survives, and that the skip is logged.
  • five third-party renderings (memory-lancedb, "memory-lancedb", MEMORY-LANCEDB, plugins.slots.memory=memory-lancedb, slots.memory: memory-lancedb) → no restore; ten restore-eligible ones (memory-anolisa, "memory-anolisa", memory-core, MEMORY-CORE, null, none, undefined, (empty), absent, empty string) → restore plus marker cleared.
  • the openclaw.json fallback with TEST_MEMORY_SLOT unset, i.e. a CLI that cannot answer.
  • no marker → the probe must not run at all.

Reverting uninstall.sh to 9599000c fails at slot hand-off: uninstall forced the memory slot back to memory-core, with the transcript showing Re-enabled memory-core — the overwrite you reproduced.

bash -n and shellcheck -s bash clean on both scripts and the test; git diff --check clean; docs-lint.sh and docs-link-check.py pass. The en/zh user guides gained a paragraph on the slot-ownership condition and how to override the skip. Still out of scope here: the anolisa adapter enable / adapter-manager path (#3225), unchanged since the last round.

中文摘要:已按 review 修复。uninstall.sh 现在在 plugins uninstall 和 config 清理之前读取 plugins.slots.memory 的归属(openclaw config get 优先,答不上来退回 openclaw.json),只有明确识别出第三方归属(如 memory-lancedb)时才跳过 plugins enable memory-core,并打印归属、跳过原因和手动恢复命令,同时保留 marker;slot 为空、属于本插件、属于 memory-core 或读不到时照旧恢复,因为那几种情况下跳过才会让宿主彻底没有 memory 后端。测试从 59 条增至 63 条,含你点名的 install → 切换 slot → uninstall 生命周期用例;把 uninstall.sh 回退到 9599000c 会在该用例失败。请重新 review。

@ikunkun-sys ikunkun-sys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

审查 head:34eca9853a954a2e8e5ac01ccc93dff8b02eb213

此前切换到 memory-lancedb 后卸载会覆盖 slot 的问题已修复,但仍有一个 P2:plugins.slots.memory="none" 被当成未配置状态,卸载会重新启用 memory-core,撤销用户明确禁用 memory 的选择。详见 inline finding。

本地验证:安装/卸载脚本测试、bash -nshellcheck -xgit diff --check 均通过;使用真实 OpenClaw 2026.5.27、隔离的临时配置与最小 memory 插件 fixture,运行当前 uninstall.sh,复现 slot 从 none 变为 memory-core、enabled 从 false 变为 true、恢复标记删除,退出码为 0。未重跑完整 gateway 工具调用端到端测试,也未独立重跑作者报告的 2026.9.2 E2E。

提交前刷新:head 未变,CI 已执行检查全部成功;mergeable=MERGEABLEmergeStateStatus=BLOCKEDreviewDecision=CHANGES_REQUESTED,原有 3 个 inline 线程均已解决。

结论:REQUEST_CHANGES

Comment thread src/agent-memory/adapters/agent-memory/openclaw/scripts/uninstall.sh Outdated
OpenClaw keeps its bundled memory-core plugin loaded as the memory
consolidation ("dreaming") sidecar even after another plugin takes the
memory slot, and memory-core owns the memory_get / memory_search tool
names. OpenClaw's plugin tool registry is first-wins and drops a plugin
tool whose normalized name is already taken, so memory-anolisa's
same-named tools never reach the agent: the gateway logs
"plugin tool name conflict (memory-anolisa): memory_get" and agent calls
bind to memory-core's workspace-file reader, which answers
disabled:true for every path under ~/.anolisa/memory, including files
that are on disk.

install.sh now runs `openclaw plugins disable memory-core` after the
plugin install, which releases both names. The memory slot already
routes memory traffic through this plugin, so nothing else changes for
the agent; the visible cost is that `openclaw memory` and MEMORY.md
dreaming come from memory-core and stay unavailable until uninstall.

`plugins disable` is idempotent and exits 0 either way, so its status
cannot separate a real transition from a no-op. install.sh therefore
reads plugins.entries.memory-core.enabled first and records the disable
in ${OPENCLAW_STATE_DIR}/.anolisa-memory-anolisa-disabled-memory-core
only when it caused that transition; uninstall.sh re-enables memory-core
from that record, so a memory-core an operator disabled themselves is
left untouched. An unreadable answer still records it, because the
failure modes are not symmetric: skipping the record strands the host
with no memory plugin at all after an uninstall, since `plugins
uninstall` resets the slot to its memory-core default while config still
says enabled=false, whereas an unwanted restore costs one `plugins
disable`. The install log names that case. uninstall.sh also resolves
the CLI through OPENCLAW_BIN the way install.sh does, so an
absolute-path override still gets its restore instead of a "CLI not
found" that leaves memory-core off.

The record is necessary but not sufficient. It says install.sh disabled
memory-core, not that this plugin still owns the memory slot, and
`plugins enable` re-runs OpenClaw's exclusive slot selection — so a
restore driven by the record alone dragged the slot back from a backend
the operator chose afterwards (`plugins enable memory-lancedb`, or an
explicit plugins.slots.memory edit), and the backend they picked then
silently stopped serving retrieval. uninstall.sh now reads
plugins.slots.memory before deciding, through `config get` with
openclaw.json as the fallback for a CLI that cannot answer, and skips
the restore when the operator has since made that slot their own —
naming the reason, the command that overrides the skip, and keeping the
marker, which still records that memory-core is off because of an
anolisa install. Choosing no memory plugin at all is such a choice:
OpenClaw documents plugins.slots.memory = "none" as an explicit "disable
memory plugins" value, not as an unset slot, and `plugins enable` answers
it with `Exclusive slot "memory" switched from "none" to "memory-core".`
— so classifying "none" as "nobody owns the slot" re-enabled a backend
the operator had deliberately turned off. Only a positively identified
operator choice blocks the restore now, a third-party owner or "none":
an empty, this-plugin-owned, memory-core-owned or unreadable slot
restores as before, because skipping there is what strands the host with
no memory backend at all.

A failed disable warns and still exits 0: memory_observe, auto-recall
and auto-capture keep working, and the warning names the exact command
that finishes the job.

Only install.sh performs this hand-off. `anolisa adapter enable
agent-memory openclaw` runs `plugins install` from the built-in OpenClaw
driver and never executes the adapter's install.sh, so the conflict
survives on that path; the docs now say which entry point hands off and
give the manual commands, and #3225 tracks carrying the hand-off in the
driver's receipt lifecycle.

Fixes #3218

Co-authored-by: multica-agent <github@multica.ai>
@Forrest-ly
Forrest-ly force-pushed the fix/AGE-7144-openclaw-memory-tool-name-conflict branch from 34eca98 to 57df63f Compare September 18, 2026 03:48
@Forrest-ly

Copy link
Copy Markdown
Collaborator Author

@ikunkun-sys 第 2 轮的 P2 已修复,请重新 review。

head:57df63ff16bff686c2a3ba76646bcfbaf663fccc(amend 进原 commit,PR 仍是单 commit)

plugins.slots.memory="none" 现在按 OpenClaw 文档语义当作运维显式禁用 memory,不再当作未配置:uninstall.sh 的 slot 归属判定为 none 单开一档,置 RESTORE_MEMORY_CORE=0、不执行 plugins enable memory-core、保留恢复标记,并在输出里说明原因与覆盖命令。被固化的测试期望同步改正,另外补了五种 none 渲染 + openclaw.json 回退两组断言,并做了变异验证(只回退脚本、保留新测试会 FAIL)。

真机复核(OpenClaw 2026.5.22 + 隔离 state dir + 最小插件 fixture):none 场景下 slot 保持 nonememory-core.enabled 保持 false、标记保留、退出码 0、无 Exclusive slot ... switched 输出;上一轮的 memory-lancedb 路径未回退。make test-openclaw-install 65 PASS,bash -n / shellcheck -x / git diff --check / docs-lint / link-check 均通过。en/zh 用户指南已同步。

细节见 inline thread 的答复。未重跑 gateway 工具调用 E2E,也未复跑 2026.9.2 E2E —— 与你的验证边界一致。

@ikunkun-sys ikunkun-sys left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

复审 head:57df63ff16bff686c2a3ba76646bcfbaf663fccc。未发现新的阻塞问题,上一轮 P2「卸载撤销 memory=none 的明确禁用选择」已修复。

已检查完整变更及相对上一轮的 range-diff。none 现在独立阻止恢复,保留 slot、memory-core 的禁用状态及恢复标记;CLI 读取与 openclaw.json 回退测试均覆盖该语义,双语说明同步。

本地验证:

  • make test-openclaw-install:65 PASS,退出码 0。
  • bash -nshellcheck -xgit diff --check:通过。
  • 真实 OpenClaw 2026.5.27 + 隔离临时配置 + 最小插件 fixture:确认 nonememory-lancedb 均被保留,memory-core 保持禁用且标记保留;卸载自身占用的 slot 时正常恢复 memory-core 并移除标记。
  • 相同 none 用例在旧 head 34eca9853 上仍复现覆盖,确认新版本消除了原问题。

验证边界:本地真实 CLI 验证止于卸载后的配置及标记状态,未重跑 gateway 工具调用或 OpenClaw 2026.9.2 E2E。

提交前刷新:head 未变,CI 已运行检查全部成功,4 个审查线程均已解决。提交前 mergeable=MERGEABLEmergeStateStatus=BLOCKEDreviewDecision=CHANGES_REQUESTED;本次批准更新此前的审查结论。

结论:APPROVE

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component:memory src/memory scope:documentation ./docs/|./*.md|./NOTICE

Projects

None yet

2 participants