Skip to main content

agent_loop/
agent_loop.rs

1//! A minimal perception→action loop: launch an app, capture a frame, act on
2//! it, and capture the result. Demonstrates transport reporting, capture,
3//! pointer/keyboard input, and clean teardown.
4//!
5//! Run: `cargo run --example agent_loop -- <executable> [args...]`
6
7use agent_seat_linux::{ComputerUse, LaunchConfig, PointerButton};
8use std::env;
9
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    let mut args = env::args().skip(1);
12    let program = args
13        .next()
14        .unwrap_or_else(|| "gnome-calculator".to_string());
15
16    let mut config = LaunchConfig::new(&program);
17    for extra in args {
18        config = config.arg(extra);
19    }
20
21    let harness = ComputerUse::new()?;
22    let mut app = harness.launch(config)?;
23    println!("launched {program} via {:?}", app.transport());
24
25    // 1. Perceive: capture the initial frame.
26    let before = app.capture()?;
27    before.image.save("agent-loop-before.png")?;
28    println!(
29        "captured {}x{} -> agent-loop-before.png",
30        before.image.width(),
31        before.image.height()
32    );
33
34    // 2. Act: focus, select-all, and type, exercising keyboard + text paths.
35    app.click(
36        before.image.width() as f64 / 2.0,
37        before.image.height() as f64 / 2.0,
38        PointerButton::Left,
39        1,
40    )?;
41    app.press_key("ctrl+a")?;
42    app.type_text("agent-seat-linux")?;
43
44    // 3. Perceive again: capture the post-action frame.
45    let after = app.capture()?;
46    after.image.save("agent-loop-after.png")?;
47    println!(
48        "captured {}x{} -> agent-loop-after.png",
49        after.image.width(),
50        after.image.height()
51    );
52
53    // 4. Teardown: stop the app, then close the seat.
54    app.stop();
55    harness.close();
56    println!("done");
57    Ok(())
58}