mirror of
https://github.com/moltbot/moltbot.git
synced 2026-05-13 15:47:28 +00:00
test: stabilize active memory timeout mocks
This commit is contained in:
@@ -125,6 +125,20 @@ describe("active-memory plugin", () => {
|
||||
"utf8",
|
||||
);
|
||||
};
|
||||
const waitForAbort = async (abortSignal?: AbortSignal): Promise<never> => {
|
||||
if (abortSignal?.aborted) {
|
||||
throw (abortSignal.reason as unknown) ?? new Error("Operation aborted");
|
||||
}
|
||||
return await new Promise<never>((_resolve, reject) => {
|
||||
abortSignal?.addEventListener(
|
||||
"abort",
|
||||
() => {
|
||||
reject((abortSignal.reason as unknown) ?? new Error("Operation aborted"));
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
});
|
||||
};
|
||||
const makeMemoryToolAllowlistError = (
|
||||
reason: string,
|
||||
sources = "runtime toolsAllow: memory_recall, memory_search, memory_get",
|
||||
@@ -145,6 +159,7 @@ describe("active-memory plugin", () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
vi.clearAllMocks();
|
||||
runEmbeddedPiAgent.mockReset();
|
||||
stateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-active-memory-test-"));
|
||||
configFile = {
|
||||
plugins: {
|
||||
@@ -171,6 +186,9 @@ describe("active-memory plugin", () => {
|
||||
},
|
||||
},
|
||||
};
|
||||
for (const key of Object.keys(hoisted.sessionStore)) {
|
||||
delete hoisted.sessionStore[key];
|
||||
}
|
||||
hoisted.sessionStore["agent:main:main"] = {
|
||||
sessionId: "s-main",
|
||||
updatedAt: 0,
|
||||
@@ -1547,26 +1565,28 @@ describe("active-memory plugin", () => {
|
||||
const sessionKey = "agent:main:transcript-debug";
|
||||
hoisted.sessionStore[sessionKey] = { sessionId: "s-main", updatedAt: 0 };
|
||||
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
const lines = [
|
||||
JSON.stringify({
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: { debug: { backend: "qmd", hits: 3 } },
|
||||
},
|
||||
}),
|
||||
JSON.stringify({
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: {},
|
||||
},
|
||||
}),
|
||||
];
|
||||
await fs.writeFile(params.sessionFile, `${lines.join("\n")}\n`, "utf8");
|
||||
return { payloads: [{ text: "wings are fine." }] };
|
||||
});
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
const lines = [
|
||||
JSON.stringify({
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: { debug: { backend: "qmd", hits: 3 } },
|
||||
},
|
||||
}),
|
||||
JSON.stringify({
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: {},
|
||||
},
|
||||
}),
|
||||
];
|
||||
await fs.writeFile(params.sessionFile, `${lines.join("\n")}\n`, "utf8");
|
||||
return { payloads: [{ text: "wings are fine." }] };
|
||||
},
|
||||
);
|
||||
|
||||
await hooks.before_prompt_build(
|
||||
{ prompt: "debug transcript bug", messages: [] },
|
||||
@@ -1807,27 +1827,29 @@ describe("active-memory plugin", () => {
|
||||
sessionId: "s-timeout-partial",
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(
|
||||
params.sessionFile,
|
||||
[
|
||||
{ type: "message", message: { role: "user", content: "ignore this user text" } },
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "alpha beta gamma delta" },
|
||||
},
|
||||
{
|
||||
type: "message",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "epsilon zeta eta theta" }],
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(
|
||||
params.sessionFile,
|
||||
[
|
||||
{ type: "message", message: { role: "user", content: "ignore this user text" } },
|
||||
{
|
||||
type: "message",
|
||||
message: { role: "assistant", content: "alpha beta gamma delta" },
|
||||
},
|
||||
},
|
||||
],
|
||||
"\n{",
|
||||
);
|
||||
return await new Promise<never>(() => {});
|
||||
});
|
||||
{
|
||||
type: "message",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: [{ type: "text", text: "epsilon zeta eta theta" }],
|
||||
},
|
||||
},
|
||||
],
|
||||
"\n{",
|
||||
);
|
||||
return await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what wings should i order? timeout partial", messages: [] },
|
||||
@@ -1879,15 +1901,7 @@ describe("active-memory plugin", () => {
|
||||
message: { role: "assistant", content: "temporary partial recall summary" },
|
||||
},
|
||||
]);
|
||||
await new Promise<never>((_resolve, reject) => {
|
||||
params.abortSignal?.addEventListener(
|
||||
"abort",
|
||||
() => {
|
||||
reject(params.abortSignal?.reason ?? new Error("Operation aborted"));
|
||||
},
|
||||
{ once: true },
|
||||
);
|
||||
});
|
||||
await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -1899,7 +1913,9 @@ describe("active-memory plugin", () => {
|
||||
expect(result).toEqual({
|
||||
prependContext: expect.stringContaining("temporary partial recall summary"),
|
||||
});
|
||||
await expect(fs.access(tempSessionFile)).rejects.toThrow();
|
||||
await vi.waitFor(async () => {
|
||||
await expect(fs.access(tempSessionFile)).rejects.toThrow();
|
||||
});
|
||||
expect(getActiveMemoryLines(sessionKey)).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.stringContaining("🧩 Active Memory: status=timeout_partial"),
|
||||
@@ -1925,10 +1941,12 @@ describe("active-memory plugin", () => {
|
||||
sessionId: "s-timeout-empty-transcript",
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await fs.writeFile(params.sessionFile, "", "utf8");
|
||||
return await new Promise<never>(() => {});
|
||||
});
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await fs.writeFile(params.sessionFile, "", "utf8");
|
||||
return await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what wings should i order? empty timeout transcript", messages: [] },
|
||||
@@ -1956,7 +1974,9 @@ describe("active-memory plugin", () => {
|
||||
sessionId: "s-timeout-missing-transcript",
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async () => await new Promise<never>(() => {}));
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { abortSignal?: AbortSignal }) => await waitForAbort(params.abortSignal),
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what wings should i order? missing timeout transcript", messages: [] },
|
||||
@@ -1983,18 +2003,20 @@ describe("active-memory plugin", () => {
|
||||
sessionId: "s-timeout-boilerplate-transcript",
|
||||
updatedAt: 0,
|
||||
};
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: "LLM request timed out after 15000 ms.",
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
type: "message",
|
||||
message: {
|
||||
role: "assistant",
|
||||
content: "LLM request timed out after 15000 ms.",
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
await new Promise<never>(() => {});
|
||||
});
|
||||
]);
|
||||
await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what wings should i order? timeout boilerplate", messages: [] },
|
||||
@@ -2494,18 +2516,20 @@ describe("active-memory plugin", () => {
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
const sessionKey = "agent:main:terminal-zero-hit";
|
||||
hoisted.sessionStore[sessionKey] = { sessionId: "s-terminal-zero-hit", updatedAt: 0 };
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: { results: [], debug: { backend: "qmd", hits: 0, searchMs: 8 } },
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: { results: [], debug: { backend: "qmd", hits: 0, searchMs: 8 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
await new Promise<never>(() => {});
|
||||
});
|
||||
]);
|
||||
await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what food do i usually order? zero hit", messages: [] },
|
||||
@@ -2579,23 +2603,25 @@ describe("active-memory plugin", () => {
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
const sessionKey = "agent:main:terminal-unavailable";
|
||||
hoisted.sessionStore[sessionKey] = { sessionId: "s-terminal-unavailable", updatedAt: 0 };
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async (params: { sessionFile: string }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: {
|
||||
disabled: true,
|
||||
warning: "Memory search is unavailable due to an embedding/provider error.",
|
||||
action: "Check the embedding provider configuration, then retry memory_search.",
|
||||
error: "embedding request failed",
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { sessionFile: string; abortSignal?: AbortSignal }) => {
|
||||
await writeTranscriptJsonl(params.sessionFile, [
|
||||
{
|
||||
message: {
|
||||
role: "toolResult",
|
||||
toolName: "memory_search",
|
||||
details: {
|
||||
disabled: true,
|
||||
warning: "Memory search is unavailable due to an embedding/provider error.",
|
||||
action: "Check the embedding provider configuration, then retry memory_search.",
|
||||
error: "embedding request failed",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
]);
|
||||
await new Promise<never>(() => {});
|
||||
});
|
||||
]);
|
||||
await waitForAbort(params.abortSignal);
|
||||
},
|
||||
);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what food do i usually order? unavailable", messages: [] },
|
||||
@@ -3591,7 +3617,9 @@ describe("active-memory plugin", () => {
|
||||
circuitBreakerCooldownMs: 60_000,
|
||||
};
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
runEmbeddedPiAgent.mockImplementation(async () => await new Promise<never>(() => {}));
|
||||
runEmbeddedPiAgent.mockImplementation(
|
||||
async (params: { abortSignal?: AbortSignal }) => await waitForAbort(params.abortSignal),
|
||||
);
|
||||
|
||||
// First two calls should actually attempt the subagent (and timeout).
|
||||
await hooks.before_prompt_build(
|
||||
@@ -3646,7 +3674,9 @@ describe("active-memory plugin", () => {
|
||||
plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
// First call: timeout (trips the breaker with max=1).
|
||||
runEmbeddedPiAgent.mockImplementationOnce(async () => await new Promise<never>(() => {}));
|
||||
runEmbeddedPiAgent.mockImplementationOnce(
|
||||
async (params: { abortSignal?: AbortSignal }) => await waitForAbort(params.abortSignal),
|
||||
);
|
||||
await hooks.before_prompt_build(
|
||||
{ prompt: "cb reset test timeout", messages: [] },
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user