1use std::time::Duration;
2
3use tea_protocol::{ProtocolMetadata, RetryClass};
4
5use crate::ModelStreamValueError;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum ModelFailureCode {
10 InvalidRequest,
12 ContextOverflow,
14 Authentication,
16 PermissionDenied,
18 RateLimited,
20 Unavailable,
22 Transport,
24 MalformedResponse,
26 Cancelled,
28 Internal,
30}
31
32impl ModelFailureCode {
33 pub const ALL: [Self; 10] = [
35 Self::InvalidRequest,
36 Self::ContextOverflow,
37 Self::Authentication,
38 Self::PermissionDenied,
39 Self::RateLimited,
40 Self::Unavailable,
41 Self::Transport,
42 Self::MalformedResponse,
43 Self::Cancelled,
44 Self::Internal,
45 ];
46}
47
48#[derive(Debug, Clone, PartialEq)]
50pub struct ModelFailure {
51 code: ModelFailureCode,
52 message: String,
53 retry: RetryClass,
54 retry_after: Option<Duration>,
55 metadata: ProtocolMetadata,
56 safe_diagnostic: bool,
57}
58
59impl ModelFailure {
60 #[must_use]
62 pub fn internal_adapter_failure() -> Self {
63 Self {
64 code: ModelFailureCode::Internal,
65 message: "model adapter failed internally".to_owned(),
66 retry: RetryClass::Never,
67 retry_after: None,
68 metadata: ProtocolMetadata::default(),
69 safe_diagnostic: false,
70 }
71 }
72
73 pub fn new(
80 code: ModelFailureCode,
81 message: impl Into<String>,
82 retry: RetryClass,
83 ) -> Result<Self, ModelStreamValueError> {
84 let message = message.into();
85 if message.is_empty() || message.len() > 4096 || message.contains('\0') {
86 return Err(ModelStreamValueError::InvalidFailureMessage);
87 }
88 Ok(Self {
89 code,
90 message,
91 retry,
92 retry_after: None,
93 metadata: ProtocolMetadata::default(),
94 safe_diagnostic: false,
95 })
96 }
97
98 pub fn safe(
108 code: ModelFailureCode,
109 message: impl Into<String>,
110 retry: RetryClass,
111 ) -> Result<Self, ModelStreamValueError> {
112 let mut failure = Self::new(code, message, retry)?;
113 failure.safe_diagnostic = true;
114 Ok(failure)
115 }
116
117 #[must_use]
119 pub fn with_metadata(mut self, metadata: ProtocolMetadata) -> Self {
120 self.metadata = metadata;
121 self
122 }
123
124 #[must_use]
126 pub fn with_retry_after(mut self, retry_after: Duration) -> Self {
127 self.retry_after = Some(retry_after);
128 self
129 }
130
131 #[must_use]
133 pub const fn code(&self) -> ModelFailureCode {
134 self.code
135 }
136
137 #[must_use]
139 pub fn message(&self) -> &str {
140 &self.message
141 }
142
143 #[must_use]
145 pub const fn retry(&self) -> RetryClass {
146 self.retry
147 }
148
149 #[must_use]
151 pub const fn retry_after(&self) -> Option<Duration> {
152 self.retry_after
153 }
154
155 #[must_use]
157 pub const fn metadata(&self) -> &ProtocolMetadata {
158 &self.metadata
159 }
160
161 #[must_use]
163 pub const fn is_safe_diagnostic(&self) -> bool {
164 self.safe_diagnostic
165 }
166}