use serde::{Deserialize, Serialize};
use crate::message::Message;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ToolSpec {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
impl ToolSpec {
pub fn new(
name: impl Into<String>,
description: impl Into<String>,
parameters: serde_json::Value,
) -> Self {
Self {
name: name.into(),
description: description.into(),
parameters,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
#[serde(rename_all = "lowercase")]
pub enum ThinkingEffort {
#[default]
Default,
Low,
Medium,
High,
}
impl ThinkingEffort {
pub fn as_str(self) -> &'static str {
match self {
Self::Default => "default",
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
}
}
pub fn parse(text: &str) -> Option<Self> {
match text.trim().to_lowercase().as_str() {
"default" => Some(Self::Default),
"low" => Some(Self::Low),
"medium" => Some(Self::Medium),
"high" => Some(Self::High),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Default)]
pub struct ChatParams {
pub model: String,
pub temperature: Option<f32>,
pub max_tokens: Option<u32>,
#[serde(default)]
pub thinking: ThinkingEffort,
}
impl ChatParams {
pub fn new(model: impl Into<String>) -> Self {
Self {
model: model.into(),
..Default::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ModelRequest {
pub system: Option<String>,
pub messages: Vec<Message>,
pub tools: Vec<ToolSpec>,
pub params: ChatParams,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn levels_parse_and_round_trip_through_serde() {
assert_eq!(ThinkingEffort::parse(" High "), Some(ThinkingEffort::High));
assert_eq!(ThinkingEffort::parse("low"), Some(ThinkingEffort::Low));
assert_eq!(ThinkingEffort::parse("maximal"), None);
assert_eq!(ThinkingEffort::default(), ThinkingEffort::Default);
let params = ChatParams {
thinking: ThinkingEffort::High,
..ChatParams::new("m")
};
let json = serde_json::to_string(¶ms).unwrap();
assert!(json.contains("\"thinking\":\"high\""), "{json}");
assert_eq!(serde_json::from_str::<ChatParams>(&json).unwrap(), params);
let legacy: ChatParams = serde_json::from_str(r#"{"model":"m"}"#).unwrap();
assert_eq!(legacy.thinking, ThinkingEffort::Default);
}
}