1pub mod error;
2
3pub use crate::error::TypeError;
4use pyo3::prelude::*;
5use schemars::JsonSchema;
6use serde::de::Error;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::any::type_name;
10use std::fmt;
11use std::fmt::Display;
12use std::path::{Path, PathBuf};
13use tracing::error;
14pub mod anthropic;
15pub mod common;
16pub mod google;
17pub mod openai;
18pub mod prompt;
19pub mod spec;
20pub mod tools;
21pub mod traits;
22
23#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
24#[pyclass(from_py_object)]
25pub enum Model {
26 Undefined,
27}
28
29impl Model {
30 pub fn as_str(&self) -> &str {
31 match self {
32 Model::Undefined => "undefined",
33 }
34 }
35
36 pub fn from_string(s: &str) -> Result<Self, TypeError> {
37 match s.to_lowercase().as_str() {
38 "undefined" => Ok(Model::Undefined),
39 _ => Err(TypeError::UnknownModelError(s.to_string())),
40 }
41 }
42}
43
44pub enum Common {
45 Undefined,
46}
47
48impl Common {
49 pub fn as_str(&self) -> &str {
50 match self {
51 Common::Undefined => "undefined",
52 }
53 }
54}
55
56impl Display for Common {
57 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
58 write!(f, "{}", self.as_str())
59 }
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
63#[pyclass(from_py_object, eq, eq_int)]
64pub enum Provider {
65 OpenAI,
66 Gemini,
67 Google,
68 Vertex,
69 Anthropic,
70 GoogleAdk,
71 Undefined, }
73
74impl Provider {
75 pub fn from_string(s: &str) -> Result<Self, TypeError> {
76 match s.to_lowercase().as_str() {
77 "openai" => Ok(Provider::OpenAI),
78 "gemini" => Ok(Provider::Gemini),
79 "google" => Ok(Provider::Google),
80 "vertex" => Ok(Provider::Vertex),
81 "anthropic" => Ok(Provider::Anthropic),
82 "google_adk" => Ok(Provider::GoogleAdk),
83 "undefined" => Ok(Provider::Undefined), _ => Err(TypeError::UnknownProviderError(s.to_string())),
85 }
86 }
87
88 pub fn extract_provider(provider: &Bound<'_, PyAny>) -> Result<Provider, TypeError> {
99 match provider.is_instance_of::<Provider>() {
100 true => Ok(provider.extract::<Provider>().inspect_err(|e| {
101 error!("Failed to extract provider: {}", e);
102 })?),
103 false => {
104 let provider = provider.extract::<String>().unwrap();
105 Ok(Provider::from_string(&provider).inspect_err(|e| {
106 error!("Failed to convert string to provider: {}", e);
107 })?)
108 }
109 }
110 }
111
112 pub fn as_str(&self) -> &str {
113 match self {
114 Provider::OpenAI => "openai",
115 Provider::Gemini => "gemini",
116 Provider::Vertex => "vertex",
117 Provider::Google => "google",
118 Provider::Anthropic => "anthropic",
119 Provider::GoogleAdk => "google_adk",
120 Provider::Undefined => "undefined", }
122 }
123}
124
125impl Display for Provider {
126 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
127 write!(f, "{}", self.as_str())
128 }
129}
130
131#[pyclass(from_py_object, eq, eq_int)]
132#[derive(Debug, PartialEq, Clone)]
133pub enum SaveName {
134 Prompt,
135}
136
137#[pymethods]
138impl SaveName {
139 #[staticmethod]
140 pub fn from_string(s: &str) -> Option<Self> {
141 match s {
142 "prompt" => Some(SaveName::Prompt),
143
144 _ => None,
145 }
146 }
147
148 pub fn as_string(&self) -> &str {
149 match self {
150 SaveName::Prompt => "prompt",
151 }
152 }
153
154 pub fn __str__(&self) -> String {
155 self.to_string()
156 }
157}
158
159impl Display for SaveName {
160 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
161 write!(f, "{}", self.as_string())
162 }
163}
164
165impl AsRef<Path> for SaveName {
166 fn as_ref(&self) -> &Path {
167 match self {
168 SaveName::Prompt => Path::new("prompt"),
169 }
170 }
171}
172
173impl From<SaveName> for PathBuf {
175 fn from(save_name: SaveName) -> Self {
176 PathBuf::from(save_name.as_ref())
177 }
178}
179
180pub trait StructuredOutput: for<'de> serde::Deserialize<'de> + JsonSchema {
199 fn type_name() -> &'static str {
200 type_name::<Self>().rsplit("::").next().unwrap_or("Unknown")
201 }
202
203 fn model_validate_json_value(value: &Value) -> Result<Self, serde_json::Error> {
211 match &value {
212 Value::String(json_str) => Self::model_validate_json_str(json_str),
213 Value::Object(_) => {
214 serde_json::from_value(value.clone())
216 }
217 _ => {
218 Err(Error::custom("Expected a JSON string or object"))
220 }
221 }
222 }
223
224 fn model_validate_json_str(value: &str) -> Result<Self, serde_json::Error> {
225 serde_json::from_str(value)
226 }
227
228 fn get_structured_output_schema() -> Value {
233 let schema = ::schemars::schema_for!(Self);
234 schema.into()
235 }
236 }
238
239#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
240#[pyclass(from_py_object)]
241pub enum SettingsType {
242 GoogleChat,
243 OpenAIChat,
244 ModelSettings,
245 Anthropic,
246}
247
248#[cfg(test)]
249mod tests {
250 use super::*;
251
252 #[test]
253 fn test_provider_google_adk_round_trip() {
254 let p = Provider::from_string("google_adk").unwrap();
255 assert_eq!(p, Provider::GoogleAdk);
256 assert_eq!(p.as_str(), "google_adk");
257 }
258
259 #[test]
260 fn test_provider_all_variants_round_trip() {
261 for (s, variant) in [
262 ("openai", Provider::OpenAI),
263 ("gemini", Provider::Gemini),
264 ("google", Provider::Google),
265 ("vertex", Provider::Vertex),
266 ("anthropic", Provider::Anthropic),
267 ("google_adk", Provider::GoogleAdk),
268 ("undefined", Provider::Undefined),
269 ] {
270 let parsed = Provider::from_string(s).unwrap();
271 assert_eq!(parsed, variant);
272 assert_eq!(parsed.as_str(), s);
273 }
274 }
275
276 #[test]
277 fn test_provider_unknown_string_errors() {
278 assert!(Provider::from_string("not_a_provider").is_err());
279 }
280}