Skip to main content

objectiveai_sdk/cli/command/functions/execute/swiss_system/
mod.rs

1//! `functions execute swiss-system` — async handler stub.
2
3use crate::cli::command::CommandRequest;
4use crate::functions::expression::InputValue;
5use super::{FunctionArgs, FunctionSpec, ProfileArgs, ProfileSpec};
6
7#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
8#[schemars(rename = "cli.command.functions.execute.swiss_system.Request")]
9pub struct Request {
10    pub path_type: Path,
11    pub function: FunctionSpec,
12    pub profile: ProfileSpec,
13    pub input: RequestInput,
14    pub continuation: Option<String>,
15    pub split: bool,
16    pub invert: bool,
17    pub pool: Option<usize>,
18    pub rounds: Option<usize>,
19    pub dangerous_advanced: Option<RequestDangerousAdvanced>,
20    #[serde(flatten)]
21    pub base: crate::cli::command::RequestBase,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
25#[schemars(rename = "cli.command.functions.execute.swiss_system.Path")]
26pub enum Path {
27    #[serde(rename = "functions/execute/swiss_system")]
28    FunctionsExecuteSwissSystem,
29}
30
31#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
32#[schemars(rename = "cli.command.functions.execute.swiss_system.RequestInput")]
33pub enum RequestInput {
34    #[schemars(title = "Inline")]
35    Inline(InputValue),
36    #[schemars(title = "File")]
37    File(std::path::PathBuf),
38    #[schemars(title = "PythonInline")]
39    PythonInline(String),
40    #[schemars(title = "PythonFile")]
41    PythonFile(std::path::PathBuf),
42}
43
44impl RequestInput {
45    fn push_flags(&self, out: &mut Vec<String>) {
46        match self {
47            RequestInput::Inline(v) => {
48                out.push("--input-inline".to_string());
49                out.push(serde_json::to_string(v).expect("input serializes"));
50            }
51            RequestInput::File(p) => {
52                out.push("--input-file".to_string());
53                out.push(p.to_string_lossy().into_owned());
54            }
55            RequestInput::PythonInline(code) => {
56                out.push("--input-python-inline".to_string());
57                out.push(code.clone());
58            }
59            RequestInput::PythonFile(p) => {
60                out.push("--input-python-file".to_string());
61                out.push(p.to_string_lossy().into_owned());
62            }
63        }
64    }
65}
66
67impl CommandRequest for Request {
68    fn request_base(&self) -> &crate::cli::command::RequestBase {
69        &self.base
70    }
71
72    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
73        Some(&mut self.base)
74    }
75}
76
77#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
78#[schemars(rename = "cli.command.functions.execute.swiss_system.RequestDangerousAdvanced")]
79pub struct RequestDangerousAdvanced {
80    #[serde(default, skip_serializing_if = "Option::is_none")]
81    #[schemars(extend("omitempty" = true))]
82    pub stream: Option<bool>,
83    /// Deterministic seed for downstream mock agents. Forwarded
84    /// to every per-task `AgentCompletionCreateParams.seed`.
85    #[serde(default, skip_serializing_if = "Option::is_none")]
86    #[schemars(extend("omitempty" = true))]
87    pub seed: Option<i64>,
88}
89
90/// A unique agent instance participating in this execution, announced
91/// exactly once — right after its instance lock is acquired (the same
92/// moment `agents spawn` announces its own hierarchy). The constant
93/// `type:"agent_instance_hierarchy"` discriminator disambiguates this
94/// variant inside the untagged [`ResponseItem`] union, mirroring
95/// `type:"mcp"` on `plugins run`'s `Mcp`.
96#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
97#[schemars(rename = "cli.command.functions.execute.swiss_system.AgentInstanceHierarchy")]
98pub struct AgentInstanceHierarchy {
99    pub r#type: AgentInstanceHierarchyType,
100    pub agent_instance_hierarchy: String,
101}
102
103/// Single-variant discriminator for [`AgentInstanceHierarchy`]'s
104/// `type` field. Always `"agent_instance_hierarchy"` on the wire.
105#[derive(
106    Debug,
107    Clone,
108    Copy,
109    PartialEq,
110    Eq,
111    serde::Serialize,
112    serde::Deserialize,
113    schemars::JsonSchema,
114)]
115#[serde(rename_all = "snake_case")]
116#[schemars(rename = "cli.command.functions.execute.swiss_system.AgentInstanceHierarchyType")]
117pub enum AgentInstanceHierarchyType {
118    AgentInstanceHierarchy,
119}
120
121#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
122#[serde(untagged)]
123#[schemars(rename = "cli.command.functions.execute.swiss_system.ResponseItem")]
124pub enum ResponseItem {
125    // Placement above `Chunk` is load-bearing: serde untagged tries
126    // variants in source order, and the constant discriminator must
127    // win before the all-optional chunk object could absorb it.
128    #[schemars(title = "AgentInstanceHierarchy")]
129    AgentInstanceHierarchy(AgentInstanceHierarchy),
130    #[schemars(title = "Chunk")]
131    Chunk(crate::functions::executions::response::streaming::FunctionExecutionChunk),
132    #[schemars(title = "Id")]
133    Id(String),
134}
135
136/// Non-chunk variant of [`ResponseItem`]. Returned by the unary `execute`
137/// path (with `dangerous_advanced.stream` cleared) when the cli emits a
138/// single bare id string.
139pub type Response = String;
140
141/// Exactly-one-of `--input-inline | --input-file | --input-python-inline
142/// | --input-python-file`. See
143/// `super::standard::InputArgs` for the group-id rationale.
144#[derive(clap::Args)]
145#[group(id = "input_group", required = true, multiple = false)]
146pub struct InputArgs {
147    /// Inline JSON input value.
148    #[arg(long, group = "input_group")]
149    pub input_inline: Option<String>,
150    /// Path to a JSON file containing the input value.
151    #[arg(long, group = "input_group")]
152    pub input_file: Option<std::path::PathBuf>,
153    /// Inline Python that produces the input value.
154    #[arg(long, group = "input_group")]
155    pub input_python_inline: Option<String>,
156    /// Path to a Python file that produces the input value.
157    #[arg(long, group = "input_group")]
158    pub input_python_file: Option<std::path::PathBuf>,
159}
160
161#[derive(clap::Args)]
162pub struct Args {
163    /// Exactly one of `--function`, `--function-inline`,
164    /// `--function-file`, `--function-python-inline`,
165    /// `--function-python-file`.
166    #[command(flatten)]
167    pub function: FunctionArgs,
168    /// Exactly one of `--profile`, `--profile-inline`,
169    /// `--profile-file`, `--profile-python-inline`,
170    /// `--profile-python-file`.
171    #[command(flatten)]
172    pub profile: ProfileArgs,
173    /// Exactly one of `--input-inline`, `--input-file`,
174    /// `--input-python-inline`, `--input-python-file`.
175    #[command(flatten)]
176    pub input: InputArgs,
177    /// Continuation token from a previous response.
178    #[arg(long)]
179    pub continuation: Option<String>,
180    /// Treat input as an array and execute once per element.
181    #[arg(long)]
182    pub split: bool,
183    /// Invert outputs after expressions evaluate.
184    #[arg(long)]
185    pub invert: bool,
186    /// Advanced opt-in flags as inline JSON.
187    #[arg(long)]
188    pub dangerous_advanced: Option<String>,
189    /// How many vector responses per execution.
190    #[arg(long)]
191    pub pool: Option<usize>,
192    /// How many sequential rounds of comparison.
193    #[arg(long)]
194    pub rounds: Option<usize>,
195    #[command(flatten)]
196    pub base: crate::cli::command::RequestBaseArgs,
197}
198
199#[derive(clap::Args)]
200#[command(args_conflicts_with_subcommands = true)]
201pub struct Command {
202    #[command(flatten)]
203    pub args: Args,
204    #[command(subcommand)]
205    pub schema: Option<Schema>,
206}
207
208#[derive(clap::Subcommand)]
209pub enum Schema {
210    /// Emit the JSON Schema for this leaf's `Request` type and exit.
211    RequestSchema(request_schema::Args),
212    /// Emit the JSON Schema for this leaf's `Response` type and exit.
213    ResponseSchema(response_schema::Args),
214}
215
216impl TryFrom<Args> for Request {
217    type Error = crate::cli::command::FromArgsError;
218    fn try_from(args: Args) -> Result<Self, Self::Error> {
219        let function = FunctionSpec::try_from(args.function)?;
220        let profile = ProfileSpec::try_from(args.profile)?;
221        let input = if let Some(s) = args.input.input_inline {
222            let mut de = serde_json::Deserializer::from_str(&s);
223            let v = serde_path_to_error::deserialize(&mut de)
224                .map_err(|e| crate::cli::command::FromArgsError::json("input_inline", e))?;
225            RequestInput::Inline(v)
226        } else if let Some(p) = args.input.input_file {
227            RequestInput::File(p)
228        } else if let Some(s) = args.input.input_python_inline {
229            RequestInput::PythonInline(s)
230        } else {
231            RequestInput::PythonFile(args.input.input_python_file.unwrap())
232        };
233        let dangerous_advanced: Option<RequestDangerousAdvanced> =
234            if let Some(s) = args.dangerous_advanced {
235                let mut de = serde_json::Deserializer::from_str(&s);
236                let v = serde_path_to_error::deserialize(&mut de)
237                    .map_err(|e| crate::cli::command::FromArgsError::json("dangerous_advanced", e))?;
238                Some(v)
239            } else {
240                None
241            };
242        Ok(Self { path_type: Path::FunctionsExecuteSwissSystem,
243            function,
244            profile,
245            input,
246            continuation: args.continuation,
247            split: args.split,
248            invert: args.invert,
249            pool: args.pool,
250            rounds: args.rounds,
251            dangerous_advanced,
252            base: args.base.into(),
253        })
254    }
255}
256
257#[cfg(feature = "cli-executor")]
258pub async fn execute_streaming<E: crate::cli::command::CommandExecutor>(
259    executor: &E,
260    mut request: Request,
261
262        agent_arguments: Option<&crate::cli::command::AgentArguments>,
263    ) -> Result<E::Stream<ResponseItem>, E::Error> {
264    request.base.clear_transform();
265    let mut advanced = request.dangerous_advanced.unwrap_or_default();
266    advanced.stream = Some(true);
267    request.dangerous_advanced = Some(advanced);
268    executor.execute(request, agent_arguments).await
269}
270
271#[cfg(feature = "cli-executor")]
272pub async fn execute_streaming_transform<E: crate::cli::command::CommandExecutor>(
273    executor: &E,
274    mut request: Request,
275    transform: crate::cli::command::Transform,
276
277        agent_arguments: Option<&crate::cli::command::AgentArguments>,
278    ) -> Result<E::Stream<serde_json::Value>, E::Error> {
279    request.base.set_transform(transform);
280    let mut advanced = request.dangerous_advanced.unwrap_or_default();
281    advanced.stream = Some(true);
282    request.dangerous_advanced = Some(advanced);
283    executor.execute(request, agent_arguments).await
284}
285
286#[cfg(feature = "cli-executor")]
287pub async fn execute<E: crate::cli::command::CommandExecutor>(
288    executor: &E,
289    mut request: Request,
290
291        agent_arguments: Option<&crate::cli::command::AgentArguments>,
292    ) -> Result<Response, E::Error> {
293    request.base.clear_transform();
294    if let Some(advanced) = request.dangerous_advanced.as_mut() {
295        advanced.stream = None;
296    }
297    executor.execute_one(request, agent_arguments).await
298}
299
300#[cfg(feature = "cli-executor")]
301pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
302    executor: &E,
303    mut request: Request,
304    transform: crate::cli::command::Transform,
305
306        agent_arguments: Option<&crate::cli::command::AgentArguments>,
307    ) -> Result<serde_json::Value, E::Error> {
308    request.base.set_transform(transform);
309    if let Some(advanced) = request.dangerous_advanced.as_mut() {
310        advanced.stream = None;
311    }
312    executor.execute_one(request, agent_arguments).await
313}
314
315#[cfg(feature = "mcp")]
316impl crate::cli::command::CommandResponse for ResponseItem {
317    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
318        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
319    }
320}
321
322pub mod request_schema;
323
324pub mod response_schema;
325
326/// One `/listen` broadcast run of `functions execute swiss_system` in its unary
327/// form (the plain `execute`): the actual [`Request`], the
328/// producer's
329/// [`AgentArguments`](crate::cli::command::AgentArguments), and the
330/// unary response future. See [`crate::cli::websocket_listener`].
331#[cfg(feature = "cli-listener")]
332pub struct ListenerExecution {
333    pub request: Request,
334    pub agent_arguments: crate::cli::command::AgentArguments,
335    pub response: crate::cli::websocket_listener::UnaryResponse<Response>,
336}
337
338/// One `/listen` broadcast run of `functions execute swiss_system` in its
339/// streaming form (`execute_streaming` — the request set
340/// `dangerous_advanced.stream: true`): the actual [`Request`], the
341/// producer's
342/// [`AgentArguments`](crate::cli::command::AgentArguments), and the
343/// response-item stream. See [`crate::cli::websocket_listener`].
344#[cfg(feature = "cli-listener")]
345pub struct ListenerExecutionStreaming {
346    pub request: Request,
347    pub agent_arguments: crate::cli::command::AgentArguments,
348    pub response: crate::cli::websocket_listener::ResponseItemStream<ResponseItem>,
349}
350
351/// This leaf's multiple listener executions — one variant per
352/// execute fn (`Execution` for the plain `execute`, `Streaming`
353/// for `execute_streaming`), discriminated per request off
354/// `dangerous_advanced.stream`. The branch enum's single variant
355/// for this leaf wraps this.
356#[cfg(feature = "cli-listener")]
357pub enum ListenerExecutionVariant {
358    Execution(ListenerExecution),
359    Streaming(ListenerExecutionStreaming),
360}