//! Purge Tool - Delete memories visible to the current token with optional filters use anyhow::{bail, Context, Result}; use chrono::DateTime; use serde_json::Value; use std::sync::Arc; use tracing::{info, warn}; use crate::auth::PUBLIC_AUTH_SCOPE; use crate::tools::INTERNAL_AUTH_SCOPE_ARG; use crate::AppState; /// Execute the purge tool pub async fn execute(state: &Arc, arguments: Value) -> Result { // Extract parameters let source_agent_id = arguments .get("source_agent_id") .and_then(|v| v.as_str()) .or_else(|| arguments.get("agent_id").and_then(|v| v.as_str())); let auth_scope = arguments .get(INTERNAL_AUTH_SCOPE_ARG) .and_then(|v| v.as_str()) .unwrap_or(PUBLIC_AUTH_SCOPE); let confirm = arguments .get("confirm") .and_then(|v| v.as_bool()) .unwrap_or(false); if !confirm { bail!("Purge operation requires 'confirm: true' to proceed"); } let before = arguments .get("before") .and_then(|v| v.as_str()) .map(|s| DateTime::parse_from_rfc3339(s)) .transpose() .context("Invalid 'before' timestamp format - use ISO8601/RFC3339")? .map(|dt| dt.with_timezone(&chrono::Utc)); // Get current count before purge let count_before = state .db .count_memories(auth_scope, source_agent_id) .await .context("Failed to count memories")?; if count_before == 0 { info!( "No memories found to purge for auth scope '{}' with source_agent_id={:?}", auth_scope, source_agent_id ); return Ok(serde_json::json!({ "success": true, "source_agent_id_filter": source_agent_id, "deleted": 0, "message": "No memories found to purge" }) .to_string()); } warn!( "Purging memories for auth scope '{}' with source_agent_id={:?} (before={:?})", auth_scope, source_agent_id, before ); // Execute purge let deleted = state .db .purge_memories(auth_scope, source_agent_id, before) .await .context("Failed to purge memories")?; info!( "Purged {} memories for auth scope '{}' with source_agent_id={:?}", deleted, auth_scope, source_agent_id ); Ok(serde_json::json!({ "success": true, "source_agent_id_filter": source_agent_id, "deleted": deleted, "had_before_filter": before.is_some(), "message": format!("Successfully purged {} memories", deleted) }) .to_string()) }