alchemy_llm/types/
message.rs1use serde::{Deserialize, Deserializer, Serialize};
2use std::time::{SystemTime, UNIX_EPOCH};
3
4use super::content::{Content, ImageContent, TextContent};
5use super::tool_call_id::ToolCallId;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8#[serde(tag = "role")]
9pub enum Message {
10 User(UserMessage),
11 Assistant(AssistantMessage),
12 ToolResult(ToolResultMessage),
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct UserMessage {
17 #[serde(deserialize_with = "deserialize_user_content")]
18 pub content: UserContent,
19 #[serde(default = "current_timestamp")]
20 pub timestamp: i64,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24#[serde(untagged)]
25pub enum UserContent {
26 Text(String),
27 Multi(Vec<UserContentBlock>),
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(untagged)]
32pub enum UserContentBlock {
33 Text(TextContent),
34 Image(ImageContent),
35}
36
37fn deserialize_user_content<'de, D>(deserializer: D) -> Result<UserContent, D::Error>
38where
39 D: Deserializer<'de>,
40{
41 #[derive(Deserialize)]
42 #[serde(untagged)]
43 enum ContentHelper {
44 String(String),
45 Array(Vec<UserContentBlock>),
46 }
47
48 match ContentHelper::deserialize(deserializer)? {
49 ContentHelper::String(s) => Ok(UserContent::Text(s)),
50 ContentHelper::Array(arr) => Ok(UserContent::Multi(arr)),
51 }
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55pub struct AssistantMessage {
56 pub content: Vec<Content>,
57 pub api: super::api::Api,
58 pub provider: super::api::Provider,
59 pub model: String,
60 pub usage: Usage,
61 pub stop_reason: StopReason,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub error_message: Option<String>,
64 #[serde(default = "current_timestamp")]
65 pub timestamp: i64,
66}
67
68#[derive(Debug, Clone, Serialize, Deserialize)]
69pub struct ToolResultMessage {
70 pub tool_call_id: ToolCallId,
71 pub tool_name: String,
72 pub content: Vec<ToolResultContent>,
73 #[serde(skip_serializing_if = "Option::is_none")]
74 pub details: Option<serde_json::Value>,
75 pub is_error: bool,
76 #[serde(default = "current_timestamp")]
77 pub timestamp: i64,
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize)]
81#[serde(untagged)]
82pub enum ToolResultContent {
83 Text(TextContent),
84 Image(ImageContent),
85}
86
87#[derive(Debug, Clone, Default, Serialize, Deserialize)]
88pub struct Context {
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub system_prompt: Option<String>,
91 pub messages: Vec<Message>,
92 #[serde(skip_serializing_if = "Option::is_none")]
93 pub tools: Option<Vec<Tool>>,
94}
95
96use super::tool::Tool;
97use super::usage::{StopReason, Usage};
98
99fn current_timestamp() -> i64 {
100 match SystemTime::now().duration_since(UNIX_EPOCH) {
101 Ok(duration) => duration.as_millis() as i64,
102 Err(error) => -(error.duration().as_millis() as i64),
103 }
104}