//! The contract between the harness and the process table: run a command in the world. //! The process table implements it; the harness's `bash` tool uses it. use std::time::Duration; /// What to run: a shell string (run by the world's `sh -c`) or an argv without a shell. #[derive(Clone, Debug)] pub enum Command { Shell(String), Argv(Vec), } /// How to run it. `cwd` is a world path. `timeout` ends the command and all its processes. /// `conversations` carries the nearest-first conversation chain. Child processes inherit it. #[derive(Clone, Debug, Default)] pub struct Options { pub cwd: String, pub env: Vec<(String, String)>, pub timeout: Option, pub conversations: Vec, /// Undo tag shared by this tool call and all child processes. pub tool_call: Option, } /// The stream that one output chunk came from. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Stream { Stdout, Stderr, } /// Run commands in the world. Dropping the future kills the command and all processes it started. #[async_trait::async_trait] pub trait Exec: Send + Sync { /// Run to completion and return the exit status. `output` gets each chunk as it arrives, in order. async fn exec( &self, command: Command, options: Options, output: &mut (dyn for<'chunk> FnMut(Stream, &'chunk [u8]) + Send), ) -> anyhow::Result; }