From aabb842ec4925062cbe3bd19e141e0f3e381bd10 Mon Sep 17 00:00:00 2001 From: Hitesh Sagtani Date: Tue, 10 Sep 2024 15:16:16 +0530 Subject: [PATCH] Hitesh/1.34.2 patch release (#5524) ## Context Cherry-pick Autocomplete Logging: The PR fixes the contextCandidates logged in the inlineCompletionItemContext. [pull/5507](https://github.com/sourcegraph/cody/pull/5507) ## Test plan Updated version and changelog --- lib/shared/src/completions/types.ts | 1 + vscode/CHANGELOG.md | 11 +++ vscode/package.json | 2 +- .../completions/context/context-mixer.test.ts | 24 +++++ .../src/completions/context/context-mixer.ts | 3 + .../context/retrievers/bfg/bfg-retriever.ts | 4 +- .../bestJaccardMatch.test.ts | 5 + .../jaccard-similarity/bestJaccardMatch.ts | 4 + .../jaccard-similarity-retriever.ts | 4 +- .../lsp-light/lsp-light-retriever.ts | 3 +- .../recent-edits/recent-edits-retriever.ts | 5 +- .../context/retrievers/tsc/tsc-retriever.ts | 4 +- vscode/src/completions/context/utils.ts | 8 ++ .../src/completions/get-inline-completions.ts | 8 +- vscode/src/completions/logger.test.ts | 93 +++++++++++++++++++ vscode/src/completions/logger.ts | 46 ++++++--- .../model-helpers/__tests__/test-data.ts | 3 + .../src/graph/lsp/symbol-context-snippets.ts | 2 + 18 files changed, 203 insertions(+), 27 deletions(-) diff --git a/lib/shared/src/completions/types.ts b/lib/shared/src/completions/types.ts index 222f4b5d855..508adfa3443 100644 --- a/lib/shared/src/completions/types.ts +++ b/lib/shared/src/completions/types.ts @@ -2,6 +2,7 @@ import type * as vscode from 'vscode' import type { URI } from 'vscode-uri' export interface AutocompleteFileContextSnippet { + identifier: string uri: URI startLine: number endLine: number diff --git a/vscode/CHANGELOG.md b/vscode/CHANGELOG.md index 0dd22d3584f..7fcacdbce43 100644 --- a/vscode/CHANGELOG.md +++ b/vscode/CHANGELOG.md @@ -10,6 +10,17 @@ This is a log of all notable changes to Cody for VS Code. [Unreleased] changes a ### Changed + +## 1.34.2 + +### Added + +### Fixed + +- Autocomplete Logging: The PR fixes the contextCandidates logged in the inlineCompletionItemContext. [pull/5507](https://github.com/sourcegraph/cody/pull/5507) + +### Changed + ## 1.34.1 ### Added diff --git a/vscode/package.json b/vscode/package.json index b6de23225b9..d5b350ff610 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -3,7 +3,7 @@ "name": "cody-ai", "private": true, "displayName": "Cody: AI Coding Assistant with Autocomplete & Chat", - "version": "1.34.1", + "version": "1.34.2", "publisher": "sourcegraph", "license": "Apache-2.0", "icon": "resources/cody.png", diff --git a/vscode/src/completions/context/context-mixer.test.ts b/vscode/src/completions/context/context-mixer.test.ts index 2a12fa09c71..f4fc43f406e 100644 --- a/vscode/src/completions/context/context-mixer.test.ts +++ b/vscode/src/completions/context/context-mixer.test.ts @@ -88,12 +88,14 @@ describe('ContextMixer', () => { createMockStrategy([ [ { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo() {}', startLine: 0, endLine: 0, }, { + identifier: 'jaccard-similarity', uri: testFileUri('bar.ts'), content: 'function bar() {}', startLine: 0, @@ -107,12 +109,14 @@ describe('ContextMixer', () => { { fileName: 'foo.ts', content: 'function foo() {}', + identifier: 'jaccard-similarity', startLine: 0, endLine: 0, }, { fileName: 'bar.ts', content: 'function bar() {}', + identifier: 'jaccard-similarity', startLine: 0, endLine: 0, }, @@ -142,12 +146,14 @@ describe('ContextMixer', () => { createMockStrategy([ [ { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}', startLine: 0, endLine: 0, }, { + identifier: 'jaccard-similarity', uri: testFileUri('bar.ts'), content: 'function bar1() {}', startLine: 0, @@ -157,18 +163,21 @@ describe('ContextMixer', () => { [ { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo3() {}', startLine: 10, endLine: 10, }, { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}\nfunction foo2() {}', startLine: 0, endLine: 1, }, { + identifier: 'jaccard-similarity', uri: testFileUri('bar.ts'), content: 'function bar1() {}\nfunction bar2() {}', startLine: 0, @@ -188,6 +197,7 @@ describe('ContextMixer', () => { "content": "function foo1() {}", "endLine": 0, "fileName": "foo.ts", + "identifier": "jaccard-similarity", "startLine": 0, }, { @@ -195,12 +205,14 @@ describe('ContextMixer', () => { function foo2() {}", "endLine": 1, "fileName": "foo.ts", + "identifier": "jaccard-similarity", "startLine": 0, }, { "content": "function bar1() {}", "endLine": 0, "fileName": "bar.ts", + "identifier": "jaccard-similarity", "startLine": 0, }, { @@ -208,12 +220,14 @@ describe('ContextMixer', () => { function bar2() {}", "endLine": 1, "fileName": "bar.ts", + "identifier": "jaccard-similarity", "startLine": 0, }, { "content": "function foo3() {}", "endLine": 10, "fileName": "foo.ts", + "identifier": "jaccard-similarity", "startLine": 10, }, ] @@ -260,12 +274,14 @@ describe('ContextMixer', () => { createMockStrategy([ [ { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}', startLine: 0, endLine: 0, }, { + identifier: 'jaccard-similarity', uri: testFileUri('foo/bar.ts'), content: 'function bar1() {}', startLine: 0, @@ -274,18 +290,21 @@ describe('ContextMixer', () => { ], [ { + identifier: 'jaccard-similarity', uri: testFileUri('test/foo.ts'), content: 'function foo3() {}', startLine: 10, endLine: 10, }, { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}\nfunction foo2() {}', startLine: 0, endLine: 1, }, { + identifier: 'jaccard-similarity', uri: testFileUri('example/bar.ts'), content: 'function bar1() {}\nfunction bar2() {}', startLine: 0, @@ -322,12 +341,14 @@ describe('ContextMixer', () => { createMockStrategy([ [ { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}', startLine: 0, endLine: 0, }, { + identifier: 'jaccard-similarity', uri: testFileUri('foo/bar.ts'), content: 'function bar1() {}', startLine: 0, @@ -336,18 +357,21 @@ describe('ContextMixer', () => { ], [ { + identifier: 'jaccard-similarity', uri: testFileUri('test/foo.ts'), content: 'function foo3() {}', startLine: 10, endLine: 10, }, { + identifier: 'jaccard-similarity', uri: testFileUri('foo.ts'), content: 'function foo1() {}\nfunction foo2() {}', startLine: 0, endLine: 1, }, { + identifier: 'jaccard-similarity', uri: testFileUri('example/bar.ts'), content: 'function bar1() {}\nfunction bar2() {}', startLine: 0, diff --git a/vscode/src/completions/context/context-mixer.ts b/vscode/src/completions/context/context-mixer.ts index 1fce8aa1f55..ac8bb7a72ea 100644 --- a/vscode/src/completions/context/context-mixer.ts +++ b/vscode/src/completions/context/context-mixer.ts @@ -61,6 +61,7 @@ export interface ContextSummary { export interface GetContextResult { context: AutocompleteContextSnippet[] logSummary: ContextSummary + rankedContextCandidates: AutocompleteContextSnippet[] } /** @@ -90,6 +91,7 @@ export class ContextMixer implements vscode.Disposable { duration: 0, retrieverStats: {}, }, + rankedContextCandidates: [], } } @@ -172,6 +174,7 @@ export class ContextMixer implements vscode.Disposable { return { context: mixedContext, logSummary, + rankedContextCandidates: Array.from(fusedResults), } } diff --git a/vscode/src/completions/context/retrievers/bfg/bfg-retriever.ts b/vscode/src/completions/context/retrievers/bfg/bfg-retriever.ts index a73f6e16fe5..5f11b66bde5 100644 --- a/vscode/src/completions/context/retrievers/bfg/bfg-retriever.ts +++ b/vscode/src/completions/context/retrievers/bfg/bfg-retriever.ts @@ -9,6 +9,7 @@ import { captureException } from '../../../../services/sentry/sentry' import type { ContextRetriever, ContextRetrieverOptions } from '../../../types' import type { AutocompleteContextSnippet } from '@sourcegraph/cody-shared' +import { RetrieverIdentifier } from '../../utils' import { getLastNGraphContextIdentifiersFromDocument, getLastNGraphContextIdentifiersFromString, @@ -16,7 +17,7 @@ import { import { type SimpleRepository, inferGitRepository } from './simple-git' export class BfgRetriever implements ContextRetriever { - public identifier = 'bfg' + public identifier = RetrieverIdentifier.BfgRetriever private loadedBFG: Promise private bfgIndexingPromise = Promise.resolve(undefined) private awaitIndexing: boolean @@ -235,6 +236,7 @@ export class BfgRetriever implements ContextRetriever { // Convert BFG snippets to match the format expected on the client. const symbols = (response.symbols || []).map(contextSnippet => ({ ...contextSnippet, + identifier: RetrieverIdentifier.BfgRetriever, uri: vscode.Uri.from({ scheme: 'file', path: contextSnippet.fileName }), })) satisfies Omit[] diff --git a/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.test.ts b/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.test.ts index d0f63f967a6..e6bef2b315e 100644 --- a/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.test.ts +++ b/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.test.ts @@ -127,12 +127,14 @@ describe('bestJaccardMatch', () => { score: 1, content: 'foo\nbar\nbaz', endLine: 2, + identifier: 'jaccard-similarity', startLine: 0, }) expect(bestJaccardMatches('bar\nquux', matchText, 4, MAX_MATCHES)[0]).toEqual({ score: 0.5, content: 'bar\nbaz\nqux\nquux', endLine: 4, + identifier: 'jaccard-similarity', startLine: 1, }) expect( @@ -146,6 +148,7 @@ describe('bestJaccardMatch', () => { score: 0.3, startLine: 4, endLine: 9, + identifier: 'jaccard-similarity', content: ['quux', 'quuz', 'corge', 'grault', 'garply', 'waldo'].join('\n'), }) }) @@ -206,6 +209,7 @@ describe('bestJaccardMatch', () => { 'foo', 'bar',", "endLine": 4, + "identifier": "jaccard-similarity", "score": 0.14285714285714285, "startLine": 0, } @@ -216,6 +220,7 @@ describe('bestJaccardMatch', () => { expect(bestJaccardMatches('foo', 'foo', 10, MAX_MATCHES)[0]).toEqual({ content: 'foo', endLine: 0, + identifier: 'jaccard-similarity', score: 1, startLine: 0, }) diff --git a/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.ts b/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.ts index 12d0c89aa41..d9406537ccb 100644 --- a/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.ts +++ b/vscode/src/completions/context/retrievers/jaccard-similarity/bestJaccardMatch.ts @@ -1,9 +1,11 @@ import { LRUCache } from 'lru-cache' import winkUtils from 'wink-nlp-utils' +import { RetrieverIdentifier } from '../../utils' const MAX_STEM_CACHE_SIZE = 30000 export interface JaccardMatch { + identifier: string score: number content: string startLine: number @@ -67,6 +69,7 @@ export function bestJaccardMatches( // Initialize the result set with the first window const windows: JaccardMatch[] = [ { + identifier: RetrieverIdentifier.JaccardSimilarityRetriever, score: jaccardSimilarity(targetWordCounts, windowWordCounts, intersectionWordCounts), content: lines.slice(firstWindowStart, firstWindowEnd + 1).join('\n'), startLine: firstWindowStart, @@ -118,6 +121,7 @@ export function bestJaccardMatches( const startLine = i const endLine = i + windowSize - 1 windows.push({ + identifier: RetrieverIdentifier.JaccardSimilarityRetriever, score, content: lines.slice(startLine, endLine + 1).join('\n'), startLine, diff --git a/vscode/src/completions/context/retrievers/jaccard-similarity/jaccard-similarity-retriever.ts b/vscode/src/completions/context/retrievers/jaccard-similarity/jaccard-similarity-retriever.ts index b25e0957e8e..5b101eaf60d 100644 --- a/vscode/src/completions/context/retrievers/jaccard-similarity/jaccard-similarity-retriever.ts +++ b/vscode/src/completions/context/retrievers/jaccard-similarity/jaccard-similarity-retriever.ts @@ -8,7 +8,7 @@ import { type DocumentHistory, VSCodeDocumentHistory } from './history' import { FeatureFlag, isDefined } from '@sourcegraph/cody-shared' import { completionProviderConfig } from '../../../completion-provider-config' import { lastNLines } from '../../../text-processing' -import { type ShouldUseContextParams, shouldBeUsedAsContext } from '../../utils' +import { RetrieverIdentifier, type ShouldUseContextParams, shouldBeUsedAsContext } from '../../utils' import { type CachedRerieverOptions, CachedRetriever } from '../cached-retriever' import { type JaccardMatch, bestJaccardMatches } from './bestJaccardMatch' @@ -47,7 +47,7 @@ export class JaccardSimilarityRetriever extends CachedRetriever implements Conte this.maxMatchesPerFile = options.maxMatchesPerFile ?? MAX_MATCHES_PER_FILE } - public identifier = 'jaccard-similarity' + public identifier = RetrieverIdentifier.JaccardSimilarityRetriever private history = new VSCodeDocumentHistory() public async doRetrieval({ diff --git a/vscode/src/completions/context/retrievers/lsp-light/lsp-light-retriever.ts b/vscode/src/completions/context/retrievers/lsp-light/lsp-light-retriever.ts index 9455e62f42d..33dd70c824c 100644 --- a/vscode/src/completions/context/retrievers/lsp-light/lsp-light-retriever.ts +++ b/vscode/src/completions/context/retrievers/lsp-light/lsp-light-retriever.ts @@ -10,6 +10,7 @@ import { } from '../../../../graph/lsp/symbol-context-snippets' import { SupportedLanguage } from '../../../../tree-sitter/grammars' import type { ContextRetriever, ContextRetrieverOptions } from '../../../types' +import { RetrieverIdentifier } from '../../utils' import { getLastNGraphContextIdentifiersFromDocument } from '../graph/identifiers' const SUPPORTED_LANGUAGES = new Set([ @@ -26,7 +27,7 @@ const RECURSION_LIMIT = 3 const IDENTIFIERS_TO_RESOLVE = 1 export class LspLightRetriever implements ContextRetriever { - public identifier = 'lsp-light' + public identifier = RetrieverIdentifier.LspLightRetriever private disposables: vscode.Disposable[] = [] private isCacheDisabled = IS_LSP_LIGHT_CACHE_DISABLED diff --git a/vscode/src/completions/context/retrievers/recent-edits/recent-edits-retriever.ts b/vscode/src/completions/context/retrievers/recent-edits/recent-edits-retriever.ts index 456ae546489..de1fdedb9dc 100644 --- a/vscode/src/completions/context/retrievers/recent-edits/recent-edits-retriever.ts +++ b/vscode/src/completions/context/retrievers/recent-edits/recent-edits-retriever.ts @@ -4,7 +4,7 @@ import type { AutocompleteContextSnippet } from '@sourcegraph/cody-shared' import * as vscode from 'vscode' import { getLanguageConfig } from '../../../../tree-sitter/language' import type { ContextRetriever, ContextRetrieverOptions } from '../../../types' -import { type ShouldUseContextParams, shouldBeUsedAsContext } from '../../utils' +import { RetrieverIdentifier, type ShouldUseContextParams, shouldBeUsedAsContext } from '../../utils' interface TrackedDocument { content: string @@ -24,7 +24,7 @@ export class RecentEditsRetriever implements vscode.Disposable, ContextRetriever // We use a map from the document URI to the set of tracked completions inside that document to // improve performance of the `onDidChangeTextDocument` event handler. private trackedDocuments: Map = new Map() - public identifier = 'recent-edits' + public identifier = RetrieverIdentifier.RecentEditsRetriever private disposables: vscode.Disposable[] = [] constructor( @@ -54,6 +54,7 @@ export class RecentEditsRetriever implements vscode.Disposable, ContextRetriever ).toString() const autocompleteSnippet = { uri: diff.uri, + identifier: RetrieverIdentifier.RecentEditsRetriever, content, } satisfies Omit autocompleteContextSnippets.push(autocompleteSnippet) diff --git a/vscode/src/completions/context/retrievers/tsc/tsc-retriever.ts b/vscode/src/completions/context/retrievers/tsc/tsc-retriever.ts index 35bae766473..1ded851fe00 100644 --- a/vscode/src/completions/context/retrievers/tsc/tsc-retriever.ts +++ b/vscode/src/completions/context/retrievers/tsc/tsc-retriever.ts @@ -17,6 +17,7 @@ import type { ProtocolRelatedInformationDiagnostic, } from '../../../../jsonrpc/agent-protocol' import type { ContextRetriever, ContextRetrieverOptions } from '../../../types' +import { RetrieverIdentifier } from '../../utils' import { SymbolFormatter, isStdLibNode } from './SymbolFormatter' import { getTSSymbolAtLocation } from './getTSSymbolAtLocation' import { type NodeMatchKind, relevantTypeIdentifiers } from './relevantTypeIdentifiers' @@ -112,7 +113,7 @@ interface DocumentSnapshot { * information about the autocomplete request location. */ export class TscRetriever implements ContextRetriever { - public identifier = 'tsc' + public identifier = RetrieverIdentifier.TscRetriever constructor(private options: TscRetrieverOptions = defaultTscRetrieverOptions()) { this.disposables.push( @@ -535,6 +536,7 @@ class SymbolCollector { // Skip module declarations because they can be too large. // We still format them to queue the referenced types. const snippet: AutocompleteContextSnippet = { + identifier: RetrieverIdentifier.TscRetriever, symbol: sym.name, content, startLine: start.line, diff --git a/vscode/src/completions/context/utils.ts b/vscode/src/completions/context/utils.ts index eba68a58d6a..ce7a73b98e9 100644 --- a/vscode/src/completions/context/utils.ts +++ b/vscode/src/completions/context/utils.ts @@ -14,6 +14,14 @@ const htmlFamily = new Set([ // import CSS modules but define them in the same file instead. ]) +export enum RetrieverIdentifier { + BfgRetriever = 'bfg', + RecentEditsRetriever = 'recent-edits', + JaccardSimilarityRetriever = 'jaccard-similarity', + TscRetriever = 'tsc', + LspLightRetriever = 'lsp-light', +} + export interface ShouldUseContextParams { enableExtendedLanguagePool: boolean baseLanguageId: string diff --git a/vscode/src/completions/get-inline-completions.ts b/vscode/src/completions/get-inline-completions.ts index 96724773cd9..c162f3e03d1 100644 --- a/vscode/src/completions/get-inline-completions.ts +++ b/vscode/src/completions/get-inline-completions.ts @@ -526,7 +526,7 @@ async function doGetInlineCompletions( requestParams, isDotComUser, stale, - context: contextResult?.context ?? [], + rankedContextCandidates: contextResult?.rankedContextCandidates ?? [], }) } @@ -537,7 +537,7 @@ interface ProcessRequestManagerResultParams { requestParams: RequestParams isDotComUser: boolean stale: boolean | undefined - context?: AutocompleteContextSnippet[] + rankedContextCandidates?: AutocompleteContextSnippet[] } function processRequestManagerResult( @@ -549,7 +549,7 @@ function processRequestManagerResult( requestParams, isDotComUser, stale, - context, + rankedContextCandidates, } = params let { logId } = params @@ -563,7 +563,7 @@ function processRequestManagerResult( } const inlineContextParams = { - context: context ?? [], + context: rankedContextCandidates ?? [], filePath: gitIdentifiersForFile?.filePath, gitUrl: gitIdentifiersForFile?.gitUrl, commit: gitIdentifiersForFile?.commit, diff --git a/vscode/src/completions/logger.test.ts b/vscode/src/completions/logger.test.ts index 60c45656dca..7fcc458b137 100644 --- a/vscode/src/completions/logger.test.ts +++ b/vscode/src/completions/logger.test.ts @@ -8,6 +8,7 @@ import { getCurrentDocContext } from './get-current-doc-context' import { InlineCompletionsResultSource, TriggerKind } from './get-inline-completions' import { initCompletionProviderConfig } from './get-inline-completions-tests/helpers' import * as CompletionLogger from './logger' +import { type InlineCompletionItemContext, getInlineContextItemToLog } from './logger' import type { RequestParams } from './request-manager' import { documentAndPosition } from './test-helpers' @@ -173,4 +174,96 @@ describe('logger', () => { CompletionLogger.partiallyAccept(id, item, 5, false) CompletionLogger.partiallyAccept(id, item, 8, false) }) + + describe('getInlineContextItemToLog', () => { + it('filters context items based on payload size limit', () => { + const inlineCompletionItemContext: InlineCompletionItemContext = { + gitUrl: 'https://github.com/example/repo', + commit: 'abc123', + filePath: '/path/to/file.ts', + prefix: 'const foo = ', + suffix: ';', + triggerLine: 10, + triggerCharacter: 5, + isRepoPublic: true, + context: [ + { + identifier: 'item1', + content: 'a'.repeat(500 * 1024), + startLine: 1, + endLine: 10, + filePath: '/path/to/file1.ts', + }, + { + identifier: 'item2', + content: 'b'.repeat(300 * 1024), + startLine: 11, + endLine: 20, + filePath: '/path/to/file2.ts', + }, + { + identifier: 'item3', + content: 'c'.repeat(300 * 1024), + startLine: 21, + endLine: 30, + filePath: '/path/to/file3.ts', + }, + ], + } + + const result = getInlineContextItemToLog(inlineCompletionItemContext) + + expect(result).toBeDefined() + expect(result?.prefix).toBe('const foo = ') + expect(result?.suffix).toBe(';') + expect(result?.context).toHaveLength(2) + expect(result?.context?.[0].identifier).toBe('item1') + expect(result?.context?.[1].identifier).toBe('item2') + expect(result?.context?.[2]).toBeUndefined() + }) + + it('filters when the prefix and suffix is too long', () => { + const inlineCompletionItemContext: InlineCompletionItemContext = { + gitUrl: 'https://github.com/example/repo', + commit: 'abc123', + filePath: '/path/to/file.ts', + prefix: 'a'.repeat(1024 * 1024), + suffix: ';', + triggerLine: 10, + triggerCharacter: 5, + isRepoPublic: true, + context: [ + { + identifier: 'item1', + content: 'a'.repeat(500 * 1024), + startLine: 1, + endLine: 10, + filePath: '/path/to/file1.ts', + }, + { + identifier: 'item2', + content: 'b'.repeat(300 * 1024), + startLine: 11, + endLine: 20, + filePath: '/path/to/file2.ts', + }, + { + identifier: 'item3', + content: 'c'.repeat(300 * 1024), + startLine: 21, + endLine: 30, + filePath: '/path/to/file3.ts', + }, + ], + } + + const result = getInlineContextItemToLog(inlineCompletionItemContext) + expect(result).toBeUndefined() + }) + + it('returns undefined for undefined input', () => { + const result = getInlineContextItemToLog(undefined) + expect(result).toBeUndefined() + }) + }) }) diff --git a/vscode/src/completions/logger.ts b/vscode/src/completions/logger.ts index 246f4136cc0..c98a7852e01 100644 --- a/vscode/src/completions/logger.ts +++ b/vscode/src/completions/logger.ts @@ -67,6 +67,7 @@ export type CompletionItemID = string & { _opaque: typeof CompletionItemID } declare const CompletionItemID: unique symbol interface InlineCompletionItemRetrievedContext { + identifier: string content: string filePath: string startLine: number @@ -80,7 +81,7 @@ interface InlineContextItemsParams { commit: string | undefined } -interface InlineCompletionItemContext { +export interface InlineCompletionItemContext { gitUrl: string commit?: string filePath?: string @@ -740,6 +741,7 @@ export function loaded(params: LoadedParams): void { triggerLine: requestParams.position.line, triggerCharacter: requestParams.position.character, context: inlineContextParams.context.map(snippet => ({ + identifier: snippet.identifier, content: snippet.content, startLine: snippet.startLine, endLine: snippet.endLine, @@ -1007,25 +1009,39 @@ export function flushActiveSuggestionRequests(isDotComUser: boolean): void { logSuggestionEvents(isDotComUser) } -function getInlineContextItemToLog( - inlineCompletionItemContext: InlineCompletionItemContext | undefined +export function getInlineContextItemToLog( + inlineCompletionItemContext?: InlineCompletionItemContext ): InlineCompletionItemContext | undefined { - if (inlineCompletionItemContext === undefined) { + if (!inlineCompletionItemContext?.prefix || !inlineCompletionItemContext?.suffix) { return undefined } - const MAX_CONTEXT_ITEMS = 15 - const MAX_CHARACTERS = 20_000 - return { - ...inlineCompletionItemContext, - prefix: inlineCompletionItemContext.prefix?.slice(-MAX_CHARACTERS), - suffix: inlineCompletionItemContext.suffix?.slice(0, MAX_CHARACTERS), - context: inlineCompletionItemContext.context?.slice(0, MAX_CONTEXT_ITEMS).map(c => ({ - ...c, - content: c.content.slice(0, MAX_CHARACTERS), - })), + + const MAX_PAYLOAD_SIZE_BYTES = 1024 * 1024 + const prefixSize = Buffer.byteLength(inlineCompletionItemContext.prefix, 'utf8') + const suffixSize = Buffer.byteLength(inlineCompletionItemContext.suffix, 'utf8') + // If the prefix and suffix are too large, we don't log the context as the data is not useful for offline analysis. + if (prefixSize + suffixSize > MAX_PAYLOAD_SIZE_BYTES) { + return undefined } -} + const result: Partial = { + prefix: inlineCompletionItemContext.prefix, + suffix: inlineCompletionItemContext.suffix, + } + + let currentPayloadSizeBytes = prefixSize + suffixSize + + result.context = inlineCompletionItemContext.context?.filter(item => { + const itemSize = Buffer.byteLength(item.content, 'utf8') + if (currentPayloadSizeBytes + itemSize <= MAX_PAYLOAD_SIZE_BYTES) { + currentPayloadSizeBytes += itemSize + return true + } + return false + }) + + return { ...inlineCompletionItemContext, ...result } +} export function logSuggestionEvents(isDotComUser: boolean): void { const now = performance.now() // biome-ignore lint/complexity/noForEach: LRUCache#forEach has different typing than #entries, so just keeping it for now diff --git a/vscode/src/completions/model-helpers/__tests__/test-data.ts b/vscode/src/completions/model-helpers/__tests__/test-data.ts index 1966ddffce5..3afec237642 100644 --- a/vscode/src/completions/model-helpers/__tests__/test-data.ts +++ b/vscode/src/completions/model-helpers/__tests__/test-data.ts @@ -20,18 +20,21 @@ export const completionParams = paramsWithInlinedCompletion( export const contextSnippets = [ { + identifier: 'jaccard-similarity', uri: testFileUri('codebase/context1.ts'), content: 'function contextSnippetOne() {}', startLine: 1, endLine: 2, }, { + identifier: 'jaccard-similarity', uri: testFileUri('codebase/context2.ts'), content: 'const contextSnippet2 = {}', startLine: 1, endLine: 2, }, { + identifier: 'jaccard-similarity', uri: testFileUri('codebase/context3.ts'), content: 'interface ContextParams {}', startLine: 1, diff --git a/vscode/src/graph/lsp/symbol-context-snippets.ts b/vscode/src/graph/lsp/symbol-context-snippets.ts index 8f859389bcd..9c3dfb86357 100644 --- a/vscode/src/graph/lsp/symbol-context-snippets.ts +++ b/vscode/src/graph/lsp/symbol-context-snippets.ts @@ -12,6 +12,7 @@ import { getLastNGraphContextIdentifiersFromString } from '../../completions/con import { lines } from '../../completions/text-processing' import { SupportedLanguage } from '../../tree-sitter/grammars' +import { RetrieverIdentifier } from '../../completions/context/utils' import { IS_LSP_LIGHT_LOGGING_ENABLED, debugSymbol, @@ -126,6 +127,7 @@ async function getSnippetForLocationGetter( } const symbolContextSnippet = { + identifier: RetrieverIdentifier.LspLightRetriever, key: `${definitionUri}::${definitionRange.start.line}:${definitionRange.start.character}`, uri: definitionUri, startLine: definitionRange.start.line,