use super::{AutomationExit, AutomationInterrupted, TerminalReason};
pub(super) struct TerminalMessages {
authentication: String,
}
impl TerminalMessages {
pub(super) fn for_selection(provider: &str, auth: &str) -> Self {
let alternatives = rho_providers::provider::provider_descriptor(provider)
.into_iter()
.flat_map(|descriptor| descriptor.auth_modes())
.filter(|mode| {
mode.id != auth
&& !matches!(
mode.auth_kind,
rho_providers::provider::ProviderAuthKind::None
)
})
.map(|mode| format!("--auth {}", mode.id))
.collect::<Vec<_>>();
let mut authentication =
format!("authentication failed for {provider} (auth: {auth}); run /login {provider}");
if !alternatives.is_empty() {
authentication.push_str(" or pass ");
authentication.push_str(&alternatives.join(" or "));
}
Self { authentication }
}
pub(super) fn for_error(&self, reason: TerminalReason, error: &anyhow::Error) -> String {
match reason {
TerminalReason::Authentication => self.authentication.clone(),
TerminalReason::ProviderError
| TerminalReason::ToolHostError
| TerminalReason::ConfigurationError
| TerminalReason::OutputError
| TerminalReason::OtherError
| TerminalReason::Interrupted
| TerminalReason::MaxSteps
| TerminalReason::Timeout
| TerminalReason::Completed => error.to_string(),
}
}
}
pub(super) fn classify_error(error: &anyhow::Error) -> (TerminalReason, u8) {
if let Some(interrupted) = error.downcast_ref::<AutomationInterrupted>() {
return (TerminalReason::Interrupted, interrupted.exit_code());
}
if let Some(exit) = error.downcast_ref::<AutomationExit>() {
return (exit.reason(), exit.exit_code());
}
for cause in error.chain() {
if let Some(error) = cause.downcast_ref::<rho_sdk::Error>() {
return match error {
rho_sdk::Error::Authentication { .. } => (TerminalReason::Authentication, 1),
rho_sdk::Error::Provider(provider)
if provider.kind() == rho_sdk::ProviderErrorKind::Authentication =>
{
(TerminalReason::Authentication, 1)
}
rho_sdk::Error::Provider(_) => (TerminalReason::ProviderError, 1),
rho_sdk::Error::Tool(_) => (TerminalReason::ToolHostError, 1),
rho_sdk::Error::InvalidConfiguration { .. } => {
(TerminalReason::ConfigurationError, 2)
}
_ => (TerminalReason::OtherError, 1),
};
}
if let Some(error) = cause.downcast_ref::<rho_providers::model::ModelError>() {
use rho_providers::model::ModelError;
return match error {
ModelError::MissingCredentials(_) | ModelError::Credentials(_) => {
(TerminalReason::Authentication, 1)
}
ModelError::UnsupportedReasoning { .. } | ModelError::UnsupportedProvider(_) => {
(TerminalReason::ConfigurationError, 2)
}
_ => (TerminalReason::ProviderError, 1),
};
}
}
(TerminalReason::OtherError, 1)
}