use crate::error::Result;
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NewConversation {
pub conversation_id: String,
#[serde(default = "default_user_id")]
pub user_id: String,
pub agent_type: Option<String>,
pub title: Option<String>,
}
fn default_user_id() -> String {
"default".to_string()
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Conversation {
pub id: i64,
pub conversation_id: String,
pub user_id: String,
pub agent_type: Option<String>,
pub title: Option<String>,
pub summary: Option<String>,
pub compressed_before_id: Option<i64>,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConversationMeta {
pub id: i64,
pub conversation_id: String,
pub user_id: String,
pub title: Option<String>,
pub message_count: usize,
pub created_at: String,
pub updated_at: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoredMessage {
pub id: Option<i64>,
pub conversation_id: String,
pub role: String,
pub content: Option<String>,
pub attachments_json: Option<String>,
pub tool_calls_json: Option<String>,
pub tool_result_json: Option<String>,
pub created_at: String,
}
#[derive(Debug, Clone, Default)]
pub struct ConversationFilter {
pub user_id: Option<String>,
pub agent_type: Option<String>,
pub limit: Option<usize>,
pub offset: Option<usize>,
}
pub trait ConversationStore: Send + Sync {
fn create_conversation<'a>(
&'a self,
conv: NewConversation,
) -> BoxFuture<'a, Result<Conversation>>;
fn get_conversation<'a>(
&'a self,
conversation_id: &'a str,
) -> BoxFuture<'a, Result<Option<Conversation>>>;
fn list_conversations<'a>(
&'a self,
filter: ConversationFilter,
) -> BoxFuture<'a, Result<Vec<ConversationMeta>>>;
fn update_conversation<'a>(
&'a self,
conversation_id: &'a str,
title: Option<&'a str>,
summary: Option<&'a str>,
compressed_before_id: Option<i64>,
) -> BoxFuture<'a, Result<()>>;
fn delete_conversation<'a>(&'a self, conversation_id: &'a str) -> BoxFuture<'a, Result<()>>;
fn save_messages<'a>(
&'a self,
conversation_id: &'a str,
messages: &'a [StoredMessage],
) -> BoxFuture<'a, Result<()>>;
fn get_messages<'a>(
&'a self,
conversation_id: &'a str,
) -> BoxFuture<'a, Result<Vec<StoredMessage>>>;
fn count_messages<'a>(&'a self, conversation_id: &'a str) -> BoxFuture<'a, Result<usize>>;
fn ensure_conversation<'a>(
&'a self,
conv: NewConversation,
) -> BoxFuture<'a, Result<Conversation>> {
Box::pin(async move {
let conversation_id = conv.conversation_id.clone();
if let Some(existing) = self.get_conversation(&conversation_id).await? {
Ok(existing)
} else {
self.create_conversation(conv).await
}
})
}
}