Skip to main content

bamboo_sdk/agent/
error.rs

1//! Typed SDK error surface.
2//!
3//! Replaces the stringly-typed `Result<_, String>` the builder previously
4//! returned (`with_defaults_for_data_dir` / `build`) with a single
5//! `#[derive(thiserror::Error)]` enum, matching the runtime's own [`AgentError`]
6//! (`bamboo_agent_core::AgentError`) instead of forcing callers to match on
7//! substrings. Every fallible SDK entry point added alongside cancellation /
8//! approval+resume / session ergonomics returns `Result<_, SdkError>`.
9//!
10//! `run` / `run_stream` and friends keep returning [`AgentError`] directly (it
11//! was already typed) — [`SdkError::Agent`] lets callers unify the two with `?`
12//! in a function that returns `Result<_, SdkError>`.
13
14use bamboo_agent_core::AgentError;
15use bamboo_engine::session_app::errors::{RespondError, SessionLoadError, SessionSaveError};
16
17/// Errors surfaced by the `bamboo_sdk` facade.
18#[derive(Debug, thiserror::Error)]
19pub enum SdkError {
20    /// A run/resume of the underlying agent loop failed. Wraps the runtime's
21    /// own typed error so `?` composes across `Agent::run*` and the newer
22    /// facade methods in a function returning `Result<_, SdkError>`.
23    #[error(transparent)]
24    Agent(#[from] AgentError),
25
26    /// `AgentBuilder::build()` failed — the wrapped engine builder rejected an
27    /// incomplete or inconsistent dependency set (e.g. a required dependency
28    /// was never supplied).
29    #[error("agent builder error: {0}")]
30    Build(String),
31
32    /// `with_defaults_for_data_dir` failed to read/parse `config.json`.
33    #[error("configuration error: {0}")]
34    Config(String),
35
36    /// `with_defaults_for_data_dir` failed to construct the configured LLM
37    /// provider — commonly a missing/invalid API key. See
38    /// [`AgentBuilder::api_key`](super::AgentBuilder::api_key) and
39    /// [`AgentBuilder::provider_name`](super::AgentBuilder::provider_name).
40    #[error("provider initialization failed: {0}")]
41    ProviderInit(String),
42
43    /// `with_defaults_for_data_dir` failed to open the session store at the
44    /// given data directory.
45    #[error("session store initialization failed: {0}")]
46    StoreInit(String),
47
48    /// `with_defaults_for_data_dir` failed to initialize the skill manager.
49    #[error("skill manager initialization failed: {0}")]
50    SkillInit(String),
51
52    /// An MCP server failed to start (see
53    /// [`AgentBuilder::mcp_server`](super::AgentBuilder::mcp_server)).
54    #[error("MCP server '{server_id}' failed to start: {source}")]
55    McpServerStart {
56        server_id: String,
57        #[source]
58        source: bamboo_mcp::McpError,
59    },
60
61    /// The requested session does not exist.
62    #[error("session not found: {0}")]
63    SessionNotFound(String),
64
65    /// Loading a session from storage failed.
66    #[error("session load failed: {0}")]
67    SessionLoad(String),
68
69    /// Persisting a session failed.
70    #[error("session save failed: {0}")]
71    SessionSave(String),
72
73    /// [`Agent::answer`](super::Agent::answer) was called on a session with no
74    /// pending question / approval to respond to.
75    #[error("no pending question waiting for response")]
76    NoPendingQuestion,
77
78    /// The response passed to [`Agent::answer`](super::Agent::answer) did not
79    /// match one of the pending question's fixed options (and it does not
80    /// allow a custom response).
81    #[error("invalid response: {0}")]
82    InvalidResponse(String),
83
84    /// A capability that requires `with_defaults_for_data_dir` (e.g. session
85    /// listing, which needs the concrete session-index handle) was called on
86    /// an `Agent` assembled from manually-injected dependencies.
87    #[error("unsupported: {0}")]
88    Unsupported(String),
89
90    /// Underlying I/O failure (session store reads/writes, etc).
91    #[error("I/O error: {0}")]
92    Io(#[from] std::io::Error),
93}
94
95impl From<SessionLoadError> for SdkError {
96    fn from(error: SessionLoadError) -> Self {
97        match error {
98            SessionLoadError::NotFound(id) => SdkError::SessionNotFound(id),
99            SessionLoadError::StorageError(message) => SdkError::SessionLoad(message),
100        }
101    }
102}
103
104impl From<SessionSaveError> for SdkError {
105    fn from(error: SessionSaveError) -> Self {
106        match error {
107            SessionSaveError::StorageError(message) => SdkError::SessionSave(message),
108        }
109    }
110}
111
112impl From<RespondError> for SdkError {
113    fn from(error: RespondError) -> Self {
114        match error {
115            RespondError::NotFound(id) => SdkError::SessionNotFound(id),
116            RespondError::LoadFailed(inner) => inner.into(),
117            RespondError::SaveFailed(inner) => inner.into(),
118            RespondError::NoPendingQuestion => SdkError::NoPendingQuestion,
119            RespondError::InvalidResponse(message) => SdkError::InvalidResponse(message),
120        }
121    }
122}