2026-07-19 17:05:27 +07:00
|
|
|
//! Chat message types shared across the entity layer.
|
|
|
|
|
//!
|
|
|
|
|
//! Provides [`Role`] (conversation participant) and [`ChatMessage`] (a single
|
|
|
|
|
//! message with optional tool-call metadata). Includes convenience constructors
|
|
|
|
|
//! for each role: `user`, `assistant`, `system`, `tool`/`tool_result`.
|
|
|
|
|
//!
|
|
|
|
|
//! # Flow
|
|
|
|
|
//!
|
|
|
|
|
//! Messages are constructed via the typed constructors → pushed into
|
|
|
|
|
//! [`Conversation`](super::conversation::Conversation) → serialized as JSON
|
|
|
|
|
//! to `conversation.json`.
|
2026-07-11 13:16:10 +07:00
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// The conversation participant who authored a message.
|
2026-07-19 17:05:27 +07:00
|
|
|
///
|
|
|
|
|
/// Variants: `User`, `Assistant`, `System`, `Tool`. Serialized as lowercase
|
|
|
|
|
/// strings (e.g. `"user"`, `"assistant"`, `"system"`, `"tool"`).
|
2026-07-11 13:16:10 +07:00
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
|
|
|
pub enum Role {
|
|
|
|
|
#[serde(rename = "user")]
|
|
|
|
|
User,
|
|
|
|
|
#[serde(rename = "assistant")]
|
|
|
|
|
Assistant,
|
|
|
|
|
#[serde(rename = "system")]
|
|
|
|
|
System,
|
|
|
|
|
#[serde(rename = "tool")]
|
|
|
|
|
Tool,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Role {
|
2026-07-16 07:42:03 +07:00
|
|
|
/// Return the role as a lowercase string.
|
|
|
|
|
pub fn as_str(&self) -> &'static str {
|
|
|
|
|
match self {
|
|
|
|
|
Role::User => "user",
|
|
|
|
|
Role::Assistant => "assistant",
|
|
|
|
|
Role::System => "system",
|
|
|
|
|
Role::Tool => "tool",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl std::fmt::Display for Role {
|
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
|
f.write_str(self.as_str())
|
|
|
|
|
}
|
2026-07-11 13:16:10 +07:00
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// A single message in a conversation, compatible with the OpenAI/Anthropic
|
|
|
|
|
/// chat-completion API structures.
|
2026-07-11 13:16:10 +07:00
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
|
|
|
pub struct ChatMessage {
|
2026-07-19 17:05:27 +07:00
|
|
|
/// Who sent this message (user, assistant, system, tool).
|
2026-07-11 13:16:10 +07:00
|
|
|
pub role: Role,
|
2026-07-19 17:05:27 +07:00
|
|
|
/// The message text content. `None` for assistant messages that only
|
|
|
|
|
/// contain tool calls.
|
2026-07-11 13:16:10 +07:00
|
|
|
pub content: Option<String>,
|
2026-07-19 17:05:27 +07:00
|
|
|
/// Tool-call requests attached to an assistant message (OpenAI-style).
|
2026-07-11 13:16:10 +07:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
2026-07-16 12:32:17 +07:00
|
|
|
pub tool_calls: Option<Vec<super::tool_call::ToolCall>>,
|
2026-07-19 17:05:27 +07:00
|
|
|
/// For tool-role messages: the `id` of the `ToolCall` being responded to.
|
2026-07-11 13:16:10 +07:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub tool_call_id: Option<String>,
|
2026-07-19 17:05:27 +07:00
|
|
|
/// Optional function name for the tool invocation.
|
2026-07-11 13:16:10 +07:00
|
|
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
|
|
|
pub name: Option<String>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl ChatMessage {
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Build a user-role message with the given text content.
|
2026-07-11 13:16:10 +07:00
|
|
|
pub fn user(content: impl Into<String>) -> Self {
|
|
|
|
|
ChatMessage {
|
|
|
|
|
role: Role::User,
|
|
|
|
|
content: Some(content.into()),
|
|
|
|
|
tool_calls: None,
|
|
|
|
|
tool_call_id: None,
|
|
|
|
|
name: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Build an assistant-role message with an optional text response.
|
2026-07-11 13:16:10 +07:00
|
|
|
pub fn assistant(content: Option<String>) -> Self {
|
|
|
|
|
ChatMessage {
|
|
|
|
|
role: Role::Assistant,
|
|
|
|
|
content,
|
|
|
|
|
tool_calls: None,
|
|
|
|
|
tool_call_id: None,
|
|
|
|
|
name: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Build a system-role message with the given instruction text.
|
2026-07-11 13:16:10 +07:00
|
|
|
pub fn system(content: impl Into<String>) -> Self {
|
|
|
|
|
ChatMessage {
|
|
|
|
|
role: Role::System,
|
|
|
|
|
content: Some(content.into()),
|
|
|
|
|
tool_calls: None,
|
|
|
|
|
tool_call_id: None,
|
|
|
|
|
name: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-12 11:28:39 +07:00
|
|
|
/// Build a tool-role result message referencing a prior tool call.
|
2026-07-16 12:32:17 +07:00
|
|
|
pub fn tool(tool_call_id: String, content: String) -> Self {
|
|
|
|
|
ChatMessage {
|
|
|
|
|
role: Role::Tool,
|
|
|
|
|
content: Some(content),
|
|
|
|
|
tool_calls: None,
|
|
|
|
|
tool_call_id: Some(tool_call_id),
|
|
|
|
|
name: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Alias for `tool`, used throughout the codebase for tool results.
|
2026-07-11 13:16:10 +07:00
|
|
|
pub fn tool_result(tool_call_id: String, content: String) -> Self {
|
|
|
|
|
ChatMessage {
|
|
|
|
|
role: Role::Tool,
|
|
|
|
|
content: Some(content),
|
|
|
|
|
tool_calls: None,
|
|
|
|
|
tool_call_id: Some(tool_call_id),
|
|
|
|
|
name: None,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|