Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Autocomplete: Don't delay completions for cached entries #3138

Merged
merged 4 commits into from
Feb 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a

### Changed

- Autocomplete: Removes the latency for cached completions. [https://github.com/sourcegraph/cody/pull/3138](https://github.com/sourcegraph/cody/pull/3138)
- Autocomplete: Enable the recent jaccard similarity improvements by default. [pull/3135](https://github.com/sourcegraph/cody/pull/3135)

## [1.4.3]
Expand Down
32 changes: 24 additions & 8 deletions vscode/src/completions/get-inline-completions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,30 @@ async function doGetInlineCompletions(
traceId: getActiveTraceAndSpanId()?.traceId,
})

const requestParams: RequestParams = {
document,
docContext,
position,
selectedCompletionInfo,
abortSignal,
}

const cachedResult = requestManager.checkCache({
requestParams,
isCacheEnabled: triggerKind !== TriggerKind.Manual,
})
if (cachedResult) {
const { completions, source } = cachedResult

CompletionLogger.loaded(logId, requestParams, completions, source, isDotComUser)

return {
logId,
items: completions,
source,
}
}

// Debounce to avoid firing off too many network requests as the user is still typing.
await wrapInActiveSpan('autocomplete.debounce', async () => {
const interval =
Expand Down Expand Up @@ -334,14 +358,6 @@ async function doGetInlineCompletions(

CompletionLogger.networkRequestStarted(logId, contextResult?.logSummary)

const requestParams: RequestParams = {
document,
docContext,
position,
selectedCompletionInfo,
abortSignal,
}

// Get the processed completions from providers
const { completions, source } = await requestManager.request({
requestParams,
Expand Down
31 changes: 17 additions & 14 deletions vscode/src/completions/request-manager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ describe('RequestManager', () => {
provider: Provider,
suffix?: string
) => Promise<RequestManagerResult>
let checkCache: (prefix: string, suffix?: string) => RequestManagerResult | null
beforeEach(async () => {
await initCompletionProviderConfig({})
const requestManager = new RequestManager()
Expand All @@ -110,6 +111,8 @@ describe('RequestManager', () => {
context: [],
isCacheEnabled: true,
})
checkCache = (prefix: string, suffix?: string) =>
requestManager.checkCache({ requestParams: docState(prefix, suffix), isCacheEnabled: true })
})

it('resolves a single request', async () => {
Expand All @@ -124,20 +127,6 @@ describe('RequestManager', () => {
expect(source).toBe(InlineCompletionsResultSource.Network)
})

it('resolves a single request', async () => {
const prefix = 'console.log('
const provider1 = createProvider(prefix)
setTimeout(() => provider1.yield(["'hello')"]), 0)
await createRequest(prefix, provider1)

const provider2 = createProvider(prefix)

const { completions, source } = await createRequest(prefix, provider2)

expect(source).toBe(InlineCompletionsResultSource.Cache)
expect(completions[0].insertText).toBe("'hello')")
})

it('does not resolve from cache if the suffix has changed', async () => {
const prefix = 'console.log('
const suffix1 = ')\nconsole.log(1)'
Expand Down Expand Up @@ -205,6 +194,20 @@ describe('RequestManager', () => {
provider2.yield(["'world')"])
})

describe('cache', () => {
it('resolves a single request with a cached value without waiting for the debounce timeout', async () => {
const prefix = 'console.log('
const provider1 = createProvider(prefix)
setTimeout(() => provider1.yield(["'hello')"]), 0)
await createRequest(prefix, provider1)

const { completions, source } = checkCache(prefix)!

expect(source).toBe(InlineCompletionsResultSource.Cache)
expect(completions[0].insertText).toBe("'hello')")
})
})

describe('abort logic', () => {
it('aborts a newer request if a prior request resolves it', async () => {
const prefix1 = 'console.'
Expand Down
25 changes: 15 additions & 10 deletions vscode/src/completions/request-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,23 +73,28 @@ export class RequestManager {
// the relevance of existing requests (i.e to find out if the generations are still relevant)
private latestRequestParams: null | RequestsManagerParams = null

public checkCache(
params: Pick<RequestsManagerParams, 'requestParams' | 'isCacheEnabled'>
): RequestManagerResult | null {
const { requestParams, isCacheEnabled } = params
const cachedCompletions = this.cache.get(requestParams)

if (isCacheEnabled && cachedCompletions) {
addAutocompleteDebugEvent('RequestManager.checkCache', { cachedCompletions })
return cachedCompletions
}
return null
}

public async request(params: RequestsManagerParams): Promise<RequestManagerResult> {
const eagerCancellation = completionProviderConfig.getPrefetchedFlag(
FeatureFlag.CodyAutocompleteEagerCancellation
)
this.latestRequestParams = params

const { requestParams, provider, context, isCacheEnabled, tracer } = params
const { requestParams, provider, context, tracer } = params

const cachedCompletions = this.cache.get(requestParams)
addAutocompleteDebugEvent('RequestManager.request', {
cachedCompletions,
isCacheEnabled,
})

if (isCacheEnabled && cachedCompletions) {
return cachedCompletions
}
addAutocompleteDebugEvent('RequestManager.request')

// When request recycling is enabled, we do not pass the original abort signal forward as to
// not interrupt requests that are no longer relevant. Instead, we let all previous requests
Expand Down
Loading