Skip to main content

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}