claw_core/store/
tool_output.rs1use chrono::{DateTime, Utc};
8use serde::{Deserialize, Serialize};
9use sqlx::SqlitePool;
10use uuid::Uuid;
11
12use crate::error::{ClawError, ClawResult};
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct ToolOutputRecord {
17 pub id: Uuid,
19 pub session_id: String,
21 pub tool_name: String,
23 pub output: serde_json::Value,
25 pub success: bool,
27 pub created_at: DateTime<Utc>,
29}
30
31#[derive(Debug)]
33pub struct ToolOutputStore<'a> {
34 pool: &'a SqlitePool,
35}
36
37impl<'a> ToolOutputStore<'a> {
38 pub fn new(pool: &'a SqlitePool) -> Self {
40 ToolOutputStore { pool }
41 }
42
43 pub async fn insert(&self, record: &ToolOutputRecord) -> ClawResult<()> {
49 sqlx::query(
50 r#"
51 INSERT INTO tool_output (id, session_id, tool_name, output, success, created_at)
52 VALUES (?, ?, ?, ?, ?, ?)
53 "#,
54 )
55 .bind(record.id.to_string())
56 .bind(&record.session_id)
57 .bind(&record.tool_name)
58 .bind(serde_json::to_string(&record.output)?)
59 .bind(record.success)
60 .bind(record.created_at.to_rfc3339())
61 .execute(self.pool)
62 .await?;
63
64 Ok(())
65 }
66
67 pub async fn get_by_session(&self, session_id: &str) -> ClawResult<Vec<ToolOutputRecord>> {
74 let rows = sqlx::query_as::<_, (String, String, String, String, bool, String)>(
75 "SELECT id, session_id, tool_name, output, success, created_at \
76 FROM tool_output WHERE session_id = ? ORDER BY created_at ASC",
77 )
78 .bind(session_id)
79 .fetch_all(self.pool)
80 .await?;
81
82 rows.into_iter()
83 .map(|(id, session_id, tool_name, output, success, created_at)| {
84 Ok(ToolOutputRecord {
85 id: Uuid::parse_str(&id).map_err(|e| ClawError::Store(e.to_string()))?,
86 session_id,
87 tool_name,
88 output: serde_json::from_str(&output)?,
89 success,
90 created_at: DateTime::parse_from_rfc3339(&created_at)
91 .map_err(|e| ClawError::Store(e.to_string()))?
92 .with_timezone(&Utc),
93 })
94 })
95 .collect()
96 }
97}