acp: Detect gemini auth errors and show a button (#36641)
Closes #ISSUE Release Notes: - N/A
This commit is contained in:
parent
bb32d4567a
commit
7f95310020
1 changed files with 60 additions and 3 deletions
|
@ -76,11 +76,12 @@ enum ThreadError {
|
||||||
PaymentRequired,
|
PaymentRequired,
|
||||||
ModelRequestLimitReached(cloud_llm_client::Plan),
|
ModelRequestLimitReached(cloud_llm_client::Plan),
|
||||||
ToolUseLimitReached,
|
ToolUseLimitReached,
|
||||||
|
AuthenticationRequired(SharedString),
|
||||||
Other(SharedString),
|
Other(SharedString),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ThreadError {
|
impl ThreadError {
|
||||||
fn from_err(error: anyhow::Error) -> Self {
|
fn from_err(error: anyhow::Error, agent: &Rc<dyn AgentServer>) -> Self {
|
||||||
if error.is::<language_model::PaymentRequiredError>() {
|
if error.is::<language_model::PaymentRequiredError>() {
|
||||||
Self::PaymentRequired
|
Self::PaymentRequired
|
||||||
} else if error.is::<language_model::ToolUseLimitReachedError>() {
|
} else if error.is::<language_model::ToolUseLimitReachedError>() {
|
||||||
|
@ -90,7 +91,17 @@ impl ThreadError {
|
||||||
{
|
{
|
||||||
Self::ModelRequestLimitReached(error.plan)
|
Self::ModelRequestLimitReached(error.plan)
|
||||||
} else {
|
} else {
|
||||||
Self::Other(error.to_string().into())
|
let string = error.to_string();
|
||||||
|
// TODO: we should have Gemini return better errors here.
|
||||||
|
if agent.clone().downcast::<agent_servers::Gemini>().is_some()
|
||||||
|
&& string.contains("Could not load the default credentials")
|
||||||
|
|| string.contains("API key not valid")
|
||||||
|
|| string.contains("Request had invalid authentication credentials")
|
||||||
|
{
|
||||||
|
Self::AuthenticationRequired(string.into())
|
||||||
|
} else {
|
||||||
|
Self::Other(error.to_string().into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -930,7 +941,7 @@ impl AcpThreadView {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_thread_error(&mut self, error: anyhow::Error, cx: &mut Context<Self>) {
|
fn handle_thread_error(&mut self, error: anyhow::Error, cx: &mut Context<Self>) {
|
||||||
self.thread_error = Some(ThreadError::from_err(error));
|
self.thread_error = Some(ThreadError::from_err(error, &self.agent));
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4310,6 +4321,9 @@ impl AcpThreadView {
|
||||||
fn render_thread_error(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Div> {
|
fn render_thread_error(&self, window: &mut Window, cx: &mut Context<Self>) -> Option<Div> {
|
||||||
let content = match self.thread_error.as_ref()? {
|
let content = match self.thread_error.as_ref()? {
|
||||||
ThreadError::Other(error) => self.render_any_thread_error(error.clone(), cx),
|
ThreadError::Other(error) => self.render_any_thread_error(error.clone(), cx),
|
||||||
|
ThreadError::AuthenticationRequired(error) => {
|
||||||
|
self.render_authentication_required_error(error.clone(), cx)
|
||||||
|
}
|
||||||
ThreadError::PaymentRequired => self.render_payment_required_error(cx),
|
ThreadError::PaymentRequired => self.render_payment_required_error(cx),
|
||||||
ThreadError::ModelRequestLimitReached(plan) => {
|
ThreadError::ModelRequestLimitReached(plan) => {
|
||||||
self.render_model_request_limit_reached_error(*plan, cx)
|
self.render_model_request_limit_reached_error(*plan, cx)
|
||||||
|
@ -4348,6 +4362,24 @@ impl AcpThreadView {
|
||||||
.dismiss_action(self.dismiss_error_button(cx))
|
.dismiss_action(self.dismiss_error_button(cx))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn render_authentication_required_error(
|
||||||
|
&self,
|
||||||
|
error: SharedString,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) -> Callout {
|
||||||
|
Callout::new()
|
||||||
|
.severity(Severity::Error)
|
||||||
|
.title("Authentication Required")
|
||||||
|
.description(error.clone())
|
||||||
|
.actions_slot(
|
||||||
|
h_flex()
|
||||||
|
.gap_0p5()
|
||||||
|
.child(self.authenticate_button(cx))
|
||||||
|
.child(self.create_copy_button(error)),
|
||||||
|
)
|
||||||
|
.dismiss_action(self.dismiss_error_button(cx))
|
||||||
|
}
|
||||||
|
|
||||||
fn render_model_request_limit_reached_error(
|
fn render_model_request_limit_reached_error(
|
||||||
&self,
|
&self,
|
||||||
plan: cloud_llm_client::Plan,
|
plan: cloud_llm_client::Plan,
|
||||||
|
@ -4469,6 +4501,31 @@ impl AcpThreadView {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn authenticate_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
|
Button::new("authenticate", "Authenticate")
|
||||||
|
.label_size(LabelSize::Small)
|
||||||
|
.style(ButtonStyle::Filled)
|
||||||
|
.on_click(cx.listener({
|
||||||
|
move |this, _, window, cx| {
|
||||||
|
let agent = this.agent.clone();
|
||||||
|
let ThreadState::Ready { thread, .. } = &this.thread_state else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let connection = thread.read(cx).connection().clone();
|
||||||
|
let err = AuthRequired {
|
||||||
|
description: None,
|
||||||
|
provider_id: None,
|
||||||
|
};
|
||||||
|
this.clear_thread_error(cx);
|
||||||
|
let this = cx.weak_entity();
|
||||||
|
window.defer(cx, |window, cx| {
|
||||||
|
Self::handle_auth_required(this, err, agent, connection, window, cx);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
fn upgrade_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
fn upgrade_button(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
Button::new("upgrade", "Upgrade")
|
Button::new("upgrade", "Upgrade")
|
||||||
.label_size(LabelSize::Small)
|
.label_size(LabelSize::Small)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue