mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-27 02:27:53 +01:00
nes: joint: don't enforce cache delay if document hasn't changed (#2409)
This commit is contained in:
committed by
GitHub
parent
1840e2bdff
commit
aee2abe2e1
@@ -42,9 +42,13 @@ import { CachedOrRebasedEdit, NextEditCache } from './nextEditCache';
|
||||
import { LlmNESTelemetryBuilder } from './nextEditProviderTelemetry';
|
||||
import { INextEditResult, NextEditResult } from './nextEditResult';
|
||||
|
||||
export interface NESInlineCompletionContext extends vscode.InlineCompletionContext {
|
||||
enforceCacheDelay: boolean;
|
||||
}
|
||||
|
||||
export interface INextEditProvider<T extends INextEditResult, TTelemetry, TData = void> extends IDisposable {
|
||||
readonly ID: string;
|
||||
getNextEdit(docId: DocumentId, context: vscode.InlineCompletionContext, logContext: InlineEditRequestLogContext, cancellationToken: CancellationToken, telemetryBuilder: TTelemetry, data?: TData): Promise<T>;
|
||||
getNextEdit(docId: DocumentId, context: NESInlineCompletionContext, logContext: InlineEditRequestLogContext, cancellationToken: CancellationToken, telemetryBuilder: TTelemetry, data?: TData): Promise<T>;
|
||||
handleShown(suggestion: T): void;
|
||||
handleAcceptance(docId: DocumentId, suggestion: T): void;
|
||||
handleRejection(docId: DocumentId, suggestion: T): void;
|
||||
@@ -121,7 +125,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
|
||||
|
||||
public async getNextEdit(
|
||||
docId: DocumentId,
|
||||
context: vscode.InlineCompletionContext,
|
||||
context: NESInlineCompletionContext,
|
||||
logContext: InlineEditRequestLogContext,
|
||||
cancellationToken: CancellationToken,
|
||||
telemetryBuilder: LlmNESTelemetryBuilder
|
||||
@@ -160,7 +164,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
|
||||
|
||||
private async _getNextEditCanThrow(
|
||||
docId: DocumentId,
|
||||
context: vscode.InlineCompletionContext,
|
||||
context: NESInlineCompletionContext,
|
||||
triggerTime: number,
|
||||
shouldExpandEditWindow: boolean,
|
||||
parentTracer: ITracer,
|
||||
@@ -303,7 +307,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
|
||||
|
||||
telemetryBuilder.setHasNextEdit(true);
|
||||
|
||||
const delay = this.computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit }, tracer);
|
||||
const delay = this.computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, enforceCacheDelay: context.enforceCacheDelay }, tracer);
|
||||
if (delay > 0) {
|
||||
await timeout(delay);
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
@@ -702,7 +706,12 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
|
||||
return disposables;
|
||||
}
|
||||
|
||||
private computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit }: { triggerTime: number; isRebasedCachedEdit: boolean; isSubsequentCachedEdit: boolean }, tracer: ITracer): number {
|
||||
private computeMinimumResponseDelay({ triggerTime, isRebasedCachedEdit, isSubsequentCachedEdit, enforceCacheDelay }: { triggerTime: number; isRebasedCachedEdit: boolean; isSubsequentCachedEdit: boolean; enforceCacheDelay: boolean }, tracer: ITracer): number {
|
||||
|
||||
if (!enforceCacheDelay) {
|
||||
tracer.trace('[minimumDelay] no minimum delay enforced due to enforceCacheDelay being false');
|
||||
return 0;
|
||||
}
|
||||
|
||||
const cacheDelay = this._configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsCacheDelay, this._expService);
|
||||
const rebasedCacheDelay = this._configService.getExperimentBasedConfig(ConfigKey.TeamInternal.InlineEditsRebasedCacheDelay, this._expService);
|
||||
|
||||
+6
-7
@@ -4,7 +4,6 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import { outdent } from 'outdent';
|
||||
import { afterAll, assert, beforeAll, describe, expect, it } from 'vitest';
|
||||
import type { InlineCompletionContext } from 'vscode';
|
||||
import { IConfigurationService } from '../../../../platform/configuration/common/configurationService';
|
||||
import { DefaultsOnlyConfigurationService } from '../../../../platform/configuration/common/defaultsOnlyConfigurationService';
|
||||
import { IGitExtensionService } from '../../../../platform/git/common/gitExtensionService';
|
||||
@@ -20,20 +19,20 @@ import { ILogService, LogServiceImpl } from '../../../../platform/log/common/log
|
||||
import { ISnippyService, NullSnippyService } from '../../../../platform/snippy/common/snippyService';
|
||||
import { IExperimentationService, NullExperimentationService } from '../../../../platform/telemetry/common/nullExperimentationService';
|
||||
import { mockNotebookService } from '../../../../platform/test/common/testNotebookService';
|
||||
import { TestWorkspaceService } from '../../../../platform/test/node/testWorkspaceService';
|
||||
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
|
||||
import { Result } from '../../../../util/common/result';
|
||||
import { ITracer } from '../../../../util/common/tracing';
|
||||
import { CancellationToken } from '../../../../util/vs/base/common/cancellation';
|
||||
import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';
|
||||
import { URI } from '../../../../util/vs/base/common/uri';
|
||||
import { generateUuid } from '../../../../util/vs/base/common/uuid';
|
||||
import { LineEdit, LineReplacement } from '../../../../util/vs/editor/common/core/edits/lineEdit';
|
||||
import { StringEdit } from '../../../../util/vs/editor/common/core/edits/stringEdit';
|
||||
import { LineRange } from '../../../../util/vs/editor/common/core/ranges/lineRange';
|
||||
import { OffsetRange } from '../../../../util/vs/editor/common/core/ranges/offsetRange';
|
||||
import { NextEditProvider } from '../../node/nextEditProvider';
|
||||
import { NESInlineCompletionContext, NextEditProvider } from '../../node/nextEditProvider';
|
||||
import { NextEditProviderTelemetryBuilder } from '../../node/nextEditProviderTelemetry';
|
||||
import { DisposableStore } from '../../../../util/vs/base/common/lifecycle';
|
||||
import { IWorkspaceService } from '../../../../platform/workspace/common/workspaceService';
|
||||
import { TestWorkspaceService } from '../../../../platform/test/node/testWorkspaceService';
|
||||
import { ITracer } from '../../../../util/common/tracing';
|
||||
|
||||
describe('NextEditProvider Caching', () => {
|
||||
|
||||
@@ -110,7 +109,7 @@ describe('NextEditProvider Caching', () => {
|
||||
|
||||
doc.applyEdit(StringEdit.insert(11, '3D'));
|
||||
|
||||
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now(), earliestShownDateTime: Date.now() + 200 };
|
||||
const context: NESInlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now(), earliestShownDateTime: Date.now() + 200, enforceCacheDelay: false };
|
||||
const logContext = new InlineEditRequestLogContext(doc.id.toString(), 1, context);
|
||||
const cancellationToken = CancellationToken.None;
|
||||
const tb1 = new NextEditProviderTelemetryBuilder(gitExtensionService, mockNotebookService, workspaceService, nextEditProvider.ID, doc);
|
||||
|
||||
+3
-3
@@ -18,7 +18,7 @@ import { BugIndicatingError } from '../../../../util/vs/base/common/errors';
|
||||
import { Disposable } from '../../../../util/vs/base/common/lifecycle';
|
||||
import { StringReplacement } from '../../../../util/vs/editor/common/core/edits/stringEdit';
|
||||
import { IInstantiationService } from '../../../../util/vs/platform/instantiation/common/instantiation';
|
||||
import { INextEditProvider } from '../../node/nextEditProvider';
|
||||
import { INextEditProvider, NESInlineCompletionContext } from '../../node/nextEditProvider';
|
||||
import { DiagnosticsTelemetryBuilder } from '../../node/nextEditProviderTelemetry';
|
||||
import { INextEditDisplayLocation, INextEditResult } from '../../node/nextEditResult';
|
||||
import { VSCodeWorkspace } from '../parts/vscodeWorkspace';
|
||||
@@ -66,7 +66,7 @@ export class DiagnosticsNextEditProvider extends Disposable implements INextEdit
|
||||
this._diagnosticsCompletionHandler = this._register(instantiationService.createInstance(DiagnosticsCompletionProcessor, workspace, git));
|
||||
}
|
||||
|
||||
async getNextEdit(docId: DocumentId, context: vscode.InlineCompletionContext, logContext: InlineEditRequestLogContext, cancellationToken: CancellationToken, tb: DiagnosticsTelemetryBuilder): Promise<DiagnosticsNextEditResult> {
|
||||
async getNextEdit(docId: DocumentId, context: NESInlineCompletionContext, logContext: InlineEditRequestLogContext, cancellationToken: CancellationToken, tb: DiagnosticsTelemetryBuilder): Promise<DiagnosticsNextEditResult> {
|
||||
this._lastTriggerTime = Date.now();
|
||||
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
@@ -82,7 +82,7 @@ export class DiagnosticsNextEditProvider extends Disposable implements INextEdit
|
||||
return this._createNextEditResult(diagnosticEditResult, logContext, tb);
|
||||
}
|
||||
|
||||
async runUntilNextEdit(docId: DocumentId, context: vscode.InlineCompletionContext, logContext: InlineEditRequestLogContext, delayStart: number, cancellationToken: CancellationToken, tb: DiagnosticsTelemetryBuilder): Promise<DiagnosticsNextEditResult> {
|
||||
async runUntilNextEdit(docId: DocumentId, context: NESInlineCompletionContext, logContext: InlineEditRequestLogContext, delayStart: number, cancellationToken: CancellationToken, tb: DiagnosticsTelemetryBuilder): Promise<DiagnosticsNextEditResult> {
|
||||
try {
|
||||
await timeout(delayStart);
|
||||
if (cancellationToken.isCancellationRequested) {
|
||||
|
||||
+5
-4
@@ -36,6 +36,7 @@ import { StringEdit } from '../../../util/vs/editor/common/core/edits/stringEdit
|
||||
import { IInstantiationService } from '../../../util/vs/platform/instantiation/common/instantiation';
|
||||
import { LineCheck } from '../../inlineChat/vscode-node/naturalLanguageHint';
|
||||
import { createCorrelationId } from '../common/correlationId';
|
||||
import { NESInlineCompletionContext } from '../node/nextEditProvider';
|
||||
import { NextEditProviderTelemetryBuilder, TelemetrySender } from '../node/nextEditProviderTelemetry';
|
||||
import { INextEditResult, NextEditResult } from '../node/nextEditResult';
|
||||
import { InlineCompletionCommand, InlineEditDebugComponent } from './components/inlineEditDebugComponent';
|
||||
@@ -174,19 +175,19 @@ export class InlineCompletionProviderImpl extends Disposable implements InlineCo
|
||||
public async provideInlineCompletionItems(
|
||||
document: TextDocument,
|
||||
position: Position,
|
||||
context: InlineCompletionContext,
|
||||
context: InlineCompletionContext | NESInlineCompletionContext,
|
||||
token: CancellationToken
|
||||
): Promise<NesCompletionList | undefined> {
|
||||
const label = `NES | ${basename(document.uri.fsPath)} (v${document.version})`;
|
||||
const capturingToken = new CapturingToken(label, undefined, true, true);
|
||||
|
||||
return this._requestLogger.captureInvocation(capturingToken, () => this._provideInlineCompletionItems(document, position, context, token));
|
||||
const nesContext: NESInlineCompletionContext = { enforceCacheDelay: true, ...context };
|
||||
return this._requestLogger.captureInvocation(capturingToken, () => this._provideInlineCompletionItems(document, position, nesContext, token));
|
||||
}
|
||||
|
||||
private async _provideInlineCompletionItems(
|
||||
document: TextDocument,
|
||||
position: Position,
|
||||
context: InlineCompletionContext,
|
||||
context: NESInlineCompletionContext,
|
||||
token: CancellationToken
|
||||
): Promise<NesCompletionList | undefined> {
|
||||
const tracer = this._tracer.sub(['provideInlineCompletionItems', shortenOpportunityId(context.requestUuid)]);
|
||||
|
||||
+7
-4
@@ -36,6 +36,7 @@ import { CopilotInlineCompletionItemProvider } from '../../completions-core/vsco
|
||||
import { ICopilotInlineCompletionItemProviderService } from '../../completions/common/copilotInlineCompletionItemProviderService';
|
||||
import { CompletionsCoreContribution } from '../../completions/vscode-node/completionsCoreContribution';
|
||||
import { unificationStateObservable } from '../../completions/vscode-node/completionsUnificationContribution';
|
||||
import { NESInlineCompletionContext } from '../node/nextEditProvider';
|
||||
import { TelemetrySender } from '../node/nextEditProviderTelemetry';
|
||||
import { InlineEditDebugComponent, reportFeedbackCommandId } from './components/inlineEditDebugComponent';
|
||||
import { LogContextRecorder } from './components/logContextRecorder';
|
||||
@@ -359,13 +360,14 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
|
||||
// prefer completions unless there are none
|
||||
tracer.trace(`no last NES suggestion to consider`);
|
||||
const completionsP = this._invokeCompletionsProvider(tracer, document, position, context, tokens, sw);
|
||||
const nesP = this._invokeNESProvider(tracer, document, position, context, tokens, sw);
|
||||
const nesP = this._invokeNESProvider(tracer, document, position, true, context, tokens, sw);
|
||||
return this._returnCompletionsOrOtherwiseNES(completionsP, nesP, sw, tracer, tokens);
|
||||
}
|
||||
|
||||
tracer.trace(`last NES suggestion is for the current document, checking if it agrees with the current suggestion`);
|
||||
|
||||
const nesP = this._invokeNESProvider(tracer, document, position, context, tokens, sw);
|
||||
const enforceCacheDelay = (lastNesSuggestion.docVersionId !== document.version);
|
||||
const nesP = this._invokeNESProvider(tracer, document, position, enforceCacheDelay, context, tokens, sw);
|
||||
if (!nesP) {
|
||||
tracer.trace(`no NES provider`);
|
||||
const completionsP = this._invokeCompletionsProvider(tracer, document, position, context, tokens, sw);
|
||||
@@ -433,11 +435,12 @@ class JointCompletionsProvider extends Disposable implements vscode.InlineComple
|
||||
return this._returnCompletionsOrOtherwiseNES(completionsP, nesP, sw, tracer, tokens);
|
||||
}
|
||||
|
||||
private _invokeNESProvider(tracer: ITracer, document: vscode.TextDocument, position: vscode.Position, context: vscode.InlineCompletionContext, tokens: { coreToken: CancellationToken; completionsCts: CancellationTokenSource; nesCts: CancellationTokenSource }, sw: StopWatch) {
|
||||
private _invokeNESProvider(tracer: ITracer, document: vscode.TextDocument, position: vscode.Position, enforceCacheDelay: boolean, context: vscode.InlineCompletionContext, tokens: { coreToken: CancellationToken; completionsCts: CancellationTokenSource; nesCts: CancellationTokenSource }, sw: StopWatch) {
|
||||
const nesContext: NESInlineCompletionContext = { ...context, enforceCacheDelay };
|
||||
let nesP: Promise<NesCompletionList | undefined> | undefined;
|
||||
if (this._inlineEditProvider) {
|
||||
tracer.trace(`- requesting NES provideInlineCompletionItems`);
|
||||
nesP = this._inlineEditProvider.provideInlineCompletionItems(document, position, context, tokens.nesCts.token);
|
||||
nesP = this._inlineEditProvider.provideInlineCompletionItems(document, position, nesContext, tokens.nesCts.token);
|
||||
nesP.then((nesR) => {
|
||||
tracer.trace(`got NES response in ${sw.elapsed()}ms -- ${nesR === undefined ? 'undefined' : `with ${nesR.items.length} items`}`);
|
||||
}).catch((e) => {
|
||||
|
||||
@@ -49,7 +49,7 @@ import { ICompletionsPromiseQueueService, PromiseQueue } from '../../extension/c
|
||||
import { ICompletionsRuntimeModeService, RuntimeMode } from '../../extension/completions-core/vscode-node/lib/src/util/runtimeMode';
|
||||
import { DocumentContext, WorkspaceFolder } from '../../extension/completions-core/vscode-node/types/src';
|
||||
import { DebugRecorder } from '../../extension/inlineEdits/node/debugRecorder';
|
||||
import { INextEditProvider, NextEditProvider } from '../../extension/inlineEdits/node/nextEditProvider';
|
||||
import { INextEditProvider, NESInlineCompletionContext, NextEditProvider } from '../../extension/inlineEdits/node/nextEditProvider';
|
||||
import { LlmNESTelemetryBuilder, NextEditProviderTelemetryBuilder, TelemetrySender } from '../../extension/inlineEdits/node/nextEditProviderTelemetry';
|
||||
import { INextEditResult } from '../../extension/inlineEdits/node/nextEditResult';
|
||||
import { ChatMLFetcherImpl } from '../../extension/prompt/node/chatMLFetcher';
|
||||
@@ -277,12 +277,13 @@ class NESProvider extends Disposable implements INESProvider<NESResult> {
|
||||
const docId = DocumentId.create(documentUri.toString());
|
||||
|
||||
// Create minimal required context objects
|
||||
const context: vscode.InlineCompletionContext = {
|
||||
const context: NESInlineCompletionContext = {
|
||||
triggerKind: 1, // Invoke
|
||||
selectedCompletionInfo: undefined,
|
||||
requestUuid: generateUuid(),
|
||||
requestIssuedDateTime: Date.now(),
|
||||
earliestShownDateTime: Date.now() + 200,
|
||||
enforceCacheDelay: true,
|
||||
};
|
||||
|
||||
// Create log context
|
||||
|
||||
@@ -5,12 +5,11 @@
|
||||
|
||||
import { rename } from 'fs/promises';
|
||||
import { basename, dirname, join } from 'path';
|
||||
import type { InlineCompletionContext } from 'vscode';
|
||||
import { VisualizationTestRun } from '../../../src/extension/inlineChat/node/rendererVisualization';
|
||||
import { IRecordingInformation, ObservableWorkspaceRecordingReplayer } from '../../../src/extension/inlineEdits/common/observableWorkspaceRecordingReplayer';
|
||||
import { createNextEditProvider } from '../../../src/extension/inlineEdits/node/createNextEditProvider';
|
||||
import { DebugRecorder } from '../../../src/extension/inlineEdits/node/debugRecorder';
|
||||
import { NextEditProvider } from '../../../src/extension/inlineEdits/node/nextEditProvider';
|
||||
import { NESInlineCompletionContext, NextEditProvider } from '../../../src/extension/inlineEdits/node/nextEditProvider';
|
||||
import { NextEditProviderTelemetryBuilder } from '../../../src/extension/inlineEdits/node/nextEditProviderTelemetry';
|
||||
import { NextEditResult } from '../../../src/extension/inlineEdits/node/nextEditResult';
|
||||
import { ConfigKey, IConfigurationService } from '../../../src/platform/configuration/common/configurationService';
|
||||
@@ -164,7 +163,7 @@ export class InlineEditTester {
|
||||
|
||||
const historyContext = historyContextProvider.getHistoryContext(docId)!;
|
||||
const activeDocument = historyContext.getMostRecentDocument(); // TODO
|
||||
const context: InlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now(), earliestShownDateTime: Date.now() + 200 };
|
||||
const context: NESInlineCompletionContext = { triggerKind: 1, selectedCompletionInfo: undefined, requestUuid: generateUuid(), requestIssuedDateTime: Date.now(), earliestShownDateTime: Date.now() + 200, enforceCacheDelay: false };
|
||||
const logContext = new InlineEditRequestLogContext(activeDocument.docId.toString(), 1, context);
|
||||
const telemetryBuilder = new NextEditProviderTelemetryBuilder(gitExtensionService, notebookService, workspaceService, nextEditProvider.ID, workspace.getDocument(activeDocument.docId)!);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user