1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum GrpcError {
5 #[error("Failed to connect to gRPC server: {0}")]
6 ConnectionFailed(#[from] tonic::transport::Error),
7
8 #[error("gRPC call failed: {0}")]
9 CallFailed(#[from] Box<tonic::Status>),
10
11 #[error("Failed to convert message at index {index}: {reason}")]
12 MessageConversionFailed { index: usize, reason: String },
13
14 #[error("Session not found: {session_id}")]
15 SessionNotFound { session_id: String },
16
17 #[error("Invalid session state: {reason}")]
18 InvalidSessionState { reason: String },
19
20 #[error("Stream error: {0}")]
21 StreamError(String),
22
23 #[error("Conversion error: {0}")]
24 ConversionError(#[from] ConversionError),
25
26 #[error("Core error: {0}")]
27 CoreError(#[from] steer_core::error::Error),
28
29 #[error("Channel receive error: {0}")]
30 ChannelError(String),
31}
32
33#[derive(Error, Debug)]
34pub enum ConversionError {
35 #[error("Missing required field: {field}")]
36 MissingField { field: String },
37
38 #[error("Invalid enum value: {value} for {enum_name}")]
39 InvalidEnumValue { value: i32, enum_name: String },
40
41 #[error("JSON serialization error: {0}")]
42 JsonError(#[from] serde_json::Error),
43
44 #[error("Invalid variant: expected {expected}, got {actual}")]
45 InvalidVariant { expected: String, actual: String },
46
47 #[error("Missing oneof variant in {message}")]
48 MissingOneofVariant { message: String },
49
50 #[error("Invalid value '{value}' for field '{field}'")]
51 InvalidValue { field: String, value: String },
52
53 #[error("Invalid JSON for field '{field}': {error}")]
54 InvalidJson { field: String, error: String },
55
56 #[error("Invalid data: {message}")]
57 InvalidData { message: String },
58
59 #[error("Tool result conversion error: {0}")]
60 ToolResultConversion(String),
61}
62
63impl From<GrpcError> for tonic::Status {
64 fn from(err: GrpcError) -> Self {
65 match err {
66 GrpcError::ConnectionFailed(e) => {
67 tonic::Status::unavailable(format!("Connection failed: {e}"))
68 }
69 GrpcError::CallFailed(status) => *status,
70 GrpcError::MessageConversionFailed { index, reason } => {
71 tonic::Status::invalid_argument(format!(
72 "Failed to convert message at index {index}: {reason}"
73 ))
74 }
75 GrpcError::SessionNotFound { session_id } => {
76 tonic::Status::not_found(format!("Session not found: {session_id}"))
77 }
78 GrpcError::InvalidSessionState { reason } => {
79 tonic::Status::failed_precondition(format!("Invalid session state: {reason}"))
80 }
81 GrpcError::StreamError(msg) => tonic::Status::internal(format!("Stream error: {msg}")),
82 GrpcError::ConversionError(e) => {
83 tonic::Status::invalid_argument(format!("Conversion error: {e}"))
84 }
85 GrpcError::CoreError(e) => tonic::Status::internal(format!("Core error: {e}")),
86 GrpcError::ChannelError(msg) => {
87 tonic::Status::internal(format!("Channel error: {msg}"))
88 }
89 }
90 }
91}