1use anyhow::Result;
2use std::future::Future;
3
4pub async fn retry_with_parse<T, F, Fut, P>(llm_call: F, parser: P, max_retries: u32) -> Result<T>
6where
7 F: Fn() -> Fut,
8 Fut: Future<Output = Result<String>>,
9 P: Fn(&str) -> Result<T>,
10{
11 let mut last_error = None;
12
13 for attempt in 1..=max_retries {
14 let response = match llm_call().await {
16 Ok(resp) => resp,
17 Err(e) => {
18 last_error = Some(e);
19 if attempt < max_retries {
20 tracing::warn!(
21 "LLM call failed (attempt {}/{}): Retrying...",
22 attempt,
23 max_retries
24 );
25 continue;
26 } else {
27 tracing::error!("All retry attempts exhausted.");
28 break;
29 }
30 }
31 };
32
33 match parser(&response) {
35 Ok(parsed) => return Ok(parsed),
36 Err(e) => {
37 last_error = Some(e);
38 if attempt < max_retries {
39 tracing::warn!(
40 "Parse failed (attempt {}/{}): Retrying...",
41 attempt,
42 max_retries
43 );
44 continue;
45 } else {
46 tracing::error!("All retry attempts exhausted.");
47 break;
48 }
49 }
50 }
51 }
52
53 Err(last_error.unwrap_or_else(|| anyhow::anyhow!("Unknown error after retries")))
55}