devin15/cursor2api-rust
0
1use super::aiserver::v1::error_details::Error as ErrorType;2use reqwest::StatusCode;3use serde::{Deserialize, Serialize};4 5#[derive(Deserialize)]6pub struct ChatError {7 error: ErrorBody,8}9 10#[derive(Deserialize)]11pub struct ErrorBody {12 code: String,13 // message: String, always: Error14 details: Vec<ErrorDetail>,15}16 17#[derive(Deserialize)]18pub struct ErrorDetail {19 // #[serde(rename = "type")]20 // error_type: String, always: aiserver.v1.ErrorDetails21 debug: ErrorDebug,22 value: String,23}24 25#[derive(Deserialize)]26pub struct ErrorDebug {27 error: String,28 details: ErrorDetails,29 // #[serde(rename = "isExpected")]30 // is_expected: Option<bool>,31}32 33#[derive(Deserialize)]34pub struct ErrorDetails {35 title: String,36 detail: String,37 // #[serde(rename = "isRetryable")]38 // is_retryable: Option<bool>,39}40 41use crate::common::models::{ApiStatus, ErrorResponse as CommonErrorResponse};42 43impl ChatError {44 pub fn to_error_response(&self) -> ErrorResponse {45 if self.error.details.is_empty() {46 return ErrorResponse {47 status: 500,48 code: "unknown".to_string(),49 error: None,50 };51 }52 ErrorResponse {53 status: self.status_code(),54 code: self.error.code.clone(),55 error: Some(Error {56 message: self.error.details[0].debug.details.title.clone(),57 details: self.error.details[0].debug.details.detail.clone(),58 value: self.error.details[0].value.clone(),59 }),60 }61 }62 63 pub fn status_code(&self) -> u16 {64 match ErrorType::from_str_name(&self.error.details[0].debug.error) {65 Some(error) => match error {66 ErrorType::Unspecified => 500,67 ErrorType::BadApiKey68 | ErrorType::InvalidAuthId69 | ErrorType::AuthTokenNotFound70 | ErrorType::AuthTokenExpired71 | ErrorType::Unauthorized => 401,72 ErrorType::NotLoggedIn73 | ErrorType::NotHighEnoughPermissions74 | ErrorType::AgentRequiresLogin75 | ErrorType::ProUserOnly76 | ErrorType::TaskNoPermissions => 403,77 ErrorType::NotFound78 | ErrorType::UserNotFound79 | ErrorType::TaskUuidNotFound80 | ErrorType::AgentEngineNotFound81 | ErrorType::GitgraphNotFound82 | ErrorType::FileNotFound => 404,83 ErrorType::FreeUserRateLimitExceeded84 | ErrorType::ProUserRateLimitExceeded85 | ErrorType::OpenaiRateLimitExceeded86 | ErrorType::OpenaiAccountLimitExceeded87 | ErrorType::GenericRateLimitExceeded88 | ErrorType::Gpt4VisionPreviewRateLimit89 | ErrorType::ApiKeyRateLimit => 429,90 ErrorType::BadRequest91 | ErrorType::BadModelName92 | ErrorType::SlashEditFileTooLong93 | ErrorType::FileUnsupported94 | ErrorType::ClaudeImageTooLarge => 400,95 ErrorType::Deprecated96 | ErrorType::FreeUserUsageLimit97 | ErrorType::ProUserUsageLimit98 | ErrorType::ResourceExhausted99 | ErrorType::Openai100 | ErrorType::MaxTokens101 | ErrorType::ApiKeyNotSupported102 | ErrorType::UserAbortedRequest103 | ErrorType::CustomMessage104 | ErrorType::OutdatedClient105 | ErrorType::Debounced106 | ErrorType::RepositoryServiceRepositoryIsNotInitialized => 500,107 },108 None => 500,109 }110 }111 112 // pub fn is_expected(&self) -> bool {113 // self.error.details[0].debug.is_expected.unwrap_or_default()114 // }115}116 117#[derive(Serialize)]118pub struct ErrorResponse {119 pub status: u16,120 pub code: String,121 #[serde(skip_serializing_if = "Option::is_none")]122 pub error: Option<Error>,123}124 125#[derive(Serialize)]126pub struct Error {127 pub message: String,128 pub details: String,129 pub value: String,130}131 132impl ErrorResponse {133 // pub fn to_json(&self) -> serde_json::Value {134 // serde_json::to_value(self).unwrap()135 // }136 137 pub fn status_code(&self) -> StatusCode {138 StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)139 }140 141 pub fn native_code(&self) -> String {142 self.code.replace("_", " ")143 }144 145 pub fn to_common(self) -> CommonErrorResponse {146 CommonErrorResponse {147 status: ApiStatus::Error,148 code: Some(self.status),149 error: self.error.as_ref().map(|error| error.message.clone()).or(Some(self.code.clone())),150 message: self.error.as_ref().map(|error| error.details.clone()),151 }152 }153}154 155pub enum StreamError {156 ChatError(ChatError),157 DataLengthLessThan5,158 EmptyMessage,159}160 161impl std::fmt::Display for StreamError {162 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {163 match self {164 StreamError::ChatError(error) => write!(f, "{}", error.error.details[0].debug.details.title),165 StreamError::DataLengthLessThan5 => write!(f, "data length less than 5"),166 StreamError::EmptyMessage => write!(f, "empty message"),167 }168 }169}170 