Improve instructions bundle mode switching

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
dotta
2026-03-18 08:10:36 -05:00
parent 5252568825
commit 154a4a7ac1
5 changed files with 259 additions and 41 deletions

View File

@@ -103,6 +103,7 @@ describe("agent instructions bundle routes", () => {
companyId: "company-1",
mode: "managed",
rootPath: "/tmp/agent-1",
managedRootPath: "/tmp/agent-1",
entryFile: "AGENTS.md",
resolvedEntryPath: "/tmp/agent-1/AGENTS.md",
editable: true,
@@ -161,6 +162,7 @@ describe("agent instructions bundle routes", () => {
expect(res.body).toMatchObject({
mode: "managed",
rootPath: "/tmp/agent-1",
managedRootPath: "/tmp/agent-1",
entryFile: "AGENTS.md",
});
expect(mockAgentInstructionsService.getBundle).toHaveBeenCalled();

View File

@@ -0,0 +1,123 @@
import fs from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { afterEach, describe, expect, it } from "vitest";
import { agentInstructionsService } from "../services/agent-instructions.js";
type TestAgent = {
id: string;
companyId: string;
name: string;
adapterConfig: Record<string, unknown>;
};
async function makeTempDir(prefix: string) {
return fs.mkdtemp(path.join(os.tmpdir(), prefix));
}
function makeAgent(adapterConfig: Record<string, unknown>): TestAgent {
return {
id: "agent-1",
companyId: "company-1",
name: "Agent 1",
adapterConfig,
};
}
describe("agent instructions service", () => {
const originalPaperclipHome = process.env.PAPERCLIP_HOME;
const originalPaperclipInstanceId = process.env.PAPERCLIP_INSTANCE_ID;
const cleanupDirs = new Set<string>();
afterEach(async () => {
if (originalPaperclipHome === undefined) delete process.env.PAPERCLIP_HOME;
else process.env.PAPERCLIP_HOME = originalPaperclipHome;
if (originalPaperclipInstanceId === undefined) delete process.env.PAPERCLIP_INSTANCE_ID;
else process.env.PAPERCLIP_INSTANCE_ID = originalPaperclipInstanceId;
await Promise.all([...cleanupDirs].map(async (dir) => {
await fs.rm(dir, { recursive: true, force: true });
cleanupDirs.delete(dir);
}));
});
it("copies the existing bundle into the managed root when switching to managed mode", async () => {
const paperclipHome = await makeTempDir("paperclip-agent-instructions-home-");
const externalRoot = await makeTempDir("paperclip-agent-instructions-external-");
cleanupDirs.add(paperclipHome);
cleanupDirs.add(externalRoot);
process.env.PAPERCLIP_HOME = paperclipHome;
process.env.PAPERCLIP_INSTANCE_ID = "test-instance";
await fs.writeFile(path.join(externalRoot, "AGENTS.md"), "# External Agent\n", "utf8");
await fs.mkdir(path.join(externalRoot, "docs"), { recursive: true });
await fs.writeFile(path.join(externalRoot, "docs", "TOOLS.md"), "## Tools\n", "utf8");
const svc = agentInstructionsService();
const agent = makeAgent({
instructionsBundleMode: "external",
instructionsRootPath: externalRoot,
instructionsEntryFile: "AGENTS.md",
instructionsFilePath: path.join(externalRoot, "AGENTS.md"),
});
const result = await svc.updateBundle(agent, { mode: "managed" });
expect(result.bundle.mode).toBe("managed");
expect(result.bundle.managedRootPath).toBe(
path.join(
paperclipHome,
"instances",
"test-instance",
"companies",
"company-1",
"agents",
"agent-1",
"instructions",
),
);
expect(result.bundle.files.map((file) => file.path)).toEqual(["AGENTS.md", "docs/TOOLS.md"]);
await expect(fs.readFile(path.join(result.bundle.managedRootPath, "AGENTS.md"), "utf8")).resolves.toBe("# External Agent\n");
await expect(fs.readFile(path.join(result.bundle.managedRootPath, "docs", "TOOLS.md"), "utf8")).resolves.toBe("## Tools\n");
});
it("creates the target entry file when switching to a new external root", async () => {
const paperclipHome = await makeTempDir("paperclip-agent-instructions-home-");
const managedRoot = path.join(
paperclipHome,
"instances",
"test-instance",
"companies",
"company-1",
"agents",
"agent-1",
"instructions",
);
const externalRoot = await makeTempDir("paperclip-agent-instructions-new-external-");
cleanupDirs.add(paperclipHome);
cleanupDirs.add(externalRoot);
process.env.PAPERCLIP_HOME = paperclipHome;
process.env.PAPERCLIP_INSTANCE_ID = "test-instance";
await fs.mkdir(managedRoot, { recursive: true });
await fs.writeFile(path.join(managedRoot, "AGENTS.md"), "# Managed Agent\n", "utf8");
const svc = agentInstructionsService();
const agent = makeAgent({
instructionsBundleMode: "managed",
instructionsRootPath: managedRoot,
instructionsEntryFile: "AGENTS.md",
instructionsFilePath: path.join(managedRoot, "AGENTS.md"),
});
const result = await svc.updateBundle(agent, {
mode: "external",
rootPath: externalRoot,
entryFile: "docs/AGENTS.md",
});
expect(result.bundle.mode).toBe("external");
expect(result.bundle.rootPath).toBe(externalRoot);
await expect(fs.readFile(path.join(externalRoot, "docs", "AGENTS.md"), "utf8")).resolves.toBe("# Managed Agent\n");
});
});