use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionCall {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub name: String,
#[serde(default)]
pub args: Value,
#[serde(
default,
skip_serializing_if = "Option::is_none",
rename = "thoughtSignature"
)]
pub thought_signature: Option<String>,
}
impl FunctionCall {
pub fn new(name: impl Into<String>, args: Value) -> Self {
Self {
id: None,
name: name.into(),
args,
thought_signature: None,
}
}
#[must_use]
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum Scheduling {
Silent,
WhenIdle,
Interrupt,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct FunctionResponse {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub id: Option<String>,
pub name: String,
#[serde(default)]
pub response: Value,
#[serde(
default,
skip_serializing_if = "Option::is_none",
rename = "willContinue"
)]
pub will_continue: Option<bool>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub scheduling: Option<Scheduling>,
}
impl FunctionResponse {
pub fn new(name: impl Into<String>, response: Value) -> Self {
Self {
id: None,
name: name.into(),
response,
will_continue: None,
scheduling: None,
}
}
#[must_use]
pub fn with_id(mut self, id: impl Into<String>) -> Self {
self.id = Some(id.into());
self
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn function_call_round_trips() {
let fc = FunctionCall::new("get_weather", json!({"city": "Paris"})).with_id("call-1");
let j = serde_json::to_value(&fc).unwrap();
assert_eq!(j["name"], "get_weather");
assert_eq!(j["id"], "call-1");
let back: FunctionCall = serde_json::from_value(j).unwrap();
assert_eq!(back, fc);
}
#[test]
fn function_response_omits_unset_optionals() {
let fr = FunctionResponse::new("noop", json!({"ok": true}));
let j = serde_json::to_string(&fr).unwrap();
assert!(!j.contains("willContinue"));
assert!(!j.contains("scheduling"));
assert!(!j.contains(r#""id""#));
}
}