use crate::AppState;
use anyhow::{anyhow, Result};
use serde_json::{json, Value};
use trusty_common::memory_core::store::chat_sessions::ChatMessage;
use super::helpers::resolve_palace;
const VALID_ROLES: [&str; 3] = ["user", "assistant", "system"];
pub(crate) async fn handle_chat_session_create(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_create")?;
let store = state.session_store(&palace)?;
let title = args
.get("title")
.and_then(|v| v.as_str())
.map(|s| s.to_string());
let session_id = match args.get("session_id").and_then(|v| v.as_str()) {
Some(id) => {
if store.get_session(id)?.is_none() {
store.upsert_session(id, &[])?;
}
id.to_string()
}
None => store.create_session(title)?,
};
let session = store
.get_session(&session_id)?
.ok_or_else(|| anyhow!("chat_session_create: session vanished after write"))?;
Ok(json!({
"session_id": session.id,
"created_at": session.created_at,
"message_count": session.history.len(),
}))
}
pub(crate) async fn handle_chat_session_add_turn(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_add_turn")?;
let session_id = args
.get("session_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_add_turn: missing 'session_id'"))?;
let role = args
.get("role")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_add_turn: missing 'role'"))?;
if !VALID_ROLES.contains(&role) {
return Err(anyhow!(
"chat_session_add_turn: invalid role '{role}' (expected one of {VALID_ROLES:?})"
));
}
let content = args
.get("content")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_add_turn: missing 'content'"))?;
let store = state.session_store(&palace)?;
let mut history = store
.get_session(session_id)?
.map(|s| s.history)
.unwrap_or_default();
history.push(ChatMessage {
role: role.to_string(),
content: content.to_string(),
});
store.upsert_session(session_id, &history)?;
let session = store
.get_session(session_id)?
.ok_or_else(|| anyhow!("chat_session_add_turn: session vanished after write"))?;
Ok(json!({
"message_count": session.history.len(),
"updated_at": session.updated_at,
}))
}
pub(crate) async fn handle_chat_session_get(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_get")?;
let session_id = args
.get("session_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_get: missing 'session_id'"))?;
let store = state.session_store(&palace)?;
let session = store
.get_session(session_id)?
.ok_or_else(|| anyhow!("chat_session_get: session not found: {session_id}"))?;
Ok(serde_json::to_value(session)?)
}
pub(crate) async fn handle_chat_session_list(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_list")?;
let limit = args.get("limit").and_then(|v| v.as_u64()).unwrap_or(50) as usize;
let offset = args.get("offset").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
let store = state.session_store(&palace)?;
let metas = store.list_sessions()?;
let total_count = metas.len();
let page: Vec<_> = metas.into_iter().skip(offset).take(limit).collect();
Ok(json!({
"sessions": serde_json::to_value(page)?,
"total_count": total_count,
}))
}
pub(crate) async fn handle_chat_session_delete(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_delete")?;
let session_id = args
.get("session_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_delete: missing 'session_id'"))?;
let store = state.session_store(&palace)?;
store.delete_session(session_id)?;
Ok(json!({ "deleted": session_id }))
}
pub(crate) async fn handle_chat_session_recall(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_session_recall")?;
let session_id = args
.get("session_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_session_recall: missing 'session_id'"))?;
let store = state.session_store(&palace)?;
let session = store
.get_session(session_id)?
.ok_or_else(|| anyhow!("chat_session_recall: session not found: {session_id}"))?;
Ok(serde_json::to_value(session)?)
}
pub(crate) async fn handle_chat_turn_append(state: &AppState, args: Value) -> Result<Value> {
let palace = resolve_palace(state, &args, "chat_turn_append")?;
let session_id = args
.get("session_id")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_turn_append: missing 'session_id'"))?;
let prompt = args
.get("prompt")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_turn_append: missing 'prompt'"))?;
let response = args
.get("response")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow!("chat_turn_append: missing 'response'"))?;
let store = state.session_store(&palace)?;
let mut history = store
.get_session(session_id)?
.map(|s| s.history)
.unwrap_or_default();
history.push(ChatMessage {
role: "user".to_string(),
content: prompt.to_string(),
});
history.push(ChatMessage {
role: "assistant".to_string(),
content: response.to_string(),
});
store.upsert_session(session_id, &history)?;
let session = store
.get_session(session_id)?
.ok_or_else(|| anyhow!("chat_turn_append: session vanished after write"))?;
Ok(json!({
"message_count": session.history.len(),
"updated_at": session.updated_at,
}))
}