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}