Skip to main content

app/tools/
error.rs

1use domain::{entities, policy};
2
3/// Result type returned by fallible tools error operations.
4pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error, Clone, PartialEq, Eq)]
7/// Decision choices for error in the agent tool error surface; each value guides source-grounded routing and review.
8pub enum Error {
9    #[error("not found: {resource} {id}")]
10    /// Resource copied from reviewed source input for audit, reviewer explanation, or agent context; callers must not invent or mutate it.
11    NotFound {
12        /// Resource value stored on this variant.
13        resource: Resource,
14        /// Id value stored on this variant.
15        id: ResourceId,
16    },
17    #[error("policy denied: {reason}")]
18    /// Reason copied from reviewed source input for audit, reviewer explanation, or agent context; callers must not invent or mutate it.
19    PolicyDenied {
20        /// Reason value stored on this variant.
21        reason: policy::denial::Reason,
22    },
23    #[error("external system error: {failure}")]
24    /// Failure copied from reviewed source input for audit, reviewer explanation, or agent context; callers must not invent or mutate it.
25    External {
26        /// Failure value stored on this variant.
27        failure: ExternalFailure,
28    },
29}
30
31impl Error {
32    /// Builds policy denied for the agent tool error gate rules from validated source facts while preserving review gates and draft-only side effects.
33    pub fn policy_denied(reason: policy::denial::Reason) -> Self {
34        Self::PolicyDenied { reason }
35    }
36}
37
38#[derive(Debug, Clone, Copy, PartialEq, Eq)]
39/// Decision choices for resource in the agent tool error surface; each value guides source-grounded routing and review.
40pub enum Resource {
41    /// Selects customer for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
42    Customer,
43    /// Selects pet for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
44    Pet,
45    /// Selects reservation for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
46    Reservation,
47    /// Selects availability snapshot for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
48    AvailabilitySnapshot,
49    /// Selects draft reservation update for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
50    DraftReservationUpdate,
51}
52
53impl std::fmt::Display for Resource {
54    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55        let label = match self {
56            Self::Customer => "customer",
57            Self::Pet => "pet",
58            Self::Reservation => "reservation",
59            Self::AvailabilitySnapshot => "availability snapshot",
60            Self::DraftReservationUpdate => "draft reservation update",
61        };
62        formatter.write_str(label)
63    }
64}
65
66#[derive(Debug, Clone, PartialEq, Eq)]
67/// Decision choices for resource id in the agent tool error surface; each value guides source-grounded routing and review.
68pub enum ResourceId {
69    /// Selects customer for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
70    Customer(entities::CustomerId),
71    /// Selects pet for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
72    Pet(entities::PetId),
73    /// Selects reservation for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
74    Reservation(entities::reservation::Id),
75    /// Selects snapshot for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
76    Snapshot(super::availability::CapacitySnapshotId),
77    /// Selects draft for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
78    Draft(super::draft_update::draft::Id),
79    /// Selects external for the tool error decision model so the app can choose a review, evidence, or draft path without taking live action.
80    External(String),
81}
82
83impl std::fmt::Display for ResourceId {
84    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        match self {
86            Self::Customer(id) => write!(formatter, "{}", id.0),
87            Self::Pet(id) => write!(formatter, "{}", id.0),
88            Self::Reservation(id) => write!(formatter, "{}", id.0),
89            Self::Snapshot(id) => formatter.write_str(id.clone().into_inner().as_str()),
90            Self::Draft(id) => formatter.write_str(id.clone().into_inner().as_str()),
91            Self::External(id) => formatter.write_str(id),
92        }
93    }
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
97/// Decision choices for external failure in the agent tool error surface; each value guides source-grounded routing and review.
98pub enum ExternalFailure {
99    /// Identifies portal unavailable as the reason the workflow must stop, retry, or request review.
100    PortalUnavailable,
101    /// Identifies payment provider unavailable as the reason the workflow must stop, retry, or request review.
102    PaymentProviderUnavailable,
103    /// Identifies message provider unavailable as the reason the workflow must stop, retry, or request review.
104    MessageProviderUnavailable,
105    /// Identifies storage unavailable as the reason the workflow must stop, retry, or request review.
106    StorageUnavailable,
107    /// Identifies other as the reason the workflow must stop, retry, or request review.
108    Other(String),
109}
110
111impl std::fmt::Display for ExternalFailure {
112    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
113        let label = match self {
114            Self::PortalUnavailable => "portal unavailable",
115            Self::PaymentProviderUnavailable => "payment provider unavailable",
116            Self::MessageProviderUnavailable => "message provider unavailable",
117            Self::StorageUnavailable => "storage unavailable",
118            Self::Other(message) => return formatter.write_str(message),
119        };
120        formatter.write_str(label)
121    }
122}