feat(FN-4045): surface and handle delegate task collision errors

Added delegate collision detection and error surfacing across the task creation and delegation pipeline. The core store now throws a typed `DelegateCollisionError` when `createTask` encounters a duplicate task ID, the engine's `delegate_task` tool propagates these errors with context, and the CLI ex

Fusion-Task-Id: FN-4045
This commit is contained in:
Fusion
2026-05-11 22:58:23 -07:00
committed by gsxdsm
parent c6edf5f49f
commit 7b5ec3d063
7 changed files with 194 additions and 91 deletions

View File

@@ -245,4 +245,23 @@ describe.skipIf(!SHOULD_RUN_EXTENSION_INTEGRATION)("built fn pi extension integr
expect(rejected.isError).toBe(true);
expect(rejected.content[0].text).toContain("ephemeral/runtime agent");
});
it("returns explicit error when fn_delegate_task hits task-id collision", async () => {
const agent = await seedAgent(tmpDir, { name: "release-agent" });
const delegateTool = api.tools.get("fn_delegate_task")!;
const createSpy = vi.spyOn(TaskStore.prototype, "createTask").mockRejectedValueOnce(new Error("Task ID already exists: FN-001"));
const result = await delegateTool.execute(
"delegate-collision",
{ agent_id: agent.id, description: "collision task" },
undefined,
undefined,
makeCtx(tmpDir),
);
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain("Task ID already exists: FN-001");
expect(result.details.error).toContain("Task ID already exists: FN-001");
createSpy.mockRestore();
});
});

View File

@@ -1474,6 +1474,24 @@ describe("fn pi extension (runnable structured-output regression slice)", () =>
expect(result.content[0].text).toContain(ephemeralId);
});
it("returns explicit collision error when fn_task_create hits an existing task id", async () => {
const createSpy = vi.spyOn(TaskStore.prototype, "createTask").mockRejectedValueOnce(new Error("Task ID already exists: FN-001"));
const createTool = api.tools.get("fn_task_create")!;
const result = await createTool.execute(
"create-collision",
{ description: "collision task" },
undefined,
undefined,
makeCtx(tmpDir),
);
expect(result.isError).toBe(true);
expect(result.content[0].text).toContain("Task ID already exists: FN-001");
expect(result.details.error).toContain("Task ID already exists: FN-001");
createSpy.mockRestore();
});
it("fn_task_create allows durable engineer assignment for implementation tasks", async () => {
const agentStore = new AgentStore({ rootDir: join(tmpDir, ".fusion") });
await agentStore.init();