feat(#1466): add sessions table + turn_stats.session_id capture for per-session stats

This commit is contained in:
damocles 2026-06-10 19:37:48 +02:00 committed by mara
commit 17ddba0341
5 changed files with 102 additions and 3 deletions

View file

@ -618,6 +618,15 @@ pub struct Bus {
/// behavior. Atomic so the consumer can take-and-clear without a
/// lock.
skip_continue_once: Arc<AtomicBool>,
/// Current fresh-claude-session id (FK to `sessions.id`). Set by the
/// bin loop after minting a session row on a fresh start; stamped onto
/// every `turn_stats` row until the next fresh session. `None` before
/// the first fresh turn or when the stats db is unavailable.
session_id: Arc<Mutex<Option<i64>>>,
/// One-shot: `run_claude` flips this true when it suppresses
/// `--continue` (a fresh session). The bin loop takes-and-clears it
/// after the turn to decide whether to mint a new `sessions` row.
fresh_session: Arc<AtomicBool>,
/// Per-turn tool-call counter. Reset by the bin loop between
/// turns via `take_tool_calls`. Populated by `observe_stream` as
/// the stdout pump parses each stream-json line. Powers the
@ -691,6 +700,8 @@ impl Bus {
last_cost_usage: Arc::new(Mutex::new(None)),
rate_limited: Arc::new(AtomicBool::new(was_rate_limited)),
skip_continue_once: Arc::new(AtomicBool::new(false)),
session_id: Arc::new(Mutex::new(None)),
fresh_session: Arc::new(AtomicBool::new(false)),
tool_calls: Arc::new(Mutex::new(std::collections::HashMap::new())),
last_turn_ended_unix: Arc::new(AtomicI64::new(0)),
api_context_window: Arc::new(Mutex::new(None)),
@ -727,6 +738,39 @@ impl Bus {
self.skip_continue_once.swap(false, Ordering::SeqCst)
}
/// Mark that the current turn started a fresh claude session.
/// `run_claude` calls this when it suppresses `--continue`.
pub fn mark_fresh_session(&self) {
self.fresh_session.store(true, Ordering::SeqCst);
}
/// Take + clear the fresh-session one-shot. The bin loop calls this
/// after the turn to decide whether to mint a new `sessions` row.
#[must_use]
pub fn take_fresh_session(&self) -> bool {
self.fresh_session.swap(false, Ordering::SeqCst)
}
/// Currently-active session id (FK to `sessions.id`), or `None`.
///
/// # Panics
///
/// Panics if the internal lock is poisoned.
#[must_use]
pub fn current_session_id(&self) -> Option<i64> {
*self.session_id.lock().unwrap()
}
/// Set the active session id after minting a `sessions` row on a
/// fresh start.
///
/// # Panics
///
/// Panics if the internal lock is poisoned.
pub fn set_session_id(&self, id: Option<i64>) {
*self.session_id.lock().unwrap() = id;
}
/// Currently-selected claude model name. Read on every turn so a
/// `/model <name>` flip takes effect on the next turn.
///