test: merge overlapping trigger-handling suites

This commit is contained in:
Peter Steinberger
2026-02-23 05:19:23 +00:00
parent af547ec52c
commit d90e9f561f
6 changed files with 246 additions and 321 deletions

View File

@@ -47,6 +47,59 @@ describe("trigger handling", () => {
expect(store[MAIN_SESSION_KEY]?.elevatedLevel).toBeUndefined();
});
});
it("allows elevated off in groups without mention", async () => {
await withTempHome(async (home) => {
const cfg = makeWhatsAppElevatedCfg(home, { requireMentionInGroups: false });
const res = await getReplyFromConfig(
{
Body: "/elevated off",
From: "whatsapp:group:123@g.us",
To: "whatsapp:+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
ChatType: "group",
WasMentioned: false,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode disabled.");
const store = await readSessionStore(cfg);
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("off");
});
});
it("allows elevated directive in groups when mentioned", async () => {
await withTempHome(async (home) => {
const cfg = makeWhatsAppElevatedCfg(home, { requireMentionInGroups: true });
const res = await getReplyFromConfig(
{
Body: "/elevated on",
From: "whatsapp:group:123@g.us",
To: "whatsapp:+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
ChatType: "group",
WasMentioned: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode set to ask");
const store = await readSessionStore(cfg);
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("on");
});
});
it("ignores elevated directive in groups when not mentioned", async () => {
await withTempHome(async (home) => {
getRunEmbeddedPiAgentMock().mockResolvedValue({

View File

@@ -1,71 +0,0 @@
import { beforeAll, describe, expect, it } from "vitest";
import { loadSessionStore } from "../config/sessions.js";
import {
installTriggerHandlingE2eTestHooks,
loadGetReplyFromConfig,
makeWhatsAppElevatedCfg,
readSessionStore,
requireSessionStorePath,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
beforeAll(async () => {
getReplyFromConfig = await loadGetReplyFromConfig();
});
installTriggerHandlingE2eTestHooks();
describe("trigger handling", () => {
it("allows elevated off in groups without mention", async () => {
await withTempHome(async (home) => {
const cfg = makeWhatsAppElevatedCfg(home, { requireMentionInGroups: false });
const res = await getReplyFromConfig(
{
Body: "/elevated off",
From: "whatsapp:group:123@g.us",
To: "whatsapp:+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
ChatType: "group",
WasMentioned: false,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode disabled.");
const store = loadSessionStore(requireSessionStorePath(cfg));
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("off");
});
});
it("allows elevated directive in groups when mentioned", async () => {
await withTempHome(async (home) => {
const cfg = makeWhatsAppElevatedCfg(home, { requireMentionInGroups: true });
const res = await getReplyFromConfig(
{
Body: "/elevated on",
From: "whatsapp:group:123@g.us",
To: "whatsapp:+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
ChatType: "group",
WasMentioned: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Elevated mode set to ask");
const store = await readSessionStore(cfg);
expect(store["agent:main:whatsapp:group:123@g.us"]?.elevatedLevel).toBe("on");
});
});
});

View File

@@ -1,14 +1,16 @@
import { readFile } from "node:fs/promises";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { normalizeTestText } from "../../test/helpers/normalize-text.js";
import type { OpenClawConfig } from "../config/config.js";
import { resolveSessionKey } from "../config/sessions.js";
import {
createBlockReplyCollector,
getProviderUsageMocks,
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
makeCfg,
requireSessionStorePath,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
@@ -362,4 +364,70 @@ describe("trigger handling", () => {
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("reports active auth profile and key snippet in status", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const cfg = makeCfg(home);
const agentDir = join(home, ".openclaw", "agents", "main", "agent");
await mkdir(agentDir, { recursive: true });
await writeFile(
join(agentDir, "auth-profiles.json"),
JSON.stringify(
{
version: 1,
profiles: {
"anthropic:work": {
type: "api_key",
provider: "anthropic",
key: "sk-test-1234567890abcdef",
},
},
lastGood: { anthropic: "anthropic:work" },
},
null,
2,
),
);
const sessionKey = resolveSessionKey("per-sender", {
From: "+1002",
To: "+2000",
Provider: "whatsapp",
} as Parameters<typeof resolveSessionKey>[1]);
await writeFile(
requireSessionStorePath(cfg),
JSON.stringify(
{
[sessionKey]: {
sessionId: "session-auth",
updatedAt: Date.now(),
authProfileOverride: "anthropic:work",
},
},
null,
2,
),
);
const res = await getReplyFromConfig(
{
Body: "/status",
From: "+1002",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1002",
CommandAuthorized: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("api-key");
expect(text).toMatch(/\u2026|\.{3}/);
expect(text).toContain("(anthropic:work)");
expect(text).not.toContain("mixed");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
});

View File

@@ -1,9 +1,11 @@
import fs from "node:fs/promises";
import { beforeAll, describe, expect, it } from "vitest";
import {
expectInlineCommandHandledAndStripped,
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
loadGetReplyFromConfig,
MAIN_SESSION_KEY,
makeCfg,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
@@ -15,10 +17,9 @@ beforeAll(async () => {
installTriggerHandlingE2eTestHooks();
async function expectUnauthorizedCommandDropped(home: string, body: "/status" | "/whoami") {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
function makeUnauthorizedWhatsAppCfg(home: string) {
const baseCfg = makeCfg(home);
const cfg = {
return {
...baseCfg,
channels: {
...baseCfg.channels,
@@ -27,6 +28,19 @@ async function expectUnauthorizedCommandDropped(home: string, body: "/status" |
},
},
};
}
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
async function expectUnauthorizedCommandDropped(home: string, body: "/status" | "/whoami") {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const cfg = makeUnauthorizedWhatsAppCfg(home);
const res = await getReplyFromConfig(
{
@@ -44,6 +58,37 @@ async function expectUnauthorizedCommandDropped(home: string, body: "/status" |
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
}
function mockEmbeddedOk() {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
runEmbeddedPiAgentMock.mockResolvedValue({
payloads: [{ text: "ok" }],
meta: {
durationMs: 1,
agentMeta: { sessionId: "s", provider: "p", model: "m" },
},
});
return runEmbeddedPiAgentMock;
}
async function runInlineUnauthorizedCommand(params: {
home: string;
command: "/status" | "/help";
}) {
const cfg = makeUnauthorizedWhatsAppCfg(params.home);
const res = await getReplyFromConfig(
{
Body: `please ${params.command} now`,
From: "+2001",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+2001",
},
{},
cfg,
);
return res;
}
describe("trigger handling", () => {
it("handles inline /commands and strips it before the agent", async () => {
await withTempHome(async (home) => {
@@ -95,4 +140,80 @@ describe("trigger handling", () => {
await expectUnauthorizedCommandDropped(home, "/whoami");
});
});
it("keeps inline /status for unauthorized senders", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = mockEmbeddedOk();
const res = await runInlineUnauthorizedCommand({
home,
command: "/status",
});
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe("ok");
expect(runEmbeddedPiAgentMock).toHaveBeenCalled();
const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? "";
expect(prompt).toContain("/status");
});
});
it("keeps inline /help for unauthorized senders", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = mockEmbeddedOk();
const res = await runInlineUnauthorizedCommand({
home,
command: "/help",
});
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe("ok");
expect(runEmbeddedPiAgentMock).toHaveBeenCalled();
const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? "";
expect(prompt).toContain("/help");
});
});
it("returns help without invoking the agent", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const res = await getReplyFromConfig(
{
Body: "/help",
From: "+1002",
To: "+2000",
CommandAuthorized: true,
},
{},
makeCfg(home),
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Help");
expect(text).toContain("Session");
expect(text).toContain("More: /commands for full list");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("allows owner to set send policy", async () => {
await withTempHome(async (home) => {
const cfg = makeUnauthorizedWhatsAppCfg(home);
const res = await getReplyFromConfig(
{
Body: "/send off",
From: "+1000",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Send policy set to off");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { sendPolicy?: string }>;
expect(store[MAIN_SESSION_KEY]?.sendPolicy).toBe("deny");
});
});
});

View File

@@ -1,159 +0,0 @@
import fs from "node:fs/promises";
import { beforeAll, describe, expect, it } from "vitest";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
MAIN_SESSION_KEY,
makeCfg,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
beforeAll(async () => {
({ getReplyFromConfig } = await import("./reply.js"));
});
installTriggerHandlingE2eTestHooks();
function mockEmbeddedOk() {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
runEmbeddedPiAgentMock.mockResolvedValue({
payloads: [{ text: "ok" }],
meta: {
durationMs: 1,
agentMeta: { sessionId: "s", provider: "p", model: "m" },
},
});
return runEmbeddedPiAgentMock;
}
function makeUnauthorizedWhatsAppCfg(home: string) {
const baseCfg = makeCfg(home);
return {
...baseCfg,
channels: {
...baseCfg.channels,
whatsapp: {
allowFrom: ["+1000"],
},
},
};
}
function requireSessionStorePath(cfg: { session?: { store?: string } }): string {
const storePath = cfg.session?.store;
if (!storePath) {
throw new Error("expected session store path");
}
return storePath;
}
async function runInlineUnauthorizedCommand(params: {
home: string;
command: "/status" | "/help";
getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
}) {
const cfg = makeUnauthorizedWhatsAppCfg(params.home);
const res = await params.getReplyFromConfig(
{
Body: `please ${params.command} now`,
From: "+2001",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+2001",
},
{},
cfg,
);
return { cfg, res };
}
describe("trigger handling", () => {
it("keeps inline /status for unauthorized senders", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = mockEmbeddedOk();
const { res } = await runInlineUnauthorizedCommand({
home,
command: "/status",
getReplyFromConfig,
});
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe("ok");
expect(runEmbeddedPiAgentMock).toHaveBeenCalled();
const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? "";
// Not allowlisted: inline /status is treated as plain text and is not stripped.
expect(prompt).toContain("/status");
});
});
it("keeps inline /help for unauthorized senders", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = mockEmbeddedOk();
const { res } = await runInlineUnauthorizedCommand({
home,
command: "/help",
getReplyFromConfig,
});
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toBe("ok");
expect(runEmbeddedPiAgentMock).toHaveBeenCalled();
const prompt = runEmbeddedPiAgentMock.mock.calls[0]?.[0]?.prompt ?? "";
expect(prompt).toContain("/help");
});
});
it("returns help without invoking the agent", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const res = await getReplyFromConfig(
{
Body: "/help",
From: "+1002",
To: "+2000",
CommandAuthorized: true,
},
{},
makeCfg(home),
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Help");
expect(text).toContain("Session");
expect(text).toContain("More: /commands for full list");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("allows owner to set send policy", async () => {
await withTempHome(async (home) => {
const baseCfg = makeCfg(home);
const cfg = {
...baseCfg,
channels: {
...baseCfg.channels,
whatsapp: {
allowFrom: ["+1000"],
},
},
};
const res = await getReplyFromConfig(
{
Body: "/send off",
From: "+1000",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1000",
CommandAuthorized: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("Send policy set to off");
const storeRaw = await fs.readFile(requireSessionStorePath(cfg), "utf-8");
const store = JSON.parse(storeRaw) as Record<string, { sendPolicy?: string }>;
expect(store[MAIN_SESSION_KEY]?.sendPolicy).toBe("deny");
});
});
});

View File

@@ -1,87 +0,0 @@
import fs from "node:fs/promises";
import { join } from "node:path";
import { beforeAll, describe, expect, it } from "vitest";
import { resolveSessionKey } from "../config/sessions.js";
import {
getRunEmbeddedPiAgentMock,
installTriggerHandlingE2eTestHooks,
loadGetReplyFromConfig,
makeCfg,
requireSessionStorePath,
withTempHome,
} from "./reply.triggers.trigger-handling.test-harness.js";
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
beforeAll(async () => {
getReplyFromConfig = await loadGetReplyFromConfig();
});
installTriggerHandlingE2eTestHooks();
describe("trigger handling", () => {
it("reports active auth profile and key snippet in status", async () => {
await withTempHome(async (home) => {
const runEmbeddedPiAgentMock = getRunEmbeddedPiAgentMock();
const cfg = makeCfg(home);
const agentDir = join(home, ".openclaw", "agents", "main", "agent");
await fs.mkdir(agentDir, { recursive: true });
await fs.writeFile(
join(agentDir, "auth-profiles.json"),
JSON.stringify(
{
version: 1,
profiles: {
"anthropic:work": {
type: "api_key",
provider: "anthropic",
key: "sk-test-1234567890abcdef",
},
},
lastGood: { anthropic: "anthropic:work" },
},
null,
2,
),
);
const sessionKey = resolveSessionKey("per-sender", {
From: "+1002",
To: "+2000",
Provider: "whatsapp",
} as Parameters<typeof resolveSessionKey>[1]);
await fs.writeFile(
requireSessionStorePath(cfg),
JSON.stringify(
{
[sessionKey]: {
sessionId: "session-auth",
updatedAt: Date.now(),
authProfileOverride: "anthropic:work",
},
},
null,
2,
),
);
const res = await getReplyFromConfig(
{
Body: "/status",
From: "+1002",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1002",
CommandAuthorized: true,
},
{},
cfg,
);
const text = Array.isArray(res) ? res[0]?.text : res?.text;
expect(text).toContain("api-key");
expect(text).toMatch(/\u2026|\.{3}/);
expect(text).toContain("(anthropic:work)");
expect(text).not.toContain("mixed");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
});