Skip to main content

systemprompt_agent/services/shared/
error.rs

1//! Service-layer error type, distinct from the crate-public [`AgentError`]:
2//! it models failures internal to runtime services and converts into
3//! `AgentError` at the crate boundary.
4//!
5//! [`AgentError`]: crate::error::AgentError
6//!
7//! Copyright (c) systemprompt.io — Business Source License 1.1.
8//! See <https://systemprompt.io> for licensing details.
9
10use systemprompt_traits::{BoxedSource, RepositoryError};
11use thiserror::Error;
12
13#[derive(Debug, Error)]
14pub enum AgentServiceError {
15    #[error("repository operation failed: {0}")]
16    Repository(#[from] RepositoryError),
17
18    #[error("agent operation failed: {0}")]
19    Agent(#[from] crate::error::AgentError),
20
21    #[error("network request failed: {0}")]
22    Network(#[from] reqwest::Error),
23
24    #[error("io: {0}")]
25    Io(#[from] std::io::Error),
26
27    #[error("ai inference failed: {0}")]
28    AiInference(#[from] systemprompt_models::errors::AiInferenceError),
29
30    #[error("mcp registry failed: {0}")]
31    McpRegistry(#[from] systemprompt_models::errors::McpRegistryError),
32
33    #[error("validation failed for {field}: {source}")]
34    Validation {
35        field: &'static str,
36        #[source]
37        source: BoxedSource,
38    },
39
40    #[error("{context}: {source}")]
41    Operation {
42        context: String,
43        #[source]
44        source: BoxedSource,
45    },
46
47    #[error("Tool execution failed: {0}")]
48    ToolExecution(String),
49
50    #[error("tool {tool_name} returned no result")]
51    ToolReturnedNoResult {
52        tool_name: systemprompt_identifiers::McpToolName,
53    },
54
55    #[error("tool {tool_name} failed: {message}")]
56    ToolFailed {
57        tool_name: systemprompt_identifiers::McpToolName,
58        message: String,
59    },
60
61    #[error("tool {tool_name} returned no structured_content")]
62    ToolReturnedNoStructuredContent {
63        tool_name: systemprompt_identifiers::McpToolName,
64    },
65
66    #[error("agent stream failed: {message}")]
67    StreamFailed { message: String },
68
69    #[error("skill {skill_id} not found on disk: {} is missing", .path.display())]
70    SkillNotOnDisk {
71        skill_id: systemprompt_identifiers::SkillId,
72        path: std::path::PathBuf,
73    },
74
75    #[error("stream consumer closed before the task finished")]
76    StreamClosed,
77
78    #[error("task was cancelled before it finished")]
79    TaskCancelled,
80
81    #[error("skill {skill_id} is managed but withheld ({reason})")]
82    SkillWithheld {
83        skill_id: systemprompt_identifiers::SkillId,
84        reason: &'static str,
85    },
86
87    #[error("skill {skill_id} could not be resolved: {source}")]
88    SkillSource {
89        skill_id: systemprompt_identifiers::SkillId,
90        #[source]
91        source: systemprompt_traits::ManagedSkillResolverError,
92    },
93}
94
95impl AgentServiceError {
96    pub fn operation<E>(context: impl Into<String>, source: E) -> Self
97    where
98        E: std::error::Error + Send + Sync + 'static,
99    {
100        Self::Operation {
101            context: context.into(),
102            source: Box::new(source),
103        }
104    }
105
106    pub fn validation<E>(field: &'static str, source: E) -> Self
107    where
108        E: std::error::Error + Send + Sync + 'static,
109    {
110        Self::Validation {
111            field,
112            source: Box::new(source),
113        }
114    }
115}
116
117impl From<sqlx::Error> for AgentServiceError {
118    fn from(err: sqlx::Error) -> Self {
119        Self::Repository(err.into())
120    }
121}
122
123pub type Result<T> = std::result::Result<T, AgentServiceError>;