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
use std::collections::BTreeMap;
use runifold_core::RetrySafety;
use serde::{Deserialize, Serialize};
use serde_json::Value;
use thiserror::Error;
/// A normalized model-layer error category.
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
#[non_exhaustive]
pub enum ModelErrorKind {
/// Request data failed local validation.
InvalidRequest,
/// The selected model or provider does not support a required feature.
UnsupportedFeature,
/// A provider transport failed.
Transport,
/// A provider response violated its protocol.
Protocol,
/// Stream events violated the canonical lifecycle.
StreamState,
/// Accumulated tool arguments were not valid JSON.
MalformedToolArguments,
/// A provider rejected or failed a request.
Provider,
/// The model call was cancelled.
Cancelled,
/// The model call exceeded its deadline.
DeadlineExceeded,
}
/// A structured model-layer error.
#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
#[error("{kind:?}: {message}")]
pub struct ModelError {
/// Normalized category.
pub kind: ModelErrorKind,
/// Safe human-readable explanation.
pub message: String,
/// Provider namespace, when known.
pub provider: Option<String>,
/// Retry-safety classification.
pub retry_safety: RetrySafety,
/// Namespaced diagnostic metadata.
pub metadata: BTreeMap<String, Value>,
}
impl ModelError {
/// Creates a non-retryable local validation or state error.
pub fn local(kind: ModelErrorKind, message: impl Into<String>) -> Self {
Self {
kind,
message: message.into(),
provider: None,
retry_safety: RetrySafety::Unknown,
metadata: BTreeMap::new(),
}
}
}