fix(coding-agent): show compact read line ranges
This commit is contained in:
@@ -61,22 +61,21 @@ export interface ReadToolOptions {
|
||||
operations?: ReadOperations;
|
||||
}
|
||||
|
||||
function formatReadCall(
|
||||
args: { path?: string; file_path?: string; offset?: number; limit?: number } | undefined,
|
||||
theme: Theme,
|
||||
): string {
|
||||
type ReadRenderArgs = { path?: string; file_path?: string; offset?: number; limit?: number };
|
||||
|
||||
function formatReadLineRange(args: ReadRenderArgs | undefined, theme: Theme): string {
|
||||
if (args?.offset === undefined && args?.limit === undefined) return "";
|
||||
const startLine = args.offset ?? 1;
|
||||
const endLine = args.limit !== undefined ? startLine + args.limit - 1 : "";
|
||||
return theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
|
||||
}
|
||||
|
||||
function formatReadCall(args: ReadRenderArgs | undefined, theme: Theme): string {
|
||||
const rawPath = str(args?.file_path ?? args?.path);
|
||||
const path = rawPath !== null ? shortenPath(rawPath) : null;
|
||||
const offset = args?.offset;
|
||||
const limit = args?.limit;
|
||||
const invalidArg = invalidArgText(theme);
|
||||
let pathDisplay = path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
|
||||
if (offset !== undefined || limit !== undefined) {
|
||||
const startLine = offset ?? 1;
|
||||
const endLine = limit !== undefined ? startLine + limit - 1 : "";
|
||||
pathDisplay += theme.fg("warning", `:${startLine}${endLine ? `-${endLine}` : ""}`);
|
||||
}
|
||||
return `${theme.fg("toolTitle", theme.bold("read"))} ${pathDisplay}`;
|
||||
const pathDisplay = path === null ? invalidArg : path ? theme.fg("accent", path) : theme.fg("toolOutput", "...");
|
||||
return `${theme.fg("toolTitle", theme.bold("read"))} ${pathDisplay}${formatReadLineRange(args, theme)}`;
|
||||
}
|
||||
|
||||
function trimTrailingEmptyLines(lines: string[]): string[] {
|
||||
@@ -118,7 +117,7 @@ function getPiDocsClassification(absolutePath: string): CompactReadClassificatio
|
||||
}
|
||||
|
||||
function getCompactReadClassification(
|
||||
args: { path?: string; file_path?: string } | undefined,
|
||||
args: ReadRenderArgs | undefined,
|
||||
cwd: string,
|
||||
): CompactReadClassification | undefined {
|
||||
const rawPath = str(args?.file_path ?? args?.path);
|
||||
@@ -140,12 +139,18 @@ function getCompactReadClassification(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function formatCompactReadCall(classification: CompactReadClassification, theme: Theme): string {
|
||||
function formatCompactReadCall(
|
||||
classification: CompactReadClassification,
|
||||
args: ReadRenderArgs | undefined,
|
||||
theme: Theme,
|
||||
): string {
|
||||
const expandHint = theme.fg("dim", ` (${keyText("app.tools.expand")} to expand)`);
|
||||
if (classification.kind === "skill") {
|
||||
return (
|
||||
theme.fg("customMessageLabel", `\x1b[1m[skill]\x1b[22m `) +
|
||||
theme.fg("customMessageText", classification.label) +
|
||||
theme.fg("dim", ` (${keyText("app.tools.expand")} to expand)`)
|
||||
formatReadLineRange(args, theme) +
|
||||
expandHint
|
||||
);
|
||||
}
|
||||
|
||||
@@ -153,12 +158,13 @@ function formatCompactReadCall(classification: CompactReadClassification, theme:
|
||||
theme.fg("toolTitle", theme.bold(`read ${classification.kind}`)) +
|
||||
" " +
|
||||
theme.fg("accent", classification.label) +
|
||||
theme.fg("dim", ` (${keyText("app.tools.expand")} to expand)`)
|
||||
formatReadLineRange(args, theme) +
|
||||
expandHint
|
||||
);
|
||||
}
|
||||
|
||||
function formatReadResult(
|
||||
args: { path?: string; file_path?: string; offset?: number; limit?: number } | undefined,
|
||||
args: ReadRenderArgs | undefined,
|
||||
result: { content: (TextContent | ImageContent)[]; details?: ReadToolDetails },
|
||||
options: ToolRenderResultOptions,
|
||||
theme: Theme,
|
||||
@@ -336,7 +342,9 @@ export function createReadToolDefinition(
|
||||
renderCall(args, theme, context) {
|
||||
const text = (context.lastComponent as Text | undefined) ?? new Text("", 0, 0);
|
||||
const classification = !context.expanded ? getCompactReadClassification(args, context.cwd) : undefined;
|
||||
text.setText(classification ? formatCompactReadCall(classification, theme) : formatReadCall(args, theme));
|
||||
text.setText(
|
||||
classification ? formatCompactReadCall(classification, args, theme) : formatReadCall(args, theme),
|
||||
);
|
||||
return text;
|
||||
},
|
||||
renderResult(result, options, theme, context) {
|
||||
|
||||
@@ -384,4 +384,25 @@ describe("ToolExecutionComponent parity", () => {
|
||||
expect(expanded).toContain(scenario.hidden);
|
||||
});
|
||||
}
|
||||
|
||||
for (const scenario of [
|
||||
{ title: "SKILL.md", path: join(process.cwd(), "attio", "SKILL.md"), compact: "[skill] attio:120-329" },
|
||||
{ title: "Pi documentation", path: getReadmePath(), compact: "read docs README.md:120-329" },
|
||||
] as const) {
|
||||
test(`shows the read line range in compact ${scenario.title} reads before the expand hint`, () => {
|
||||
const component = new ToolExecutionComponent(
|
||||
"read",
|
||||
`tool-compact-range-${scenario.title}`,
|
||||
{ path: scenario.path, offset: 120, limit: 210 },
|
||||
{},
|
||||
createReadToolDefinition(process.cwd()),
|
||||
createFakeTui(),
|
||||
process.cwd(),
|
||||
);
|
||||
|
||||
const collapsed = stripAnsi(component.render(120).join("\n"));
|
||||
expect(collapsed).toContain(scenario.compact);
|
||||
expect(collapsed.indexOf(":120-329")).toBeLessThan(collapsed.indexOf("to expand"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user