in plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt [51:182]
override suspend fun interact(action: SessionStateAction): SessionStateInteraction<SessionState> {
val startTime = System.currentTimeMillis()
var result: MetricResult = MetricResult.Succeeded
var failureReason: String? = null
var failureReasonDesc: String? = null
var codeGenerationWorkflowStatus: CodeGenerationWorkflowStatus = CodeGenerationWorkflowStatus.COMPLETE
var numberOfReferencesGenerated: Int? = null
var numberOfFilesGenerated: Int? = null
try {
val codeGenerationId = UUID.randomUUID()
val response =
config.featureDevService.startTaskAssistCodeGeneration(
conversationId = config.conversationId,
uploadId = uploadId,
message = action.msg,
codeGenerationId = codeGenerationId.toString(),
currentCodeGenerationId = currentCodeGenerationId.toString(),
)
if (action.token?.token?.isCancellationRequested() != true) {
this.currentCodeGenerationId = codeGenerationId.toString()
}
messenger.sendAnswerPart(
tabId = tabID,
message = message("amazonqFeatureDev.code_generation.generating_code"),
)
messenger.sendUpdatePlaceholder(
tabId = tabID,
newPlaceholder = message("amazonqFeatureDev.code_generation.generating_code"),
)
val codeGenerationResult = generateCode(codeGenerationId = response.codeGenerationId(), messenger = messenger, token = action.token)
numberOfReferencesGenerated = codeGenerationResult.references.size
numberOfFilesGenerated = codeGenerationResult.newFiles.size
codeGenerationRemainingIterationCount = codeGenerationResult.codeGenerationRemainingIterationCount
codeGenerationTotalIterationCount = codeGenerationResult.codeGenerationTotalIterationCount
currentIteration =
if (codeGenerationRemainingIterationCount != null && codeGenerationTotalIterationCount != null) {
codeGenerationTotalIterationCount?.let { total -> codeGenerationRemainingIterationCount?.let { remaining -> total - remaining } }
} else {
currentIteration?.plus(1)
}
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.addressableRoot
.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,
approach = approach,
config = config,
filePaths = codeGenerationResult.newFiles,
deletedFiles = codeGenerationResult.deletedFiles,
references = codeGenerationResult.references,
currentIteration = currentIteration,
uploadId = uploadId,
messenger = messenger,
codeGenerationRemainingIterationCount = codeGenerationRemainingIterationCount,
codeGenerationTotalIterationCount = codeGenerationTotalIterationCount,
token = this.token,
diffMetricsProcessed = diffMetricsProcessed,
)
// It is not needed to interact right away with the PrepareCodeGeneration.
// returns therefore a SessionStateInteraction object to be handled by the controller.
return SessionStateInteraction(
nextState = nextState,
interaction = Interaction(content = "", interactionSucceeded = true),
)
} catch (e: Exception) {
logger.warn(e) { "$FEATURE_NAME: Code generation failed: ${e.message}" }
result = MetricResult.Failed
failureReason = e.javaClass.simpleName
if (e is FeatureDevException) {
failureReason = e.reason()
failureReasonDesc = e.reasonDesc()
}
codeGenerationWorkflowStatus = CodeGenerationWorkflowStatus.FAILED
throw e
} finally {
currentIteration?.let {
AmazonqTelemetry.codeGenerationInvoke(
amazonqConversationId = config.conversationId,
amazonqCodeGenerationResult = codeGenerationWorkflowStatus.toString(),
amazonqGenerateCodeIteration = it.toDouble(),
amazonqNumberOfReferences = numberOfReferencesGenerated?.toDouble(),
amazonqGenerateCodeResponseLatency = (System.currentTimeMillis() - startTime).toDouble(),
amazonqNumberOfFilesGenerated = numberOfFilesGenerated?.toDouble(),
amazonqRepositorySize = repositorySize,
result = result,
reason = failureReason,
reasonDesc = failureReasonDesc,
duration = (System.currentTimeMillis() - startTime).toDouble(),
credentialStartUrl = getStartUrl(config.featureDevService.project),
)
}
}
}