Skip to main content

caliban_provider/
message.rs

1//! Core message types: roles, messages, content blocks.
2
3use serde::{Deserialize, Serialize};
4
5use crate::cache::CacheControl;
6use crate::thinking::ThinkingBlock;
7use crate::tool::{ToolResultBlock, ToolUseBlock};
8
9/// The conversational role of a message.
10#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
11#[serde(rename_all = "lowercase")]
12pub enum Role {
13    /// A message from the end user.
14    User,
15    /// A message generated by the assistant.
16    Assistant,
17    /// An instruction message that precedes the conversation.
18    System,
19}
20
21/// A single turn in a conversation.
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct Message {
24    /// The role of the speaker.
25    pub role: Role,
26    /// The content of the message as an ordered list of blocks.
27    pub content: Vec<ContentBlock>,
28}
29
30impl Message {
31    /// Construct a single-block user text message.
32    pub fn user_text(text: impl Into<String>) -> Self {
33        Self {
34            role: Role::User,
35            content: vec![ContentBlock::Text(TextBlock {
36                text: text.into(),
37                cache_control: None,
38            })],
39        }
40    }
41
42    /// Construct a single-block assistant text message.
43    pub fn assistant_text(text: impl Into<String>) -> Self {
44        Self {
45            role: Role::Assistant,
46            content: vec![ContentBlock::Text(TextBlock {
47                text: text.into(),
48                cache_control: None,
49            })],
50        }
51    }
52
53    /// Construct a single-block system text message.
54    pub fn system_text(text: impl Into<String>) -> Self {
55        Self {
56            role: Role::System,
57            content: vec![ContentBlock::Text(TextBlock {
58                text: text.into(),
59                cache_control: None,
60            })],
61        }
62    }
63}
64
65/// A typed content block within a message.
66#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
67#[serde(tag = "type", rename_all = "snake_case")]
68pub enum ContentBlock {
69    /// A plain-text block.
70    Text(TextBlock),
71    /// An image block.
72    Image(ImageBlock),
73    /// A tool-use invocation block.
74    ToolUse(ToolUseBlock),
75    /// A tool-result block.
76    ToolResult(ToolResultBlock),
77    /// An extended-thinking block.
78    Thinking(ThinkingBlock),
79}
80
81/// A plain-text content block.
82#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
83pub struct TextBlock {
84    /// The text content.
85    pub text: String,
86    /// Optional cache-control marker.
87    #[serde(skip_serializing_if = "Option::is_none", default)]
88    pub cache_control: Option<CacheControl>,
89}
90
91/// An image content block.
92#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
93pub struct ImageBlock {
94    /// The source of the image data.
95    pub source: ImageSource,
96    /// Optional cache-control marker.
97    #[serde(skip_serializing_if = "Option::is_none", default)]
98    pub cache_control: Option<CacheControl>,
99    /// SHA-256 fingerprint (64-char hex) of the (post-resize) image bytes.
100    /// Populated by [`caliban-images`] at ingest time; the provider IR
101    /// itself does not require it.
102    #[serde(skip_serializing_if = "Option::is_none", default)]
103    pub sha256: Option<String>,
104    /// (width, height) in pixels, populated at ingest.
105    #[serde(skip_serializing_if = "Option::is_none", default)]
106    pub dims: Option<(u32, u32)>,
107}
108
109/// The source of image data.
110#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
111#[serde(tag = "type", rename_all = "snake_case")]
112pub enum ImageSource {
113    /// Base64-encoded image with a MIME type.
114    Base64 {
115        /// MIME type of the image (e.g. `"image/png"`).
116        media_type: String,
117        /// Base64-encoded image bytes.
118        data: String,
119    },
120    /// A URL pointing to the image.
121    Url {
122        /// The URL of the image.
123        url: String,
124    },
125    /// A reference to a session-local blob, identified by SHA-256.
126    ///
127    /// **Never** sent to a provider: provider adapters must reject `BlobRef`
128    /// (or, equivalently, the session loader resolves it to
129    /// [`ImageSource::Base64`] before dispatch). Round-trips through
130    /// `serde_json` because session storage persists this variant on-disk.
131    BlobRef {
132        /// SHA-256 fingerprint (64-char hex).
133        sha256: String,
134        /// MIME type of the referenced blob.
135        media_type: String,
136    },
137}