feat: type-scope events vacuum to prune only stream rows (14d) + drop turn-stats vacuum
This commit is contained in:
parent
f8cf76b62d
commit
6e39515669
9 changed files with 50 additions and 99 deletions
|
|
@ -1,13 +1,18 @@
|
|||
//! Host-side vacuum of every per-agent events.sqlite. The harness
|
||||
//! writes to `/agents/<name>/harness/hyperhive-events.sqlite`
|
||||
//! (bind-mounted from `/var/lib/hyperhive/agents/<name>/harness/`);
|
||||
//! we open the same file from the host every hour and delete rows
|
||||
//! older than `KEEP_SECS`.
|
||||
//! Age-only — no row cap — so a chatty turn doesn't lose history
|
||||
//! sooner than a quiet one; disk pressure on a sustained burst is
|
||||
//! a cheaper problem than a missing event when the operator is
|
||||
//! debugging a regression. Keeping retention on the host means
|
||||
//! agents don't need any cleanup wiring of their own, and a
|
||||
//! we open the same file from the host every hour.
|
||||
//!
|
||||
//! **Type-scoped retention**: only the verbose `stream` rows (the raw
|
||||
//! claude `stream-json` deltas — one per text chunk / `tool_use`, the
|
||||
//! bulk of the file's size) are pruned, and only once they're older
|
||||
//! than [`STREAM_KEEP_SECS`]. Every other kind (`turn_start`,
|
||||
//! `turn_end`, `note`, `status_changed`, `model_changed`,
|
||||
//! `token_usage_changed`, `turn_state_changed`) is kept — they're
|
||||
//! small and carry the meaningful per-turn history the operator wants
|
||||
//! to scroll back through. This keeps events.sqlite small-and-bounded
|
||||
//! without throwing away semantic history. Keeping retention on the
|
||||
//! host means agents don't need any cleanup wiring of their own, and a
|
||||
//! misbehaving harness can't disable its own vacuum.
|
||||
|
||||
use std::path::Path;
|
||||
|
|
@ -19,7 +24,9 @@ use rusqlite::{Connection, Result, params};
|
|||
use crate::coordinator::Coordinator;
|
||||
|
||||
const VACUUM_INTERVAL: Duration = Duration::from_hours(1);
|
||||
const KEEP_SECS: i64 = 7 * 24 * 3600;
|
||||
/// How long verbose `stream` rows are kept before pruning. Other event
|
||||
/// kinds are never deleted by this sweep.
|
||||
const STREAM_KEEP_SECS: i64 = 14 * 24 * 3600;
|
||||
|
||||
/// Background loop: sweep every existing agent state dir hourly, run
|
||||
/// the vacuum SQL against its events.sqlite if present. Errors are
|
||||
|
|
@ -61,7 +68,11 @@ fn vacuum_file(path: &Path) -> Result<u64> {
|
|||
.ok()
|
||||
.and_then(|d| i64::try_from(d.as_secs()).ok())
|
||||
.unwrap_or(0);
|
||||
let cutoff = now - KEEP_SECS;
|
||||
let removed = conn.execute("DELETE FROM events WHERE ts < ?1", params![cutoff])?;
|
||||
let cutoff = now - STREAM_KEEP_SECS;
|
||||
// Prune only the verbose `stream` deltas; semantic events are kept.
|
||||
let removed = conn.execute(
|
||||
"DELETE FROM events WHERE kind = 'stream' AND ts < ?1",
|
||||
params![cutoff],
|
||||
)?;
|
||||
Ok(u64::try_from(removed).unwrap_or(0))
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue