Skip to content

fix(memory): remove sync-on-miss from memory_search tool handler (fixes #98520)#98572

Closed
liuhao1024 wants to merge 1 commit into
openclaw:mainfrom
liuhao1024:fix/memory-search-sync-on-miss-blocks-foreground
Closed

fix(memory): remove sync-on-miss from memory_search tool handler (fixes #98520)#98572
liuhao1024 wants to merge 1 commit into
openclaw:mainfrom
liuhao1024:fix/memory-search-sync-on-miss-blocks-foreground

Conversation

@liuhao1024

Copy link
Copy Markdown
Contributor

What Problem This Solves

memory_search blocks the foreground tool call for the full duration of a memory sync when the first search returns zero results. The tool handler in extensions/memory-core/src/tools.ts performs a synchronous manager.sync({ reason: "search", force: true }) on every empty-result search, which can take minutes when the embedding provider is slow or unreachable.

This makes a normal "no results" search miss behave like a full memory indexing/sync operation inside the user-facing tool call deadline.

Why This Change Was Made

The tool-level sync-on-miss (lines 569-578 in tools.ts) is redundant with the manager's bootstrap sync in manager.ts:631-642. The manager already handles the "fresh process with no indexed content" case with its own synchronous bootstrap. The tool-level retry adds a second full sync on every empty result — not just the first search after restart.

Root cause: The tool handler called manager.sync({ force: true }) whenever rawResults.length === 0, regardless of whether the index was already populated. For queries with no matches, this triggered a full sync cycle (filesystem scan, embedding calls, vector updates) that blocked the foreground search.

Fix: Remove the tool-level sync-on-miss block. The manager's bootstrap sync handles the edge case of a fresh process with no indexed content. Additionally, add a 15-second timeout to the bootstrap sync so it does not block indefinitely when the embedding provider is unreachable.

User Impact

  • memory_search for queries with no matches returns immediately instead of blocking for minutes
  • First search after process restart still bootstraps the index, but with a bounded 15s timeout
  • Background syncs continue to keep the index up to date independently

Evidence

Real behavior proof

  • Behavior addressed: memory_search blocks foreground tool call on zero-result queries due to synchronous sync-on-miss
  • Environment tested: macOS, Node 22, OpenClaw 2026.6.11 (local checkout at upstream/main)
  • Steps run after the patch: Built OpenClaw (pnpm build), ran node openclaw.mjs memory search 'nonexistent_test_query_xyz_12345' --json
  • Evidence after fix:
$ node openclaw.mjs memory search 'nonexistent_test_query_xyz_12345' --json
[memory] sync failed (search-bootstrap): Error: memory sync bootstrap timed out
{
  "results": []
}
  • Observed result after fix: The search returns empty results. The bootstrap sync times out at 15s (embedding provider unreachable in this environment) instead of blocking indefinitely. The tool-level sync-on-miss that previously re-triggered a full sync on every empty result is no longer present.
  • What was not tested: Live search with a working embedding provider (OpenAI API unreachable from this environment). The fix's correctness is verified by unit tests (21/21 pass) and source code inspection. The timeout improvement is demonstrated by the bootstrap timeout log message.

Changes Made

  • extensions/memory-core/src/tools.ts: Remove the rawResults.length === 0 && activeMemory.manager.sync sync-on-miss block (lines 569-578)
  • extensions/memory-core/src/memory/manager.ts: Add 15-second Promise.race timeout to the bootstrap sync in search() method
  • extensions/memory-core/src/tools.test.ts: Update two tests that depended on the retry-on-miss behavior

How to Test

pnpm test:extension memory-core
node scripts/run-vitest.mjs run extensions/memory-core/src/tools.test.ts
  • AI-assisted (Hermes Agent)

The memory_search tool performed a synchronous forced sync when the
first search returned zero results (rawResults.length === 0). This
blocked the foreground tool call for the full duration of the memory
sync — potentially minutes when the embedding provider is slow or
unreachable.

The manager's search() method already handles bootstrap sync for fresh
processes with no indexed content. The tool-level sync-on-miss was
redundant and harmful: it re-triggered a full sync on every empty
result, not just on the first search after restart.

Changes:
- tools.ts: Remove the rawResults.length === 0 sync-on-miss block
- manager.ts: Add 15s timeout to the bootstrap sync so it does not
  block indefinitely when the embedding provider is unreachable
- tools.test.ts: Update two tests that depended on the retry-on-miss
  behavior to reflect the new single-search-call semantics

Fixes openclaw#98520
@clawsweeper

clawsweeper Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Thanks for the context here. I swept through the related work, and this is now duplicate or superseded.

Close as superseded: the same QMD zero-hit memory_search stall is already owned by the open, proof-positive, maintainer-marked canonical PR at #90030, while this branch is broader and removes fallback behavior outside the reported QMD path.

Root-cause cluster
Relationship: superseded
Canonical: #90030
Summary: This PR is a broader duplicate of the QMD zero-hit forced-sync fix; the open canonical PR is proof-positive, clean, and maintainer-marked land-ready.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Canonical path: Close this branch and continue review or landing on #90030, which fixes the QMD hot-path stall without removing the broader retry contract.

So I’m closing this here and keeping the remaining discussion on #90030.

Review details

Best possible solution:

Close this branch and continue review or landing on #90030, which fixes the QMD hot-path stall without removing the broader retry contract.

Do we have a high-confidence way to reproduce the issue?

Yes. Current main still awaits a forced sync after zero raw memory_search results, and QMD sync awaits update maintenance; the canonical issue also has repeated live reports from QMD-backed deployments.

Is this the best way to solve the issue?

No. The best fix is the narrower canonical QMD-only path in #90030, because this PR removes retry behavior for unaffected backends and adds separate bootstrap timeout policy.

Security review:

Security review cleared: No concrete security or supply-chain concern found; the diff is limited to memory-core runtime behavior and tests.

AGENTS.md: found and applied where relevant.

What I checked:

Likely related people:

  • TurboTheTurtle: Recent merged work kept memory_search in transient QMD mode and touched both the tool and QMD manager surfaces adjacent to the zero-hit retry behavior. (role: recent memory_search and QMD lifecycle contributor; confidence: high; commits: ddacb7ba39d4, 6aff1e8f9ea4, 9408380ae729; files: extensions/memory-core/src/tools.ts, extensions/memory-core/src/memory/qmd-manager.ts)
  • vincentkoc: Recent QMD watcher/probe work is adjacent to this backend path, and a member comment marked the narrower QMD-only PR as the canonical land-ready fix. (role: recent QMD area contributor and canonical-fix reviewer; confidence: high; commits: dbcae5b78d9f, 6aff1e8f9ea4; files: extensions/memory-core/src/memory/qmd-manager.ts, extensions/memory-core/src/tools.ts)
  • dreamhunter2333: Authored the recent memory_search AbortSignal/deadline work around the same foreground timeout wrapper that this stall path runs under. (role: recent memory_search timeout contributor; confidence: medium; commits: 8d72cb9401e5; files: extensions/memory-core/src/tools.ts, extensions/memory-core/src/tools.test.ts)
  • osolmaz: Recent work changed memory index identity and QMD rerank/search configuration adjacent to zero-hit and stale-index behavior. (role: adjacent memory index and QMD config contributor; confidence: medium; commits: a4b4fed41287, 0dbf17471b41; files: extensions/memory-core/src/tools.ts, extensions/memory-core/src/memory/qmd-manager.ts, packages/memory-host-sdk/src/host/backend-config.ts)
  • steipete: Recent commits touched memory recall stall handling and QMD timeout/config defaults near this failure mode. (role: recent memory-core hardening contributor; confidence: medium; commits: 73dd758310e8, 9e2bd8b2f7eb, c36ba9ea7a2d; files: extensions/memory-core/src/tools.ts, extensions/memory-core/src/memory/qmd-manager.ts, packages/memory-host-sdk/src/host/backend-config.ts)

Codex review notes: model internal, reasoning high; reviewed against c99add65a223.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. labels Jul 1, 2026
@vincentkoc

Copy link
Copy Markdown
Member

Thanks for working on this. The same zero-hit memory_search stall is now covered by the narrower canonical fix in #90030, which landed as 90e31be. Closing this PR to keep the queue clean because #90030 preserves the one-shot QMD bootstrap retry while removing the long-lived QMD hot-path sync.

@vincentkoc vincentkoc closed this Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: memory-core Extension: memory-core merge-risk: 🚨 availability 🚨 May cause crashes, hangs, restart loops, stalls, or process outages. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. P2 Normal backlog priority with limited blast radius. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants