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 into_command(&self) -> Vec<String> {
69        let mut argv = vec![
70            "functions".to_string(),
71            "execute".to_string(),
72            "swiss-system".to_string(),
73        ];
74        self.function.push_flags(&mut argv);
75        self.profile.push_flags(&mut argv);
76        self.input.push_flags(&mut argv);
77        if let Some(c) = &self.continuation {
78            argv.push("--continuation".to_string());
79            argv.push(c.clone());
80        }
81        if self.split {
82            argv.push("--split".to_string());
83        }
84        if self.invert {
85            argv.push("--invert".to_string());
86        }
87        if let Some(pool) = self.pool {
88            argv.push("--pool".to_string());
89            argv.push(pool.to_string());
90        }
91        if let Some(rounds) = self.rounds {
92            argv.push("--rounds".to_string());
93            argv.push(rounds.to_string());
94        }
95        if let Some(advanced) = &self.dangerous_advanced {
96            argv.push("--dangerous-advanced".to_string());
97            argv.push(
98                serde_json::to_string(advanced)
99                    .expect("RequestDangerousAdvanced serializes"),
100            );
101        }
102        self.base.push_flags(&mut argv);
103        argv
104    }
105
106    fn request_base(&self) -> &crate::cli::command::RequestBase {
107        &self.base
108    }
109
110    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
111        Some(&mut self.base)
112    }
113}
114
115#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
116#[schemars(rename = "cli.command.functions.execute.swiss_system.RequestDangerousAdvanced")]
117pub struct RequestDangerousAdvanced {
118    #[serde(default, skip_serializing_if = "Option::is_none")]
119    #[schemars(extend("omitempty" = true))]
120    pub stream: Option<bool>,
121    /// Deterministic seed for downstream mock agents. Forwarded
122    /// to every per-task `AgentCompletionCreateParams.seed`.
123    #[serde(default, skip_serializing_if = "Option::is_none")]
124    #[schemars(extend("omitempty" = true))]
125    pub seed: Option<i64>,
126}
127
128#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
129#[serde(untagged)]
130#[schemars(rename = "cli.command.functions.execute.swiss_system.ResponseItem")]
131pub enum ResponseItem {
132    #[schemars(title = "Chunk")]
133    Chunk(crate::functions::executions::response::streaming::FunctionExecutionChunk),
134    #[schemars(title = "Id")]
135    Id(String),
136}
137
138/// Non-chunk variant of [`ResponseItem`]. Returned by the unary `execute`
139/// path (with `dangerous_advanced.stream` cleared) when the cli emits a
140/// single bare id string.
141pub type Response = String;
142
143/// Exactly-one-of `--input-inline | --input-file | --input-python-inline
144/// | --input-python-file`. See
145/// `super::standard::InputArgs` for the group-id rationale.
146#[derive(clap::Args)]
147#[group(id = "input_group", required = true, multiple = false)]
148pub struct InputArgs {
149    /// Inline JSON input value.
150    #[arg(long, group = "input_group")]
151    pub input_inline: Option<String>,
152    /// Path to a JSON file containing the input value.
153    #[arg(long, group = "input_group")]
154    pub input_file: Option<std::path::PathBuf>,
155    /// Inline Python that produces the input value.
156    #[arg(long, group = "input_group")]
157    pub input_python_inline: Option<String>,
158    /// Path to a Python file that produces the input value.
159    #[arg(long, group = "input_group")]
160    pub input_python_file: Option<std::path::PathBuf>,
161}
162
163#[derive(clap::Args)]
164pub struct Args {
165    /// Exactly one of `--function`, `--function-inline`,
166    /// `--function-file`, `--function-python-inline`,
167    /// `--function-python-file`.
168    #[command(flatten)]
169    pub function: FunctionArgs,
170    /// Exactly one of `--profile`, `--profile-inline`,
171    /// `--profile-file`, `--profile-python-inline`,
172    /// `--profile-python-file`.
173    #[command(flatten)]
174    pub profile: ProfileArgs,
175    /// Exactly one of `--input-inline`, `--input-file`,
176    /// `--input-python-inline`, `--input-python-file`.
177    #[command(flatten)]
178    pub input: InputArgs,
179    /// Continuation token from a previous response.
180    #[arg(long)]
181    pub continuation: Option<String>,
182    /// Treat input as an array and execute once per element.
183    #[arg(long)]
184    pub split: bool,
185    /// Invert outputs after expressions evaluate.
186    #[arg(long)]
187    pub invert: bool,
188    /// Advanced opt-in flags as inline JSON.
189    #[arg(long)]
190    pub dangerous_advanced: Option<String>,
191    /// How many vector responses per execution.
192    #[arg(long)]
193    pub pool: Option<usize>,
194    /// How many sequential rounds of comparison.
195    #[arg(long)]
196    pub rounds: Option<usize>,
197    #[command(flatten)]
198    pub base: crate::cli::command::RequestBaseArgs,
199}
200
201#[derive(clap::Args)]
202#[command(args_conflicts_with_subcommands = true)]
203pub struct Command {
204    #[command(flatten)]
205    pub args: Args,
206    #[command(subcommand)]
207    pub schema: Option<Schema>,
208}
209
210#[derive(clap::Subcommand)]
211pub enum Schema {
212    /// Emit the JSON Schema for this leaf's `Request` type and exit.
213    RequestSchema(request_schema::Args),
214    /// Emit the JSON Schema for this leaf's `Response` type and exit.
215    ResponseSchema(response_schema::Args),
216}
217
218impl TryFrom<Args> for Request {
219    type Error = crate::cli::command::FromArgsError;
220    fn try_from(args: Args) -> Result<Self, Self::Error> {
221        let function = FunctionSpec::try_from(args.function)?;
222        let profile = ProfileSpec::try_from(args.profile)?;
223        let input = if let Some(s) = args.input.input_inline {
224            let mut de = serde_json::Deserializer::from_str(&s);
225            let v = serde_path_to_error::deserialize(&mut de)
226                .map_err(|e| crate::cli::command::FromArgsError::json("input_inline", e))?;
227            RequestInput::Inline(v)
228        } else if let Some(p) = args.input.input_file {
229            RequestInput::File(p)
230        } else if let Some(s) = args.input.input_python_inline {
231            RequestInput::PythonInline(s)
232        } else {
233            RequestInput::PythonFile(args.input.input_python_file.unwrap())
234        };
235        let dangerous_advanced: Option<RequestDangerousAdvanced> =
236            if let Some(s) = args.dangerous_advanced {
237                let mut de = serde_json::Deserializer::from_str(&s);
238                let v = serde_path_to_error::deserialize(&mut de)
239                    .map_err(|e| crate::cli::command::FromArgsError::json("dangerous_advanced", e))?;
240                Some(v)
241            } else {
242                None
243            };
244        Ok(Self { path_type: Path::FunctionsExecuteSwissSystem,
245            function,
246            profile,
247            input,
248            continuation: args.continuation,
249            split: args.split,
250            invert: args.invert,
251            pool: args.pool,
252            rounds: args.rounds,
253            dangerous_advanced,
254            base: args.base.into(),
255        })
256    }
257}
258
259#[cfg(feature = "cli-executor")]
260pub async fn execute_streaming<E: crate::cli::command::CommandExecutor>(
261    executor: &E,
262    mut request: Request,
263
264        agent_arguments: Option<&crate::cli::command::AgentArguments>,
265    ) -> Result<E::Stream<ResponseItem>, E::Error> {
266    request.base.clear_transform();
267    let mut advanced = request.dangerous_advanced.unwrap_or_default();
268    advanced.stream = Some(true);
269    request.dangerous_advanced = Some(advanced);
270    executor.execute(request, agent_arguments).await
271}
272
273#[cfg(feature = "cli-executor")]
274pub async fn execute_streaming_transform<E: crate::cli::command::CommandExecutor>(
275    executor: &E,
276    mut request: Request,
277    transform: crate::cli::command::Transform,
278
279        agent_arguments: Option<&crate::cli::command::AgentArguments>,
280    ) -> Result<E::Stream<serde_json::Value>, E::Error> {
281    request.base.set_transform(transform);
282    let mut advanced = request.dangerous_advanced.unwrap_or_default();
283    advanced.stream = Some(true);
284    request.dangerous_advanced = Some(advanced);
285    executor.execute(request, agent_arguments).await
286}
287
288#[cfg(feature = "cli-executor")]
289pub async fn execute<E: crate::cli::command::CommandExecutor>(
290    executor: &E,
291    mut request: Request,
292
293        agent_arguments: Option<&crate::cli::command::AgentArguments>,
294    ) -> Result<Response, E::Error> {
295    request.base.clear_transform();
296    if let Some(advanced) = request.dangerous_advanced.as_mut() {
297        advanced.stream = None;
298    }
299    executor.execute_one(request, agent_arguments).await
300}
301
302#[cfg(feature = "cli-executor")]
303pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
304    executor: &E,
305    mut request: Request,
306    transform: crate::cli::command::Transform,
307
308        agent_arguments: Option<&crate::cli::command::AgentArguments>,
309    ) -> Result<serde_json::Value, E::Error> {
310    request.base.set_transform(transform);
311    if let Some(advanced) = request.dangerous_advanced.as_mut() {
312        advanced.stream = None;
313    }
314    executor.execute_one(request, agent_arguments).await
315}
316
317#[cfg(feature = "mcp")]
318impl crate::cli::command::CommandResponse for ResponseItem {
319    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
320        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
321    }
322}
323
324pub mod request_schema;
325
326
327pub mod response_schema;