import { mkdir, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { fileURLToPath } from "node:url"; import { tmpdir } from "node:os"; import path from "node:path"; import { assistantMessage, getToolCallNames, getToolExecution, PiIntegrationTest, testArtifactsDir, text, toolCall, } from "pi-coding-agent-test"; import { afterEach, expect, test } from "vitest"; const workspaces: string[] = []; const toolNames = ["ls", "find", "grep", "read", "edit", "read", "write", "bash"] as const; const replayNotes = [ "// Generated by the comprehensive replay demo.", "// The source file above is a real TypeScript implementation from this package.", "export const replayDemoSummary = {", " source: \"src/live/pacing.ts\",", " tools: [\"ls\", \"find\", \"grep\", \"read\", \"edit\", \"write\", \"bash\"],", " purpose: \"Make every built-in Pi tool visible in one replay\",", "} as const;", "", ].join("\n"); afterEach(async () => { await Promise.all(workspaces.splice(0).map((directory) => rm(directory, { recursive: true, force: true }))); }); test("replays every built-in tool across a real TypeScript source file", async () => { const workspace = await mkdtemp(path.join(tmpdir(), "pi-coding-agent-test-replay-demo-")); workspaces.push(workspace); const sourcePath = fileURLToPath(new URL("../../src/live/pacing.ts", import.meta.url)); const targetPath = path.join(workspace, "src/live/pacing.ts"); await mkdir(path.dirname(targetPath), { recursive: true }); await writeFile(targetPath, await readFile(sourcePath, "utf8"), "utf8"); const result = await new PiIntegrationTest({ testName: "replay-demo", artifactsDir: testArtifactsDir(import.meta.filename), cwd: workspace, rawMode: false, tools: [...toolNames], conversation: [ assistantMessage([ toolCall({ id: "replay-ls", name: "ls", arguments: { path: "src/live", limit: 20 }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-find", name: "find", arguments: { path: "src", pattern: "*.ts", limit: 50 }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-grep", name: "grep", arguments: { path: "src/live/pacing.ts", pattern: "streamProfiles", context: 3, limit: 20, }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-read-before", name: "read", arguments: { path: "src/live/pacing.ts", offset: 1, limit: 180 }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-edit", name: "edit", arguments: { path: "src/live/pacing.ts", edits: [ { oldText: "const defaultStreamProfile = \"gpt-5.6-sol-xhigh\";", newText: [ "const defaultStreamProfile = \"gpt-5.6-sol-xhigh\";", "// The replay demo keeps the default pacing visible in the source.", ].join("\n"), }, { oldText: " outputTokensPerSecond: 68,", newText: [ " outputTokensPerSecond: 68,", " // Keep packet pacing and output speed easy to inspect.", ].join("\n"), }, { oldText: [ "function scheduleValue(value: string, profile: StreamProfile, random: Random): StreamSchedule", "{", " const characters = unicodeCharacters(value);", " const chunks: string[] = [];", ].join("\n"), newText: [ "function scheduleValue(value: string, profile: StreamProfile, random: Random): StreamSchedule", "{", " // Schedule each packet so replay preserves the progressive transition.", " const characters = unicodeCharacters(value);", " const chunks: string[] = [];", ].join("\n"), }, ], }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-read-after", name: "read", arguments: { path: "src/live/pacing.ts", offset: 1, limit: 220 }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-write", name: "write", arguments: { path: "src/live/replay-demo-summary.ts", content: replayNotes }, }), ], { stopReason: "toolUse" }), assistantMessage([ toolCall({ id: "replay-bash", name: "bash", arguments: { command: "wc -l src/live/pacing.ts src/live/replay-demo-summary.ts && grep -n \"replay demo\" src/live/pacing.ts", }, }), ], { stopReason: "toolUse" }), assistantMessage([text("The complete built-in-tool replay demo is finished.")]), ], }).run("Inspect, edit, write, and verify a real TypeScript pacing implementation with every built-in tool"); const editedSource = await readFile(targetPath, "utf8"); expect(editedSource).toContain("The replay demo keeps the default pacing visible"); expect(editedSource).toContain("Schedule each packet so replay preserves"); await expect(readFile(path.join(workspace, "src/live/replay-demo-summary.ts"), "utf8")).resolves.toBe(replayNotes); expect(getToolCallNames(result)).toEqual(toolNames); for (const toolName of toolNames) { const execution = getToolExecution(result, `replay-${toolName === "read" ? "read-before" : toolName}`); expect(execution.isError, `${toolName} failed`).toBe(false); } expect(getToolExecution(result, "replay-read-after").isError).toBe(false); expect(getToolExecution(result, "replay-write").isError).toBe(false); expect(getToolExecution(result, "replay-bash").isError).toBe(false); expect(result.tuiRenderedOutput).toContain("pacing.ts"); expect(result.tuiRenderedOutput).toContain("replay-demo-summary.ts"); expect(result.tuiRenderedOutput).toContain("The complete built-in-tool replay demo is finished."); });