Skip to content

Commit 457b5cc

Browse files
authored
Merge branch 'aws:master' into master
2 parents 2bccb32 + 7f36a2d commit 457b5cc

File tree

6 files changed

+48
-123
lines changed

6 files changed

+48
-123
lines changed

packages/amazonq/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@
410410
},
411411
{
412412
"command": "aws.amazonq.showLogs",
413-
"when": "view == aws.amazonq.AmazonQChatView",
413+
"when": "!aws.isSageMakerUnifiedStudio",
414414
"group": "1_amazonQ@5"
415415
},
416416
{
@@ -644,8 +644,7 @@
644644
{
645645
"command": "aws.amazonq.showLogs",
646646
"title": "%AWS.command.codewhisperer.showLogs%",
647-
"category": "%AWS.amazonq.title%",
648-
"enablement": "aws.codewhisperer.connected"
647+
"category": "%AWS.amazonq.title%"
649648
},
650649
{
651650
"command": "aws.amazonq.selectRegionProfile",

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

Lines changed: 5 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* SPDX-License-Identifier: Apache-2.0
44
*/
55

6-
import { diffChars } from 'diff'
6+
import { diffWordsWithSpace } from 'diff'
77
import * as vscode from 'vscode'
88
import { ToolkitError, getLogger } from 'aws-core-vscode/shared'
99
import { diffUtilities } from 'aws-core-vscode/shared'
@@ -413,45 +413,6 @@ export class SvgGenerationService {
413413
const originalRanges: Range[] = []
414414
const afterRanges: Range[] = []
415415

416-
/**
417-
* Merges ranges on the same line that are separated by only one character
418-
*/
419-
const mergeAdjacentRanges = (ranges: Range[]): Range[] => {
420-
const sortedRanges = [...ranges].sort((a, b) => {
421-
if (a.line !== b.line) {
422-
return a.line - b.line
423-
}
424-
return a.start - b.start
425-
})
426-
427-
const result: Range[] = []
428-
429-
// Process all ranges
430-
for (let i = 0; i < sortedRanges.length; i++) {
431-
const current = sortedRanges[i]
432-
433-
// If this is the last range or ranges are on different lines, add it directly
434-
if (i === sortedRanges.length - 1 || current.line !== sortedRanges[i + 1].line) {
435-
result.push(current)
436-
continue
437-
}
438-
439-
// Check if current range and next range can be merged
440-
const next = sortedRanges[i + 1]
441-
if (current.line === next.line && next.start - current.end <= 1) {
442-
sortedRanges[i + 1] = {
443-
line: current.line,
444-
start: current.start,
445-
end: Math.max(current.end, next.end),
446-
}
447-
} else {
448-
result.push(current)
449-
}
450-
}
451-
452-
return result
453-
}
454-
455416
// Create reverse mapping for quicker lookups
456417
const reverseMap = new Map<string, string>()
457418
for (const [original, modified] of modifiedLines.entries()) {
@@ -465,7 +426,7 @@ export class SvgGenerationService {
465426
// If line exists in modifiedLines as a key, process character diffs
466427
if (Array.from(modifiedLines.keys()).includes(line)) {
467428
const modifiedLine = modifiedLines.get(line)!
468-
const changes = diffChars(line, modifiedLine)
429+
const changes = diffWordsWithSpace(line, modifiedLine)
469430

470431
let charPos = 0
471432
for (const part of changes) {
@@ -497,7 +458,7 @@ export class SvgGenerationService {
497458

498459
if (reverseMap.has(line)) {
499460
const originalLine = reverseMap.get(line)!
500-
const changes = diffChars(originalLine, line)
461+
const changes = diffWordsWithSpace(originalLine, line)
501462

502463
let charPos = 0
503464
for (const part of changes) {
@@ -522,12 +483,9 @@ export class SvgGenerationService {
522483
}
523484
}
524485

525-
const mergedOriginalRanges = mergeAdjacentRanges(originalRanges)
526-
const mergedAfterRanges = mergeAdjacentRanges(afterRanges)
527-
528486
return {
529-
removedRanges: mergedOriginalRanges,
530-
addedRanges: mergedAfterRanges,
487+
removedRanges: originalRanges,
488+
addedRanges: afterRanges,
531489
}
532490
}
533491
}

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

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ export class InlineCompletionManager implements Disposable {
198198
}
199199

200200
export class AmazonQInlineCompletionItemProvider implements InlineCompletionItemProvider {
201-
private logger = getLogger('nextEditPrediction')
201+
private logger = getLogger()
202202
constructor(
203203
private readonly languageClient: LanguageClient,
204204
private readonly recommendationService: RecommendationService,
@@ -299,7 +299,8 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
299299
}
300300
// re-use previous suggestions as long as new typed prefix matches
301301
if (prevItemMatchingPrefix.length > 0) {
302-
getLogger().debug(`Re-using suggestions that match user typed characters`)
302+
logstr += `- not call LSP and reuse previous suggestions that match user typed characters
303+
- duration between trigger to completion suggestion is displayed ${performance.now() - t0}`
303304
return prevItemMatchingPrefix
304305
}
305306
getLogger().debug(`Auto rejecting suggestions from previous session`)
@@ -318,7 +319,6 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
318319
this.sessionManager.clear()
319320
}
320321

321-
// TODO: this line will take ~200ms each trigger, need to root cause and maybe better to disable it for now
322322
// tell the tutorial that completions has been triggered
323323
await this.inlineTutorialAnnotation.triggered(context.triggerKind)
324324

@@ -346,12 +346,13 @@ export class AmazonQInlineCompletionItemProvider implements InlineCompletionItem
346346

347347
const t2 = performance.now()
348348

349-
logstr = logstr += `- number of suggestions: ${items.length}
349+
logstr += `- number of suggestions: ${items.length}
350350
- sessionId: ${this.sessionManager.getActiveSession()?.sessionId}
351351
- first suggestion content (next line):
352352
${itemLog}
353-
- duration since trigger to before sending Flare call: ${t1 - t0}ms
354-
- duration since trigger to receiving responses from Flare: ${t2 - t0}ms
353+
- duration between trigger to before sending LSP call: ${t1 - t0}ms
354+
- duration between trigger to after receiving LSP response: ${t2 - t0}ms
355+
- duration between before sending LSP call to after receving LSP response: ${t2 - t1}ms
355356
`
356357
const session = this.sessionManager.getActiveSession()
357358

@@ -361,16 +362,13 @@ ${itemLog}
361362
}
362363

363364
if (!session || !items.length || !editor) {
364-
getLogger().debug(
365-
`Failed to produce inline suggestion results. Received ${items.length} items from service`
366-
)
365+
logstr += `Failed to produce inline suggestion results. Received ${items.length} items from service`
367366
return []
368367
}
369368

370369
const cursorPosition = document.validatePosition(position)
371370

372371
if (position.isAfter(editor.selection.active)) {
373-
getLogger().debug(`Cursor moved behind trigger position. Discarding suggestion...`)
374372
const params: LogInlineCompletionSessionResultsParams = {
375373
sessionId: session.sessionId,
376374
completionSessionResult: {
@@ -383,6 +381,7 @@ ${itemLog}
383381
}
384382
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
385383
this.sessionManager.clear()
384+
logstr += `- cursor moved behind trigger position. Discarding suggestion...`
386385
return []
387386
}
388387

@@ -410,9 +409,7 @@ ${itemLog}
410409
// Check if Next Edit Prediction feature flag is enabled
411410
if (Experiments.instance.get('amazonqLSPNEP', true)) {
412411
await showEdits(item, editor, session, this.languageClient, this)
413-
const t3 = performance.now()
414-
logstr = logstr + `- duration since trigger to NEP suggestion is displayed: ${t3 - t0}ms`
415-
this.logger.info(logstr)
412+
logstr += `- duration between trigger to edits suggestion is displayed: ${performance.now() - t0}ms`
416413
}
417414
return []
418415
}
@@ -438,9 +435,6 @@ ${itemLog}
438435

439436
// report discard if none of suggestions match typeahead
440437
if (itemsMatchingTypeahead.length === 0) {
441-
getLogger().debug(
442-
`Suggestion does not match user typeahead from insertion position. Discarding suggestion...`
443-
)
444438
const params: LogInlineCompletionSessionResultsParams = {
445439
sessionId: session.sessionId,
446440
completionSessionResult: {
@@ -453,17 +447,21 @@ ${itemLog}
453447
}
454448
this.languageClient.sendNotification(this.logSessionResultMessageName, params)
455449
this.sessionManager.clear()
450+
logstr += `- suggestion does not match user typeahead from insertion position. Discarding suggestion...`
456451
return []
457452
}
458453

459454
this.sessionManager.updateCodeReferenceAndImports()
460455
// suggestions returned here will be displayed on screen
456+
logstr += `- duration between trigger to completion suggestion is displayed: ${performance.now() - t0}ms`
461457
return itemsMatchingTypeahead as InlineCompletionItem[]
462458
} catch (e) {
463459
getLogger('amazonqLsp').error('Failed to provide completion items: %O', e)
460+
logstr += `- failed to provide completion items ${(e as Error).message}`
464461
return []
465462
} finally {
466463
vsCodeState.isRecommendationsActive = false
464+
this.logger.info(logstr)
467465
}
468466
}
469467
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,13 +92,15 @@ export class RecommendationService {
9292
nextToken: request.partialResultToken,
9393
},
9494
})
95+
const t0 = performance.now()
9596
const result: InlineCompletionListWithReferences = await languageClient.sendRequest(
9697
inlineCompletionWithReferencesRequestType.method,
9798
request,
9899
token
99100
)
100-
getLogger().info('Received inline completion response: %O', {
101+
getLogger().info('Received inline completion response from LSP: %O', {
101102
sessionId: result.sessionId,
103+
latency: performance.now() - t0,
102104
itemCount: result.items?.length || 0,
103105
items: result.items?.map((item) => ({
104106
itemId: item.itemId,
@@ -128,6 +130,7 @@ export class RecommendationService {
128130

129131
const isInlineEdit = result.items.some((item) => item.isInlineEdit)
130132

133+
// TODO: question, is it possible that the first request returns empty suggestion but has non-empty next token?
131134
if (result.partialResultToken) {
132135
if (!isInlineEdit) {
133136
// If the suggestion is COMPLETIONS and there are more results to fetch, handle them in the background

packages/amazonq/src/app/inline/tutorials/inlineTutorialAnnotation.ts

Lines changed: 22 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,7 @@
55

66
import * as vscode from 'vscode'
77
import * as os from 'os'
8-
import {
9-
AnnotationChangeSource,
10-
AuthUtil,
11-
inlinehintKey,
12-
runtimeLanguageContext,
13-
TelemetryHelper,
14-
} from 'aws-core-vscode/codewhisperer'
8+
import { AnnotationChangeSource, AuthUtil, inlinehintKey, runtimeLanguageContext } from 'aws-core-vscode/codewhisperer'
159
import { editorUtilities, getLogger, globals, setContext, vscodeUtilities } from 'aws-core-vscode/shared'
1610
import { LinesChangeEvent, LineSelection, LineTracker } from '../stateTracker/lineTracker'
1711
import { telemetry } from 'aws-core-vscode/telemetry'
@@ -296,28 +290,27 @@ export class InlineTutorialAnnotation implements vscode.Disposable {
296290
}
297291

298292
async triggered(triggerType: vscode.InlineCompletionTriggerKind): Promise<void> {
299-
await telemetry.withTraceId(async () => {
300-
if (!this._isReady) {
301-
return
302-
}
303-
304-
if (this._currentState instanceof ManualtriggerState) {
305-
if (
306-
triggerType === vscode.InlineCompletionTriggerKind.Invoke &&
307-
this._currentState.hasManualTrigger === false
308-
) {
309-
this._currentState.hasManualTrigger = true
310-
}
311-
if (
312-
this.sessionManager.getActiveRecommendation().length > 0 &&
313-
this._currentState.hasValidResponse === false
314-
) {
315-
this._currentState.hasValidResponse = true
316-
}
317-
}
318-
319-
await this.refresh(vscode.window.activeTextEditor, 'codewhisperer')
320-
}, TelemetryHelper.instance.traceId)
293+
// TODO: this logic will take ~200ms each trigger, need to root cause and re-enable once it's fixed, or it should only be invoked when the tutorial is actually needed
294+
// await telemetry.withTraceId(async () => {
295+
// if (!this._isReady) {
296+
// return
297+
// }
298+
// if (this._currentState instanceof ManualtriggerState) {
299+
// if (
300+
// triggerType === vscode.InlineCompletionTriggerKind.Invoke &&
301+
// this._currentState.hasManualTrigger === false
302+
// ) {
303+
// this._currentState.hasManualTrigger = true
304+
// }
305+
// if (
306+
// this.sessionManager.getActiveRecommendation().length > 0 &&
307+
// this._currentState.hasValidResponse === false
308+
// ) {
309+
// this._currentState.hasValidResponse = true
310+
// }
311+
// }
312+
// await this.refresh(vscode.window.activeTextEditor, 'codewhisperer')
313+
// }, TelemetryHelper.instance.traceId)
321314
}
322315

323316
isTutorialDone(): boolean {

packages/amazonq/test/unit/app/inline/EditRendering/svgGenerator.test.ts

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,7 @@ describe('SvgGenerationService', function () {
150150
})
151151

152152
describe('highlight ranges', function () {
153-
it('should generate highlight ranges for character-level changes', function () {
153+
it('should generate highlight ranges for word-level changes', function () {
154154
const originalCode = ['function test() {', ' return 42;', '}']
155155
const afterCode = ['function test() {', ' return 100;', '}']
156156
const modifiedLines = new Map([[' return 42;', ' return 100;']])
@@ -174,32 +174,6 @@ describe('SvgGenerationService', function () {
174174
assert.ok(addedRange.end > addedRange.start)
175175
})
176176

177-
it('should merge adjacent highlight ranges', function () {
178-
const originalCode = ['function test() {', ' return 42;', '}']
179-
const afterCode = ['function test() {', ' return 100;', '}']
180-
const modifiedLines = new Map([[' return 42;', ' return 100;']])
181-
182-
const generateHighlightRanges = (service as any).generateHighlightRanges.bind(service)
183-
const result = generateHighlightRanges(originalCode, afterCode, modifiedLines)
184-
185-
// Adjacent ranges should be merged
186-
const sortedRanges = [...result.addedRanges].sort((a, b) => {
187-
if (a.line !== b.line) {
188-
return a.line - b.line
189-
}
190-
return a.start - b.start
191-
})
192-
193-
// Check that no adjacent ranges exist
194-
for (let i = 0; i < sortedRanges.length - 1; i++) {
195-
const current = sortedRanges[i]
196-
const next = sortedRanges[i + 1]
197-
if (current.line === next.line) {
198-
assert.ok(next.start - current.end > 1, 'Adjacent ranges should be merged')
199-
}
200-
}
201-
})
202-
203177
it('should handle HTML escaping in highlight edits', function () {
204178
const newLines = ['function test() {', ' return "<script>alert(1)</script>";', '}']
205179
const highlightRanges = [{ line: 1, start: 10, end: 35 }]

0 commit comments

Comments
 (0)