use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct ChatRequest {
pub model: String,
pub messages: Vec<crate::Message>,
pub tools: Option<Vec<ToolDefinition>>,
pub temperature: Option<f64>,
pub max_tokens: Option<u32>,
pub top_p: Option<f64>,
pub seed: Option<u64>,
pub tool_choice: Option<ToolChoice>,
pub stop_sequences: Option<Vec<String>>,
pub prefill: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub reasoning: Option<ReasoningConfig>,
#[serde(skip_serializing_if = "Option::is_none")]
pub max_reasoning_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub extra: Option<serde_json::Map<String, serde_json::Value>>,
}
impl ChatRequest {
pub fn user_prompt(prompt: String) -> Self {
Self {
messages: vec![crate::Message::User {
content: crate::text_block(prompt),
}],
..Default::default()
}
}
pub fn with_temperature(mut self, temp: f64) -> Self {
self.temperature = Some(temp);
self
}
pub fn with_max_tokens(mut self, max: u32) -> Self {
self.max_tokens = Some(max);
self
}
pub fn with_top_p(mut self, top_p: f64) -> Self {
self.top_p = Some(top_p);
self
}
pub fn with_seed(mut self, seed: u64) -> Self {
self.seed = Some(seed);
self
}
pub fn with_model(mut self, model: String) -> Self {
self.model = model;
self
}
pub fn with_tools(mut self, tools: Vec<ToolDefinition>) -> Self {
self.tools = Some(tools);
self
}
pub fn with_system_prompt(mut self, prompt: String) -> Self {
self.messages.insert(
0,
crate::Message::System {
content: crate::text_block(prompt),
},
);
self
}
pub fn with_reasoning(mut self, reasoning: ReasoningConfig) -> Self {
self.reasoning = Some(reasoning);
self
}
pub fn with_max_reasoning_tokens(mut self, max: u32) -> Self {
self.max_reasoning_tokens = Some(max);
self
}
pub fn with_extra(mut self, extra: serde_json::Map<String, serde_json::Value>) -> Self {
self.extra = Some(extra);
self
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ToolChoice {
Tool { name: String },
Any,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolDefinition {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_control: Option<crate::message::CacheControl>,
}
impl ToolDefinition {
pub fn with_cache(self, cache: crate::message::CacheControl) -> Self {
Self {
cache_control: Some(cache),
..self
}
}
pub fn compute_and_clean_schema<S: schemars::JsonSchema>() -> serde_json::Value {
let root = schemars::schema_for!(S);
let val = serde_json::to_value(&root)
.expect("Failed to serialize JsonSchema; this is a bug in schemars");
Self::clean_schema(val)
}
fn clean_schema(mut value: serde_json::Value) -> serde_json::Value {
if let Some(obj) = value.as_object_mut() {
obj.remove("$schema");
obj.remove("$id");
obj.remove("title");
obj.remove("description");
}
value
}
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
pub enum ReasoningConfig {
Disabled,
Low,
Medium,
High,
}
impl ReasoningConfig {
pub fn is_disabled(self) -> bool {
matches!(self, Self::Disabled)
}
}