Skip to content

Commit df9fc73

Browse files
authored
codewhisperer: suppress token filling from auto-trigger (#3892)
1 parent 8f4c902 commit df9fc73

File tree

4 files changed

+77
-1
lines changed

4 files changed

+77
-1
lines changed

src/codewhisperer/models/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,7 @@ export enum UserGroup {
265265
Classifier = 'Classifier',
266266
CrossFile = 'CrossFile',
267267
Control = 'Control',
268+
RightContext = 'RightContext',
268269
}
269270

270271
export const isClassifierEnabledKey = 'CODEWHISPERER_CLASSIFIER_TRIGGER_ENABLED'

src/codewhisperer/service/keyStrokeHandler.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import { AuthUtil } from '../util/authUtil'
1919
import { ClassifierTrigger } from './classifierTrigger'
2020
import { isIamConnection } from '../../auth/connection'
2121
import { session } from '../util/codeWhispererSession'
22+
import { extractContextForCodeWhisperer } from '../util/editorContext'
23+
import { CodeWhispererUserGroupSettings } from '../util/userGroupUtil'
2224

2325
const performance = globalThis.performance ?? require('perf_hooks').performance
2426

@@ -111,6 +113,20 @@ export class KeyStrokeHandler {
111113
}
112114
}
113115

116+
const { rightFileContent } = extractContextForCodeWhisperer(editor)
117+
const rightContextLines = rightFileContent.split(/\r?\n/)
118+
const rightContextAtCurrentLine = rightContextLines[0]
119+
// we do not want to trigger when there is immediate right context on the same line
120+
// with "}" being an exception because of IDE auto-complete
121+
if (
122+
CodeWhispererUserGroupSettings.getUserGroup() === CodeWhispererConstants.UserGroup.RightContext &&
123+
rightContextAtCurrentLine.length &&
124+
!rightContextAtCurrentLine.startsWith(' ') &&
125+
rightContextAtCurrentLine.trim() !== '}'
126+
) {
127+
return
128+
}
129+
114130
let triggerType: CodewhispererAutomatedTriggerType | undefined
115131
const changedSource = new DefaultDocumentChangedType(event.contentChanges).checkChangeSource()
116132

src/codewhisperer/util/userGroupUtil.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ export class CodeWhispererUserGroupSettings {
5656
}
5757

5858
private guessUserGroup(): UserGroup {
59-
return UserGroup.Control
59+
const randomNum = Math.random()
60+
const result = randomNum <= 1 / 2 ? UserGroup.Control : UserGroup.RightContext
61+
return result
6062
}
6163

6264
static #instance: CodeWhispererUserGroupSettings | undefined

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { RecommendationHandler } from '../../../codewhisperer/service/recommenda
2020
import { isInlineCompletionEnabled } from '../../../codewhisperer/util/commonUtil'
2121
import { ClassifierTrigger } from '../../../codewhisperer/service/classifierTrigger'
2222
import { CodeWhispererUserGroupSettings } from '../../../codewhisperer/util/userGroupUtil'
23+
import * as CodeWhispererConstants from '../../../codewhisperer/models/constants'
2324

2425
const performance = globalThis.performance ?? require('perf_hooks').performance
2526

@@ -213,6 +214,62 @@ describe('keyStrokeHandler', function () {
213214
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
214215
assert.ok(invokeSpy.called)
215216
})
217+
218+
it('Should skip invoking if there is immediate right context on the same line and not a single } for the user group', async function () {
219+
const casesForSuppressTokenFilling = [
220+
{
221+
rightContext: 'add',
222+
shouldInvoke: false,
223+
},
224+
{
225+
rightContext: '}',
226+
shouldInvoke: true,
227+
},
228+
{
229+
rightContext: '} ',
230+
shouldInvoke: true,
231+
},
232+
{
233+
rightContext: ' add',
234+
shouldInvoke: true,
235+
},
236+
{
237+
rightContext: ' ',
238+
shouldInvoke: true,
239+
},
240+
{
241+
rightContext: '\naddTwo',
242+
shouldInvoke: true,
243+
},
244+
]
245+
casesForSuppressTokenFilling.forEach(async ({ rightContext, shouldInvoke }) => {
246+
await testIfRightContextShouldInvoke(
247+
rightContext,
248+
shouldInvoke,
249+
CodeWhispererConstants.UserGroup.RightContext
250+
)
251+
})
252+
})
253+
254+
it('Should not skip invoking based on right context for control group', async function () {
255+
await testIfRightContextShouldInvoke('add', true, CodeWhispererConstants.UserGroup.Control)
256+
})
257+
258+
async function testIfRightContextShouldInvoke(
259+
rightContext: string,
260+
shouldTrigger: boolean,
261+
userGroup: CodeWhispererConstants.UserGroup
262+
) {
263+
const mockEditor = createMockTextEditor(rightContext, 'test.js', 'javascript', 1, 1)
264+
const mockEvent: vscode.TextDocumentChangeEvent = createTextDocumentChangeEvent(
265+
mockEditor.document,
266+
new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 1)),
267+
'{'
268+
)
269+
CodeWhispererUserGroupSettings.instance.userGroup = userGroup
270+
await KeyStrokeHandler.instance.processKeyStroke(mockEvent, mockEditor, mockClient, config)
271+
assert.strictEqual(invokeSpy.called, shouldTrigger)
272+
}
216273
})
217274

218275
describe('invokeAutomatedTrigger', function () {

0 commit comments

Comments
 (0)