Skip to main content

objectiveai_sdk/cli/command/agents/logs/read/pending/
mod.rs

1//! `agents logs read pending` — fetch the unread delta for the
2//! children spawned by a parent AIH, coalesced into [`ResponseItem`]
3//! blocks. Read-and-advance: the per-child watermark
4//! (`logs.messages_queue.read_index`) is bumped to the maximum
5//! returned id in the same SQL statement, never downgraded.
6
7use crate::cli::command::CommandRequest;
8
9#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
10#[schemars(rename = "cli.command.agents.logs.read.pending.Request")]
11pub struct Request {
12    pub path_type: Path,
13    pub targets: Vec<Target>,
14    /// Skip rows with `logs.messages."index" <= after_id`. Composes
15    /// with the per-child watermark (`GREATEST` of the two applies).
16    #[serde(default, skip_serializing_if = "Option::is_none")]
17    #[schemars(extend("omitempty" = true))]
18    pub after_id: Option<i64>,
19    /// Cap on rows scanned per target. `None` = unlimited.
20    #[serde(default, skip_serializing_if = "Option::is_none")]
21    #[schemars(extend("omitempty" = true))]
22    pub limit: Option<i64>,
23    pub jq: Option<String>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)]
27#[schemars(rename = "cli.command.agents.logs.read.pending.Path")]
28pub enum Path {
29    #[serde(rename = "agents/logs/read/pending")]
30    AgentsLogsReadPending,
31}
32
33impl CommandRequest for Request {
34    fn into_command(&self) -> Vec<String> {
35        let mut argv = vec![
36            "agents".to_string(),
37            "logs".to_string(),
38            "read".to_string(),
39            "pending".to_string(),
40        ];
41        for target in &self.targets {
42            argv.push("--target".to_string());
43            argv.push(target.into_arg_string());
44        }
45        if let Some(after_id) = self.after_id {
46            argv.push("--after-id".to_string());
47            argv.push(after_id.to_string());
48        }
49        if let Some(limit) = self.limit {
50            argv.push("--limit".to_string());
51            argv.push(limit.to_string());
52        }
53        if let Some(jq) = &self.jq {
54            argv.push("--jq".to_string());
55            argv.push(jq.clone());
56        }
57        argv
58    }
59}
60
61// Share the ResponseItem / part / part-type shapes AND the docker-style
62// `Target` parser with `agents logs read all` — same underlying
63// `logs.messages` rows surfaced as either the full target slice or
64// the watermark-delta slice, same per-target input shape.
65pub use super::all::{
66    AssistantResponsePart, AssistantResponsePartType, ClientNotificationPart,
67    ClientNotificationPartType, ResponseItem, Target, ToolResponsePart, ToolResponsePartType,
68};
69
70#[derive(clap::Args)]
71pub struct Args {
72    /// One or more `--target instance=L[,parent=P]` entries. `parent`
73    /// defaults to the cli's own `Config.agent_instance_hierarchy`
74    /// when omitted on an individual target. Also accepts
75    /// `--target tag=T` and `--target me` (the caller's own AIH).
76    #[arg(long = "target", required = true)]
77    pub targets: Vec<String>,
78    /// Skip rows with `logs.messages."index" <= after_id` per target.
79    #[arg(long)]
80    pub after_id: Option<i64>,
81    /// Cap on rows scanned per target.
82    #[arg(long)]
83    pub limit: Option<i64>,
84    /// jq filter applied to the JSON output.
85    #[arg(long)]
86    pub jq: Option<String>,
87}
88
89#[derive(clap::Args)]
90#[command(args_conflicts_with_subcommands = true)]
91pub struct Command {
92    #[command(flatten)]
93    pub args: Args,
94    #[command(subcommand)]
95    pub schema: Option<Schema>,
96}
97
98#[derive(clap::Subcommand)]
99pub enum Schema {
100    /// Emit the JSON Schema for this leaf's `Request` type and exit.
101    RequestSchema(request_schema::Args),
102    /// Emit the JSON Schema for this leaf's `Response` type and exit.
103    ResponseSchema(response_schema::Args),
104}
105
106impl TryFrom<Args> for Request {
107    type Error = crate::cli::command::FromArgsError;
108    fn try_from(args: Args) -> Result<Self, Self::Error> {
109        let targets = args
110            .targets
111            .iter()
112            .map(|s| {
113                s.parse::<Target>().map_err(|msg| {
114                    crate::cli::command::FromArgsError::path_parse("target", msg)
115                })
116            })
117            .collect::<Result<Vec<_>, _>>()?;
118        Ok(Self {
119            path_type: Path::AgentsLogsReadPending,
120            targets,
121            after_id: args.after_id,
122            limit: args.limit,
123            jq: args.jq,
124        })
125    }
126}
127
128#[cfg(feature = "cli-executor")]
129pub async fn execute<E: crate::cli::command::CommandExecutor>(
130    executor: &E,
131    mut request: Request,
132
133        agent_arguments: Option<&crate::cli::command::AgentArguments>,
134    ) -> Result<E::Stream<ResponseItem>, E::Error> {
135    request.jq = None;
136    executor.execute(request, agent_arguments).await
137}
138
139#[cfg(feature = "cli-executor")]
140pub async fn execute_jq<E: crate::cli::command::CommandExecutor>(
141    executor: &E,
142    mut request: Request,
143    jq: String,
144
145        agent_arguments: Option<&crate::cli::command::AgentArguments>,
146    ) -> Result<E::Stream<serde_json::Value>, E::Error> {
147    request.jq = Some(jq);
148    executor.execute(request, agent_arguments).await
149}
150
151pub mod request_schema;
152
153
154pub mod response_schema;