1use pyo3::exceptions::PyRuntimeError;
2use pyo3::pyclass::PyClassGuardError;
3use pyo3::PyErr;
4use pythonize::PythonizeError;
5use thiserror::Error;
6use tracing::error;
7
8#[derive(Error, Debug)]
9pub enum TypeError {
10 #[error("Error: {0}")]
11 Error(String),
12
13 #[error("Unknown provider: {0}")]
14 UnknownProviderError(String),
15
16 #[error("No provider specified. Pass `provider=` explicitly or set the {0} env var.")]
17 MissingProviderError(&'static str),
18
19 #[error("Unknown model: {0}")]
20 UnknownModelError(String),
21
22 #[error("{0}")]
23 InvalidInput(String),
24
25 #[error(transparent)]
26 UtilError(#[from] potato_util::UtilError),
27
28 #[error(transparent)]
29 SerdeError(#[from] serde_json::Error),
30
31 #[error(transparent)]
32 StdError(#[from] std::io::Error),
33
34 #[error("Failed to create GeminiEmbeddingConfig: {0}")]
35 GeminiEmbeddingConfigError(String),
36
37 #[error("Invalid media type: {0}")]
38 InvalidMediaType(String),
39
40 #[error("Invalid media file: {0}")]
41 InvalidMediaFile(String),
42
43 #[error("Media file '{path}' is too large: {size} bytes exceeds maximum {max_size} bytes")]
44 MediaFileTooLarge {
45 path: String,
46 size: u64,
47 max_size: u64,
48 },
49
50 #[error("media placeholder '${{media:{name}}}' not found in any user message")]
51 MediaPlaceholderNotFound { name: String },
52
53 #[error("media placeholder '${{media:{name}}}' must be the entire content of a text block")]
54 MediaPlaceholderNotIsolated { name: String },
55
56 #[error("provider {provider} does not support media kind {kind:?} with given source")]
57 UnsupportedMediaForProvider {
58 provider: String,
59 kind: crate::prompt::media::MediaKind,
60 },
61
62 #[error("media placeholders are not allowed in system messages")]
63 MediaInSystemMessage,
64
65 #[error("Unsupported prompt content type")]
66 UnsupportedTypeError,
67
68 #[error("Cannot bind non-string content")]
69 CannotBindNonStringContent,
70
71 #[error("Failed to serialize Python object: {0}")]
72 PySerializationError(String),
73
74 #[error("Content type is not supported")]
75 UnsupportedContentType,
76
77 #[error("Invalid model settings provided. ModelSettings expects either OpenAIChatSettings, GeminiSettings, or AnthropicSettings.")]
78 InvalidModelSettings,
79
80 #[error("Expected string, Message, or list of messages")]
81 MessageParseError,
82
83 #[error("Invalid message type in list. Received: {0}")]
84 InvalidMessageTypeInList(String),
85
86 #[error("Either 'auto_mode' or 'manual_mode' must be provided, but not both.")]
87 MissingRoutingConfigMode,
88
89 #[error("Invalid data type for Part. Expected String, Blob, FileData, FunctionCall, FunctionResponse, ExecutableCode, or CodeExecutionResult. Got: {0}")]
90 InvalidDataType(String),
91
92 #[error("Invalid list type for Part. Expected a list of Strings or a list of Message objects. Got: {0}")]
93 InvalidListType(String),
94
95 #[error("Parts must be a string, Part, DataNum variant, or a list of these types")]
96 InvalidPartType,
97
98 #[error("Invalid ranking config provided.")]
99 InvalidRankingConfig,
100
101 #[error("Invalid retrieval source provided.")]
102 InvalidRetrievalSource,
103
104 #[error("Invalid authentication configuration provided.")]
105 InvalidAuthConfig,
106
107 #[error("Invalid OAuth configuration provided.")]
108 InvalidOauthConfig,
109
110 #[error("Invalid OIDC configuration provided.")]
111 InvalidOidcConfig,
112
113 #[error("More than one system instruction provided where only one is allowed.")]
114 MoreThanOneSystemInstruction,
115
116 #[error("Invalid request type for Anthropic provider.")]
117 InvalidRequestTypeForAnthropic,
118
119 #[error("Invalid request type for Gemini provider.")]
120 InvalidRequestTypeForGemini,
121
122 #[error("Invalid request type for OpenAI provider.")]
123 InvalidRequestTypeForOpenAI,
124
125 #[error("Unsupported provider for request creation.")]
126 UnsupportedProviderForRequestCreation,
127
128 #[error("OpenAI response content is empty.")]
129 EmptyOpenAIResponseContent,
130
131 #[error("{0}")]
132 UnsupportedConversion(String),
133
134 #[error("Cannot convert message to self")]
135 CantConvertSelf,
136
137 #[error("Unsupported provider for message conversion")]
138 UnsupportedProviderError,
139
140 #[error("Message is not an OpenAI ChatMessage")]
141 MessageIsNotOpenAIChatMessage,
142
143 #[error("Message is not a Google GeminiContent")]
144 MessageIsNotGoogleGeminiContent,
145
146 #[error("Message is not an Anthropic MessageParam")]
147 MessageIsNotAnthropicMessageParam,
148
149 #[error("Failed to resolve prompt path '{requested_path}'. Tried: {attempted_paths}")]
150 PromptPathNotFound {
151 requested_path: String,
152 attempted_paths: String,
153 },
154
155 #[error("Prompt path '{requested_path}' is ambiguous. Matches: {candidate_paths}")]
156 AmbiguousPromptPath {
157 requested_path: String,
158 candidate_paths: String,
159 },
160
161 #[error(transparent)]
162 SerdeYamlError(#[from] serde_yaml::Error),
163}
164
165impl From<TypeError> for PyErr {
166 fn from(err: TypeError) -> PyErr {
167 let msg = err.to_string();
168 error!("{}", msg);
169 PyRuntimeError::new_err(msg)
170 }
171}
172
173impl From<PythonizeError> for TypeError {
174 fn from(err: PythonizeError) -> Self {
175 TypeError::Error(err.to_string())
176 }
177}
178
179impl From<PyErr> for TypeError {
180 fn from(err: PyErr) -> Self {
181 TypeError::Error(err.to_string())
182 }
183}
184
185impl<'a, 'py> From<PyClassGuardError<'a, 'py>> for TypeError {
186 fn from(err: PyClassGuardError<'a, 'py>) -> Self {
187 TypeError::Error(err.to_string())
188 }
189}
190
191impl<'a, 'py> From<pyo3::CastError<'a, 'py>> for TypeError {
192 fn from(err: pyo3::CastError<'a, 'py>) -> Self {
193 TypeError::Error(err.to_string())
194 }
195}