Skip to main content

objectiveai_sdk/cli/command/
agent_arguments.rs

1/// Agent identity + response routing args carried per call.
2///
3/// When passed as `Some(&AgentArguments)` to a [`CommandExecutor`],
4/// subprocess-spawning executors (e.g. [`binary::BinaryExecutor`])
5/// apply ALL six fields to the spawned child's env atomically —
6/// `Some(v)` → set, `None` → `env_remove` so the parent's value for
7/// that var can't leak through. `None` for the whole bag means
8/// "inherit parent env unmodified". In-process executors (e.g.
9/// [`plugin::PluginExecutor`]) ignore the bag.
10///
11/// Field ↔ env-var mapping (same as `EnvConfigBuilder` in
12/// `objectiveai-cli/src/run.rs`):
13///
14/// - `agent_instance_hierarchy` ↔ `OBJECTIVEAI_AGENT_INSTANCE_HIERARCHY`
15/// - `agent_id` ↔ `OBJECTIVEAI_AGENT_ID`
16/// - `agent_full_id` ↔ `OBJECTIVEAI_AGENT_FULL_ID`
17/// - `agent_remote` ↔ `OBJECTIVEAI_AGENT_REMOTE`
18/// - `response_id` ↔ `OBJECTIVEAI_RESPONSE_ID`
19/// - `response_ids` ↔ `OBJECTIVEAI_RESPONSE_IDS`
20/// - `mcp_session_id` ↔ `MCP_SESSION_ID` (the MCP transport
21///   session id minted by the MCP server, NOT an objectiveai-scoped
22///   identifier — same env-var convention as
23///   [`crate::mcp::MCP_SESSION_ID_ENV`])
24#[derive(
25    Debug,
26    Clone,
27    Default,
28    PartialEq,
29    Eq,
30    serde::Serialize,
31    serde::Deserialize,
32    schemars::JsonSchema,
33)]
34#[schemars(rename = "cli.command.AgentArguments")]
35pub struct AgentArguments {
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    #[schemars(extend("omitempty" = true))]
38    pub agent_instance_hierarchy: Option<String>,
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    #[schemars(extend("omitempty" = true))]
41    pub agent_id: Option<String>,
42    #[serde(default, skip_serializing_if = "Option::is_none")]
43    #[schemars(extend("omitempty" = true))]
44    pub agent_full_id: Option<String>,
45    #[serde(default, skip_serializing_if = "Option::is_none")]
46    #[schemars(extend("omitempty" = true))]
47    pub agent_remote: Option<String>,
48    #[serde(default, skip_serializing_if = "Option::is_none")]
49    #[schemars(extend("omitempty" = true))]
50    pub response_id: Option<String>,
51    #[serde(default, skip_serializing_if = "Option::is_none")]
52    #[schemars(extend("omitempty" = true))]
53    pub response_ids: Option<String>,
54    #[serde(default, skip_serializing_if = "Option::is_none")]
55    #[schemars(extend("omitempty" = true))]
56    pub mcp_session_id: Option<String>,
57}
58
59impl AgentArguments {
60    /// Apply this bag to a child-process command: every `Some(v)`
61    /// stamps the matching env var, every `None` env-removes it so
62    /// the parent's value can't leak through. Called by
63    /// [`binary::BinaryExecutor`]; available for any executor that
64    /// spawns a subprocess.
65    #[cfg(feature = "cli-executor")]
66    pub fn apply_to_command(&self, command: &mut tokio::process::Command) {
67        let pairs: [(&str, &Option<String>); 7] = [
68            (
69                "OBJECTIVEAI_AGENT_INSTANCE_HIERARCHY",
70                &self.agent_instance_hierarchy,
71            ),
72            ("OBJECTIVEAI_AGENT_ID", &self.agent_id),
73            ("OBJECTIVEAI_AGENT_FULL_ID", &self.agent_full_id),
74            ("OBJECTIVEAI_AGENT_REMOTE", &self.agent_remote),
75            ("OBJECTIVEAI_RESPONSE_ID", &self.response_id),
76            ("OBJECTIVEAI_RESPONSE_IDS", &self.response_ids),
77            (crate::mcp::MCP_SESSION_ID_ENV, &self.mcp_session_id),
78        ];
79        for (name, value) in pairs {
80            match value {
81                Some(v) => {
82                    command.env(name, v);
83                }
84                None => {
85                    command.env_remove(name);
86                }
87            }
88        }
89    }
90}