diff --git a/.changes/next-release/feature-5391ea41-f418-4154-9f0c-5de8bacf1aeb.json b/.changes/next-release/feature-5391ea41-f418-4154-9f0c-5de8bacf1aeb.json new file mode 100644 index 00000000000..9102d60ebfc --- /dev/null +++ b/.changes/next-release/feature-5391ea41-f418-4154-9f0c-5de8bacf1aeb.json @@ -0,0 +1,4 @@ +{ + "type" : "feature", + "description" : "The logs emitted by the Agent during user command execution will be accepted and written to `.amazonq/dev/run_command.log` file in the user's local repository." +} \ No newline at end of file diff --git a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt index 1c664733869..5448a51b55e 100644 --- a/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt +++ b/plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationState.kt @@ -30,6 +30,7 @@ import software.aws.toolkits.telemetry.MetricResult import java.util.UUID private val logger = getLogger() +private const val RUN_COMMAND_LOG_PATH = ".amazonq/dev/run_command.log" class CodeGenerationState( override val tabID: String, @@ -211,9 +212,23 @@ private suspend fun CodeGenerationState.generateCode( conversationId = config.conversationId, ) - val newFileInfo = registerNewFiles(newFileContents = codeGenerationStreamResult.new_file_contents) - val deletedFileInfo = registerDeletedFiles(deletedFiles = codeGenerationStreamResult.deleted_files) + val fileContents = codeGenerationStreamResult.new_file_contents.filterKeys { file -> + if (file.endsWith(RUN_COMMAND_LOG_PATH)) { + val contents: String = codeGenerationStreamResult.new_file_contents[file].orEmpty() + val truncatedContents = if (contents.length > 10000000) { + contents.substring(0, 10000000) + } else { + contents + } + logger.info(truncatedContents) { "Run command log: $truncatedContents" } + false + } else { + true + } + } + val newFileInfo = registerNewFiles(newFileContents = fileContents) + val deletedFileInfo = registerDeletedFiles(deletedFiles = codeGenerationStreamResult.deleted_files) return CodeGenerationResult( newFiles = newFileInfo, deletedFiles = deletedFileInfo, diff --git a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevTestBase.kt b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevTestBase.kt index 6c1a2fb6389..da392cd08cd 100644 --- a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevTestBase.kt +++ b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/FeatureDevTestBase.kt @@ -65,6 +65,8 @@ open class FeatureDevTestBase( internal val otherStatus = "Other" internal val testTabId = "test-tab-id" internal val testFilePaths = mapOf(Pair("test.ts", "This is a comment")) + internal val testRunCommandLogPath = ".amazonq/dev/run_command.log" + internal val testLogPath = mapOf(Pair(testRunCommandLogPath, "This is a log")) internal val testDeletedFiles = listOf("deleted.ts") internal val testReferences = listOf(CodeReferenceGenerated()) internal val testChecksumSha = "test-sha" diff --git a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationStateTest.kt b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationStateTest.kt index 45d613f6b24..8e60630ac21 100644 --- a/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationStateTest.kt +++ b/plugins/amazonq/chat/jetbrains-community/tst/software/aws/toolkits/jetbrains/services/amazonqFeatureDev/session/CodeGenerationStateTest.kt @@ -39,13 +39,14 @@ class CodeGenerationStateTest : FeatureDevTestBase() { private lateinit var messenger: MessagePublisher private val action = SessionStateAction("test-task", userMessage) private lateinit var featureDevService: FeatureDevService + private lateinit var repoContext: FeatureDevSessionContext @Before override fun setup() { featureDevService = mockk() every { featureDevService.project } returns projectRule.project messenger = mock() - val repoContext = mock() + repoContext = mockk() val sessionStateConfig = SessionStateConfig(testConversationId, repoContext, featureDevService) codeGenerationState = @@ -103,6 +104,34 @@ class CodeGenerationStateTest : FeatureDevTestBase() { coVerify(exactly = 1) { featureDevService.exportTaskAssistArchiveResult(testConversationId) } } + @Test + fun `test generateCode excludes run_command log file`() { + val runCommandLogFileName = "run_command.log" + + val archiveFiles = mapOf( + runCommandLogFileName to "newLog", + "other.ts" to "other content" + ) + val deletedFiles = emptyList() + val references = emptyList() + + every { featureDevService.getTaskAssistCodeGeneration(any(), any()) } returns exampleCompleteGetTaskAssistCodeGenerationResponse + every { featureDevService.startTaskAssistCodeGeneration(any(), any(), any(), any(), any()) } returns exampleStartTaskAssistConversationResponse + coEvery { featureDevService.exportTaskAssistArchiveResult(any()) } returns + CodeGenerationStreamResult(archiveFiles, listOf("deleted.ts"), listOf(CodeReferenceGenerated())) + + runTest { + val actual = codeGenerationState.interact(action) + val nextState = actual.nextState as PrepareCodeGenerationState + assertThat(nextState.filePaths).contains( + NewFileZipInfo(runCommandLogFileName, "newLog", rejected = false, changeApplied = false) + ) + assertThat(nextState.filePaths).contains( + NewFileZipInfo("other.ts", "other content", rejected = false, changeApplied = false) + ) + } + } + @Test(expected = FeatureDevException::class) fun `test code generation failed`() = runTest {