open_agent/types/message_blocks.rs
1/// Identifies the sender/role of a message in the conversation.
2///
3/// This enum follows the standard chat completion role system used by most
4/// LLM APIs. The role determines how the message is interpreted and processed.
5///
6/// # Serialization
7///
8/// Serializes to lowercase strings via serde (`"system"`, `"user"`, etc.)
9/// to match OpenAI API format.
10///
11/// # Role Semantics
12///
13/// - [`System`](MessageRole::System): Establishes context, instructions, and behavior
14/// - [`User`](MessageRole::User): Input from the human or calling application
15/// - [`Assistant`](MessageRole::Assistant): Response from the AI model
16/// - [`Tool`](MessageRole::Tool): Results from tool/function execution
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
18#[serde(rename_all = "lowercase")]
19pub enum MessageRole {
20 /// System message that establishes agent behavior and context.
21 ///
22 /// Typically the first message in a conversation. Used for instructions,
23 /// personality definition, and constraints that apply throughout the
24 /// conversation.
25 System,
26
27 /// User message representing human or application input.
28 ///
29 /// The prompt or query that the agent should respond to. In multi-turn
30 /// conversations, user messages alternate with assistant messages.
31 User,
32
33 /// Assistant message containing the AI model's response.
34 ///
35 /// Can include text, tool use requests, or both. When the model wants to
36 /// call a tool, it includes ToolUseBlock content.
37 Assistant,
38
39 /// Tool result message containing function execution results.
40 ///
41 /// Sent back to the model after executing a requested tool. Contains the
42 /// tool's output that the model can use in its next response.
43 Tool,
44}
45
46/// Multi-modal content blocks that can appear in messages.
47///
48/// Messages are composed of one or more content blocks, allowing rich,
49/// structured communication between the user, assistant, and tools.
50///
51/// # Serialization
52///
53/// Uses serde's "externally tagged" enum format with a `"type"` field:
54/// ```json
55/// {"type": "text", "text": "Hello"}
56/// {"type": "tool_use", "id": "call_123", "name": "search", "input": {...}}
57/// {"type": "tool_result", "tool_use_id": "call_123", "content": {...}}
58/// ```
59///
60/// # Block Types
61///
62/// - [`Text`](ContentBlock::Text): Simple text content
63/// - [`Image`](ContentBlock::Image): Image content (URL or base64)
64/// - [`ToolUse`](ContentBlock::ToolUse): Request from model to execute a tool
65/// - [`ToolResult`](ContentBlock::ToolResult): Result of tool execution
66///
67/// # Usage
68///
69/// Messages can contain multiple blocks. For example, a user message might
70/// include text and an image, or an assistant message might include text
71/// followed by a tool use request.
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(tag = "type", rename_all = "snake_case")]
74pub enum ContentBlock {
75 /// Text content block containing a string message.
76 Text(TextBlock),
77
78 /// Image content block for vision-capable models.
79 Image(ImageBlock),
80
81 /// Tool use request from the model to execute a function.
82 ToolUse(ToolUseBlock),
83
84 /// Tool execution result sent back to the model.
85 ToolResult(ToolResultBlock),
86}
87
88/// Simple text content in a message.
89///
90/// The most common content type, representing plain text communication.
91/// Both users and assistants primarily use text blocks for their messages.
92///
93/// # Example
94///
95/// ```
96/// use open_agent::{TextBlock, ContentBlock};
97///
98/// let block = TextBlock::new("Hello, world!");
99/// let content = ContentBlock::Text(block);
100/// ```
101#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct TextBlock {
103 /// The text content.
104 pub text: String,
105}
106
107impl TextBlock {
108 /// Creates a new text block from any string-like type.
109 ///
110 /// # Example
111 ///
112 /// ```
113 /// use open_agent::TextBlock;
114 ///
115 /// let block = TextBlock::new("Hello");
116 /// assert_eq!(block.text, "Hello");
117 /// ```
118 pub fn new(text: impl Into<String>) -> Self {
119 Self { text: text.into() }
120 }
121}
122
123/// Tool use request from the AI model.
124///
125/// When the model determines it needs to call a tool/function, it returns
126/// a ToolUseBlock specifying which tool to call and with what parameters.
127/// The application must then execute the tool and return results via
128/// [`ToolResultBlock`].
129///
130/// # Fields
131///
132/// - `id`: Unique identifier for this tool call, used to correlate results
133/// - `name`: Name of the tool to execute (must match a registered tool)
134/// - `input`: JSON parameters to pass to the tool
135///
136/// # Example
137///
138/// ```
139/// use open_agent::{ToolUseBlock, ContentBlock};
140/// use serde_json::json;
141///
142/// let block = ToolUseBlock::new(
143/// "call_123",
144/// "calculate",
145/// json!({"expression": "2 + 2"})
146/// );
147/// assert_eq!(block.id(), "call_123");
148/// assert_eq!(block.name(), "calculate");
149/// ```
150#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct ToolUseBlock {
152 /// Unique identifier for this tool call.
153 ///
154 /// Generated by the model. Used to correlate the tool result back to
155 /// this specific request, especially when multiple tools are called.
156 id: String,
157
158 /// Name of the tool to execute.
159 ///
160 /// Must match the name of a tool that was provided in the agent's
161 /// configuration, otherwise execution will fail.
162 name: String,
163
164 /// JSON parameters to pass to the tool.
165 ///
166 /// The structure should match the tool's input schema. The tool's
167 /// execution function receives this value as input.
168 input: serde_json::Value,
169}
170
171impl ToolUseBlock {
172 /// Creates a new tool use block.
173 ///
174 /// # Parameters
175 ///
176 /// - `id`: Unique identifier for this tool call
177 /// - `name`: Name of the tool to execute
178 /// - `input`: JSON parameters for the tool
179 ///
180 /// # Example
181 ///
182 /// ```
183 /// use open_agent::ToolUseBlock;
184 /// use serde_json::json;
185 ///
186 /// let block = ToolUseBlock::new(
187 /// "call_abc",
188 /// "search",
189 /// json!({"query": "Rust async programming"})
190 /// );
191 /// ```
192 pub fn new(id: impl Into<String>, name: impl Into<String>, input: serde_json::Value) -> Self {
193 Self {
194 id: id.into(),
195 name: name.into(),
196 input,
197 }
198 }
199
200 /// Returns the unique identifier for this tool call.
201 pub fn id(&self) -> &str {
202 &self.id
203 }
204
205 /// Returns the name of the tool to execute.
206 pub fn name(&self) -> &str {
207 &self.name
208 }
209
210 /// Returns the JSON parameters for the tool.
211 pub fn input(&self) -> &serde_json::Value {
212 &self.input
213 }
214}
215
216/// Tool execution result sent back to the model.
217///
218/// After executing a tool requested via [`ToolUseBlock`], the application
219/// creates a ToolResultBlock containing the tool's output and sends it back
220/// to the model. The model then uses this information in its next response.
221///
222/// # Fields
223///
224/// - `tool_use_id`: Must match the `id` from the corresponding ToolUseBlock
225/// - `content`: JSON result from the tool execution
226///
227/// # Example
228///
229/// ```
230/// use open_agent::{ToolResultBlock, ContentBlock};
231/// use serde_json::json;
232///
233/// let result = ToolResultBlock::new(
234/// "call_123",
235/// json!({"result": 4})
236/// );
237/// assert_eq!(result.tool_use_id(), "call_123");
238/// ```
239#[derive(Debug, Clone, Serialize, Deserialize)]
240pub struct ToolResultBlock {
241 /// ID of the tool use request this result corresponds to.
242 ///
243 /// Must match the `id` field from the ToolUseBlock that requested
244 /// this tool execution. This correlation is essential for the model
245 /// to understand which tool call produced which result.
246 tool_use_id: String,
247
248 /// JSON result from executing the tool.
249 ///
250 /// Contains the tool's output data. Can be any valid JSON structure -
251 /// the model will interpret it based on the tool's description and
252 /// output schema.
253 content: serde_json::Value,
254}
255
256impl ToolResultBlock {
257 /// Creates a new tool result block.
258 ///
259 /// # Parameters
260 ///
261 /// - `tool_use_id`: ID from the corresponding ToolUseBlock
262 /// - `content`: JSON result from tool execution
263 ///
264 /// # Example
265 ///
266 /// ```
267 /// use open_agent::ToolResultBlock;
268 /// use serde_json::json;
269 ///
270 /// let result = ToolResultBlock::new(
271 /// "call_xyz",
272 /// json!({
273 /// "status": "success",
274 /// "data": {"temperature": 72}
275 /// })
276 /// );
277 /// ```
278 pub fn new(tool_use_id: impl Into<String>, content: serde_json::Value) -> Self {
279 Self {
280 tool_use_id: tool_use_id.into(),
281 content,
282 }
283 }
284
285 /// Returns the ID of the tool use request this result corresponds to.
286 pub fn tool_use_id(&self) -> &str {
287 &self.tool_use_id
288 }
289
290 /// Returns the JSON result from executing the tool.
291 pub fn content(&self) -> &serde_json::Value {
292 &self.content
293 }
294}