verify_enrichment/
verify_enrichment.rs1use std::sync::{mpsc::sync_channel, Arc};
13
14use harness::{default_registry, ReasoningEffort, RunCallback, RunEvent, RunMode, RunRequest, RunTuning};
15
16fn main() -> Result<(), String> {
17 let id = std::env::args().nth(1).unwrap_or_else(|| "claude".to_owned());
18 let prompt = std::env::args().nth(2).unwrap_or_else(|| default_prompt(&id));
19
20 let reg = default_registry();
21 let h = reg
22 .by_id(&id)
23 .ok_or_else(|| format!("unknown/disabled harness: {id}"))?;
24
25 let tuning = match id.as_str() {
27 "claude" => RunTuning { model: Some("haiku".to_owned()), ..RunTuning::default() },
28 "codex" => RunTuning { effort: Some(ReasoningEffort::Low), ..RunTuning::default() },
29 _ => RunTuning::default(),
30 };
31
32 let (tx, rx) = sync_channel::<RunEvent>(256);
33 let on_event: RunCallback = Arc::new(move |ev| {
34 let _ = tx.send(ev);
35 });
36
37 eprintln!("── running {id} ──");
38 let _handle = h.run(
39 RunRequest {
40 run_id: "verify".into(),
41 prompt,
42 cwd: Some(std::env::current_dir().map_err(|e| e.to_string())?),
43 mode: RunMode::Ask,
44 tuning,
45 },
46 on_event,
47 )
48 .map_err(|e| e.to_string())?;
49
50 let (mut session, mut tool_input, mut tool_output, mut usage) = (false, false, false, false);
51 for ev in rx {
52 print_event(&ev);
53 match &ev {
54 RunEvent::Session { session_id, model, .. } => {
55 session = session_id.is_some() || model.is_some();
56 }
57 RunEvent::ToolStart { input, .. } => tool_input |= input.is_some(),
58 RunEvent::ToolEnd { output, .. } => tool_output |= output.is_some(),
59 RunEvent::Usage { input_tokens, output_tokens, total_tokens, .. } => {
60 usage = input_tokens.is_some() || output_tokens.is_some() || total_tokens.is_some();
61 }
62 RunEvent::Exited { .. } => break,
63 _ => {}
64 }
65 }
66 eprintln!(
67 "\n── enrichment seen from real {id}: session={session} tool_input={tool_input} tool_output={tool_output} usage={usage}"
68 );
69 Ok(())
70}
71
72fn default_prompt(id: &str) -> String {
73 match id {
74 "codex" => "Run the command `ls` to list the current directory, then tell me how many entries there are in one short sentence.".to_owned(),
75 _ => "Use the Read tool to read the file Cargo.toml, then tell me the workspace resolver version in one short sentence.".to_owned(),
76 }
77}
78
79fn print_event(ev: &RunEvent) {
80 let line = match ev {
81 RunEvent::Text { delta, .. } => format!("Text({:?})", trunc(delta, 40)),
82 RunEvent::Thinking { delta, .. } => format!("Thinking({:?})", trunc(delta, 40)),
83 RunEvent::Session { session_id, model, .. } => {
84 format!("Session(session_id={session_id:?}, model={model:?})")
85 }
86 RunEvent::ToolStart { name, input, .. } => {
87 format!("ToolStart(name={name:?}, input={:?})", input.as_deref().map(|s| trunc(s, 60)))
88 }
89 RunEvent::ToolEnd { ok, output, .. } => {
90 format!("ToolEnd(ok={ok}, output={:?})", output.as_deref().map(|s| trunc(s, 60)))
91 }
92 RunEvent::Usage { input_tokens, output_tokens, total_tokens, .. } => {
93 format!("Usage(in={input_tokens:?}, out={output_tokens:?}, total={total_tokens:?})")
94 }
95 other => format!("{other:?}"),
96 };
97 eprintln!(" {line}");
98}
99
100fn trunc(s: &str, n: usize) -> String {
101 let s = s.replace('\n', "\\n");
102 if s.chars().count() > n {
103 format!("{}…", s.chars().take(n).collect::<String>())
104 } else {
105 s
106 }
107}