use crate::models::content::Content;
use crate::tools::{ToolCall, ToolResponse};
use serde::{Deserialize, Serialize};
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Serialize, Deserialize, derive_more::Display)]
pub enum Role {
System,
User,
Assistant,
Tool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Event {
role: Role,
content: Content,
}
impl Event {
pub fn system(content: impl Into<Content>) -> Self {
Self {
role: Role::System,
content: content.into(),
}
}
pub fn assistant(content: impl Into<Content>) -> Self {
Self {
role: Role::Assistant,
content: content.into(),
}
}
pub fn user(content: impl Into<Content>) -> Self {
Self {
role: Role::User,
content: content.into(),
}
}
#[must_use]
pub const fn role(&self) -> &Role {
&self.role
}
#[must_use]
pub const fn content(&self) -> &Content {
&self.content
}
#[must_use]
pub fn into_content(self) -> Content {
self.content
}
#[must_use]
pub fn into_parts(self) -> (Role, Content) {
(self.role, self.content)
}
}
impl From<Vec<ToolCall>> for Event {
fn from(tool_calls: Vec<ToolCall>) -> Self {
Self {
role: Role::Assistant,
content: Content::from(tool_calls),
}
}
}
impl From<ToolResponse> for Event {
fn from(value: ToolResponse) -> Self {
Self {
role: Role::Tool,
content: Content::from(value),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tools::{ToolCall, ToolResponse, ToolResult};
use serde_json::json;
#[test]
fn constructors_assign_roles() {
assert!(matches!(Event::system("sys").role(), Role::System));
assert!(matches!(Event::user("user").role(), Role::User));
assert!(matches!(
Event::assistant("assistant").role(),
Role::Assistant
));
}
#[test]
fn event_from_tool_artifacts_sets_roles() {
let call = ToolCall::new("id", "tool", json!({}));
let event = Event::from(vec![call]);
assert!(matches!(event.role(), Role::Assistant));
assert!(event.content().has_tool_calls());
let response = ToolResponse::new("id", ToolResult::success(json!({"ok": true})));
let tool_event = Event::from(response);
assert!(matches!(tool_event.role(), Role::Tool));
assert!(tool_event.content().has_tool_responses());
}
#[test]
fn into_parts_returns_role_and_content() {
let event = Event::assistant("Done");
let (role, content) = event.into_parts();
assert!(matches!(role, Role::Assistant));
assert_eq!(content.first_text(), Some("Done"));
}
}