From 0f20ee4eb871907defe7848f0d3e2203cfff057e Mon Sep 17 00:00:00 2001 From: Michelle Tilley Date: Tue, 21 Apr 2026 10:32:54 -0700 Subject: feat: AI tool rendering overhaul + edit_file tool (#3423) Overhaul of how AI tool calls are modeled, rendered, and displayed in the Atuin AI TUI. Fixes bugs in shell command output capture, implements the `edit_file` tool with full safety infrastructure, and adds a diff preview for edits. --- crates/atuin-ai/src/store.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'crates/atuin-ai/src/store.rs') diff --git a/crates/atuin-ai/src/store.rs b/crates/atuin-ai/src/store.rs index 2a75d8f4..20b9e881 100644 --- a/crates/atuin-ai/src/store.rs +++ b/crates/atuin-ai/src/store.rs @@ -299,6 +299,38 @@ impl AiSessionStore { .await?; Ok(()) } + + // ── Session metadata (key-value per session) ── + + /// Read a metadata value for a session. Returns `None` if the key doesn't + /// exist or the session hasn't been persisted yet. + pub async fn get_metadata(&self, session_id: &str, key: &str) -> Result> { + let row: Option<(String,)> = + sqlx::query_as("SELECT value FROM session_metadata WHERE session_id = ?1 AND key = ?2") + .bind(session_id) + .bind(key) + .fetch_optional(&self.pool) + .await?; + + Ok(row.map(|(v,)| v)) + } + + /// Write a metadata value for a session (upsert). + pub async fn set_metadata(&self, session_id: &str, key: &str, value: &str) -> Result<()> { + let now = OffsetDateTime::now_utc().unix_timestamp(); + sqlx::query( + "INSERT INTO session_metadata (session_id, key, value, updated_at) + VALUES (?1, ?2, ?3, ?4) + ON CONFLICT (session_id, key) DO UPDATE SET value = ?3, updated_at = ?4", + ) + .bind(session_id) + .bind(key) + .bind(value) + .bind(now) + .execute(&self.pool) + .await?; + Ok(()) + } } #[cfg(test)] -- cgit v1.3.1