use std::collections::HashMap;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
pub use super::common::ReasoningConfiguration;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[non_exhaustive]
pub struct MessageResponse {
pub id: String,
pub content: String,
pub peer_id: String,
pub session_id: String,
#[serde(default)]
pub metadata: HashMap<String, serde_json::Value>,
pub created_at: DateTime<Utc>,
pub workspace_id: String,
#[serde(default)]
pub token_count: u64,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
#[non_exhaustive]
pub struct MessageCreate {
pub content: String,
pub peer_id: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub configuration: Option<MessageConfiguration>,
#[serde(skip_serializing_if = "Option::is_none")]
pub created_at: Option<DateTime<Utc>>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, bon::Builder)]
#[builder(finish_fn = build)]
#[non_exhaustive]
pub struct MessageBatchCreate {
pub messages: Vec<MessageCreate>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
#[non_exhaustive]
pub struct MessageUpdate {
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<HashMap<String, serde_json::Value>>,
}
#[derive(Debug, Clone, Serialize, PartialEq, Eq)]
pub(crate) struct MessageMetadataSet {
pub metadata: HashMap<String, serde_json::Value>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Default)]
#[non_exhaustive]
pub struct MessageConfiguration {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning: Option<ReasoningConfiguration>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, bon::Builder)]
#[builder(on(String, into))]
#[builder(finish_fn = build)]
#[non_exhaustive]
pub struct MessageSearchOptions {
pub query: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub filters: Option<HashMap<String, serde_json::Value>>,
#[serde(default = "default_limit")]
#[builder(default = default_limit())]
pub limit: u32,
}
const fn default_limit() -> u32 {
MessageSearchOptions::DEFAULT_LIMIT
}
impl MessageSearchOptions {
const DEFAULT_LIMIT: u32 = 10;
}
pub type MessagePage = super::pagination::Page<MessageResponse>;
#[cfg(test)]
#[allow(
clippy::unwrap_used,
clippy::expect_used,
clippy::panic,
clippy::unnecessary_wraps,
clippy::needless_pass_by_value,
clippy::unused_async
)]
mod tests {
use super::*;
#[test]
fn message_search_options_default_limit() {
let opts: MessageSearchOptions = serde_json::from_str(r#"{"query":"hello"}"#).unwrap();
assert_eq!(opts.limit, 10);
}
#[test]
fn message_batch_create_builder_constructs_from_messages() {
let msg = MessageCreate::builder()
.content("hello")
.peer_id("peer_01")
.build();
let batch = MessageBatchCreate::builder().messages(vec![msg]).build();
assert_eq!(batch.messages.len(), 1);
}
#[test]
fn message_response_token_count_defaults_to_zero_when_missing() {
let json = r#"{
"id": "msg_01",
"content": "hello",
"peer_id": "peer_01",
"session_id": "sess_01",
"workspace_id": "ws_01",
"created_at": "2024-01-01T00:00:00Z"
}"#;
let msg: MessageResponse = serde_json::from_str(json).unwrap();
assert_eq!(msg.token_count, 0);
}
}