Skip to content

Commit 97f39b1

Browse files
authored
feat(codewhisperer): roll out classifier to more languages #3546
1 parent 97a0b3c commit 97f39b1

File tree

5 files changed

+66
-36
lines changed

5 files changed

+66
-36
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type": "Feature",
3+
"description": "CodeWhisperer improves auto-suggestions for java python typescript and csharp"
4+
}

src/codewhisperer/service/classifierTrigger.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,23 +332,24 @@ export class ClassifierTrigger {
332332

333333
public shouldInvokeClassifier(language: string) {
334334
const mappedLanguage = runtimeLanguageContext.mapVscLanguageToCodeWhispererLanguage(language)
335-
return this.isClassifierEnabled() && this.isSupportedLanguage(mappedLanguage)
335+
return this.isSupportedLanguage(mappedLanguage)
336336
}
337337

338338
public recordClassifierResultForManualTrigger(editor: vscode.TextEditor) {
339339
if (this.shouldInvokeClassifier(editor.document.languageId)) {
340-
this.shouldTriggerFromClassifier(undefined, editor, undefined)
340+
this.shouldTriggerFromClassifier(undefined, editor, undefined, true)
341341
}
342342
}
343343

344344
public recordClassifierResultForAutoTrigger(
345-
event: vscode.TextDocumentChangeEvent,
346345
editor: vscode.TextEditor,
347-
triggerType: CodewhispererAutomatedTriggerType
346+
triggerType?: CodewhispererAutomatedTriggerType,
347+
event?: vscode.TextDocumentChangeEvent
348348
) {
349-
if (triggerType !== 'Classifier') {
350-
this.shouldTriggerFromClassifier(event, editor, triggerType)
349+
if (!triggerType) {
350+
return
351351
}
352+
this.shouldTriggerFromClassifier(event, editor, triggerType, true)
352353
}
353354

354355
public isSupportedLanguage(language?: CodewhispererLanguage) {
@@ -361,7 +362,8 @@ export class ClassifierTrigger {
361362
public shouldTriggerFromClassifier(
362363
event: vscode.TextDocumentChangeEvent | undefined,
363364
editor: vscode.TextEditor,
364-
autoTriggerType: string | undefined
365+
autoTriggerType: string | undefined,
366+
shouldRecordResult: boolean = false
365367
): boolean {
366368
const fileContext = extractContextForCodeWhisperer(editor)
367369
const osPlatform = this.normalizeOsName(os.platform(), os.version())
@@ -382,8 +384,10 @@ export class ClassifierTrigger {
382384
const threshold = this.getThreshold()
383385

384386
const shouldTrigger = classifierResult > threshold
385-
TelemetryHelper.instance.setClassifierResult(classifierResult)
386-
TelemetryHelper.instance.setClassifierThreshold(threshold)
387+
if (shouldRecordResult) {
388+
TelemetryHelper.instance.setClassifierResult(classifierResult)
389+
TelemetryHelper.instance.setClassifierThreshold(threshold)
390+
}
387391
return shouldTrigger
388392
}
389393

src/codewhisperer/service/inlineCompletionService.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import { shared } from '../../shared/utilities/functionUtils'
2525
import { ImportAdderProvider } from './importAdderProvider'
2626
import * as AsyncLock from 'async-lock'
2727
import { updateInlineLockKey } from '../models/constants'
28+
import { ClassifierTrigger } from './classifierTrigger'
2829

2930
const performance = globalThis.performance ?? require('perf_hooks').performance
3031
const lock = new AsyncLock({ maxPending: 1 })
@@ -392,11 +393,19 @@ export class InlineCompletionService {
392393
editor: vscode.TextEditor,
393394
triggerType: CodewhispererTriggerType,
394395
config: ConfigurationEntry,
395-
autoTriggerType?: CodewhispererAutomatedTriggerType
396+
autoTriggerType?: CodewhispererAutomatedTriggerType,
397+
event?: vscode.TextDocumentChangeEvent
396398
) {
397399
if (vsCodeState.isCodeWhispererEditing || this._isPaginationRunning || this.isSuggestionVisible()) {
398400
return
399401
}
402+
if (ClassifierTrigger.instance.shouldInvokeClassifier(editor.document.languageId)) {
403+
ClassifierTrigger.instance.recordClassifierResultForAutoTrigger(editor, autoTriggerType, event)
404+
}
405+
const triggerChar = event?.contentChanges[0]?.text
406+
if (autoTriggerType === 'SpecialCharacters' && triggerChar) {
407+
TelemetryHelper.instance.setTriggerCharForUserTriggerDecision(triggerChar)
408+
}
400409
const isAutoTrigger = triggerType === 'AutoTrigger'
401410
if (AuthUtil.instance.isConnectionExpired()) {
402411
await AuthUtil.instance.notifyReauthenticate(isAutoTrigger)

src/codewhisperer/service/keyStrokeHandler.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ export class KeyStrokeHandler {
6767
}
6868

6969
try {
70-
this.invokeAutomatedTrigger('IdleTime', editor, client, config)
70+
this.invokeAutomatedTrigger('IdleTime', editor, client, config, event)
7171
} finally {
7272
if (this.idleTriggerTimer) {
7373
clearInterval(this.idleTriggerTimer)
@@ -142,13 +142,7 @@ export class KeyStrokeHandler {
142142
}
143143

144144
if (triggerType) {
145-
if (ClassifierTrigger.instance.shouldInvokeClassifier(editor.document.languageId)) {
146-
ClassifierTrigger.instance.recordClassifierResultForAutoTrigger(event, editor, triggerType)
147-
}
148-
if (changedSource === DocumentChangedSource.SpecialCharsKey) {
149-
TelemetryHelper.instance.setTriggerCharForUserTriggerDecision(event.contentChanges[0].text)
150-
}
151-
this.invokeAutomatedTrigger(triggerType, editor, client, config)
145+
this.invokeAutomatedTrigger(triggerType, editor, client, config, event)
152146
}
153147
} catch (error) {
154148
getLogger().error('Automated Trigger Exception : ', error)
@@ -160,7 +154,8 @@ export class KeyStrokeHandler {
160154
autoTriggerType: CodewhispererAutomatedTriggerType,
161155
editor: vscode.TextEditor,
162156
client: DefaultCodeWhispererClient,
163-
config: ConfigurationEntry
157+
config: ConfigurationEntry,
158+
event: vscode.TextDocumentChangeEvent
164159
): Promise<void> {
165160
if (editor) {
166161
ClassifierTrigger.instance.setLastInvocationLineNumber(editor.selection.active.line)
@@ -210,7 +205,8 @@ export class KeyStrokeHandler {
210205
editor,
211206
'AutoTrigger',
212207
config,
213-
autoTriggerType
208+
autoTriggerType,
209+
event
214210
)
215211
}
216212
}

src/test/codewhisperer/service/keyStrokeHandler.test.ts

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { InlineCompletionService } from '../../../codewhisperer/service/inlineCo
1818
import * as EditorContext from '../../../codewhisperer/util/editorContext'
1919
import { RecommendationHandler } from '../../../codewhisperer/service/recommendationHandler'
2020
import { isInlineCompletionEnabled } from '../../../codewhisperer/util/commonUtil'
21+
import { ClassifierTrigger } from '../../../codewhisperer/service/classifierTrigger'
2122

2223
const performance = globalThis.performance ?? require('perf_hooks').performance
2324

@@ -67,19 +68,6 @@ describe('keyStrokeHandler', function () {
6768
assert.ok(!startTimerSpy.called)
6869
})
6970

70-
it('Should not call invokeAutomatedTrigger when changed text matches active recommendation prefix', async function () {
71-
const mockEditor = createMockTextEditor()
72-
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
73-
mockEditor.document,
74-
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
75-
'd'
76-
)
77-
RecommendationHandler.instance.startPos = new vscode.Position(1, 0)
78-
RecommendationHandler.instance.recommendations = [{ content: 'def two_sum(nums, target):\n for i in nums' }]
79-
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
80-
assert.ok(!invokeSpy.called)
81-
})
82-
8371
it('Should not call invokeAutomatedTrigger when changed text across multiple lines', async function () {
8472
const mockEditor = createMockTextEditor()
8573
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
@@ -200,8 +188,8 @@ describe('keyStrokeHandler', function () {
200188
assert.ok(!startTimerSpy.called)
201189
})
202190

203-
it('Should start idle trigger timer when inputing non-special characters', async function () {
204-
const mockEditor = createMockTextEditor('function addTwo', 'test.js', 'javascript')
191+
it('Should start idle trigger timer when inputing non-special characters for non-classifier language', async function () {
192+
const mockEditor = createMockTextEditor('def addTwo', 'test.rb', 'ruby')
205193
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
206194
mockEditor.document,
207195
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
@@ -210,6 +198,30 @@ describe('keyStrokeHandler', function () {
210198
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
211199
assert.ok(startTimerSpy.called)
212200
})
201+
202+
it('Should not call invokeAutomatedTrigger for non-special characters for classifier language if classifier says no', async function () {
203+
const mockEditor = createMockTextEditor('function addTwo', 'test.js', 'javascript')
204+
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
205+
mockEditor.document,
206+
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
207+
'a'
208+
)
209+
sinon.stub(ClassifierTrigger.instance, 'shouldTriggerFromClassifier').returns(false)
210+
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
211+
assert.ok(!invokeSpy.called)
212+
})
213+
214+
it('Should call invokeAutomatedTrigger for non-special characters for classifier language if classifier says yes', async function () {
215+
const mockEditor = createMockTextEditor('function addTwo', 'test.js', 'javascript')
216+
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
217+
mockEditor.document,
218+
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
219+
'a'
220+
)
221+
sinon.stub(ClassifierTrigger.instance, 'shouldTriggerFromClassifier').returns(true)
222+
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
223+
assert.ok(invokeSpy.called)
224+
})
213225
})
214226

215227
describe('invokeAutomatedTrigger', function () {
@@ -228,8 +240,13 @@ describe('keyStrokeHandler', function () {
228240
it('should call getPaginatedRecommendation when inline completion is enabled', async function () {
229241
const mockEditor = createMockTextEditor()
230242
const keyStrokeHandler = new KeyStrokeHandler()
243+
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
244+
mockEditor.document,
245+
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
246+
' '
247+
)
231248
const getRecommendationsStub = sinon.stub(InlineCompletionService.instance, 'getPaginatedRecommendation')
232-
await keyStrokeHandler.invokeAutomatedTrigger('Enter', mockEditor, mockClient, config)
249+
await keyStrokeHandler.invokeAutomatedTrigger('Enter', mockEditor, mockClient, config, mockEvent)
233250
assert.strictEqual(getRecommendationsStub.called, isInlineCompletionEnabled())
234251
})
235252
})

0 commit comments

Comments
 (0)