fix(read_file): normalize indentation config keys and pagination metadata

This commit is contained in:
Hannes Rudolph 2025-12-21 17:25:52 -07:00
parent 823bd2afac
commit cd60bc4fd5
4 changed files with 37 additions and 31 deletions

View file

@ -328,45 +328,40 @@ export class NativeToolCallParser {
entry.mode = file.mode
}
// Map indentation configuration (accepts both camelCase and snake_case)
// Map indentation configuration
if (file.indentation && typeof file.indentation === "object") {
const indent = file.indentation
const indentConfig: FileEntry["indentation"] = {}
// anchorLine (camelCase) or anchor_line (snake_case)
const anchorLineValue = indent.anchorLine ?? indent.anchor_line
if (anchorLineValue !== undefined) {
const anchorLine = Number(anchorLineValue)
// anchorLine
if (indent.anchorLine !== undefined) {
const anchorLine = Number(indent.anchorLine)
if (!isNaN(anchorLine) && anchorLine > 0) {
indentConfig.anchorLine = anchorLine
}
}
// maxLevels (camelCase) or max_levels (snake_case)
const maxLevelsValue = indent.maxLevels ?? indent.max_levels
if (maxLevelsValue !== undefined) {
const maxLevels = Number(maxLevelsValue)
// maxLevels
if (indent.maxLevels !== undefined) {
const maxLevels = Number(indent.maxLevels)
if (!isNaN(maxLevels) && maxLevels >= 0) {
indentConfig.maxLevels = maxLevels
}
}
// includeSiblings (camelCase) or include_siblings (snake_case)
const includeSiblingsValue = indent.includeSiblings ?? indent.include_siblings
if (includeSiblingsValue !== undefined) {
indentConfig.includeSiblings = Boolean(includeSiblingsValue)
// includeSiblings
if (indent.includeSiblings !== undefined) {
indentConfig.includeSiblings = Boolean(indent.includeSiblings)
}
// includeHeader (camelCase) or include_header (snake_case)
const includeHeaderValue = indent.includeHeader ?? indent.include_header
if (includeHeaderValue !== undefined) {
indentConfig.includeHeader = Boolean(includeHeaderValue)
// includeHeader
if (indent.includeHeader !== undefined) {
indentConfig.includeHeader = Boolean(indent.includeHeader)
}
// maxLines (camelCase) or max_lines (snake_case)
const maxLinesValue = indent.maxLines ?? indent.max_lines
if (maxLinesValue !== undefined) {
const maxLines = Number(maxLinesValue)
// maxLines
if (indent.maxLines !== undefined) {
const maxLines = Number(indent.maxLines)
if (!isNaN(maxLines) && maxLines > 0) {
indentConfig.maxLines = maxLines
}

View file

@ -50,9 +50,9 @@ describe("NativeToolCallParser", () => {
offset: 50,
mode: "indentation",
indentation: {
anchor_line: 55,
max_levels: 2,
include_siblings: true,
anchorLine: 55,
maxLevels: 2,
includeSiblings: true,
},
},
],
@ -126,7 +126,7 @@ describe("NativeToolCallParser", () => {
path: "file2.ts",
offset: 100,
mode: "indentation",
indentation: { max_levels: 1 },
indentation: { maxLevels: 1 },
},
{
path: "file3.ts",
@ -237,7 +237,7 @@ describe("NativeToolCallParser", () => {
path: "finalized.ts",
offset: 500,
mode: "indentation",
indentation: { anchor_line: 520 },
indentation: { anchorLine: 520 },
},
],
}),

View file

@ -109,6 +109,15 @@ describe("read-file-content", () => {
expect(result.content).not.toContain("\r")
})
})
it("should only mark truncatedByLimit when more lines exist after endLine", async () => {
const content = "Line 1\nLine 2\nLine 3"
await withTempFile("slice-truncated-metadata-test.txt", content, async (filepath) => {
const result = await readSlice(filepath, 1, 3)
expect(result.metadata.hasMoreAfter).toBe(false)
expect(result.metadata.truncatedByLimit).toBe(false)
})
})
})
describe("readIndentationBlock", () => {

View file

@ -226,7 +226,7 @@ export async function readSlice(
let buffer = ""
let startLine = 0
let endLine = 0
let truncatedByLimit = false
let hitLimit = false
const input = createReadStream(filePath)
@ -248,7 +248,7 @@ export async function readSlice(
lineNumber++
// Only collect content if we haven't hit the limit yet
if (!truncatedByLimit && lineNumber >= offset && collected.length < limit) {
if (!hitLimit && lineNumber >= offset && collected.length < limit) {
// Track first line collected
if (startLine === 0) {
startLine = lineNumber
@ -265,7 +265,7 @@ export async function readSlice(
// Check if we've hit the limit
if (collected.length >= limit) {
truncatedByLimit = true
hitLimit = true
// Continue counting lines instead of destroying stream
}
}
@ -281,7 +281,7 @@ export async function readSlice(
// Process any remaining data (last line without newline)
if (buffer.length > 0) {
lineNumber++
if (!truncatedByLimit && lineNumber >= offset && collected.length < limit) {
if (!hitLimit && lineNumber >= offset && collected.length < limit) {
if (startLine === 0) {
startLine = lineNumber
}
@ -321,7 +321,9 @@ export async function readSlice(
}
const linesReturned = collected.length
const hasMoreAfter = endLine > 0 && endLine < totalLines
const linesAfterEnd = endLine > 0 ? totalLines - endLine : 0
const truncatedByLimit = hitLimit && hasMoreAfter
resolve({
content: collected.join("\n"),
@ -334,7 +336,7 @@ export async function readSlice(
startLine: startLine || offset,
endLine: endLine || offset,
hasMoreBefore: (startLine || offset) > 1,
hasMoreAfter: linesAfterEnd > 0,
hasMoreAfter,
linesBeforeStart: (startLine || offset) - 1,
linesAfterEnd,
truncatedByLimit,