Skip to main content

objectiveai_sdk/cli/command/laboratories/
mod.rs

1//! `laboratories` — top-level group for laboratory containers (podman
2//! containers the conduit dials as client-side MCP servers), sibling to
3//! `agents`/`swarms`. Distinct from `agents laboratories` (attachments).
4//! `create` creates + starts a laboratory container; `list` streams the
5//! laboratory containers created in this state.
6
7use crate::cli::command::CommandRequest;
8
9pub mod create;
10pub mod list;
11
12#[derive(clap::Subcommand)]
13pub enum Command {
14    /// Create + start a laboratory container.
15    Create(create::Command),
16    /// List the laboratory containers created in this state.
17    List(list::Command),
18}
19
20#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
21#[serde(untagged)]
22#[schemars(rename = "cli.command.laboratories.Request")]
23pub enum Request {
24    #[schemars(title = "Create")]
25    Create(create::Request),
26    #[schemars(title = "CreateRequestSchema")]
27    CreateRequestSchema(create::request_schema::Request),
28    #[schemars(title = "CreateResponseSchema")]
29    CreateResponseSchema(create::response_schema::Request),
30    #[schemars(title = "List")]
31    List(list::Request),
32    #[schemars(title = "ListRequestSchema")]
33    ListRequestSchema(list::request_schema::Request),
34    #[schemars(title = "ListResponseSchema")]
35    ListResponseSchema(list::response_schema::Request),
36}
37
38// Exempt from json-schema coverage: tier aggregate (see the root
39// `ResponseItem` in command.rs - TS7056).
40#[objectiveai_sdk_macros::json_schema_ignore]
41#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
42#[schemars(rename = "cli.command.laboratories.ResponseItem")]
43#[serde(untagged)]
44pub enum ResponseItem {
45    #[schemars(title = "Create")]
46    Create(create::Response),
47    #[schemars(title = "CreateRequestSchema")]
48    CreateRequestSchema(create::request_schema::Response),
49    #[schemars(title = "CreateResponseSchema")]
50    CreateResponseSchema(create::response_schema::Response),
51    #[schemars(title = "List")]
52    List(list::ResponseItem),
53    #[schemars(title = "ListRequestSchema")]
54    ListRequestSchema(list::request_schema::Response),
55    #[schemars(title = "ListResponseSchema")]
56    ListResponseSchema(list::response_schema::Response),
57}
58
59#[cfg(feature = "mcp")]
60impl crate::cli::command::CommandResponse for ResponseItem {
61    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
62        match self {
63            ResponseItem::Create(v) => v.into_mcp(),
64            ResponseItem::CreateRequestSchema(v) => v.into_mcp(),
65            ResponseItem::CreateResponseSchema(v) => v.into_mcp(),
66            ResponseItem::List(v) => v.into_mcp(),
67            ResponseItem::ListRequestSchema(v) => v.into_mcp(),
68            ResponseItem::ListResponseSchema(v) => v.into_mcp(),
69        }
70    }
71}
72
73impl TryFrom<Command> for Request {
74    type Error = crate::cli::command::FromArgsError;
75    fn try_from(command: Command) -> Result<Self, Self::Error> {
76        match command {
77            Command::Create(cmd) => match cmd.schema {
78                None => Ok(Request::Create(create::Request::try_from(cmd.args)?)),
79                Some(create::Schema::RequestSchema(args)) => Ok(Request::CreateRequestSchema(
80                    create::request_schema::Request::try_from(args)?,
81                )),
82                Some(create::Schema::ResponseSchema(args)) => Ok(Request::CreateResponseSchema(
83                    create::response_schema::Request::try_from(args)?,
84                )),
85            },
86            Command::List(cmd) => match cmd.schema {
87                None => Ok(Request::List(list::Request::try_from(cmd.args)?)),
88                Some(list::Schema::RequestSchema(args)) => Ok(Request::ListRequestSchema(
89                    list::request_schema::Request::try_from(args)?,
90                )),
91                Some(list::Schema::ResponseSchema(args)) => Ok(Request::ListResponseSchema(
92                    list::response_schema::Request::try_from(args)?,
93                )),
94            },
95        }
96    }
97}
98
99impl CommandRequest for Request {
100    fn request_base(&self) -> &crate::cli::command::RequestBase {
101        match self {
102            Request::Create(inner) => inner.request_base(),
103            Request::CreateRequestSchema(inner) => inner.request_base(),
104            Request::CreateResponseSchema(inner) => inner.request_base(),
105            Request::List(inner) => inner.request_base(),
106            Request::ListRequestSchema(inner) => inner.request_base(),
107            Request::ListResponseSchema(inner) => inner.request_base(),
108        }
109    }
110
111    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
112        match self {
113            Request::Create(inner) => inner.request_base_mut(),
114            Request::CreateRequestSchema(inner) => inner.request_base_mut(),
115            Request::CreateResponseSchema(inner) => inner.request_base_mut(),
116            Request::List(inner) => inner.request_base_mut(),
117            Request::ListRequestSchema(inner) => inner.request_base_mut(),
118            Request::ListResponseSchema(inner) => inner.request_base_mut(),
119        }
120    }
121}
122
123#[cfg(feature = "cli-executor")]
124pub async fn execute<E: crate::cli::command::CommandExecutor>(
125    executor: &E,
126    request: Request,
127    agent_arguments: Option<&crate::cli::command::AgentArguments>,
128) -> Result<
129    std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>>,
130    E::Error,
131> {
132    use futures::StreamExt as _;
133    let stream: std::pin::Pin<
134        Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>,
135    > = match request {
136        Request::Create(req) => {
137            let value = create::execute(executor, req, agent_arguments).await?;
138            Box::pin(crate::cli::command::StreamOnce::new(Ok(
139                ResponseItem::Create(value),
140            )))
141        }
142        Request::CreateRequestSchema(req) => {
143            let value = create::request_schema::execute(executor, req, agent_arguments).await?;
144            Box::pin(crate::cli::command::StreamOnce::new(Ok(
145                ResponseItem::CreateRequestSchema(value),
146            )))
147        }
148        Request::CreateResponseSchema(req) => {
149            let value = create::response_schema::execute(executor, req, agent_arguments).await?;
150            Box::pin(crate::cli::command::StreamOnce::new(Ok(
151                ResponseItem::CreateResponseSchema(value),
152            )))
153        }
154        Request::List(req) => {
155            let inner = list::execute(executor, req, agent_arguments).await?;
156            Box::pin(inner.map(|r| r.map(ResponseItem::List)))
157        }
158        Request::ListRequestSchema(req) => {
159            let value = list::request_schema::execute(executor, req, agent_arguments).await?;
160            Box::pin(crate::cli::command::StreamOnce::new(Ok(
161                ResponseItem::ListRequestSchema(value),
162            )))
163        }
164        Request::ListResponseSchema(req) => {
165            let value = list::response_schema::execute(executor, req, agent_arguments).await?;
166            Box::pin(crate::cli::command::StreamOnce::new(Ok(
167                ResponseItem::ListResponseSchema(value),
168            )))
169        }
170    };
171    Ok(stream)
172}
173
174#[cfg(feature = "cli-executor")]
175pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
176    executor: &E,
177    request: Request,
178    transform: crate::cli::command::Transform,
179    agent_arguments: Option<&crate::cli::command::AgentArguments>,
180) -> Result<
181    std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>>,
182    E::Error,
183> {
184    let stream: std::pin::Pin<
185        Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>,
186    > = match request {
187        Request::Create(req) => {
188            let value = create::execute_transform(executor, req, transform, agent_arguments).await?;
189            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
190        }
191        Request::CreateRequestSchema(req) => {
192            let value = create::request_schema::execute_transform(
193                executor,
194                req,
195                transform,
196                agent_arguments,
197            )
198            .await?;
199            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
200        }
201        Request::CreateResponseSchema(req) => {
202            let value = create::response_schema::execute_transform(
203                executor,
204                req,
205                transform,
206                agent_arguments,
207            )
208            .await?;
209            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
210        }
211        Request::List(req) => {
212            let inner = list::execute_transform(executor, req, transform, agent_arguments).await?;
213            Box::pin(inner)
214        }
215        Request::ListRequestSchema(req) => {
216            let value = list::request_schema::execute_transform(
217                executor,
218                req,
219                transform,
220                agent_arguments,
221            )
222            .await?;
223            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
224        }
225        Request::ListResponseSchema(req) => {
226            let value = list::response_schema::execute_transform(
227                executor,
228                req,
229                transform,
230                agent_arguments,
231            )
232            .await?;
233            Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
234        }
235    };
236    Ok(stream)
237}