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: Log the number of lines of an accepted completion and fix a bug #53878

Merged
merged 7 commits into from
Jun 22, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
2 changes: 2 additions & 0 deletions client/cody/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Starting from `0.2.0`, Cody is using `major.EVEN_NUMBER.patch` for release versi

### Fixed

- Autocomplete: Include the number of lines of an accepted autocomplete recommendation and fix an issue where sometimes accepted completions would not be logged correctly. [pull/](https://github.com/sourcegraph/sourcegraph/pull/)

### Changed

- Improved the response quality when Cody is asked about a selected piece of code through the chat window. [pull/53742](https://github.com/sourcegraph/sourcegraph/pull/53742)
Expand Down
2 changes: 1 addition & 1 deletion client/cody/src/completions/cache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface CachedCompletion {

export class CompletionsCache {
private cache = new LRUCache<string, CachedCompletion>({
max: 500, // Maximum input prefixes in the cache.
max: 100, // Maximum input prefixes in the cache.
})

public clear(): void {
Expand Down
2 changes: 1 addition & 1 deletion client/cody/src/completions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ function toInlineCompletionItems(logId: string, completions: Completion[]): vsco
new vscode.InlineCompletionItem(completion.content, undefined, {
title: 'Completion accepted',
command: 'cody.completions.inline.accepted',
arguments: [{ codyLogId: logId }],
arguments: [{ codyLogId: logId, codyLines: completion.content.split('\n').length }],
})
)
}
Expand Down
53 changes: 38 additions & 15 deletions client/cody/src/completions/logger.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { LRUCache } from 'lru-cache'

import { logEvent } from '../event-logger'

interface CompletionEvent {
Expand All @@ -11,8 +13,16 @@ interface CompletionEvent {
}
languageId: string
}
// The timestamp when the request started
startedAt: number
// The timestamp of when the suggestion was first displayed to a users
// screen
suggestedAt: number | null
// The timestamp of when the suggestion was logged to our analytics backend
// This is to avoid double-logging
suggestionLoggedAt: number | null
// The timestamp of when a completion was accepted and logged to our backend
acceptedAt: number | null
// When set, the completion will always be marked as `read`. This helps us
// to avoid not counting a suggested event in case where the user accepts
// the completion below the default timeout
Expand All @@ -21,7 +31,9 @@ interface CompletionEvent {

const READ_TIMEOUT = 750

const displayedCompletions: Map<string, CompletionEvent> = new Map()
const displayedCompletions = new LRUCache<string, CompletionEvent>({
max: 500, // Maximum number of completions that we are keeping track of
})

export function logCompletionEvent(name: string, params?: unknown): void {
logEvent(`CodyVSCodeExtension:completion:${name}`, params, params)
Expand All @@ -33,6 +45,8 @@ export function start(params: CompletionEvent['params']): string {
params,
startedAt: Date.now(),
suggestedAt: null,
suggestionLoggedAt: null,
acceptedAt: null,
forceRead: false,
})

Expand All @@ -41,25 +55,26 @@ export function start(params: CompletionEvent['params']): string {
return id
}

// Suggested completions will not logged individually. Instead, we log them when we either hide them
// again (they are NOT accepted) or when they ARE accepted. This way, we can calculate the duration
// they were actually visible.
// Suggested completions will not logged individually. Instead, we log them when
// we either hide them again (they are NOT accepted) or when they ARE accepted.
// This way, we can calculate the duration they were actually visible.
export function suggest(id: string): void {
const event = displayedCompletions.get(id)
if (event) {
event.suggestedAt = Date.now()
}
}

export function accept(id: string): void {
export function accept(id: string, lines: number): void {
const completionEvent = displayedCompletions.get(id)
if (!completionEvent) {
if (!completionEvent || completionEvent.acceptedAt) {
return
}
completionEvent.forceRead = true
completionEvent.acceptedAt = Date.now()

logSuggestionEvent()
logCompletionEvent('accepted', completionEvent.params)
logCompletionEvent('accepted', { ...completionEvent.params, lines })
}

export function noResponse(id: string): void {
Expand All @@ -68,7 +83,8 @@ export function noResponse(id: string): void {
}

/**
* This callback should be triggered whenever VS Code tries to highlight a new completion and it's
* This callback should be triggered whenever VS Code tries to highlight a new
* completion and it's
* used to measure how long previous completions were visible.
*/
export function clear(): void {
Expand All @@ -81,12 +97,16 @@ function createId(): string {

function logSuggestionEvent(): void {
const now = Date.now()
for (const completionEvent of displayedCompletions.values()) {
const { suggestedAt, startedAt, params, forceRead } = completionEvent

if (!suggestedAt) {
continue
// eslint-disable-next-line ban/ban
displayedCompletions.forEach(completionEvent => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove this ban from our config 🙂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do this as a follow up

const { suggestedAt, suggestionLoggedAt, startedAt, params, forceRead } = completionEvent

// Only log events that were already suggested to the user and have not
// been logged yet.
if (!suggestedAt || suggestionLoggedAt) {
return
}
completionEvent.suggestionLoggedAt = now

const latency = suggestedAt - startedAt
const displayDuration = now - suggestedAt
Expand All @@ -98,6 +118,9 @@ function logSuggestionEvent(): void {
displayDuration,
read: forceRead || read,
})
}
displayedCompletions.clear()
})

// Completions are kept in the LRU cache for longer. This is because they
// can still become visible if e.g. they are served from the cache and we
// need to retain the ability to mark them as seen
}
4 changes: 2 additions & 2 deletions client/cody/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -421,8 +421,8 @@ function createCompletionsProvider(
vscode.commands.registerCommand('cody.manual-completions', async () => {
await manualCompletionService.fetchAndShowManualCompletions()
}),
vscode.commands.registerCommand('cody.completions.inline.accepted', ({ codyLogId }) => {
CompletionsLogger.accept(codyLogId)
vscode.commands.registerCommand('cody.completions.inline.accepted', ({ codyLogId, codyLines }) => {
CompletionsLogger.accept(codyLogId, codyLines)
}),
vscode.languages.registerInlineCompletionItemProvider('*', completionsProvider)
)
Expand Down