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}