import type { AgentTool } from "@mariozechner/pi-agent-core"; import { Type } from "@sinclair/typebox"; import type { Executor } from "../sandbox.js"; const writeSchema = Type.Object({ label: Type.String({ description: "Brief description of what you're writing (shown to user)" }), 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(executor: Executor): 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 }: { label: string; path: string; content: string }, signal?: AbortSignal, ) => { // Create parent directories and write file using heredoc const dir = path.includes("/") ? path.substring(0, path.lastIndexOf("/")) : "."; // Use printf to handle content with special characters, pipe to file // This avoids issues with heredoc and special characters const cmd = `mkdir -p ${shellEscape(dir)} && printf '%s' ${shellEscape(content)} > ${shellEscape(path)}`; const result = await executor.exec(cmd, { signal }); if (result.code !== 0) { throw new Error(result.stderr || `Failed to write file: ${path}`); } return { content: [{ type: "text", text: `Successfully wrote ${content.length} bytes to ${path}` }], details: undefined, }; }, }; } function shellEscape(s: string): string { return `'${s.replace(/'/g, "'\\''")}'`; }