Skip to main content

objectiveai_sdk/cli/command/agents/read/subscribe/
mod.rs

1//! `agents read subscribe` — async handler stub.
2
3use crate::cli::command::CommandRequest;
4
5/// The six values stored in the `messages.kind` TEXT column. Owning
6/// this enum in the SDK lets bare-naked callers reason about message
7/// kinds without depending on the CLI's filesystem layer.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, schemars::JsonSchema, clap::ValueEnum)]
9#[serde(rename_all = "snake_case")]
10#[clap(rename_all = "kebab-case")]
11#[schemars(rename = "cli.command.agents.read.subscribe.RequestMessageKind")]
12pub enum RequestMessageKind {
13    AgentCompletionRequest,
14    FunctionExecutionRequest,
15    FunctionInventionRecursiveRequest,
16    AgentCompletionNotification,
17    AssistantResponse,
18    ToolResponse,
19}
20
21#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
22#[schemars(rename = "cli.command.agents.read.subscribe.Request")]
23pub struct Request {
24    pub path_type: Path,
25    pub agent_instance_hierarchy: String,
26    pub kind: Option<RequestMessageKind>,
27    pub jq: Option<String>,
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
31#[schemars(rename = "cli.command.agents.read.subscribe.Path")]
32pub enum Path {
33    #[serde(rename = "agents/read/subscribe")]
34    AgentsReadSubscribe,
35}
36
37impl CommandRequest for Request {
38    fn into_command(&self) -> Vec<String> {
39        let mut argv = vec![
40            "agents".to_string(),
41            "read".to_string(),
42            "subscribe".to_string(),
43            self.agent_instance_hierarchy.clone(),
44        ];
45        if let Some(kind) = &self.kind {
46            argv.push("--kind".to_string());
47            argv.push(message_kind_flag(kind).to_string());
48        }
49        if let Some(jq) = &self.jq {
50            argv.push("--jq".to_string());
51            argv.push(jq.clone());
52        }
53        argv
54    }
55}
56
57fn message_kind_flag(kind: &RequestMessageKind) -> &'static str {
58    // Wire form matches clap's `value_enum` rename_all = "kebab-case" default.
59    match kind {
60        RequestMessageKind::AgentCompletionRequest => "agent-completion-request",
61        RequestMessageKind::FunctionExecutionRequest => "function-execution-request",
62        RequestMessageKind::FunctionInventionRecursiveRequest => {
63            "function-invention-recursive-request"
64        }
65        RequestMessageKind::AgentCompletionNotification => "agent-completion-notification",
66        RequestMessageKind::AssistantResponse => "assistant-response",
67        RequestMessageKind::ToolResponse => "tool-response",
68    }
69}
70
71// Share the queue-item / queue-message / content shapes with
72// `agents read all` — same on-disk persistence rows surfaced
73// through different read patterns.
74pub use super::all::{ResponseContent, ResponseQueueItem, ResponseQueueMessage};
75
76#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
77#[serde(untagged)]
78#[schemars(rename = "cli.command.agents.read.subscribe.ResponseItem")]
79pub enum ResponseItem {
80    #[schemars(title = "Items")]
81    Items {
82        agent_id: String,
83        items: Vec<ResponseQueueItem>,
84    },
85    #[schemars(title = "Inactive")]
86    Inactive {
87        agent_id: String,
88    },
89}
90
91#[derive(clap::Args)]
92pub struct Args {
93    /// Lineage path of the agent to subscribe to.
94    pub agent_instance_hierarchy: String,
95    /// Filter the stream to messages of this kind only.
96    #[arg(long, value_enum)]
97    pub kind: Option<RequestMessageKind>,
98    /// jq filter applied to the JSON output.
99    #[arg(long)]
100    pub jq: Option<String>,
101}
102
103#[derive(clap::Args)]
104#[command(args_conflicts_with_subcommands = true)]
105pub struct Command {
106    #[command(flatten)]
107    pub args: Args,
108    #[command(subcommand)]
109    pub schema: Option<Schema>,
110}
111
112#[derive(clap::Subcommand)]
113pub enum Schema {
114    /// Emit the JSON Schema for this leaf's `Request` type and exit.
115    RequestSchema(request_schema::Args),
116    /// Emit the JSON Schema for this leaf's `Response` type and exit.
117    ResponseSchema(response_schema::Args),
118}
119
120impl TryFrom<Args> for Request {
121    type Error = crate::cli::command::FromArgsError;
122    fn try_from(args: Args) -> Result<Self, Self::Error> {
123        Ok(Self { path_type: Path::AgentsReadSubscribe,
124            agent_instance_hierarchy: args.agent_instance_hierarchy,
125            kind: args.kind,
126            jq: args.jq,
127        })
128    }
129}
130
131#[cfg(feature = "cli-executor")]
132pub async fn execute<E: crate::cli::command::CommandExecutor>(
133    executor: &E,
134    mut request: Request,
135
136        agent_arguments: Option<&crate::cli::command::AgentArguments>,
137    ) -> Result<E::Stream<ResponseItem>, E::Error> {
138    request.jq = None;
139    executor.execute(request, agent_arguments).await
140}
141
142#[cfg(feature = "cli-executor")]
143pub async fn execute_jq<E: crate::cli::command::CommandExecutor>(
144    executor: &E,
145    mut request: Request,
146    jq: String,
147
148        agent_arguments: Option<&crate::cli::command::AgentArguments>,
149    ) -> Result<E::Stream<serde_json::Value>, E::Error> {
150    request.jq = Some(jq);
151    executor.execute(request, agent_arguments).await
152}
153
154#[cfg(feature = "mcp")]
155impl crate::cli::command::CommandResponse for ResponseItem {
156    fn into_mcp(self) -> crate::cli::command::McpResponseItem {
157        crate::cli::command::McpResponseItem::JSONL(serde_json::to_value(self).unwrap())
158    }
159}
160
161pub mod request_schema;
162
163
164pub mod response_schema;