fix(read): normalize displayed line ranges for limits (#105105)

Co-authored-by: Peter Steinberger <steipete@gmail.com>
This commit is contained in:
qingminlong
2026-07-17 09:38:27 +08:00
committed by GitHub
parent 71c5005d2c
commit fb0346fe45
2 changed files with 27 additions and 2 deletions

View File

@@ -9,7 +9,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { useAutoCleanupTempDirTracker } from "../../../../test/helpers/temp-dir.js";
import { withEnvAsync } from "../../../test-utils/env.js";
import { createReadToolDefinition } from "./read.js";
import { DEFAULT_MAX_BYTES } from "./truncate.js";
import { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES } from "./truncate.js";
const decodeWindowsTextFileBufferMock = vi.hoisted(() => vi.fn(() => ""));
const tempDirs = useAutoCleanupTempDirTracker(afterEach);
@@ -43,6 +43,21 @@ function textContent(
return first?.type === "text" ? (first.text ?? "") : "";
}
const plainTheme = {
fg: (_token: string, text: string) => text,
bold: (text: string) => text,
} as never;
function renderReadCall(args: { path: string; offset?: number; limit?: number }): string {
const tool = createReadToolDefinition("/workspace");
const component = tool.renderCall?.(args, plainTheme, {
lastComponent: undefined,
expanded: true,
cwd: "/workspace",
} as never);
return component?.render(120).join("\n").trimEnd() ?? "";
}
describe("read tool", () => {
beforeEach(() => {
decodeWindowsTextFileBufferMock.mockReset();
@@ -151,6 +166,14 @@ describe("read tool", () => {
expect(textContent(result)).toBe("alpha\n\n[2 more lines in file. Use offset=2 to continue.]");
});
it.each([
{ limit: -1, range: ":1-1" },
{ limit: 1.5, range: ":1-1" },
{ limit: Number.POSITIVE_INFINITY, range: `:1-${DEFAULT_MAX_LINES}` },
])("normalizes read call line ranges for limit $limit", ({ limit, range }) => {
expect(renderReadCall({ path: "notes.txt", limit })).toBe(`read notes.txt${range}`);
});
it.each([0, -1, 1.5])("rejects invalid offset %s before accessing the file", async (offset) => {
const access = vi.fn(async () => {});
const detectImageMimeType = vi.fn(async () => null);

View File

@@ -87,7 +87,9 @@ function formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): st
return "";
}
const startLine = args.offset ?? 1;
const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
const normalizedLimit =
args.limit !== undefined ? normalizePositiveLimit(args.limit, DEFAULT_MAX_LINES) : undefined;
const endLine = normalizedLimit !== undefined ? startLine + normalizedLimit - 1 : "";
return theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
}