fix(agents): include SOUL.md, IDENTITY.md, USER.md in subagent/cron bootstrap allowlist

Subagent and isolated cron sessions only loaded AGENTS.md and TOOLS.md,
causing subagents to lose their role personality, identity, and user
preferences. Expand MINIMAL_BOOTSTRAP_ALLOWLIST to include the three
missing identity files.

Closes #24852

(cherry picked from commit c33377150e)
This commit is contained in:
root
2026-02-24 10:35:10 +08:00
committed by Peter Steinberger
parent 9d3bd50990
commit 8d2035633b
3 changed files with 63 additions and 3 deletions

View File

@@ -11,8 +11,10 @@ import {
DEFAULT_TOOLS_FILENAME,
DEFAULT_USER_FILENAME,
ensureAgentWorkspace,
filterBootstrapFilesForSession,
loadWorkspaceBootstrapFiles,
resolveDefaultAgentWorkspaceDir,
type WorkspaceBootstrapFile,
} from "./workspace.js";
describe("resolveDefaultAgentWorkspaceDir", () => {
@@ -141,3 +143,52 @@ describe("loadWorkspaceBootstrapFiles", () => {
expect(getMemoryEntries(files)).toHaveLength(0);
});
});
describe("filterBootstrapFilesForSession", () => {
const mockFiles: WorkspaceBootstrapFile[] = [
{ name: "AGENTS.md", path: "/w/AGENTS.md", content: "", missing: false },
{ name: "SOUL.md", path: "/w/SOUL.md", content: "", missing: false },
{ name: "TOOLS.md", path: "/w/TOOLS.md", content: "", missing: false },
{ name: "IDENTITY.md", path: "/w/IDENTITY.md", content: "", missing: false },
{ name: "USER.md", path: "/w/USER.md", content: "", missing: false },
{ name: "HEARTBEAT.md", path: "/w/HEARTBEAT.md", content: "", missing: false },
{ name: "BOOTSTRAP.md", path: "/w/BOOTSTRAP.md", content: "", missing: false },
{ name: "MEMORY.md", path: "/w/MEMORY.md", content: "", missing: false },
];
it("returns all files for main session (no sessionKey)", () => {
const result = filterBootstrapFilesForSession(mockFiles);
expect(result).toHaveLength(mockFiles.length);
});
it("returns all files for normal (non-subagent, non-cron) session key", () => {
const result = filterBootstrapFilesForSession(mockFiles, "agent:default:chat:main");
expect(result).toHaveLength(mockFiles.length);
});
it("filters to allowlist for subagent sessions", () => {
const result = filterBootstrapFilesForSession(mockFiles, "agent:default:subagent:task-1");
const names = result.map((f) => f.name);
expect(names).toContain("AGENTS.md");
expect(names).toContain("TOOLS.md");
expect(names).toContain("SOUL.md");
expect(names).toContain("IDENTITY.md");
expect(names).toContain("USER.md");
expect(names).not.toContain("HEARTBEAT.md");
expect(names).not.toContain("BOOTSTRAP.md");
expect(names).not.toContain("MEMORY.md");
});
it("filters to allowlist for cron sessions", () => {
const result = filterBootstrapFilesForSession(mockFiles, "agent:default:cron:daily-check");
const names = result.map((f) => f.name);
expect(names).toContain("AGENTS.md");
expect(names).toContain("TOOLS.md");
expect(names).toContain("SOUL.md");
expect(names).toContain("IDENTITY.md");
expect(names).toContain("USER.md");
expect(names).not.toContain("HEARTBEAT.md");
expect(names).not.toContain("BOOTSTRAP.md");
expect(names).not.toContain("MEMORY.md");
});
});

View File

@@ -494,7 +494,13 @@ export async function loadWorkspaceBootstrapFiles(dir: string): Promise<Workspac
return result;
}
const MINIMAL_BOOTSTRAP_ALLOWLIST = new Set([DEFAULT_AGENTS_FILENAME, DEFAULT_TOOLS_FILENAME]);
const MINIMAL_BOOTSTRAP_ALLOWLIST = new Set([
DEFAULT_AGENTS_FILENAME,
DEFAULT_TOOLS_FILENAME,
DEFAULT_SOUL_FILENAME,
DEFAULT_IDENTITY_FILENAME,
DEFAULT_USER_FILENAME,
]);
export function filterBootstrapFilesForSession(
files: WorkspaceBootstrapFile[],

View File

@@ -92,7 +92,10 @@ describe("bootstrap-extra-files hook", () => {
const event = createHookEvent("agent", "bootstrap", "agent:main:subagent:abc", context);
await handler(event);
expect(context.bootstrapFiles.map((f) => f.name).toSorted()).toEqual(["AGENTS.md", "TOOLS.md"]);
expect(context.bootstrapFiles.map((f) => f.name).toSorted()).toEqual([
"AGENTS.md",
"SOUL.md",
"TOOLS.md",
]);
});
});