Skip to main content

artifactize_tools/
launch.rs

1//! How the `help` built-in starts its program. A host with a process layer of its own passes
2//! it as a [`Launcher`]; the standalone command uses [`Standalone`], which keeps the program
3//! and its children in one process group or Job Object and gives it an explicit environment.
4
5use std::{
6    collections::BTreeMap, ffi::OsString, future::Future, path::PathBuf, pin::Pin, time::Duration,
7};
8
9use tokio_util::sync::CancellationToken;
10
11use crate::platform;
12
13/// One resolved program to run: its path, its arguments and its working directory.
14#[derive(Debug, Clone)]
15pub struct Launch {
16    pub program: PathBuf,
17    pub args: Vec<OsString>,
18    pub cwd: PathBuf,
19    /// How long the program may run before it and its children are killed.
20    pub timeout: Duration,
21    /// How many bytes of each output stream are kept; more sets `truncated`.
22    pub output_limit: usize,
23}
24
25/// What a finished program produced.
26#[derive(Debug)]
27pub struct Finished {
28    /// The actual exit status, not independently editable success and diagnostic fields.
29    pub status: std::process::ExitStatus,
30    pub stdout: Vec<u8>,
31    pub stderr: Vec<u8>,
32    /// An output stream exceeded `output_limit`.
33    pub truncated: bool,
34}
35
36/// Why a program did not finish.
37#[derive(Debug, thiserror::Error)]
38pub enum LaunchError {
39    #[error("timed out")]
40    TimedOut,
41    #[error("Tool call was cancelled.")]
42    Cancelled,
43    #[error("{0}")]
44    Failed(String),
45}
46
47/// The boxed future a [`Launcher`] returns, so that hosts can pass one as a trait object.
48pub type Running<'a> = Pin<Box<dyn Future<Output = Result<Finished, LaunchError>> + Send + 'a>>;
49
50/// Starts a built-in's program and waits for it.
51pub trait Launcher: Sync {
52    fn run<'a>(&'a self, launch: Launch, cancellation: &'a CancellationToken) -> Running<'a>;
53}
54
55/// The standalone command's launcher: the program runs in its own process group or Job
56/// Object, which is killed when it finishes, times out or is cancelled, with only the
57/// variables in [`passed_environment`].
58pub struct Standalone;
59
60impl Launcher for Standalone {
61    fn run<'a>(&'a self, launch: Launch, cancellation: &'a CancellationToken) -> Running<'a> {
62        Box::pin(platform::process::run(launch, cancellation))
63    }
64}
65
66/// The variables a standalone program receives: the whole environment of this process, as in
67/// the author's terminal, without artifactize's own `ARTIFACTIZE_*` variables.
68pub fn passed_environment() -> BTreeMap<OsString, OsString> {
69    platform::process::passed_environment()
70}