use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[non_exhaustive]
pub struct GoogleThinkProvider {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub version: Option<GoogleVersion>,
pub model: GoogleModel,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub temperature: Option<f64>,
}
impl GoogleThinkProvider {
pub fn new(model: GoogleModel) -> Self {
Self {
version: None,
model,
temperature: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum GoogleVersion {
#[serde(rename = "ai-studio-v1beta")]
AiStudioV1Beta,
#[serde(rename = "gemini-enterprise-agent-v1")]
GeminiEnterpriseAgentV1,
#[serde(rename = "v1beta")]
V1Beta,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub enum GoogleModel {
Gemini20Flash,
Gemini20FlashLite,
Gemini25Flash,
Other(String),
}
impl GoogleModel {
pub fn as_str(&self) -> &str {
match self {
Self::Gemini20Flash => "gemini-2.0-flash",
Self::Gemini20FlashLite => "gemini-2.0-flash-lite",
Self::Gemini25Flash => "gemini-2.5-flash",
Self::Other(s) => s,
}
}
}
impl From<String> for GoogleModel {
fn from(value: String) -> Self {
match value.as_str() {
"gemini-2.0-flash" => Self::Gemini20Flash,
"gemini-2.0-flash-lite" => Self::Gemini20FlashLite,
"gemini-2.5-flash" => Self::Gemini25Flash,
_ => Self::Other(value),
}
}
}
impl Serialize for GoogleModel {
fn serialize<S: Serializer>(&self, ser: S) -> Result<S::Ok, S::Error> {
ser.serialize_str(self.as_str())
}
}
impl<'de> Deserialize<'de> for GoogleModel {
fn deserialize<D: Deserializer<'de>>(de: D) -> Result<Self, D::Error> {
Ok(Self::from(String::deserialize(de)?))
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn round_trip() {
let raw = json!({
"version": "v1beta",
"model": "gemini-2.5-flash",
"temperature": 1.2,
});
let p: GoogleThinkProvider = serde_json::from_value(raw.clone()).unwrap();
assert_eq!(p.model, GoogleModel::Gemini25Flash);
assert_eq!(serde_json::to_value(&p).unwrap(), raw);
}
#[test]
fn version_wire_strings_match_spec() {
let cases = [
(GoogleVersion::AiStudioV1Beta, "ai-studio-v1beta"),
(
GoogleVersion::GeminiEnterpriseAgentV1,
"gemini-enterprise-agent-v1",
),
(GoogleVersion::V1Beta, "v1beta"),
];
for (version, wire) in cases {
assert_eq!(
serde_json::to_string(&version).unwrap(),
format!("\"{wire}\"")
);
let back: GoogleVersion = serde_json::from_str(&format!("\"{wire}\"")).unwrap();
assert_eq!(back, version);
}
let mut p = GoogleThinkProvider::new(GoogleModel::Gemini25Flash);
p.version = Some(GoogleVersion::GeminiEnterpriseAgentV1);
assert_eq!(
serde_json::to_string(&p).unwrap(),
r#"{"version":"gemini-enterprise-agent-v1","model":"gemini-2.5-flash"}"#
);
}
}