Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,18 @@
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.future.await
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import migration.software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager
import org.eclipse.lsp4j.jsonrpc.ResponseErrorException
import org.eclipse.lsp4j.jsonrpc.messages.Either
import software.amazon.awssdk.services.ssooidc.model.InvalidGrantException
import software.aws.toolkits.core.utils.debug
import software.aws.toolkits.core.utils.getLogger
import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineBgContext
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
import software.aws.toolkits.jetbrains.core.credentials.sso.bearer.BearerTokenProvider
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
import software.aws.toolkits.jetbrains.services.codewhisperer.importadder.CodeWhispererImportAdder
Expand All @@ -59,8 +67,10 @@
import software.aws.toolkits.jetbrains.services.codewhisperer.telemetry.CodeWhispererTelemetryService
import software.aws.toolkits.jetbrains.services.codewhisperer.toolwindow.CodeWhispererCodeReferenceManager
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererConstants
import software.aws.toolkits.jetbrains.services.codewhisperer.util.CodeWhispererUtil
import software.aws.toolkits.jetbrains.services.codewhisperer.util.getDocumentDiagnostics
import software.aws.toolkits.jetbrains.utils.isQConnected
import software.aws.toolkits.jetbrains.utils.isQExpired
import software.aws.toolkits.resources.message
import software.aws.toolkits.telemetry.CodewhispererTriggerType
import java.awt.Dimension
Expand Down Expand Up @@ -393,8 +403,22 @@

override suspend fun getSuggestion(request: InlineCompletionRequest): InlineCompletionSuggestion {
val editor = request.editor
val document = editor.document
val project = editor.project ?: return InlineCompletionSuggestion.Empty

// try to refresh automatically if possible, otherwise ask user to login again
if (isQExpired(project)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this isQExpired should be very fast so that inline completion latency does not go up

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is just check on token timestamp

// consider changing to only running once a ~minute since this is relatively expensive
// say the connection is un-refreshable if refresh fails for 3 times
val shouldReauth = withContext(getCoroutineBgContext()) {
CodeWhispererUtil.promptReAuth(project)

Check warning on line 413 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L413

Added line #L413 was not covered by tests
}

if (shouldReauth) {
return InlineCompletionSuggestion.Empty

Check warning on line 417 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L417

Added line #L417 was not covered by tests
}
}

val document = editor.document

Check warning on line 421 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L421

Added line #L421 was not covered by tests
val handler = InlineCompletion.getHandlerOrNull(editor) ?: return InlineCompletionSuggestion.Empty
val session = InlineCompletionSession.getOrNull(editor) ?: return InlineCompletionSuggestion.Empty
val triggerSessionId = triggerSessionId++
Expand Down Expand Up @@ -446,31 +470,28 @@
}

try {
// Launch coroutine for background pagination progress
cs.launch {
var nextToken: Either<String, Int>? = null
do {
nextToken = startPaginationInBackground(
project,
editor,
triggerTypeInfo,
triggerSessionId,
nextToken,
sessionContext,
)
} while (nextToken != null && !nextToken.left.isNullOrEmpty())
var nextToken: Either<String, Int>? = null

Check warning on line 473 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L473

Added line #L473 was not covered by tests
do {
nextToken = startPaginationInBackground(
project,
editor,
triggerTypeInfo,
triggerSessionId,
nextToken,
sessionContext,

Check warning on line 481 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L475-L481

Added lines #L475 - L481 were not covered by tests
)
} while (nextToken != null && !nextToken.left.isNullOrEmpty())

// closing all channels since pagination for this session has finished
// closing all channels since pagination for this session has finished
logInline(triggerSessionId) {
"Pagination finished, closing all channels"

Check warning on line 487 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L486-L487

Added lines #L486 - L487 were not covered by tests
}
sessionContext.itemContexts.forEach {
it.channel.close()
}

Check warning on line 491 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L489-L491

Added lines #L489 - L491 were not covered by tests
if (session.context.isDisposed) {
logInline(triggerSessionId) {
"Pagination finished, closing all channels"
}
sessionContext.itemContexts.forEach {
it.channel.close()
}
if (session.context.isDisposed) {
logInline(triggerSessionId) {
"Current display session already disposed by a new trigger before pagination finishes, exiting"
}
"Current display session already disposed by a new trigger before pagination finishes, exiting"

Check warning on line 494 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L494

Added line #L494 was not covered by tests
}
}

Expand Down Expand Up @@ -575,6 +596,27 @@
logInline(triggerSessionId, e) {
"Error during pagination"
}
if (e is ResponseErrorException) {
// convoluted but lines up with "The bearer token included in the request is invalid"
// https://github.com/aws/language-servers/blob/1f3e93024eeb22186a34f0bd560f8d552f517300/server/aws-lsp-codewhisperer/src/language-server/chat/utils.ts#L22-L23
// error data is nullable
if (e.responseError.data?.toString()?.contains("E_AMAZON_Q_CONNECTION_EXPIRED") == true) {
// kill the session if the connection is expired
val connection = ToolkitConnectionManager
.getInstance(project)
.activeConnectionForFeature(QConnection.getInstance()) as? AwsBearerTokenConnection

Check warning on line 607 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L606-L607

Added lines #L606 - L607 were not covered by tests
val tokenProvider = connection?.let { it.getConnectionSettings().tokenProvider.delegate as? BearerTokenProvider }
tokenProvider?.let {
// TODO: fragile
try {
it.refresh()
} catch (_: InvalidGrantException) {
it.invalidate()
CodeWhispererUtil.reconnectCodeWhisperer(project)
}

Check warning on line 616 in plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt

View check run for this annotation

Codecov / codecov/patch

plugins/amazonq/codewhisperer/jetbrains-community/src/software/aws/toolkits/jetbrains/services/codewhisperer/popup/QInlineCompletionProvider.kt#L611-L616

Added lines #L611 - L616 were not covered by tests
}
}
}
return null
}
}
Expand All @@ -594,6 +636,7 @@
val editor = request.editor
val project = editor.project ?: return false

// qExpired case handled in completion handler
if (!isQConnected(project)) return false
if (QRegionProfileManager.getInstance().hasValidConnectionButNoActiveProfile(project)) return false
if (event.isManualCall()) return true
Expand Down
Loading