feat: Implement write file tool (#2)

* feat: Implement write file tool

* cr
This commit is contained in:
Brace Sproul 2025-05-21 18:21:20 -07:00 • committed by GitHub
parent 0830c9c3e8
commit 5f95ff2a01
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 136 additions and 21 deletions

View file

@ -1,21 +0,0 @@
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { applyPatch } from "diff";
const applyDiffToolSchema = z.object({
diff: z.string().describe("The diff to apply"),
file_path: z.string().describe("The file path to apply the diff to"),
});
export const applyDiffTool = tool(
(input) => {
const { diff, file_path } = input;
const res = applyPatch(file_path, diff);
return `Successfully applied diff to \`${file_path}\``;
},
{
name: "apply_diff",
description: "Applies a diff to a file.",
schema: applyDiffToolSchema,
},
);

52
src/tools/write-file.ts Normal file
View file

@ -0,0 +1,52 @@
import { tool } from "@langchain/core/tools";
import { z } from "zod";
import { applyPatch } from "diff";
import { GraphConfig } from "../types.js";
import { Sandbox } from "@e2b/code-interpreter";
import { readFile, writeFile } from "../utils/read-write.js";
const writeFileToolSchema = z.object({
diff: z.string().describe("The diff to apply"),
file_path: z.string().describe("The file path to apply the diff to"),
});
export const writeFileTool = tool(
async (input, config: GraphConfig) => {
const { diff, file_path } = input;
const sessionId = config.configurable?.sandbox_session_id;
if (!sessionId) {
return "FAILED TO RUN COMMAND: No sandbox session ID provided";
}
const sandbox = await Sandbox.connect(sessionId);
const { success: readFileSuccess, output: readFileOutput } = await readFile(
sandbox,
file_path,
);
if (!readFileSuccess) {
return readFileOutput;
}
const patchedContent = applyPatch(readFileOutput, diff);
if (patchedContent === false) {
return `FAILED TO APPLY PATCH: The diff could not be applied to file '${file_path}'. This may be due to an invalid diff format or conflicting changes with the file's current content. Original content length: ${readFileOutput.length}, Diff: ${diff.substring(0, 100)}...`;
}
// TODO: Should we be committing every time we apply a diff?
const { success: writeFileSuccess, output: writeFileOutput } =
await writeFile(sandbox, file_path, patchedContent);
if (!writeFileSuccess) {
return writeFileOutput;
}
return `Successfully applied diff to \`${file_path}\` and saved changes.`;
},
{
name: "write_file",
description:
"Writes a file given a file path and diff content. Can be used to create or update files.",
schema: writeFileToolSchema,
},
);

84
src/utils/read-write.ts Normal file
View file

@ -0,0 +1,84 @@
import { Sandbox } from "@e2b/code-interpreter";
export async function readFile(
sandbox: Sandbox,
filePath: string,
): Promise<{
success: boolean;
output: string;
}> {
try {
const readOutput = await sandbox.commands.run(`cat "${filePath}"`);
if (readOutput.exitCode !== 0) {
console.error(
`Error reading file '${filePath}' from sandbox via cat:`,
readOutput,
);
return {
success: false,
output: `FAILED TO READ FILE from sandbox '${filePath}'. Exit code: ${readOutput.exitCode}.\nStderr: ${readOutput.stderr}.\nStdout: ${readOutput.stdout}`,
};
}
if (readOutput.stderr) {
console.warn(
`Stderr while reading file '${filePath}' from sandbox via cat: ${readOutput.stderr}`,
);
}
return {
success: true,
output: readOutput.stdout,
};
} catch (e: any) {
console.error(
`Exception while trying to read file '${filePath}' from sandbox via cat:`,
e,
);
return {
success: false,
output: `FAILED TO EXECUTE READ COMMAND for sandbox '${filePath}'. Error: ${(e as Error).message || String(e)}`,
};
}
}
export async function writeFile(
sandbox: Sandbox,
filePath: string,
content: string,
): Promise<{
success: boolean;
output: string;
}> {
try {
const writeCommand = `printf '%s' '${content}' > "${filePath}"`;
const writeOutput = await sandbox.commands.run(writeCommand);
if (writeOutput.exitCode !== 0) {
console.error(
`Error writing file '${filePath}' to sandbox via printf:`,
writeOutput,
);
return {
success: false,
output: `FAILED TO WRITE FILE to sandbox '${filePath}'. Exit code: ${writeOutput.exitCode}. Stderr: ${writeOutput.stderr}. Stdout: ${writeOutput.stdout}`,
};
}
if (writeOutput.stderr) {
console.warn(
`Stderr while writing file '${filePath}' to sandbox via printf: ${writeOutput.stderr}`,
);
}
return {
success: true,
output: `Successfully wrote file '${filePath}' to sandbox via printf.`,
};
} catch (e: any) {
console.error(
`Exception while trying to write file '${filePath}' to sandbox via printf:`,
e,
);
return {
success: false,
output: `FAILED TO EXECUTE WRITE COMMAND for sandbox '${filePath}'. Error: ${(e as Error).message || String(e)}`,
};
}
}