test: move directive state coverage to pure tests

This commit is contained in:
Peter Steinberger
2026-04-08 20:50:56 +01:00
parent 5f5b3d733b
commit 37fb1eb9ad
2 changed files with 83 additions and 93 deletions

View File

@@ -4,7 +4,6 @@ import type { OpenClawConfig } from "../config/config.js";
import { loadSessionStore } from "../config/sessions.js";
import {
AUTHORIZED_WHATSAPP_COMMAND,
assertElevatedOffStatusReply,
installDirectiveBehaviorE2EHooks,
makeElevatedDirectiveConfig,
makeRestrictedElevatedDisabledConfig,
@@ -179,27 +178,6 @@ describe("directive behavior", () => {
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("persists fast toggles across /status and /fast", async () => {
await withTempHome(async (home) => {
const storePath = sessionStorePath(home);
const onText = await runCommand(home, "/fast on");
expect(onText).toContain("Fast mode enabled");
expect(loadSessionStore(storePath)["agent:main:main"]?.fastMode).toBe(true);
const statusText = await runCommand(home, "/status");
const optionsLine = statusText?.split("\n").find((line) => line.trim().startsWith("⚙️"));
expect(optionsLine).toContain("Fast: on");
const offText = await runCommand(home, "/fast off");
expect(offText).toContain("Fast mode disabled");
expect(loadSessionStore(storePath)["agent:main:main"]?.fastMode).toBe(false);
const fastText = await runCommand(home, "/fast");
expect(fastText).toContain("Current fast mode: off");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("treats /fast status like the no-argument status query", async () => {
await withTempHome(async (home) => {
const statusText = await runCommand(home, "/fast status", {
@@ -217,29 +195,6 @@ describe("directive behavior", () => {
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("persists elevated toggles across /status and /elevated", async () => {
await withTempHome(async (home) => {
const storePath = sessionStorePath(home);
const offStatusText = replyText(await runElevatedCommand(home, "/elevated off\n/status"));
expect(offStatusText).toContain("Session: agent:main:main");
assertElevatedOffStatusReply(offStatusText);
const offLevelText = replyText(await runElevatedCommand(home, "/elevated"));
expect(offLevelText).toContain("Current elevated level: off");
expect(loadSessionStore(storePath)["agent:main:main"]?.elevatedLevel).toBe("off");
await runElevatedCommand(home, "/elevated on");
const onStatusText = replyText(await runElevatedCommand(home, "/status"));
const optionsLine = onStatusText?.split("\n").find((line) => line.trim().startsWith("⚙️"));
expect(optionsLine).toBeTruthy();
expect(optionsLine).toContain("elevated");
const store = loadSessionStore(storePath);
expect(store["agent:main:main"]?.elevatedLevel).toBe("on");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("enforces per-agent elevated restrictions and status visibility", async () => {
await withTempHome(async (home) => {
const deniedRes = await getReplyFromConfig(
@@ -258,21 +213,6 @@ describe("directive behavior", () => {
const deniedText = replyText(deniedRes);
expect(deniedText).toContain("agents.list[].tools.elevated.enabled");
const statusRes = await getReplyFromConfig(
{
Body: "/status",
From: "+1222",
To: "+1222",
Provider: "whatsapp",
SenderE164: "+1222",
SessionKey: "agent:restricted:main",
CommandAuthorized: true,
},
{},
makeRestrictedElevatedDisabledConfig(home) as unknown as OpenClawConfig,
);
const statusText = replyText(statusRes);
expect(statusText).not.toContain("elevated");
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
@@ -376,37 +316,4 @@ describe("directive behavior", () => {
expect(runEmbeddedPiAgentMock).not.toHaveBeenCalled();
});
});
it("strips inline elevated directives from the user text (does not persist session override)", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValue({
payloads: [{ text: "ok" }],
meta: {
durationMs: 1,
agentMeta: { sessionId: "s", provider: "p", model: "m" },
},
});
const storePath = sessionStorePath(home);
await getReplyFromConfig(
{
Body: "hello there /elevated off",
From: "+1222",
To: "+1222",
Provider: "whatsapp",
SenderE164: "+1222",
},
{},
makeElevatedDirectiveConfig(home),
);
const store = loadSessionStore(storePath);
expect(store["agent:main:main"]?.elevatedLevel).toBeUndefined();
const calls = runEmbeddedPiAgentMock.mock.calls;
expect(calls.length).toBeGreaterThan(0);
const call = calls[0]?.[0];
expect(call?.prompt).toContain("hello there");
expect(call?.prompt).not.toContain("/elevated");
});
});
});

View File

@@ -622,6 +622,14 @@ describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
expect(result?.text ?? "").not.toContain("failed");
});
it("strips inline elevated directives while keeping user text", () => {
const directives = parseInlineDirectives("hello there /elevated off");
expect(directives.hasElevatedDirective).toBe(true);
expect(directives.elevatedLevel).toBe("off");
expect(directives.cleaned).toBe("hello there");
});
it("persists thinkingLevel=off (does not clear)", async () => {
const directives = parseInlineDirectives("/think off");
const sessionEntry = createSessionEntry({ thinkingLevel: "low" });
@@ -639,6 +647,81 @@ describe("handleDirectiveOnly model persist behavior (fixes #1435)", () => {
expect(sessionStore["agent:main:dm:1"]?.thinkingLevel).toBe("off");
});
it("persists and reports fast-mode directives", async () => {
const sessionEntry = createSessionEntry();
const sessionStore = { [sessionKey]: sessionEntry };
const onReply = await handleDirectiveOnly(
createHandleParams({
directives: parseInlineDirectives("/fast on"),
sessionEntry,
sessionStore,
}),
);
expect(onReply?.text).toContain("Fast mode enabled");
expect(sessionEntry.fastMode).toBe(true);
const statusReply = await handleDirectiveOnly(
createHandleParams({
directives: parseInlineDirectives("/fast"),
sessionEntry,
sessionStore,
currentFastMode: sessionEntry.fastMode,
}),
);
expect(statusReply?.text).toContain("Current fast mode: on");
const offReply = await handleDirectiveOnly(
createHandleParams({
directives: parseInlineDirectives("/fast off"),
sessionEntry,
sessionStore,
currentFastMode: sessionEntry.fastMode,
}),
);
expect(offReply?.text).toContain("Fast mode disabled");
expect(sessionEntry.fastMode).toBe(false);
});
it("persists and reports elevated-mode directives when allowed", async () => {
const sessionEntry = createSessionEntry();
const sessionStore = { [sessionKey]: sessionEntry };
const base = {
elevatedAllowed: true,
elevatedEnabled: true,
sessionEntry,
sessionStore,
} satisfies Partial<HandleParams>;
const onReply = await handleDirectiveOnly(
createHandleParams({
...base,
directives: parseInlineDirectives("/elevated on"),
}),
);
expect(onReply?.text).toContain("Elevated mode set to ask");
expect(sessionEntry.elevatedLevel).toBe("on");
const statusReply = await handleDirectiveOnly(
createHandleParams({
...base,
directives: parseInlineDirectives("/elevated"),
currentElevatedLevel: sessionEntry.elevatedLevel,
}),
);
expect(statusReply?.text).toContain("Current elevated level: on");
const offReply = await handleDirectiveOnly(
createHandleParams({
...base,
directives: parseInlineDirectives("/elevated off"),
currentElevatedLevel: sessionEntry.elevatedLevel,
}),
);
expect(offReply?.text).toContain("Elevated mode disabled");
expect(sessionEntry.elevatedLevel).toBe("off");
});
it("blocks internal operator.write exec persistence in directive-only handling", async () => {
const directives = parseInlineDirectives(
"/exec host=node security=allowlist ask=always node=worker-1",