Uses core provider request time instead of extension provider invocation time for debouncing (guarded by chat.advanced.inlineEdits.debounceUseCoreRequestTime). (#366)

This commit is contained in:
Henning Dieterichs
2025-07-25 18:44:43 +02:00
committed by GitHub
parent f80655043f
commit 1991bb86bf
9 changed files with 24 additions and 14 deletions

View File

@@ -7,13 +7,12 @@ import { ConfigKey, IConfigurationService } from '../../../platform/configuratio
import { IExperimentationService } from '../../../platform/telemetry/common/nullExperimentationService';
export class DelaySession {
private readonly providerInvocationTime = Date.now();
private extraDebounce = 0;
constructor(
private baseDebounceTime: number,
private readonly expectedTotalTime: number | undefined,
private readonly providerInvocationTime: number = Date.now(),
) {
}
@@ -53,13 +52,13 @@ export class Delayer {
) {
}
public createDelaySession(): DelaySession {
public createDelaySession(requestTime: number | undefined): DelaySession {
const baseDebounceTime = this._configurationService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsDebounce, this._experimentationService);
const backoffDebounceEnabled = this._configurationService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsBackoffDebounceEnabled, this._experimentationService);
const expectedTotalTime = backoffDebounceEnabled ? this._getExpectedTotalTime(baseDebounceTime) : undefined;
return new DelaySession(baseDebounceTime, expectedTotalTime);
return new DelaySession(baseDebounceTime, expectedTotalTime, requestTime);
}
public handleAcceptance(): void {

View File

@@ -8,4 +8,5 @@ export interface INesConfigs {
isRevisedCacheStrategy: boolean;
isCacheTracksRejections: boolean;
isRecentlyShownCacheEnabled: boolean;
debounceUseCoreRequestTime: boolean;
}

View File

@@ -136,6 +136,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
isRevisedCacheStrategy: this._configService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsRevisedCacheStrategy, this._expService),
isCacheTracksRejections: this._configService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsCacheTracksRejections, this._expService),
isRecentlyShownCacheEnabled: this._configService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsRecentlyShownCacheEnabled, this._expService),
debounceUseCoreRequestTime: this._configService.getExperimentBasedConfig(ConfigKey.Internal.InlineEditsDebounceUseCoreRequestTime, this._expService),
};
telemetryBuilder.setNESConfigs({ ...nesConfigs });
@@ -191,7 +192,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
} else {
tracer.trace('fetching next edit');
req = new NextEditFetchRequest(logContext, Date.now());
req = new NextEditFetchRequest(logContext, nesConfigs.debounceUseCoreRequestTime ? (context.requestIssuedDateTime ?? undefined) : undefined);
telemetryBuilder.setHeaderRequestId(req.headerRequestId);
const startVersion = doc.value.get();
@@ -425,7 +426,8 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
firstEdit,
logContext,
req.log.recordingBookmark,
recording
recording,
req.providerRequestStartDateTime,
);
let nextEditResult: StatelessNextEditResult | undefined;
@@ -683,7 +685,7 @@ export class NextEditFetchRequest {
public readonly headerRequestId = generateUuid();
constructor(
public readonly log: InlineEditRequestLogContext,
public readonly startTime: number,
public readonly providerRequestStartDateTime: number | undefined,
) {
}
}

View File

@@ -20,6 +20,7 @@ import { ILogService, LogServiceImpl } from '../../../../platform/log/common/log
import { NulSimulationTestContext } from '../../../../platform/simulationTestContext/common/simulationTestContext';
import { ISnippyService, NullSnippyService } from '../../../../platform/snippy/common/snippyService';
import { IExperimentationService, NullExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
import { mockNotebookService } from '../../../../platform/test/common/testNotebookService';
import { MockExtensionContext } from '../../../../platform/test/node/extensionContext';
import { Result } from '../../../../util/common/result';
import { CancellationToken } from '../../../../util/vs/base/common/cancellation';
@@ -31,7 +32,6 @@ import { LineRange } from '../../../../util/vs/editor/common/core/ranges/lineRan
import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';
import { NextEditProvider } from '../../node/nextEditProvider';
import { NextEditProviderTelemetryBuilder } from '../../node/nextEditProviderTelemetry';
import { mockNotebookService } from '../../../../platform/test/common/testNotebookService';
describe('NextEditProvider Caching', () => {
@@ -103,7 +103,7 @@ describe('NextEditProvider Caching', () => {
doc.applyEdit(StringEdit.insert(11, '3D'));
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid() };
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now() };
const logContext = new InlineEditRequestLogContext(doc.id.toString(), 1, context);
const cancellationToken = CancellationToken.None;
const tb1 = new NextEditProviderTelemetryBuilder(gitExtensionService, mockNotebookService, nextEditProvider.ID, doc);

View File

@@ -64,6 +64,10 @@ declare module 'vscode' {
* If some inline completion provider registered by such an extension returns a result, this provider is not asked.
*/
yieldTo?: string[];
/**
* Can override the extension id for the yieldTo mechanism. Used for testing, so that yieldTo can be tested within one extension.
*/
groupId?: string;
debounceDelayMs?: number;
@@ -150,6 +154,8 @@ declare module 'vscode' {
readonly userPrompt?: string;
readonly requestUuid: string;
readonly requestIssuedDateTime: number;
}
export interface PartialAcceptInfo {

View File

@@ -117,7 +117,7 @@ export class XtabProvider extends ChainedStatelessNextEditProvider {
return StatelessNextEditResult.noEdit(new NoNextEditReason.ActiveDocumentHasNoEdits(), telemetry);
}
const delaySession = this.delayer.createDelaySession();
const delaySession = this.delayer.createDelaySession(request.providerRequestStartDateTime);
const nextEditResult = await this.doGetNextEdit(request, pushEdit, delaySession, logContext, cancellationToken, telemetry, RetryState.NotRetrying);

View File

@@ -645,6 +645,7 @@ export namespace ConfigKey {
export const InlineEditsRevisedCacheStrategy = defineExpSetting<boolean>('chat.advanced.inlineEdits.revisedCacheStrategy', true, INTERNAL_RESTRICTED);
export const InlineEditsCacheTracksRejections = defineExpSetting<boolean>('chat.advanced.inlineEdits.cacheTracksRejections', true, INTERNAL_RESTRICTED);
export const InlineEditsRecentlyShownCacheEnabled = defineExpSetting<boolean>('chat.advanced.inlineEdits.recentlyShownCacheEnabled', false, INTERNAL_RESTRICTED);
export const InlineEditsDebounceUseCoreRequestTime = defineExpSetting<boolean>('chat.advanced.inlineEdits.debounceUseCoreRequestTime', false, INTERNAL_RESTRICTED);
export const InlineEditsYieldToCopilot = defineExpSetting<boolean>('chat.advanced.inlineEdits.yieldToCopilot', false, INTERNAL_RESTRICTED);
export const InlineEditsLogContextRecorderEnabled = defineSetting('chat.advanced.inlineEdits.logContextRecorder.enabled', false, INTERNAL_RESTRICTED);
export const InlineEditsDebounce = defineExpSetting<number>('chat.advanced.inlineEdits.debounce', 200, INTERNAL_RESTRICTED);

View File

@@ -63,8 +63,9 @@ export class StatelessNextEditRequest<TFirstEdit = any> {
public readonly xtabEditHistory: IXtabHistoryEntry[],
public readonly firstEdit: DeferredPromise<Result<TFirstEdit, NoNextEditReason>>,
public readonly logContext: InlineEditRequestLogContext,
public readonly recordingBookmark?: DebugRecorderBookmark,
public readonly recording?: LogEntry[],
public readonly recordingBookmark: DebugRecorderBookmark | undefined,
public readonly recording: LogEntry[] | undefined,
public readonly providerRequestStartDateTime: number | undefined,
) {
assert(documents.length > 0);
assert(activeDocumentIdx >= 0 && activeDocumentIdx < documents.length);

View File

@@ -25,6 +25,7 @@ import { ObservableWorkspace } from '../../../src/platform/inlineEdits/common/ob
import { IHistoryContextProvider } from '../../../src/platform/inlineEdits/common/workspaceEditTracker/historyContextProvider';
import { NesHistoryContextProvider } from '../../../src/platform/inlineEdits/common/workspaceEditTracker/nesHistoryContextProvider';
import { NesXtabHistoryTracker } from '../../../src/platform/inlineEdits/common/workspaceEditTracker/nesXtabHistoryTracker';
import { INotebookService } from '../../../src/platform/notebook/common/notebookService';
import { IExperimentationService } from '../../../src/platform/telemetry/common/nullExperimentationService';
import { TestingServiceCollection } from '../../../src/platform/test/node/services';
import { TaskQueue } from '../../../src/util/common/async';
@@ -46,7 +47,6 @@ import { ITestInformation } from '../testInformation';
import { IInlineEditBaseFile, ILoadedFile } from './fileLoading';
import { inlineEditScoringService } from './inlineEditScoringService';
import { SpyingServerPoweredNesProvider } from './spyingServerPoweredNesProvider';
import { INotebookService } from '../../../src/platform/notebook/common/notebookService';
export interface IInlineEditTest {
recentEdit: IInlineEditTestDocument | IInlineEditTestDocument[];
@@ -167,7 +167,7 @@ export class InlineEditTester {
const historyContext = historyContextProvider.getHistoryContext(docId)!;
const activeDocument = historyContext.getMostRecentDocument(); // TODO
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid() };
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now() };
const logContext = new InlineEditRequestLogContext(activeDocument.docId.toString(), 1, context);
const telemetryBuilder = new NextEditProviderTelemetryBuilder(gitExtensionService, notebookService, nextEditProvider.ID, workspace.getDocument(activeDocument.docId)!);