Skip to main content

llm_cascade/models/
conversation.rs

1//! Conversation and message types.
2
3use serde::{Deserialize, Serialize};
4
5use crate::models::ToolDefinition;
6
7/// The role of a message sender.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9#[serde(rename_all = "lowercase")]
10pub enum MessageRole {
11    /// System instructions that set context for the assistant.
12    System,
13    /// User input.
14    User,
15    /// Assistant response.
16    Assistant,
17    /// Tool execution result.
18    Tool,
19}
20
21impl std::fmt::Display for MessageRole {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            MessageRole::System => write!(f, "system"),
25            MessageRole::User => write!(f, "user"),
26            MessageRole::Assistant => write!(f, "assistant"),
27            MessageRole::Tool => write!(f, "tool"),
28        }
29    }
30}
31
32/// A single message in a conversation.
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct Message {
35    /// The sender's role.
36    pub role: MessageRole,
37    /// Text content of the message.
38    pub content: String,
39    /// Associates a tool result with its originating tool call. Only set when `role` is `Tool`.
40    #[serde(skip_serializing_if = "Option::is_none")]
41    pub tool_call_id: Option<String>,
42}
43
44impl Message {
45    /// Creates a system message.
46    pub fn system(content: impl Into<String>) -> Self {
47        Self {
48            role: MessageRole::System,
49            content: content.into(),
50            tool_call_id: None,
51        }
52    }
53
54    /// Creates a user message.
55    pub fn user(content: impl Into<String>) -> Self {
56        Self {
57            role: MessageRole::User,
58            content: content.into(),
59            tool_call_id: None,
60        }
61    }
62
63    /// Creates an assistant message.
64    pub fn assistant(content: impl Into<String>) -> Self {
65        Self {
66            role: MessageRole::Assistant,
67            content: content.into(),
68            tool_call_id: None,
69        }
70    }
71
72    /// Creates a tool result message, associated with a tool call ID.
73    pub fn tool(content: impl Into<String>, tool_call_id: impl Into<String>) -> Self {
74        Self {
75            role: MessageRole::Tool,
76            content: content.into(),
77            tool_call_id: Some(tool_call_id.into()),
78        }
79    }
80}
81
82/// An ordered list of messages, optionally with tool definitions.
83#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct Conversation {
85    /// The conversation messages.
86    pub messages: Vec<Message>,
87    /// Optional tool definitions to pass to the provider.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub tools: Option<Vec<ToolDefinition>>,
90}
91
92impl Conversation {
93    /// Creates a new conversation from a list of messages.
94    pub fn new(messages: Vec<Message>) -> Self {
95        Self {
96            messages,
97            tools: None,
98        }
99    }
100
101    /// Attaches tool definitions to the conversation.
102    pub fn with_tools(mut self, tools: Vec<ToolDefinition>) -> Self {
103        self.tools = Some(tools);
104        self
105    }
106
107    /// Convenience constructor for a single-user-prompt conversation.
108    pub fn single_user_prompt(prompt: impl Into<String>) -> Self {
109        Self {
110            messages: vec![Message::user(prompt.into())],
111            tools: None,
112        }
113    }
114}