

























@@ -17,6 +17,7 @@ import {
1717type MemoryReadParams,
1818} from "./memory-tool-manager-mock.js";
1919import { createMemoryCoreTestHarness } from "./test-helpers.js";
20+import { testing as memoryToolsTesting } from "./tools.js";
2021import {
2122asOpenClawConfig,
2223createAutoCitationsMemorySearchTool,
@@ -51,6 +52,7 @@ async function waitFor<T>(task: () => Promise<T>, timeoutMs = 1500): Promise<T>
51525253beforeEach(() => {
5354clearMemoryPluginState();
55+memoryToolsTesting.resetMemorySearchToolCooldowns();
5456resetMemoryToolMockState({
5557backend: "builtin",
5658searchImpl: async () => [
@@ -447,6 +449,105 @@ describe("memory tools", () => {
447449expect(getMemorySearchManagerMockCalls()).toBe(1);
448450});
449451452+it("does not cooldown primary memory when a corpus=all wiki supplement stalls", async () => {
453+vi.useFakeTimers();
454+try {
455+let searchCalls = 0;
456+setMemorySearchImpl(async () => {
457+searchCalls += 1;
458+return [
459+{
460+path: "MEMORY.md",
461+startLine: 5,
462+endLine: 7,
463+score: 0.9,
464+snippet: "@@ -5,3 @@\nAssistant: noted",
465+source: "memory" as const,
466+},
467+];
468+});
469+registerMemoryCorpusSupplement("memory-wiki", {
470+search: async () => await new Promise(() => undefined),
471+get: async () => null,
472+});
473+474+const tool = createMemorySearchToolOrThrow();
475+const stalledAllResultPromise = tool.execute("call_all_stalled_wiki", {
476+query: "alpha",
477+corpus: "all",
478+});
479+await vi.advanceTimersByTimeAsync(15_000);
480+const stalledAllResult = await stalledAllResultPromise;
481+expectUnavailableMemorySearchDetails(stalledAllResult.details, {
482+error: "memory_search timed out after 15s",
483+warning: "Memory search is unavailable due to an embedding/provider error.",
484+action: "Check embedding provider configuration and retry memory_search.",
485+});
486+487+const memoryResult = await tool.execute("call_memory_after_stalled_wiki", {
488+query: "alpha",
489+});
490+const details = memoryResult.details as { results: Array<{ corpus: string; path: string }> };
491+expect(details.results.map((entry) => [entry.corpus, entry.path])).toEqual([
492+["memory", "MEMORY.md"],
493+]);
494+expect(searchCalls).toBe(2);
495+} finally {
496+vi.useRealTimers();
497+}
498+});
499+500+it("cooldowns primary memory when corpus=all memory search stalls", async () => {
501+vi.useFakeTimers();
502+try {
503+let searchCalls = 0;
504+setMemorySearchImpl(async () => {
505+searchCalls += 1;
506+return await new Promise(() => undefined);
507+});
508+registerMemoryCorpusSupplement("memory-wiki", {
509+search: async () => [
510+{
511+corpus: "wiki",
512+path: "entities/alpha.md",
513+title: "Alpha",
514+kind: "entity",
515+score: 4,
516+snippet: "Alpha wiki entry",
517+},
518+],
519+get: async () => null,
520+});
521+522+const tool = createMemorySearchToolOrThrow();
523+const stalledAllResultPromise = tool.execute("call_all_stalled_memory", {
524+query: "alpha",
525+corpus: "all",
526+});
527+await vi.advanceTimersByTimeAsync(15_000);
528+const stalledAllResult = await stalledAllResultPromise;
529+expectUnavailableMemorySearchDetails(stalledAllResult.details, {
530+error: "memory_search timed out after 15s",
531+warning: "Memory search is unavailable due to an embedding/provider error.",
532+action: "Check embedding provider configuration and retry memory_search.",
533+});
534+535+const wikiOnlyResult = await tool.execute("call_all_after_stalled_memory", {
536+query: "alpha",
537+corpus: "all",
538+});
539+const details = wikiOnlyResult.details as {
540+results: Array<{ corpus: string; path: string }>;
541+};
542+expect(details.results.map((entry) => [entry.corpus, entry.path])).toEqual([
543+["wiki", "entities/alpha.md"],
544+]);
545+expect(searchCalls).toBe(1);
546+} finally {
547+vi.useRealTimers();
548+}
549+});
550+450551it("falls back to a wiki corpus supplement for memory_get corpus=all", async () => {
451552setMemoryReadFileImpl(async () => {
452553throw new Error("path required");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。