Skip to content
This repository was archived by the owner on Aug 1, 2025. It is now read-only.
Draft
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 lib/shared/src/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export interface AutoEditsTokenLimit {
codeToRewritePrefixLines: number
codeToRewriteSuffixLines: number
contextSpecificTokenLimit: Record<string, number>
contextSpecificNumItemsLimit: Record<string, number>
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ import { getCurrentDocContext } from '../../completions/get-current-doc-context'
import { documentAndPosition } from '../../completions/test-helpers'
import * as sentryModule from '../../services/sentry/sentry'
import { type AutoeditModelOptions, AutoeditStopReason } from '../adapters/base'
import { getCodeToReplaceData, getCurrentFilePath } from '../prompt/prompt-utils'
import { getCodeToReplaceData } from '../prompt/prompt-utils/code-to-replace'
import { getCurrentFilePath } from '../prompt/prompt-utils/common'
import { getDecorationInfo } from '../renderer/diff-utils'

import { AutoeditAnalyticsLogger } from './analytics-logger'
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/autoedits/analytics-logger/analytics-logger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type * as vscode from 'vscode'
import {
type BillingCategory,
type BillingProduct,
type CodeToReplaceData,
type DocumentContext,
isDotComAuthed,
isNetworkError,
Expand All @@ -21,7 +22,6 @@ import { captureException, shouldErrorBeReported } from '../../services/sentry/s
import { splitSafeMetadata } from '../../services/telemetry-v2'
import type { AutoeditsPrompt, PartialModelResponse, SuccessModelResponse } from '../adapters/base'
import { autoeditsOutputChannelLogger } from '../output-channel-logger'
import type { CodeToReplaceData } from '../prompt/prompt-utils'
import type { DecorationInfo } from '../renderer/decorators/base'
import { getDecorationStats } from '../renderer/diff-utils'

Expand Down
3 changes: 1 addition & 2 deletions vscode/src/autoedits/analytics-logger/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type * as vscode from 'vscode'

import type { DocumentContext } from '@sourcegraph/cody-shared'
import type { CodeToReplaceData, DocumentContext } from '@sourcegraph/cody-shared'
import type { InlineCompletionItemRetrievedContext } from '../../../src/completions/analytics-logger'
import type { ContextSummary } from '../../completions/context/context-mixer'
import type { CodeGenEventMetadata } from '../../services/CharactersLogger'
import type { ModelResponse } from '../adapters/base'
import type { CodeToReplaceData } from '../prompt/prompt-utils'
import type { DecorationStats } from '../renderer/diff-utils'
import type { AutoEditRenderOutput } from '../renderer/render-output'

Expand Down
14 changes: 14 additions & 0 deletions vscode/src/autoedits/autoedits-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ export const defaultTokenLimit: AutoEditsTokenLimit = {
[RetrieverIdentifier.DiagnosticsRetriever]: 250,
[RetrieverIdentifier.RecentViewPortRetriever]: 1000,
},
contextSpecificNumItemsLimit: {
[RetrieverIdentifier.RecentEditsRetriever]: 10,
[RetrieverIdentifier.JaccardSimilarityRetriever]: 0,
[RetrieverIdentifier.RecentCopyRetriever]: 0,
[RetrieverIdentifier.DiagnosticsRetriever]: 2,
[RetrieverIdentifier.RecentViewPortRetriever]: 2,
},
} as const satisfies AutoEditsTokenLimit

export const hotStreakTokenLimit: AutoEditsTokenLimit = {
Expand All @@ -55,6 +62,13 @@ export const hotStreakTokenLimit: AutoEditsTokenLimit = {
[RetrieverIdentifier.DiagnosticsRetriever]: 100,
[RetrieverIdentifier.RecentViewPortRetriever]: 500,
},
contextSpecificNumItemsLimit: {
[RetrieverIdentifier.RecentEditsRetriever]: 10,
[RetrieverIdentifier.JaccardSimilarityRetriever]: 0,
[RetrieverIdentifier.RecentCopyRetriever]: 0,
[RetrieverIdentifier.DiagnosticsRetriever]: 2,
[RetrieverIdentifier.RecentViewPortRetriever]: 2,
},
} as const satisfies AutoEditsTokenLimit

let hotStreakEnabled = false
Expand Down
5 changes: 3 additions & 2 deletions vscode/src/autoedits/autoedits-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type { Histogram } from '@opentelemetry/api'
import {
type ChatClient,
type ClientCapabilities,
type CodeToReplaceData,
type DocumentContext,
clientCapabilities,
currentResolvedConfig,
Expand Down Expand Up @@ -54,8 +55,8 @@ import { createMockResponseGenerator } from './mock-response-generator'
import { autoeditsOutputChannelLogger } from './output-channel-logger'
import type { AutoeditsUserPromptStrategy } from './prompt/base'
import { createPromptProvider } from './prompt/create-prompt-provider'
import { type CodeToReplaceData, getCodeToReplaceData } from './prompt/prompt-utils'
import { getCurrentFilePath } from './prompt/prompt-utils'
import { getCodeToReplaceData } from './prompt/prompt-utils/code-to-replace'
import { getCurrentFilePath } from './prompt/prompt-utils/common'
import { DefaultDecorator } from './renderer/decorators/default-decorator'
import { InlineDiffDecorator } from './renderer/decorators/inline-diff-decorator'
import { getAddedLines, getDecorationInfoFromPrediction } from './renderer/diff-utils'
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/autoedits/hot-streak/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import type {
IgnoredPredictionResult,
SuggestedPredictionResult,
} from '../autoedits-provider'
import { getCodeToReplaceData } from '../prompt/prompt-utils'
import { getCodeToReplaceData } from '../prompt/prompt-utils/code-to-replace'
import { isDuplicatingTextFromRewriteArea } from '../utils'

import { getHotStreakChunk } from './get-chunk'
Expand Down
2 changes: 1 addition & 1 deletion vscode/src/autoedits/prompt/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
import type { AutoeditsPrompt } from '../adapters/base'

import { SYSTEM_PROMPT } from './constants'
import { getCompletionsPromptWithSystemPrompt } from './prompt-utils'
import { getCompletionsPromptWithSystemPrompt } from './prompt-utils/common'

export interface UserPromptArgs {
document: vscode.TextDocument
Expand Down
3 changes: 2 additions & 1 deletion vscode/src/autoedits/prompt/long-prompt-experimental.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { documentAndPosition } from '../../completions/test-helpers'

import type { UserPromptArgs } from './base'
import { LongTermPromptStrategy } from './long-prompt-experimental'
import { getCodeToReplaceData } from './prompt-utils'
import { getCodeToReplaceData } from './prompt-utils/code-to-replace'

describe('LongTermPromptStrategy', () => {
beforeEach(() => {
Expand Down Expand Up @@ -67,6 +67,7 @@ describe('LongTermPromptStrategy', () => {
[RetrieverIdentifier.JaccardSimilarityRetriever]: 100,
[RetrieverIdentifier.DiagnosticsRetriever]: 100,
},
contextSpecificNumItemsLimit: {},
}
const codeToReplaceData = getCodeToReplaceData({
docContext,
Expand Down
65 changes: 22 additions & 43 deletions vscode/src/autoedits/prompt/long-prompt-experimental.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
import { type AutocompleteContextSnippet, PromptString, ps } from '@sourcegraph/cody-shared'
import { groupConsecutiveItemsByPredicate } from '../../completions/context/retrievers/recent-user-actions/recent-edits-diff-helpers/utils'
import { RetrieverIdentifier } from '../../completions/context/utils'

import { AutoeditsUserPromptStrategy, type UserPromptArgs } from './base'
import * as constants from './constants'
import {
getContextItemMappingWithTokenLimit,
getContextItemsForIdentifier,
getCurrentFileLongSuggestionPrompt,
getLintErrorsPrompt,
getPromptForTheContextSource,
getPromptWithNewline,
getRecentEditsPrompt,
getRecentlyViewedSnippetsPrompt,
joinPromptsWithNewlineSeparator,
} from './prompt-utils'
} from './prompt-utils/common'
import { getCurrentFileLongSuggestionPrompt } from './prompt-utils/current-file'
import { getLintErrorsPrompt } from './prompt-utils/lint'
import {
getRecentEditsPrompt,
groupConsecutiveRecentEditsItemsFromSameFile,
splitMostRecentRecentEditItemAsShortTermItem,
} from './prompt-utils/recent-edits'
import { getRecentSnippetViewPromptWithMaxSnippetAge } from './prompt-utils/recent-view'

export class LongTermPromptStrategy extends AutoeditsUserPromptStrategy {
// Oldest timestamp for a snippet view that can be included in the prompt.
private SNIPPET_VIEW_MAX_TIMESTAMP_MS = 1000 * 60 * 10 // 10 minutes

getUserPrompt({ context, tokenBudget, codeToReplaceData, document }: UserPromptArgs): PromptString {
const contextItemMapping = getContextItemMappingWithTokenLimit(
context,
tokenBudget.contextSpecificTokenLimit
tokenBudget.contextSpecificTokenLimit,
tokenBudget.contextSpecificNumItemsLimit
)
const recentViewsPrompt = getPromptForTheContextSource(
const recentViewsPrompt = getRecentSnippetViewPromptWithMaxSnippetAge(
contextItemMapping.get(RetrieverIdentifier.RecentViewPortRetriever) || [],
constants.LONG_TERM_SNIPPET_VIEWS_INSTRUCTION,
getRecentlyViewedSnippetsPrompt
this.SNIPPET_VIEW_MAX_TIMESTAMP_MS
)
const { shortTermEditsPrompt, longTermEditsPrompt } = this.getRecentEditsPrompt(
contextItemMapping.get(RetrieverIdentifier.RecentEditsRetriever) || []
Expand Down Expand Up @@ -62,18 +67,10 @@ export class LongTermPromptStrategy extends AutoeditsUserPromptStrategy {
shortTermEditsPrompt: PromptString
longTermEditsPrompt: PromptString
} {
const recentEditsSnippets = getContextItemsForIdentifier(
contextItems,
RetrieverIdentifier.RecentEditsRetriever
)

const shortTermEditsPrompt =
recentEditsSnippets.length > 0 ? ps`${getRecentEditsPrompt([recentEditsSnippets[0]])}` : ps``

const longTermEditsPrompt =
recentEditsSnippets.length > 1
? this.computeLongTermRecentEditsPrompt(recentEditsSnippets.slice(1))
: ps``
const { shortTermEditItems, longTermEditItems } =
splitMostRecentRecentEditItemAsShortTermItem(contextItems)
const shortTermEditsPrompt = getRecentEditsPrompt(shortTermEditItems)
const longTermEditsPrompt = this.computeLongTermRecentEditsPrompt(longTermEditItems)

return {
shortTermEditsPrompt,
Expand All @@ -82,28 +79,10 @@ export class LongTermPromptStrategy extends AutoeditsUserPromptStrategy {
}

private computeLongTermRecentEditsPrompt(contextItems: AutocompleteContextSnippet[]): PromptString {
if (contextItems.length === 0) {
const combinedContextItems = groupConsecutiveRecentEditsItemsFromSameFile(contextItems)
if (combinedContextItems.length === 0) {
return ps``
}
// Group consecutive items by file name
const groupedContextItems = groupConsecutiveItemsByPredicate(
contextItems,
(a, b) => a.uri.toString() === b.uri.toString()
)
const combinedContextItems: AutocompleteContextSnippet[] = []
for (const group of groupedContextItems) {
const combinedItem = {
...group[0],
// The group content is from the latest to the oldest item.
// We need to reverse the order of the content to get diff from old to new.
content: group
.map(item => item.content)
.reverse()
.join('\nthen\n'),
}
combinedContextItems.push(combinedItem)
}

return joinPromptsWithNewlineSeparator([
constants.RECENT_EDITS_INSTRUCTION,
getRecentEditsPrompt(combinedContextItems),
Expand Down
30 changes: 5 additions & 25 deletions vscode/src/autoedits/prompt/prompt-cache-optimized-v1.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { documentAndPosition } from '../../completions/test-helpers'

import type { UserPromptArgs } from './base'
import { PromptCacheOptimizedV1 } from './prompt-cache-optimized-v1'
import { getCodeToReplaceData } from './prompt-utils'
import { getCodeToReplaceData } from './prompt-utils/code-to-replace'

describe('PromptCacheOptimizedV1', () => {
beforeEach(() => {
Expand Down Expand Up @@ -66,6 +66,10 @@ describe('PromptCacheOptimizedV1', () => {
[RetrieverIdentifier.JaccardSimilarityRetriever]: 100,
[RetrieverIdentifier.DiagnosticsRetriever]: 100,
},
contextSpecificNumItemsLimit: {
[RetrieverIdentifier.DiagnosticsRetriever]: 4,
[RetrieverIdentifier.RecentViewPortRetriever]: 2,
},
}

const codeToReplaceData = getCodeToReplaceData({
Expand Down Expand Up @@ -370,28 +374,4 @@ describe('PromptCacheOptimizedV1', () => {
expect(result.longTermEditsPrompt.toString()).toContain('long term edit')
})
})

describe('getDiagnosticsPrompt', () => {
const strategy = new PromptCacheOptimizedV1()

it('returns empty prompt when no diagnostics are provided', () => {
const result = (strategy as any).getDiagnosticsPrompt([])
expect(result.toString()).toBe('')
})

it('limits the number of diagnostics to DIAGNOSTICS_MAX_COUNT', () => {
const diagnostics = Array.from({ length: 6 }, (_, i) =>
getContextItem(
`diagnostic ${i}`,
100,
RetrieverIdentifier.DiagnosticsRetriever,
`test${i}.ts`
)
)

const result = (strategy as any).getDiagnosticsPrompt(diagnostics)
const matches = result.toString().match(/diagnostic \d/g) || []
expect(matches.length).toBe(4) // DIAGNOSTICS_MAX_COUNT is 4
})
})
})
Loading
Loading