Skip to content

Commit d9c199d

Browse files
authored
feat(amazonq): Agentic coding experience
feat(amazonq): Agentic coding experience
2 parents 36319e7 + a6d80b4 commit d9c199d

File tree

280 files changed

+7583
-13137
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

280 files changed

+7583
-13137
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "bugfix",
3+
"description" : "Support full Unicode range in inline chat panel on Windows"
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"type" : "feature",
3+
"description" : "Agentic coding experience: Amazon Q can now write code and run shell commands on your behalf"
4+
}

buildSrc/src/main/kotlin/temp-toolkit-intellij-root-conventions.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ val toolkitVersion: String by project
3535

3636
// please check changelog generation logic if this format is changed
3737
// also sync with gateway version
38-
version = "$toolkitVersion-${ideProfile.shortName}"
38+
version = "$toolkitVersion.${ideProfile.shortName}"
3939

4040
val resharperDlls = configurations.register("resharperDlls") {
4141
isCanBeConsumed = false

buildSrc/src/main/kotlin/toolkit-publishing-conventions.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ val ideProfile = IdeVersions.ideProfile(project)
1616
val toolkitVersion: String by project
1717

1818
// please check changelog generation logic if this format is changed
19-
version = "$toolkitVersion-${ideProfile.shortName}"
19+
version = "$toolkitVersion.${ideProfile.shortName}"
2020

2121
// attach the current commit hash on local builds
2222
if (!project.isCi()) {

plugins/amazonq/build.gradle.kts

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,24 @@
11
// Copyright 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
33

4-
import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType
4+
import com.fasterxml.jackson.databind.DeserializationFeature
5+
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
6+
import de.undercouch.gradle.tasks.download.Download
7+
import org.jetbrains.intellij.platform.gradle.tasks.PrepareSandboxTask
58
import software.aws.toolkits.gradle.changelog.tasks.GeneratePluginChangeLog
6-
import software.aws.toolkits.gradle.intellij.IdeFlavor
7-
import software.aws.toolkits.gradle.intellij.IdeVersions
8-
import software.aws.toolkits.gradle.intellij.toolkitIntelliJ
99

1010
plugins {
1111
id("toolkit-publishing-conventions")
1212
id("toolkit-publish-root-conventions")
1313
id("toolkit-jvm-conventions")
1414
id("toolkit-testing")
15+
id("de.undercouch.download")
16+
}
17+
18+
buildscript {
19+
dependencies {
20+
classpath(libs.bundles.jackson)
21+
}
1522
}
1623

1724
val changelog = tasks.register<GeneratePluginChangeLog>("pluginChangeLog") {
@@ -51,3 +58,81 @@ tasks.check {
5158
}
5259
}
5360
}
61+
62+
val downloadFlareManifest by tasks.registering(Download::class) {
63+
src("https://aws-toolkit-language-servers.amazonaws.com/qAgenticChatServer/0/manifest.json")
64+
dest(layout.buildDirectory.file("flare/manifest.json"))
65+
onlyIfModified(true)
66+
useETag(true)
67+
}
68+
69+
data class FlareManifest(
70+
val versions: List<FlareVersion>,
71+
)
72+
73+
data class FlareVersion(
74+
val serverVersion: String,
75+
val thirdPartyLicenses: String,
76+
val targets: List<FlareTarget>,
77+
)
78+
79+
data class FlareTarget(
80+
val platform: String,
81+
val arch: String,
82+
val contents: List<FlareContent>
83+
)
84+
85+
data class FlareContent(
86+
val url: String,
87+
)
88+
89+
val downloadFlareArtifacts by tasks.registering(Download::class) {
90+
dependsOn(downloadFlareManifest)
91+
inputs.files(downloadFlareManifest)
92+
93+
val manifestFile = downloadFlareManifest.map { it.outputFiles.first() }
94+
val manifest = manifestFile.map { jacksonObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).readValue(it.readText(), FlareManifest::class.java) }
95+
96+
// use darwin-aarch64 because its the smallest and we're going to throw away everything platform specific
97+
val latest = manifest.map { it.versions.first() }
98+
val latestVersion = latest.map { it.serverVersion }
99+
val licensesUrl = latest.map { it.thirdPartyLicenses }
100+
val darwin = latest.map { it.targets.first { target -> target.platform == "darwin" && target.arch == "arm64" } }
101+
val contentUrls = darwin.map { it.contents.map { content -> content.url } }
102+
103+
val destination = layout.buildDirectory.dir(latestVersion.map { "flare/$it" })
104+
outputs.dir(destination)
105+
106+
src(contentUrls.zip(licensesUrl) { left, right -> left + right})
107+
dest(destination)
108+
onlyIfModified(true)
109+
useETag(true)
110+
}
111+
112+
val prepareBundledFlare by tasks.registering(Copy::class) {
113+
dependsOn(downloadFlareArtifacts)
114+
inputs.files(downloadFlareArtifacts)
115+
116+
val dest = layout.buildDirectory.dir("tmp/extractFlare")
117+
into(dest)
118+
from(downloadFlareArtifacts.map { it.outputFiles.filterNot { file -> file.name.endsWith(".zip") } })
119+
120+
doLast {
121+
copy {
122+
into(dest)
123+
includeEmptyDirs = false
124+
downloadFlareArtifacts.get().outputFiles.filter { it.name.endsWith(".zip") }.forEach {
125+
dest.get().file(it.parentFile.name).asFile.createNewFile()
126+
from(zipTree(it)) {
127+
include("*.js")
128+
include("*.txt")
129+
}
130+
}
131+
}
132+
}
133+
}
134+
135+
tasks.withType<PrepareSandboxTask>().configureEach {
136+
intoChild(intellijPlatform.projectName.map { "$it/flare" })
137+
.from(prepareBundledFlare)
138+
}

plugins/amazonq/chat/jetbrains-community/resources/META-INF/plugin-chat.xml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88
<projectListeners>
99
<listener class="software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowListener"
1010
topic="com.intellij.openapi.wm.ex.ToolWindowManagerListener"/>
11-
<listener class="software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextEditorListener"
12-
topic="com.intellij.openapi.fileEditor.FileEditorManagerListener"/>
1311
</projectListeners>
1412

1513
<extensions defaultExtensionNs="com.intellij">

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QLoginWebview.kt

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ import com.intellij.ui.components.panels.Wrapper
1818
import com.intellij.ui.dsl.builder.Align
1919
import com.intellij.ui.dsl.builder.panel
2020
import com.intellij.ui.jcef.JBCefJSQuery
21+
import kotlinx.coroutines.CoroutineScope
22+
import kotlinx.coroutines.flow.distinctUntilChanged
23+
import kotlinx.coroutines.flow.launchIn
24+
import kotlinx.coroutines.flow.onEach
2125
import org.cef.CefApp
2226
import software.aws.toolkits.core.utils.debug
2327
import software.aws.toolkits.core.utils.error
@@ -40,6 +44,8 @@ import software.aws.toolkits.jetbrains.services.amazonq.profile.QProfileSwitchIn
4044
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfile
4145
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
4246
import software.aws.toolkits.jetbrains.services.amazonq.util.createBrowser
47+
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.EditorThemeAdapter
48+
import software.aws.toolkits.jetbrains.services.amazonq.webview.theme.ThemeBrowserAdapter
4349
import software.aws.toolkits.jetbrains.utils.isQConnected
4450
import software.aws.toolkits.jetbrains.utils.isQExpired
4551
import software.aws.toolkits.jetbrains.utils.isQWebviewsAvailable
@@ -54,7 +60,7 @@ import javax.swing.JButton
5460
import javax.swing.JComponent
5561

5662
@Service(Service.Level.PROJECT)
57-
class QWebviewPanel private constructor(val project: Project) : Disposable {
63+
class QWebviewPanel private constructor(val project: Project, private val scope: CoroutineScope) : Disposable {
5864
private val webviewContainer = Wrapper()
5965
var browser: QWebviewBrowser? = null
6066
private set
@@ -102,6 +108,14 @@ class QWebviewPanel private constructor(val project: Project) : Disposable {
102108
} else {
103109
browser = QWebviewBrowser(project, this).also {
104110
webviewContainer.add(it.component())
111+
112+
val themeBrowserAdapter = ThemeBrowserAdapter()
113+
EditorThemeAdapter().onThemeChange()
114+
.distinctUntilChanged()
115+
.onEach { theme ->
116+
themeBrowserAdapter.updateLoginThemeInBrowser(it.jcefBrowser.cefBrowser, theme)
117+
}
118+
.launchIn(scope)
105119
}
106120
}
107121
}

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/QRefreshPanelAction.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import com.intellij.openapi.project.DumbAwareAction
1111
import com.intellij.util.messages.Topic
1212
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindow
1313
import software.aws.toolkits.resources.AmazonQBundle
14-
import software.aws.toolkits.resources.message
1514
import java.util.EventListener
1615

1716
class QRefreshPanelAction : DumbAwareAction(AmazonQBundle.message("amazonq.refresh.panel"), null, AllIcons.Actions.Refresh) {

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/commands/MessageSerializer.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,15 @@ import com.fasterxml.jackson.databind.MapperFeature
1212
import com.fasterxml.jackson.databind.SerializationFeature
1313
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
1414
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
15+
import com.fasterxml.jackson.module.kotlin.treeToValue
1516
import org.jetbrains.annotations.VisibleForTesting
1617
import software.aws.toolkits.jetbrains.services.amazonq.messages.AmazonQMessage
1718
import software.aws.toolkits.jetbrains.services.amazonq.messages.UnknownMessageType
1819
import software.aws.toolkits.jetbrains.services.amazonq.util.command
1920

2021
class MessageSerializer @VisibleForTesting constructor() {
2122

22-
private val objectMapper = jacksonObjectMapper()
23+
val objectMapper = jacksonObjectMapper()
2324
.registerModule(JavaTimeModule())
2425
.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS)
2526
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
@@ -36,6 +37,12 @@ class MessageSerializer @VisibleForTesting constructor() {
3637

3738
fun serialize(value: Any): String = objectMapper.writeValueAsString(value)
3839

40+
inline fun <reified T> deserializeChatMessages(value: JsonNode): T =
41+
objectMapper.treeToValue<T>(value)
42+
43+
inline fun <reified T> deserializeChatMessages(value: JsonNode, clazz: Class<T>): T =
44+
objectMapper.treeToValue(value, clazz)
45+
3946
// Provide singleton global access
4047
companion object {
4148
private val instance = MessageSerializer()

plugins/amazonq/chat/jetbrains-community/src/software/aws/toolkits/jetbrains/services/amazonq/startup/AmazonQStartupActivity.kt

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,20 @@ package software.aws.toolkits.jetbrains.services.amazonq.startup
66
import com.intellij.openapi.application.ApplicationManager
77
import com.intellij.openapi.application.runInEdt
88
import com.intellij.openapi.project.Project
9-
import com.intellij.openapi.project.waitForSmartMode
109
import com.intellij.openapi.startup.ProjectActivity
1110
import com.intellij.openapi.wm.ToolWindowManager
12-
import kotlinx.coroutines.TimeoutCancellationException
13-
import kotlinx.coroutines.delay
14-
import kotlinx.coroutines.time.withTimeout
15-
import software.aws.toolkits.core.utils.getLogger
16-
import software.aws.toolkits.core.utils.warn
1711
import software.aws.toolkits.jetbrains.core.credentials.AwsBearerTokenConnection
1812
import software.aws.toolkits.jetbrains.core.credentials.ToolkitConnectionManager
1913
import software.aws.toolkits.jetbrains.core.credentials.pinning.QConnection
2014
import software.aws.toolkits.jetbrains.core.gettingstarted.emitUserState
2115
import software.aws.toolkits.jetbrains.services.amazonq.CodeWhispererFeatureConfigService
2216
import software.aws.toolkits.jetbrains.services.amazonq.lsp.AmazonQLspService
2317
import software.aws.toolkits.jetbrains.services.amazonq.profile.QRegionProfileManager
24-
import software.aws.toolkits.jetbrains.services.amazonq.project.ProjectContextController
2518
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindow
2619
import software.aws.toolkits.jetbrains.services.amazonq.toolwindow.AmazonQToolWindowFactory
2720
import software.aws.toolkits.jetbrains.services.codewhisperer.explorer.CodeWhispererExplorerActionManager
2821
import software.aws.toolkits.jetbrains.services.cwc.inline.InlineChatController
2922
import software.aws.toolkits.jetbrains.settings.CodeWhispererSettings
30-
import java.lang.management.ManagementFactory
31-
import java.time.Duration
3223
import java.util.concurrent.atomic.AtomicBoolean
3324

3425
class AmazonQStartupActivity : ProjectActivity {
@@ -58,39 +49,8 @@ class AmazonQStartupActivity : ProjectActivity {
5849
QRegionProfileManager.getInstance().validateProfile(project)
5950

6051
AmazonQLspService.getInstance(project)
61-
startLsp(project)
6252
if (runOnce.get()) return
6353
emitUserState(project)
6454
runOnce.set(true)
6555
}
66-
67-
private suspend fun startLsp(project: Project) {
68-
// Automatically start the project context LSP after some delay when average CPU load is below 30%.
69-
// The CPU load requirement is to avoid competing with native JetBrains indexing and other CPU expensive OS processes
70-
// In the future we will decouple LSP start and indexing start to let LSP perform other tasks.
71-
val startLspIndexingDuration = Duration.ofMinutes(30)
72-
project.waitForSmartMode()
73-
delay(30_000) // Wait for 30 seconds for systemLoadAverage to be more accurate
74-
try {
75-
withTimeout(startLspIndexingDuration) {
76-
while (true) {
77-
val cpuUsage = ManagementFactory.getOperatingSystemMXBean().systemLoadAverage
78-
if (cpuUsage > 0 && cpuUsage < 30) {
79-
ProjectContextController.getInstance(project = project)
80-
break
81-
} else {
82-
delay(60_000) // Wait for 60 seconds
83-
}
84-
}
85-
}
86-
} catch (e: TimeoutCancellationException) {
87-
LOG.warn { "Failed to start LSP server due to time out" }
88-
} catch (e: Exception) {
89-
LOG.warn { "Failed to start LSP server" }
90-
}
91-
}
92-
93-
companion object {
94-
private val LOG = getLogger<AmazonQStartupActivity>()
95-
}
9656
}

0 commit comments

Comments
 (0)