Skip to main content

kaizen/store/sqlite/
visualization.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3use super::*;
4
5mod activity;
6mod aggregates;
7mod session_search;
8mod session_search_sql;
9mod sessions;
10
11pub(crate) use session_search::SessionSearchQuery;
12
13#[derive(Clone, Copy, Debug, Default)]
14pub(crate) struct TokenRead {
15    pub(crate) input: u64,
16    pub(crate) output: u64,
17    pub(crate) reasoning: u64,
18    pub(crate) cache_read: u64,
19    pub(crate) cache_create: u64,
20}
21
22#[derive(Clone, Debug, Default)]
23pub(crate) struct ReportTotalsRead {
24    pub(crate) session_count: u64,
25    pub(crate) running_count: u64,
26    pub(crate) event_count: u64,
27    pub(crate) error_count: u64,
28    pub(crate) tool_call_count: u64,
29    pub(crate) cost_usd_e6: i64,
30    pub(crate) tokens: TokenRead,
31    pub(crate) token_event_count: u64,
32    pub(crate) cost_event_count: u64,
33    pub(crate) cost_session_count: u64,
34}
35
36#[derive(Clone, Debug)]
37pub(crate) struct SessionSummaryRead {
38    pub(crate) session: SessionRecord,
39    pub(crate) last_event_ms: Option<u64>,
40    pub(crate) event_count: u64,
41    pub(crate) error_count: u64,
42    pub(crate) tool_call_count: u64,
43    pub(crate) cost_usd_e6: i64,
44    pub(crate) tokens: TokenRead,
45    pub(crate) top_tools: Vec<(String, u64)>,
46}
47
48#[derive(Clone, Copy, Debug)]
49pub(crate) struct ActivityWindow {
50    pub(crate) start_ms: u64,
51    pub(crate) end_ms: u64,
52    pub(crate) width_ms: u64,
53}
54
55#[derive(Clone, Debug, Default)]
56pub(crate) struct ActivityTotalRead {
57    pub(crate) bin: usize,
58    pub(crate) event_count: u64,
59    pub(crate) session_count: u64,
60    pub(crate) token_total: u64,
61    pub(crate) cost_usd_e6: i64,
62}
63
64#[derive(Clone, Debug)]
65pub(crate) struct ActivityCountRead {
66    pub(crate) bin: usize,
67    pub(crate) name: String,
68    pub(crate) count: u64,
69}
70
71#[derive(Clone, Debug, Default)]
72pub(crate) struct ActivityRead {
73    pub(crate) totals: Vec<ActivityTotalRead>,
74    pub(crate) agents: Vec<ActivityCountRead>,
75    pub(crate) kinds: Vec<ActivityCountRead>,
76}
77
78impl Store {
79    pub fn files_for_session(&self, session_id: &str) -> Result<Vec<String>> {
80        self.limited_files_for_session(session_id, usize::MAX)
81    }
82
83    pub(crate) fn limited_files_for_session(
84        &self,
85        session_id: &str,
86        limit: usize,
87    ) -> Result<Vec<String>> {
88        let mut stmt = self.conn.prepare(
89            "SELECT path FROM files_touched
90             WHERE session_id = ?1 ORDER BY path ASC LIMIT ?2",
91        )?;
92        let rows = stmt.query_map(params![session_id, sql_limit(limit)], |row| row.get(0))?;
93        rows.map(|row| row.map_err(Into::into)).collect()
94    }
95}
96
97fn sql_limit(limit: usize) -> i64 {
98    limit.min(i64::MAX as usize) as i64
99}