diff --git a/src/index.ts b/src/index.ts index 6bcb68d..509891d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,4 @@ +import { randomUUID } from "node:crypto"; import { spawn } from "node:child_process"; import { mkdir, writeFile } from "node:fs/promises"; import { join } from "node:path"; @@ -252,12 +253,13 @@ function spawnCommand(command: ParsedCommand, timeoutMs: number): Promise): Promise { - await mkdir(artifactDir, { recursive: true }); - const resultPath = join(artifactDir, "result.json"); + const invocationDir = join(artifactDir, randomUUID()); + await mkdir(invocationDir, { recursive: true }); + const resultPath = join(invocationDir, "result.json"); const resultBytes = Buffer.from(JSON.stringify(payload, null, 2)); await writeFile(resultPath, resultBytes); const artifacts = [{ uri: resultPath, kind: "json", contentType: "application/json", sizeBytes: resultBytes.byteLength }]; - await writeFile(join(artifactDir, "manifest.json"), JSON.stringify({ artifacts }, null, 2)); + await writeFile(join(invocationDir, "manifest.json"), JSON.stringify({ artifacts }, null, 2)); return artifacts; } diff --git a/test/worker.test.ts b/test/worker.test.ts index 9ec593d..5a9434d 100644 --- a/test/worker.test.ts +++ b/test/worker.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import { mkdtemp, readFile, rm } from "node:fs/promises"; -import { join } from "node:path"; +import { dirname, join } from "node:path"; import { tmpdir } from "node:os"; import { runAgentDispatchWorkerTask, type AgentFrameworkAdapter } from "../src/index.js"; @@ -13,7 +13,20 @@ describe("worker contract", () => { expect(result.events[0].type).toBe("task.progress"); expect(result.events.some((event) => event.type === "task.heartbeat")).toBe(true); expect(result.artifacts[0]).toMatchObject({ kind: "json", contentType: "application/json" }); - await expect(readFile(join(artifactDir, "manifest.json"), "utf8")).resolves.toContain("result.json"); + await expect(readFile(join(dirname(result.artifacts[0].uri), "manifest.json"), "utf8")).resolves.toContain("result.json"); + await rm(artifactDir, { recursive: true, force: true }); + }); + + it("writes per-invocation artifact paths without collisions", async () => { + const artifactDir = await mkdtemp(join(tmpdir(), "agentdispatch-worker-")); + const first = await runAgentDispatchWorkerTask({ taskType: "agent.run", input: { instruction: "first" } }, { artifactDir }); + const second = await runAgentDispatchWorkerTask({ taskType: "agent.run", input: { instruction: "second" } }, { artifactDir }); + + expect(first.artifacts[0].uri).not.toBe(second.artifacts[0].uri); + await expect(readFile(first.artifacts[0].uri, "utf8")).resolves.toContain("first"); + await expect(readFile(second.artifacts[0].uri, "utf8")).resolves.toContain("second"); + await expect(readFile(join(dirname(first.artifacts[0].uri), "manifest.json"), "utf8")).resolves.toContain(first.artifacts[0].uri); + await expect(readFile(join(dirname(second.artifacts[0].uri), "manifest.json"), "utf8")).resolves.toContain(second.artifacts[0].uri); await rm(artifactDir, { recursive: true, force: true }); });