Skip to content

Commit e389d92

Browse files
authored
Merge branch 'feature/code-diff' into feature/StreamingDiffAnimation
2 parents 120aba1 + 99793f3 commit e389d92

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+2693
-117
lines changed

package-lock.json

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"date": "2025-08-06",
3+
"version": "1.88.0",
4+
"entries": [
5+
{
6+
"type": "Feature",
7+
"description": "Amazon Q Chat provides error explanations and fixes when hovering or right-clicking on error indicators and messages"
8+
},
9+
{
10+
"type": "Feature",
11+
"description": "/transform: Show transformation history in Transformation Hub and allow users to resume jobs"
12+
}
13+
]
14+
}

packages/amazonq/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 1.88.0 2025-08-06
2+
3+
- **Feature** Amazon Q Chat provides error explanations and fixes when hovering or right-clicking on error indicators and messages
4+
- **Feature** /transform: Show transformation history in Transformation Hub and allow users to resume jobs
5+
16
## 1.87.0 2025-07-31
27

38
- Miscellaneous non-user-facing changes

packages/amazonq/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "amazon-q-vscode",
33
"displayName": "Amazon Q",
44
"description": "The most capable generative AI–powered assistant for software development.",
5-
"version": "1.88.0-SNAPSHOT",
5+
"version": "1.89.0-SNAPSHOT",
66
"extensionKind": [
77
"workspace"
88
],
@@ -746,7 +746,7 @@
746746
},
747747
{
748748
"command": "aws.amazonq.showHistoryInHub",
749-
"title": "%AWS.command.q.transform.viewJobStatus%"
749+
"title": "%AWS.command.q.transform.viewJobHistory%"
750750
},
751751
{
752752
"command": "aws.amazonq.selectCustomization",

packages/amazonq/src/app/inline/EditRendering/displayImage.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,8 @@ export async function displaySvgDecoration(
352352
discarded: false,
353353
},
354354
},
355+
totalSessionDisplayTime: Date.now() - session.requestStartTime,
356+
firstCompletionDisplayLatency: session.firstCompletionDisplayLatency,
355357
isInlineEdit: true,
356358
}
357359
languageClient.sendNotification('aws/logInlineCompletionSessionResults', params)

packages/amazonq/src/app/inline/completion.ts

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,11 @@ export class InlineCompletionManager implements Disposable {
170170
const onInlineRejection = async () => {
171171
try {
172172
vsCodeState.isCodeWhispererEditing = true
173-
if (this.sessionManager.getActiveSession() === undefined) {
173+
const session = this.sessionManager.getActiveSession()
174+
if (session === undefined) {
174175
return
175176
}
176-
const requestStartTime = this.sessionManager.getActiveSession()!.requestStartTime
177+
const requestStartTime = session.requestStartTime
177178
const totalSessionDisplayTime = performance.now() - requestStartTime
178179
await commands.executeCommand('editor.action.inlineSuggest.hide')
179180
// TODO: also log the seen state for other suggestions in session
@@ -182,9 +183,9 @@ export class InlineCompletionManager implements Disposable {
182183
CodeWhispererConstants.platformLanguageIds,
183184
this.inlineCompletionProvider
184185
)
185-
const sessionId = this.sessionManager.getActiveSession()?.sessionId
186+
const sessionId = session.sessionId
186187
const itemId = this.sessionManager.getActiveRecommendation()[0]?.itemId
187-
if (!sessionId || !itemId) {
188+
if (!itemId) {
188189
return
189190
}
190191
const params: LogInlineCompletionSessionResultsParams = {
@@ -196,6 +197,7 @@ export class InlineCompletionManager implements Disposable {
196197
discarded: false,
197198
},
198199
},
200+
firstCompletionDisplayLatency: session.firstCompletionDisplayLatency,
199201
totalSessionDisplayTime: totalSessionDisplayTime,
200202
}
201203
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
@@ -274,12 +276,6 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
274276

275277
// yield event loop to let the document listen catch updates
276278
await sleep(1)
277-
// prevent user deletion invoking auto trigger
278-
// this is a best effort estimate of deletion
279-
if (this.documentEventListener.isLastEventDeletion(document.uri.fsPath)) {
280-
getLogger().debug('Skip auto trigger when deleting code')
281-
return []
282-
}
283279

284280
let logstr = `GenerateCompletion metadata:\\n`
285281
try {
@@ -290,14 +286,16 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
290286
const prevSessionId = prevSession?.sessionId
291287
const prevItemId = this.sessionManager.getActiveRecommendation()?.[0]?.itemId
292288
const prevStartPosition = prevSession?.startPosition
293-
if (prevSession?.triggerOnAcceptance) {
289+
const editsTriggerOnAcceptance = prevSession?.triggerOnAcceptance
290+
if (editsTriggerOnAcceptance) {
294291
getAllRecommendationsOptions = {
295292
...getAllRecommendationsOptions,
296293
editsStreakToken: prevSession?.editsStreakPartialResultToken,
297294
}
298295
}
299296
const editor = window.activeTextEditor
300-
if (prevSession && prevSessionId && prevItemId && prevStartPosition) {
297+
// Skip prefix matching for Edits suggestions that trigger on acceptance.
298+
if (prevSession && prevSessionId && prevItemId && prevStartPosition && !editsTriggerOnAcceptance) {
301299
const prefix = document.getText(new Range(prevStartPosition, position))
302300
const prevItemMatchingPrefix = []
303301
for (const item of this.sessionManager.getActiveRecommendation()) {
@@ -341,6 +339,7 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
341339
discarded: !prevSession.displayed,
342340
},
343341
},
342+
firstCompletionDisplayLatency: prevSession.firstCompletionDisplayLatency,
344343
totalSessionDisplayTime: performance.now() - prevSession.requestStartTime,
345344
}
346345
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
@@ -365,8 +364,8 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
365364
},
366365
token,
367366
isAutoTrigger,
368-
getAllRecommendationsOptions,
369-
this.documentEventListener.getLastDocumentChangeEvent(document.uri.fsPath)?.event
367+
this.documentEventListener,
368+
getAllRecommendationsOptions
370369
)
371370
// get active item from session for displaying
372371
const items = this.sessionManager.getActiveRecommendation()
@@ -399,21 +398,24 @@ ${itemLog}
399398

400399
const cursorPosition = document.validatePosition(position)
401400

402-
if (position.isAfter(editor.selection.active)) {
403-
const params: LogInlineCompletionSessionResultsParams = {
404-
sessionId: session.sessionId,
405-
completionSessionResult: {
406-
[itemId]: {
407-
seen: false,
408-
accepted: false,
409-
discarded: true,
401+
// Completion will not be rendered if users cursor moves to a position which is before the position when the service is invoked
402+
if (items.length > 0 && !items[0].isInlineEdit) {
403+
if (position.isAfter(editor.selection.active)) {
404+
const params: LogInlineCompletionSessionResultsParams = {
405+
sessionId: session.sessionId,
406+
completionSessionResult: {
407+
[itemId]: {
408+
seen: false,
409+
accepted: false,
410+
discarded: true,
411+
},
410412
},
411-
},
413+
}
414+
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
415+
this.sessionManager.clear()
416+
logstr += `- cursor moved behind trigger position. Discarding completion suggestion...`
417+
return []
412418
}
413-
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
414-
this.sessionManager.clear()
415-
logstr += `- cursor moved behind trigger position. Discarding suggestion...`
416-
return []
417419
}
418420

419421
// delay the suggestion rendeing if user is actively typing

packages/amazonq/src/app/inline/recommendationService.ts

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
* SPDX-License-Identifier: Apache-2.0
44
*/
5-
import * as vscode from 'vscode'
65
import {
76
InlineCompletionListWithReferences,
87
InlineCompletionWithReferencesParams,
98
inlineCompletionWithReferencesRequestType,
109
TextDocumentContentChangeEvent,
10+
editCompletionRequestType,
1111
} from '@aws/language-server-runtimes/protocol'
1212
import { CancellationToken, InlineCompletionContext, Position, TextDocument } from 'vscode'
1313
import { LanguageClient } from 'vscode-languageclient'
@@ -21,6 +21,8 @@ import {
2121
import { TelemetryHelper } from './telemetryHelper'
2222
import { ICursorUpdateRecorder } from './cursorUpdateManager'
2323
import { getLogger } from 'aws-core-vscode/shared'
24+
import { DocumentEventListener } from './documentEventListener'
25+
import { getOpenFilesInWindow } from 'aws-core-vscode/utils'
2426
import { asyncCallWithTimeout } from '../../util/timeoutUtil'
2527

2628
export interface GetAllRecommendationsOptions {
@@ -65,9 +67,11 @@ export class RecommendationService {
6567
context: InlineCompletionContext,
6668
token: CancellationToken,
6769
isAutoTrigger: boolean,
68-
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true },
69-
documentChangeEvent?: vscode.TextDocumentChangeEvent
70+
documentEventListener: DocumentEventListener,
71+
options: GetAllRecommendationsOptions = { emitTelemetry: true, showUi: true }
7072
) {
73+
const documentChangeEvent = documentEventListener?.getLastDocumentChangeEvent(document.uri.fsPath)?.event
74+
7175
// Record that a regular request is being made
7276
this.cursorUpdateRecorder?.recordCompletionRequest()
7377
const documentChangeParams = documentChangeEvent
@@ -79,14 +83,15 @@ export class RecommendationService {
7983
contentChanges: documentChangeEvent.contentChanges.map((x) => x as TextDocumentContentChangeEvent),
8084
}
8185
: undefined
82-
86+
const openTabs = await getOpenFilesInWindow()
8387
let request: InlineCompletionWithReferencesParams = {
8488
textDocument: {
8589
uri: document.uri.toString(),
8690
},
8791
position,
8892
context,
8993
documentChangeParams: documentChangeParams,
94+
openTabFilepaths: openTabs,
9095
}
9196
if (options.editsStreakToken) {
9297
request = { ...request, partialResultToken: options.editsStreakToken }
@@ -117,7 +122,51 @@ export class RecommendationService {
117122
})
118123
const t0 = performance.now()
119124

120-
const result = await this.getRecommendationsWithTimeout(languageClient, request, token)
125+
// Best effort estimate of deletion
126+
const isTriggerByDeletion = documentEventListener.isLastEventDeletion(document.uri.fsPath)
127+
128+
const ps: Promise<InlineCompletionListWithReferences>[] = []
129+
/**
130+
* IsTriggerByDeletion is to prevent user deletion invoking Completions.
131+
* PartialResultToken is not a hack for now since only Edits suggestion use partialResultToken across different calls of [getAllRecommendations],
132+
* Completions use PartialResultToken with single 1 call of [getAllRecommendations].
133+
* Edits leverage partialResultToken to achieve EditStreak such that clients can pull all continuous suggestions generated by the model within 1 EOS block.
134+
*/
135+
if (!isTriggerByDeletion && !request.partialResultToken) {
136+
const completionPromise: Promise<InlineCompletionListWithReferences> = languageClient.sendRequest(
137+
inlineCompletionWithReferencesRequestType.method,
138+
request,
139+
token
140+
)
141+
ps.push(completionPromise)
142+
}
143+
144+
/**
145+
* Though Edit request is sent on keystrokes everytime, the language server will execute the request in a debounced manner so that it won't be immediately executed.
146+
*/
147+
const editPromise: Promise<InlineCompletionListWithReferences> = languageClient.sendRequest(
148+
editCompletionRequestType.method,
149+
request,
150+
token
151+
)
152+
ps.push(editPromise)
153+
154+
/**
155+
* First come first serve, ideally we should simply return the first response returned. However there are some caviar here because either
156+
* (1) promise might be returned early without going through service
157+
* (2) some users are not enabled with edits suggestion, therefore service will return empty result without passing through the model
158+
* With the scenarios listed above or others, it's possible that 1 promise will ALWAYS win the race and users will NOT get any suggestion back.
159+
* This is the hack to return first "NON-EMPTY" response
160+
*/
161+
let result = await Promise.race(ps)
162+
if (ps.length > 1 && result.items.length === 0) {
163+
for (const p of ps) {
164+
const r = await p
165+
if (r.items.length > 0) {
166+
result = r
167+
}
168+
}
169+
}
121170

122171
getLogger().info('Received inline completion response from LSP: %O', {
123172
sessionId: result.sessionId,

packages/amazonq/src/extension.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ import { registerCommands } from './commands'
4545
import { focusAmazonQPanel } from 'aws-core-vscode/codewhispererChat'
4646
import { activate as activateAmazonqLsp } from './lsp/activation'
4747
import { hasGlibcPatch } from './lsp/client'
48+
import { activateAutoDebug } from './lsp/chat/autoDebug/activation'
4849

4950
export const amazonQContextPrefix = 'amazonq'
5051

@@ -131,6 +132,14 @@ export async function activateAmazonQCommon(context: vscode.ExtensionContext, is
131132
await activateAmazonqLsp(context)
132133
}
133134

135+
// Activate AutoDebug feature at extension level
136+
try {
137+
const autoDebugFeature = await activateAutoDebug(context)
138+
context.subscriptions.push(autoDebugFeature)
139+
} catch (error) {
140+
getLogger().error('Failed to activate AutoDebug feature at extension level: %s', error)
141+
}
142+
134143
// Generic extension commands
135144
registerGenericCommands(context, amazonQContextPrefix)
136145

packages/amazonq/src/lsp/chat/activation.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,16 @@ import { activate as registerLegacyChatListeners } from '../../app/chat/activati
1717
import { DefaultAmazonQAppInitContext } from 'aws-core-vscode/amazonq'
1818
import { AuthUtil, getSelectedCustomization } from 'aws-core-vscode/codewhisperer'
1919
import { pushConfigUpdate } from '../config'
20+
import { AutoDebugLspClient } from './autoDebug/lsp/autoDebugLspClient'
2021

2122
export async function activate(languageClient: LanguageClient, encryptionKey: Buffer, mynahUIPath: string) {
2223
const disposables = globals.context.subscriptions
2324

2425
const provider = new AmazonQChatViewProvider(mynahUIPath, languageClient)
2526

27+
// Set the chat view provider for AutoDebug to use
28+
AutoDebugLspClient.setChatViewProvider(provider)
29+
2630
disposables.push(
2731
window.registerWebviewViewProvider(AmazonQChatViewProvider.viewType, provider, {
2832
webviewOptions: {

0 commit comments

Comments
 (0)