runifold_model/error.rs
1use std::collections::BTreeMap;
2
3use runifold_core::RetrySafety;
4use serde::{Deserialize, Serialize};
5use serde_json::Value;
6use thiserror::Error;
7
8/// A normalized model-layer error category.
9#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
10#[non_exhaustive]
11pub enum ModelErrorKind {
12 /// Request data failed local validation.
13 InvalidRequest,
14 /// The selected model or provider does not support a required feature.
15 UnsupportedFeature,
16 /// A provider transport failed.
17 Transport,
18 /// A provider response violated its protocol.
19 Protocol,
20 /// Stream events violated the canonical lifecycle.
21 StreamState,
22 /// Accumulated tool arguments were not valid JSON.
23 MalformedToolArguments,
24 /// A provider rejected or failed a request.
25 Provider,
26 /// The model call was cancelled.
27 Cancelled,
28 /// The model call exceeded its deadline.
29 DeadlineExceeded,
30}
31
32/// A structured model-layer error.
33#[derive(Clone, Debug, Deserialize, Error, PartialEq, Serialize)]
34#[error("{kind:?}: {message}")]
35pub struct ModelError {
36 /// Normalized category.
37 pub kind: ModelErrorKind,
38 /// Safe human-readable explanation.
39 pub message: String,
40 /// Provider namespace, when known.
41 pub provider: Option<String>,
42 /// Retry-safety classification.
43 pub retry_safety: RetrySafety,
44 /// Namespaced diagnostic metadata.
45 pub metadata: BTreeMap<String, Value>,
46}
47
48impl ModelError {
49 /// Creates a non-retryable local validation or state error.
50 pub fn local(kind: ModelErrorKind, message: impl Into<String>) -> Self {
51 Self {
52 kind,
53 message: message.into(),
54 provider: None,
55 retry_safety: RetrySafety::Unknown,
56 metadata: BTreeMap::new(),
57 }
58 }
59}