Skip to content

memory_recall can fail after DB migration/import while memory-pro search still works (runtime scope/agent resolution mismatch) #273

@lamkan0210

Description

@lamkan0210

Summary

After migrating memory-lancedb-pro from a 768-dim DB to a new 1024-dim DB, the memory data could be restored into the new LanceDB and openclaw memory-pro search worked, but the memory_recall tool in the running OpenClaw session returned No relevant memories found.

This turned out to be a combination of migration/import friction and a tool-runtime scope resolution issue.

Environment

  • Plugin: memory-lancedb-pro@1.1.0-beta.9
  • OpenClaw host: macOS
  • Embedding model: bge-large:latest via Ollama-compatible endpoint
  • Old DB: 768 dims
  • New DB: 1024 dims

What happened

  1. Switched plugin config to a new 1024-dim dbPath
  2. Restarted gateway
  3. Verified plugin loaded and pointed at the new DB
  4. memory_recall returned no results
  5. CLI showed the new DB was empty
  6. Historical memories still existed in JSONL backup
  7. Imported backup into new DB
  8. After import:
    • openclaw memory-pro stats showed memories present
    • openclaw memory-pro search ... returned results
    • but memory_recall still returned no results in-session

Additional import issue

A subset of backup entries were long session-summary style memories. Import hit repeated embedding errors like:

Document exceeded context limit (400 the input length exceeds the context length), attempting chunking...

As a practical recovery step, trimming the longest entries before import allowed the full dataset to be restored.

Root cause we found locally

The main behavioral mismatch was:

  • CLI search worked
  • memory_recall tool did not

The relevant code path appears to be tool runtime context resolution in src/tools.ts:

function resolveToolContext(
  base: ToolContext,
  runtimeCtx: unknown,
): ToolContext {
  return {
    ...base,
    agentId: resolveRuntimeAgentId(base.agentId, runtimeCtx),
  };
}

During tool registration in index.ts, tools are registered with:

agentId: undefined // Will be determined at runtime from context

If the host does not pass agentId / sessionKey as expected in the tool runtime context, then agentId remains undefined.

From src/scopes.ts, that means getAccessibleScopes(undefined) falls back to getAllScopes(), which only includes explicitly defined scopes.

In our case, restored memories were in agent:main, but the plugin config did not explicitly define agent:main in scopes.definitions, so tool-side resolution could end up searching the wrong accessible scope set even though CLI with explicit --scope agent:main worked.

Local workaround / fix that restored memory_recall

We made three local changes:

1) Add a runtime fallback in resolveToolContext

function resolveToolContext(
  base: ToolContext,
  runtimeCtx: unknown,
): ToolContext {
  return {
    ...base,
    agentId: resolveRuntimeAgentId(base.agentId, runtimeCtx) || "main",
  };
}

2) Explicitly configure scope definitions / access

"scopes": {
  "default": "agent:main",
  "definitions": {
    "global": { "description": "Shared knowledge across all agents" },
    "agent:main": { "description": "Primary private memory scope for the main agent" }
  },
  "agentAccess": {
    "main": ["global", "agent:main"]
  }
}

3) Lower retrieval thresholds back to more forgiving values

"retrieval": {
  "minScore": 0.3,
  "hardMinScore": 0.35
}

After reload, both of these worked again:

  • openclaw memory-pro search ...
  • memory_recall

Why this is worth fixing in the plugin

The current behavior is fragile because tool correctness depends on runtime context injection being perfect, while the scope manager treats undefined agentId very differently from a concrete agent.

This can produce a confusing state where:

  • the database is healthy
  • CLI retrieval is healthy
  • but agent tool recall appears broken

Suggested fixes

  1. Add a safer fallback for tool runtime agentId

    • maybe default to main for main-session usage
    • or use a more robust derivation path when runtime context is partial
  2. Make built-in agent:* scopes more resilient when no explicit definition exists

    • or ensure getAllScopes() includes active built-in agent scopes when memories already exist there
  3. Improve import behavior for overlong memory texts

    • proper chunking/truncation strategy during import
    • clearer reporting for which entries failed and why
  4. Consider a migration helper for dimension/dbPath changes

    • detect backup presence
    • optionally re-import into the new DB automatically or interactively

Repro signal

A strong signal for this issue is:

  • memory-pro search returns relevant results from agent:main
  • memory_recall returns No relevant memories found
  • tool runtime has no usable agentId/sessionKey
  • agent:main is not explicitly present in scopes.definitions

If helpful, I can also open a follow-up PR with the fallback fix.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions