use serde::{Deserialize, Serialize};
use uuid::Uuid;
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
#[serde(transparent)]
pub struct SessionId(pub Uuid);
impl SessionId {
#[must_use]
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl Default for SessionId {
fn default() -> Self {
Self::new()
}
}
impl std::fmt::Display for SessionId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.0)
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Role {
System,
User,
Assistant,
Tool,
}
impl Role {
#[must_use]
pub const fn as_wire_str(self) -> &'static str {
match self {
Self::System => "system",
Self::User => "user",
Self::Assistant => "assistant",
Self::Tool => "tool",
}
}
#[must_use]
pub fn from_wire_str(s: &str) -> Option<Self> {
Some(match s {
"system" => Self::System,
"user" => Self::User,
"assistant" => Self::Assistant,
"tool" => Self::Tool,
_ => return None,
})
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Message {
pub role: Role,
pub content: String,
#[serde(skip_serializing_if = "Vec::is_empty", default)]
pub tool_calls: Vec<ToolCall>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
pub server: String,
pub tool: String,
pub arguments: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolResult {
pub call_id: String,
pub content: serde_json::Value,
#[serde(default)]
pub is_error: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn session_id_is_unique() {
let a = SessionId::new();
let b = SessionId::new();
assert_ne!(a, b);
}
#[test]
fn message_serde_roundtrip() {
let msg = Message {
role: Role::Assistant,
content: "hello".into(),
tool_calls: vec![],
};
let json = serde_json::to_string(&msg).unwrap();
let back: Message = serde_json::from_str(&json).unwrap();
assert!(matches!(back.role, Role::Assistant));
assert_eq!(back.content, "hello");
}
}