Skip to content

Commit b6d44c3

Browse files
authored
nes: fix: use speculativeRequestDelay for cached speculative results (#4985)
* test: add failing test for cached speculative result using wrong delay When a speculative request completes and its result is cached before the user accepts, the subsequent getNextEdit() takes the cache path where isFromSpeculativeRequest stays false. This causes computeMinimumResponseDelay to use the normal cacheDelay instead of the speculative-specific speculativeRequestDelay (typically 0ms). The test sets cacheDelay=5000ms and speculativeRequestDelay=0ms, then verifies that a cached speculative result returns fast. Currently it times out at 5000ms, confirming the bug. * fix: use speculativeRequestDelay for cached speculative results When a speculative request completes and caches its result before the user accepts, the subsequent getNextEdit() takes the cache path. In this path, isFromSpeculativeRequest was not being set from the cached edit's source, causing computeMinimumResponseDelay to apply the normal cacheDelay instead of the speculative-specific speculativeRequestDelay. Set isFromSpeculativeRequest from cachedEdit.source.isSpeculative in the cache path so that cached speculative results use the correct (typically 0ms) delay.
1 parent 1522ae8 commit b6d44c3

File tree

2 files changed

+60
-0
lines changed

2 files changed

+60
-0
lines changed

src/extension/inlineEdits/node/nextEditProvider.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,7 @@ export class NextEditProvider extends Disposable implements INextEditProvider<Ne
346346
}
347347
isRebasedCachedEdit = !!cachedEdit.rebasedEdit;
348348
isSubsequentCachedEdit = cachedEdit.subsequentN !== undefined && cachedEdit.subsequentN > 0;
349+
isFromSpeculativeRequest = cachedEdit.source.isSpeculative;
349350
req = cachedEdit.source;
350351
logContext.setIsCachedResult(cachedEdit.source.log);
351352
currentDocument = documentAtInvocationTime;

src/extension/inlineEdits/test/node/nextEditProviderSpeculative.spec.ts

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1311,4 +1311,63 @@ describe('NextEditProvider speculative requests', () => {
13111311
await statelessProvider.calls[0].completed.p;
13121312
});
13131313
});
1314+
1315+
describe('cached speculative result delay', () => {
1316+
it('uses speculativeRequestDelay (not cacheDelay) when speculative result is served from cache', async () => {
1317+
const CACHE_DELAY_MS = 5_000;
1318+
await configService.setConfig(ConfigKey.TeamInternal.InlineEditsSpeculativeRequests, SpeculativeRequestsEnablement.On);
1319+
await configService.setConfig(ConfigKey.TeamInternal.InlineEditsCacheDelay, CACHE_DELAY_MS);
1320+
await configService.setConfig(ConfigKey.TeamInternal.InlineEditsSpeculativeRequestDelay, 0);
1321+
1322+
const statelessProvider = new TestStatelessNextEditProvider();
1323+
statelessProvider.enqueueBehavior({ kind: 'yieldEditThenNoSuggestions', edit: lineReplacement(1, 'const value = 2;') });
1324+
statelessProvider.enqueueBehavior({ kind: 'yieldEditThenNoSuggestions', edit: lineReplacement(2, 'console.log(value + 1);') });
1325+
const { nextEditProvider, workspace } = createProviderAndWorkspace(statelessProvider);
1326+
1327+
const doc = workspace.addDocument({
1328+
id: DocumentId.create(URI.file('/test/spec-cache-delay.ts').toString()),
1329+
initialValue: 'const value = 1;\nconsole.log(value);',
1330+
});
1331+
doc.setSelection([new OffsetRange(0, 0)], undefined);
1332+
1333+
// First request (fresh)
1334+
const firstSuggestion = await getNextEdit(nextEditProvider, doc.id);
1335+
assert(firstSuggestion.result?.edit);
1336+
1337+
// Show → triggers speculative request; wait for it to complete and cache
1338+
nextEditProvider.handleShown(firstSuggestion);
1339+
await statelessProvider.waitForCall(2);
1340+
await statelessProvider.calls[1].completed.p;
1341+
1342+
// Accept and apply — doc now matches speculative request's postEditContent
1343+
nextEditProvider.handleAcceptance(doc.id, firstSuggestion);
1344+
doc.applyEdit(firstSuggestion.result.edit.toEdit());
1345+
1346+
// Next getNextEdit hits the cache path (speculative result already cached).
1347+
// With enforceCacheDelay=true, it should use speculativeRequestDelay (0ms),
1348+
// NOT the normal cacheDelay (5000ms).
1349+
const context: NESInlineCompletionContext = {
1350+
triggerKind: 1,
1351+
selectedCompletionInfo: undefined,
1352+
requestUuid: generateUuid(),
1353+
requestIssuedDateTime: Date.now(),
1354+
earliestShownDateTime: Date.now(),
1355+
enforceCacheDelay: true,
1356+
};
1357+
const logContext = new InlineEditRequestLogContext(doc.id.toString(), 1, context);
1358+
const telemetryBuilder = new NextEditProviderTelemetryBuilder(gitExtensionService, mockNotebookService, workspaceService, nextEditProvider.ID, undefined);
1359+
const start = Date.now();
1360+
try {
1361+
const cachedSuggestion = await nextEditProvider.getNextEdit(doc.id, context, logContext, CancellationToken.None, telemetryBuilder.nesBuilder);
1362+
const elapsed = Date.now() - start;
1363+
assert(cachedSuggestion.result?.edit);
1364+
1365+
// The result comes from a speculative request's cache, so it should
1366+
// use the speculative delay (0ms) rather than the cache delay (5000ms)
1367+
expect(elapsed).toBeLessThan(100);
1368+
} finally {
1369+
telemetryBuilder.dispose();
1370+
}
1371+
});
1372+
});
13141373
});

0 commit comments

Comments
 (0)