Add simplified start_line, end_line, and file_length metadata to replace tool response

This commit is contained in:
Christian Gunderman
2026-02-25 16:55:32 +00:00
parent 55d0bf5f8e
commit 57ef47b9ce
+52 -13
View File
@@ -137,7 +137,22 @@ async function calculateExactReplacement(
const normalizedSearch = old_string.replace(/\r\n/g, '\n');
const normalizedReplace = new_string.replace(/\r\n/g, '\n');
const exactOccurrences = normalizedCode.split(normalizedSearch).length - 1;
const matchRanges: Array<{ start: number; end: number }> = [];
let index = normalizedCode.indexOf(normalizedSearch);
while (index !== -1) {
const startLine = normalizedCode
.substring(0, index)
.split(String.fromCharCode(10)).length;
const endLine =
startLine + normalizedSearch.split(String.fromCharCode(10)).length - 1;
matchRanges.push({ start: startLine, end: endLine });
index = normalizedCode.indexOf(
normalizedSearch,
index + normalizedSearch.length,
);
}
const exactOccurrences = matchRanges.length;
if (!params.allow_multiple && exactOccurrences > 1) {
return {
@@ -145,6 +160,8 @@ async function calculateExactReplacement(
occurrences: exactOccurrences,
finalOldString: normalizedSearch,
finalNewString: normalizedReplace,
strategy: 'exact',
matchRanges,
};
}
@@ -160,6 +177,8 @@ async function calculateExactReplacement(
occurrences: exactOccurrences,
finalOldString: normalizedSearch,
finalNewString: normalizedReplace,
strategy: 'exact',
matchRanges,
};
}
@@ -178,9 +197,9 @@ async function calculateFlexibleReplacement(
const sourceLines = normalizedCode.match(/.*(?:\n|$)/g)?.slice(0, -1) ?? [];
const searchLinesStripped = normalizedSearch
.split('\n')
.split(String.fromCharCode(10))
.map((line: string) => line.trim());
const replaceLines = normalizedReplace.split('\n');
const replaceLines = normalizedReplace.split(String.fromCharCode(10));
let flexibleOccurrences = 0;
let i = 0;
@@ -238,11 +257,13 @@ async function calculateRegexReplacement(
let processedString = normalizedSearch;
for (const delim of delimiters) {
processedString = processedString.split(delim).join(` ${delim} `);
processedString = processedString
.split(String.fromCharCode(10))
.join(` ${delim} `);
}
// Split by any whitespace and remove empty strings.
const tokens = processedString.split(/\s+/).filter(Boolean);
const tokens = processedString.split(String.fromCharCode(10)).filter(Boolean);
if (tokens.length === 0) {
return null;
@@ -265,7 +286,7 @@ async function calculateRegexReplacement(
}
const occurrences = matches.length;
const newLines = normalizedReplace.split('\n');
const newLines = normalizedReplace.split(String.fromCharCode(10));
// Use the appropriate regex for replacement based on allow_multiple.
const replaceRegex = new RegExp(
@@ -765,11 +786,13 @@ class EditToolInvocation
}
const oldStringSnippet =
this.params.old_string.split('\n')[0].substring(0, 30) +
(this.params.old_string.length > 30 ? '...' : '');
this.params.old_string
.split(String.fromCharCode(10))[0]
.substring(0, 30) + (this.params.old_string.length > 30 ? '...' : '');
const newStringSnippet =
this.params.new_string.split('\n')[0].substring(0, 30) +
(this.params.new_string.length > 30 ? '...' : '');
this.params.new_string
.split(String.fromCharCode(10))[0]
.substring(0, 30) + (this.params.new_string.length > 30 ? '...' : '');
if (this.params.old_string === this.params.new_string) {
return `No file changes to ${shortenPath(relativePath)}`;
@@ -877,10 +900,26 @@ class EditToolInvocation
};
}
const totalLength = finalContent.split(String.fromCharCode(10)).length;
const metadataParts = [];
if (editData.matchRanges && editData.matchRanges.length > 0) {
if (editData.matchRanges.length === 1) {
metadataParts.push(
`start_line: ${editData.matchRanges[0].start}, end_line: ${editData.matchRanges[0].end}`,
);
} else {
const ranges = editData.matchRanges
.map((r) => `${r.start}-${r.end}`)
.join(', ');
metadataParts.push(`ranges: ${ranges}`);
}
}
metadataParts.push(`file_length: ${totalLength}`);
const llmSuccessMessageParts = [
editData.isNewFile
? `Created new file: ${this.params.file_path} with provided content.`
: `Successfully modified file: ${this.params.file_path} (${editData.occurrences} replacements).`,
? `Created new file: ${this.params.file_path} with provided content. [file_length: ${totalLength}]`
: `Successfully modified file: ${this.params.file_path}. [${metadataParts.join(', ')}]`,
];
// Return a diff of the file before and after the write so that the agent
@@ -1211,7 +1250,7 @@ async function calculateFuzzyReplacement(
// so that indices remain valid
selectedMatches.sort((a, b) => b.index - a.index);
const newLines = normalizedReplace.split('\n');
const newLines = normalizedReplace.split(String.fromCharCode(10));
for (const match of selectedMatches) {
// If we want to preserve the indentation of the first line of the match: