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//! One deliberate non-participant:
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
23use objectiveai_sdk::cli::command::RequestBase;
24
25/// Strip the parent-only envelope fields (`jq`, `python`,
26/// `max_tokens`) from a typed child request's base, leaving
27/// `timeout_seconds` intact. Called at every `BinaryExecutor`
28/// re-exec site on the child request before it's handed to the
29/// executor.
30pub fn strip_inherited(base: &mut RequestBase) {
31 base.jq = None;
32 base.python = None;
33 base.max_tokens = None;
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 #[test]
41 fn strip_inherited_keeps_only_timeout() {
42 let mut base = RequestBase {
43 jq: Some(".x".to_string()),
44 python: Some("y".to_string()),
45 timeout_seconds: Some(30),
46 max_tokens: Some(100),
47 };
48 strip_inherited(&mut base);
49 assert_eq!(base.jq, None);
50 assert_eq!(base.python, None);
51 assert_eq!(base.max_tokens, None);
52 assert_eq!(base.timeout_seconds, Some(30));
53 }
54}