@@ -492,27 +492,49 @@ fn match_log_cause(
492492 }
493493}
494494
495- fn load_raw_db_cache_events ( limit : usize ) -> Result < Vec < RawDbCacheEvent > , rusqlite:: Error > {
495+ fn load_raw_db_cache_events ( limit : usize , since_timestamp : Option < i64 > ) -> Result < Vec < RawDbCacheEvent > , rusqlite:: Error > {
496496 let Some ( opencode_db_path) = resolve_opencode_db_path ( ) else {
497497 return Ok ( Vec :: new ( ) ) ;
498498 } ;
499499
500500 let conn = open_readonly ( & opencode_db_path) ?;
501- let mut stmt = conn. prepare (
502- "SELECT CAST(m.id AS TEXT), m.session_id, m.time_created,
503- COALESCE(CAST(json_extract(m.data, '$.tokens.input') AS INTEGER), 0) AS input_tokens,
504- COALESCE(CAST(json_extract(m.data, '$.tokens.cache.read') AS INTEGER), 0) AS cache_read,
505- COALESCE(CAST(json_extract(m.data, '$.tokens.cache.write') AS INTEGER), 0) AS cache_write,
506- COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) AS total_tokens,
507- CAST(json_extract(m.data, '$.agent') AS TEXT) AS agent
508- FROM message m
509- WHERE json_extract(m.data, '$.role') = 'assistant'
510- AND COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) > 0
511- ORDER BY m.time_created DESC
512- LIMIT ?1" ,
513- ) ?;
514501
515- let rows = stmt. query_map ( [ limit as i64 ] , |row| {
502+ let ( sql, params) : ( String , Vec < Box < dyn rusqlite:: types:: ToSql > > ) = if let Some ( since) = since_timestamp {
503+ (
504+ "SELECT CAST(m.id AS TEXT), m.session_id, m.time_created,
505+ COALESCE(CAST(json_extract(m.data, '$.tokens.input') AS INTEGER), 0) AS input_tokens,
506+ COALESCE(CAST(json_extract(m.data, '$.tokens.cache.read') AS INTEGER), 0) AS cache_read,
507+ COALESCE(CAST(json_extract(m.data, '$.tokens.cache.write') AS INTEGER), 0) AS cache_write,
508+ COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) AS total_tokens,
509+ CAST(json_extract(m.data, '$.agent') AS TEXT) AS agent
510+ FROM message m
511+ WHERE json_extract(m.data, '$.role') = 'assistant'
512+ AND COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) > 0
513+ AND m.time_created > ?1
514+ ORDER BY m.time_created DESC
515+ LIMIT ?2" . to_string ( ) ,
516+ vec ! [ Box :: new( since) as Box <dyn rusqlite:: types:: ToSql >, Box :: new( limit as i64 ) ] ,
517+ )
518+ } else {
519+ (
520+ "SELECT CAST(m.id AS TEXT), m.session_id, m.time_created,
521+ COALESCE(CAST(json_extract(m.data, '$.tokens.input') AS INTEGER), 0) AS input_tokens,
522+ COALESCE(CAST(json_extract(m.data, '$.tokens.cache.read') AS INTEGER), 0) AS cache_read,
523+ COALESCE(CAST(json_extract(m.data, '$.tokens.cache.write') AS INTEGER), 0) AS cache_write,
524+ COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) AS total_tokens,
525+ CAST(json_extract(m.data, '$.agent') AS TEXT) AS agent
526+ FROM message m
527+ WHERE json_extract(m.data, '$.role') = 'assistant'
528+ AND COALESCE(CAST(json_extract(m.data, '$.tokens.total') AS INTEGER), 0) > 0
529+ ORDER BY m.time_created DESC
530+ LIMIT ?1" . to_string ( ) ,
531+ vec ! [ Box :: new( limit as i64 ) as Box <dyn rusqlite:: types:: ToSql >] ,
532+ )
533+ } ;
534+
535+ let mut stmt = conn. prepare ( & sql) ?;
536+ let params_refs: Vec < & dyn rusqlite:: types:: ToSql > = params. iter ( ) . map ( |p| p. as_ref ( ) ) . collect ( ) ;
537+ let rows = stmt. query_map ( params_refs. as_slice ( ) , |row| {
516538 Ok ( RawDbCacheEvent {
517539 message_id : row. get ( 0 ) ?,
518540 session_id : row. get ( 1 ) ?,
@@ -584,15 +606,15 @@ fn build_db_cache_events(rows: Vec<RawDbCacheEvent>, enrich_causes: bool) -> Vec
584606 chronological
585607}
586608
587- pub fn get_cache_events_from_db ( limit : usize ) -> Vec < DbCacheEvent > {
588- load_raw_db_cache_events ( limit)
609+ pub fn get_cache_events_from_db ( limit : usize , since_timestamp : Option < i64 > ) -> Vec < DbCacheEvent > {
610+ load_raw_db_cache_events ( limit, since_timestamp )
589611 . map ( |rows| build_db_cache_events ( rows, true ) )
590612 . unwrap_or_default ( )
591613}
592614
593615pub fn get_session_cache_stats_from_db ( limit : usize ) -> Vec < SessionCacheStats > {
594616 // Reuse raw rows instead of re-querying + re-parsing logs
595- let events = load_raw_db_cache_events ( 200 )
617+ let events = load_raw_db_cache_events ( 200 , None )
596618 . map ( |rows| build_db_cache_events ( rows, false ) ) // skip log enrichment for stats
597619 . unwrap_or_default ( ) ;
598620 let mut map: HashMap < String , ( usize , i64 , i64 , i64 , i64 , usize ) > = HashMap :: new ( ) ;
0 commit comments