1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Post-decode validators for typed structured output.
//!
//! [`OutputValidator<O>`] runs after `complete_typed_validated`
//! parses the model's response into `O`. Validators that detect a
//! semantic problem the JSON schema cannot catch — value out of
//! range, business-rule violation, cross-field invariant — return
//! [`crate::Error::ModelRetry`] with a corrective hint. The chat model's
//! retry loop catches the variant, reflects the hint to the model
//! as a user message (mirror of the schema-mismatch retry path,
//!), and re-invokes within the configured
//! [`ChatModelConfig::validation_retries`](crate::ChatModelConfig::validation_retries)
//! budget.
//!
//! # Closures fit too
//!
//! Any `Fn(&O) -> Result<()> + Send + Sync + 'static` satisfies
//! the trait via the blanket impl, so the common case is a
//! one-liner:
//!
//! ```ignore
//! let model = ChatModel::anthropic("…", "claude-…")
//! .with_validation_retries(2);
//! let output: MyOutput = model.complete_typed_validated(
//! messages,
//! |out: &MyOutput| {
//! if out.score >= 0 && out.score <= 100 {
//! Ok(())
//! } else {
//! Err(Error::model_retry(
//! "score must be between 0 and 100".to_owned().for_llm(),
//! 0,
//! ))
//! }
//! },
//! &ctx,
//! ).await?;
//! ```
use crateResult;
/// Post-decode validator. Implementors return [`Error::ModelRetry`]
/// to signal the `ChatModel` retry loop should re-prompt the model
/// with corrective feedback. Other error variants bubble unchanged.
///
/// [`Error::ModelRetry`]: crate::Error::ModelRetry