Skip to content

Commit bd7af0e

Browse files
authored
codewhisperer: fix unintended change which is causing server side error "Exceed supplemental context content length" (#3759)
1 parent dcf55e4 commit bd7af0e

File tree

3 files changed

+147
-2
lines changed

3 files changed

+147
-2
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Bug Fix",
3+
"description": "CodeWhisperer sometimes fails on big files"
4+
}

src/codewhisperer/util/supplementalContext/crossFileContextUtil.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export async function fetchSupplementalContextForSrc(
7575
let chunkList: Chunk[] = []
7676
for (const relevantFile of relevantCrossFilePaths) {
7777
throwIfCancelled(cancellationToken)
78-
const chunks: Chunk[] = splitFileToChunks(relevantFile, codeChunksCalculated)
78+
const chunks: Chunk[] = splitFileToChunks(relevantFile, crossFileContextConfig.numberOfLinesEachChunk)
7979
const linkedChunks = linkChunks(chunks)
8080
chunkList.push(...linkedChunks)
8181
if (chunkList.length >= codeChunksCalculated) {
@@ -189,7 +189,7 @@ function linkChunks(chunks: Chunk[]) {
189189
return updatedChunks
190190
}
191191

192-
function splitFileToChunks(filePath: string, chunkSize: number): Chunk[] {
192+
export function splitFileToChunks(filePath: string, chunkSize: number): Chunk[] {
193193
const chunks: Chunk[] = []
194194

195195
const fileContent = fs.readFileSync(filePath, 'utf-8').trimEnd()

src/test/codewhisperer/util/crossFileContextUtil.test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import {
1717
createTestWorkspaceFolder,
1818
openATextEditorWithText,
1919
shuffleList,
20+
toFile,
2021
} from '../../testUtil'
2122
import { areEqual, normalize } from '../../../shared/utilities/pathUtils'
2223
import * as path from 'path'
2324
import { getMinVscodeVersion } from '../../../shared/vscode/env'
25+
import { crossFileContextConfig } from '../../../codewhisperer/models/constants'
2426

2527
const userGroupSettings = CodeWhispererUserGroupSettings.instance
2628
let tempFolder: string
@@ -41,6 +43,46 @@ describe('crossFileContextUtil', function () {
4143

4244
let mockEditor: vscode.TextEditor
4345

46+
describe('fetchSupplementalContextForSrc', function () {
47+
beforeEach(async function () {
48+
tempFolder = (await createTestWorkspaceFolder()).uri.fsPath
49+
})
50+
51+
describe('should fetch 3 chunks and each chunk should contains 10 lines', function () {
52+
async function assertCorrectCodeChunk() {
53+
await openATextEditorWithText(sampleFileOf60Lines, 'CrossFile.java', tempFolder, { preview: false })
54+
const myCurrentEditor = await openATextEditorWithText('', 'TargetFile.java', tempFolder, {
55+
preview: false,
56+
})
57+
const actual = await crossFile.fetchSupplementalContextForSrc(myCurrentEditor, fakeCancellationToken)
58+
assert.ok(actual)
59+
assert.ok(actual.length === 3)
60+
61+
assert.strictEqual(actual[0].content.split('\n').length, 10)
62+
assert.strictEqual(actual[1].content.split('\n').length, 10)
63+
assert.strictEqual(actual[2].content.split('\n').length, 10)
64+
}
65+
66+
it('control group', async function () {
67+
if (!shouldRunTheTest()) {
68+
this.skip()
69+
}
70+
71+
CodeWhispererUserGroupSettings.instance.userGroup = UserGroup.Control
72+
await assertCorrectCodeChunk()
73+
})
74+
75+
it('treatment group', async function () {
76+
if (!shouldRunTheTest()) {
77+
this.skip()
78+
}
79+
80+
CodeWhispererUserGroupSettings.instance.userGroup = UserGroup.CrossFile
81+
await assertCorrectCodeChunk()
82+
})
83+
})
84+
})
85+
4486
describe('non supported language should return undefined', function () {
4587
it('c++', async function () {
4688
mockEditor = createMockTextEditor('content', 'fileName', 'cpp')
@@ -229,4 +271,103 @@ describe('crossFileContextUtil', function () {
229271
})
230272
})
231273
})
274+
275+
describe('splitFileToChunks', function () {
276+
beforeEach(async function () {
277+
tempFolder = (await createTestWorkspaceFolder()).uri.fsPath
278+
})
279+
280+
it('should split file to a chunk of 2 lines', function () {
281+
const filePath = path.join(tempFolder, 'file.txt')
282+
toFile('line_1\nline_2\nline_3\nline_4\nline_5\nline_6\nline_7', filePath)
283+
284+
const chunks = crossFile.splitFileToChunks(filePath, 2)
285+
286+
assert.strictEqual(chunks.length, 4)
287+
assert.strictEqual(chunks[0].content, 'line_1\nline_2')
288+
assert.strictEqual(chunks[1].content, 'line_3\nline_4')
289+
assert.strictEqual(chunks[2].content, 'line_5\nline_6')
290+
assert.strictEqual(chunks[3].content, 'line_7')
291+
})
292+
293+
it('should split file to a chunk of 5 lines', function () {
294+
const filePath = path.join(tempFolder, 'file.txt')
295+
toFile('line_1\nline_2\nline_3\nline_4\nline_5\nline_6\nline_7', filePath)
296+
297+
const chunks = crossFile.splitFileToChunks(filePath, 5)
298+
299+
assert.strictEqual(chunks.length, 2)
300+
assert.strictEqual(chunks[0].content, 'line_1\nline_2\nline_3\nline_4\nline_5')
301+
assert.strictEqual(chunks[1].content, 'line_6\nline_7')
302+
})
303+
304+
it('codewhisperer crossfile config should use 10 lines', function () {
305+
const filePath = path.join(tempFolder, 'file.txt')
306+
toFile(sampleFileOf60Lines, filePath)
307+
308+
const chunks = crossFile.splitFileToChunks(filePath, crossFileContextConfig.numberOfLinesEachChunk)
309+
assert.strictEqual(chunks.length, 6)
310+
})
311+
})
232312
})
313+
314+
const sampleFileOf60Lines = `import java.util.List;
315+
// we need this comment on purpose because chunk will be trimed right, adding this to avoid trimRight and make assertion easier
316+
/**
317+
*
318+
*
319+
*
320+
*
321+
*
322+
**/
323+
class Main {
324+
public static void main(String[] args) {
325+
Calculator calculator = new Calculator();
326+
calculator.add(1, 2);
327+
calculator.subtract(1, 2);
328+
calculator.multiply(1, 2);
329+
calculator.divide(1, 2);
330+
calculator.remainder(1, 2);
331+
}
332+
}
333+
//
334+
class Calculator {
335+
public Calculator() {
336+
System.out.println("constructor");
337+
}
338+
//
339+
public add(int num1, int num2) {
340+
System.out.println("add");
341+
return num1 + num2;
342+
}
343+
//
344+
public subtract(int num1, int num2) {
345+
System.out.println("subtract");
346+
return num1 - num2;
347+
}
348+
//
349+
public multiply(int num1, int num2) {
350+
System.out.println("multiply");
351+
return num1 * num2;
352+
}
353+
//
354+
public divide(int num1, int num2) {
355+
System.out.println("divide");
356+
return num1 / num2;
357+
}
358+
//
359+
public remainder(int num1, int num2) {
360+
System.out.println("remainder");
361+
return num1 % num2;
362+
}
363+
//
364+
public power(int num1, int num2) {
365+
System.out.println("power");
366+
return (int) Math.pow(num1, num2);
367+
}
368+
//
369+
public squareRoot(int num1) {
370+
System.out.println("squareRoot");
371+
return (int) Math.sqrt(num1);
372+
}
373+
}`

0 commit comments

Comments
 (0)