Files
openclaw/src/auto-reply/reply.directive.exec-agent-defaults.test.ts
Gustavo Madeira Santana d78512b09d Refactor: centralize native approval lifecycle assembly (#62135)
Merged via squash.

Prepared head SHA: b7c20a7398
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
2026-04-07 14:40:26 -04:00

214 lines
5.7 KiB
TypeScript

import fs from "node:fs/promises";
import "./reply.directive.directive-behavior.e2e-mocks.js";
import { beforeEach, describe, expect, it, vi } from "vitest";
import {
DEFAULT_TEST_MODEL_CATALOG,
MAIN_SESSION_KEY,
installDirectiveBehaviorE2EHooks,
installFreshDirectiveBehaviorReplyMocks,
makeEmbeddedTextResult,
sessionStorePath,
withTempHome,
} from "./reply.directive.directive-behavior.e2e-harness.js";
import {
loadModelCatalogMock,
runEmbeddedPiAgentMock,
} from "./reply.directive.directive-behavior.e2e-mocks.js";
import { withFullRuntimeReplyConfig } from "./reply/get-reply-fast-path.js";
let getReplyFromConfig: typeof import("./reply/get-reply.js").getReplyFromConfig;
function makeAgentExecConfig(home: string) {
return withFullRuntimeReplyConfig({
agents: {
defaults: {
model: "anthropic/claude-opus-4-6",
workspace: `${home}/openclaw`,
},
list: [
{
id: "main",
tools: {
exec: {
host: "node" as const,
security: "allowlist" as const,
ask: "always" as const,
node: "worker-alpha",
},
},
},
],
},
channels: { whatsapp: { allowFrom: ["*"] } },
session: { store: sessionStorePath(home) },
});
}
describe("directive behavior exec agent defaults", () => {
installDirectiveBehaviorE2EHooks();
beforeEach(async () => {
vi.resetModules();
loadModelCatalogMock.mockReset();
loadModelCatalogMock.mockResolvedValue(DEFAULT_TEST_MODEL_CATALOG);
installFreshDirectiveBehaviorReplyMocks();
({ getReplyFromConfig } = await import("./reply/get-reply.js"));
});
it("threads per-agent tools.exec defaults into live runs without a persisted session override", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValue(makeEmbeddedTextResult("done"));
await getReplyFromConfig(
{
Body: "run a command",
From: "+1004",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1004",
},
{},
makeAgentExecConfig(home),
);
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
const call = runEmbeddedPiAgentMock.mock.calls[0]?.[0];
expect(call?.execOverrides).toEqual({
host: "node",
security: "allowlist",
ask: "always",
node: "worker-alpha",
});
});
});
it("prefers standalone inline exec directives over per-agent exec defaults on the next live run", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValue(makeEmbeddedTextResult("done"));
await getReplyFromConfig(
{
Body: "/exec host=auto",
From: "+1004",
To: "+2000",
CommandAuthorized: true,
},
{},
makeAgentExecConfig(home),
);
runEmbeddedPiAgentMock.mockClear();
await getReplyFromConfig(
{
Body: "run a command",
From: "+1004",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1004",
},
{},
makeAgentExecConfig(home),
);
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
const call = runEmbeddedPiAgentMock.mock.calls[0]?.[0];
expect(call?.execOverrides).toEqual({
host: "auto",
security: "allowlist",
ask: "always",
node: "worker-alpha",
});
});
});
it("prefers persisted session exec overrides over per-agent exec defaults", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValue(makeEmbeddedTextResult("done"));
await fs.writeFile(
sessionStorePath(home),
JSON.stringify({
[MAIN_SESSION_KEY]: {
sessionId: "main",
updatedAt: Date.now(),
execHost: "auto",
},
}),
"utf-8",
);
await getReplyFromConfig(
{
Body: "run a command",
From: "+1004",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1004",
},
{},
makeAgentExecConfig(home),
);
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
const call = runEmbeddedPiAgentMock.mock.calls[0]?.[0];
expect(call?.execOverrides).toEqual({
host: "auto",
security: "allowlist",
ask: "always",
node: "worker-alpha",
});
});
});
it("replaces a prior deny override with newer exec settings on later turns", async () => {
await withTempHome(async (home) => {
runEmbeddedPiAgentMock.mockResolvedValue(makeEmbeddedTextResult("done"));
await getReplyFromConfig(
{
Body: "/exec host=gateway security=deny ask=off",
From: "+1004",
To: "+2000",
CommandAuthorized: true,
},
{},
makeAgentExecConfig(home),
);
await getReplyFromConfig(
{
Body: "/exec host=gateway security=full ask=always",
From: "+1004",
To: "+2000",
CommandAuthorized: true,
},
{},
makeAgentExecConfig(home),
);
runEmbeddedPiAgentMock.mockClear();
await getReplyFromConfig(
{
Body: "run a command",
From: "+1004",
To: "+2000",
Provider: "whatsapp",
SenderE164: "+1004",
},
{},
makeAgentExecConfig(home),
);
expect(runEmbeddedPiAgentMock).toHaveBeenCalledOnce();
const call = runEmbeddedPiAgentMock.mock.calls[0]?.[0];
expect(call?.execOverrides).toEqual({
host: "gateway",
security: "full",
ask: "always",
node: "worker-alpha",
});
});
});
});