Skip to main content

objectiveai_sdk/cli/command/agents/
mod.rs

1pub mod get;
2pub mod instances;
3pub mod list;
4pub mod logs;
5pub mod message;
6pub mod publish;
7pub mod queue;
8pub mod spawn;
9pub mod tags;
10
11#[derive(clap::Subcommand)]
12pub enum Command {
13    /// Get an agent by remote path or favorite name.
14    Get(get::Command),
15    /// Caller-side handles for live spawned agents that didn't earn
16    /// their own top-level home: `me`, `list`.
17    Instances {
18        #[command(subcommand)]
19        command: instances::Command,
20    },
21    /// List remote agents available from a given source.
22    List(list::Command),
23    /// Persisted log tier — `read` and friends.
24    Logs {
25        #[command(subcommand)]
26        command: logs::Command,
27    },
28    /// Deliver a message to a running spawned agent (or resume its
29    /// most recent completion via continuation if it's dormant).
30    Message(message::Command),
31    /// Publish an agent to the local filesystem.
32    Publish(publish::Command),
33    /// Deferred-prompt queue — `delete`, `read`. (Add is gone — use
34    /// `agents message` instead.)
35    Queue {
36        #[command(subcommand)]
37        command: queue::Command,
38    },
39    /// Spawn an agent completion (open a streaming run as a child of
40    /// this caller).
41    Spawn(spawn::Command),
42    /// Client-side agent tags — lookup / apply.
43    Tags {
44        #[command(subcommand)]
45        command: tags::Command,
46    },
47}
48
49#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
50#[serde(untagged)]
51#[schemars(rename = "cli.command.agents.Request")]
52pub enum Request {
53    #[schemars(title = "Get")]
54    Get(get::Request),
55    #[schemars(title = "GetRequestSchema")]
56    GetRequestSchema(get::request_schema::Request),
57    #[schemars(title = "GetResponseSchema")]
58    GetResponseSchema(get::response_schema::Request),
59    #[schemars(title = "Instances")]
60    Instances(instances::Request),
61    #[schemars(title = "List")]
62    List(list::Request),
63    #[schemars(title = "ListRequestSchema")]
64    ListRequestSchema(list::request_schema::Request),
65    #[schemars(title = "ListResponseSchema")]
66    ListResponseSchema(list::response_schema::Request),
67    #[schemars(title = "Logs")]
68    Logs(logs::Request),
69    #[schemars(title = "Message")]
70    Message(message::Request),
71    #[schemars(title = "MessageRequestSchema")]
72    MessageRequestSchema(message::request_schema::Request),
73    #[schemars(title = "MessageResponseSchema")]
74    MessageResponseSchema(message::response_schema::Request),
75    #[schemars(title = "Publish")]
76    Publish(publish::Request),
77    #[schemars(title = "PublishRequestSchema")]
78    PublishRequestSchema(publish::request_schema::Request),
79    #[schemars(title = "PublishResponseSchema")]
80    PublishResponseSchema(publish::response_schema::Request),
81    #[schemars(title = "Queue")]
82    Queue(queue::Request),
83    #[schemars(title = "Spawn")]
84    Spawn(spawn::Request),
85    #[schemars(title = "SpawnRequestSchema")]
86    SpawnRequestSchema(spawn::request_schema::Request),
87    #[schemars(title = "SpawnResponseSchema")]
88    SpawnResponseSchema(spawn::response_schema::Request),
89    #[schemars(title = "Tags")]
90    Tags(tags::Request),
91}
92
93// Exempt from json-schema coverage: tier aggregate (see the root
94// `ResponseItem` in command.rs - TS7056).
95#[objectiveai_sdk_macros::json_schema_ignore]
96#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
97#[schemars(rename = "cli.command.agents.ResponseItem")]
98#[serde(untagged)]
99pub enum ResponseItem {
100    #[schemars(title = "Get")]
101    Get(get::Response),
102    #[schemars(title = "GetRequestSchema")]
103    GetRequestSchema(get::request_schema::Response),
104    #[schemars(title = "GetResponseSchema")]
105    GetResponseSchema(get::response_schema::Response),
106    #[schemars(title = "Instances")]
107    Instances(instances::ResponseItem),
108    #[schemars(title = "List")]
109    List(list::ResponseItem),
110    #[schemars(title = "ListRequestSchema")]
111    ListRequestSchema(list::request_schema::Response),
112    #[schemars(title = "ListResponseSchema")]
113    ListResponseSchema(list::response_schema::Response),
114    #[schemars(title = "Logs")]
115    Logs(logs::ResponseItem),
116    #[schemars(title = "Message")]
117    Message(message::ResponseItem),
118    #[schemars(title = "MessageRequestSchema")]
119    MessageRequestSchema(message::request_schema::Response),
120    #[schemars(title = "MessageResponseSchema")]
121    MessageResponseSchema(message::response_schema::Response),
122    #[schemars(title = "Publish")]
123    Publish(publish::Response),
124    #[schemars(title = "PublishRequestSchema")]
125    PublishRequestSchema(publish::request_schema::Response),
126    #[schemars(title = "PublishResponseSchema")]
127    PublishResponseSchema(publish::response_schema::Response),
128    #[schemars(title = "Queue")]
129    Queue(queue::ResponseItem),
130    #[schemars(title = "Spawn")]
131    Spawn(spawn::ResponseItem),
132    #[schemars(title = "SpawnRequestSchema")]
133    SpawnRequestSchema(spawn::request_schema::Response),
134    #[schemars(title = "SpawnResponseSchema")]
135    SpawnResponseSchema(spawn::response_schema::Response),
136    #[schemars(title = "Tags")]
137    Tags(tags::ResponseItem),
138}
139
140#[cfg(feature = "mcp")]
141impl crate::cli::command::CommandResponse for ResponseItem {
142    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
143        match self {
144            ResponseItem::Get(v) => v.into_mcp(),
145            ResponseItem::GetRequestSchema(v) => v.into_mcp(),
146            ResponseItem::GetResponseSchema(v) => v.into_mcp(),
147            ResponseItem::Instances(v) => v.into_mcp(),
148            ResponseItem::List(v) => v.into_mcp(),
149            ResponseItem::ListRequestSchema(v) => v.into_mcp(),
150            ResponseItem::ListResponseSchema(v) => v.into_mcp(),
151            ResponseItem::Logs(v) => v.into_mcp(),
152            ResponseItem::Message(v) => v.into_mcp(),
153            ResponseItem::MessageRequestSchema(v) => v.into_mcp(),
154            ResponseItem::MessageResponseSchema(v) => v.into_mcp(),
155            ResponseItem::Publish(v) => v.into_mcp(),
156            ResponseItem::PublishRequestSchema(v) => v.into_mcp(),
157            ResponseItem::PublishResponseSchema(v) => v.into_mcp(),
158            ResponseItem::Queue(v) => v.into_mcp(),
159            ResponseItem::Spawn(v) => v.into_mcp(),
160            ResponseItem::SpawnRequestSchema(v) => v.into_mcp(),
161            ResponseItem::SpawnResponseSchema(v) => v.into_mcp(),
162            ResponseItem::Tags(v) => v.into_mcp(),
163        }
164    }
165}
166
167impl TryFrom<Command> for Request {
168    type Error = crate::cli::command::FromArgsError;
169    fn try_from(command: Command) -> Result<Self, Self::Error> {
170        match command {
171            Command::Get(cmd) => match cmd.schema {
172                None => Ok(Request::Get(get::Request::try_from(cmd.args)?)),
173                Some(get::Schema::RequestSchema(args)) =>
174                    Ok(Request::GetRequestSchema(get::request_schema::Request::try_from(args)?)),
175                Some(get::Schema::ResponseSchema(args)) =>
176                    Ok(Request::GetResponseSchema(get::response_schema::Request::try_from(args)?)),
177            },
178            Command::Instances { command } =>
179                Ok(Request::Instances(instances::Request::try_from(command)?)),
180            Command::List(cmd) => match cmd.schema {
181                None => Ok(Request::List(list::Request::try_from(cmd.args)?)),
182                Some(list::Schema::RequestSchema(args)) =>
183                    Ok(Request::ListRequestSchema(list::request_schema::Request::try_from(args)?)),
184                Some(list::Schema::ResponseSchema(args)) =>
185                    Ok(Request::ListResponseSchema(list::response_schema::Request::try_from(args)?)),
186            },
187            Command::Logs { command } =>
188                Ok(Request::Logs(logs::Request::try_from(command)?)),
189            Command::Message(cmd) => match cmd.schema {
190                None => Ok(Request::Message(message::Request::try_from(cmd.args)?)),
191                Some(message::Schema::RequestSchema(args)) =>
192                    Ok(Request::MessageRequestSchema(message::request_schema::Request::try_from(args)?)),
193                Some(message::Schema::ResponseSchema(args)) =>
194                    Ok(Request::MessageResponseSchema(message::response_schema::Request::try_from(args)?)),
195            },
196            Command::Publish(cmd) => match cmd.schema {
197                None => Ok(Request::Publish(publish::Request::try_from(cmd.args)?)),
198                Some(publish::Schema::RequestSchema(args)) =>
199                    Ok(Request::PublishRequestSchema(publish::request_schema::Request::try_from(args)?)),
200                Some(publish::Schema::ResponseSchema(args)) =>
201                    Ok(Request::PublishResponseSchema(publish::response_schema::Request::try_from(args)?)),
202            },
203            Command::Queue { command } =>
204                Ok(Request::Queue(queue::Request::try_from(command)?)),
205            Command::Spawn(cmd) => match cmd.schema {
206                None => Ok(Request::Spawn(spawn::Request::try_from(cmd.args)?)),
207                Some(spawn::Schema::RequestSchema(args)) =>
208                    Ok(Request::SpawnRequestSchema(spawn::request_schema::Request::try_from(args)?)),
209                Some(spawn::Schema::ResponseSchema(args)) =>
210                    Ok(Request::SpawnResponseSchema(spawn::response_schema::Request::try_from(args)?)),
211            },
212            Command::Tags { command } =>
213                Ok(Request::Tags(tags::Request::try_from(command)?)),
214        }
215    }
216}
217
218impl crate::cli::command::CommandRequest for Request {
219    fn into_command(&self) -> Vec<String> {
220        match self {
221            Request::Get(inner) => inner.into_command(),
222            Request::GetRequestSchema(inner) => inner.into_command(),
223            Request::GetResponseSchema(inner) => inner.into_command(),
224            Request::Instances(inner) => inner.into_command(),
225            Request::List(inner) => inner.into_command(),
226            Request::ListRequestSchema(inner) => inner.into_command(),
227            Request::ListResponseSchema(inner) => inner.into_command(),
228            Request::Logs(inner) => inner.into_command(),
229            Request::Message(inner) => inner.into_command(),
230            Request::MessageRequestSchema(inner) => inner.into_command(),
231            Request::MessageResponseSchema(inner) => inner.into_command(),
232            Request::Publish(inner) => inner.into_command(),
233            Request::PublishRequestSchema(inner) => inner.into_command(),
234            Request::PublishResponseSchema(inner) => inner.into_command(),
235            Request::Queue(inner) => inner.into_command(),
236            Request::Spawn(inner) => inner.into_command(),
237            Request::SpawnRequestSchema(inner) => inner.into_command(),
238            Request::SpawnResponseSchema(inner) => inner.into_command(),
239            Request::Tags(inner) => inner.into_command(),
240        }
241    }
242}
243
244#[cfg(feature = "cli-executor")]
245pub async fn execute<E: crate::cli::command::CommandExecutor>(
246    executor: &E,
247    request: Request,
248
249        agent_arguments: Option<&crate::cli::command::AgentArguments>,
250    ) -> Result<
251    std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>>,
252    E::Error,
253> {
254    use futures::StreamExt;
255    let stream: std::pin::Pin<Box<dyn futures::Stream<Item = Result<ResponseItem, E::Error>> + Send>> =
256        match request {
257            Request::Get(req) => {
258                let value = get::execute(executor, req, agent_arguments).await?;
259                Box::pin(crate::cli::command::StreamOnce::new(Ok(
260                    ResponseItem::Get(value),
261                )))
262            }
263            Request::GetRequestSchema(req) => {
264                let value = get::request_schema::execute(executor, req, agent_arguments).await?;
265                Box::pin(crate::cli::command::StreamOnce::new(Ok(
266                    ResponseItem::GetRequestSchema(value),
267                )))
268            }
269            Request::GetResponseSchema(req) => {
270                let value = get::response_schema::execute(executor, req, agent_arguments).await?;
271                Box::pin(crate::cli::command::StreamOnce::new(Ok(
272                    ResponseItem::GetResponseSchema(value),
273                )))
274            }
275            Request::Instances(req) => {
276                let inner = instances::execute(executor, req, agent_arguments).await?;
277                Box::pin(inner.map(|r| r.map(ResponseItem::Instances)))
278            }
279            Request::List(req) => {
280                let inner = list::execute(executor, req, agent_arguments).await?;
281                Box::pin(inner.map(|r| r.map(ResponseItem::List)))
282            }
283            Request::ListRequestSchema(req) => {
284                let value = list::request_schema::execute(executor, req, agent_arguments).await?;
285                Box::pin(crate::cli::command::StreamOnce::new(Ok(
286                    ResponseItem::ListRequestSchema(value),
287                )))
288            }
289            Request::ListResponseSchema(req) => {
290                let value = list::response_schema::execute(executor, req, agent_arguments).await?;
291                Box::pin(crate::cli::command::StreamOnce::new(Ok(
292                    ResponseItem::ListResponseSchema(value),
293                )))
294            }
295            Request::Logs(req) => {
296                let inner = logs::execute(executor, req, agent_arguments).await?;
297                Box::pin(inner.map(|r| r.map(ResponseItem::Logs)))
298            }
299            Request::Message(req) => {
300                let want_streaming = req
301                    .dangerous_advanced
302                    .as_ref()
303                    .and_then(|a| a.stream)
304                    .unwrap_or(false);
305                if want_streaming {
306                    let inner = message::execute_streaming(executor, req, agent_arguments).await?;
307                    Box::pin(inner.map(|r| r.map(ResponseItem::Message)))
308                } else {
309                    let value = message::execute(executor, req, agent_arguments).await?;
310                    Box::pin(crate::cli::command::StreamOnce::new(Ok(
311                        ResponseItem::Message(value.into()),
312                    )))
313                }
314            }
315            Request::MessageRequestSchema(req) => {
316                let value = message::request_schema::execute(executor, req, agent_arguments).await?;
317                Box::pin(crate::cli::command::StreamOnce::new(Ok(
318                    ResponseItem::MessageRequestSchema(value),
319                )))
320            }
321            Request::MessageResponseSchema(req) => {
322                let value = message::response_schema::execute(executor, req, agent_arguments).await?;
323                Box::pin(crate::cli::command::StreamOnce::new(Ok(
324                    ResponseItem::MessageResponseSchema(value),
325                )))
326            }
327            Request::Publish(req) => {
328                let value = publish::execute(executor, req, agent_arguments).await?;
329                Box::pin(crate::cli::command::StreamOnce::new(Ok(
330                    ResponseItem::Publish(value),
331                )))
332            }
333            Request::PublishRequestSchema(req) => {
334                let value = publish::request_schema::execute(executor, req, agent_arguments).await?;
335                Box::pin(crate::cli::command::StreamOnce::new(Ok(
336                    ResponseItem::PublishRequestSchema(value),
337                )))
338            }
339            Request::PublishResponseSchema(req) => {
340                let value = publish::response_schema::execute(executor, req, agent_arguments).await?;
341                Box::pin(crate::cli::command::StreamOnce::new(Ok(
342                    ResponseItem::PublishResponseSchema(value),
343                )))
344            }
345            Request::Queue(req) => {
346                let inner = queue::execute(executor, req, agent_arguments).await?;
347                Box::pin(inner.map(|r| r.map(ResponseItem::Queue)))
348            }
349            Request::Spawn(req) => {
350                let want_streaming = req
351                    .dangerous_advanced
352                    .as_ref()
353                    .and_then(|a| a.stream)
354                    .unwrap_or(false);
355                if want_streaming {
356                    let inner = spawn::execute_streaming(executor, req, agent_arguments).await?;
357                    Box::pin(inner.map(|r| r.map(ResponseItem::Spawn)))
358                } else {
359                    let value = spawn::execute(executor, req, agent_arguments).await?;
360                    Box::pin(crate::cli::command::StreamOnce::new(Ok(
361                        ResponseItem::Spawn(spawn::ResponseItem::Id(value)),
362                    )))
363                }
364            }
365            Request::SpawnRequestSchema(req) => {
366                let value = spawn::request_schema::execute(executor, req, agent_arguments).await?;
367                Box::pin(crate::cli::command::StreamOnce::new(Ok(
368                    ResponseItem::SpawnRequestSchema(value),
369                )))
370            }
371            Request::SpawnResponseSchema(req) => {
372                let value = spawn::response_schema::execute(executor, req, agent_arguments).await?;
373                Box::pin(crate::cli::command::StreamOnce::new(Ok(
374                    ResponseItem::SpawnResponseSchema(value),
375                )))
376            }
377            Request::Tags(req) => {
378                let inner = tags::execute(executor, req, agent_arguments).await?;
379                Box::pin(inner.map(|r| r.map(ResponseItem::Tags)))
380            }
381        };
382    Ok(stream)
383}
384
385#[cfg(feature = "cli-executor")]
386pub async fn execute_jq<E: crate::cli::command::CommandExecutor>(
387    executor: &E,
388    request: Request,
389    jq: String,
390
391        agent_arguments: Option<&crate::cli::command::AgentArguments>,
392    ) -> Result<
393    std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>>,
394    E::Error,
395> {
396    let stream: std::pin::Pin<Box<dyn futures::Stream<Item = Result<serde_json::Value, E::Error>> + Send>> =
397        match request {
398            Request::Get(req) => {
399                let value = get::execute_jq(executor, req, jq, agent_arguments).await?;
400                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
401            }
402            Request::GetRequestSchema(req) => {
403                let value = get::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
404                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
405            }
406            Request::GetResponseSchema(req) => {
407                let value = get::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
408                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
409            }
410            Request::Instances(req) => {
411                let inner = instances::execute_jq(executor, req, jq, agent_arguments).await?;
412                Box::pin(inner)
413            }
414            Request::List(req) => {
415                let inner = list::execute_jq(executor, req, jq, agent_arguments).await?;
416                Box::pin(inner)
417            }
418            Request::ListRequestSchema(req) => {
419                let value = list::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
420                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
421            }
422            Request::ListResponseSchema(req) => {
423                let value = list::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
424                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
425            }
426            Request::Logs(req) => {
427                let inner = logs::execute_jq(executor, req, jq, agent_arguments).await?;
428                Box::pin(inner)
429            }
430            Request::Message(req) => {
431                let want_streaming = req
432                    .dangerous_advanced
433                    .as_ref()
434                    .and_then(|a| a.stream)
435                    .unwrap_or(false);
436                if want_streaming {
437                    let inner = message::execute_streaming_jq(executor, req, jq, agent_arguments).await?;
438                    Box::pin(inner)
439                } else {
440                    let value = message::execute_jq(executor, req, jq, agent_arguments).await?;
441                    Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
442                }
443            }
444            Request::MessageRequestSchema(req) => {
445                let value =
446                    message::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
447                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
448            }
449            Request::MessageResponseSchema(req) => {
450                let value =
451                    message::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
452                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
453            }
454            Request::Publish(req) => {
455                let value = publish::execute_jq(executor, req, jq, agent_arguments).await?;
456                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
457            }
458            Request::PublishRequestSchema(req) => {
459                let value = publish::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
460                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
461            }
462            Request::PublishResponseSchema(req) => {
463                let value = publish::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
464                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
465            }
466            Request::Queue(req) => {
467                let inner = queue::execute_jq(executor, req, jq, agent_arguments).await?;
468                Box::pin(inner)
469            }
470            Request::Spawn(req) => {
471                let want_streaming = req
472                    .dangerous_advanced
473                    .as_ref()
474                    .and_then(|a| a.stream)
475                    .unwrap_or(false);
476                if want_streaming {
477                    let inner = spawn::execute_streaming_jq(executor, req, jq, agent_arguments).await?;
478                    Box::pin(inner)
479                } else {
480                    let value = spawn::execute_jq(executor, req, jq, agent_arguments).await?;
481                    Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
482                }
483            }
484            Request::SpawnRequestSchema(req) => {
485                let value =
486                    spawn::request_schema::execute_jq(executor, req, jq, agent_arguments).await?;
487                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
488            }
489            Request::SpawnResponseSchema(req) => {
490                let value =
491                    spawn::response_schema::execute_jq(executor, req, jq, agent_arguments).await?;
492                Box::pin(crate::cli::command::StreamOnce::new(Ok(value)))
493            }
494            Request::Tags(req) => {
495                let inner = tags::execute_jq(executor, req, jq, agent_arguments).await?;
496                Box::pin(inner)
497            }
498        };
499    Ok(stream)
500}