Skip to main content

openai_core/
error.rs

1//! SDK 错误类型定义。
2
3use 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
13/// SDK 统一 `Result` 类型别名。
14pub type Result<T, E = Error> = std::result::Result<T, E>;
15
16/// SDK 对外暴露的统一错误类型。
17#[derive(Debug, Error)]
18pub enum Error {
19    /// 表示客户端配置无效。
20    #[error("客户端配置无效: {0}")]
21    InvalidConfig(String),
22    /// 表示请求缺少必填字段。
23    #[error("请求缺少必填字段: {field}")]
24    MissingRequiredField {
25        /// 缺失字段名。
26        field: &'static str,
27    },
28    /// 表示缺少请求所需的凭证。
29    #[error("缺少 API 凭证")]
30    MissingCredentials,
31    /// 表示接口返回了业务错误。
32    #[error(transparent)]
33    Api(#[from] ApiError),
34    /// 表示底层网络连接相关错误。
35    #[error(transparent)]
36    Connection(#[from] ConnectionError),
37    /// 表示请求执行超时。
38    #[error("请求超时")]
39    Timeout,
40    /// 表示流式解析相关错误。
41    #[error(transparent)]
42    Stream(#[from] StreamError),
43    /// 表示 WebSocket 错误。
44    #[error(transparent)]
45    WebSocket(#[from] WebSocketError),
46    /// 表示序列化或反序列化失败。
47    #[error(transparent)]
48    Serialization(#[from] SerializationError),
49    /// 表示模型因长度截断而无法完成结构化语义。
50    #[error(transparent)]
51    LengthFinishReason(#[from] LengthFinishReasonError),
52    /// 表示模型因内容过滤而无法完成结构化语义。
53    #[error(transparent)]
54    ContentFilterFinishReason(#[from] ContentFilterFinishReasonError),
55    /// 表示 Webhook 校验失败。
56    #[error(transparent)]
57    WebhookVerification(#[from] WebhookVerificationError),
58    /// 表示当前 Provider 的兼容性校验失败。
59    #[error(transparent)]
60    ProviderCompatibility(#[from] ProviderCompatibilityError),
61    /// 表示请求被主动取消。
62    #[error("请求已取消")]
63    Cancelled,
64}
65
66/// 表示 API 错误的大类。
67#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
68#[serde(rename_all = "snake_case")]
69pub enum ApiErrorKind {
70    /// 表示 400 类错误。
71    BadRequest,
72    /// 表示鉴权失败。
73    Authentication,
74    /// 表示权限不足。
75    PermissionDenied,
76    /// 表示资源不存在。
77    NotFound,
78    /// 表示资源冲突。
79    Conflict,
80    /// 表示请求参数语义错误。
81    UnprocessableEntity,
82    /// 表示触发限流。
83    RateLimit,
84    /// 表示服务端内部错误。
85    InternalServer,
86    /// 表示未归类的 API 错误。
87    Unknown,
88}
89
90impl ApiErrorKind {
91    /// 根据 HTTP 状态码推导错误大类。
92    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/// 表示标准化后的 API 错误对象。
108#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct ApiError {
110    /// HTTP 状态码。
111    pub status: u16,
112    /// 错误大类。
113    pub kind: ApiErrorKind,
114    /// 主要错误消息。
115    pub message: String,
116    /// 请求 ID。
117    pub request_id: Option<String>,
118    /// 当前 Provider。
119    pub provider: ProviderKind,
120    /// 原始错误载荷。
121    pub raw: Option<JsonPayload>,
122}
123
124impl ApiError {
125    /// 创建一个新的 API 错误。
126    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/// 表示底层连接或 DNS/TLS 等错误。
153#[derive(Debug, Error, Clone)]
154#[error("{message}")]
155pub struct ConnectionError {
156    /// 错误消息。
157    pub message: String,
158}
159
160impl ConnectionError {
161    /// 创建新的连接错误。
162    pub fn new(message: impl Into<String>) -> Self {
163        Self {
164            message: message.into(),
165        }
166    }
167}
168
169/// 表示序列化或反序列化错误。
170#[derive(Debug, Error, Clone)]
171#[error("{message}")]
172pub struct SerializationError {
173    /// 错误消息。
174    pub message: String,
175}
176
177impl SerializationError {
178    /// 创建新的序列化错误。
179    pub fn new(message: impl Into<String>) -> Self {
180        Self {
181            message: message.into(),
182        }
183    }
184}
185
186/// 表示 SSE 或增量聚合相关错误。
187#[derive(Debug, Error, Clone)]
188#[error("{message}")]
189pub struct StreamError {
190    /// 错误消息。
191    pub message: String,
192}
193
194/// 表示模型因为达到长度上限而提前终止。
195#[derive(Debug, Error, Clone)]
196#[error("无法继续解析响应内容: 模型因长度上限提前结束")]
197pub struct LengthFinishReasonError;
198
199/// 表示模型输出被内容过滤器拦截。
200#[derive(Debug, Error, Clone)]
201#[error("无法继续解析响应内容: 请求被内容过滤器拦截")]
202pub struct ContentFilterFinishReasonError;
203
204impl StreamError {
205    /// 创建新的流式错误。
206    pub fn new(message: impl Into<String>) -> Self {
207        Self {
208            message: message.into(),
209        }
210    }
211}
212
213/// 表示 WebSocket 连接或协议错误。
214#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
215#[serde(rename_all = "snake_case")]
216pub enum WebSocketErrorKind {
217    /// 传输层错误,例如底层连接或 IO 问题。
218    Transport,
219    /// 协议层错误,例如事件反序列化失败。
220    Protocol,
221    /// 服务端主动推送的错误事件。
222    Server,
223}
224
225/// 表示 WebSocket 连接或协议错误。
226#[derive(Debug, Error, Clone)]
227#[error("{message}")]
228pub struct WebSocketError {
229    /// 错误分类。
230    pub kind: WebSocketErrorKind,
231    /// 错误消息。
232    pub message: String,
233    /// 关联的服务端事件类型。
234    pub event_type: Option<String>,
235}
236
237impl WebSocketError {
238    /// 创建新的 WebSocket 错误。
239    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    /// 创建新的传输层 WebSocket 错误。
248    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    /// 创建新的协议层 WebSocket 错误。
257    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    /// 创建新的服务端 WebSocket 错误。
266    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/// 表示 Webhook 校验错误。
276#[derive(Debug, Error, Clone)]
277#[error("{message}")]
278pub struct WebhookVerificationError {
279    /// 错误消息。
280    pub message: String,
281}
282
283impl WebhookVerificationError {
284    /// 创建新的 Webhook 校验错误。
285    pub fn new(message: impl Into<String>) -> Self {
286        Self {
287            message: message.into(),
288        }
289    }
290}
291
292/// 表示 Provider 兼容性错误。
293#[derive(Debug, Error, Clone)]
294#[error("{message}")]
295pub struct ProviderCompatibilityError {
296    /// 错误消息。
297    pub message: String,
298    /// 触发错误的 Provider。
299    pub provider: ProviderKind,
300}
301
302impl ProviderCompatibilityError {
303    /// 创建新的 Provider 兼容性错误。
304    pub fn new(provider: ProviderKind, message: impl Into<String>) -> Self {
305        Self {
306            message: message.into(),
307            provider,
308        }
309    }
310}
311
312/// 表示通用的 API 错误载荷结构。
313#[derive(Debug, Clone, Serialize, Deserialize, Default)]
314pub struct ErrorBody {
315    /// 错误消息。
316    pub message: Option<String>,
317    /// 错误类型。
318    #[serde(rename = "type")]
319    pub error_type: Option<String>,
320    /// 错误参数。
321    pub param: Option<String>,
322    /// 错误码。
323    pub code: Option<JsonPayload>,
324    /// 额外字段。
325    #[serde(flatten)]
326    pub extra: BTreeMap<String, Value>,
327}