claude_agent/session/state/
message.rs

1//! Session message types.
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5
6use super::ids::MessageId;
7use crate::session::types::EnvironmentContext;
8use crate::types::{ContentBlock, Message, Role, TokenUsage};
9
10#[derive(Clone, Debug, Default, Serialize, Deserialize)]
11pub struct MessageMetadata {
12    pub model: Option<String>,
13    pub request_id: Option<String>,
14    pub tool_results: Option<Vec<ToolResultMeta>>,
15    pub thinking: Option<ThinkingMetadata>,
16}
17
18#[derive(Clone, Debug, Serialize, Deserialize)]
19pub struct ToolResultMeta {
20    pub tool_use_id: String,
21    pub tool_name: String,
22    pub is_error: bool,
23    pub duration_ms: Option<u64>,
24}
25
26#[derive(Clone, Debug, Serialize, Deserialize)]
27pub struct ThinkingMetadata {
28    pub level: String,
29    pub disabled: bool,
30}
31
32#[derive(Clone, Debug, Serialize, Deserialize)]
33pub struct SessionMessage {
34    pub id: MessageId,
35    pub parent_id: Option<MessageId>,
36    pub role: Role,
37    pub content: Vec<ContentBlock>,
38    #[serde(default)]
39    pub is_sidechain: bool,
40    #[serde(default)]
41    pub is_compact_summary: bool,
42    pub usage: Option<TokenUsage>,
43    pub timestamp: DateTime<Utc>,
44    #[serde(default)]
45    pub metadata: MessageMetadata,
46    #[serde(default, skip_serializing_if = "Option::is_none")]
47    pub environment: Option<EnvironmentContext>,
48}
49
50impl SessionMessage {
51    pub fn user(content: Vec<ContentBlock>) -> Self {
52        Self {
53            id: MessageId::new(),
54            parent_id: None,
55            role: Role::User,
56            content,
57            is_sidechain: false,
58            is_compact_summary: false,
59            usage: None,
60            timestamp: Utc::now(),
61            metadata: MessageMetadata::default(),
62            environment: None,
63        }
64    }
65
66    pub fn assistant(content: Vec<ContentBlock>) -> Self {
67        Self {
68            id: MessageId::new(),
69            parent_id: None,
70            role: Role::Assistant,
71            content,
72            is_sidechain: false,
73            is_compact_summary: false,
74            usage: None,
75            timestamp: Utc::now(),
76            metadata: MessageMetadata::default(),
77            environment: None,
78        }
79    }
80
81    pub fn with_parent(mut self, parent_id: MessageId) -> Self {
82        self.parent_id = Some(parent_id);
83        self
84    }
85
86    pub fn with_usage(mut self, usage: TokenUsage) -> Self {
87        self.usage = Some(usage);
88        self
89    }
90
91    pub fn as_sidechain(mut self) -> Self {
92        self.is_sidechain = true;
93        self
94    }
95
96    pub fn as_compact_summary(mut self) -> Self {
97        self.is_compact_summary = true;
98        self
99    }
100
101    pub fn with_environment(mut self, env: EnvironmentContext) -> Self {
102        self.environment = Some(env);
103        self
104    }
105
106    pub fn with_model(mut self, model: impl Into<String>) -> Self {
107        self.metadata.model = Some(model.into());
108        self
109    }
110
111    pub fn with_request_id(mut self, request_id: impl Into<String>) -> Self {
112        self.metadata.request_id = Some(request_id.into());
113        self
114    }
115
116    pub fn to_api_message(&self) -> Message {
117        Message {
118            role: self.role,
119            content: self.content.clone(),
120        }
121    }
122}