Skip to content

Commit 5a0404e

Browse files
authored
fix(chat): Improve fsRead truncation handling (aws#7084)
## Problem - LLM sometimes gets confused when reading a large file that are truncated ## Solution - Improve fsRead truncation handling --- - Treat all work as PUBLIC. Private `feature/x` branches will not be squash-merged at release time. - Your code changes must meet the guidelines in [CONTRIBUTING.md](https://github.com/aws/aws-toolkit-vscode/blob/master/CONTRIBUTING.md#guidelines). - License: I confirm that my contribution is made under the terms of the Apache 2.0 license.
1 parent 62f6ac5 commit 5a0404e

File tree

3 files changed

+20
-13
lines changed

3 files changed

+20
-13
lines changed

packages/core/src/codewhispererChat/tools/fsRead.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,23 +139,29 @@ export class FsRead {
139139
}
140140

141141
private createOutput(content: string): InvokeOutput {
142+
let truncated = false
142143
if (content.length > fsReadToolResponseSize) {
144+
truncated = true
143145
this.logger.info(
144146
`The file is too large, truncating output to the first ${fsReadToolResponseSize} characters.`
145147
)
146148
content = this.truncateContent(content)
147149
}
150+
const outputJson = {
151+
content: content,
152+
truncated: truncated,
153+
}
148154
return {
149155
output: {
150-
kind: OutputKind.Text,
151-
content: content,
156+
kind: OutputKind.Json,
157+
content: outputJson,
152158
},
153159
}
154160
}
155161

156162
private truncateContent(content: string): string {
157163
if (content.length > fsReadToolResponseSize) {
158-
return content.substring(0, fsReadToolResponseSize)
164+
return content.substring(0, fsReadToolResponseSize - 3) + '...'
159165
}
160166
return content
161167
}

packages/core/src/codewhispererChat/tools/tool_index.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"fsRead": {
33
"name": "fsRead",
4-
"description": "A tool for reading a file.\n * This tool returns the contents of a file, and the optional `readRange` determines what range of lines will be read from the specified file.\n * If the file exceeds 200K characters, this tool will only read the first 200K characters of the file.",
4+
"description": "A tool for reading a file.\n * This tool returns the contents of a file, and the optional `readRange` determines what range of lines will be read from the specified file.\n * If the file exceeds 200K characters, this tool will only read the first 200K characters of the file with `truncated = true` in the output.",
55
"inputSchema": {
66
"type": "object",
77
"properties": {
@@ -10,7 +10,7 @@
1010
"type": "string"
1111
},
1212
"readRange": {
13-
"description": "Optional parameter when reading files.\n * If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start.\n * Setting `[startLine, -1]` shows all lines from `startLine` to the end of the file.",
13+
"description": "Optional parameter when reading files.\n * If none is given, the full file or the first 200K characters is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start.\n * Setting `[startLine, -1]` shows all lines from `startLine` to the end of the file.",
1414
"items": {
1515
"type": "integer"
1616
},

packages/core/src/test/codewhispererChat/tools/fsRead.test.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ describe('FsRead Tool', () => {
3434
await fsRead.validate()
3535
const result = await fsRead.invoke(process.stdout)
3636

37-
assert.strictEqual(result.output.kind, 'text', 'Output kind should be "text"')
38-
assert.strictEqual(result.output.content, fileContent, 'File content should match exactly')
37+
assert.strictEqual(result.output.kind, 'json', 'Output kind should be "json"')
38+
assert.strictEqual(result.output.content.content, fileContent, 'File content should match exactly')
3939
})
4040

4141
it('truncate output if too large', async () => {
@@ -44,12 +44,13 @@ describe('FsRead Tool', () => {
4444
const fsRead = new FsRead({ path: filePath })
4545
await fsRead.validate()
4646
const result = await fsRead.invoke(process.stdout)
47-
assert.strictEqual(result.output.kind, 'text', 'Output kind should be "text"')
47+
assert.strictEqual(result.output.kind, 'json', 'Output kind should be "json"')
4848
assert.strictEqual(
49-
result.output.content.length,
49+
result.output.content.content.length,
5050
fsReadToolResponseSize,
5151
'Output should be truncated to the max size'
5252
)
53+
assert.ok(result.output.content.truncated, 'Output should be truncated to the max size')
5354
})
5455

5556
it('reads partial lines of a file', async () => {
@@ -60,8 +61,8 @@ describe('FsRead Tool', () => {
6061
await fsRead.validate()
6162
const result = await fsRead.invoke(process.stdout)
6263

63-
assert.strictEqual(result.output.kind, 'text')
64-
assert.strictEqual(result.output.content, 'B\nC\nD')
64+
assert.strictEqual(result.output.kind, 'json')
65+
assert.strictEqual(result.output.content.content, 'B\nC\nD')
6566
})
6667

6768
it('throws error if path does not exist', async () => {
@@ -81,8 +82,8 @@ describe('FsRead Tool', () => {
8182

8283
await fsRead.validate()
8384
const result = await fsRead.invoke(process.stdout)
84-
assert.strictEqual(result.output.kind, 'text')
85-
assert.strictEqual(result.output.content, '')
85+
assert.strictEqual(result.output.kind, 'json')
86+
assert.strictEqual(result.output.content.content, '')
8687
})
8788

8889
it('should require acceptance if fsPath is outside the workspace', () => {

0 commit comments

Comments
 (0)