Skip to main content

kaish_types/
kernel.rs

1//! Kernel-level execution options.
2//!
3//! `ExecuteOptions` is the input to a single kernel `execute` call. It collects
4//! the per-call knobs (variables, timeout, cancellation) so embedders don't need
5//! to manage half a dozen execute-method overloads.
6
7use std::collections::HashMap;
8use std::path::PathBuf;
9use std::time::Duration;
10
11use tokio_util::sync::CancellationToken;
12
13use crate::value::Value;
14
15/// Per-call options for `Kernel::execute_with_options`.
16///
17/// Construct with `ExecuteOptions::new()` and the chainable `with_*` builders,
18/// or via `Default`.
19///
20/// # Cancellation vs. timeout — embedder note
21///
22/// If a `cancel_token` is supplied, it is **raced** against the kernel's
23/// internal token. The kernel does NOT cancel the embedder's token on its
24/// own timeouts — it cancels its internal token and returns exit code 124.
25/// So `your_token.is_cancelled()` after the call returns reflects only
26/// whether *you* (or someone sharing your token) cancelled, not whether the
27/// kernel timed out. Distinguish via the returned `ExecResult.code`:
28/// `124` = kernel timeout, `130` = cancellation (Ctrl-C / `Kernel::cancel`).
29#[derive(Default, Clone)]
30pub struct ExecuteOptions {
31    /// Variables exported into this call's environment (per-call overlay).
32    pub vars: HashMap<String, Value>,
33    /// Per-call timeout. Overrides `KernelConfig::request_timeout`.
34    ///
35    /// `None` means no timeout (or whatever the kernel-config default is).
36    /// `Some(Duration::ZERO)` returns exit 124 immediately without spawning
37    /// anything — useful for tests and dry-run paths.
38    /// Any other `Some(d)` lets the kernel run for at most `d` before cancelling
39    /// (which kills external children with the configured grace) and returning 124.
40    pub timeout: Option<Duration>,
41    /// Optional externally-owned cancellation token, *raced* against the kernel's
42    /// internal token. Either firing cancels the request and kills any running
43    /// external children. The kernel does not store this token in its own state —
44    /// it's a per-call read-only input, so embedders are free to drop or reuse
45    /// the original token after the call returns. CancellationToken is internally
46    /// `Arc`-shared, so `clone()` it into the builder if you want to keep your
47    /// original handle.
48    pub cancel_token: Option<CancellationToken>,
49    /// Per-call working directory override.
50    ///
51    /// When `Some(path)`, the kernel runs this call as if `cd path` happened
52    /// first, then restores the prior cwd on return. Useful for embedders that
53    /// run scripts in workspace contexts (notebook cells, per-tool dirs)
54    /// without polluting the long-lived kernel's cwd.
55    pub cwd: Option<PathBuf>,
56}
57
58impl ExecuteOptions {
59    pub fn new() -> Self {
60        Self::default()
61    }
62
63    /// Replace the entire vars overlay with the given map.
64    pub fn with_vars(mut self, vars: HashMap<String, Value>) -> Self {
65        self.vars = vars;
66        self
67    }
68
69    /// Add a single variable to the overlay (extending; last write wins).
70    pub fn with_var(mut self, name: impl Into<String>, value: Value) -> Self {
71        self.vars.insert(name.into(), value);
72        self
73    }
74
75    pub fn with_timeout(mut self, timeout: Duration) -> Self {
76        self.timeout = Some(timeout);
77        self
78    }
79
80    pub fn with_cancel_token(mut self, token: CancellationToken) -> Self {
81        self.cancel_token = Some(token);
82        self
83    }
84
85    /// Run this call as if `cd path` had happened first; the prior cwd is
86    /// restored on return.
87    pub fn with_cwd(mut self, cwd: PathBuf) -> Self {
88        self.cwd = Some(cwd);
89        self
90    }
91}