Skip to content
Merged
Changes from 4 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
106 changes: 91 additions & 15 deletions packages/amazonq/src/app/inline/completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ export class InlineCompletionManager implements Disposable {
await ImportAdderProvider.instance.onAcceptRecommendation(editor, item, startLine)
}
this.sessionManager.incrementSuggestionCount()
// clear session manager states once accepted
this.sessionManager.clear()
}
commands.registerCommand('aws.amazonq.acceptInline', onInlineAcceptance)

Expand Down Expand Up @@ -166,6 +168,8 @@ export class InlineCompletionManager implements Disposable {
},
}
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
// clear session manager states once rejected
this.sessionManager.clear()
}
commands.registerCommand('aws.amazonq.rejectCodeSuggestion', onInlineRejection)
}
Expand All @@ -179,6 +183,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
private readonly inlineTutorialAnnotation: InlineTutorialAnnotation
) {}

private readonly logSessionResultMessageName = 'aws/logInlineCompletionSessionResults'
provideInlineCompletionItems = debounce(
this._provideInlineCompletionItems.bind(this),
inlineCompletionsDebounceDelay,
Expand All @@ -191,6 +196,10 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
context: InlineCompletionContext,
token: CancellationToken
): Promise<InlineCompletionItem[]> {
// prevent concurrent API calls and write to shared state variables
if (vsCodeState.isRecommendationsActive) {
return []
}
try {
vsCodeState.isRecommendationsActive = true
const isAutoTrigger = context.triggerKind === InlineCompletionTriggerKind.Automatic
Expand All @@ -199,6 +208,24 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
return []
}

// report suggestion state for previous suggestions if they exist
const prevSessionId = this.sessionManager.getActiveSession()?.sessionId
const prevItemId = this.sessionManager.getActiveRecommendation()?.[0]?.itemId
if (prevSessionId && prevItemId) {
const params: LogInlineCompletionSessionResultsParams = {
sessionId: prevSessionId,
completionSessionResult: {
[prevItemId]: {
seen: true,
accepted: false,
discarded: false,
},
},
}
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
this.sessionManager.clear()
}

// tell the tutorial that completions has been triggered
await this.inlineTutorialAnnotation.triggered(context.triggerKind)
TelemetryHelper.instance.setInvokeSuggestionStartTime()
Expand All @@ -213,6 +240,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
)
// get active item from session for displaying
const items = this.sessionManager.getActiveRecommendation()
const itemId = this.sessionManager.getActiveRecommendation()?.[0]?.itemId
const session = this.sessionManager.getActiveSession()
const editor = window.activeTextEditor

Expand All @@ -229,24 +257,72 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
}

const cursorPosition = document.validatePosition(position)
for (const item of items) {
item.command = {
command: 'aws.amazonq.acceptInline',
title: 'On acceptance',
arguments: [
session.sessionId,
item,
editor,
session.requestStartTime,
cursorPosition.line,
session.firstCompletionDisplayLatency,
],

if (position.isAfter(editor.selection.active)) {
getLogger().debug(`Cursor moved behind trigger position. Discarding suggestion...`)
const params: LogInlineCompletionSessionResultsParams = {
sessionId: session.sessionId,
completionSessionResult: {
[itemId]: {
seen: false,
accepted: false,
discarded: true,
},
},
}
item.range = new Range(cursorPosition, cursorPosition)
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
this.sessionManager.clear()
return []
}

// the user typed characters from invoking suggestion cursor position to receiving suggestion position
const typeahead = document.getText(new Range(position, editor.selection.active))

const itemsMatchingTypeahead = []

for (const item of items) {
item.insertText = typeof item.insertText === 'string' ? item.insertText : item.insertText.value
ImportAdderProvider.instance.onShowRecommendation(document, cursorPosition.line, item)
if (item.insertText.startsWith(typeahead)) {
item.command = {
command: 'aws.amazonq.acceptInline',
title: 'On acceptance',
arguments: [
session.sessionId,
item,
editor,
session.requestStartTime,
cursorPosition.line,
session.firstCompletionDisplayLatency,
],
}
item.range = new Range(cursorPosition, cursorPosition)
itemsMatchingTypeahead.push(item)
ImportAdderProvider.instance.onShowRecommendation(document, cursorPosition.line, item)
}
}

// report discard if none of suggestions match typeahead
if (itemsMatchingTypeahead.length === 0) {
getLogger().debug(
`Suggestion does not match user typeahead from insertion position. Discarding suggestion...`
)
const params: LogInlineCompletionSessionResultsParams = {
sessionId: session.sessionId,
completionSessionResult: {
[itemId]: {
seen: false,
accepted: false,
discarded: true,
},
},
}
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
this.sessionManager.clear()
return []
}
return items as InlineCompletionItem[]

// suggestions returned here will be displayed on screen
return itemsMatchingTypeahead as InlineCompletionItem[]
} catch (e) {
getLogger('amazonqLsp').error('Failed to provide completion items: %O', e)
return []
Expand Down
Loading