1pub mod standard;
2pub mod swiss_system;
3
4#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
18#[serde(untagged)]
19#[schemars(rename = "cli.command.functions.execute.FunctionSpec")]
20pub enum FunctionSpec {
21 #[schemars(title = "Resolved")]
22 Resolved(crate::functions::FullInlineFunctionOrRemoteCommitOptional),
23 #[schemars(title = "Favorite")]
24 Favorite(String),
25 #[schemars(title = "File")]
26 File(std::path::PathBuf),
27 #[schemars(title = "PythonInline")]
28 PythonInline(String),
29 #[schemars(title = "PythonFile")]
30 PythonFile(std::path::PathBuf),
31}
32
33#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
37#[serde(untagged)]
38#[schemars(rename = "cli.command.functions.execute.ProfileSpec")]
39pub enum ProfileSpec {
40 #[schemars(title = "Resolved")]
41 Resolved(crate::functions::InlineProfileOrRemoteCommitOptional),
42 #[schemars(title = "Favorite")]
43 Favorite(String),
44 #[schemars(title = "File")]
45 File(std::path::PathBuf),
46 #[schemars(title = "PythonInline")]
47 PythonInline(String),
48 #[schemars(title = "PythonFile")]
49 PythonFile(std::path::PathBuf),
50}
51
52impl FunctionSpec {
53 pub fn push_flags(&self, out: &mut Vec<String>) {
56 use crate::cli::command::path_ref::remote_path_to_arg_string;
57 use crate::functions::FullInlineFunctionOrRemoteCommitOptional;
58 match self {
59 FunctionSpec::Resolved(FullInlineFunctionOrRemoteCommitOptional::Remote(p)) => {
60 out.push("--function".to_string());
61 out.push(remote_path_to_arg_string(p));
62 }
63 FunctionSpec::Resolved(inline @ FullInlineFunctionOrRemoteCommitOptional::Inline(_)) => {
64 out.push("--function-inline".to_string());
65 out.push(serde_json::to_string(inline).expect("function serializes"));
66 }
67 FunctionSpec::Favorite(name) => {
68 out.push("--function".to_string());
69 out.push(format!("favorite={name}"));
70 }
71 FunctionSpec::File(p) => {
72 out.push("--function-file".to_string());
73 out.push(p.to_string_lossy().into_owned());
74 }
75 FunctionSpec::PythonInline(code) => {
76 out.push("--function-python-inline".to_string());
77 out.push(code.clone());
78 }
79 FunctionSpec::PythonFile(p) => {
80 out.push("--function-python-file".to_string());
81 out.push(p.to_string_lossy().into_owned());
82 }
83 }
84 }
85}
86
87impl ProfileSpec {
88 pub fn push_flags(&self, out: &mut Vec<String>) {
91 use crate::cli::command::path_ref::remote_path_to_arg_string;
92 use crate::functions::InlineProfileOrRemoteCommitOptional;
93 match self {
94 ProfileSpec::Resolved(InlineProfileOrRemoteCommitOptional::Remote(p)) => {
95 out.push("--profile".to_string());
96 out.push(remote_path_to_arg_string(p));
97 }
98 ProfileSpec::Resolved(inline @ InlineProfileOrRemoteCommitOptional::Inline(_)) => {
99 out.push("--profile-inline".to_string());
100 out.push(serde_json::to_string(inline).expect("profile serializes"));
101 }
102 ProfileSpec::Favorite(name) => {
103 out.push("--profile".to_string());
104 out.push(format!("favorite={name}"));
105 }
106 ProfileSpec::File(p) => {
107 out.push("--profile-file".to_string());
108 out.push(p.to_string_lossy().into_owned());
109 }
110 ProfileSpec::PythonInline(code) => {
111 out.push("--profile-python-inline".to_string());
112 out.push(code.clone());
113 }
114 ProfileSpec::PythonFile(p) => {
115 out.push("--profile-python-file".to_string());
116 out.push(p.to_string_lossy().into_owned());
117 }
118 }
119 }
120}
121
122#[derive(clap::Args)]
131#[group(id = "function_group", required = true, multiple = false)]
132pub struct FunctionArgs {
133 #[arg(long, group = "function_group")]
136 pub function: Option<String>,
137 #[arg(long, group = "function_group")]
139 pub function_inline: Option<String>,
140 #[arg(long, group = "function_group")]
142 pub function_file: Option<std::path::PathBuf>,
143 #[arg(long, group = "function_group")]
145 pub function_python_inline: Option<String>,
146 #[arg(long, group = "function_group")]
148 pub function_python_file: Option<std::path::PathBuf>,
149}
150
151#[derive(clap::Args)]
154#[group(id = "profile_group", required = true, multiple = false)]
155pub struct ProfileArgs {
156 #[arg(long, group = "profile_group")]
159 pub profile: Option<String>,
160 #[arg(long, group = "profile_group")]
162 pub profile_inline: Option<String>,
163 #[arg(long, group = "profile_group")]
165 pub profile_file: Option<std::path::PathBuf>,
166 #[arg(long, group = "profile_group")]
168 pub profile_python_inline: Option<String>,
169 #[arg(long, group = "profile_group")]
171 pub profile_python_file: Option<std::path::PathBuf>,
172}
173
174impl TryFrom<FunctionArgs> for FunctionSpec {
175 type Error = crate::cli::command::FromArgsError;
176 fn try_from(args: FunctionArgs) -> Result<Self, Self::Error> {
177 use crate::cli::command::path_ref::RemotePathCommitOptionalOrFavorite;
178 use crate::functions::FullInlineFunctionOrRemoteCommitOptional;
179 if let Some(s) = args.function {
180 let parsed: RemotePathCommitOptionalOrFavorite = s
181 .parse()
182 .map_err(|e| crate::cli::command::FromArgsError::path_parse("function", e))?;
183 Ok(match parsed {
184 RemotePathCommitOptionalOrFavorite::Resolved(p) => FunctionSpec::Resolved(
185 FullInlineFunctionOrRemoteCommitOptional::Remote(p),
186 ),
187 RemotePathCommitOptionalOrFavorite::Favorite(name) => FunctionSpec::Favorite(name),
188 })
189 } else if let Some(s) = args.function_inline {
190 let mut de = serde_json::Deserializer::from_str(&s);
191 let v = serde_path_to_error::deserialize(&mut de)
192 .map_err(|e| crate::cli::command::FromArgsError::json("function_inline", e))?;
193 Ok(FunctionSpec::Resolved(v))
194 } else if let Some(p) = args.function_file {
195 Ok(FunctionSpec::File(p))
196 } else if let Some(s) = args.function_python_inline {
197 Ok(FunctionSpec::PythonInline(s))
198 } else {
199 Ok(FunctionSpec::PythonFile(args.function_python_file.unwrap()))
200 }
201 }
202}
203
204impl TryFrom<ProfileArgs> for ProfileSpec {
205 type Error = crate::cli::command::FromArgsError;
206 fn try_from(args: ProfileArgs) -> Result<Self, Self::Error> {
207 use crate::cli::command::path_ref::RemotePathCommitOptionalOrFavorite;
208 use crate::functions::InlineProfileOrRemoteCommitOptional;
209 if let Some(s) = args.profile {
210 let parsed: RemotePathCommitOptionalOrFavorite = s
211 .parse()
212 .map_err(|e| crate::cli::command::FromArgsError::path_parse("profile", e))?;
213 Ok(match parsed {
214 RemotePathCommitOptionalOrFavorite::Resolved(p) => ProfileSpec::Resolved(
215 InlineProfileOrRemoteCommitOptional::Remote(p),
216 ),
217 RemotePathCommitOptionalOrFavorite::Favorite(name) => ProfileSpec::Favorite(name),
218 })
219 } else if let Some(s) = args.profile_inline {
220 let mut de = serde_json::Deserializer::from_str(&s);
221 let v = serde_path_to_error::deserialize(&mut de)
222 .map_err(|e| crate::cli::command::FromArgsError::json("profile_inline", e))?;
223 Ok(ProfileSpec::Resolved(v))
224 } else if let Some(p) = args.profile_file {
225 Ok(ProfileSpec::File(p))
226 } else if let Some(s) = args.profile_python_inline {
227 Ok(ProfileSpec::PythonInline(s))
228 } else {
229 Ok(ProfileSpec::PythonFile(args.profile_python_file.unwrap()))
230 }
231 }
232}
233
234#[derive(clap::Subcommand)]
235pub enum Command {
236 Standard(standard::Command),
237 SwissSystem(swiss_system::Command),
238}
239
240#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
241#[serde(untagged)]
242#[schemars(rename = "cli.command.functions.execute.Request")]
243pub enum Request {
244 #[schemars(title = "Standard")]
245 Standard(standard::Request),
246 #[schemars(title = "StandardRequestSchema")]
247 StandardRequestSchema(standard::request_schema::Request),
248 #[schemars(title = "StandardResponseSchema")]
249 StandardResponseSchema(standard::response_schema::Request),
250 #[schemars(title = "SwissSystem")]
251 SwissSystem(swiss_system::Request),
252 #[schemars(title = "SwissSystemRequestSchema")]
253 SwissSystemRequestSchema(swiss_system::request_schema::Request),
254 #[schemars(title = "SwissSystemResponseSchema")]
255 SwissSystemResponseSchema(swiss_system::response_schema::Request),
256}
257
258#[objectiveai_sdk_macros::json_schema_ignore]
261#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
262#[schemars(rename = "cli.command.functions.execute.ResponseItem")]
263#[serde(untagged)]
264pub enum ResponseItem {
265 #[schemars(title = "Standard")]
266 Standard(standard::ResponseItem),
267 #[schemars(title = "StandardRequestSchema")]
268 StandardRequestSchema(standard::request_schema::Response),
269 #[schemars(title = "StandardResponseSchema")]
270 StandardResponseSchema(standard::response_schema::Response),
271 #[schemars(title = "SwissSystem")]
272 SwissSystem(swiss_system::ResponseItem),
273 #[schemars(title = "SwissSystemRequestSchema")]
274 SwissSystemRequestSchema(swiss_system::request_schema::Response),
275 #[schemars(title = "SwissSystemResponseSchema")]
276 SwissSystemResponseSchema(swiss_system::response_schema::Response),
277}
278
279#[cfg(feature = "mcp")]
280impl crate::cli::command::CommandResponse for ResponseItem {
281 fn into_mcp(self) -> crate::cli::command::McpResponseItem {
282 match self {
283 ResponseItem::Standard(v) => v.into_mcp(),
284 ResponseItem::StandardRequestSchema(v) => v.into_mcp(),
285 ResponseItem::StandardResponseSchema(v) => v.into_mcp(),
286 ResponseItem::SwissSystem(v) => v.into_mcp(),
287 ResponseItem::SwissSystemRequestSchema(v) => v.into_mcp(),
288 ResponseItem::SwissSystemResponseSchema(v) => v.into_mcp(),
289 }
290 }
291}
292
293impl TryFrom<Command> for Request {
294 type Error = crate::cli::command::FromArgsError;
295 fn try_from(command: Command) -> Result<Self, Self::Error> {
296 match command {
297 Command::Standard(cmd) => match cmd.schema {
298 None => Ok(Request::Standard(standard::Request::try_from(cmd.args)?)),
299 Some(standard::Schema::RequestSchema(args)) =>
300 Ok(Request::StandardRequestSchema(standard::request_schema::Request::try_from(args)?)),
301 Some(standard::Schema::ResponseSchema(args)) =>
302 Ok(Request::StandardResponseSchema(standard::response_schema::Request::try_from(args)?)),
303 },
304 Command::SwissSystem(cmd) => match cmd.schema {
305 None => Ok(Request::SwissSystem(swiss_system::Request::try_from(cmd.args)?)),
306 Some(swiss_system::Schema::RequestSchema(args)) =>
307 Ok(Request::SwissSystemRequestSchema(swiss_system::request_schema::Request::try_from(args)?)),
308 Some(swiss_system::Schema::ResponseSchema(args)) =>
309 Ok(Request::SwissSystemResponseSchema(swiss_system::response_schema::Request::try_from(args)?)),
310 },
311 }
312 }
313}
314
315impl crate::cli::command::CommandRequest for Request {
316 fn into_command(&self) -> Vec<String> {
317 match self {
318 Request::Standard(inner) => inner.into_command(),
319 Request::StandardRequestSchema(inner) => inner.into_command(),
320 Request::StandardResponseSchema(inner) => inner.into_command(),
321 Request::SwissSystem(inner) => inner.into_command(),
322 Request::SwissSystemRequestSchema(inner) => inner.into_command(),
323 Request::SwissSystemResponseSchema(inner) => inner.into_command(),
324 }
325 }
326}
327
328#[cfg(feature = "cli-executor")]
329pub async fn execute<E: crate::cli::command::CommandExecutor>(
330 executor: &E,
331 request: Request,
332
333 agent_arguments: Option<&crate::cli::command::AgentArguments>,
334 ) -> Result<
335 std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>>,
336 E::Error,
337> {
338 use futures::StreamExt;
339 let stream: std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>> =
340 match request {
341 Request::Standard(req) => {
342 let want_streaming = req
343 .dangerous_advanced
344 .as_ref()
345 .and_then(|a| a.stream)
346 .unwrap_or(false);
347 if want_streaming {
348 let inner = standard::execute_streaming(executor, req, agent_arguments).await?;
349 Box::pin(inner.map(|r| r.map(ResponseItem::Standard)))
350 } else {
351 let value = standard::execute(executor, req, agent_arguments).await?;
352 Box::pin(crate::cli::command::StreamOnce::new(Ok(
353 ResponseItem::Standard(standard::ResponseItem::Id(value)),
354 )))
355 }
356 }
357 Request::StandardRequestSchema(req) => {
358 let value = standard::request_schema::execute(executor, req, agent_arguments).await?;
359 Box::pin(crate::cli::command::StreamOnce::new(Ok(
360 ResponseItem::StandardRequestSchema(value),
361 )))
362 }
363 Request::StandardResponseSchema(req) => {
364 let value = standard::response_schema::execute(executor, req, agent_arguments).await?;
365 Box::pin(crate::cli::command::StreamOnce::new(Ok(
366 ResponseItem::StandardResponseSchema(value),
367 )))
368 }
369 Request::SwissSystem(req) => {
370 let want_streaming = req
371 .dangerous_advanced
372 .as_ref()
373 .and_then(|a| a.stream)
374 .unwrap_or(false);
375 if want_streaming {
376 let inner = swiss_system::execute_streaming(executor, req, agent_arguments).await?;
377 Box::pin(inner.map(|r| r.map(ResponseItem::SwissSystem)))
378 } else {
379 let value = swiss_system::execute(executor, req, agent_arguments).await?;
380 Box::pin(crate::cli::command::StreamOnce::new(Ok(
381 ResponseItem::SwissSystem(swiss_system::ResponseItem::Id(value)),
382 )))
383 }
384 }
385 Request::SwissSystemRequestSchema(req) => {
386 let value = swiss_system::request_schema::execute(executor, req, agent_arguments).await?;
387 Box::pin(crate::cli::command::StreamOnce::new(Ok(
388 ResponseItem::SwissSystemRequestSchema(value),
389 )))
390 }
391 Request::SwissSystemResponseSchema(req) => {
392 let value = swiss_system::response_schema::execute(executor, req, agent_arguments).await?;
393 Box::pin(crate::cli::command::StreamOnce::new(Ok(
394 ResponseItem::SwissSystemResponseSchema(value),
395 )))
396 }
397 };
398 Ok(stream)
399}
400
401#[cfg(feature = "cli-executor")]
402pub async fn execute_jq<E: crate::cli::command::CommandExecutor>(
403 executor: &E,
404 request: Request,
405 jq: String,
406
407 agent_arguments: Option<&crate::cli::command::AgentArguments>,
408 ) -> Result<
409 std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>>,
410 E::Error,
411> {
412 let stream: std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>> =
413 match request {
414 Request::Standard(req) => {
415 let want_streaming = req
416 .dangerous_advanced
417 .as_ref()
418 .and_then(|a| a.stream)
419 .unwrap_or(false);
420 if want_streaming {
421 let inner = standard::execute_streaming_jq(executor, req, jq, agent_arguments).await?;
422 Box::pin(inner)
423 } else {
424 let value = standard::execute_jq(executor, req, jq, agent_arguments).await?;
425 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
426 }
427 }
428 Request::StandardRequestSchema(req) => {
429 let value = standard::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
430 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
431 }
432 Request::StandardResponseSchema(req) => {
433 let value = standard::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
434 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
435 }
436 Request::SwissSystem(req) => {
437 let want_streaming = req
438 .dangerous_advanced
439 .as_ref()
440 .and_then(|a| a.stream)
441 .unwrap_or(false);
442 if want_streaming {
443 let inner = swiss_system::execute_streaming_jq(executor, req, jq, agent_arguments).await?;
444 Box::pin(inner)
445 } else {
446 let value = swiss_system::execute_jq(executor, req, jq, agent_arguments).await?;
447 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
448 }
449 }
450 Request::SwissSystemRequestSchema(req) => {
451 let value = swiss_system::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
452 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
453 }
454 Request::SwissSystemResponseSchema(req) => {
455 let value = swiss_system::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
456 Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
457 }
458 };
459 Ok(stream)
460}