1use std::collections::BTreeMap;
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8use thiserror::Error;
9
10use crate::json_payload::JsonPayload;
11use crate::providers::ProviderKind;
12
13pub type Result<T, E = Error> = std::result::Result<T, E>;
15
16#[derive(Debug, Error)]
18pub enum Error {
19 #[error("客户端配置无效: {0}")]
21 InvalidConfig(String),
22 #[error("请求缺少必填字段: {field}")]
24 MissingRequiredField {
25 field: &'static str,
27 },
28 #[error("缺少 API 凭证")]
30 MissingCredentials,
31 #[error(transparent)]
33 Api(#[from] ApiError),
34 #[error(transparent)]
36 Connection(#[from] ConnectionError),
37 #[error("请求超时")]
39 Timeout,
40 #[error(transparent)]
42 Stream(#[from] StreamError),
43 #[error(transparent)]
45 WebSocket(#[from] WebSocketError),
46 #[error(transparent)]
48 Serialization(#[from] SerializationError),
49 #[error(transparent)]
51 LengthFinishReason(#[from] LengthFinishReasonError),
52 #[error(transparent)]
54 ContentFilterFinishReason(#[from] ContentFilterFinishReasonError),
55 #[error(transparent)]
57 WebhookVerification(#[from] WebhookVerificationError),
58 #[error(transparent)]
60 ProviderCompatibility(#[from] ProviderCompatibilityError),
61 #[error("请求已取消")]
63 Cancelled,
64}
65
66#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
68#[serde(rename_all = "snake_case")]
69pub enum ApiErrorKind {
70 BadRequest,
72 Authentication,
74 PermissionDenied,
76 NotFound,
78 Conflict,
80 UnprocessableEntity,
82 RateLimit,
84 InternalServer,
86 Unknown,
88}
89
90impl ApiErrorKind {
91 pub fn from_status(status: u16) -> Self {
93 match status {
94 400 => Self::BadRequest,
95 401 => Self::Authentication,
96 403 => Self::PermissionDenied,
97 404 => Self::NotFound,
98 409 => Self::Conflict,
99 422 => Self::UnprocessableEntity,
100 429 => Self::RateLimit,
101 500..=599 => Self::InternalServer,
102 _ => Self::Unknown,
103 }
104 }
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct ApiError {
110 pub status: u16,
112 pub kind: ApiErrorKind,
114 pub message: String,
116 pub request_id: Option<String>,
118 pub provider: ProviderKind,
120 pub raw: Option<JsonPayload>,
122}
123
124impl ApiError {
125 pub fn new(
127 status: u16,
128 message: impl Into<String>,
129 request_id: Option<String>,
130 provider: ProviderKind,
131 raw: Option<JsonPayload>,
132 ) -> Self {
133 Self {
134 status,
135 kind: ApiErrorKind::from_status(status),
136 message: message.into(),
137 request_id,
138 provider,
139 raw,
140 }
141 }
142}
143
144impl fmt::Display for ApiError {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 write!(f, "{} (status {})", self.message, self.status)
147 }
148}
149
150impl std::error::Error for ApiError {}
151
152#[derive(Debug, Error, Clone)]
154#[error("{message}")]
155pub struct ConnectionError {
156 pub message: String,
158}
159
160impl ConnectionError {
161 pub fn new(message: impl Into<String>) -> Self {
163 Self {
164 message: message.into(),
165 }
166 }
167}
168
169#[derive(Debug, Error, Clone)]
171#[error("{message}")]
172pub struct SerializationError {
173 pub message: String,
175}
176
177impl SerializationError {
178 pub fn new(message: impl Into<String>) -> Self {
180 Self {
181 message: message.into(),
182 }
183 }
184}
185
186#[derive(Debug, Error, Clone)]
188#[error("{message}")]
189pub struct StreamError {
190 pub message: String,
192}
193
194#[derive(Debug, Error, Clone)]
196#[error("无法继续解析响应内容: 模型因长度上限提前结束")]
197pub struct LengthFinishReasonError;
198
199#[derive(Debug, Error, Clone)]
201#[error("无法继续解析响应内容: 请求被内容过滤器拦截")]
202pub struct ContentFilterFinishReasonError;
203
204impl StreamError {
205 pub fn new(message: impl Into<String>) -> Self {
207 Self {
208 message: message.into(),
209 }
210 }
211}
212
213#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
215#[serde(rename_all = "snake_case")]
216pub enum WebSocketErrorKind {
217 Transport,
219 Protocol,
221 Server,
223}
224
225#[derive(Debug, Error, Clone)]
227#[error("{message}")]
228pub struct WebSocketError {
229 pub kind: WebSocketErrorKind,
231 pub message: String,
233 pub event_type: Option<String>,
235}
236
237impl WebSocketError {
238 pub fn new(message: impl Into<String>) -> Self {
240 Self {
241 kind: WebSocketErrorKind::Protocol,
242 message: message.into(),
243 event_type: None,
244 }
245 }
246
247 pub fn transport(message: impl Into<String>) -> Self {
249 Self {
250 kind: WebSocketErrorKind::Transport,
251 message: message.into(),
252 event_type: None,
253 }
254 }
255
256 pub fn protocol(message: impl Into<String>) -> Self {
258 Self {
259 kind: WebSocketErrorKind::Protocol,
260 message: message.into(),
261 event_type: None,
262 }
263 }
264
265 pub fn server(message: impl Into<String>, event_type: Option<String>) -> Self {
267 Self {
268 kind: WebSocketErrorKind::Server,
269 message: message.into(),
270 event_type,
271 }
272 }
273}
274
275#[derive(Debug, Error, Clone)]
277#[error("{message}")]
278pub struct WebhookVerificationError {
279 pub message: String,
281}
282
283impl WebhookVerificationError {
284 pub fn new(message: impl Into<String>) -> Self {
286 Self {
287 message: message.into(),
288 }
289 }
290}
291
292#[derive(Debug, Error, Clone)]
294#[error("{message}")]
295pub struct ProviderCompatibilityError {
296 pub message: String,
298 pub provider: ProviderKind,
300}
301
302impl ProviderCompatibilityError {
303 pub fn new(provider: ProviderKind, message: impl Into<String>) -> Self {
305 Self {
306 message: message.into(),
307 provider,
308 }
309 }
310}
311
312#[derive(Debug, Clone, Serialize, Deserialize, Default)]
314pub struct ErrorBody {
315 pub message: Option<String>,
317 #[serde(rename = "type")]
319 pub error_type: Option<String>,
320 pub param: Option<String>,
322 pub code: Option<JsonPayload>,
324 #[serde(flatten)]
326 pub extra: BTreeMap<String, Value>,
327}