import type { AgentTool } from "@mariozechner/pi-agent-core"; import { Type } from "@sinclair/typebox"; import { mkdir, writeFile } from "fs/promises"; import { dirname } from "path"; import { resolveToCwd } from "./path-utils.js"; const writeSchema = Type.Object({ path: Type.String({ description: "Path to the file to write (relative or absolute)" }), content: Type.String({ description: "Content to write to the file" }), }); export function createWriteTool(cwd: string): AgentTool { return { name: "write", label: "write", description: "Write content to a file. Creates the file if it doesn't exist, overwrites if it does. Automatically creates parent directories.", parameters: writeSchema, execute: async ( _toolCallId: string, { path, content }: { path: string; content: string }, signal?: AbortSignal, ) => { const absolutePath = resolveToCwd(path, cwd); const dir = dirname(absolutePath); return new Promise<{ content: Array<{ type: "text"; text: string }>; details: undefined }>( (resolve, reject) => { // Check if already aborted if (signal?.aborted) { reject(new Error("Operation aborted")); return; } let aborted = false; // Set up abort handler const onAbort = () => { aborted = true; reject(new Error("Operation aborted")); }; if (signal) { signal.addEventListener("abort", onAbort, { once: true }); } // Perform the write operation (async () => { try { // Create parent directories if needed await mkdir(dir, { recursive: true }); // Check if aborted before writing if (aborted) { return; } // Write the file await writeFile(absolutePath, content, "utf-8"); // Check if aborted after writing if (aborted) { return; } // Clean up abort handler if (signal) { signal.removeEventListener("abort", onAbort); } resolve({ content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }], details: undefined, }); } catch (error: any) { // Clean up abort handler if (signal) { signal.removeEventListener("abort", onAbort); } if (!aborted) { reject(error); } } })(); }, ); }, }; } /** Default write tool using process.cwd() - for backwards compatibility */ export const writeTool = createWriteTool(process.cwd());