Skip to content

fix(memory-core): declare "local" memoryEmbeddingProviders contract#70873

Merged
steipete merged 2 commits intoopenclaw:mainfrom
mattznojassist:fix/memory-core-local-embedding-capability-contract
Apr 24, 2026
Merged

fix(memory-core): declare "local" memoryEmbeddingProviders contract#70873
steipete merged 2 commits intoopenclaw:mainfrom
mattznojassist:fix/memory-core-local-embedding-capability-contract

Conversation

@mattznojassist
Copy link
Copy Markdown
Contributor

Summary

  • Problem: On v2026.4.22, openclaw memory status, openclaw memory index, and openclaw memory search all fail with Unknown memory embedding provider: local, even with a valid local memorySearch config and node-llama-cpp installed. Matches [Bug]: openclaw memory index fails with 'Unknown memory embedding provider: local' while gateway memory is vector ready #70836 verbatim.
  • Why it matters: The CLI reindex/search path is unusable for anyone on local embeddings. In-session memory_search via the gateway keeps working (different registration path), which is why the regression is easy to miss.
  • What changed: One-line addition of "contracts": { "memoryEmbeddingProviders": ["local"] } to extensions/memory-core/openclaw.plugin.json. Matches the declaration pattern the 7 other embedding provider plugins already use (google, ollama, openai, voyage, lmstudio, mistral, amazon-bedrock, github-copilot).
  • What did NOT change (scope boundary): Zero source-code changes. The localAdapter definition, autoSelectPriority: 10, model resolution, and runtime registerBuiltInMemoryEmbeddingProviders(api) call are all untouched. This only makes the plugin manifest self-describe a capability the code already provides at runtime.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

Root Cause

Commit 77e6e4cf87 introduced a capability-manifest registration pathway so bundled plugins can be resolved by provider id without requiring the full plugin register(api) lifecycle to have run (used by standalone CLI subprocesses, which do not boot the gateway). Each provider-plugin was updated to declare its memoryEmbeddingProviders contract in openclaw.plugin.json:

extensions/google/openclaw.plugin.json:      "memoryEmbeddingProviders": ["gemini"]
extensions/ollama/openclaw.plugin.json:      "memoryEmbeddingProviders": ["ollama"]
extensions/openai/openclaw.plugin.json:      "memoryEmbeddingProviders": ["openai"]
extensions/voyage/openclaw.plugin.json:      "memoryEmbeddingProviders": ["voyage"]
extensions/lmstudio/openclaw.plugin.json:    "memoryEmbeddingProviders": ["lmstudio"]
extensions/mistral/openclaw.plugin.json:     "memoryEmbeddingProviders": ["mistral"]
extensions/amazon-bedrock/openclaw.plugin.json: "memoryEmbeddingProviders": ["bedrock"]
extensions/github-copilot/openclaw.plugin.json: "memoryEmbeddingProviders": ["github-copilot"]

But extensions/memory-core/openclaw.plugin.json was not updated, even though memory-core owns the built-in local adapter (registered at runtime via registerBuiltInMemoryEmbeddingProviders(api) in extensions/memory-core/index.ts).

Gateway startup still registers the adapter in the active runtime registry, so gateway-hosted memory_search keeps working. Standalone CLI invocations fall through to resolveBundledCapabilityCompatPluginIdsloadPluginManifestRegistry (see src/plugins/capability-provider-runtime.ts:45-63), which only surfaces plugins whose manifest declares the contract. With local not declared anywhere, the CLI can't find it and throws.

Diagram

Before:
openclaw memory index
  -> getMemoryEmbeddingProvider("local")
     -> active registry: empty (CLI didn't run plugin register())
     -> manifest-compat: no plugin declares "memoryEmbeddingProviders: [local]"
     -> undefined
  -> throw "Unknown memory embedding provider: local"

After:
openclaw memory index
  -> getMemoryEmbeddingProvider("local")
     -> active registry: empty
     -> manifest-compat: memory-core declares "memoryEmbeddingProviders: [local]"
     -> loads memory-core, localAdapter registers, lookup succeeds
  -> reindex proceeds

Security Impact (required)

  • New permissions/capabilities? No — the capability was already registered at runtime; this only documents it in the manifest so the manifest-compat lookup path finds it.
  • Secrets/tokens handling changed? No.
  • New/changed network calls? Nolocal adapter uses node-llama-cpp on-device, no network.
  • Command/tool execution surface changed? No.
  • Data access scope changed? No.

Repro + Verification

Environment

  • OS: macOS 26.2 arm64
  • Runtime: Node 22, pnpm 10.33.0
  • Model/provider: local via hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf
  • Integration: n/a (CLI path)
  • Relevant config (redacted):
    "memorySearch": {
      "provider": "local",
      "fallback": "none",
      "local": { "modelPath": "hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf" }
    }

Steps

  1. Install/upgrade to v2026.4.22
  2. Configure agents.defaults.memorySearch.provider = "local"
  3. Run openclaw memory index --agent main --verbose

Expected

  • Exit 0, "Memory index updated ()." per agent.

Actual (before this fix)

Memory Index (main)
Provider: local (requested: local)
Model: local
Sources: memory (MEMORY.md + ~/.openclaw/workspace/memory/*.md)

Memory index failed (main): Unknown memory embedding provider: local

Evidence

Tested on a detached checkout of v2026.4.22 with this one-line manifest change applied and pnpm run build run. Before vs after from the same machine, same config:

Before:

$ openclaw memory status --agent main
[openclaw] Failed to start CLI: Error: Unknown memory embedding provider: local
    at getAdapter (.../manager-xvPcitvj.js:143:22)
    at createEmbeddingProvider (.../manager-xvPcitvj.js:195:25)
    at MemoryIndexManager.loadProviderResult (...)

After:

$ openclaw memory status --agent main
Memory Search (main)
Provider: local (requested: local)
Model: hf:ggml-org/embeddinggemma-300m-qat-q8_0-GGUF/embeddinggemma-300m-qat-Q8_0.gguf
Sources: memory
Indexed: 162/162 files · 942 chunks

$ openclaw memory index --agent main
Memory index updated (main).

$ openclaw memory search "example query" --agent main --max-results 2
0.754 memory/archive/web-scraping-toolkit.md:35-68
[...content...]

Human Verification (required)

What I personally verified (not just CI):

  • Verified scenarios:
    • openclaw memory status --agent main returns Provider: local, Indexed: 162/162
    • openclaw memory index --agent main completes with "Memory index updated"
    • openclaw memory search returns hits embedded with the local model
    • Gateway restart under patched build; gateway RPC probe ok, 0 plugin errors
    • In-session memory_search via gateway still works (unchanged behavior)
  • Edge cases checked:
    • provider: "auto" → still correctly auto-selects local (priority 10) ahead of other providers when local.modelPath is set
    • oxfmt --check on the manifest passes (pre-commit hook runs clean)
  • What I did NOT verify:
    • Behavior on Linux / Windows (only tested macOS arm64)
    • Contract tests (vitest run src/plugins/contracts/) — node_modules pnpm install was skipped in the PR worktree to keep the turnaround fast; no source/test changes so no test expectation diffs expected, but worth confirming in CI
    • memory-lancedb-pro interaction if that plugin is enabled

Compatibility / Migration

  • Backward compatible? Yes — purely additive manifest declaration.
  • Config/env changes? No.
  • Migration needed? No — existing provider: "local" configs start working again.

Risks and Mitigations

  • Risk: Another plugin somewhere else also tries to claim id "local".
    • Mitigation: Verified no other openclaw.plugin.json declares "memoryEmbeddingProviders": ["local"]; getRegisteredMemoryEmbeddingProvider/filterUnregisteredMemoryEmbeddingProviderAdapters already handle duplicate-id cases gracefully.
  • Risk: Fix exposes the Metal GGML_ASSERT crash mentioned in [Bug]: openclaw memory index fails with 'Unknown memory embedding provider: local' while gateway memory is vector ready #70836 (previously masked because indexing couldn't start).
    • Mitigation: Orthogonal native-layer issue; not introduced by this change. Worth tracking separately.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 24, 2026

Greptile Summary

This PR fixes a regression introduced in v2026.4.22 where openclaw memory status, openclaw memory index, and openclaw memory search all failed with Unknown memory embedding provider: local. The fix adds a single "contracts": { "memoryEmbeddingProviders": ["local"] } declaration to extensions/memory-core/openclaw.plugin.json, matching the pattern already established by the 8 other embedding provider plugins (google, ollama, openai, voyage, lmstudio, mistral, amazon-bedrock, github-copilot). No source code was changed; the local adapter already existed at runtime — the manifest declaration was simply missing, causing the standalone CLI manifest-compat resolution path to fail while the gateway path (which runs full plugin registration) remained unaffected.

Confidence Score: 5/5

This PR is safe to merge — it is a single-line additive manifest declaration with no source code changes and zero risk of regression.

The change is minimal, structurally consistent with 8 sibling plugins, well-tested by the author against a real repro, and carries no source-code modifications. All remaining considerations (Linux/Windows coverage, contract test CI run) are tracked separately and do not affect correctness on the fixed path.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(memory-core): declare local memoryEm..." | Re-trigger Greptile

mattznojassist and others added 2 commits April 24, 2026 03:00
The v2026.4.22 refactor (77e6e4c) moved embedding providers into
provider-plugin extensions that declare a `memoryEmbeddingProviders`
capability in their plugin manifests. All 7 extensions were migrated,
but the built-in "local" adapter in memory-core was missed.

Without the contract declaration, the standalone CLI path
(openclaw memory status / index / search) cannot resolve the
"local" provider via the bundled-plugin capability-compat lookup,
even though the adapter is still registered at gateway startup via
`registerBuiltInMemoryEmbeddingProviders`.

Fixes the CLI regression reported in openclaw#70836.

- Gateway in-session memory_search remained functional (goes through
  the active runtime registry, not the manifest-compat path).
- No source or behavior change: the adapter itself, its priority,
  and its model resolution are unchanged. This only makes the
  manifest self-describe the capability that memory-core already
  provides at runtime.

Verified locally on macOS 26.2 arm64 / Node 22 / v2026.4.22:
- `openclaw memory status --agent main` → Provider: local ✓
- `openclaw memory index --agent main` → reindexed 162/162 files ✓
- `openclaw memory search "<query>"` → returns local-embedding hits ✓
- Gateway restart + status → running, RPC ok, 0 plugin errors ✓
@steipete steipete force-pushed the fix/memory-core-local-embedding-capability-contract branch from 9607f5a to e2b29bb Compare April 24, 2026 02:03
@steipete steipete merged commit e069d03 into openclaw:main Apr 24, 2026
68 checks passed
@steipete
Copy link
Copy Markdown
Contributor

Landed via squash onto main.

  • Local gate: pnpm test src/plugins/bundled-capability-metadata.test.ts src/plugins/contracts/memory-embedding-provider.contract.test.ts extensions/memory-core/src/memory/provider-adapter-registration.test.ts src/plugins/memory-embedding-provider-runtime.test.ts src/plugins/capability-provider-runtime.test.ts extensions/memory-core/src/memory/index.test.ts src/plugins/memory-embedding-providers.test.ts
  • Local gate: pnpm check:changed
  • Live check: forced agents.defaults.memorySearch.provider = "local" with ~/.profile sourced; openclaw memory status --agent main --deep --verbose reported Provider: local and Embeddings: ready; openclaw memory index --agent main --force --verbose completed with Memory index updated.
  • PR head after maintainer changelog commit: e2b29bb
  • Squash commit: e069d03

Thanks @mattznojassist!

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: openclaw memory index fails with 'Unknown memory embedding provider: local' while gateway memory is vector ready

2 participants