Summary
The gateway's memory_search tool is permanently stuck with Dirty: yes because this.provider.model is empty/uninitialized when the OpenAI embedding adapter resolves, but every identity check and meta write uses it raw — overwriting the correct model identity stamped by the CLI.
Reproduction
- Configure
memorySearch with provider: "openai" and model: "text-embedding-3-small"
- Build a clean index with the CLI:
openclaw memory status --index --agent main → Dirty: no
- Start the gateway
- Run
openclaw memory status → Dirty: yes, Index identity: index was built for model text-embedding-3-small, expected
The expected model is an empty string because this.provider.model is not populated by the OpenAI adapter after create().
Root cause
resolveProviderModel() correctly resolves the model name during adapter.create(), but the resolved name is not backfilled onto the returned provider object's .model field. The adapter returns provider.model = "" (or the raw provider ID).
Every downstream use of this.provider.model then propagates the empty string:
- Identity checks (
refreshIndexIdentityDirty, resolveCurrentIndexIdentityState, runSync) compare "" against "text-embedding-3-small" → always "mismatched" → Dirty: yes
- Meta writes (
writeMeta in safe-reindex and runUnsafeReindex) stamp "" into sqlite → next boot sees identity mismatch
- Chunk writes/queries (
writeChunks, searchVector, searchKeyword) use inconsistent model tags
- The dirty verdict is cached and only re-evaluated at boot or on search — but boot wipes the meta first, so there is no path to recovery from outside
Affected code
dist/manager-dZw31DAG2.js — 13 occurrences of this.provider.model / this.provider?.model with no fallback to this.settings.model:
- Lines 1143, 2049, 3567 (identity checks)
- Lines 2271, 2338 (meta writes)
- Lines 2002, 2528, 2850, 2951, 2962, 3706, 3721 (data paths)
Workaround
Patch all 13 sites to fall back: this.provider.model || this.settings.model
For example in refreshIndexIdentityDirty:
// Before:
model: this.provider.model
// After:
model: this.provider.model || this.settings.model
Suggested fix
Either:
- Backfill
provider.model with the resolved model name in createWithAdapter / adaptGenericEmbeddingProvider after resolveProviderModel() runs
- Or add the
|| this.settings.model fallback in MemoryIndexManager at each usage site
Option 1 is cleaner — single fix at the source.
Environment
- OpenClaw v2026.6.1 (2e08f0f)
- macOS (darwin arm64)
- Node 22.22.2
- Provider: openai, model: text-embedding-3-small
Summary
The gateway's
memory_searchtool is permanently stuck withDirty: yesbecausethis.provider.modelis empty/uninitialized when the OpenAI embedding adapter resolves, but every identity check and meta write uses it raw — overwriting the correct model identity stamped by the CLI.Reproduction
memorySearchwithprovider: "openai"andmodel: "text-embedding-3-small"openclaw memory status --index --agent main→Dirty: noopenclaw memory status→Dirty: yes,Index identity: index was built for model text-embedding-3-small, expectedThe expected model is an empty string because
this.provider.modelis not populated by the OpenAI adapter aftercreate().Root cause
resolveProviderModel()correctly resolves the model name duringadapter.create(), but the resolved name is not backfilled onto the returnedproviderobject's.modelfield. The adapter returnsprovider.model = ""(or the raw provider ID).Every downstream use of
this.provider.modelthen propagates the empty string:refreshIndexIdentityDirty,resolveCurrentIndexIdentityState,runSync) compare""against"text-embedding-3-small"→ always"mismatched"→Dirty: yeswriteMetain safe-reindex andrunUnsafeReindex) stamp""into sqlite → next boot sees identity mismatchwriteChunks,searchVector,searchKeyword) use inconsistent model tagsAffected code
dist/manager-dZw31DAG2.js— 13 occurrences ofthis.provider.model/this.provider?.modelwith no fallback tothis.settings.model:Workaround
Patch all 13 sites to fall back:
this.provider.model || this.settings.modelFor example in
refreshIndexIdentityDirty:Suggested fix
Either:
provider.modelwith the resolved model name increateWithAdapter/adaptGenericEmbeddingProviderafterresolveProviderModel()runs|| this.settings.modelfallback inMemoryIndexManagerat each usage siteOption 1 is cleaner — single fix at the source.
Environment