Skip to content

Commit b6a8ce3

Browse files
authored
feat: add into_http_result() util for better error message (#1235)
1 parent 509876c commit b6a8ce3

File tree

9 files changed

+70
-84
lines changed

9 files changed

+70
-84
lines changed

src/llm/anthropic.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -88,19 +88,13 @@ impl LlmGenerationClient for Client {
8888

8989
let encoded_api_key = encode(&self.api_key);
9090

91-
let resp = retryable::run(
92-
|| async {
93-
self.client
94-
.post(url)
95-
.header("x-api-key", encoded_api_key.as_ref())
96-
.header("anthropic-version", "2023-06-01")
97-
.json(&payload)
98-
.send()
99-
.await?
100-
.error_for_status()
101-
},
102-
&retryable::HEAVY_LOADED_OPTIONS,
103-
)
91+
let resp = http::request(|| {
92+
self.client
93+
.post(url)
94+
.header("x-api-key", encoded_api_key.as_ref())
95+
.header("anthropic-version", "2023-06-01")
96+
.json(&payload)
97+
})
10498
.await
10599
.context("Anthropic API error")?;
106100

src/llm/bedrock.rs

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -106,22 +106,16 @@ impl LlmGenerationClient for Client {
106106

107107
let encoded_api_key = encode(&self.api_key);
108108

109-
let resp = retryable::run(
110-
|| async {
111-
self.client
112-
.post(&url)
113-
.header(
114-
"Authorization",
115-
format!("Bearer {}", encoded_api_key.as_ref()),
116-
)
117-
.header("Content-Type", "application/json")
118-
.json(&payload)
119-
.send()
120-
.await?
121-
.error_for_status()
122-
},
123-
&retryable::HEAVY_LOADED_OPTIONS,
124-
)
109+
let resp = http::request(|| {
110+
self.client
111+
.post(&url)
112+
.header(
113+
"Authorization",
114+
format!("Bearer {}", encoded_api_key.as_ref()),
115+
)
116+
.header("Content-Type", "application/json")
117+
.json(&payload)
118+
})
125119
.await
126120
.context("Bedrock API error")?;
127121

src/llm/gemini.rs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -150,18 +150,9 @@ impl LlmGenerationClient for AiStudioClient {
150150
}
151151

152152
let url = self.get_api_url(request.model, "generateContent");
153-
let resp = retryable::run(
154-
|| self.client.post(&url).json(&payload).send(),
155-
&retryable::HEAVY_LOADED_OPTIONS,
156-
)
157-
.await?;
158-
if !resp.status().is_success() {
159-
bail!(
160-
"Gemini API error: {:?}\n{}\n",
161-
resp.status(),
162-
resp.text().await?
163-
);
164-
}
153+
let resp = http::request(|| self.client.post(&url).json(&payload))
154+
.await
155+
.context("Gemini API error")?;
165156
let resp_json: Value = resp.json().await.context("Invalid JSON")?;
166157

167158
if let Some(error) = resp_json.get("error") {

src/llm/ollama.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,11 @@ impl LlmGenerationClient for Client {
101101
system: request.system_prompt.as_ref().map(|s| s.as_ref()),
102102
stream: Some(false),
103103
};
104-
let res = retryable::run(
105-
|| async {
106-
self.reqwest_client
107-
.post(self.generate_url.as_str())
108-
.json(&req)
109-
.send()
110-
.await?
111-
.error_for_status()
112-
},
113-
&retryable::HEAVY_LOADED_OPTIONS,
114-
)
104+
let res = http::request(|| {
105+
self.reqwest_client
106+
.post(self.generate_url.as_str())
107+
.json(&req)
108+
})
115109
.await
116110
.context("Ollama API error")?;
117111
let json: OllamaResponse = res.json().await?;
@@ -140,19 +134,9 @@ impl LlmEmbeddingClient for Client {
140134
model: request.model,
141135
input: request.text.as_ref(),
142136
};
143-
let resp = retryable::run(
144-
|| async {
145-
self.reqwest_client
146-
.post(self.embed_url.as_str())
147-
.json(&req)
148-
.send()
149-
.await?
150-
.error_for_status()
151-
},
152-
&retryable::HEAVY_LOADED_OPTIONS,
153-
)
154-
.await
155-
.context("Ollama API error")?;
137+
let resp = http::request(|| self.reqwest_client.post(self.embed_url.as_str()).json(&req))
138+
.await
139+
.context("Ollama API error")?;
156140

157141
let embedding_resp: OllamaEmbeddingResponse = resp.json().await.context("Invalid JSON")?;
158142

src/llm/voyage.rs

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -75,18 +75,12 @@ impl LlmEmbeddingClient for Client {
7575
payload["input_type"] = serde_json::Value::String(task_type.into());
7676
}
7777

78-
let resp = retryable::run(
79-
|| async {
80-
self.client
81-
.post(url)
82-
.header("Authorization", format!("Bearer {}", self.api_key))
83-
.json(&payload)
84-
.send()
85-
.await?
86-
.error_for_status()
87-
},
88-
&retryable::HEAVY_LOADED_OPTIONS,
89-
)
78+
let resp = http::request(|| {
79+
self.client
80+
.post(url)
81+
.header("Authorization", format!("Bearer {}", self.api_key))
82+
.json(&payload)
83+
})
9084
.await
9185
.context("Voyage AI API error")?;
9286

src/ops/targets/kuzu.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,9 @@ impl KuzuThinClient {
8080
let query = json!({
8181
"query": cyper_builder.query
8282
});
83-
self.reqwest_client
84-
.post(&self.query_url)
85-
.json(&query)
86-
.send()
87-
.await?
88-
.error_for_status()?;
83+
http::request(|| self.reqwest_client.post(&self.query_url).json(&query))
84+
.await
85+
.context("Kuzu API error")?;
8986
Ok(())
9087
}
9188
}

src/prelude.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub(crate) use crate::ops::interface;
2626
pub(crate) use crate::service::error::{ApiError, invariance_violation};
2727
pub(crate) use crate::setup;
2828
pub(crate) use crate::setup::AuthRegistry;
29-
pub(crate) use crate::utils::{self, batching, concur_control, retryable};
29+
pub(crate) use crate::utils::{self, batching, concur_control, http, retryable};
3030
pub(crate) use crate::{api_bail, api_error};
3131

3232
pub(crate) use anyhow::{anyhow, bail};

src/utils/http.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use crate::utils::retryable::{self, IsRetryable};
2+
3+
pub async fn request(
4+
req_builder: impl Fn() -> reqwest::RequestBuilder,
5+
) -> anyhow::Result<reqwest::Response> {
6+
let resp = retryable::run(
7+
|| async {
8+
let req = req_builder();
9+
let resp = req.send().await?;
10+
let Err(err) = resp.error_for_status_ref() else {
11+
return Ok(resp);
12+
};
13+
14+
let is_retryable = err.is_retryable();
15+
16+
let mut anyhow_error = anyhow::Error::new(err);
17+
let body = resp.text().await?;
18+
if !body.is_empty() {
19+
anyhow_error = anyhow_error.context(format!("Error message body:\n{body}"));
20+
}
21+
22+
Err(retryable::Error {
23+
error: anyhow_error,
24+
is_retryable,
25+
})
26+
},
27+
&retryable::HEAVY_LOADED_OPTIONS,
28+
)
29+
.await?;
30+
Ok(resp)
31+
}

src/utils/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ pub mod concur_control;
44
pub mod db;
55
pub mod deser;
66
pub mod fingerprint;
7+
pub mod http;
78
pub mod immutable;
89
pub mod retryable;
910
pub mod str_sanitize;

0 commit comments

Comments
 (0)