1use thiserror::Error;
2
3#[derive(Debug, Clone)]
5pub struct CastIssue {
6 pub pointer: String,
8 pub message: String,
10}
11
12#[derive(Debug, Error)]
14pub enum CastError {
15 #[error("invalid JSON after repair: {0}")]
17 InvalidJson(String),
18 #[error("schema validation failed ({} issue(s))", issues.len())]
20 Invalid {
21 issues: Vec<CastIssue>,
23 },
24 #[error("retry budget exhausted after {attempts} attempts; last error: {last}")]
26 RetryExhausted {
27 attempts: usize,
29 last: String,
31 },
32 #[error("retry function failed: {0}")]
34 RetryFailed(String),
35 #[error("invalid schema: {0}")]
37 InvalidSchema(String),
38}
39
40impl CastError {
41 pub fn for_llm(&self) -> Option<String> {
44 match self {
45 CastError::Invalid { issues } => {
46 let mut s = String::from("Output rejected. Fix and try again:\n");
47 for i in issues {
48 s.push_str(" - ");
49 if !i.pointer.is_empty() {
50 s.push_str(&i.pointer);
51 s.push_str(": ");
52 }
53 s.push_str(&i.message);
54 s.push('\n');
55 }
56 Some(s.trim_end().to_string())
57 }
58 CastError::InvalidJson(msg) => Some(format!(
59 "Output was not valid JSON. Return only a JSON object matching the schema. Parser said: {msg}"
60 )),
61 _ => None,
62 }
63 }
64}