mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-09-30 15:03:16 +00:00
feat: Implement write file tool (#2)
* feat: Implement write file tool * cr
This commit is contained in:
parent
0830c9c3e8
commit
5f95ff2a01
3 changed files with 136 additions and 21 deletions
|
|
@ -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
52
src/tools/write-file.ts
Normal 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
84
src/utils/read-write.ts
Normal 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)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue