Adjust the read_file prompt based on whether partial reads are enabled (#3995)

This commit is contained in:
Matt Rubens 2025-05-26 14:55:53 -04:00 committed by GitHub
parent 61a381af55
commit ce6cc6fa97
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 615 additions and 334 deletions

File diff suppressed because it is too large Load diff

View file

@ -76,6 +76,9 @@ describe("File-Based Custom System Prompt", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Should contain default sections
@ -110,6 +113,9 @@ describe("File-Based Custom System Prompt", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Should contain role definition and file-based system prompt
@ -153,6 +159,9 @@ describe("File-Based Custom System Prompt", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Should contain custom role definition and file-based system prompt

View file

@ -211,6 +211,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -231,6 +234,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -253,6 +259,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -273,6 +282,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -293,6 +305,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -313,6 +328,9 @@ describe("SYSTEM_PROMPT", () => {
true, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toContain("apply_diff")
@ -334,6 +352,9 @@ describe("SYSTEM_PROMPT", () => {
false, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).not.toContain("apply_diff")
@ -355,6 +376,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).not.toContain("apply_diff")
@ -403,6 +427,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toContain("Language Preference:")
@ -461,6 +488,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
experiments,
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Role definition should be at the top
@ -496,6 +526,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
undefined, // experiments
false, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Role definition from promptComponent should be at the top
@ -526,6 +559,9 @@ describe("SYSTEM_PROMPT", () => {
undefined, // diffEnabled
undefined, // experiments
false, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
// Should use the default mode's role definition
@ -570,6 +606,9 @@ describe("addCustomInstructions", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -590,6 +629,9 @@ describe("addCustomInstructions", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
@ -612,6 +654,9 @@ describe("addCustomInstructions", () => {
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).toContain("Creating an MCP Server")
@ -635,12 +680,38 @@ describe("addCustomInstructions", () => {
undefined, // diffEnabled
undefined, // experiments
false, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
undefined, // partialReadsEnabled
)
expect(prompt).not.toContain("Creating an MCP Server")
expect(prompt).toMatchSnapshot()
})
it("should include partial read instructions when partialReadsEnabled is true", async () => {
const prompt = await SYSTEM_PROMPT(
mockContext,
"/test/path",
false, // supportsComputerUse
undefined, // mcpHub
undefined, // diffStrategy
undefined, // browserViewportSize
defaultModeSlug, // mode
undefined, // customModePrompts
undefined, // customModes,
undefined, // globalCustomInstructions
undefined, // diffEnabled
undefined, // experiments
true, // enableMcpServerCreation
undefined, // language
undefined, // rooIgnoreInstructions
true, // partialReadsEnabled
)
expect(prompt).toMatchSnapshot()
})
it("should prioritize mode-specific rules for code mode", async () => {
const instructions = await addCustomInstructions("", "", "/test/path", defaultModeSlug)
expect(instructions).toMatchSnapshot()

View file

@ -45,6 +45,7 @@ async function generatePrompt(
enableMcpServerCreation?: boolean,
language?: string,
rooIgnoreInstructions?: string,
partialReadsEnabled?: boolean,
): Promise<string> {
if (!context) {
throw new Error("Extension context is required for generating system prompt")
@ -82,6 +83,7 @@ ${getToolDescriptionsForMode(
mcpHub,
customModeConfigs,
experiments,
partialReadsEnabled,
)}
${getToolUseGuidelinesSection()}
@ -119,6 +121,7 @@ export const SYSTEM_PROMPT = async (
enableMcpServerCreation?: boolean,
language?: string,
rooIgnoreInstructions?: string,
partialReadsEnabled?: boolean,
): Promise<string> => {
if (!context) {
throw new Error("Extension context is required for generating system prompt")
@ -185,5 +188,6 @@ ${customInstructions}`
enableMcpServerCreation,
language,
rooIgnoreInstructions,
partialReadsEnabled,
)
}

View file

@ -56,6 +56,7 @@ export function getToolDescriptionsForMode(
mcpHub?: McpHub,
customModes?: ModeConfig[],
experiments?: Record<string, boolean>,
partialReadsEnabled?: boolean,
): string {
const config = getModeConfig(mode, customModes)
const args: ToolArgs = {
@ -64,6 +65,7 @@ export function getToolDescriptionsForMode(
diffStrategy,
browserViewportSize,
mcpHub,
partialReadsEnabled,
}
const tools = new Set<string>()

View file

@ -1,17 +1,39 @@
import { ToolArgs } from "./types"
export function getReadFileDescription(args: ToolArgs): string {
return `## read_file
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. The output includes line numbers prefixed to each line (e.g. "1 | const x = 1"), making it easier to reference specific lines when creating diffs or discussing code. By specifying start_line and end_line parameters, you can efficiently read specific portions of large files without loading the entire file into memory. Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string.
// Base description without partial read instructions
let description = `## read_file
Description: Request to read the contents of a file at the specified path. Use this when you need to examine the contents of an existing file you do not know the contents of, for example to analyze code, review text files, or extract information from configuration files. The output includes line numbers prefixed to each line (e.g. "1 | const x = 1"), making it easier to reference specific lines when creating diffs or discussing code.`
// Add partial read instructions only when partial reads are active
if (args.partialReadsEnabled) {
description += ` By specifying start_line and end_line parameters, you can efficiently read specific portions of large files without loading the entire file into memory.`
}
description += ` Automatically extracts raw text from PDF and DOCX files. May not be suitable for other types of binary files, as it returns the raw content as a string.
Parameters:
- path: (required) The path of the file to read (relative to the current workspace directory ${args.cwd})
- path: (required) The path of the file to read (relative to the current workspace directory ${args.cwd})`
// Add start_line and end_line parameters only when partial reads are active
if (args.partialReadsEnabled) {
description += `
- start_line: (optional) The starting line number to read from (1-based). If not provided, it starts from the beginning of the file.
- end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file.
- end_line: (optional) The ending line number to read to (1-based, inclusive). If not provided, it reads to the end of the file.`
}
description += `
Usage:
<read_file>
<path>File path here</path>
<path>File path here</path>`
// Add start_line and end_line in usage only when partial reads are active
if (args.partialReadsEnabled) {
description += `
<start_line>Starting line number (optional)</start_line>
<end_line>Ending line number (optional)</end_line>
<end_line>Ending line number (optional)</end_line>`
}
description += `
</read_file>
Examples:
@ -19,7 +41,11 @@ Examples:
1. Reading an entire file:
<read_file>
<path>frontend-config.json</path>
</read_file>
</read_file>`
// Add partial read examples only when partial reads are active
if (args.partialReadsEnabled) {
description += `
2. Reading the first 1000 lines of a large log file:
<read_file>
@ -42,4 +68,7 @@ Examples:
</read_file>
Note: When both start_line and end_line are provided, this tool efficiently streams only the requested lines, making it suitable for processing large files like logs, CSV files, and other large datasets without memory issues.`
}
return description
}

View file

@ -8,4 +8,5 @@ export type ToolArgs = {
browserViewportSize?: string
mcpHub?: McpHub
toolOptions?: any
partialReadsEnabled?: boolean
}

View file

@ -1451,18 +1451,19 @@ export class Task extends EventEmitter<ClineEvents> {
const rooIgnoreInstructions = this.rooIgnoreController?.getInstructions()
const state = await this.providerRef.deref()?.getState()
const {
browserViewportSize,
mode,
customModes,
customModePrompts,
customInstructions,
experiments,
enableMcpServerCreation,
browserToolEnabled,
language,
} = (await this.providerRef.deref()?.getState()) ?? {}
const { customModes } = (await this.providerRef.deref()?.getState()) ?? {}
maxReadFileLine,
} = state ?? {}
return await (async () => {
const provider = this.providerRef.deref()
@ -1487,6 +1488,7 @@ export class Task extends EventEmitter<ClineEvents> {
enableMcpServerCreation,
language,
rooIgnoreInstructions,
maxReadFileLine !== -1,
)
})()
}

View file

@ -20,6 +20,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
enableMcpServerCreation,
browserToolEnabled,
language,
maxReadFileLine,
} = await provider.getState()
const diffStrategy = new MultiSearchReplaceDiffStrategy(fuzzyMatchThreshold)
@ -67,6 +68,7 @@ export const generateSystemPrompt = async (provider: ClineProvider, message: Web
enableMcpServerCreation,
language,
rooIgnoreInstructions,
maxReadFileLine !== -1,
)
return systemPrompt