Skip to content

Commit ba5d289

Browse files
Merge main into feature/q-lsp
2 parents 013c54f + 68a179a commit ba5d289

File tree

9 files changed

+29
-199
lines changed

9 files changed

+29
-199
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "removal",
3+
"description" : "Amazon Q: Revert prefetch logic to enable more stable inline completion."
4+
}

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/credentials/CodeWhispererClientAdaptor.kt

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@ interface CodeWhispererClientAdaptor : Disposable {
7777
firstRequest: GenerateCompletionsRequest,
7878
): Sequence<GenerateCompletionsResponse>
7979

80-
fun generateCompletions(
81-
firstRequest: GenerateCompletionsRequest,
82-
): GenerateCompletionsResponse
83-
8480
fun createUploadUrl(
8581
request: CreateUploadUrlRequest,
8682
): CreateUploadUrlResponse
@@ -327,8 +323,6 @@ open class CodeWhispererClientAdaptorImpl(override val project: Project) : CodeW
327323
yield(response)
328324
} while (!nextToken.isNullOrEmpty())
329325
}
330-
override fun generateCompletions(firstRequest: GenerateCompletionsRequest): GenerateCompletionsResponse =
331-
bearerClient().generateCompletions(firstRequest)
332326

333327
override fun createUploadUrl(request: CreateUploadUrlRequest): CreateUploadUrlResponse =
334328
bearerClient().createUploadUrl(request)

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupListener.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import com.intellij.openapi.ui.popup.JBPopupListener
77
import com.intellij.openapi.ui.popup.LightweightWindowEvent
88
import software.aws.toolkits.jetbrains.services.codewhisperer.model.InvocationContext
99
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
10-
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererService
1110
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererServiceNew
1211
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
1312
import java.time.Duration
@@ -28,8 +27,7 @@ class CodeWhispererPopupListener(private val states: InvocationContext) : JBPopu
2827
recommendationContext,
2928
CodeWhispererPopupManager.getInstance().sessionContext,
3029
event.isOk,
31-
CodeWhispererInvocationStatus.getInstance().popupStartTimestamp?.let { Duration.between(it, Instant.now()) },
32-
CodeWhispererService.getInstance().getNextInvocationContext()
30+
CodeWhispererInvocationStatus.getInstance().popupStartTimestamp?.let { Duration.between(it, Instant.now()) }
3331
)
3432

3533
CodeWhispererInvocationStatus.getInstance().setDisplaySessionActive(false)

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/CodeWhispererPopupManager.kt

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.Co
6868
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.CodeWhispererScrollListener
6969
import software.aws.toolkits.jetbrains.services.codewhisperer.popup.listeners.addIntelliSenseAcceptListener
7070
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererInvocationStatus
71-
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererService
7271
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
7372
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
7473
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererColorUtil.POPUP_DIM_HEX
@@ -453,9 +452,6 @@ class CodeWhispererPopupManager {
453452
CodeWhispererEditorManager.getInstance().updateEditorWithRecommendation(states, sessionContext)
454453
}
455454
closePopup(states.popup)
456-
if (sessionContext.selectedIndex == 0) {
457-
CodeWhispererService.getInstance().promoteNextInvocationIfAvailable()
458-
}
459455
}
460456
}
461457
)

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/service/CodeWhispererService.kt

Lines changed: 1 addition & 148 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import com.intellij.openapi.editor.Editor
1616
import com.intellij.openapi.editor.VisualPosition
1717
import com.intellij.openapi.project.Project
1818
import com.intellij.openapi.ui.popup.JBPopup
19-
import com.intellij.openapi.ui.popup.JBPopupFactory
2019
import com.intellij.openapi.util.Disposer
2120
import com.intellij.psi.PsiDocumentManager
2221
import com.intellij.psi.PsiFile
@@ -25,7 +24,6 @@ import com.intellij.util.messages.Topic
2524
import kotlinx.coroutines.CoroutineScope
2625
import kotlinx.coroutines.Deferred
2726
import kotlinx.coroutines.Job
28-
import kotlinx.coroutines.SupervisorJob
2927
import kotlinx.coroutines.async
3028
import kotlinx.coroutines.delay
3129
import kotlinx.coroutines.isActive
@@ -100,7 +98,6 @@ import java.util.concurrent.TimeUnit
10098
class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
10199
private val codeInsightSettingsFacade = CodeInsightsSettingsFacade()
102100
private var refreshFailure: Int = 0
103-
private var nextInvocationContext: InvocationContext? = null
104101

105102
init {
106103
Disposer.register(this, codeInsightSettingsFacade)
@@ -212,118 +209,7 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
212209
invokeCodeWhispererInBackground(requestContext)
213210
}
214211

215-
internal suspend fun invokeCodeWhispererInBackground(
216-
requestContext: RequestContext,
217-
currStates: InvocationContext? = null,
218-
): Job {
219-
// current states != null means that it's prefetch
220-
if (currStates != null) {
221-
val firstValidRecommendation = currStates.recommendationContext.details
222-
.firstOrNull {
223-
!it.isDiscarded && it.recommendation.content().isNotEmpty()
224-
} ?: return SupervisorJob().apply { complete() }
225-
val job = cs.launch(getCoroutineBgContext()) {
226-
val latencyContext = LatencyContext().apply {
227-
codewhispererPreprocessingStart = System.nanoTime()
228-
codewhispererEndToEndStart = System.nanoTime()
229-
}
230-
231-
val nextCaretPosition = CaretPosition(
232-
line = requestContext.caretPosition.line + firstValidRecommendation.recommendation.content().count { it == '\n' },
233-
offset = requestContext.caretPosition.offset + firstValidRecommendation.recommendation.content().length
234-
)
235-
236-
val nextFileContextInfo = requestContext.fileContextInfo.copy(
237-
caretContext = requestContext.fileContextInfo.caretContext.copy(
238-
leftFileContext = requestContext.fileContextInfo.caretContext.leftFileContext + firstValidRecommendation.recommendation.content()
239-
)
240-
)
241-
242-
val nextRequestContext = requestContext.copy(
243-
caretPosition = nextCaretPosition,
244-
fileContextInfo = nextFileContextInfo,
245-
latencyContext = latencyContext
246-
)
247-
val newVisualPosition = withContext(EDT) {
248-
runReadAction {
249-
nextRequestContext.editor.offsetToVisualPosition(nextRequestContext.caretPosition.offset)
250-
}
251-
}
252-
try {
253-
val nextResponse = CodeWhispererClientAdaptor
254-
.getInstance(nextRequestContext.project)
255-
.generateCompletions(
256-
buildCodeWhispererRequest(
257-
nextRequestContext.fileContextInfo,
258-
nextRequestContext.awaitSupplementalContext(),
259-
nextRequestContext.customizationArn
260-
)
261-
)
262-
val startTime = System.nanoTime()
263-
nextRequestContext.latencyContext.codewhispererPreprocessingEnd = System.nanoTime()
264-
nextRequestContext.latencyContext.paginationAllCompletionsStart = System.nanoTime()
265-
CodeWhispererInvocationStatus.getInstance().setInvocationStart()
266-
nextResponse.let {
267-
val endTime = System.nanoTime()
268-
val latency = TimeUnit.NANOSECONDS.toMillis(endTime - startTime).toDouble()
269-
val requestId = nextResponse.responseMetadata().requestId()
270-
val sessionId = nextResponse.sdkHttpResponse().headers().getOrDefault(KET_SESSION_ID, listOf(requestId))[0]
271-
272-
nextRequestContext.latencyContext.apply {
273-
codewhispererPostprocessingStart = System.nanoTime()
274-
paginationFirstCompletionTime = (endTime - codewhispererEndToEndStart).toDouble()
275-
firstRequestId = requestId
276-
}
277-
278-
CodeWhispererInvocationStatus.getInstance().setInvocationSessionId(sessionId)
279-
280-
val nextResponseContext = ResponseContext(sessionId)
281-
CodeWhispererTelemetryService.getInstance().sendServiceInvocationEvent(
282-
nextResponse.responseMetadata().requestId(),
283-
nextRequestContext,
284-
nextResponseContext,
285-
nextResponse.completions().size,
286-
invocationSuccess = true,
287-
latency,
288-
null
289-
)
290-
val validatedResponse = validateResponse(it)
291-
val detailContexts = withContext(EDT) {
292-
runReadAction {
293-
CodeWhispererRecommendationManager.getInstance().buildDetailContext(
294-
nextRequestContext,
295-
"",
296-
validatedResponse.completions(),
297-
validatedResponse.responseMetadata().requestId()
298-
)
299-
}
300-
}
301-
val nextRecommendationContext = RecommendationContext(detailContexts, "", "", newVisualPosition)
302-
val newPopup = withContext(EDT) {
303-
JBPopupFactory.getInstance().createMessage("Dummy popup")
304-
}
305-
306-
// send userDecision and trigger decision when next recommendation haven't been seen
307-
if (currStates.popup.isDisposed) {
308-
CodeWhispererTelemetryService.getInstance().sendUserDecisionEventForAll(
309-
nextRequestContext,
310-
nextResponseContext,
311-
nextRecommendationContext,
312-
SessionContext(),
313-
false
314-
)
315-
} else {
316-
nextInvocationContext = InvocationContext(nextRequestContext, nextResponseContext, nextRecommendationContext, newPopup)
317-
}
318-
LOG.debug { "Prefetched next invocation stored in nextInvocationContext" }
319-
}
320-
} catch (ex: Exception) {
321-
LOG.warn { "Failed to prefetch next codewhisperer invocation: ${ex.message}" }
322-
}
323-
}
324-
return job
325-
}
326-
212+
internal suspend fun invokeCodeWhispererInBackground(requestContext: RequestContext): Job {
327213
val popup = withContext(EDT) {
328214
CodeWhispererPopupManager.getInstance().initPopup().also {
329215
Disposer.register(it) { CodeWhispererInvocationStatus.getInstance().finishInvocation() }
@@ -605,9 +491,6 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
605491
CodeWhispererPopupManager.getInstance().cancelPopup(popup)
606492
return null
607493
}
608-
cs.launch(getCoroutineBgContext()) {
609-
invokeCodeWhispererInBackground(requestContext, nextStates)
610-
}
611494
} else {
612495
// subsequent responses
613496
nextStates = updateStates(currStates, response)
@@ -739,34 +622,6 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
739622
CodeWhispererPopupManager.getInstance().changeStates(states, 0, recommendationAdded)
740623
}
741624

742-
fun promoteNextInvocationIfAvailable() {
743-
val nextStates = nextInvocationContext ?: run {
744-
LOG.debug { "No nextInvocationContext found, nothing to promote." }
745-
return
746-
}
747-
nextInvocationContext?.popup?.let { Disposer.dispose(it) }
748-
nextInvocationContext = null
749-
750-
cs.launch {
751-
val newPopup = CodeWhispererPopupManager.getInstance().initPopup()
752-
val updatedNextStates = nextStates.copy(popup = newPopup).also {
753-
addPopupChildDisposables(it.requestContext.project, it.requestContext.editor, it.popup)
754-
Disposer.register(newPopup, it)
755-
}
756-
CodeWhispererPopupManager.getInstance().initPopupListener(updatedNextStates)
757-
withContext(EDT) {
758-
CodeWhispererPopupManager.getInstance().changeStates(
759-
updatedNextStates,
760-
0,
761-
recommendationAdded = false
762-
)
763-
}
764-
invokeCodeWhispererInBackground(updatedNextStates.requestContext, updatedNextStates)
765-
}
766-
767-
LOG.debug { "Promoted nextInvocationContext to current session and displayed next recommendation." }
768-
}
769-
770625
private fun sendDiscardedUserDecisionEventForAll(
771626
requestContext: RequestContext,
772627
responseContext: ResponseContext,
@@ -940,8 +795,6 @@ class CodeWhispererService(private val cs: CoroutineScope) : Disposable {
940795

941796
override fun dispose() {}
942797

943-
fun getNextInvocationContext(): InvocationContext? = nextInvocationContext
944-
945798
companion object {
946799
private val LOG = getLogger<CodeWhispererService>()
947800
private const val MAX_REFRESH_ATTEMPT = 3

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/telemetry/CodeWhispererTelemetryService.kt

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,6 @@ class CodeWhispererTelemetryService {
457457
sessionContext: SessionContext,
458458
hasUserAccepted: Boolean,
459459
popupShownTime: Duration? = null,
460-
nextInvocationContext: InvocationContext? = null,
461460
) {
462461
val detailContexts = recommendationContext.details
463462
val decisions = mutableListOf<CodewhispererSuggestionState>()
@@ -505,19 +504,6 @@ class CodeWhispererTelemetryService {
505504
previousUserTriggerDecisions.add(this)
506505
// we need this as well because AutotriggerService will reset the queue periodically
507506
CodeWhispererAutoTriggerService.getInstance().addPreviousDecision(this)
508-
// send possible next session event if current action is reject and next popup haven't shown up
509-
if (CodewhispererSuggestionState.from(this.toString()) == CodewhispererSuggestionState.Reject) {
510-
nextInvocationContext?.let {
511-
sendUserDecisionEventForAll(
512-
it.requestContext,
513-
it.responseContext,
514-
it.recommendationContext,
515-
SessionContext(),
516-
false,
517-
nextInvocationContext = null
518-
)
519-
}
520-
}
521507
}
522508
}
523509

plugins/amazonq/codewhisperer/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/codewhisperer/CodeWhispererSettingsTest.kt

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package software.aws.toolkits.jetbrains.services.codewhisperer
55

66
import com.intellij.analysis.problemsView.toolWindow.ProblemsView
7+
import com.intellij.openapi.application.ApplicationManager
78
import com.intellij.openapi.components.service
89
import com.intellij.openapi.wm.RegisterToolWindowTask
910
import com.intellij.openapi.wm.ToolWindow
@@ -19,12 +20,14 @@ import org.junit.Ignore
1920
import org.junit.Test
2021
import org.mockito.kotlin.any
2122
import org.mockito.kotlin.never
23+
import org.mockito.kotlin.spy
2224
import org.mockito.kotlin.verify
2325
import org.mockito.kotlin.whenever
2426
import software.aws.toolkits.jetbrains.core.ToolWindowHeadlessManagerImpl
2527
import software.aws.toolkits.jetbrains.services.codewhisperer.credentials.CodeWhispererLoginType
2628
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExploreActionState
2729
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.isCodeWhispererEnabled
30+
import software.aws.toolkits.jetbrains.services.codewhisperer.service.CodeWhispererService
2831
import software.aws.toolkits.jetbrains.services.codewhisperer.status.CodeWhispererStatusBarWidgetFactory
2932
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceToolWindowFactory
3033
import software.aws.toolkits.jetbrains.settings.CodeWhispererConfiguration
@@ -34,11 +37,14 @@ import kotlin.test.fail
3437

3538
class CodeWhispererSettingsTest : CodeWhispererTestBase() {
3639

40+
private lateinit var codewhispererServiceSpy: CodeWhispererService
3741
private lateinit var toolWindowHeadlessManager: ToolWindowHeadlessManagerImpl
3842

3943
@Before
4044
override fun setUp() {
4145
super.setUp()
46+
codewhispererServiceSpy = spy(codewhispererService)
47+
ApplicationManager.getApplication().replaceService(CodeWhispererService::class.java, codewhispererServiceSpy, disposableRule.disposable)
4248

4349
// Create a mock ToolWindowManager with working implementation of setAvailable() and isAvailable()
4450
toolWindowHeadlessManager = object : ToolWindowHeadlessManagerImpl(projectRule.project) {
@@ -80,7 +86,7 @@ class CodeWhispererSettingsTest : CodeWhispererTestBase() {
8086
whenever(stateManager.checkActiveCodeWhispererConnectionType(projectRule.project)).thenReturn(CodeWhispererLoginType.Logout)
8187
assertThat(isCodeWhispererEnabled(projectRule.project)).isFalse
8288
invokeCodeWhispererService()
83-
verify(codewhispererService, never()).showRecommendationsInPopup(any(), any(), any())
89+
verify(codewhispererServiceSpy, never()).showRecommendationsInPopup(any(), any(), any())
8490
}
8591

8692
@Test
@@ -89,7 +95,7 @@ class CodeWhispererSettingsTest : CodeWhispererTestBase() {
8995
assertThat(stateManager.isAutoEnabled()).isFalse
9096
runInEdtAndWait {
9197
projectRule.fixture.type(':')
92-
verify(codewhispererService, never()).showRecommendationsInPopup(any(), any(), any())
98+
verify(codewhispererServiceSpy, never()).showRecommendationsInPopup(any(), any(), any())
9399
}
94100
}
95101

0 commit comments

Comments
 (0)