Skip to main content

ai_agent/types/
message.rs

1// Source: ~/claudecode/openclaudecode/src/types/message.ts
2// Also includes: ~/claudecode/openclaudecode/src/utils/messages.ts (createAwaySummaryMessage)
3
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// Origin of a message.
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct MessageOrigin {
10    #[serde(rename = "kind", skip_serializing_if = "Option::is_none")]
11    pub kind: Option<String>,
12    #[serde(flatten)]
13    pub extra: HashMap<String, serde_json::Value>,
14}
15
16/// Base message type with common fields.
17#[derive(Debug, Clone, Serialize, Deserialize, Default)]
18pub struct MessageBase {
19    #[serde(skip_serializing_if = "Option::is_none")]
20    pub uuid: Option<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    #[serde(rename = "parentUuid")]
23    pub parent_uuid: Option<String>,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub timestamp: Option<String>,
26    #[serde(skip_serializing_if = "Option::is_none")]
27    #[serde(rename = "createdAt")]
28    pub created_at: Option<String>,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    #[serde(rename = "isMeta")]
31    pub is_meta: Option<bool>,
32    #[serde(skip_serializing_if = "Option::is_none")]
33    #[serde(rename = "isVirtual")]
34    pub is_virtual: Option<bool>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    #[serde(rename = "isCompactSummary")]
37    pub is_compact_summary: Option<bool>,
38    #[serde(skip_serializing_if = "Option::is_none")]
39    #[serde(rename = "toolUseResult")]
40    pub tool_use_result: Option<serde_json::Value>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub origin: Option<MessageOrigin>,
43    #[serde(flatten)]
44    pub extra: HashMap<String, serde_json::Value>,
45}
46
47/// Attachment message.
48#[derive(Debug, Clone, Serialize, Deserialize)]
49pub struct AttachmentMessage {
50    #[serde(flatten)]
51    pub base: MessageBase,
52    #[serde(rename = "type")]
53    pub message_type: String, // "attachment"
54    #[serde(skip_serializing_if = "Option::is_none")]
55    pub path: Option<String>,
56}
57
58/// User message with content.
59#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct UserMessage {
61    #[serde(flatten)]
62    pub base: MessageBase,
63    #[serde(rename = "type")]
64    pub message_type: String, // "user"
65    pub message: UserMessageContent,
66}
67
68/// Content of a user message.
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub struct UserMessageContent {
71    pub content: UserContent,
72    #[serde(flatten)]
73    pub extra: HashMap<String, serde_json::Value>,
74}
75
76/// Content can be a string or an array of content blocks.
77#[derive(Debug, Clone, Serialize, Deserialize)]
78#[serde(untagged)]
79pub enum UserContent {
80    Text(String),
81    Blocks(Vec<UserContentBlock>),
82}
83
84/// A content block within user message content.
85#[derive(Debug, Clone, Serialize, Deserialize)]
86pub struct UserContentBlock {
87    #[serde(rename = "type")]
88    pub block_type: String,
89    #[serde(skip_serializing_if = "Option::is_none")]
90    pub text: Option<String>,
91    #[serde(flatten)]
92    pub extra: HashMap<String, serde_json::Value>,
93}
94
95/// Assistant message with optional content.
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct AssistantMessage {
98    #[serde(flatten)]
99    pub base: MessageBase,
100    #[serde(rename = "type")]
101    pub message_type: String, // "assistant"
102    #[serde(skip_serializing_if = "Option::is_none")]
103    pub message: Option<AssistantMessageContent>,
104}
105
106/// Content of an assistant message.
107#[derive(Debug, Clone, Serialize, Deserialize)]
108pub struct AssistantMessageContent {
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub content: Option<serde_json::Value>,
111    #[serde(flatten)]
112    pub extra: HashMap<String, serde_json::Value>,
113}
114
115/// Progress message.
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct ProgressMessage {
118    #[serde(flatten)]
119    pub base: MessageBase,
120    #[serde(rename = "type")]
121    pub message_type: String, // "progress"
122    #[serde(skip_serializing_if = "Option::is_none")]
123    pub progress: Option<serde_json::Value>,
124}
125
126/// System message level.
127pub type SystemMessageLevel = String;
128
129/// System message.
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct SystemMessage {
132    #[serde(flatten)]
133    pub base: MessageBase,
134    #[serde(rename = "type")]
135    pub message_type: String, // "system"
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub subtype: Option<String>,
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub level: Option<SystemMessageLevel>,
140    #[serde(skip_serializing_if = "Option::is_none")]
141    pub message: Option<String>,
142}
143
144/// System local command message (subtype: "local_command").
145pub type SystemLocalCommandMessage = SystemMessage;
146
147/// System bridge status message.
148pub type SystemBridgeStatusMessage = SystemMessage;
149
150/// System turn duration message.
151pub type SystemTurnDurationMessage = SystemMessage;
152
153/// System thinking message.
154pub type SystemThinkingMessage = SystemMessage;
155
156/// System memory saved message.
157pub type SystemMemorySavedMessage = SystemMessage;
158
159/// System stop hook summary message.
160pub type SystemStopHookSummaryMessage = SystemMessage;
161
162/// System informational message.
163pub type SystemInformationalMessage = SystemMessage;
164
165/// System compact boundary message.
166pub type SystemCompactBoundaryMessage = SystemMessage;
167
168/// System micro-compact boundary message.
169pub type SystemMicrocompactBoundaryMessage = SystemMessage;
170
171/// System permission retry message.
172pub type SystemPermissionRetryMessage = SystemMessage;
173
174/// System scheduled task fire message.
175pub type SystemScheduledTaskFireMessage = SystemMessage;
176
177/// System away summary message.
178pub type SystemAwaySummaryMessage = SystemMessage;
179
180/// System agents killed message.
181pub type SystemAgentsKilledMessage = SystemMessage;
182
183/// System API metrics message.
184pub type SystemApiMetricsMessage = SystemMessage;
185
186/// System API error message.
187#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct SystemApiErrorMessage {
189    #[serde(flatten)]
190    pub base: MessageBase,
191    #[serde(rename = "type")]
192    pub message_type: String, // "system"
193    #[serde(skip_serializing_if = "Option::is_none")]
194    pub subtype: Option<String>,
195    #[serde(skip_serializing_if = "Option::is_none")]
196    pub level: Option<SystemMessageLevel>,
197    #[serde(skip_serializing_if = "Option::is_none")]
198    pub message: Option<String>,
199    #[serde(skip_serializing_if = "Option::is_none")]
200    pub error: Option<String>,
201}
202
203/// System file snapshot message.
204pub type SystemFileSnapshotMessage = SystemMessage;
205
206/// Hook result message.
207#[derive(Debug, Clone, Serialize, Deserialize)]
208pub struct HookResultMessage {
209    #[serde(flatten)]
210    pub base: MessageBase,
211    #[serde(rename = "type")]
212    pub message_type: String, // "hook_result"
213}
214
215/// Tool use summary message.
216#[derive(Debug, Clone, Serialize, Deserialize)]
217pub struct ToolUseSummaryMessage {
218    #[serde(flatten)]
219    pub base: MessageBase,
220    #[serde(rename = "type")]
221    pub message_type: String, // "tool_use_summary"
222}
223
224/// Tombstone message.
225#[derive(Debug, Clone, Serialize, Deserialize)]
226pub struct TombstoneMessage {
227    #[serde(flatten)]
228    pub base: MessageBase,
229    #[serde(rename = "type")]
230    pub message_type: String, // "tombstone"
231}
232
233/// Stream event.
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub struct StreamEvent {
236    #[serde(rename = "type", skip_serializing_if = "Option::is_none")]
237    pub event_type: Option<String>,
238    #[serde(flatten)]
239    pub extra: HashMap<String, serde_json::Value>,
240}
241
242/// Request start event.
243pub type RequestStartEvent = StreamEvent;
244
245/// Stop hook info.
246pub type StopHookInfo = HashMap<String, serde_json::Value>;
247
248/// Compact metadata.
249pub type CompactMetadata = HashMap<String, serde_json::Value>;
250
251/// Partial compact direction.
252pub type PartialCompactDirection = String;
253
254/// Collapsed read search group.
255pub type CollapsedReadSearchGroup = HashMap<String, serde_json::Value>;
256
257/// Grouped tool use message.
258#[derive(Debug, Clone, Serialize, Deserialize)]
259pub struct GroupedToolUseMessage {
260    #[serde(flatten)]
261    pub base: MessageBase,
262    #[serde(rename = "type")]
263    pub message_type: String, // "grouped_tool_use"
264}
265
266/// Collapsible message base.
267pub type CollapsibleMessage = MessageBase;
268
269/// Normalized assistant message.
270pub type NormalizedAssistantMessage = AssistantMessage;
271
272/// Normalized user message.
273pub type NormalizedUserMessage = UserMessage;
274
275/// Normalized message union.
276#[derive(Debug, Clone, Serialize, Deserialize)]
277#[serde(tag = "type")]
278pub enum NormalizedMessage {
279    #[serde(rename = "assistant")]
280    Assistant(AssistantMessage),
281    #[serde(rename = "user")]
282    User(UserMessage),
283    #[serde(rename = "progress")]
284    Progress(ProgressMessage),
285    #[serde(rename = "system")]
286    System(SystemMessage),
287    #[serde(rename = "attachment")]
288    Attachment(AttachmentMessage),
289}
290
291/// Renderable message alias.
292pub type RenderableMessage = Message;
293
294/// Unified message enum covering all message variants.
295#[derive(Debug, Clone, Serialize, Deserialize)]
296#[serde(tag = "type")]
297pub enum Message {
298    #[serde(rename = "user")]
299    User(UserMessage),
300    #[serde(rename = "assistant")]
301    Assistant(AssistantMessage),
302    #[serde(rename = "progress")]
303    Progress(ProgressMessage),
304    #[serde(rename = "system")]
305    System(SystemMessage),
306    #[serde(rename = "attachment")]
307    Attachment(AttachmentMessage),
308    #[serde(rename = "hook_result")]
309    HookResult(HookResultMessage),
310    #[serde(rename = "tool_use_summary")]
311    ToolUseSummary(ToolUseSummaryMessage),
312    #[serde(rename = "tombstone")]
313    Tombstone(TombstoneMessage),
314    #[serde(rename = "grouped_tool_use")]
315    GroupedToolUse(GroupedToolUseMessage),
316}
317
318/// Create an away summary system message.
319/// Translates createAwaySummaryMessage from utils/messages.ts.
320pub fn create_away_summary_message(content: &str) -> Message {
321    Message::System(SystemMessage {
322        base: MessageBase {
323            uuid: Some(uuid::Uuid::new_v4().to_string()),
324            timestamp: Some(chrono::Utc::now().to_rfc3339()),
325            created_at: Some(chrono::Utc::now().to_rfc3339()),
326            is_meta: Some(false),
327            ..Default::default()
328        },
329        message_type: "system".to_string(),
330        subtype: Some("away_summary".to_string()),
331        level: None,
332        message: Some(content.to_string()),
333    })
334}