test: collapse remaining trigger command shards

This commit is contained in:
Peter Steinberger
2026-02-23 05:22:24 +00:00
parent d90e9f561f
commit 9f508056d3
4 changed files with 191 additions and 222 deletions

View File

@@ -1,8 +1,11 @@
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
makeCfg,
runGreetingPromptForBareNewOrReset,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
@@ -13,6 +16,36 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
async function expectResetBlockedForNonOwner(params: {
home: string;
commandAuthorized: boolean;
getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
}): Promise<void> {
const { home, commandAuthorized, getReplyFromConfig } = params;
const cfg = makeCfg(home);
cfg.channels ??= {};
cfg.channels.whatsapp = {
...cfg.channels.whatsapp,
allowFrom: ["+1999"],
};
cfg.session = {
...cfg.session,
store: join(tmpdir(), `openclaw-session-test-${Date.now()}.json`),
};
const res = await getReplyFromConfig(
{
Body: "/reset",
From: "+1003",
To: "+2000",
CommandAuthorized: commandAuthorized,
},
{},
cfg,
);
expect(res).toBeUndefined();
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
}
describe("trigger handling", () => {
it("allows /activation from allowFrom in groups", async () => {
await withTempHome(async (home) => {
@@ -79,4 +112,32 @@ describe("trigger handling", () => {
expect(extra).toContain("Activation: always-on");
});
});
it("runs a greeting prompt for a bare /reset", async () => {
await withTempHome(async (home) => {
await runGreetingPromptForBareNewOrReset({ home, body: "/reset", getReplyFromConfig });
});
});
it("runs a greeting prompt for a bare /new", async () => {
await withTempHome(async (home) => {
await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig });
});
});
it("does not reset for unauthorized /reset", async () => {
await withTempHome(async (home) => {
await expectResetBlockedForNonOwner({
home,
commandAuthorized: false,
getReplyFromConfig,
});
});
});
it("blocks /reset for non-owner senders", async () => {
await withTempHome(async (home) => {
await expectResetBlockedForNonOwner({
home,
commandAuthorized: true,
getReplyFromConfig,
});
});
});
});

View File

@@ -1,10 +1,15 @@
import fs from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { loadSessionStore, resolveSessionKey } from "../config/sessions.js";
import {
getCompactEmbeddedPiSessionMock,
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
MAIN_SESSION_KEY,
makeCfg,
mockRunEmbeddedPiAgentOk,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
import { HEARTBEAT_TOKEN } from "./tokens.js";
@@ -57,6 +62,22 @@ async function writeStoredModelOverride(cfg: ReturnType<typeof makeCfg>): Promis
);
}
function mockSuccessfulCompaction() {
getCompactEmbeddedPiSessionMock().mockResolvedValue({
ok: true,
compacted: true,
result: {
summary: "summary",
firstKeptEntryId: "x",
tokensBefore: 12000,
},
});
}
function replyText(res: Awaited<ReturnType<typeof getReplyFromConfig>>) {
return Array.isArray(res) ? res[0]?.text : res?.text;
}
describe("trigger handling", () => {
it("includes the error cause when the embedded agent throws", async () => {
await withTempHome(async (home) => {
@@ -170,4 +191,113 @@ describe("trigger handling", () => {
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("runs /compact as a gated command", async () => {
await withTempHome(async (home) => {
const storePath = join(tmpdir(), `openclaw-session-test-${Date.now()}.json`);
const cfg = makeCfg(home);
cfg.session = { ...cfg.session, store: storePath };
mockSuccessfulCompaction();
const res = await getReplyFromConfig(
{
Body: "/compact focus on decisions",
From: "+1003",
To: "+2000",
CommandAuthorized: true,
},
{},
cfg,
);
const text = replyText(res);
expect(text?.startsWith("⚙️ Compacted")).toBe(true);
expect(getCompactEmbeddedPiSessionMock()).toHaveBeenCalledOnce();
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
const store = loadSessionStore(storePath);
const sessionKey = resolveSessionKey("per-sender", {
Body: "/compact focus on decisions",
From: "+1003",
To: "+2000",
});
expect(store[sessionKey]?.compactionCount).toBe(1);
});
});
it("runs /compact for non-default agents without transcript path validation failures", async () => {
await withTempHome(async (home) => {
getCompactEmbeddedPiSessionMock().mockClear();
mockSuccessfulCompaction();
const res = await getReplyFromConfig(
{
Body: "/compact",
From: "+1004",
To: "+2000",
SessionKey: "agent:worker1:telegram:12345",
CommandAuthorized: true,
},
{},
makeCfg(home),
);
const text = replyText(res);
expect(text?.startsWith("⚙️ Compacted")).toBe(true);
expect(getCompactEmbeddedPiSessionMock()).toHaveBeenCalledOnce();
expect(getCompactEmbeddedPiSessionMock().mock.calls[0]?.[0]?.sessionFile).toContain(
join("agents", "worker1", "sessions"),
);
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
});
});
it("ignores think directives that only appear in the context wrapper", async () => {
await withTempHome(async (home) => {
mockRunEmbeddedPiAgentOk();
const res = await getReplyFromConfig(
{
Body: [
"[Chat messages since your last reply - for context]",
"Peter: /thinking high [2025-12-05T21:45:00.000Z]",
"",
"[Current message - respond to this]",
"Give me the status",
].join("\n"),
From: "+1002",
To: "+2000",
},
{},
makeCfg(home),
);
const text = replyText(res);
expect(text).toBe("ok");
expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce();
const prompt = getRunEmbeddedPiAgentMock().mock.calls[0]?.[0]?.prompt ?? "";
expect(prompt).toContain("Give me the status");
expect(prompt).not.toContain("/thinking high");
expect(prompt).not.toContain("/think high");
});
});
it("does not emit directive acks for heartbeats with /think", async () => {
await withTempHome(async (home) => {
mockRunEmbeddedPiAgentOk();
const res = await getReplyFromConfig(
{
Body: "HEARTBEAT /think:high",
From: "+1003",
To: "+1003",
},
{ isHeartbeat: true },
makeCfg(home),
);
const text = replyText(res);
expect(text).toBe("ok");
expect(text).not.toMatch(/Thinking level set/i);
expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce();
});
});
});

View File

@@ -1,144 +0,0 @@
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { loadSessionStore, resolveSessionKey } from "../config/sessions.js";
import {
getCompactEmbeddedPiSessionMock,
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
loadGetReplyFromConfig,
makeCfg,
mockRunEmbeddedPiAgentOk,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
beforeAll(async () => {
getReplyFromConfig = await loadGetReplyFromConfig();
});
installTriggerHandlingE2eTestHooks();
function mockSuccessfulCompaction() {
getCompactEmbeddedPiSessionMock().mockResolvedValue({
ok: true,
compacted: true,
result: {
summary: "summary",
firstKeptEntryId: "x",
tokensBefore: 12000,
},
});
}
function replyText(res: Awaited<ReturnType<typeof getReplyFromConfig>>) {
return Array.isArray(res) ? res[0]?.text : res?.text;
}
describe("trigger handling", () => {
it("runs /compact as a gated command", async () => {
await withTempHome(async (home) => {
const storePath = join(tmpdir(), `openclaw-session-test-${Date.now()}.json`);
const cfg = makeCfg(home);
cfg.session = { ...cfg.session, store: storePath };
mockSuccessfulCompaction();
const res = await getReplyFromConfig(
{
Body: "/compact focus on decisions",
From: "+1003",
To: "+2000",
CommandAuthorized: true,
},
{},
cfg,
);
const text = replyText(res);
expect(text?.startsWith("⚙️ Compacted")).toBe(true);
expect(getCompactEmbeddedPiSessionMock()).toHaveBeenCalledOnce();
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
const store = loadSessionStore(storePath);
const sessionKey = resolveSessionKey("per-sender", {
Body: "/compact focus on decisions",
From: "+1003",
To: "+2000",
});
expect(store[sessionKey]?.compactionCount).toBe(1);
});
});
it("runs /compact for non-default agents without transcript path validation failures", async () => {
await withTempHome(async (home) => {
getCompactEmbeddedPiSessionMock().mockClear();
mockSuccessfulCompaction();
const res = await getReplyFromConfig(
{
Body: "/compact",
From: "+1004",
To: "+2000",
SessionKey: "agent:worker1:telegram:12345",
CommandAuthorized: true,
},
{},
makeCfg(home),
);
const text = replyText(res);
expect(text?.startsWith("⚙️ Compacted")).toBe(true);
expect(getCompactEmbeddedPiSessionMock()).toHaveBeenCalledOnce();
expect(getCompactEmbeddedPiSessionMock().mock.calls[0]?.[0]?.sessionFile).toContain(
join("agents", "worker1", "sessions"),
);
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
});
});
it("ignores think directives that only appear in the context wrapper", async () => {
await withTempHome(async (home) => {
mockRunEmbeddedPiAgentOk();
const res = await getReplyFromConfig(
{
Body: [
"[Chat messages since your last reply - for context]",
"Peter: /thinking high [2025-12-05T21:45:00.000Z]",
"",
"[Current message - respond to this]",
"Give me the status",
].join("\n"),
From: "+1002",
To: "+2000",
},
{},
makeCfg(home),
);
const text = replyText(res);
expect(text).toBe("ok");
expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce();
const prompt = getRunEmbeddedPiAgentMock().mock.calls[0]?.[0]?.prompt ?? "";
expect(prompt).toContain("Give me the status");
expect(prompt).not.toContain("/thinking high");
expect(prompt).not.toContain("/think high");
});
});
it("does not emit directive acks for heartbeats with /think", async () => {
await withTempHome(async (home) => {
mockRunEmbeddedPiAgentOk();
const res = await getReplyFromConfig(
{
Body: "HEARTBEAT /think:high",
From: "+1003",
To: "+1003",
},
{ isHeartbeat: true },
makeCfg(home),
);
const text = replyText(res);
expect(text).toBe("ok");
expect(text).not.toMatch(/Thinking level set/i);
expect(getRunEmbeddedPiAgentMock()).toHaveBeenCalledOnce();
});
});
});

View File

@@ -1,78 +0,0 @@
import { tmpdir } from "node:os";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
makeCfg,
runGreetingPromptForBareNewOrReset,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
beforeAll(async () => {
({ getReplyFromConfig } = await import("./reply.js"));
});
installTriggerHandlingE2eTestHooks();
async function expectResetBlockedForNonOwner(params: {
home: string;
commandAuthorized: boolean;
getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
}): Promise<void> {
const { home, commandAuthorized, getReplyFromConfig } = params;
const cfg = makeCfg(home);
cfg.channels ??= {};
cfg.channels.whatsapp = {
...cfg.channels.whatsapp,
allowFrom: ["+1999"],
};
cfg.session = {
...cfg.session,
store: join(tmpdir(), `openclaw-session-test-${Date.now()}.json`),
};
const res = await getReplyFromConfig(
{
Body: "/reset",
From: "+1003",
To: "+2000",
CommandAuthorized: commandAuthorized,
},
{},
cfg,
);
expect(res).toBeUndefined();
expect(getRunEmbeddedPiAgentMock()).not.toHaveBeenCalled();
}
describe("trigger handling", () => {
it("runs a greeting prompt for a bare /reset", async () => {
await withTempHome(async (home) => {
await runGreetingPromptForBareNewOrReset({ home, body: "/reset", getReplyFromConfig });
});
});
it("runs a greeting prompt for a bare /new", async () => {
await withTempHome(async (home) => {
await runGreetingPromptForBareNewOrReset({ home, body: "/new", getReplyFromConfig });
});
});
it("does not reset for unauthorized /reset", async () => {
await withTempHome(async (home) => {
await expectResetBlockedForNonOwner({
home,
commandAuthorized: false,
getReplyFromConfig,
});
});
});
it("blocks /reset for non-owner senders", async () => {
await withTempHome(async (home) => {
await expectResetBlockedForNonOwner({
home,
commandAuthorized: true,
getReplyFromConfig,
});
});
});
});