1use chrono::{DateTime, Utc};
6use serde::{Deserialize, Serialize};
7use serde_json::Value;
8
9use crate::tool::ToolCall;
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
12#[serde(rename_all = "lowercase")]
13pub enum Role {
14 System,
16 User,
18 Assistant,
20 Tool,
22 Signal,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28#[serde(tag = "type", rename_all = "snake_case")]
29pub enum ContentBlock {
30 Text {
32 text: String,
34 },
35 Image {
37 image: ImageContent,
39 },
40 ToolUse {
42 id: String,
44 #[serde(flatten)]
46 call: ToolCall,
47 },
48 ToolResult {
50 tool_use_id: String,
52 content: Value,
54 },
55}
56
57#[derive(Debug, Clone, Serialize, Deserialize)]
59pub struct ImageContent {
60 #[serde(rename = "media_type")]
62 pub media_type: String,
63 #[serde(with = "serde_base64")]
65 pub data: Vec<u8>,
66}
67
68mod serde_base64 {
71 use base64::{engine::general_purpose::STANDARD, Engine};
72 use serde::{Deserialize, Deserializer, Serialize, Serializer};
73
74 pub fn serialize<S: Serializer>(v: &[u8], s: S) -> Result<S::Ok, S::Error> {
75 STANDARD.encode(v).serialize(s)
76 }
77
78 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<u8>, D::Error> {
79 let s = String::deserialize(d)?;
80 STANDARD
81 .decode(s.as_bytes())
82 .map_err(serde::de::Error::custom)
83 }
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
89pub struct SignalMessage {
90 pub role: Role,
92 #[serde(rename = "type")]
94 pub kind: String,
95 #[serde(rename = "tag_name", skip_serializing_if = "Option::is_none")]
97 pub tag_name: Option<String>,
98 pub content: String,
100 #[serde(skip_serializing_if = "Option::is_none")]
102 pub attributes: Option<std::collections::BTreeMap<String, String>>,
103 pub timestamp: DateTime<Utc>,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
109pub struct AgentMessage {
110 pub role: Role,
112 #[serde(default, skip_serializing_if = "Vec::is_empty")]
114 pub content: Vec<ContentBlock>,
115}