fix: Implement logger (#17)

* fix: Docs and scripts

* cr

* fix: better err handling

* cr

* cr

* fix writing

* fix types

* fix: Implement logger
This commit is contained in:
Brace Sproul 2025-05-24 14:38:14 -07:00 • committed by GitHub
parent 04b14cae32
commit 20c483f327
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 299 additions and 109 deletions

View file

@ -3,6 +3,9 @@ import { loadModel, Task } from "../utils/load-model.js";
import { shellTool, applyPatchTool } from "../tools/index.js";
import { formatPlanPrompt } from "../utils/plan-prompt.js";
import { pauseSandbox } from "../utils/sandbox.js";
import { createLogger, LogLevel } from "../utils/logger.js";
const logger = createLogger(LogLevel.INFO, "GenerateMessageNode");
const systemPrompt = `You are operating as a terminal-based agentic coding assistant built by LangChain. It wraps LLM models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful.
@ -81,10 +84,14 @@ export async function generateAction(
// No tool calls means the graph is going to end. Pause the sandbox.
let newSandboxSessionId: string | undefined;
if (!hasToolCalls && state.sandboxSessionId) {
console.log("No tool calls found. Pausing sandbox...");
logger.info("No tool calls found. Pausing sandbox...");
newSandboxSessionId = await pauseSandbox(state.sandboxSessionId);
}
logger.info("Generated action", {
name: response.tool_calls?.[0].name,
args: response.tool_calls?.[0].args,
});
return {
messages: [response],
...(newSandboxSessionId && { sandboxSessionId: newSandboxSessionId }),

View file

@ -1,4 +1,5 @@
import { Sandbox } from "@e2b/code-interpreter";
import { createLogger, LogLevel } from "../utils/logger.js";
import {
GraphState,
GraphConfig,
@ -14,6 +15,8 @@ import {
} from "../utils/git/index.js";
import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js";
const logger = createLogger(LogLevel.INFO, "Initialize");
const SANDBOX_TEMPLATE_ID = "eh0860emqx28qyxmbctu";
async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
@ -32,7 +35,7 @@ async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
gitCloneCommand.push(repoUrlWithToken);
}
console.log("Cloning repository...", {
logger.info("Cloning repository", {
command: gitCloneCommand.join(" "),
});
return await sandbox.commands.run(
@ -41,7 +44,7 @@ async function cloneRepo(sandbox: Sandbox, targetRepository: TargetRepository) {
);
} catch (e) {
const errorFields = getSandboxErrorFields(e);
console.error("Failed to clone repository", errorFields ?? e);
logger.error("Failed to clone repository", errorFields ?? e);
throw e;
}
}
@ -63,7 +66,7 @@ export async function initialize(
if (sandboxSessionId) {
try {
console.log("Sandbox session ID exists. Resuming...", {
logger.info("Sandbox session ID exists. Resuming", {
sandboxSessionId,
});
// Resume the sandbox if the session ID is in the config.
@ -76,7 +79,7 @@ export async function initialize(
};
} catch (e) {
// Error thrown, log it and continue. Will create a new sandbox session since the resumption failed.
console.error("Failed to get sandbox session.", e);
logger.error("Failed to get sandbox session", e);
}
}
@ -88,7 +91,7 @@ export async function initialize(
);
}
console.log("Creating sandbox...");
logger.info("Creating sandbox...");
const sandbox = await Sandbox.create(
SANDBOX_TEMPLATE_ID,
TIMEOUT_EXTENSION_OPT,
@ -97,16 +100,16 @@ export async function initialize(
const res = await cloneRepo(sandbox, target_repository);
if (res.error) {
// TODO: This should probably be an interrupt.
console.error("Failed to clone repository.", res.error);
logger.error("Failed to clone repository", res.error);
throw new Error(`Failed to clone repository.\n${res.error}`);
}
console.log("Repository cloned successfully.");
logger.info("Repository cloned successfully.");
const absoluteRepoDir = getRepoAbsolutePath(config);
console.log(`Configuring git user for repository at "${absoluteRepoDir}"...`);
logger.info(`Configuring git user for repository at "${absoluteRepoDir}"...`);
await configureGitUserInRepo(absoluteRepoDir, sandbox);
console.log("Git user configured successfully.");
logger.info("Git user configured successfully.");
const checkoutBranchRes = await checkoutBranch(
absoluteRepoDir,
@ -116,7 +119,7 @@ export async function initialize(
if (!checkoutBranchRes) {
// TODO: This should probably be an interrupt.
console.error("\nFailed to checkout branch.");
logger.error("Failed to checkout branch.");
throw new Error("Failed to checkout branch");
}

View file

@ -1,8 +1,11 @@
import { z } from "zod";
import { createLogger, LogLevel } from "../utils/logger.js";
import { GraphConfig, GraphState, GraphUpdate, PlanItem } from "../types.js";
import { loadModel, Task } from "../utils/load-model.js";
import { formatPlanPrompt } from "../utils/plan-prompt.js";
const logger = createLogger(LogLevel.INFO, "ProgressPlanStep");
const systemPrompt = `You are operating as a terminal-based agentic coding assistant built by LangChain. It wraps LLM models to enable natural language interaction with a local codebase. You are expected to be precise, safe, and helpful.
In your workflow, you generate a plan, then act on said plan. It may take many actions to complete a single step, or a single action to complete the step.
@ -65,7 +68,7 @@ export async function progressPlanStep(
const remainingTask = state.plan.find((p) => !p.completed);
if (!remainingTask) {
// No remaining tasks, end the process
console.log(
logger.info(
"Found no remaining tasks in the plan during the check plan step.",
);
return {};

View file

@ -1,4 +1,5 @@
import { isAIMessage, ToolMessage } from "@langchain/core/messages";
import { createLogger, LogLevel } from "../utils/logger.js";
import { applyPatchTool, shellTool } from "../tools/index.js";
import { GraphState, GraphConfig, GraphUpdate } from "../types.js";
import {
@ -8,6 +9,8 @@ import {
} from "../utils/git/index.js";
import { Sandbox } from "@e2b/code-interpreter";
const logger = createLogger(LogLevel.INFO, "TakeAction");
export async function takeAction(
state: GraphState,
config: GraphConfig,
@ -45,7 +48,11 @@ export async function takeAction(
// @ts-expect-error tool.invoke types are weird here...
result = await tool.invoke(toolCall.args);
} catch (e) {
console.error("\nFailed to call tool", e);
logger.error("Failed to call tool", {
...(e instanceof Error
? { name: e.name, message: e.message, stack: e.stack }
: { error: e }),
});
const errMessage = e instanceof Error ? e.message : "Unknown error";
result = `FAILED TO CALL TOOL: "${toolCall.name}"\n\nError: ${errMessage}`;
}
@ -66,7 +73,7 @@ export async function takeAction(
let branchName: string | undefined = state.branchName;
if (changedFiles.length > 0) {
console.log(`\nHas ${changedFiles.length} changed files. Committing...`, {
logger.info(`Has ${changedFiles.length} changed files. Committing.`, {
changedFiles,
});
branchName = await checkoutBranchAndCommit(config, sandbox, {

View file

@ -6,6 +6,9 @@ import { Sandbox } from "@e2b/code-interpreter";
import { readFile, writeFile } from "../utils/read-write.js";
import { getCurrentTaskInput } from "@langchain/langgraph";
import { fixGitPatch } from "../utils/diff.js";
import { createLogger, LogLevel } from "../utils/logger.js";
const logger = createLogger(LogLevel.INFO, "ApplyPatchTool");
const applyPatchToolSchema = z.object({
diff: z.string().describe("The diff to apply. Use a standard diff format."),
@ -17,7 +20,7 @@ export const applyPatchTool = tool(
const state = getCurrentTaskInput<GraphState>();
const { sandboxSessionId } = state;
if (!sandboxSessionId) {
console.error("FAILED TO RUN COMMAND: No sandbox session ID provided", {
logger.error("FAILED TO RUN COMMAND: No sandbox session ID provided", {
input,
});
throw new Error("FAILED TO RUN COMMAND: No sandbox session ID provided");
@ -32,37 +35,46 @@ export const applyPatchTool = tool(
file_path,
);
if (!readFileSuccess) {
logger.error("Failed to read file", readFileOutput);
return readFileOutput;
}
console.log(`\nApplying patch to file ${file_path}\n`);
console.log("\nreadFileOutput\n", readFileOutput);
console.log("\ndiff\n", diff);
let patchedContent: string | false;
try {
logger.info(`Applying patch to file ${file_path}`);
const fixedDiff = fixGitPatch(diff, {
[file_path]: readFileOutput,
});
console.log("\n\nfixedDiff\n\n", fixedDiff);
patchedContent = applyPatch(readFileOutput, fixedDiff);
} catch (e) {
console.error("Failed to apply patch", e);
logger.error("Failed to apply patch", {
...(e instanceof Error
? { name: e.name, message: e.message, stack: e.stack }
: { error: e }),
});
const errMessage = e instanceof Error ? e.message : "Unknown error";
return `FAILED TO APPLY PATCH: The diff could not be applied to file '${file_path}'.\n\nError: ${errMessage}`;
}
if (patchedContent === false) {
logger.error(
`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)}...`,
);
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) {
logger.error("Failed to write file", {
writeFileOutput,
});
return writeFileOutput;
}
logger.info(
`Successfully applied diff to \`${file_path}\` and saved changes.`,
);
return `Successfully applied diff to \`${file_path}\` and saved changes.`;
},
{

View file

@ -4,8 +4,9 @@ import { Sandbox } from "@e2b/code-interpreter";
import { GraphState } from "../types.js";
import { getCurrentTaskInput } from "@langchain/langgraph";
import { TIMEOUT_MS } from "../constants.js";
import { getSandboxErrorFields } from "../utils/sandbox-error-fields.js";
const DEFAULT_COMMAND_TIMEOUT = 120_000; // 2 minutes
const DEFAULT_COMMAND_TIMEOUT = 60_000; // 1 minute
const shellToolSchema = z.object({
command: z.array(z.string()).describe("The command to run"),
@ -55,26 +56,28 @@ export const shellTool = tool(
}
return result.stdout;
} catch (e: any) {
if (typeof e === "object" && "result" in e && e.result) {
} catch (e) {
const errorFields = getSandboxErrorFields(e);
if (errorFields) {
console.error("Failed to run command", {
error: e.message,
error_result: e.result,
input,
error: errorFields,
});
return (
"FAILED TO RUN COMMAND: " +
e.message +
"\n" +
JSON.stringify(e.result, null, 2)
);
return `Command failed. Exit code: ${errorFields.exitCode}\nError: ${errorFields.error}\nStderr:\n${errorFields.stderr}\nStdout:\n${errorFields.stdout}`;
}
console.error("Failed to run command: " + e.message, {
error: e,
input,
});
throw new Error("FAILED TO RUN COMMAND: " + e.message);
console.error(
"Failed to run command: " +
(e instanceof Error ? e.message : "Unknown error"),
{
error: e,
input,
},
);
throw new Error(
"FAILED TO RUN COMMAND: " +
(e instanceof Error ? e.message : "Unknown error"),
);
}
},
{

View file

@ -1,3 +1,7 @@
import { createLogger, LogLevel } from "./logger.js";
const logger = createLogger(LogLevel.INFO, "DiffUtil");
interface Hunk {
oldStart: number;
oldLines: number;
@ -386,8 +390,12 @@ export function fixGitPatch(
}
return result;
} catch (error: any) {
console.error("Error fixing patch:", error);
} catch (e) {
logger.error(`Error fixing patch:`, {
...(e instanceof Error
? { name: e.name, message: e.message, stack: e.stack }
: { error: e }),
});
return patchString;
}
}

View file

@ -1,8 +1,11 @@
import { CommandResult, Sandbox } from "@e2b/code-interpreter";
import { createLogger, LogLevel } from "../logger.js";
import { GraphConfig } from "../../types.js";
import { TIMEOUT_MS } from "../../constants.js";
import { getSandboxErrorFields } from "../sandbox-error-fields.js";
const logger = createLogger(LogLevel.INFO, "GitUtil");
export function getRepoAbsolutePath(config: GraphConfig): string {
const repoName = config.configurable?.target_repository.repo;
if (!repoName) {
@ -26,9 +29,7 @@ export async function checkoutBranch(
branchName: string,
sandbox: Sandbox,
): Promise<CommandResult | false> {
console.log("\nChecking out branch...", {
branchName,
});
logger.info(`Checking out branch '${branchName}'...`);
try {
const getCurrentBranchOutput = await sandbox.commands.run(
@ -38,11 +39,13 @@ export async function checkoutBranch(
await sandbox.setTimeout(TIMEOUT_MS);
if (getCurrentBranchOutput.exitCode !== 0) {
console.error("Failed to get current branch", getCurrentBranchOutput);
logger.error(`Failed to get current branch`, {
getCurrentBranchOutput,
});
} else {
const currentBranch = getCurrentBranchOutput.stdout.trim();
if (currentBranch === branchName) {
console.log(`\nAlready on branch '${branchName}'. No checkout needed.`);
logger.info(`Already on branch '${branchName}'. No checkout needed.`);
return {
stdout: `Already on branch ${branchName}`,
stderr: "",
@ -52,15 +55,22 @@ export async function checkoutBranch(
}
} catch (e) {
const errorFields = getSandboxErrorFields(e);
console.error("Failed to get current branch", errorFields ?? e);
logger.error(`Failed to get current branch`, {
...(errorFields && { errorFields }),
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return false;
}
let checkoutCommand: string;
try {
console.log("\nChecking if branch exists...", {
command: `git rev-parse --verify --quiet "refs/heads/${branchName}"`,
});
logger.info(
`Checking if branch 'refs/heads/${branchName}' exists using 'git rev-parse --verify --quiet'`,
);
// Check if branch exists using git rev-parse for robustness
const checkBranchExistsOutput = await sandbox.commands.run(
`git rev-parse --verify --quiet "refs/heads/${branchName}"`,
@ -85,7 +95,13 @@ export async function checkoutBranch(
) {
checkoutCommand = `git checkout -b "${branchName}"`;
} else {
console.error("\nError checking if branch exists", e);
logger.error(`Error checking if branch exists`, {
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return false;
}
}
@ -96,19 +112,27 @@ export async function checkoutBranch(
});
if (gitCheckoutOutput.exitCode !== 0) {
console.error("\nFailed to checkout branch", gitCheckoutOutput);
logger.error(`Failed to checkout branch`, {
gitCheckoutOutput,
});
return false;
}
console.log("\nChecked out branch successfully.", {
branchName,
gitCheckoutOutput: gitCheckoutOutput.stdout,
logger.info(`Checked out branch '${branchName}' successfully.`, {
gitCheckoutOutput,
});
return gitCheckoutOutput;
} catch (e) {
const errorFields = getSandboxErrorFields(e);
console.error("Error checking out branch", errorFields ?? e);
logger.error(`Error checking out branch`, {
...(errorFields && { errorFields }),
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return false;
}
}
@ -126,7 +150,7 @@ async function getGitUserDetailsFromGitHub(): Promise<{
}> {
const githubToken = process.env.GITHUB_PAT;
if (!githubToken) {
console.warn(
logger.warn(
"GITHUB_PAT environment variable is not set. Cannot fetch user details from GitHub.",
);
return {};
@ -141,9 +165,9 @@ async function getGitUserDetailsFromGitHub(): Promise<{
});
if (!response.ok) {
console.error(
`Failed to fetch GitHub user info: ${response.status} ${response.statusText}. Response: ${await response.text()}`,
);
logger.error(`Failed to fetch GitHub user info`, {
response,
});
return {};
}
@ -161,14 +185,20 @@ async function getGitUserDetailsFromGitHub(): Promise<{
const finalUserEmail = fetchedUserEmail || undefined;
if (!finalUserName) {
console.warn("Could not determine GitHub username from API response.");
logger.warn("Could not determine GitHub username from API response.");
}
if (!finalUserEmail) {
console.warn("Could not determine GitHub user email from API response.");
logger.warn("Could not determine GitHub user email from API response.");
}
return { userName: finalUserName, userEmail: finalUserEmail };
} catch (e) {
console.error("Error fetching GitHub user info:", e);
logger.error(`Error fetching GitHub user info`, {
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return {};
}
}
@ -197,10 +227,13 @@ export async function configureGitUserInRepo(
needsGitConfig = true;
}
} catch (checkError) {
console.warn(
"Could not check existing git config, will attempt to set it:",
checkError,
);
logger.warn(`Could not check existing git config, will attempt to set it`, {
...(checkError instanceof Error && {
name: checkError.name,
message: checkError.message,
stack: checkError.stack,
}),
});
needsGitConfig = true;
}
@ -214,14 +247,11 @@ export async function configureGitUserInRepo(
);
await sandbox.setTimeout(TIMEOUT_MS);
if (configUserNameOutput.exitCode !== 0) {
console.error(
"Failed to set git user.name:",
configUserNameOutput.stderr || configUserNameOutput.stdout,
);
} else {
console.log("\nSet git user.name successfully.", {
userName,
logger.error(`Failed to set git user.name`, {
configUserNameOutput,
});
} else {
logger.info(`Set git user.name to '${userName}' successfully.`);
}
}
@ -232,18 +262,15 @@ export async function configureGitUserInRepo(
);
await sandbox.setTimeout(TIMEOUT_MS);
if (configUserEmailOutput.exitCode !== 0) {
console.error(
"Failed to set git user.email:",
configUserEmailOutput.stderr || configUserEmailOutput.stdout,
);
} else {
console.log("\nSet git user.email successfully.", {
userEmail,
logger.error(`Failed to set git user.email`, {
configUserEmailOutput,
});
} else {
logger.info(`Set git user.email to '${userEmail}' successfully.`);
}
}
} else {
console.log(
logger.info(
"Git user.name and user.email are already configured in this repository.",
);
}
@ -262,14 +289,21 @@ export async function commitAll(
await sandbox.setTimeout(TIMEOUT_MS);
if (gitAddOutput.exitCode !== 0) {
console.error(
"Failed to commit all changes to git repository",
logger.error(`Failed to commit all changes to git repository`, {
gitAddOutput,
);
});
}
return gitAddOutput;
} catch (e) {
console.error("Failed to commit all changes to git repository", e);
const errorFields = getSandboxErrorFields(e);
logger.error(`Failed to commit all changes to git repository`, {
...(errorFields && { errorFields }),
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return false;
}
}
@ -295,13 +329,23 @@ export async function commitAllAndPush(
await sandbox.setTimeout(TIMEOUT_MS);
if (gitPushOutput.exitCode !== 0) {
console.error("Failed to push changes to git repository", gitPushOutput);
logger.error(`Failed to push changes to git repository`, {
gitPushOutput,
});
return false;
}
return gitPushOutput;
} catch (e) {
console.error("Failed to commit all and push changes to git repository", e);
const errorFields = getSandboxErrorFields(e);
logger.error(`Failed to commit all and push changes to git repository`, {
...(errorFields && { errorFields }),
...(e instanceof Error && {
name: e.name,
message: e.message,
stack: e.stack,
}),
});
return false;
}
}
@ -315,7 +359,9 @@ export async function getChangedFilesStatus(
});
if (gitStatusOutput.exitCode !== 0) {
console.error("Failed to get changed files status", gitStatusOutput);
logger.error(`Failed to get changed files status`, {
gitStatusOutput,
});
return [];
}
@ -332,15 +378,15 @@ export async function checkoutBranchAndCommit(
branchName?: string;
},
): Promise<string> {
console.log("\nChecking out branch and committing changes...");
logger.info("Checking out branch and committing changes...");
const absoluteRepoDir = getRepoAbsolutePath(config);
const branchName = options?.branchName || getBranchName(config);
await checkoutBranch(absoluteRepoDir, branchName, sandbox);
console.log(`Committing changes to branch ${branchName}`);
logger.info(`Committing changes to branch ${branchName}`);
await commitAllAndPush(absoluteRepoDir, "Apply patch", sandbox);
console.log("Successfully checked out & committed changes.\n");
logger.info("Successfully checked out & committed changes.");
return branchName;
}

View file

@ -39,11 +39,9 @@ export async function loadModel(config: GraphConfig, task: Task) {
let thinkingModel = false;
if (modelNameParts[0] === "extended-thinking") {
console.log("THINKING ENABLED", modelNameParts);
// Using a thinking model. Remove it from the model name.
modelNameParts.shift();
thinkingModel = true;
console.log("THINKING ENABLED", modelNameParts);
}
const modelName = modelNameParts.join(":");

94
src/utils/logger.ts Normal file
View file

@ -0,0 +1,94 @@
export enum LogLevel {
DEBUG = "debug",
INFO = "info",
WARN = "warn",
ERROR = "error",
}
// ANSI escape codes
const RESET = "\x1b[0m";
const BOLD = "\x1b[1m";
// Define a list of colors (foreground)
const COLORS = [
"\x1b[31m", // Red
"\x1b[32m", // Green
"\x1b[33m", // Yellow
"\x1b[34m", // Blue
"\x1b[35m", // Magenta
"\x1b[36m", // Cyan
"\x1b[91m", // Bright Red
"\x1b[92m", // Bright Green
"\x1b[93m", // Bright Yellow
"\x1b[94m", // Bright Blue
"\x1b[95m", // Bright Magenta
"\x1b[96m", // Bright Cyan
];
// Simple hashing function to get a positive integer
function simpleHash(str: string): number {
let hash = 0;
if (str.length === 0) {
return hash;
}
for (let i = 0; i < str.length; i++) {
const char = str.charCodeAt(i);
hash = (hash << 5) - hash + char;
hash |= 0; // Convert to 32bit integer
}
return Math.abs(hash); // Ensure positive for modulo index
}
export function createLogger(level: LogLevel, prefix: string) {
const hash = simpleHash(prefix);
const color = COLORS[hash % COLORS.length];
const styledPrefix = `${BOLD}${color}[${prefix}]${RESET}`; // Apply bold and color
return {
debug: (message: string, data?: any) => {
if (level === LogLevel.DEBUG) {
if (data !== undefined) {
console.log(`${styledPrefix} ${message}`, data);
} else {
console.log(`${styledPrefix} ${message}`);
}
}
},
info: (message: string, data?: any) => {
if (level === LogLevel.INFO || level === LogLevel.DEBUG) {
if (data !== undefined) {
console.log(`${styledPrefix} ${message}`, data);
} else {
console.log(`${styledPrefix} ${message}`);
}
}
},
warn: (message: string, data?: any) => {
if (
level === LogLevel.WARN ||
level === LogLevel.INFO ||
level === LogLevel.DEBUG
) {
if (data !== undefined) {
console.log(`${styledPrefix} ${message}`, data);
} else {
console.log(`${styledPrefix} ${message}`);
}
}
},
error: (message: string, data?: any) => {
if (
level === LogLevel.ERROR ||
level === LogLevel.WARN ||
level === LogLevel.INFO ||
level === LogLevel.DEBUG
) {
if (data !== undefined) {
console.log(`${styledPrefix} ${message}`, data);
} else {
console.log(`${styledPrefix} ${message}`);
}
}
},
};
}

View file

@ -1,7 +1,10 @@
import { Sandbox } from "@e2b/code-interpreter";
import { createLogger, LogLevel } from "./logger.js";
import { TIMEOUT_MS } from "../constants.js";
import { getSandboxErrorFields } from "./sandbox-error-fields.js";
const logger = createLogger(LogLevel.INFO, "ReadWriteUtil");
export async function readFile(
sandbox: Sandbox,
filePath: string,
@ -15,18 +18,17 @@ export async function readFile(
await sandbox.setTimeout(TIMEOUT_MS);
if (readOutput.exitCode !== 0) {
console.error(
`\nError reading file '${filePath}' from sandbox via cat:`,
logger.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(
`\nStderr while reading file '${filePath}' from sandbox via cat: ${readOutput.stderr}`,
logger.warn(
`Stderr while reading file '${filePath}' from sandbox via cat: ${readOutput.stderr}`,
);
}
return {
@ -34,9 +36,13 @@ export async function readFile(
output: readOutput.stdout,
};
} catch (e: any) {
console.error(
`\nException while trying to read file '${filePath}' from sandbox via cat:`,
e,
logger.error(
`Exception while trying to read file '${filePath}' from sandbox via cat:`,
{
...(e instanceof Error
? { name: e.name, message: e.message, stack: e.stack }
: { error: e }),
},
);
let outputMessage = `FAILED TO EXECUTE READ COMMAND for sandbox '${filePath}'.`;
const errorFields = getSandboxErrorFields(e);
@ -71,18 +77,17 @@ ${delimiter}`;
await sandbox.setTimeout(TIMEOUT_MS);
if (writeOutput.exitCode !== 0) {
console.error(
`\nError writing file '${filePath}' to sandbox via printf:`,
logger.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(
`\nStderr while writing file '${filePath}' to sandbox via printf: ${writeOutput.stderr}`,
logger.warn(
`Stderr while writing file '${filePath}' to sandbox via printf: ${writeOutput.stderr}`,
);
}
return {
@ -90,9 +95,13 @@ ${delimiter}`;
output: `Successfully wrote file '${filePath}' to sandbox via printf.`,
};
} catch (e: any) {
console.error(
`\nException while trying to write file '${filePath}' to sandbox via printf:`,
e,
logger.error(
`Exception while trying to write file '${filePath}' to sandbox via printf:`,
{
...(e instanceof Error
? { name: e.name, message: e.message, stack: e.stack }
: { error: e }),
},
);
let outputMessage = `FAILED TO EXECUTE WRITE COMMAND for sandbox '${filePath}'.`;