feat(FN-1085): align agent routing and runtime contracts

- Harden core AgentStore lifecycle behavior and heartbeat runtime integration paths
- Align dashboard agent APIs, server routes, and agent UI flows with the updated contract
- Tighten CLI agent/message command routing and validate payload handling semantics
- Expand test coverage across core, dashboard, engine, and CLI for route, heartbeat, and instruction regressions
This commit is contained in:
gsxdsm
2026-04-08 00:44:33 -07:00
parent 92e6aa2b49
commit 07697b2f5b
19 changed files with 942 additions and 169 deletions

View File

@@ -66,13 +66,13 @@ describe("resolveAgentInstructions", () => {
expect(result).toBe("# Custom Instructions\nUse strict TypeScript.");
});
it("returns file contents when instructionsPath is absolute", async () => {
it("ignores absolute instructionsPath for safety", async () => {
const filePath = join(testDir, "absolute-instructions.md");
await writeFile(filePath, "Absolute path instructions.");
const agent = makeAgent({ instructionsPath: filePath });
const agent = makeAgent({ instructionsPath: filePath, instructionsText: "Inline fallback." });
const result = await resolveAgentInstructions(agent, testDir);
expect(result).toBe("Absolute path instructions.");
expect(result).toBe("Inline fallback.");
});
it("concatenates instructionsText and file contents with double newline", async () => {
@@ -136,6 +136,47 @@ describe("resolveAgentInstructions", () => {
const result = await resolveAgentInstructions(agent, testDir);
expect(result).toBe("Text only.");
});
it("rejects path traversal in instructionsPath", async () => {
const agent = makeAgent({
instructionsText: "Safe inline.",
instructionsPath: "../secrets.md",
});
const result = await resolveAgentInstructions(agent, testDir);
expect(result).toBe("Safe inline.");
});
it("rejects non-markdown instruction files", async () => {
const txtPath = join(testDir, "instructions.txt");
await writeFile(txtPath, "should not be read");
const agent = makeAgent({
instructionsText: "Inline only.",
instructionsPath: "instructions.txt",
});
const result = await resolveAgentInstructions(agent, testDir);
expect(result).toBe("Inline only.");
});
it("truncates oversized inline instructions", async () => {
const oversized = "x".repeat(50010);
const agent = makeAgent({ instructionsText: oversized });
const result = await resolveAgentInstructions(agent, testDir);
expect(result.length).toBe(50000);
});
it("truncates oversized instructions files", async () => {
const filePath = join(testDir, "large.md");
await writeFile(filePath, "y".repeat(50020));
const agent = makeAgent({ instructionsPath: "large.md" });
const result = await resolveAgentInstructions(agent, testDir);
expect(result.length).toBe(50000);
});
});
describe("buildSystemPromptWithInstructions", () => {