use serde::{de::Error as _, Deserialize, Deserializer, Serialize, Serializer};
use super::{Metadata, TokenUsage, ToolArtifactRef, ToolCall};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum MessageRole {
System,
User,
Assistant,
Tool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Message {
pub role: MessageRole,
pub content: String,
pub name: Option<String>,
pub tool_call_id: Option<String>,
pub tool_calls: Vec<ToolCall>,
pub reasoning_content: Option<String>,
pub image_url: Option<String>,
pub metadata: Metadata,
pub artifact_ref: Option<ToolArtifactRef>,
}
impl Message {
pub fn new(role: MessageRole, content: impl Into<String>) -> Self {
Self {
role,
content: content.into(),
name: None,
tool_call_id: None,
tool_calls: Vec::new(),
reasoning_content: None,
image_url: None,
metadata: Metadata::new(),
artifact_ref: None,
}
}
pub fn system(content: impl Into<String>) -> Self {
Self::new(MessageRole::System, content)
}
pub fn user(content: impl Into<String>) -> Self {
Self::new(MessageRole::User, content)
}
pub fn assistant(content: impl Into<String>) -> Self {
Self::new(MessageRole::Assistant, content)
}
pub fn tool(content: impl Into<String>, tool_call_id: impl Into<String>) -> Self {
let mut message = Self::new(MessageRole::Tool, content);
message.tool_call_id = Some(tool_call_id.into());
message
}
}
impl Serialize for Message {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.to_dict().serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Message {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let value = serde_json::Value::deserialize(deserializer)?;
Self::from_dict(&value).map_err(D::Error::custom)
}
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct LLMResponse {
pub content: String,
pub tool_calls: Vec<ToolCall>,
pub raw: Metadata,
pub token_usage: TokenUsage,
}
impl LLMResponse {
pub fn new(content: impl Into<String>) -> Self {
Self {
content: content.into(),
tool_calls: Vec::new(),
raw: Metadata::new(),
token_usage: TokenUsage::default(),
}
}
pub fn with_tool_calls(content: impl Into<String>, tool_calls: Vec<ToolCall>) -> Self {
Self {
content: content.into(),
tool_calls,
raw: Metadata::new(),
token_usage: TokenUsage::default(),
}
}
}