Skip to content

Commit

Permalink
Merge main into feature/q-mega
Browse files Browse the repository at this point in the history
  • Loading branch information
aws-toolkit-automation authored Nov 22, 2024
2 parents fd4f0d1 + 2a8fd52 commit 2501dc2
Show file tree
Hide file tree
Showing 14 changed files with 206 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,42 @@ class FeatureDevClient(
requestBuilder.userContext(featureDevUserContext)
}

fun sendFeatureDevCodeGenerationEvent(
conversationId: String,
linesOfCodeGenerated: Int,
charactersOfCodeGenerated: Int,
): SendTelemetryEventResponse =
bearerClient().sendTelemetryEvent { requestBuilder ->
requestBuilder.telemetryEvent { telemetryEventBuilder ->
telemetryEventBuilder.featureDevCodeGenerationEvent {
it
.conversationId(conversationId)
.linesOfCodeGenerated(linesOfCodeGenerated)
.charactersOfCodeGenerated(charactersOfCodeGenerated)
}
}
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
requestBuilder.userContext(featureDevUserContext)
}

fun sendFeatureDevCodeAcceptanceEvent(
conversationId: String,
linesOfCodeAccepted: Int,
charactersOfCodeAccepted: Int,
): SendTelemetryEventResponse =
bearerClient().sendTelemetryEvent { requestBuilder ->
requestBuilder.telemetryEvent { telemetryEventBuilder ->
telemetryEventBuilder.featureDevCodeAcceptanceEvent {
it
.conversationId(conversationId)
.linesOfCodeAccepted(linesOfCodeAccepted)
.charactersOfCodeAccepted(charactersOfCodeAccepted)
}
}
requestBuilder.optOutPreference(getTelemetryOptOutPreference())
requestBuilder.userContext(featureDevUserContext)
}

fun createTaskAssistConversation(): CreateTaskAssistConversationResponse =
bearerClient().createTaskAssistConversation(
CreateTaskAssistConversationRequest.builder().build(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.ThrottlingExce
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendAnswerPart
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendUpdatePlaceholder
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.CancellationTokenSource
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getChangeIdentifier
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getDiffMetrics
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.readFileToString
import software.aws.toolkits.jetbrains.services.cwc.controller.chat.telemetry.getStartUrl
import software.aws.toolkits.resources.message
import software.aws.toolkits.telemetry.AmazonqTelemetry
Expand All @@ -40,6 +43,7 @@ class CodeGenerationState(
override var codeGenerationTotalIterationCount: Int? = null,
var currentCodeGenerationId: String? = "EMPTY_CURRENT_CODE_GENERATION_ID",
override var token: CancellationTokenSource?,
override var diffMetricsProcessed: DiffMetricsProcessed,
) : SessionState {
override val phase = SessionStatePhase.CODEGEN

Expand Down Expand Up @@ -81,6 +85,41 @@ class CodeGenerationState(
codeGenerationRemainingIterationCount = codeGenerationResult.codeGenerationRemainingIterationCount
codeGenerationTotalIterationCount = codeGenerationResult.codeGenerationTotalIterationCount

runCatching {
var insertedLines = 0
var insertedCharacters = 0
codeGenerationResult.newFiles.forEach { file ->
// FIXME: Ideally, the before content should be read from the uploaded context instead of from disk, to avoid drift
val before = config.repoContext.selectedSourceFolder
.toNioPath()
.resolve(file.zipFilePath)
.toFile()
.let { f ->
if (f.exists() && f.canRead()) {
readFileToString(f)
} else {
""
}
}

val changeIdentifier = getChangeIdentifier(file.zipFilePath, before, file.fileContent)

if (!diffMetricsProcessed.generated.contains(changeIdentifier)) {
val diffMetrics = getDiffMetrics(before, file.fileContent)
insertedLines += diffMetrics.insertedLines
insertedCharacters += diffMetrics.insertedCharacters
diffMetricsProcessed.generated.add(changeIdentifier)
}
}
if (insertedLines > 0) {
config.featureDevService.sendFeatureDevCodeGenerationEvent(
conversationId = config.conversationId,
linesOfCodeGenerated = insertedLines,
charactersOfCodeGenerated = insertedCharacters,
)
}
}.onFailure { /* Noop on diff telemetry failure */ }

val nextState =
PrepareCodeGenerationState(
tabID = tabID,
Expand All @@ -95,6 +134,7 @@ class CodeGenerationState(
codeGenerationRemainingIterationCount = codeGenerationRemainingIterationCount,
codeGenerationTotalIterationCount = codeGenerationTotalIterationCount,
token = this.token,
diffMetricsProcessed = diffMetricsProcessed,
)

// It is not needed to interact right away with the PrepareCodeGeneration.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class ConversationNotStartedState(
override var codeGenerationRemainingIterationCount: Int?,
override var codeGenerationTotalIterationCount: Int?,
override var currentIteration: Int?,
override var diffMetricsProcessed: DiffMetricsProcessed,
) : SessionState {
override val phase = SessionStatePhase.INIT

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class PrepareCodeGenerationState(
private var messenger: MessagePublisher,
override var codeGenerationRemainingIterationCount: Int? = null,
override var codeGenerationTotalIterationCount: Int? = null,
override var diffMetricsProcessed: DiffMetricsProcessed,
) : SessionState {
override val phase = SessionStatePhase.CODEGEN
override suspend fun interact(action: SessionStateAction): SessionStateInteraction {
Expand Down Expand Up @@ -74,7 +75,8 @@ class PrepareCodeGenerationState(
currentIteration = this.currentIteration,
repositorySize = zipFileLength.toDouble(),
messenger = messenger,
token = this.token
token = this.token,
diffMetricsProcessed = diffMetricsProcessed
)
} catch (e: Exception) {
result = Result.Failed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendA
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.updateFileComponent
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.CancellationTokenSource
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.FeatureDevService
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getChangeIdentifier
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.getDiffMetrics
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.readFileToString
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.resolveAndCreateOrUpdateFile
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util.resolveAndDeleteFile
import software.aws.toolkits.jetbrains.services.cwc.controller.ReferenceLogController
import java.util.HashSet

class Session(val tabID: String, val project: Project) {
var context: FeatureDevSessionContext

Check notice on line 30 in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/Session.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Join declaration and assignment

Can be joined with assignment
Expand All @@ -45,7 +49,15 @@ class Session(val tabID: String, val project: Project) {
context = FeatureDevSessionContext(project, MAX_PROJECT_SIZE_BYTES)
proxyClient = FeatureDevClient.getInstance(project)
featureDevService = FeatureDevService(proxyClient, project)
_state = ConversationNotStartedState("", tabID, null, 0, CODE_GENERATION_RETRY_LIMIT, 0)
_state = ConversationNotStartedState(
approach = "",
tabID = tabID,
token = null,
codeGenerationRemainingIterationCount = 0,
codeGenerationTotalIterationCount = CODE_GENERATION_RETRY_LIMIT,
currentIteration = 0,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet())
)
isAuthenticating = false
codegenRetries = CODE_GENERATION_RETRY_LIMIT
}
Expand Down Expand Up @@ -86,6 +98,7 @@ class Session(val tabID: String, val project: Project) {
uploadId = "", // There is no code gen uploadId so far
messenger = messenger,
token = CancellationTokenSource(),
diffMetricsProcessed = sessionState.diffMetricsProcessed,
)
}

Expand All @@ -110,6 +123,42 @@ class Session(val tabID: String, val project: Project) {
val selectedSourceFolder = context.selectedSourceFolder.toNioPath()
val newFilePaths = filePaths.filter { !it.rejected && !it.changeApplied }
val newDeletedFiles = deletedFiles.filter { !it.rejected && !it.changeApplied }

runCatching {
var insertedLines = 0
var insertedCharacters = 0
filePaths.forEach { file ->
// FIXME: Ideally, the before content should be read from the uploaded context instead of from disk, to avoid drift
val before = selectedSourceFolder
.resolve(file.zipFilePath)
.toFile()
.let { f ->
if (f.exists() && f.canRead()) {
readFileToString(f)
} else {
""
}
}

val changeIdentifier = getChangeIdentifier(file.zipFilePath, before, file.fileContent)

if (_state?.diffMetricsProcessed?.accepted?.contains(changeIdentifier) != true) {
val diffMetrics = getDiffMetrics(before, file.fileContent)
insertedLines += diffMetrics.insertedLines
insertedCharacters += diffMetrics.insertedCharacters
_state?.diffMetricsProcessed?.accepted?.add(changeIdentifier)
}
}

if (insertedLines > 0) {
featureDevService.sendFeatureDevCodeAcceptanceEvent(
conversationId = conversationId,
linesOfCodeAccepted = insertedLines,
charactersOfCodeAccepted = insertedCharacters,
)
}
}.onFailure { /* Noop on diff telemetry failure */ }

newFilePaths.forEach {
resolveAndCreateOrUpdateFile(selectedSourceFolder, it.zipFilePath, it.fileContent)
it.changeApplied = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ interface SessionState {
var codeGenerationTotalIterationCount: Int?
var currentIteration: Int?
var approach: String
var diffMetricsProcessed: DiffMetricsProcessed
suspend fun interact(action: SessionStateAction): SessionStateInteraction
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,8 @@ data class CodeGenerationStreamResult(
data class ExportTaskAssistResultArchiveStreamResult(
var code_generation_result: CodeGenerationStreamResult,
)

data class DiffMetricsProcessed(
var accepted: HashSet<String>,
var generated: HashSet<String>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import com.intellij.diff.comparison.ComparisonManager
import com.intellij.diff.comparison.ComparisonPolicy
import com.intellij.diff.fragments.LineFragment
import com.intellij.openapi.progress.EmptyProgressIndicator
import io.ktor.utils.io.core.toByteArray
import java.nio.charset.Charset
import java.security.MessageDigest

data class DiffMetrics(
val insertedLines: Int,
Expand Down Expand Up @@ -37,7 +40,7 @@ fun getDiffMetrics(before: String, after: String): DiffMetrics {
val fragments = comparisonManager.compareLines(
before,
after,
ComparisonPolicy.DEFAULT,
ComparisonPolicy.IGNORE_WHITESPACES,
EmptyProgressIndicator()
)

Expand Down Expand Up @@ -71,3 +74,11 @@ fun getDiffMetrics(before: String, after: String): DiffMetrics {
insertedCharacters = accCharCount,
)
}

fun getChangeIdentifier(filePath: String, before: String, after: String): String {
val hash = MessageDigest.getInstance("SHA-1")
hash.update(filePath.toByteArray(Charset.forName("UTF-8")))
hash.update(before.toByteArray(Charset.forName("UTF-8")))
hash.update(after.toByteArray(Charset.forName("UTF-8")))
return hash.digest().joinToString("") { "%02x".format(it) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -215,4 +215,32 @@ class FeatureDevService(val proxyClient: FeatureDevClient, val project: Project)
logger.warn(e) { "$FEATURE_NAME: failed to send feature dev telemetry" }
}
}

fun sendFeatureDevCodeGenerationEvent(conversationId: String, linesOfCodeGenerated: Int, charactersOfCodeGenerated: Int) {
val sendFeatureDevTelemetryEventResponse: SendTelemetryEventResponse
try {
sendFeatureDevTelemetryEventResponse = proxyClient
.sendFeatureDevCodeGenerationEvent(conversationId, linesOfCodeGenerated, charactersOfCodeGenerated)
val requestId = sendFeatureDevTelemetryEventResponse.responseMetadata().requestId()
logger.debug {
"$FEATURE_NAME: successfully sent feature dev code generation telemetry: ConversationId: $conversationId RequestId: $requestId"
}
} catch (e: Exception) {
logger.warn(e) { "$FEATURE_NAME: failed to send feature dev code generation telemetry" }
}
}

fun sendFeatureDevCodeAcceptanceEvent(conversationId: String, linesOfCodeAccepted: Int, charactersOfCodeAccepted: Int) {
val sendFeatureDevTelemetryEventResponse: SendTelemetryEventResponse
try {
sendFeatureDevTelemetryEventResponse = proxyClient
.sendFeatureDevCodeAcceptanceEvent(conversationId, linesOfCodeAccepted, charactersOfCodeAccepted)
val requestId = sendFeatureDevTelemetryEventResponse.responseMetadata().requestId()
logger.debug {
"$FEATURE_NAME: successfully sent feature dev code acceptance telemetry: ConversationId: $conversationId RequestId: $requestId"
}
} catch (e: Exception) {
logger.warn(e) { "$FEATURE_NAME: failed to send feature dev code acceptance telemetry" }
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ package software.aws.toolkits.jetbrains.services.amazonqFeatureDev.util
import com.intellij.openapi.fileChooser.FileChooser
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.CharsetToolkit
import com.intellij.openapi.vfs.VirtualFile
import java.io.File
import java.nio.charset.Charset
import java.nio.file.Path
import kotlin.io.path.createDirectories
import kotlin.io.path.deleteIfExists
Expand All @@ -33,3 +36,9 @@ fun selectFolder(project: Project, openOn: VirtualFile): VirtualFile? {
val fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor()
return FileChooser.chooseFile(fileChooserDescriptor, project, openOn)
}

fun readFileToString(file: File): String {
val charsetToolkit = CharsetToolkit(file.readBytes(), Charset.forName("UTF-8"), false)
val charset = charsetToolkit.guessEncoding(4096)
return file.readText(charset)
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendS
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.sendUpdatePlaceholder
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.messages.updateFileComponent
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DeletedFileInfo
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.DiffMetricsProcessed
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.Interaction
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.NewFileZipInfo
import software.aws.toolkits.jetbrains.services.amazonqFeatureDev.session.PrepareCodeGenerationState
Expand Down Expand Up @@ -236,6 +237,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
messenger,
0,
0,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)

Expand Down Expand Up @@ -295,6 +297,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)

Expand Down Expand Up @@ -354,6 +357,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)
whenever(mockSession.retries).thenReturn(3)
Expand Down Expand Up @@ -393,6 +397,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)
whenever(mockSession.retries).thenReturn(0)
Expand Down Expand Up @@ -425,6 +430,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)

Expand Down Expand Up @@ -458,6 +464,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)
doReturn(testConversationId).`when`(spySession).conversationId
Expand Down Expand Up @@ -514,6 +521,7 @@ class FeatureDevControllerTest : FeatureDevTestBase() {
testUploadId,
0,
messenger,
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
),
)
doReturn(testConversationId).`when`(spySession).conversationId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class CodeGenerationStateTest : FeatureDevTestBase() {
messenger,
token = null,
currentCodeGenerationId = "EMPTY_CURRENT_CODE_GENERATION_ID",
diffMetricsProcessed = DiffMetricsProcessed(HashSet(), HashSet()),
)

mockkStatic(MessagePublisher::sendAnswerPart)
Expand Down
Loading

0 comments on commit 2501dc2

Please sign in to comment.