Skip to content

Commit 52047e0

Browse files
committed
fix(memory): resolve adapter default model in plain status identity check
1 parent aee45f5 commit 52047e0

2 files changed

Lines changed: 43 additions & 1 deletion

File tree

extensions/memory-core/src/memory/index.test.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,39 @@ describe("memory index", () => {
493493
}
494494
});
495495

496+
it("keeps status clean when configured model defaults to the adapter model (#90413)", async () => {
497+
const dbPath = path.join(workspaceDir, "index-default-model-status.sqlite");
498+
// Index under the provider's resolved default model, as provider init does.
499+
const indexCfg = createCfg({
500+
storePath: dbPath,
501+
provider: "gemini",
502+
model: "gemini-embed",
503+
hybrid: { enabled: true, vectorWeight: 0.5, textWeight: 0.5 },
504+
});
505+
const indexManager = await getFreshManager(indexCfg);
506+
await indexManager.sync({ reason: "test", force: true });
507+
await indexManager.close?.();
508+
509+
// Plain status path before provider init: settings.model is the empty
510+
// default, so identity must resolve the adapter model instead of comparing
511+
// meta against a blank "expected" model.
512+
const statusCfg = createCfg({
513+
storePath: dbPath,
514+
provider: "gemini",
515+
model: "",
516+
hybrid: { enabled: true, vectorWeight: 0.5, textWeight: 0.5 },
517+
});
518+
const statusManager = await getFreshManager(statusCfg, "status");
519+
try {
520+
const status = statusManager.status();
521+
522+
expect(status.dirty).toBe(false);
523+
expect(status.custom?.indexIdentity).toEqual({ status: "valid" });
524+
} finally {
525+
await statusManager.close?.();
526+
}
527+
});
528+
496529
it("does not search stale rows when index metadata is missing", async () => {
497530
const dbPath = path.join(workspaceDir, "index-missing-meta-cutover.sqlite");
498531
const cfg = createCfg({

extensions/memory-core/src/memory/manager-sync-ops.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coer
4040
import {
4141
createEmbeddingProvider,
4242
resolveEmbeddingProviderAdapterId,
43+
resolveEmbeddingProviderFallbackModel,
4344
type EmbeddingProvider,
4445
type EmbeddingProviderId,
4546
type EmbeddingProviderRuntime,
@@ -299,14 +300,22 @@ export abstract class MemoryManagerSyncOps {
299300
hasIndexedChunks?: boolean;
300301
}): MemoryIndexIdentityState {
301302
const hasProviderOverride = params && "provider" in params;
303+
// The plain `memory status` path resolves identity before the provider is
304+
// initialized, so settings.model is still the unresolved default: an empty
305+
// string when no explicit model is configured. Mirror provider init's model
306+
// resolution here (configured model, else adapter default) so identity does
307+
// not falsely report a mismatch against meta with a blank "expected" model.
308+
const configuredModel =
309+
this.settings.model.trim() ||
310+
resolveEmbeddingProviderFallbackModel(this.settings.provider, "", this.cfg);
302311
const configuredProvider =
303312
this.settings.provider === "none"
304313
? null
305314
: {
306315
id:
307316
resolveEmbeddingProviderAdapterId(this.settings.provider, this.cfg) ??
308317
this.settings.provider,
309-
model: this.settings.model,
318+
model: configuredModel,
310319
};
311320
const provider = hasProviderOverride
312321
? params.provider!

0 commit comments

Comments
 (0)