Skip to content

Commit d857f5f

Browse files
ulugbeknaeli-w-king
authored andcommitted
NES: enable trigger on active editor change by default (#309489) (#309528)
* NES: enable trigger on active editor change by default - Set triggerOnEditorChangeAfterSeconds default to 10 (was undefined) - Set triggerOnEditorChangeStrategy default to AfterAcceptance (was Always) - Replace unconditional same-line cooldown bypass with smart reset: cooldown is enforced within a file session but clears when switching away and returning, so NES re-triggers on the same line after a round-trip to another file - Update tests to match new defaults and behavior * fix indentation
1 parent a48a840 commit d857f5f

File tree

4 files changed

+37
-23
lines changed

4 files changed

+37
-23
lines changed

extensions/copilot/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4435,6 +4435,7 @@
44354435
"number",
44364436
"null"
44374437
],
4438+
"default": 10,
44384439
"markdownDescription": "%github.copilot.config.inlineEdits.triggerOnEditorChangeAfterSeconds%",
44394440
"tags": [
44404441
"advanced",

extensions/copilot/src/extension/inlineEdits/test/vscode-node/inlineEditTriggerer.spec.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ suite('InlineEditTriggerer', () => {
392392
const doc2 = createTextDocument(undefined, Uri.file('file2.py'));
393393

394394
nextEditProvider.lastRejectionTime = Date.now() - TRIGGER_INLINE_EDIT_REJECTION_COOLDOWN - 1;
395+
nextEditProvider.lastOutcome = NesOutcome.Accepted;
395396

396397
// Configure to trigger on document switch
397398
void configurationService.setConfig(ConfigKey.Advanced.InlineEditsTriggerOnEditorChangeAfterSeconds, 30);
@@ -504,6 +505,7 @@ suite('InlineEditTriggerer', () => {
504505
const doc2 = createTextDocument(undefined, Uri.file('file2.py'));
505506

506507
nextEditProvider.lastRejectionTime = Date.now() - TRIGGER_INLINE_EDIT_REJECTION_COOLDOWN - 1;
508+
nextEditProvider.lastOutcome = NesOutcome.Accepted;
507509

508510
const triggerAfterSeconds = 30;
509511
// Configure to trigger on document switch
@@ -930,6 +932,7 @@ suite('InlineEditTriggerer', () => {
930932
const doc2 = createTextDocument(undefined, Uri.file('file2.py'), 'line1\nline2');
931933

932934
nextEditProvider.lastRejectionTime = Date.now() - TRIGGER_INLINE_EDIT_REJECTION_COOLDOWN - 1;
935+
nextEditProvider.lastOutcome = NesOutcome.Accepted;
933936
void configurationService.setConfig(ConfigKey.Advanced.InlineEditsTriggerOnEditorChangeAfterSeconds, 30);
934937

935938
// Edit doc1 and trigger
@@ -1148,6 +1151,7 @@ suite('InlineEditTriggerer', () => {
11481151
const doc2 = createTextDocument(undefined, Uri.file('file2.py'));
11491152

11501153
nextEditProvider.lastRejectionTime = Date.now() - TRIGGER_INLINE_EDIT_REJECTION_COOLDOWN - 1;
1154+
nextEditProvider.lastOutcome = NesOutcome.Accepted;
11511155
void configurationService.setConfig(ConfigKey.Advanced.InlineEditsTriggerOnEditorChangeAfterSeconds, 30);
11521156

11531157
// Fire an undo change — this should still update lastEditTimestamp
@@ -1216,25 +1220,31 @@ suite('InlineEditTriggerer', () => {
12161220
assert.strictEqual(firedEvents.length, 0, 'Should not fire on doc switch during rejection cooldown');
12171221
});
12181222

1219-
test('Same-line cooldown is bypassed when triggerOnActiveEditorChange is set', () => {
1220-
const { document, textEditor } = createTextDocument();
1223+
test('Same-line cooldown is bypassed after switching away and back', () => {
1224+
const doc1 = createTextDocument(undefined, Uri.file('file1.py'));
1225+
const doc2 = createTextDocument(undefined, Uri.file('file2.py'));
12211226
nextEditProvider.lastRejectionTime = Date.now() - TRIGGER_INLINE_EDIT_REJECTION_COOLDOWN - 1;
12221227

1223-
// Enable triggerOnActiveEditorChange — this bypasses same-line cooldown
1224-
void configurationService.setConfig(ConfigKey.Advanced.InlineEditsTriggerOnEditorChangeAfterSeconds, 30);
1225-
1226-
triggerTextChange(document);
1227-
triggerTextSelectionChange(textEditor, new Selection(0, 5, 0, 5));
1228+
// Edit doc1 and trigger on line 0
1229+
triggerTextChange(doc1.document);
1230+
triggerTextSelectionChange(doc1.textEditor, new Selection(0, 5, 0, 5));
12281231

12291232
const initialCount = firedEvents.length;
12301233
assert.isAtLeast(initialCount, 1, 'First trigger should fire');
12311234

1232-
// Same line, different column — normally would be in cooldown,
1233-
// but triggerOnActiveEditorChange is set so cooldown is bypassed
1234-
triggerTextSelectionChange(textEditor, new Selection(0, 10, 0, 10));
1235+
// Same line — cooldown blocks
1236+
triggerTextSelectionChange(doc1.textEditor, new Selection(0, 10, 0, 10));
1237+
assert.strictEqual(firedEvents.length, initialCount, 'Same-line cooldown should block');
1238+
1239+
// Switch to doc2
1240+
triggerTextChange(doc2.document);
1241+
triggerTextSelectionChange(doc2.textEditor, new Selection(0, 0, 0, 0));
1242+
const countAfterDoc2 = firedEvents.length;
12351243

1236-
assert.isAtLeast(firedEvents.length, initialCount + 1,
1237-
'Same-line cooldown should be bypassed when triggerOnActiveEditorChange is set');
1244+
// Switch back to doc1, same line — cooldown should be cleared by the doc switch
1245+
triggerTextSelectionChange(doc1.textEditor, new Selection(0, 10, 0, 10));
1246+
assert.isAtLeast(firedEvents.length, countAfterDoc2 + 1,
1247+
'Same-line cooldown should be bypassed after switching away and back');
12381248
});
12391249

12401250
test('Output pane documents are ignored for selection changes', () => {

extensions/copilot/src/extension/inlineEdits/vscode-node/inlineEditTriggerer.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,12 @@ export class InlineEditTriggerer extends Disposable {
157157
return;
158158
}
159159

160+
// When the user switches to a different file and comes back, clear same-line
161+
// cooldowns so the triggerer fires again on the same line.
162+
if (!isSameDoc) {
163+
mostRecentChange.lineNumberTriggers.clear();
164+
}
165+
160166
const hadRecentEdit = this._hasRecentEdit(mostRecentChange);
161167
if (!hadRecentEdit || !this._hasRecentTrigger()) {
162168
// The edit is too old or the provider was not triggered recently (we might be
@@ -221,17 +227,14 @@ export class InlineEditTriggerer extends Disposable {
221227
/**
222228
* Returns true if the same-line cooldown is active and we should skip triggering.
223229
*
224-
* The cooldown is bypassed when:
225-
* - `triggerOnActiveEditorChange` is configured, OR
226-
* - we're in a notebook cell and the current document differs from the one that
227-
* originally triggered the change (user moved to a different cell).
230+
* The cooldown is bypassed when we're in a notebook cell and the current document
231+
* differs from the one that originally triggered the change (user moved to a
232+
* different cell).
233+
*
234+
* When the user switches to a different file and comes back, line triggers are
235+
* cleared (see {@link _handleSelectionChange}), so the cooldown naturally resets.
228236
*/
229237
private _isSameLineCooldownActive(mostRecentChange: LastChange, selectionLine: number, currentDocument: vscode.TextDocument): boolean {
230-
const triggerOnActiveEditorChange = this._configurationService.getExperimentBasedConfig(ConfigKey.Advanced.InlineEditsTriggerOnEditorChangeAfterSeconds, this._expService);
231-
if (triggerOnActiveEditorChange) {
232-
return false; // cooldown bypassed
233-
}
234-
235238
// In a notebook, if the user moved to a different cell, bypass the cooldown
236239
if (isNotebookCell(currentDocument.uri) && currentDocument !== mostRecentChange.documentTrigger) {
237240
return false; // cooldown bypassed

extensions/copilot/src/platform/configuration/common/configurationService.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ export namespace ConfigKey {
659659
/** Maximum number of tool calls the execution subagent can make */
660660
export const ExecutionSubagentToolCallLimit = defineSetting<number>('chat.executionSubagent.toolCallLimit', ConfigType.ExperimentBased, 10);
661661

662-
export const InlineEditsTriggerOnEditorChangeAfterSeconds = defineAndMigrateExpSetting<number | undefined>('chat.advanced.inlineEdits.triggerOnEditorChangeAfterSeconds', 'chat.inlineEdits.triggerOnEditorChangeAfterSeconds', undefined);
662+
export const InlineEditsTriggerOnEditorChangeAfterSeconds = defineAndMigrateExpSetting<number | undefined>('chat.advanced.inlineEdits.triggerOnEditorChangeAfterSeconds', 'chat.inlineEdits.triggerOnEditorChangeAfterSeconds', 10);
663663
export const InlineEditsNextCursorPredictionDisplayLine = defineAndMigrateExpSetting<boolean>('chat.advanced.inlineEdits.nextCursorPrediction.displayLine', 'chat.inlineEdits.nextCursorPrediction.displayLine', true);
664664
export const InlineEditsNextCursorPredictionCurrentFileMaxTokens = defineAndMigrateExpSetting<number>('chat.advanced.inlineEdits.nextCursorPrediction.currentFileMaxTokens', 'chat.inlineEdits.nextCursorPrediction.currentFileMaxTokens', 3000);
665665
export const InlineEditsRenameSymbolSuggestions = defineSetting<boolean>('chat.inlineEdits.renameSymbolSuggestions', ConfigType.ExperimentBased, true);
@@ -777,7 +777,7 @@ export namespace ConfigKey {
777777
export const InlineEditsSpeculativeRequestsAutoExpandEditWindowLines = defineTeamInternalSetting<SpeculativeRequestsAutoExpandEditWindowLines>('chat.advanced.inlineEdits.speculativeRequestsAutoExpandEditWindowLines', ConfigType.ExperimentBased, SpeculativeRequestsAutoExpandEditWindowLines.Off, SpeculativeRequestsAutoExpandEditWindowLines.VALIDATOR);
778778
export const InlineEditsExtraDebounceInlineSuggestion = defineTeamInternalSetting<number>('chat.advanced.inlineEdits.extraDebounceInlineSuggestion', ConfigType.ExperimentBased, 0);
779779
export const InlineEditsDebounceOnSelectionChange = defineTeamInternalSetting<number | undefined>('chat.advanced.inlineEdits.debounceOnSelectionChange', ConfigType.ExperimentBased, undefined);
780-
export const InlineEditsTriggerOnEditorChangeStrategy = defineTeamInternalSetting<triggerOptions.DocumentSwitchTriggerStrategy>('chat.advanced.inlineEdits.triggerOnEditorChangeStrategy', ConfigType.ExperimentBased, triggerOptions.DocumentSwitchTriggerStrategy.Always, triggerOptions.DocumentSwitchTriggerStrategy.VALIDATOR);
780+
export const InlineEditsTriggerOnEditorChangeStrategy = defineTeamInternalSetting<triggerOptions.DocumentSwitchTriggerStrategy>('chat.advanced.inlineEdits.triggerOnEditorChangeStrategy', ConfigType.ExperimentBased, triggerOptions.DocumentSwitchTriggerStrategy.AfterAcceptance, triggerOptions.DocumentSwitchTriggerStrategy.VALIDATOR);
781781
export const InlineEditsProviderId = defineTeamInternalSetting<string | undefined>('chat.advanced.inlineEdits.providerId', ConfigType.ExperimentBased, undefined);
782782
export const InlineEditsUnification = defineTeamInternalSetting<boolean>('chat.advanced.inlineEdits.unification', ConfigType.ExperimentBased, false);
783783
export const InlineEditsNextCursorPredictionModelName = defineTeamInternalSetting<string | undefined>('chat.advanced.inlineEdits.nextCursorPrediction.modelName', ConfigType.ExperimentBased, 'copilot-suggestions-himalia-001');

0 commit comments

Comments
 (0)