diff --git a/CHANGELOG.md b/CHANGELOG.md index fb715bc5ed0..ac3b8d7b363 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Memory/status: keep plain `openclaw memory status` and `openclaw memory status --json` on the cheap read-only path by reserving vector and embedding provider probes for `--deep` or `--index`. Fixes #76769. Thanks @daruire. - Control UI/Sessions: avoid full `sessions.list` reloads for chat-turn `sessions.changed` payloads, so large session stores no longer add multi-second delays while chat responses are being delivered. (#76676) Thanks @VACInc. - Doctor/Telegram: warn when selected Telegram quote replies can suppress `streaming.preview.toolProgress`, and document the `replyToMode` trade-off without changing runtime delivery. Fixes #73487. Thanks @GodsBoy. - Plugins/install: reject source-only TypeScript package installs and installed plugin packages that are missing compiled runtime output, so broken npm artifacts fail at install/discovery time instead of falling through jiti and surfacing later as unavailable providers. Fixes #76720. diff --git a/extensions/memory-core/src/cli.runtime.ts b/extensions/memory-core/src/cli.runtime.ts index 522bb504dc5..8e2d3906560 100644 --- a/extensions/memory-core/src/cli.runtime.ts +++ b/extensions/memory-core/src/cli.runtime.ts @@ -717,8 +717,6 @@ export async function runMemoryStatus(opts: MemoryCommandOptions) { } else if (opts.index && !syncFn) { defaultRuntime.log("Memory backend does not support manual reindex."); } - } else { - await manager.probeVectorAvailability(); } const status = manager.status(); const sources = ( diff --git a/extensions/memory-core/src/cli.test.ts b/extensions/memory-core/src/cli.test.ts index 406d2616d5a..b4702f9f733 100644 --- a/extensions/memory-core/src/cli.test.ts +++ b/extensions/memory-core/src/cli.test.ts @@ -215,8 +215,9 @@ describe("memory cli", () => { it("prints vector status when available", async () => { const close = vi.fn(async () => {}); + const probeVectorAvailability = vi.fn(async () => true); mockManager({ - probeVectorAvailability: vi.fn(async () => true), + probeVectorAvailability, status: () => makeMemoryStatus({ files: 2, @@ -236,6 +237,7 @@ describe("memory cli", () => { const log = spyRuntimeLogs(defaultRuntime); await runMemoryCli(["status"]); + expect(probeVectorAvailability).not.toHaveBeenCalled(); expect(log).toHaveBeenCalledWith(expect.stringContaining("Vector: ready")); expect(log).toHaveBeenCalledWith(expect.stringContaining("Vector dims: 1024")); expect(log).toHaveBeenCalledWith(expect.stringContaining("Vector path: /opt/sqlite-vec.dylib")); @@ -246,6 +248,36 @@ describe("memory cli", () => { expect(close).toHaveBeenCalled(); }); + it("keeps plain status from probing vector or embeddings", async () => { + const close = vi.fn(async () => {}); + const probeVectorAvailability = vi.fn(async () => { + throw new Error("unexpected vector probe"); + }); + const probeEmbeddingAvailability = vi.fn(async () => { + throw new Error("unexpected embedding probe"); + }); + mockManager({ + probeVectorAvailability, + probeEmbeddingAvailability, + status: () => + makeMemoryStatus({ + provider: "auto", + requestedProvider: "auto", + vector: { enabled: true }, + }), + close, + }); + + const log = spyRuntimeLogs(defaultRuntime); + await runMemoryCli(["status"]); + + expect(probeVectorAvailability).not.toHaveBeenCalled(); + expect(probeEmbeddingAvailability).not.toHaveBeenCalled(); + expect(log).toHaveBeenCalledWith(expect.stringContaining("Provider: auto")); + expect(log).toHaveBeenCalledWith(expect.stringContaining("Vector: unknown")); + expect(close).toHaveBeenCalled(); + }); + it("resolves configured memory SecretRefs through gateway snapshot", async () => { getRuntimeConfig.mockReturnValue({ agents: { @@ -335,9 +367,10 @@ describe("memory cli", () => { it("prints embeddings status when deep", async () => { const close = vi.fn(async () => {}); + const probeVectorAvailability = vi.fn(async () => true); const probeEmbeddingAvailability = vi.fn(async () => ({ ok: true })); mockManager({ - probeVectorAvailability: vi.fn(async () => true), + probeVectorAvailability, probeEmbeddingAvailability, status: () => makeMemoryStatus({ files: 1, chunks: 1 }), close, @@ -346,6 +379,7 @@ describe("memory cli", () => { const log = spyRuntimeLogs(defaultRuntime); await runMemoryCli(["status", "--deep"]); + expect(probeVectorAvailability).toHaveBeenCalled(); expect(probeEmbeddingAvailability).toHaveBeenCalled(); expect(log).toHaveBeenCalledWith(expect.stringContaining("Embeddings: ready")); expect(close).toHaveBeenCalled(); @@ -544,9 +578,10 @@ describe("memory cli", () => { it("reindexes on status --index", async () => { const close = vi.fn(async () => {}); const sync = vi.fn(async () => {}); + const probeVectorAvailability = vi.fn(async () => true); const probeEmbeddingAvailability = vi.fn(async () => ({ ok: true })); mockManager({ - probeVectorAvailability: vi.fn(async () => true), + probeVectorAvailability, probeEmbeddingAvailability, sync, status: () => makeMemoryStatus({ files: 1, chunks: 1 }), @@ -557,6 +592,7 @@ describe("memory cli", () => { await runMemoryCli(["status", "--index"]); expectCliSync(sync); + expect(probeVectorAvailability).toHaveBeenCalled(); expect(probeEmbeddingAvailability).toHaveBeenCalled(); expect(getMemorySearchManager).toHaveBeenCalledWith({ cfg: {}, @@ -723,8 +759,15 @@ describe("memory cli", () => { it("prints status json output when requested", async () => { const close = vi.fn(async () => {}); + const probeVectorAvailability = vi.fn(async () => { + throw new Error("unexpected vector probe"); + }); + const probeEmbeddingAvailability = vi.fn(async () => { + throw new Error("unexpected embedding probe"); + }); mockManager({ - probeVectorAvailability: vi.fn(async () => true), + probeVectorAvailability, + probeEmbeddingAvailability, status: () => makeMemoryStatus({ workspaceDir: undefined }), close, }); @@ -739,6 +782,8 @@ describe("memory cli", () => { } expect(Array.isArray(payload)).toBe(true); expect((payload[0] as Record)?.agentId).toBe("main"); + expect(probeVectorAvailability).not.toHaveBeenCalled(); + expect(probeEmbeddingAvailability).not.toHaveBeenCalled(); expect(close).toHaveBeenCalled(); });