use std::time::Duration;
use async_trait::async_trait;
use thiserror::Error;
use crate::completion::Completion;
use crate::request::ConversationRequest;
#[async_trait]
pub trait Provider: Send + Sync {
fn api_schema(&self) -> &str;
async fn complete(&self, request: &ConversationRequest) -> Result<Completion, ProviderError>;
}
#[derive(Debug, Error)]
pub enum ProviderError {
#[error("transport error: {0}")]
Transport(String),
#[error("rate limited")]
RateLimited {
retry_after: Option<Duration>,
},
#[error("api error (status {status}): {message}")]
Api {
status: u16,
message: String,
},
#[error("context window exceeded")]
ContextOverflow,
#[error("quota exceeded")]
Quota,
#[error("authentication error: {0}")]
Auth(String),
#[error("failed to decode provider response: {0}")]
Decode(String),
#[error("invalid configuration: {0}")]
Config(String),
}
impl ProviderError {
#[must_use]
pub fn retryable(&self) -> bool {
match self {
ProviderError::Transport(_) | ProviderError::RateLimited { .. } => true,
ProviderError::Api { status, .. } => {
matches!(status, 408 | 409 | 500..=599)
}
ProviderError::ContextOverflow
| ProviderError::Quota
| ProviderError::Auth(_)
| ProviderError::Decode(_)
| ProviderError::Config(_) => false,
}
}
}