Skip to main content

agent_base/types/
message.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
4pub enum MessageRole {
5    System,
6    User,
7    Assistant,
8    Tool,
9}
10
11impl MessageRole {
12    pub fn as_str(&self) -> &'static str {
13        match self {
14            MessageRole::System => "system",
15            MessageRole::User => "user",
16            MessageRole::Assistant => "assistant",
17            MessageRole::Tool => "tool",
18        }
19    }
20
21    pub fn as_api_role(&self) -> &'static str {
22        self.as_str()
23    }
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct Message {
28    pub role: MessageRole,
29    pub content: String,
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize)]
33pub enum ChatMessage {
34    System {
35        content: String,
36    },
37    User {
38        content: String,
39        #[serde(default, skip_serializing_if = "Vec::is_empty")]
40        images: Vec<ImageAttachment>,
41    },
42    Assistant {
43        content: Option<String>,
44        reasoning_content: Option<String>,
45        tool_calls: Option<Vec<ToolCallMessage>>,
46    },
47    Tool {
48        tool_call_id: String,
49        content: String,
50    },
51}
52
53#[derive(Clone, Debug, Serialize, Deserialize)]
54pub struct ToolCallMessage {
55    pub id: String,
56    pub name: String,
57    pub arguments: String,
58}
59
60#[derive(Clone, Debug, Serialize, Deserialize)]
61pub enum ImageAttachment {
62    Url {
63        url: String,
64        #[serde(default, skip_serializing_if = "Option::is_none")]
65        detail: Option<ImageDetail>,
66    },
67    Base64 {
68        data: String,
69        #[serde(default, skip_serializing_if = "Option::is_none")]
70        media_type: Option<String>,
71        #[serde(default, skip_serializing_if = "Option::is_none")]
72        detail: Option<ImageDetail>,
73    },
74}
75
76#[derive(Clone, Debug, Serialize, Deserialize)]
77pub enum ImageDetail {
78    Low,
79    High,
80    Auto,
81}
82
83impl ChatMessage {
84    pub fn system(content: impl Into<String>) -> Self {
85        Self::System {
86            content: content.into(),
87        }
88    }
89
90    pub fn user(content: impl Into<String>) -> Self {
91        Self::User {
92            content: content.into(),
93            images: Vec::new(),
94        }
95    }
96
97    pub fn user_with_images(content: impl Into<String>, images: Vec<ImageAttachment>) -> Self {
98        Self::User {
99            content: content.into(),
100            images,
101        }
102    }
103
104    pub fn assistant(content: impl Into<String>) -> Self {
105        Self::Assistant {
106            content: Some(content.into()),
107            reasoning_content: None,
108            tool_calls: None,
109        }
110    }
111
112    pub fn assistant_with_reasoning(
113        content: impl Into<String>,
114        reasoning: impl Into<String>,
115    ) -> Self {
116        Self::Assistant {
117            content: Some(content.into()),
118            reasoning_content: Some(reasoning.into()),
119            tool_calls: None,
120        }
121    }
122
123    pub fn assistant_tool_call(tool_call_id: impl Into<String>, tool_name: impl Into<String>, arguments: impl Into<String>) -> Self {
124        Self::Assistant {
125            content: None,
126            reasoning_content: None,
127            tool_calls: Some(vec![ToolCallMessage {
128                id: tool_call_id.into(),
129                name: tool_name.into(),
130                arguments: arguments.into(),
131            }]),
132        }
133    }
134
135    pub fn tool(tool_call_id: impl Into<String>, content: impl Into<String>) -> Self {
136        Self::Tool {
137            tool_call_id: tool_call_id.into(),
138            content: content.into(),
139        }
140    }
141}