Skip to content

Commit 383eed4

Browse files
committed
fix(amazonq) Previous and subsequent cells are used as context for completion in a Jupyter notebook
1 parent e6464d4 commit 383eed4

File tree

2 files changed

+79
-94
lines changed

2 files changed

+79
-94
lines changed

packages/amazonq/test/unit/codewhisperer/util/editorContext.test.ts

Lines changed: 56 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -214,127 +214,122 @@ describe('editorContext', function () {
214214
})
215215

216216
describe('extractPrefixCellsContext', function () {
217-
it('Should extract content from cells in reverse order up to maxLength', function () {
217+
it('Should extract content from cells in reverse order up to maxLength from prefix cells', function () {
218218
const mockCells = [
219219
createNotebookCell(createMockDocument('First cell content')),
220220
createNotebookCell(createMockDocument('Second cell content')),
221221
createNotebookCell(createMockDocument('Third cell content')),
222222
]
223223

224-
const result = EditorContext.extractPrefixCellsContext(mockCells, 100, 'python')
224+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', false)
225225
assert.strictEqual(result, 'First cell content\nSecond cell content\nThird cell content\n')
226226
})
227227

228-
it('Should respect maxLength parameter', function () {
228+
it('Should extract content from cells in reverse order up to maxLength from suffix cells', function () {
229+
const mockCells = [
230+
createNotebookCell(createMockDocument('First cell content')),
231+
createNotebookCell(createMockDocument('Second cell content')),
232+
createNotebookCell(createMockDocument('Third cell content')),
233+
]
234+
235+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', true)
236+
assert.strictEqual(result, 'First cell content\nSecond cell content\nThird cell content\n')
237+
})
238+
239+
it('Should respect maxLength parameter from prefix cells', function () {
229240
const mockCells = [
230241
createNotebookCell(createMockDocument('First')),
231242
createNotebookCell(createMockDocument('Second')),
232243
createNotebookCell(createMockDocument('Third')),
233244
createNotebookCell(createMockDocument('Fourth')),
234245
]
235-
236-
const result = EditorContext.extractPrefixCellsContext(mockCells, 15, 'python')
246+
// Should only include part of second cell and the last two cells
247+
const result = EditorContext.extractCellsSliceContext(mockCells, 15, 'python', false)
237248
assert.strictEqual(result, 'd\nThird\nFourth\n')
238249
})
239250

240-
it('Should handle empty cells array', function () {
241-
const result = EditorContext.extractPrefixCellsContext([], 100, '')
251+
it('Should respect maxLength parameter from suffix cells', function () {
252+
const mockCells = [
253+
createNotebookCell(createMockDocument('First')),
254+
createNotebookCell(createMockDocument('Second')),
255+
createNotebookCell(createMockDocument('Third')),
256+
createNotebookCell(createMockDocument('Fourth')),
257+
]
258+
259+
// Should only include first cell and part of second cell
260+
const result = EditorContext.extractCellsSliceContext(mockCells, 15, 'python', true)
261+
assert.strictEqual(result, 'First\nSecond\nTh')
262+
})
263+
264+
it('Should handle empty cells array from prefix cells', function () {
265+
const result = EditorContext.extractCellsSliceContext([], 100, 'python', false)
242266
assert.strictEqual(result, '')
243267
})
244268

245-
it('Should add python comments to markdown cells', function () {
246-
const mockCells = [
247-
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
248-
createNotebookCell(createMockDocument('def example():\n return "test"')),
249-
]
250-
const result = EditorContext.extractPrefixCellsContext(mockCells, 100, 'python')
251-
assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n')
269+
it('Should handle empty cells array from suffix cells', function () {
270+
const result = EditorContext.extractCellsSliceContext([], 100, 'python', true)
271+
assert.strictEqual(result, '')
252272
})
253273

254-
it('Should add java comments to markdown and python cells when language is java', function () {
274+
it('Should add python comments to markdown prefix cells', function () {
255275
const mockCells = [
256276
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
257277
createNotebookCell(createMockDocument('def example():\n return "test"')),
258278
]
259-
const result = EditorContext.extractPrefixCellsContext(mockCells, 100, 'java')
260-
assert.strictEqual(result, '// # Heading\n// This is markdown\n// def example():\n// return "test"\n')
279+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', false)
280+
assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n')
261281
})
262282

263-
it('Should handle code cells with different languages', function () {
283+
it('Should add python comments to markdown suffix cells', function () {
264284
const mockCells = [
265-
createNotebookCell(
266-
createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java'),
267-
vscode.NotebookCellKind.Code
268-
),
285+
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
269286
createNotebookCell(createMockDocument('def example():\n return "test"')),
270287
]
271-
const result = EditorContext.extractPrefixCellsContext(mockCells, 100, 'python')
272-
assert.strictEqual(result, '# println(1 + 1);\ndef example():\n return "test"\n')
273-
})
274-
})
275288

276-
describe('extractSuffixCellsContext', function () {
277-
it('Should extract content from cells in order up to maxLength', function () {
278-
const mockCells = [
279-
createNotebookCell(createMockDocument('First cell content')),
280-
createNotebookCell(createMockDocument('Second cell content')),
281-
createNotebookCell(createMockDocument('Third cell content')),
282-
]
283-
284-
const result = EditorContext.extractSuffixCellsContext(mockCells, 100, 'python')
285-
assert.strictEqual(result, 'First cell content\nSecond cell content\nThird cell content\n')
289+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', true)
290+
assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n')
286291
})
287292

288-
it('Should respect maxLength parameter', function () {
293+
it('Should add java comments to markdown and python prefix cells when language is java', function () {
289294
const mockCells = [
290-
createNotebookCell(createMockDocument('First')),
291-
createNotebookCell(createMockDocument('Second')),
292-
createNotebookCell(createMockDocument('Third')),
293-
createNotebookCell(createMockDocument('Fourth')),
295+
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
296+
createNotebookCell(createMockDocument('def example():\n return "test"')),
294297
]
295-
296-
// Should only include first cell and part of second cell
297-
const result = EditorContext.extractSuffixCellsContext(mockCells, 15, 'plaintext')
298-
assert.strictEqual(result, 'First\nSecond\nTh')
299-
})
300-
301-
it('Should handle empty cells array', function () {
302-
const result = EditorContext.extractSuffixCellsContext([], 100, 'plaintext')
303-
assert.strictEqual(result, '')
298+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'java', false)
299+
assert.strictEqual(result, '// # Heading\n// This is markdown\n// def example():\n// return "test"\n')
304300
})
305301

306-
it('Should add python comments to markdown cells', function () {
302+
it('Should add java comments to markdown and python suffix cells when language is java', function () {
307303
const mockCells = [
308304
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
309-
createNotebookCell(createMockDocument('def example():\n return "test"')),
305+
createNotebookCell(createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java')),
310306
]
311307

312-
const result = EditorContext.extractSuffixCellsContext(mockCells, 100, 'python')
313-
assert.strictEqual(result, '# # Heading\n# This is markdown\ndef example():\n return "test"\n')
308+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'java', true)
309+
assert.strictEqual(result, '// # Heading\n// This is markdown\nprintln(1 + 1);\n')
314310
})
315311

316-
it('Should add java comments to markdown cells', function () {
312+
it('Should handle code prefix cells with different languages', function () {
317313
const mockCells = [
318-
createNotebookCell(createMockDocument('# Heading\nThis is markdown'), vscode.NotebookCellKind.Markup),
319314
createNotebookCell(
320315
createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java'),
321316
vscode.NotebookCellKind.Code
322317
),
318+
createNotebookCell(createMockDocument('def example():\n return "test"')),
323319
]
324-
325-
const result = EditorContext.extractSuffixCellsContext(mockCells, 100, 'java')
326-
assert.strictEqual(result, '// # Heading\n// This is markdown\nprintln(1 + 1);\n')
320+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', false)
321+
assert.strictEqual(result, '# println(1 + 1);\ndef example():\n return "test"\n')
327322
})
328323

329-
it('Should handle code cells with different languages', function () {
324+
it('Should handle code suffix cells with different languages', function () {
330325
const mockCells = [
331326
createNotebookCell(
332327
createMockDocument('println(1 + 1);', 'somefile.ipynb', 'java'),
333328
vscode.NotebookCellKind.Code
334329
),
335330
createNotebookCell(createMockDocument('def example():\n return "test"')),
336331
]
337-
const result = EditorContext.extractSuffixCellsContext(mockCells, 100, 'python')
332+
const result = EditorContext.extractCellsSliceContext(mockCells, 100, 'python', true)
338333
assert.strictEqual(result, '# println(1 + 1);\ndef example():\n return "test"\n')
339334
})
340335
})

packages/core/src/codewhisperer/util/editorContext.ts

Lines changed: 23 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,45 +50,33 @@ export function extractSingleCellContext(cell: vscode.NotebookCell, referenceLan
5050
return cellText
5151
}
5252

53-
export function extractPrefixCellsContext(
53+
export function extractCellsSliceContext(
5454
cells: vscode.NotebookCell[],
5555
maxLength: number,
56-
referenceLanguage: string
56+
referenceLanguage: string,
57+
fromStart: boolean
5758
): string {
58-
const output: string[] = []
59-
for (let i = cells.length - 1; i >= 0; i--) {
60-
let cellText = addNewlineIfMissing(extractSingleCellContext(cells[i], referenceLanguage))
61-
if (cellText.length > 0) {
62-
if (cellText.length >= maxLength) {
63-
output.unshift(cellText.substring(cellText.length - maxLength))
64-
break
65-
}
66-
output.unshift(cellText)
67-
maxLength -= cellText.length
68-
}
59+
let output: string[] = []
60+
if (!fromStart) {
61+
cells = cells.reverse()
6962
}
70-
return output.join('')
71-
}
72-
73-
export function extractSuffixCellsContext(
74-
cells: vscode.NotebookCell[],
75-
maxLength: number,
76-
referenceLanguage: string
77-
): string {
78-
const output: string[] = []
79-
for (let i = 0; i < cells.length; i++) {
80-
let cellText = addNewlineIfMissing(extractSingleCellContext(cells[i], referenceLanguage))
63+
cells.some((cell) => {
64+
let cellText = addNewlineIfMissing(extractSingleCellContext(cell, referenceLanguage))
8165
if (cellText.length > 0) {
82-
if (!cellText.endsWith('\n')) {
83-
cellText += '\n'
84-
}
8566
if (cellText.length >= maxLength) {
86-
output.push(cellText.substring(0, maxLength))
87-
break
67+
if (fromStart) {
68+
output.push(cellText.substring(0, maxLength))
69+
} else {
70+
output.push(cellText.substring(cellText.length - maxLength))
71+
}
72+
return true
8873
}
8974
output.push(cellText)
9075
maxLength -= cellText.length
9176
}
77+
})
78+
if (!fromStart) {
79+
output = output.reverse()
9280
}
9381
return output.join('')
9482
}
@@ -135,21 +123,23 @@ export function extractContextForCodeWhisperer(editor: vscode.TextEditor): codew
135123

136124
// Extract text from prior cells if there is enough room in left file context
137125
if (caretLeftFileContext.length < CodeWhispererConstants.charactersLimit - 1) {
138-
const leftCellsText = extractPrefixCellsContext(
126+
const leftCellsText = extractCellsSliceContext(
139127
allCells.slice(0, cellIndex),
140128
CodeWhispererConstants.charactersLimit - (caretLeftFileContext.length + 1),
141-
languageName
129+
languageName,
130+
true
142131
)
143132
if (leftCellsText.length > 0) {
144133
caretLeftFileContext = addNewlineIfMissing(leftCellsText) + caretLeftFileContext
145134
}
146135
}
147136
// Extract text from subsequent cells if there is enough room in right file context
148137
if (caretRightFileContext.length < CodeWhispererConstants.charactersLimit - 1) {
149-
const rightCellsText = extractSuffixCellsContext(
138+
const rightCellsText = extractCellsSliceContext(
150139
allCells.slice(cellIndex + 1),
151140
CodeWhispererConstants.charactersLimit - (caretRightFileContext.length + 1),
152-
languageName
141+
languageName,
142+
false
153143
)
154144
if (rightCellsText.length > 0) {
155145
caretRightFileContext = addNewlineIfMissing(caretRightFileContext) + rightCellsText

0 commit comments

Comments
 (0)