In the previous chapter, Intelligent String Matching, we taught our tool how to find text even if the quotes or whitespace didn't match perfectly.
Now we know what to change. But just because we can change a file doesn't mean we should.
Imagine you are a pilot. You have your destination (the new_string) and your plane (the FileEditTool). Before you take off, you don't just gun the engines. You go through a Pre-Flight Checklist.
If we skip these checks, we might overwrite code the user just wrote, crash the computer by opening a 50GB file, or replace the wrong line of code.
We are editing hello.txt.
The Safety & Validation Layer detects these problems and stops the edit immediately.
This is the most critical safety feature for an AI agent.
An AI doesn't see your screen in real-time. It takes a snapshot (reads a file), thinks for 10 seconds, and then suggests an edit. If you modified the file during those 10 seconds, the AI's snapshot is stale. If the AI overwrites the file now, your work is lost.
We enforce a strict rule: You cannot write to a file unless you have read it recently.
LastReadTime must be greater than LastModifiedTime.Computers are bad at guessing context.
File Content:
print("Hello")
print("Hello")
AI Request:
Replace "Hello" with "Goodbye" (replace_all = false).
Which one? The first or the second? If the tool guesses wrong, it breaks the program. The Safety Layer counts how many times old_string appears. If it appears more than once and replace_all is false, we reject the request.
Opening a massive file can consume all the computer's RAM, causing a crash. We set a hard limit (e.g., 1GB) to ensure the tool remains stable.
Here is how the validateInput function acts as the safety inspector.
Let's look at FileEditTool.ts to see how these checks are implemented. This happens inside the validateInput method, which runs before the main logic.
First, we ensure we aren't lifting something too heavy.
// File: FileEditTool.ts
// MAX_EDIT_FILE_SIZE is set to ~1 GB
const { size } = await fs.stat(fullFilePath)
if (size > MAX_EDIT_FILE_SIZE) {
return {
result: false,
message: `File is too large to edit (${formatFileSize(size)}).`,
errorCode: 10,
}
}
Explanation: We check the file stats (metadata) before reading the content. If it's too big, we bail out immediately.
We verify the AI isn't working with outdated information.
// File: FileEditTool.ts
// Get the timestamp of when the AI last read this file
const readTimestamp = toolUseContext.readFileState.get(fullFilePath)
// If the AI has NEVER read it, stop them.
if (!readTimestamp) {
return {
result: false,
message: 'File has not been read yet. Read it first.',
errorCode: 6,
}
}
Explanation: The toolUseContext keeps a memory of the AI's actions. No read record means no permission to write.
But what if they read it yesterday?
// File: FileEditTool.ts
const lastWriteTime = getFileModificationTime(fullFilePath)
// Check if file changed on disk AFTER the AI read it
if (lastWriteTime > readTimestamp.timestamp) {
return {
result: false,
message: 'File has been modified since read. Read it again.',
errorCode: 7,
}
}
Explanation: This comparison ensures the AI's "map" matches the "territory."
We ensure the edit target is obvious. We use the helper findActualString (from Intelligent String Matching) to normalize quotes before counting.
// File: FileEditTool.ts
// Load the file content
const file = fileContent
// Find the string (handling quote normalization)
const actualOldString = findActualString(file, old_string)
// Count how many times it appears
const matches = file.split(actualOldString).length - 1
If the count is messy, we return a helpful error message guiding the AI to be more specific.
// File: FileEditTool.ts
if (matches > 1 && !replace_all) {
return {
result: false,
message: `Found ${matches} matches... provide more context.`,
errorCode: 9,
}
}
Explanation: If replace_all is true, ambiguity doesn't matter (we change them all). If it is false, we require a unique match.
Sometimes the AI gets confused and tries to change "Hello" to "Hello". This is a waste of resources.
// File: FileEditTool.ts
if (old_string === new_string) {
return {
result: false,
message: 'No changes to make: strings are exactly the same.',
errorCode: 1,
}
}
Explanation: A simple sanity check to save time.
The Safety & Validation Layer is the responsible guardian of the file system.
By passing these checks, we guarantee that the edit operation is safe to perform. We have the file, we have the permissions, and we know exactly where to apply the change.
Now comes the fun part: actually calculating the new text and creating the "Patch" that will be written to disk.
Next Chapter: Patch Engine & Text Transformation
Generated by Code IQ