mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-27 21:07:01 -06:00
fix(memory): preserve provider on cancelled search (#124051)
This commit is contained in:
committed by
GitHub
parent
9050ff0e9e
commit
3f6bf166b6
@@ -143,6 +143,58 @@ describe("memory index", () => {
|
||||
expect(queryCalls).toBe(3);
|
||||
});
|
||||
|
||||
it("keeps a healthy local provider active when the caller cancels search", async () => {
|
||||
const cfg = createCfg({
|
||||
hybrid: { enabled: true, vectorWeight: 0.5, textWeight: 0.5 },
|
||||
});
|
||||
const manager = await getPersistentManager(cfg);
|
||||
await manager.sync({ reason: "test" });
|
||||
|
||||
const close = vi.fn(async () => {});
|
||||
let queryCalls = 0;
|
||||
const fields = manager as unknown as {
|
||||
provider: {
|
||||
id: string;
|
||||
model: string;
|
||||
embedQuery: (text: string) => Promise<number[]>;
|
||||
embedBatch: (texts: string[]) => Promise<number[][]>;
|
||||
close: () => Promise<void>;
|
||||
};
|
||||
providerKey: string;
|
||||
providerLifecycle: { mode: "active"; providerId: string };
|
||||
computeProviderKey: () => string;
|
||||
};
|
||||
fields.provider = {
|
||||
id: "local",
|
||||
model: "mock-embed",
|
||||
embedQuery: async () => {
|
||||
queryCalls += 1;
|
||||
return [1, 0, 0, 0];
|
||||
},
|
||||
embedBatch: async (texts) => texts.map(() => [1, 0, 0, 0]),
|
||||
close,
|
||||
};
|
||||
fields.providerLifecycle = { mode: "active", providerId: "local" };
|
||||
fields.providerKey = fields.computeProviderKey();
|
||||
await manager.sync({ reason: "test", force: true });
|
||||
|
||||
const abortReason = new Error("memory search was cancelled");
|
||||
await expect(
|
||||
manager.search("alpha", { signal: AbortSignal.abort(abortReason) }),
|
||||
).rejects.toMatchObject({ cause: abortReason });
|
||||
|
||||
expect(manager.status()).toMatchObject({
|
||||
provider: "local",
|
||||
custom: {
|
||||
providerState: { mode: "active", providerId: "local" },
|
||||
providerUnavailableReason: undefined,
|
||||
},
|
||||
});
|
||||
await expect(manager.search("alpha")).resolves.not.toStrictEqual([]);
|
||||
expect(queryCalls).toBe(1);
|
||||
expect(close).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("supplements thin strict FTS results for conversational queries", async () => {
|
||||
const cases = [
|
||||
{
|
||||
|
||||
@@ -285,12 +285,12 @@ export abstract class MemorySearchOrchestration extends MemoryKeywordRetrieval {
|
||||
);
|
||||
} catch (err) {
|
||||
releaseSemanticProvider();
|
||||
this.markLocalEmbeddingProviderDegraded(err);
|
||||
// An aborted caller already stopped waiting; skip fallback-provider
|
||||
// activation so the abandoned search stops instead of re-embedding.
|
||||
// An aborted caller already stopped waiting; keep the provider generation
|
||||
// healthy and skip fallback activation instead of poisoning later searches.
|
||||
if (opts?.signal?.aborted) {
|
||||
throw err;
|
||||
}
|
||||
this.markLocalEmbeddingProviderDegraded(err);
|
||||
const message = formatErrorMessage(err);
|
||||
const activatedFallback = this.shouldFallbackOnError(err)
|
||||
? await this.activateFallbackProvider(message).catch((fallbackErr: unknown) => {
|
||||
@@ -331,7 +331,9 @@ export abstract class MemorySearchOrchestration extends MemoryKeywordRetrieval {
|
||||
);
|
||||
} catch (fallbackErr) {
|
||||
releaseFallbackProvider();
|
||||
this.markLocalEmbeddingProviderDegraded(fallbackErr);
|
||||
if (!opts?.signal?.aborted) {
|
||||
this.markLocalEmbeddingProviderDegraded(fallbackErr);
|
||||
}
|
||||
throw fallbackErr;
|
||||
} finally {
|
||||
releaseFallbackProvider();
|
||||
|
||||
Reference in New Issue
Block a user