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