objectiveai_api/chat/completions/upstream/openrouter/
error.rs1use serde::{Deserialize, Serialize};
4
5#[derive(thiserror::Error, Debug)]
7pub enum Error {
8 #[error("provider error: {0}")]
10 OpenRouterProviderError(#[from] OpenRouterProviderError),
11 #[error("received an empty stream")]
13 EmptyStream,
14 #[error("deserialization error: {0}")]
16 DeserializationError(#[from] serde_path_to_error::Error<serde_json::Error>),
17 #[error("received bad status code: {code}, body: {body}")]
19 BadStatus {
20 code: reqwest::StatusCode,
22 body: serde_json::Value,
24 },
25 #[error("error fetching stream: {0}")]
27 StreamError(#[from] reqwest_eventsource::Error),
28 #[error("error fetching stream: timeout")]
30 StreamTimeout,
31 #[error("fetch Ensemble LLM error: {0}")]
33 FetchEnsembleLlm(objectiveai::error::ResponseError),
34 #[error("Ensemble LLM not found")]
36 EnsembleLlmNotFound,
37 #[error("insufficient credits")]
39 InsufficientCredits,
40 #[error("invalid Ensemble LLM: {0}")]
42 InvalidEnsembleLlm(String),
43}
44
45impl objectiveai::error::StatusError for Error {
46 fn status(&self) -> u16 {
47 match self {
48 Error::OpenRouterProviderError(e) => e.status(),
49 Error::EmptyStream => 500,
50 Error::DeserializationError(_) => 500,
51 Error::BadStatus { code, .. } => code.as_u16(),
52 Error::StreamError(reqwest_eventsource::Error::Transport(e)) => {
53 e.status().map(|s| s.as_u16()).unwrap_or(500)
54 }
55 Error::StreamError(reqwest_eventsource::Error::InvalidStatusCode(code, _)) => {
56 code.as_u16()
57 }
58 Error::StreamError(_) => 500,
59 Error::StreamTimeout => 500,
60 Error::FetchEnsembleLlm(e) => e.status(),
61 Error::InsufficientCredits => 402,
62 Error::InvalidEnsembleLlm(_) => 400,
63 Error::EnsembleLlmNotFound => 404,
64 }
65 }
66
67 fn message(&self) -> Option<serde_json::Value> {
68 Some(serde_json::json!({
69 "kind": "openrouter",
70 "error": match self {
71 Error::OpenRouterProviderError(e) => serde_json::json!({
72 "kind": "provider_error",
73 "error": e.message(),
74 }),
75 Error::EmptyStream => serde_json::json!({
76 "kind": "empty_stream",
77 "error": "received an empty stream",
78 }),
79 Error::DeserializationError(e) => serde_json::json!({
80 "kind": "deserialization",
81 "error": e.to_string(),
82 }),
83 Error::BadStatus { body, .. } => serde_json::json!({
84 "kind": "bad_status",
85 "error": body,
86 }),
87 Error::StreamError(e) => serde_json::json!({
88 "kind": "stream_error",
89 "error": e.to_string(),
90 }),
91 Error::StreamTimeout => serde_json::json!({
92 "kind": "stream_timeout",
93 "error": "error fetching stream: timeout",
94 }),
95 Error::FetchEnsembleLlm(e) => serde_json::json!({
96 "kind": "fetch_ensemble_llm",
97 "error": e.message(),
98 }),
99 Error::InsufficientCredits => serde_json::json!({
100 "kind": "insufficient_credits",
101 "error": "the user has insufficient credits",
102 }),
103 Error::InvalidEnsembleLlm(msg) => serde_json::json!({
104 "kind": "invalid_ensemble_llm",
105 "error": msg,
106 }),
107 Error::EnsembleLlmNotFound => serde_json::json!({
108 "kind": "ensemble_llm_not_found",
109 "error": "Ensemble LLM not found",
110 }),
111 },
112 }))
113 }
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
118#[error("{}", &serde_json::to_string(self).unwrap_or_default())]
119pub struct OpenRouterProviderError {
120 pub error: OpenRouterProviderErrorInner,
122 pub user_id: Option<String>,
124}
125
126impl objectiveai::error::StatusError for OpenRouterProviderError {
127 fn status(&self) -> u16 {
128 self.error.status()
129 }
130
131 fn message(&self) -> Option<serde_json::Value> {
132 self.error.message()
133 }
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize, thiserror::Error)]
138#[error("{}", &serde_json::to_string(self).unwrap_or_default())]
139pub struct OpenRouterProviderErrorInner {
140 #[serde(skip_serializing_if = "Option::is_none")]
142 pub code: Option<u16>,
143 #[serde(skip_serializing_if = "Option::is_none")]
145 pub message: Option<serde_json::Value>,
146 #[serde(skip_serializing_if = "Option::is_none")]
148 pub metadata: Option<serde_json::Value>,
149}
150
151impl objectiveai::error::StatusError for OpenRouterProviderErrorInner {
152 fn status(&self) -> u16 {
153 self.code
154 .unwrap_or(reqwest::StatusCode::INTERNAL_SERVER_ERROR.as_u16())
155 }
156
157 fn message(&self) -> Option<serde_json::Value> {
158 Some(serde_json::json!({
159 "kind": "provider",
160 "message": self.message,
161 "metadata": self.metadata,
162 }))
163 }
164}