mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-12 09:41:11 +00:00
test(auto-reply): speed up reply prompt tests
This commit is contained in:
@@ -1,91 +1,30 @@
|
||||
import path from "node:path";
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
createReplyRuntimeMocks,
|
||||
installReplyRuntimeMocks,
|
||||
makeEmbeddedTextResult,
|
||||
resetReplyRuntimeMocks,
|
||||
} from "./reply.test-harness.js";
|
||||
|
||||
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
|
||||
const agentMocks = createReplyRuntimeMocks();
|
||||
|
||||
installReplyRuntimeMocks(agentMocks);
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(
|
||||
async (home) => {
|
||||
agentMocks.runEmbeddedPiAgent.mockClear();
|
||||
return await fn(home);
|
||||
},
|
||||
{
|
||||
env: {
|
||||
OPENCLAW_BUNDLED_SKILLS_DIR: (home) => path.join(home, "bundled-skills"),
|
||||
},
|
||||
prefix: "openclaw-media-note-",
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
function makeCfg(home: string) {
|
||||
return {
|
||||
agents: {
|
||||
defaults: {
|
||||
model: "anthropic/claude-opus-4-6",
|
||||
workspace: path.join(home, "openclaw"),
|
||||
},
|
||||
},
|
||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||
session: { store: path.join(home, "sessions.json") },
|
||||
} as unknown as OpenClawConfig;
|
||||
}
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { finalizeInboundContext } from "./reply/inbound-context.js";
|
||||
import { buildReplyPromptBodies } from "./reply/prompt-prelude.js";
|
||||
|
||||
describe("getReplyFromConfig media note plumbing", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
|
||||
resetReplyRuntimeMocks(agentMocks);
|
||||
({ getReplyFromConfig } = await import("./reply.js"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("includes all MediaPaths in the agent prompt", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
let seenPrompt: string | undefined;
|
||||
agentMocks.runEmbeddedPiAgent.mockImplementation(async (params) => {
|
||||
seenPrompt = params.prompt;
|
||||
return makeEmbeddedTextResult("ok");
|
||||
});
|
||||
|
||||
const cfg = makeCfg(home);
|
||||
const res = await getReplyFromConfig(
|
||||
{
|
||||
Body: "hello",
|
||||
From: "+1001",
|
||||
To: "+2000",
|
||||
MediaPaths: ["/tmp/a.png", "/tmp/b.png"],
|
||||
MediaUrls: ["/tmp/a.png", "/tmp/b.png"],
|
||||
},
|
||||
{},
|
||||
cfg,
|
||||
);
|
||||
|
||||
const text = Array.isArray(res) ? res[0]?.text : res?.text;
|
||||
expect(text).toBe("ok");
|
||||
expect(seenPrompt).toBeTruthy();
|
||||
expect(seenPrompt).toContain("[media attached: 2 files]");
|
||||
const idxA = seenPrompt?.indexOf("[media attached 1/2: /tmp/a.png");
|
||||
const idxB = seenPrompt?.indexOf("[media attached 2/2: /tmp/b.png");
|
||||
expect(typeof idxA).toBe("number");
|
||||
expect(typeof idxB).toBe("number");
|
||||
expect((idxA ?? -1) >= 0).toBe(true);
|
||||
expect((idxB ?? -1) >= 0).toBe(true);
|
||||
expect((idxA ?? 0) < (idxB ?? 0)).toBe(true);
|
||||
it("includes all MediaPaths in the agent prompt", () => {
|
||||
const sessionCtx = finalizeInboundContext({
|
||||
Body: "hello",
|
||||
BodyForAgent: "hello",
|
||||
From: "+1001",
|
||||
To: "+2000",
|
||||
MediaPaths: ["/tmp/a.png", "/tmp/b.png"],
|
||||
MediaUrls: ["/tmp/a.png", "/tmp/b.png"],
|
||||
});
|
||||
const prompt = buildReplyPromptBodies({
|
||||
ctx: sessionCtx,
|
||||
sessionCtx,
|
||||
effectiveBaseBody: sessionCtx.BodyForAgent,
|
||||
prefixedBody: sessionCtx.BodyForAgent,
|
||||
}).prefixedCommandBody;
|
||||
|
||||
expect(prompt).toContain("[media attached: 2 files]");
|
||||
const idxA = prompt.indexOf("[media attached 1/2: /tmp/a.png");
|
||||
const idxB = prompt.indexOf("[media attached 2/2: /tmp/b.png");
|
||||
expect(idxA).toBeGreaterThanOrEqual(0);
|
||||
expect(idxB).toBeGreaterThanOrEqual(0);
|
||||
expect(idxA).toBeLessThan(idxB);
|
||||
expect(prompt).toContain("hello");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,67 +1,42 @@
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import {
|
||||
createReplyRuntimeMocks,
|
||||
createTempHomeHarness,
|
||||
installReplyRuntimeMocks,
|
||||
makeEmbeddedTextResult,
|
||||
makeReplyConfig,
|
||||
resetReplyRuntimeMocks,
|
||||
} from "./reply.test-harness.js";
|
||||
let getReplyFromConfig: typeof import("./reply.js").getReplyFromConfig;
|
||||
const agentMocks = createReplyRuntimeMocks();
|
||||
|
||||
const { withTempHome } = createTempHomeHarness({ prefix: "openclaw-rawbody-" });
|
||||
|
||||
installReplyRuntimeMocks(agentMocks);
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { parseInlineDirectives } from "./reply/directive-handling.parse.js";
|
||||
import { finalizeInboundContext } from "./reply/inbound-context.js";
|
||||
import { buildInboundUserContextPrefix } from "./reply/inbound-meta.js";
|
||||
import { buildReplyPromptBodies } from "./reply/prompt-prelude.js";
|
||||
|
||||
describe("RawBody directive parsing", () => {
|
||||
beforeEach(async () => {
|
||||
vi.resetModules();
|
||||
vi.stubEnv("OPENCLAW_TEST_FAST", "1");
|
||||
resetReplyRuntimeMocks(agentMocks);
|
||||
({ getReplyFromConfig } = await import("./reply.js"));
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("handles directives and history in the prompt", async () => {
|
||||
await withTempHome(async (home) => {
|
||||
agentMocks.runEmbeddedPiAgent.mockResolvedValue(makeEmbeddedTextResult("ok"));
|
||||
|
||||
const groupMessageCtx = {
|
||||
Body: "/think:high status please",
|
||||
BodyForAgent: "/think:high status please",
|
||||
RawBody: "/think:high status please",
|
||||
InboundHistory: [{ sender: "Peter", body: "hello", timestamp: 1700000000000 }],
|
||||
From: "+1222",
|
||||
To: "+1222",
|
||||
ChatType: "group",
|
||||
GroupSubject: "Ops",
|
||||
SenderName: "Jake McInteer",
|
||||
SenderE164: "+6421807830",
|
||||
CommandAuthorized: true,
|
||||
};
|
||||
|
||||
const res = await getReplyFromConfig(
|
||||
groupMessageCtx,
|
||||
{},
|
||||
makeReplyConfig(home) as OpenClawConfig,
|
||||
);
|
||||
|
||||
const text = Array.isArray(res) ? res[0]?.text : res?.text;
|
||||
expect(text).toBe("ok");
|
||||
expect(agentMocks.runEmbeddedPiAgent).toHaveBeenCalledOnce();
|
||||
const prompt =
|
||||
(agentMocks.runEmbeddedPiAgent.mock.calls[0]?.[0] as { prompt?: string } | undefined)
|
||||
?.prompt ?? "";
|
||||
expect(prompt).toContain("Chat history since last reply (untrusted, for context):");
|
||||
expect(prompt).toContain('"sender": "Peter"');
|
||||
expect(prompt).toContain('"body": "hello"');
|
||||
expect(prompt).toContain("status please");
|
||||
expect(prompt).not.toContain("/think:high");
|
||||
it("handles directives and history in the prompt", () => {
|
||||
const sessionCtx = finalizeInboundContext({
|
||||
Body: "/think:high status please",
|
||||
BodyForAgent: "/think:high status please",
|
||||
BodyForCommands: "/think:high status please",
|
||||
RawBody: "/think:high status please",
|
||||
InboundHistory: [{ sender: "Peter", body: "hello", timestamp: 1700000000000 }],
|
||||
From: "+1222",
|
||||
To: "+1222",
|
||||
ChatType: "group",
|
||||
GroupSubject: "Ops",
|
||||
SenderName: "Jake McInteer",
|
||||
SenderE164: "+6421807830",
|
||||
CommandAuthorized: true,
|
||||
});
|
||||
const directives = parseInlineDirectives(sessionCtx.BodyForCommands ?? "", {
|
||||
allowStatusDirective: true,
|
||||
});
|
||||
const prefixedBody = [buildInboundUserContextPrefix(sessionCtx), directives.cleaned]
|
||||
.filter(Boolean)
|
||||
.join("\n\n");
|
||||
const prompt = buildReplyPromptBodies({
|
||||
ctx: sessionCtx,
|
||||
sessionCtx: { ...sessionCtx, BodyStripped: directives.cleaned },
|
||||
effectiveBaseBody: prefixedBody,
|
||||
prefixedBody,
|
||||
}).prefixedCommandBody;
|
||||
|
||||
expect(prompt).toContain("Chat history since last reply (untrusted, for context):");
|
||||
expect(prompt).toContain('"sender": "Peter"');
|
||||
expect(prompt).toContain('"body": "hello"');
|
||||
expect(prompt).toContain("status please");
|
||||
expect(prompt).not.toContain("/think:high");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user