use crate::chat::{ContentPart, MessageContent, ToolCall, ToolResponse};
use derive_more::From;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ChatMessage {
pub role: ChatRole,
pub content: MessageContent,
pub options: Option<MessageOptions>,
}
impl ChatMessage {
pub fn system(content: impl Into<MessageContent>) -> Self {
Self {
role: ChatRole::System,
content: content.into(),
options: None,
}
}
pub fn assistant(content: impl Into<MessageContent>) -> Self {
Self {
role: ChatRole::Assistant,
content: content.into(),
options: None,
}
}
pub fn user(content: impl Into<MessageContent>) -> Self {
Self {
role: ChatRole::User,
content: content.into(),
options: None,
}
}
}
impl ChatMessage {
pub fn size(&self) -> usize {
self.content.size()
}
}
impl ChatMessage {
pub fn with_options(mut self, options: impl Into<MessageOptions>) -> Self {
self.options = Some(options.into());
self
}
pub fn assistant_tool_calls_with_thoughts(tool_calls: Vec<ToolCall>, thought_signatures: Vec<String>) -> Self {
let mut parts: Vec<ContentPart> = thought_signatures.into_iter().map(ContentPart::ThoughtSignature).collect();
parts.extend(tool_calls.into_iter().map(ContentPart::ToolCall));
ChatMessage::assistant(MessageContent::from_parts(parts))
}
}
#[derive(Debug, Clone, Serialize, Deserialize, From)]
pub struct MessageOptions {
#[from]
pub cache_control: Option<CacheControl>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum CacheControl {
Ephemeral,
}
impl From<CacheControl> for MessageOptions {
fn from(cache_control: CacheControl) -> Self {
Self {
cache_control: Some(cache_control),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, derive_more::Display)]
#[allow(missing_docs)]
pub enum ChatRole {
System,
User,
Assistant,
Tool,
}
impl From<Vec<ToolCall>> for ChatMessage {
fn from(tool_calls: Vec<ToolCall>) -> Self {
if let Some(first) = tool_calls.first()
&& let Some(thoughts) = &first.thought_signatures
{
let mut parts: Vec<ContentPart> = thoughts.iter().cloned().map(ContentPart::ThoughtSignature).collect();
parts.extend(tool_calls.into_iter().map(ContentPart::ToolCall));
return ChatMessage::assistant(MessageContent::from_parts(parts));
}
Self {
role: ChatRole::Assistant,
content: MessageContent::from(tool_calls),
options: None,
}
}
}
impl From<ToolResponse> for ChatMessage {
fn from(value: ToolResponse) -> Self {
Self {
role: ChatRole::Tool,
content: MessageContent::from(value),
options: None,
}
}
}