Skip to main content

recursive/
message.rs

1//! Chat message primitive.
2//!
3//! A `Message` mirrors the wire format that most chat completion APIs use,
4//! but stays provider-agnostic. Providers translate to/from their own shape
5//! in their adapter.
6
7use serde::{Deserialize, Serialize};
8
9use crate::llm::ToolCall;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Role {
14    System,
15    User,
16    Assistant,
17    Tool,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct Message {
22    pub role: Role,
23    pub content: String,
24    #[serde(default, skip_serializing_if = "Vec::is_empty")]
25    pub tool_calls: Vec<ToolCall>,
26    #[serde(default, skip_serializing_if = "Option::is_none")]
27    pub tool_call_id: Option<String>,
28}
29
30impl Message {
31    pub fn system(content: impl Into<String>) -> Self {
32        Self {
33            role: Role::System,
34            content: content.into(),
35            tool_calls: Vec::new(),
36            tool_call_id: None,
37        }
38    }
39
40    pub fn user(content: impl Into<String>) -> Self {
41        Self {
42            role: Role::User,
43            content: content.into(),
44            tool_calls: Vec::new(),
45            tool_call_id: None,
46        }
47    }
48
49    pub fn assistant(content: impl Into<String>) -> Self {
50        Self {
51            role: Role::Assistant,
52            content: content.into(),
53            tool_calls: Vec::new(),
54            tool_call_id: None,
55        }
56    }
57
58    pub fn assistant_with_tool_calls(
59        content: impl Into<String>,
60        tool_calls: Vec<ToolCall>,
61    ) -> Self {
62        Self {
63            role: Role::Assistant,
64            content: content.into(),
65            tool_calls,
66            tool_call_id: None,
67        }
68    }
69
70    pub fn tool_result(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
71        Self {
72            role: Role::Tool,
73            content: content.into(),
74            tool_calls: Vec::new(),
75            tool_call_id: Some(tool_call_id.into()),
76        }
77    }
78}