session: add TranscriptInfo struct, consolidate transcript lookups

TranscriptInfo provides cached transcript metadata (path, size)
with a single read. Replaces scattered fs::metadata calls in
surface_observe_cycle, reflection_cycle, resolve_conversation,
and resolve_memory_ratio.

Session::transcript() resolves the path from transcript_path or
by searching projects dir, returning a TranscriptInfo.

Co-Authored-By: Kent Overstreet <kent.overstreet@linux.dev>
This commit is contained in:
ProofOfConcept 2026-03-26 23:24:25 -04:00
parent 8ccc30d97e
commit bb2e3b9fbb
3 changed files with 79 additions and 45 deletions

View file

@ -10,7 +10,7 @@ use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::process::Command;
use std::time::{Duration, SystemTime};
use std::time::{Duration, Instant, SystemTime};
/// Max bytes per context chunk (hook output limit is ~10K chars)
@ -188,9 +188,8 @@ fn surface_observe_cycle(session: &Session, out: &mut String, log_f: &mut File)
// (studying, reading a book, etc.)
let conversation_budget: u64 = 50_000;
let offset_path = state_dir.join("transcript-offset");
let transcript_size = if !session.transcript_path.is_empty() {
fs::metadata(&session.transcript_path).map(|m| m.len()).unwrap_or(0)
} else { 0 };
let transcript = session.transcript();
let transcript_size = transcript.size;
if !live.is_empty() && transcript_size > 0 {
let last_offset: u64 = fs::read_to_string(&offset_path).ok()
@ -199,14 +198,20 @@ fn surface_observe_cycle(session: &Session, out: &mut String, log_f: &mut File)
let behind = transcript_size.saturating_sub(last_offset);
if behind > conversation_budget / 2 {
let _ = writeln!(log_f, "agent {}KB behind (budget {}KB), waiting for catchup",
behind / 1024, conversation_budget / 1024);
// Wait up to 30s for the current agent to finish
let sleep_start = Instant::now();
for _ in 0..30 {
std::thread::sleep(std::time::Duration::from_secs(1));
let still_live = crate::agents::knowledge::scan_pid_files(&state_dir, timeout);
if still_live.is_empty() { break; }
}
let sleep_duration = (Instant::now() - sleep_start).as_secs();
let _ = writeln!(log_f, "agent {}KB behind (budget {}KB), slept for {sleep_duration} seconds",
behind / 1024, conversation_budget / 1024);
out.push_str(&format!("Slept for {sleep_duration} seconds to let observe catch up\n"));
}
}
@ -240,9 +245,8 @@ fn reflection_cycle(session: &Session, out: &mut String, log_f: &mut File) {
// Check transcript growth since last reflection
let offset_path = state_dir.join("transcript-offset");
let transcript_size = if !session.transcript_path.is_empty() {
fs::metadata(&session.transcript_path).map(|m| m.len()).unwrap_or(0)
} else { 0 };
let transcript = session.transcript();
let transcript_size = transcript.size;
let last_offset: u64 = fs::read_to_string(&offset_path).ok()
.and_then(|s| s.trim().parse().ok())