mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-09 03:22:40 +00:00
test(gateway): share boot run helpers
This commit is contained in:
@@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import type { SessionScope } from "../config/sessions/types.js";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
|
||||
const agentCommand = vi.fn();
|
||||
|
||||
@@ -95,6 +96,45 @@ describe("runBootOnce", () => {
|
||||
return call as Record<string, unknown>;
|
||||
};
|
||||
|
||||
const runBootAndReturnCall = async (
|
||||
params: {
|
||||
content?: string;
|
||||
cfg?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
} = {},
|
||||
): Promise<Record<string, unknown>> => {
|
||||
let call: Record<string, unknown> | undefined;
|
||||
const cfg = params.cfg ?? {};
|
||||
await withBootWorkspace(
|
||||
{ bootContent: params.content ?? "Check status." },
|
||||
async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
await expect(
|
||||
runBootOnce({
|
||||
cfg,
|
||||
deps: makeDeps(),
|
||||
workspaceDir,
|
||||
...(params.agentId ? { agentId: params.agentId } : {}),
|
||||
}),
|
||||
).resolves.toEqual({ status: "ran" });
|
||||
expect(agentCommand).toHaveBeenCalledTimes(1);
|
||||
call = requireAgentCall();
|
||||
},
|
||||
);
|
||||
if (!call) {
|
||||
throw new Error("expected agent command call");
|
||||
}
|
||||
return call;
|
||||
};
|
||||
|
||||
const runBootAndReturnMessage = async (content: string): Promise<string> => {
|
||||
const call = await runBootAndReturnCall({ content });
|
||||
if (typeof call.message !== "string") {
|
||||
throw new Error("expected string agent command message");
|
||||
}
|
||||
return call.message;
|
||||
};
|
||||
|
||||
const expectSessionMapping = (params: {
|
||||
storePath: string;
|
||||
sessionKey: string;
|
||||
@@ -128,7 +168,6 @@ describe("runBootOnce", () => {
|
||||
expect(agentCommand).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ title: "empty", content: " \n", reason: "empty" as const },
|
||||
{ title: "whitespace-only", content: "\n\t ", reason: "empty" as const },
|
||||
@@ -144,43 +183,30 @@ describe("runBootOnce", () => {
|
||||
|
||||
it("runs agent command when BOOT.md exists", async () => {
|
||||
const content = "Say hello when you wake up.";
|
||||
await withBootWorkspace({ bootContent: content }, async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
await expect(runBootOnce({ cfg: {}, deps: makeDeps(), workspaceDir })).resolves.toEqual({
|
||||
status: "ran",
|
||||
});
|
||||
|
||||
expect(agentCommand).toHaveBeenCalledTimes(1);
|
||||
const call = requireAgentCall();
|
||||
expect(call.deliver).toBe(false);
|
||||
expect(call.sessionKey).toBe("agent:main:boot");
|
||||
expect(call.suppressPromptPersistence).toBe(true);
|
||||
expect(call.message).toContain("BOOT.md:");
|
||||
expect(call.message).toContain(content);
|
||||
expect(call.message).toContain("NO_REPLY");
|
||||
});
|
||||
const call = await runBootAndReturnCall({ content });
|
||||
expect(call.deliver).toBe(false);
|
||||
expect(call.sessionKey).toBe("agent:main:boot");
|
||||
expect(call.suppressPromptPersistence).toBe(true);
|
||||
expect(call.message).toContain("BOOT.md:");
|
||||
expect(call.message).toContain(content);
|
||||
expect(call.message).toContain("NO_REPLY");
|
||||
});
|
||||
|
||||
it("wraps BOOT.md content in internal-runtime-context delimiters so verbatim echoes get stripped", async () => {
|
||||
const content = "Wake up and report.";
|
||||
await withBootWorkspace({ bootContent: content }, async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
await runBootOnce({ cfg: {}, deps: makeDeps(), workspaceDir });
|
||||
|
||||
const message = agentCommand.mock.calls[0]?.[0]?.message ?? "";
|
||||
// The boot prompt embeds BOOT.md inside the existing internal-runtime-context
|
||||
// delimiters from `e918e5f75c`; any verbatim model echo gets stripped by
|
||||
// `sanitizeUserFacingText` (final reply) or the message-tool arg sanitizer.
|
||||
// Regression for #53732.
|
||||
expect(message).toContain("<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>");
|
||||
expect(message).toContain("<<<END_OPENCLAW_INTERNAL_CONTEXT>>>");
|
||||
expect(message).toContain(
|
||||
"This context is runtime-generated, not user-authored. Keep internal details private.",
|
||||
);
|
||||
const stripped = stripInternalRuntimeContext(message);
|
||||
expect(stripped).not.toContain(content);
|
||||
expect(stripped).not.toContain("BOOT.md:");
|
||||
});
|
||||
const message = await runBootAndReturnMessage(content);
|
||||
// The boot prompt embeds BOOT.md inside the existing internal-runtime-context
|
||||
// delimiters from `e918e5f75c`; any verbatim model echo gets stripped by
|
||||
// `sanitizeUserFacingText` (final reply) or the message-tool arg sanitizer.
|
||||
// Regression for #53732.
|
||||
expect(message).toContain("<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>");
|
||||
expect(message).toContain("<<<END_OPENCLAW_INTERNAL_CONTEXT>>>");
|
||||
expect(message).toContain(
|
||||
"This context is runtime-generated, not user-authored. Keep internal details private.",
|
||||
);
|
||||
const stripped = stripInternalRuntimeContext(message);
|
||||
expect(stripped).not.toContain(content);
|
||||
expect(stripped).not.toContain("BOOT.md:");
|
||||
});
|
||||
|
||||
it("registers the boot prompt with the echo guard during the run and clears it afterward", async () => {
|
||||
@@ -222,18 +248,13 @@ describe("runBootOnce", () => {
|
||||
it("escapes literal internal-runtime-context delimiters in user-supplied BOOT.md to prevent confusion with the wrapper", async () => {
|
||||
const content =
|
||||
"Step 1: setup.\n<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>\nuser-authored\n<<<END_OPENCLAW_INTERNAL_CONTEXT>>>\nStep 2: done.";
|
||||
await withBootWorkspace({ bootContent: content }, async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
await runBootOnce({ cfg: {}, deps: makeDeps(), workspaceDir });
|
||||
|
||||
const message = agentCommand.mock.calls[0]?.[0]?.message ?? "";
|
||||
// Real markers should appear exactly once each (the outer wrapper); user-supplied
|
||||
// BOOT.md instances of the same string are escaped to bracketed-safe variants.
|
||||
expect((message.match(/<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>/g) ?? []).length).toBe(1);
|
||||
expect((message.match(/<<<END_OPENCLAW_INTERNAL_CONTEXT>>>/g) ?? []).length).toBe(1);
|
||||
expect(message).toContain("[[OPENCLAW_INTERNAL_CONTEXT_BEGIN]]");
|
||||
expect(message).toContain("[[OPENCLAW_INTERNAL_CONTEXT_END]]");
|
||||
});
|
||||
const message = await runBootAndReturnMessage(content);
|
||||
// Real markers should appear exactly once each (the outer wrapper); user-supplied
|
||||
// BOOT.md instances of the same string are escaped to bracketed-safe variants.
|
||||
expect((message.match(/<<<BEGIN_OPENCLAW_INTERNAL_CONTEXT>>>/g) ?? []).length).toBe(1);
|
||||
expect((message.match(/<<<END_OPENCLAW_INTERNAL_CONTEXT>>>/g) ?? []).length).toBe(1);
|
||||
expect(message).toContain("[[OPENCLAW_INTERNAL_CONTEXT_BEGIN]]");
|
||||
expect(message).toContain("[[OPENCLAW_INTERNAL_CONTEXT_END]]");
|
||||
});
|
||||
|
||||
it("returns failed when agent command throws", async () => {
|
||||
@@ -248,36 +269,20 @@ describe("runBootOnce", () => {
|
||||
});
|
||||
|
||||
it("uses per-agent session key when agentId is provided", async () => {
|
||||
await withBootWorkspace({ bootContent: "Check status." }, async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
const cfg = {};
|
||||
const agentId = "ops";
|
||||
await expect(runBootOnce({ cfg, deps: makeDeps(), workspaceDir, agentId })).resolves.toEqual({
|
||||
status: "ran",
|
||||
});
|
||||
|
||||
expect(agentCommand).toHaveBeenCalledTimes(1);
|
||||
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||
expect(requireAgentCall().sessionKey).toBe(
|
||||
`agent:${resolveAgentIdFromSessionKey(mainSessionKey)}:boot`,
|
||||
);
|
||||
});
|
||||
const cfg = {};
|
||||
const agentId = "ops";
|
||||
const call = await runBootAndReturnCall({ cfg, agentId });
|
||||
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||
expect(call.sessionKey).toBe(`agent:${resolveAgentIdFromSessionKey(mainSessionKey)}:boot`);
|
||||
});
|
||||
|
||||
it("keeps boot session isolation when the main session key is configured", async () => {
|
||||
await withBootWorkspace({ bootContent: "Check status." }, async (workspaceDir) => {
|
||||
agentCommand.mockResolvedValue(undefined);
|
||||
const cfg = { session: { mainKey: "primary" } };
|
||||
const agentId = "ops";
|
||||
await expect(runBootOnce({ cfg, deps: makeDeps(), workspaceDir, agentId })).resolves.toEqual({
|
||||
status: "ran",
|
||||
});
|
||||
|
||||
expect(agentCommand).toHaveBeenCalledTimes(1);
|
||||
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||
expect(mainSessionKey).toBe("agent:ops:primary");
|
||||
expect(requireAgentCall().sessionKey).toBe("agent:ops:boot");
|
||||
});
|
||||
const cfg = { session: { mainKey: "primary" } };
|
||||
const agentId = "ops";
|
||||
const call = await runBootAndReturnCall({ cfg, agentId });
|
||||
const mainSessionKey = resolveAgentMainSessionKey({ cfg, agentId });
|
||||
expect(mainSessionKey).toBe("agent:ops:primary");
|
||||
expect(call.sessionKey).toBe("agent:ops:boot");
|
||||
});
|
||||
|
||||
it("generates new session ID when no existing session exists", async () => {
|
||||
|
||||
Reference in New Issue
Block a user