steer_grpc/grpc/
error.rs

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}