Skip to main content

objectiveai_cli/command/
reexec.rs

1//! Re-exec envelope hygiene.
2//!
3//! When a CLI `execute` handler exec's a detached child of this CLI
4//! (via the SDK's `BinaryExecutor`) by copying its own request onto
5//! the child, the child must NOT inherit the parent's output
6//! transform or token budget. Only the originating top-level
7//! invocation carries those.
8//!
9//! The rule, applied identically at every such re-exec:
10//!
11//! | base field      | child inherits? | why                          |
12//! |-----------------|-----------------|------------------------------|
13//! | `jq`            | NO (stripped)   | output transform, parent-only |
14//! | `python`        | NO (stripped)   | output transform, parent-only |
15//! | `max_tokens`    | NO (stripped)   | token budget, parent-only     |
16//! | `timeout_seconds` | YES (kept)    | the one cap a child honors    |
17//!
18//! Two deliberate non-participants:
19//! - `tools run` / `plugins run` launch foreign tool/plugin binaries
20//!   (not a re-exec of this CLI) and pass the envelope through
21//!   verbatim.
22//! - `tasks run` re-enters `crate::run` with a fired schedule's own
23//!   stored argv — that command's flags are its own configuration,
24//!   not an inherited parent envelope, so they propagate as-is.
25
26use objectiveai_sdk::cli::command::RequestBase;
27
28/// Strip the parent-only envelope fields (`jq`, `python`,
29/// `max_tokens`) from a typed child request's base, leaving
30/// `timeout_seconds` intact. Called at every `BinaryExecutor`
31/// re-exec site on the child request before it's handed to the
32/// executor.
33pub fn strip_inherited(base: &mut RequestBase) {
34    base.jq = None;
35    base.python = None;
36    base.max_tokens = None;
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn strip_inherited_keeps_only_timeout() {
45        let mut base = RequestBase {
46            jq: Some(".x".to_string()),
47            python: Some("y".to_string()),
48            timeout_seconds: Some(30),
49            max_tokens: Some(100),
50        };
51        strip_inherited(&mut base);
52        assert_eq!(base.jq, None);
53        assert_eq!(base.python, None);
54        assert_eq!(base.max_tokens, None);
55        assert_eq!(base.timeout_seconds, Some(30));
56    }
57}