Skip to main content

objectiveai_sdk/cli/command/agents/laboratories/detach/
mod.rs

1//! `agents laboratories detach` — detach a laboratory id from an agent
2//! target (a tag, or an instance hierarchy via PAIH + `--agent-instance`).
3//! Keyed the same way as `attach`; see the CLI handler for the lock +
4//! delete. Errors if the laboratory was not attached.
5
6use crate::cli::command::CommandRequest;
7use crate::cli::command::agents::selector::{AgentSelector, AgentSelectorArgs};
8
9#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
10#[schemars(rename = "cli.command.agents.laboratories.detach.Request")]
11pub struct Request {
12    pub path_type: Path,
13    pub selector: AgentSelector,
14    pub laboratory_id: String,
15    #[serde(flatten)]
16    pub base: crate::cli::command::RequestBase,
17}
18
19#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
20#[schemars(rename = "cli.command.agents.laboratories.detach.Path")]
21pub enum Path {
22    #[serde(rename = "agents/laboratories/detach")]
23    AgentsLaboratoriesDetach,
24}
25
26impl CommandRequest for Request {
27    fn request_base(&self) -> &crate::cli::command::RequestBase {
28        &self.base
29    }
30
31    fn request_base_mut(&mut self) -> Option<&mut crate::cli::command::RequestBase> {
32        Some(&mut self.base)
33    }
34}
35
36/// Confirmation — detach succeeded; echoes the laboratory id that was
37/// detached.
38#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
39#[schemars(rename = "cli.command.agents.laboratories.detach.Response")]
40pub struct Response {
41    /// The laboratory id that was detached from the target.
42    pub laboratory_id: String,
43}
44
45#[derive(clap::Args)]
46#[command(group(clap::ArgGroup::new("laboratory_id_required").required(true).args(["laboratory_id"])))]
47pub struct Args {
48    #[command(flatten)]
49    pub selector: AgentSelectorArgs,
50    /// Laboratory id to detach from the target agent.
51    #[arg(long)]
52    pub laboratory_id: Option<String>,
53    #[command(flatten)]
54    pub base: crate::cli::command::RequestBaseArgs,
55}
56
57#[derive(clap::Args)]
58#[command(args_conflicts_with_subcommands = true)]
59pub struct Command {
60    #[command(flatten)]
61    pub args: Args,
62    #[command(subcommand)]
63    pub schema: Option<Schema>,
64}
65
66#[derive(clap::Subcommand)]
67pub enum Schema {
68    /// Emit the JSON Schema for this leaf's `Request` type and exit.
69    RequestSchema(request_schema::Args),
70    /// Emit the JSON Schema for this leaf's `Response` type and exit.
71    ResponseSchema(response_schema::Args),
72}
73
74impl TryFrom<Args> for Request {
75    type Error = crate::cli::command::FromArgsError;
76    fn try_from(args: Args) -> Result<Self, Self::Error> {
77        let selector = AgentSelector::try_from(args.selector)?;
78        let laboratory_id = args.laboratory_id.ok_or_else(|| {
79            crate::cli::command::FromArgsError::path_parse(
80                "laboratory_id",
81                "--laboratory-id is required".to_string(),
82            )
83        })?;
84        Ok(Self {
85            path_type: Path::AgentsLaboratoriesDetach,
86            selector,
87            laboratory_id,
88            base: args.base.into(),
89        })
90    }
91}
92
93#[cfg(feature = "cli-executor")]
94pub async fn execute<E: crate::cli::command::CommandExecutor>(
95    executor: &E,
96    mut request: Request,
97    agent_arguments: Option<&crate::cli::command::AgentArguments>,
98) -> Result<Response, E::Error> {
99    request.base.clear_transform();
100    executor.execute_one(request, agent_arguments).await
101}
102
103#[cfg(feature = "cli-executor")]
104pub async fn execute_transform<E: crate::cli::command::CommandExecutor>(
105    executor: &E,
106    mut request: Request,
107    transform: crate::cli::command::Transform,
108    agent_arguments: Option<&crate::cli::command::AgentArguments>,
109) -> Result<serde_json::Value, E::Error> {
110    request.base.set_transform(transform);
111    executor.execute_one(request, agent_arguments).await
112}
113
114#[cfg(feature = "mcp")]
115impl crate::cli::command::CommandResponse for Response {
116    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
117        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
118    }
119}
120
121pub mod request_schema;
122
123pub mod response_schema;
124
125/// One `/listen` broadcast run of `agents laboratories detach`: the actual
126/// [`Request`], the producer's
127/// [`AgentArguments`](crate::cli::command::AgentArguments), and the
128/// unary response future. See [`crate::cli::websocket_listener`].
129#[cfg(feature = "cli-listener")]
130pub struct ListenerExecution {
131    pub request: Request,
132    pub agent_arguments: crate::cli::command::AgentArguments,
133    pub response: crate::cli::websocket_listener::UnaryResponse<Response>,
134}