Skip to main content

replay_bob/
replay_bob.rs

1//! Replay a captured bob `--output-format stream-json` file through the fixed
2//! `BobStreamParser` and print what the host would render — to verify
3//! echo-suppression + thinking-routing on REAL bob output (not synthetic).
4//!
5//! cargo run --example replay_bob --all-features -- /path/to/out.jsonl
6
7use std::io::BufRead;
8
9use harness::bob::BobStreamParser;
10
11fn main() {
12    let path = std::env::args().nth(1).expect("usage: replay_bob <out.jsonl>");
13    let file = std::fs::File::open(&path).expect("open file");
14    let mut parser = BobStreamParser::default();
15    let (mut text, mut thinking, mut tools) = (String::new(), String::new(), Vec::new());
16    for line in std::io::BufReader::new(file).lines() {
17        let parsed = parser.parse_line(&line.unwrap());
18        if let Some(t) = parsed.text {
19            text.push_str(&t);
20        }
21        if let Some(t) = parsed.thinking {
22            thinking.push_str(&t);
23        }
24        if let Some(ts) = parsed.tool_start {
25            tools.push(format!("ToolStart({})", ts.name));
26        }
27        if parsed.tool_end.is_some() {
28            tools.push("ToolEnd".to_owned());
29        }
30    }
31    println!("=== VISIBLE TEXT (host renders this as the message) ===\n{text}\n");
32    println!("contains '[using tool' ? {}", text.contains("[using tool"));
33    println!("contains '<thinking>'  ? {}", text.contains("<thinking>"));
34    println!("\n=== THINKING (routed to its own section) ===\n{}", thinking.trim());
35    println!("\n=== TOOL EVENTS ===");
36    for t in &tools {
37        println!("  {t}");
38    }
39}