Skip to main content

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}