use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct ToolCall {
#[serde(default)]
pub id: String,
#[serde(rename = "type", default)]
pub kind: String,
pub function: FunctionCall,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub index: Option<u32>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FunctionCall {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub arguments: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Tool {
Function {
function: FunctionDef,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FunctionDef {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub description: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub parameters: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub strict: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum ToolChoice {
Mode(String),
Specific {
#[serde(rename = "type")]
kind: String,
function: FunctionRef,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FunctionRef {
pub name: String,
}
impl ToolChoice {
pub fn auto() -> Self {
ToolChoice::Mode("auto".to_string())
}
pub fn none() -> Self {
ToolChoice::Mode("none".to_string())
}
pub fn required() -> Self {
ToolChoice::Mode("required".to_string())
}
pub fn function(name: impl Into<String>) -> Self {
ToolChoice::Specific {
kind: "function".to_string(),
function: FunctionRef { name: name.into() },
}
}
}
impl Tool {
pub fn function(def: FunctionDef) -> Self {
Tool::Function { function: def }
}
}
impl FunctionDef {
pub fn new(name: impl Into<String>, parameters: serde_json::Value) -> Self {
Self {
name: name.into(),
description: None,
parameters: Some(parameters),
strict: None,
}
}
pub fn with_description(mut self, description: impl Into<String>) -> Self {
self.description = Some(description.into());
self
}
pub fn with_strict(mut self, strict: bool) -> Self {
self.strict = Some(strict);
self
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum ResponseFormat {
Text,
JsonObject,
JsonSchema {
json_schema: JsonSchema,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct JsonSchema {
pub name: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub description: Option<String>,
pub schema: serde_json::Value,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub strict: Option<bool>,
}
impl ResponseFormat {
pub fn json_object() -> Self {
ResponseFormat::JsonObject
}
pub fn json_schema(name: impl Into<String>, strict: bool, schema: serde_json::Value) -> Self {
ResponseFormat::JsonSchema {
json_schema: JsonSchema {
name: name.into(),
description: None,
schema,
strict: Some(strict),
},
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Provider {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub order: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub allow_fallbacks: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub require_parameters: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub data_collection: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub only: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub ignore: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub quantizations: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub sort: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub max_price: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub zdr: Option<bool>,
}
impl Provider {
pub fn new() -> Self {
Self::default()
}
pub fn with_order<S, I>(mut self, order: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.order = Some(order.into_iter().map(Into::into).collect());
self
}
pub fn with_sort(mut self, sort: impl Into<String>) -> Self {
self.sort = Some(sort.into());
self
}
pub fn with_allow_fallbacks(mut self, allow: bool) -> Self {
self.allow_fallbacks = Some(allow);
self
}
pub fn with_only<S, I>(mut self, only: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.only = Some(only.into_iter().map(Into::into).collect());
self
}
pub fn with_ignore<S, I>(mut self, ignore: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.ignore = Some(ignore.into_iter().map(Into::into).collect());
self
}
pub fn with_quantizations<S, I>(mut self, q: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.quantizations = Some(q.into_iter().map(Into::into).collect());
self
}
pub fn with_max_price(mut self, price: serde_json::Value) -> Self {
self.max_price = Some(price);
self
}
pub fn with_data_collection(mut self, policy: impl Into<String>) -> Self {
self.data_collection = Some(policy.into());
self
}
pub fn with_require_parameters(mut self, required: bool) -> Self {
self.require_parameters = Some(required);
self
}
pub fn with_zdr(mut self, zdr: bool) -> Self {
self.zdr = Some(zdr);
self
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct ReasoningConfig {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub effort: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub max_tokens: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub exclude: Option<bool>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "id", rename_all = "kebab-case")]
pub enum Plugin {
Web(WebPluginConfig),
#[serde(rename = "file-parser")]
File(FilePluginConfig),
}
impl Plugin {
pub fn web() -> Self {
Plugin::Web(WebPluginConfig::default())
}
pub fn web_with(config: WebPluginConfig) -> Self {
Plugin::Web(config)
}
pub fn file_parser(pdf_engine: Option<&str>) -> Self {
let pdf = pdf_engine.map(|e| FilePdfConfig {
engine: Some(e.to_string()),
});
Plugin::File(FilePluginConfig { pdf })
}
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct FilePluginConfig {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub pdf: Option<FilePdfConfig>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct FilePdfConfig {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub engine: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct WebPluginConfig {
#[serde(skip_serializing_if = "Option::is_none", default)]
pub max_results: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub search_prompt: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub engine: Option<String>,
}
impl WebPluginConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_max_results(mut self, n: u32) -> Self {
self.max_results = Some(n);
self
}
pub fn with_search_prompt(mut self, prompt: impl Into<String>) -> Self {
self.search_prompt = Some(prompt.into());
self
}
pub fn with_engine(mut self, engine: impl Into<String>) -> Self {
self.engine = Some(engine.into());
self
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum Annotation {
UrlCitation {
url_citation: UrlCitation,
},
File {
file: FileAnnotation,
},
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct FileAnnotation {
pub filename: String,
pub file_data: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct UrlCitation {
pub url: String,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub title: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub content: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub start_index: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none", default)]
pub end_index: Option<u32>,
}
impl ReasoningConfig {
pub fn new() -> Self {
Self::default()
}
pub fn with_effort(mut self, effort: impl Into<String>) -> Self {
self.effort = Some(effort.into());
self
}
pub fn with_max_tokens(mut self, max_tokens: u32) -> Self {
self.max_tokens = Some(max_tokens);
self
}
pub fn with_exclude(mut self, exclude: bool) -> Self {
self.exclude = Some(exclude);
self
}
}