use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use sqlx::SqlitePool;
use uuid::Uuid;
use crate::error::{ClawError, ClawResult};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolOutputRecord {
pub id: Uuid,
pub session_id: String,
pub tool_name: String,
pub output: serde_json::Value,
pub success: bool,
pub created_at: DateTime<Utc>,
}
#[derive(Debug)]
pub struct ToolOutputStore<'a> {
pool: &'a SqlitePool,
}
impl<'a> ToolOutputStore<'a> {
pub fn new(pool: &'a SqlitePool) -> Self {
ToolOutputStore { pool }
}
pub async fn insert(&self, record: &ToolOutputRecord) -> ClawResult<()> {
sqlx::query(
r#"
INSERT INTO tool_output (id, session_id, tool_name, output, success, created_at)
VALUES (?, ?, ?, ?, ?, ?)
"#,
)
.bind(record.id.to_string())
.bind(&record.session_id)
.bind(&record.tool_name)
.bind(serde_json::to_string(&record.output)?)
.bind(record.success)
.bind(record.created_at.to_rfc3339())
.execute(self.pool)
.await?;
Ok(())
}
pub async fn get_by_session(&self, session_id: &str) -> ClawResult<Vec<ToolOutputRecord>> {
let rows = sqlx::query_as::<_, (String, String, String, String, bool, String)>(
"SELECT id, session_id, tool_name, output, success, created_at \
FROM tool_output WHERE session_id = ? ORDER BY created_at ASC",
)
.bind(session_id)
.fetch_all(self.pool)
.await?;
rows.into_iter()
.map(|(id, session_id, tool_name, output, success, created_at)| {
Ok(ToolOutputRecord {
id: Uuid::parse_str(&id).map_err(|e| ClawError::Store(e.to_string()))?,
session_id,
tool_name,
output: serde_json::from_str(&output)?,
success,
created_at: DateTime::parse_from_rfc3339(&created_at)
.map_err(|e| ClawError::Store(e.to_string()))?
.with_timezone(&Utc),
})
})
.collect()
}
}