Skip to content

fix(memory-core): register memory tools independently to prevent coupled failure#50198

Closed
artwalker wants to merge 982 commits intoopenclaw:mainfrom
artwalker:fix/memory-tool-independent-registration
Closed

fix(memory-core): register memory tools independently to prevent coupled failure#50198
artwalker wants to merge 982 commits intoopenclaw:mainfrom
artwalker:fix/memory-tool-independent-registration

Conversation

@artwalker
Copy link
Copy Markdown
Contributor

Summary

  • Split the coupled memory_search + memory_get tool registration in memory-core plugin into two independent registerTool calls
  • The previous single-factory approach returned null when either tool failed, silently dropping both tools from new sessions
  • Add debug logging when a plugin tool factory returns null to aid diagnosis

Root Cause

extensions/memory-core/index.ts registered both tools in one factory:

if (!memorySearchTool || !memoryGetTool) {
  return null;  // BOTH tools lost if EITHER fails
}

When the factory returned null, resolvePluginTools() silently skipped it with no log output, making the failure invisible.

Test plan

  • npm run build passes
  • Memory tool unit tests pass (10/10)
  • All 590 plugin tests pass (70 files)
  • Verify memory tools appear in new Feishu sessions with memory-core enabled

Fixes #50173

🤖 Generated with Claude Code

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 19, 2026

Greptile Summary

This PR fixes a silent double-failure bug in the memory-core plugin where both memory_search and memory_get tools would be dropped from new sessions if either one failed to initialize, and adds a debug log to make future null-factory returns observable.

Changes:

  • extensions/memory-core/index.ts: Splits one registerTool call (registering both tools in a single factory) into two independent calls — one per tool — so failure of one no longer silently suppresses the other.
  • src/plugins/tools.ts: Adds a log.debug message when a plugin tool factory returns null (guarded to entries that declare at least one name), filling a previously invisible failure path.

Analysis:

  • The fix is logically correct. Each factory now returns a single tool directly (or null), which is valid per the AnyAgentTool | AnyAgentTool[] | null | undefined type expected by resolvePluginTools.
  • The entry.names.length > 0 guard in the debug log intentionally keeps anonymous/conditional tool entries silent — only named entries emit the diagnostic.
  • No behavioral regressions are expected; the tools are independent operations and partial registration (one tool up, one down) is a valid and more resilient state than both-or-nothing.

Confidence Score: 5/5

  • This PR is safe to merge — the change is minimal, well-targeted, and fixes a real silent-failure bug without introducing new risk.
  • Both changes are small, focused, and logically sound. The factory split is compatible with the existing resolvePluginTools handling (single-tool returns are wrapped via Array.isArray). The debug log addition is purely additive and guarded correctly. No existing tool registration path is broken.
  • No files require special attention.

Last reviewed commit: "fix(memory-core): re..."

vincentkoc and others added 27 commits March 23, 2026 12:46
- azure.md: "What you'll do" -> "What you will do"
- standing-orders.md: "Don't" -> "Avoid"

Per CLAUDE.md: avoid em dashes and apostrophes in headings because
they break Mintlify anchor links.
…ault

- cli/plugins.md: rewrite install synopsis with ClawHub-first order
- cli/hooks.md: update hook pack install examples
- help/troubleshooting.md: <npm-spec> -> <package>
- gateway/security/index.md: drop npm-specific framing
Mintlify strips dots from backtick headings when generating anchors.
`agents.defaults.sandbox` -> #agentsdefaultssandbox (not #agents-defaults-sandbox)
- sandboxing.md: remove stale '-opt-in' suffix from Docker accordion anchor
- troubleshooting.md: remove #troubleshooting anchor (matrix has no such section)
- docker.md: drop unpredictable security heading anchor with parens/dots
- faq.md: fix SSL error accordion anchor slug
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

22 similar comments
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

1 similar comment
@openclaw-barnacle
Copy link
Copy Markdown

Closing this PR because it looks dirty (too many unrelated or unexpected changes). This usually happens when a branch picks up unrelated commits or a merge went sideways. Please recreate the PR from a clean branch.

Copy link
Copy Markdown

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

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: 2599c7e6c3

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +197 to +200
const memory = await getMemoryManagerContextWithPurpose({
cfg,
agentId,
purpose: "status",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use full manager for non-builtin memory_get calls

memory_get now requests getMemoryManagerContextWithPurpose(..., purpose: "status") for non-builtin backends, but in this commit getMemorySearchManager() returns QmdStatusOnlyManager for QMD status requests, and that manager’s readFile() always throws ("memory read unavailable in status-only mode"). In QMD deployments this makes every memory_get call return a disabled/error payload instead of file contents, so memory retrieval is effectively broken for that backend.

Useful? React with 👍 / 👎.

@frankekn
Copy link
Copy Markdown
Contributor

Opened replacement PR #52639 from a clean maintainer branch after the original fork-head recovery path became unreliable during prepare-push.

Keeping this PR for traceability; reviewers can use #52639 as the canonical merge path.

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

Labels

agents Agent runtime and tooling app: android App: android app: ios App: ios app: macos App: macos app: web-ui App: web-ui channel: bluebubbles Channel integration: bluebubbles channel: discord Channel integration: discord channel: feishu Channel integration: feishu channel: googlechat Channel integration: googlechat channel: imessage Channel integration: imessage channel: irc channel: line Channel integration: line channel: matrix Channel integration: matrix channel: mattermost Channel integration: mattermost channel: msteams Channel integration: msteams channel: nextcloud-talk Channel integration: nextcloud-talk channel: nostr Channel integration: nostr channel: signal Channel integration: signal channel: slack Channel integration: slack channel: telegram Channel integration: telegram channel: tlon Channel integration: tlon channel: twitch Channel integration: twitch channel: voice-call Channel integration: voice-call channel: whatsapp-web Channel integration: whatsapp-web channel: zalo Channel integration: zalo channel: zalouser Channel integration: zalouser cli CLI command changes commands Command implementations docker Docker and sandbox tooling docs Improvements or additions to documentation extensions: acpx extensions: anthropic extensions: byteplus extensions: cloudflare-ai-gateway extensions: copilot-proxy Extension: copilot-proxy extensions: device-pair extensions: diagnostics-otel Extension: diagnostics-otel extensions: fal extensions: huggingface extensions: kilocode extensions: kimi-coding extensions: llm-task Extension: llm-task extensions: lobster Extension: lobster extensions: memory-core Extension: memory-core extensions: memory-lancedb Extension: memory-lancedb extensions: minimax extensions: modelstudio extensions: moonshot extensions: nvidia extensions: open-prose Extension: open-prose extensions: openai extensions: phone-control extensions: qianfan extensions: qwen-portal-auth Extension: qwen-portal-auth extensions: synthetic extensions: talk-voice extensions: tavily extensions: together extensions: venice extensions: vercel-ai-gateway extensions: volcengine extensions: xiaomi gateway Gateway runtime scripts Repository scripts security Security documentation size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: memory_search tool not injected in new sessions despite plugin loaded