Skip to content

Commit c38a634

Browse files
committed
feat(amazon-bedrock): add support for default credentials provider and profile configuration
Closes #368
1 parent 942d70b commit c38a634

File tree

7 files changed

+94
-20
lines changed

7 files changed

+94
-20
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## [Unreleased]
44

5+
### Added
6+
7+
- Support AWS SDK default credential locations for Bedrock Integration (#368).
8+
59
## [2.15.0] - 2025-08-30
610

711
### Changed

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/AppSettings2.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ class AppSettings2 : PersistentStateComponent<AppSettings2> {
9393

9494
override fun loadState(state: AppSettings2) {
9595
XmlSerializerUtil.copyBean(state, this)
96+
llmClientConfigurations.forEach { it.afterSerialization() }
9697
}
9798

9899
override fun noStateLoaded() {

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/LLMClientConfiguration.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ abstract class LLMClientConfiguration(
100100
return ActionUpdateThread.EDT
101101
}
102102

103+
open fun afterSerialization() {
104+
// Allow overriding
105+
}
106+
103107
// override fun equals(other: Any?): Boolean {
104108
// return other is LLMClientConfiguration && other.id == id
105109
// }

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/amazonBedrock/AmazonBedrockClientConfiguration.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@ class AmazonBedrockClientConfiguration : LLMClientConfiguration(
1919
"0.7"
2020
) {
2121

22+
@Attribute
23+
var useStaticCredentialsProvider: Boolean? = null
2224
@Attribute
2325
var accessKeyId: String? = null
2426
@Attribute
2527
var accessKeyIsStored: Boolean = false
2628
@Transient
2729
var accessKey: String? = null
2830
@Attribute
31+
var profileName: String? = null
32+
@Attribute
2933
var timeout: Int = 30
3034
@Attribute
3135
var topP: Double? = null
@@ -66,9 +70,11 @@ class AmazonBedrockClientConfiguration : LLMClientConfiguration(
6670
copy.name = name
6771
copy.modelId = modelId
6872
copy.temperature = temperature
73+
copy.useStaticCredentialsProvider = useStaticCredentialsProvider
6974
copy.accessKeyId = accessKeyId
7075
copy.accessKeyIsStored = accessKeyIsStored
7176
copy.accessKey = accessKey
77+
copy.profileName = profileName
7278
copy.timeout = timeout
7379
copy.topP = topP
7480
copy.topK = topK
@@ -80,6 +86,14 @@ class AmazonBedrockClientConfiguration : LLMClientConfiguration(
8086

8187
override fun panel() = AmazonBedrockClientPanel(this)
8288

89+
override fun afterSerialization() {
90+
// All new configurations should have this property set upon creation
91+
if (useStaticCredentialsProvider == null) {
92+
// Old version supported only static provider
93+
useStaticCredentialsProvider = true
94+
}
95+
}
96+
8397
class RegionConverter : Converter<Region>() {
8498
override fun toString(value: Region): String? {
8599
return value.toString()

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/amazonBedrock/AmazonBedrockClientPanel.kt

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
package com.github.blarc.ai.commits.intellij.plugin.settings.clients.amazonBedrock;
1+
package com.github.blarc.ai.commits.intellij.plugin.settings.clients.amazonBedrock
22

33
import com.github.blarc.ai.commits.intellij.plugin.AICommitsBundle.message
44
import com.github.blarc.ai.commits.intellij.plugin.emptyText
55
import com.github.blarc.ai.commits.intellij.plugin.isInt
66
import com.github.blarc.ai.commits.intellij.plugin.settings.clients.LLMClientPanel
77
import com.intellij.openapi.ui.ComboBox
88
import com.intellij.ui.components.JBPasswordField
9+
import com.intellij.ui.components.JBRadioButton
910
import com.intellij.ui.components.JBTextField
1011
import com.intellij.ui.dsl.builder.*
1112
import software.amazon.awssdk.regions.Region
@@ -17,6 +18,9 @@ class AmazonBedrockClientPanel private constructor(
1718

1819
private val accessKeyIdField = JBTextField()
1920
private val accessKeyPasswordField = JBPasswordField()
21+
private val profileNameField = JBTextField()
22+
private lateinit var useDefaultCredentialsProviderRadioButton: Cell<JBRadioButton>
23+
private lateinit var useStaticCredentialsProviderRadioButton: Cell<JBRadioButton>
2024
private val regionComboBox = ComboBox(Region.regions().toTypedArray())
2125
private val maxOutputTokensTextField = JBTextField()
2226
private val topPTextField = JBTextField()
@@ -29,6 +33,8 @@ class AmazonBedrockClientPanel private constructor(
2933
modelIdRow(commentKey = "settings.amazonBedrock.modelId.comment")
3034
temperatureRow()
3135
timeoutRow(clientConfiguration::timeout)
36+
credentialsProviderRow()
37+
profileNameRow()
3238
accessKeyIdRow()
3339
accessKeyRow()
3440
regionRow()
@@ -38,6 +44,34 @@ class AmazonBedrockClientPanel private constructor(
3844
verifyRow()
3945
}
4046

47+
private fun Panel.credentialsProviderRow() {
48+
buttonsGroup {
49+
row {
50+
label(message("settings.amazonBedrock.credentialsProvider"))
51+
.widthGroup("label")
52+
useDefaultCredentialsProviderRadioButton = radioButton(message("settings.amazonBedrock.defaultCredentialsProvider"))
53+
.bindSelected({ !(clientConfiguration.useStaticCredentialsProvider ?: false) }, { clientConfiguration.useStaticCredentialsProvider = !it })
54+
.align(Align.FILL)
55+
useStaticCredentialsProviderRadioButton = radioButton(message("settings.amazonBedrock.staticCredentialsProvider"))
56+
.bindSelected(clientConfiguration::useStaticCredentialsProvider.toNonNullableProperty(true))
57+
.align(Align.FILL)
58+
contextHelp(message("settings.amazonBedrock.defaultCredentialsProvider.comment"))
59+
.align(AlignX.RIGHT)
60+
}
61+
}
62+
}
63+
64+
private fun Panel.profileNameRow() {
65+
row {
66+
label(message("settings.amazonBedrock.profileName"))
67+
.widthGroup("label")
68+
cell(profileNameField)
69+
.bindText(clientConfiguration::profileName.toNonNullableProperty(""))
70+
.resizableColumn()
71+
.align(Align.FILL)
72+
}.visibleIf(useDefaultCredentialsProviderRadioButton.selected)
73+
}
74+
4175
private fun Panel.accessKeyIdRow() {
4276
row {
4377
label(message("settings.amazonBedrock.accessKeyId"))
@@ -47,7 +81,7 @@ class AmazonBedrockClientPanel private constructor(
4781
.emptyText(message("settings.amazonBedrock.accessKeyId.example"))
4882
.resizableColumn()
4983
.align(Align.FILL)
50-
}
84+
}.visibleIf(useStaticCredentialsProviderRadioButton.selected)
5185
}
5286

5387
private fun Panel.accessKeyRow() {
@@ -63,7 +97,7 @@ class AmazonBedrockClientPanel private constructor(
6397
.align(Align.FILL)
6498
// maxLineLength was eye-balled, but prevents the dialog getting wider
6599
.comment(message("settings.amazonBedrock.accessKey.comment"), 50)
66-
}
100+
}.visibleIf(useStaticCredentialsProviderRadioButton.selected)
67101
}
68102

69103
private fun Panel.regionRow() {
@@ -96,6 +130,8 @@ class AmazonBedrockClientPanel private constructor(
96130
// Configuration passed to panel is already a copy of the original or a new configuration
97131
clientConfiguration.modelId = modelComboBox.item
98132
clientConfiguration.temperature = temperatureTextField.text
133+
clientConfiguration.useStaticCredentialsProvider = useStaticCredentialsProviderRadioButton.component.isSelected
134+
clientConfiguration.profileName = profileNameField.text
99135
clientConfiguration.accessKeyId = accessKeyIdField.text
100136
clientConfiguration.accessKey = String(accessKeyPasswordField.password)
101137
clientConfiguration.timeout = socketTimeoutTextField.text.toInt()

src/main/kotlin/com/github/blarc/ai/commits/intellij/plugin/settings/clients/amazonBedrock/AmazonBedrockClientService.kt

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ import kotlinx.coroutines.CoroutineScope
1818
import kotlinx.coroutines.Dispatchers
1919
import kotlinx.coroutines.launch
2020
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials
21+
import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider
22+
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider
2123
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider
2224
import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeAsyncClient
2325
import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient
@@ -32,19 +34,16 @@ class AmazonBedrockClientService(private val cs: CoroutineScope) : LLMClientServ
3234
}
3335

3436
override suspend fun buildChatModel(client: AmazonBedrockClientConfiguration): ChatModel {
35-
val accessKey = client.accessKeyId.nullize(true) ?: retrieveToken(client.id)?.toString(true)
36-
val credentials = AwsBasicCredentials.builder()
37-
.accessKeyId(client.accessKeyId)
38-
.secretAccessKey(accessKey)
39-
.build()
40-
4137
return BedrockChatModel.builder()
4238
.modelId(client.modelId)
4339
.region(client.region)
4440
.timeout(Duration.ofSeconds(client.timeout.toLong()))
45-
.client(BedrockRuntimeClient.builder()
46-
.region(client.region)
47-
.credentialsProvider(StaticCredentialsProvider.create(credentials)).build())
41+
.client(
42+
BedrockRuntimeClient.builder()
43+
.region(client.region)
44+
.credentialsProvider(getCredentialProvider(client))
45+
.build()
46+
)
4847
.defaultRequestParameters(
4948
BedrockChatRequestParameters.builder()
5049
.topP(client.topP)
@@ -57,20 +56,16 @@ class AmazonBedrockClientService(private val cs: CoroutineScope) : LLMClientServ
5756
}
5857

5958
override suspend fun buildStreamingChatModel(client: AmazonBedrockClientConfiguration): StreamingChatModel? {
60-
val accessKey = client.accessKeyId.nullize(true) ?: retrieveToken(client.id)?.toString(true)
61-
val credentials = AwsBasicCredentials.builder()
62-
.accessKeyId(client.accessKeyId)
63-
.secretAccessKey(accessKey)
64-
.build()
65-
6659
return BedrockStreamingChatModel.builder()
6760
.modelId(client.modelId)
6861
.region(client.region)
6962
.timeout(Duration.ofSeconds(client.timeout.toLong()))
7063
.client(
7164
BedrockRuntimeAsyncClient.builder()
72-
.region(client.region)
73-
.credentialsProvider(StaticCredentialsProvider.create(credentials)).build())
65+
.region(client.region)
66+
.credentialsProvider(getCredentialProvider(client))
67+
.build()
68+
)
7469
.defaultRequestParameters(
7570
BedrockChatRequestParameters.builder()
7671
.topP(client.topP)
@@ -82,6 +77,21 @@ class AmazonBedrockClientService(private val cs: CoroutineScope) : LLMClientServ
8277
.build()
8378
}
8479

80+
suspend fun getCredentialProvider(client: AmazonBedrockClientConfiguration): AwsCredentialsProvider {
81+
if (client.useStaticCredentialsProvider == true) {
82+
val accessKey = client.accessKeyId.nullize(true) ?: retrieveToken(client.id)?.toString(true)
83+
return StaticCredentialsProvider.create(
84+
AwsBasicCredentials.builder()
85+
.accessKeyId(client.accessKeyId)
86+
.secretAccessKey(accessKey)
87+
.build()
88+
)
89+
}
90+
return DefaultCredentialsProvider.builder()
91+
.profileName(client.profileName)
92+
.build()
93+
}
94+
8595
fun saveToken(client: AmazonBedrockClientConfiguration, token: String) {
8696
cs.launch(Dispatchers.Default) {
8797
try {

src/main/resources/messages/AiCommitsBundle.properties

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,8 @@ settings.amazonBedrock.accessKeyId=Access key ID
156156
settings.amazonBedrock.maxOutputTokens=Max output tokens
157157
settings.amazonBedrock.region=Region
158158
settings.amazonBedrock.modelId.comment=Models IDs can be found <a href="https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html">here</a>.
159+
settings.amazonBedrock.credentialsProvider=Credentials provider:
160+
settings.amazonBedrock.defaultCredentialsProvider=Default
161+
settings.amazonBedrock.staticCredentialsProvider=Static
162+
settings.amazonBedrock.profileName=Profile name
163+
settings.amazonBedrock.defaultCredentialsProvider.comment=Use Default for discovering credentials from the host's environment and Static for a fixed set of credentials.

0 commit comments

Comments
 (0)