bedrock: Fix UX bug (#28350)

Closes #29072, #28390, 

Release Notes:

- AWS Bedrock: Fixed case where user couldn't delete manually added AWS
credentials.

---------

Co-authored-by: Marshall Bowers <git@maxdeviant.com>
Co-authored-by: Peter Tripp <peter@zed.dev>
This commit is contained in:
Shardul Vaidya 2025-05-08 18:09:18 -04:00 committed by GitHub
parent a8312d623d
commit 648d0054de
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -76,8 +76,6 @@ pub struct AmazonBedrockSettings {
pub enum BedrockAuthMethod { pub enum BedrockAuthMethod {
#[serde(rename = "named_profile")] #[serde(rename = "named_profile")]
NamedProfile, NamedProfile,
#[serde(rename = "static_credentials")]
StaticCredentials,
#[serde(rename = "sso")] #[serde(rename = "sso")]
SingleSignOn, SingleSignOn,
/// IMDSv2, PodIdentity, env vars, etc. /// IMDSv2, PodIdentity, env vars, etc.
@ -186,47 +184,18 @@ impl State {
}) })
} }
fn is_authenticated(&self) -> Option<String> { fn is_authenticated(&self) -> bool {
match self let derived = self
.settings .settings
.as_ref() .as_ref()
.and_then(|s| s.authentication_method.as_ref()) .and_then(|s| s.authentication_method.as_ref());
{ let creds = self.credentials.as_ref();
Some(BedrockAuthMethod::StaticCredentials) => Some(String::from(
"You are authenticated using Static Credentials.", derived.is_some() || creds.is_some()
)),
Some(BedrockAuthMethod::NamedProfile) | Some(BedrockAuthMethod::SingleSignOn) => {
match self.settings.as_ref() {
None => Some(String::from(
"You are authenticated using a Named Profile, but no profile is set.",
)),
Some(settings) => match settings.clone().profile_name {
None => Some(String::from(
"You are authenticated using a Named Profile, but no profile is set.",
)),
Some(profile_name) => Some(format!(
"You are authenticated using a Named Profile: {profile_name}",
)),
},
}
}
Some(BedrockAuthMethod::Automatic) => Some(String::from(
"You are authenticated using Automatic Credentials.",
)),
None => {
if self.credentials.is_some() {
Some(String::from(
"You are authenticated using Static Credentials.",
))
} else {
None
}
}
}
} }
fn authenticate(&self, cx: &mut Context<Self>) -> Task<Result<(), AuthenticateError>> { fn authenticate(&self, cx: &mut Context<Self>) -> Task<Result<(), AuthenticateError>> {
if self.is_authenticated().is_some() { if self.is_authenticated() {
return Task::ready(Ok(())); return Task::ready(Ok(()));
} }
@ -328,6 +297,7 @@ impl LanguageModelProvider for BedrockLanguageModelProvider {
for model in bedrock::Model::iter() { for model in bedrock::Model::iter() {
if !matches!(model, bedrock::Model::Custom { .. }) { if !matches!(model, bedrock::Model::Custom { .. }) {
// TODO: Sonnet 3.7 vs. 3.7 Thinking bug is here.
models.insert(model.id().to_string(), model); models.insert(model.id().to_string(), model);
} }
} }
@ -357,7 +327,7 @@ impl LanguageModelProvider for BedrockLanguageModelProvider {
} }
fn is_authenticated(&self, cx: &App) -> bool { fn is_authenticated(&self, cx: &App) -> bool {
self.state.read(cx).is_authenticated().is_some() self.state.read(cx).is_authenticated()
} }
fn authenticate(&self, cx: &mut App) -> Task<Result<(), AuthenticateError>> { fn authenticate(&self, cx: &mut App) -> Task<Result<(), AuthenticateError>> {
@ -402,8 +372,7 @@ impl BedrockModel {
let auth_method = state let auth_method = state
.settings .settings
.as_ref() .as_ref()
.and_then(|s| s.authentication_method.clone()) .and_then(|s| s.authentication_method.clone());
.unwrap_or(BedrockAuthMethod::Automatic);
let endpoint = state.settings.as_ref().and_then(|s| s.endpoint.clone()); let endpoint = state.settings.as_ref().and_then(|s| s.endpoint.clone());
@ -438,7 +407,7 @@ impl BedrockModel {
} }
match auth_method { match auth_method {
BedrockAuthMethod::StaticCredentials => { None => {
if let Some(creds) = credentials { if let Some(creds) = credentials {
let aws_creds = Credentials::new( let aws_creds = Credentials::new(
creds.access_key_id, creds.access_key_id,
@ -450,7 +419,8 @@ impl BedrockModel {
config_builder = config_builder.credentials_provider(aws_creds); config_builder = config_builder.credentials_provider(aws_creds);
} }
} }
BedrockAuthMethod::NamedProfile | BedrockAuthMethod::SingleSignOn => { Some(BedrockAuthMethod::NamedProfile)
| Some(BedrockAuthMethod::SingleSignOn) => {
// Currently NamedProfile and SSO behave the same way but only the instructions change // Currently NamedProfile and SSO behave the same way but only the instructions change
// Until we support BearerAuth through SSO, this will not change. // Until we support BearerAuth through SSO, this will not change.
let profile_name = settings let profile_name = settings
@ -461,7 +431,7 @@ impl BedrockModel {
config_builder = config_builder.profile_name(profile_name); config_builder = config_builder.profile_name(profile_name);
} }
} }
BedrockAuthMethod::Automatic => { Some(BedrockAuthMethod::Automatic) => {
// Use default credential provider chain // Use default credential provider chain
} }
} }
@ -1211,7 +1181,7 @@ impl ConfigurationView {
.rounded_sm() .rounded_sm()
} }
fn should_render_editor(&self, cx: &mut Context<Self>) -> Option<String> { fn should_render_editor(&self, cx: &Context<Self>) -> bool {
self.state.read(cx).is_authenticated() self.state.read(cx).is_authenticated()
} }
} }
@ -1219,13 +1189,16 @@ impl ConfigurationView {
impl Render for ConfigurationView { impl Render for ConfigurationView {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement { fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let env_var_set = self.state.read(cx).credentials_from_env; let env_var_set = self.state.read(cx).credentials_from_env;
let creds_type = self.should_render_editor(cx).is_some(); let bedrock_settings = self.state.read(cx).settings.as_ref();
let bedrock_method = bedrock_settings
.as_ref()
.and_then(|s| s.authentication_method.clone());
if self.load_credentials_task.is_some() { if self.load_credentials_task.is_some() {
return div().child(Label::new("Loading credentials...")).into_any(); return div().child(Label::new("Loading credentials...")).into_any();
} }
if let Some(auth) = self.should_render_editor(cx) { if self.should_render_editor(cx) {
return h_flex() return h_flex()
.mt_1() .mt_1()
.p_1() .p_1()
@ -1241,7 +1214,14 @@ impl Render for ConfigurationView {
.child(Label::new(if env_var_set { .child(Label::new(if env_var_set {
format!("Access Key ID is set in {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, Secret Key is set in {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR}, Region is set in {ZED_BEDROCK_REGION_VAR} environment variables.") format!("Access Key ID is set in {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, Secret Key is set in {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR}, Region is set in {ZED_BEDROCK_REGION_VAR} environment variables.")
} else { } else {
auth.clone() match bedrock_method {
Some(BedrockAuthMethod::Automatic) => "You are using automatic credentials".into(),
Some(BedrockAuthMethod::NamedProfile) => {
"You are using named profile".into()
},
Some(BedrockAuthMethod::SingleSignOn) => "You are using a single sign on profile".into(),
None => "You are using static credentials".into(),
}
})), })),
) )
.child( .child(
@ -1249,12 +1229,12 @@ impl Render for ConfigurationView {
.icon(Some(IconName::Trash)) .icon(Some(IconName::Trash))
.icon_size(IconSize::Small) .icon_size(IconSize::Small)
.icon_position(IconPosition::Start) .icon_position(IconPosition::Start)
// .disabled(env_var_set || creds_type) .disabled(env_var_set || bedrock_method.is_some())
.when(env_var_set, |this| { .when(env_var_set, |this| {
this.tooltip(Tooltip::text(format!("To reset your credentials, unset the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR}, and {ZED_BEDROCK_REGION_VAR} environment variables."))) this.tooltip(Tooltip::text(format!("To reset your credentials, unset the {ZED_BEDROCK_ACCESS_KEY_ID_VAR}, {ZED_BEDROCK_SECRET_ACCESS_KEY_VAR}, and {ZED_BEDROCK_REGION_VAR} environment variables.")))
}) })
.when(creds_type, |this| { .when(bedrock_method.is_some(), |this| {
this.tooltip(Tooltip::text("You cannot reset credentials as they're being derived, check Zed settings to understand how.")) this.tooltip(Tooltip::text("You cannot reset credentials as they're being derived, check Zed settings to understand how"))
}) })
.on_click(cx.listener(|this, _, window, cx| this.reset_credentials(window, cx))), .on_click(cx.listener(|this, _, window, cx| this.reset_credentials(window, cx))),
) )