objectiveai_cli/command/agents/logs/read/
pending.rs1use std::pin::Pin;
4
5use futures::Stream;
6use futures::StreamExt;
7use futures::stream::FuturesUnordered;
8use objectiveai_sdk::cli::command::agents::logs::read::pending::{Request, ResponseItem, Target};
9
10use crate::context::Context;
11use crate::db::tags;
12use crate::error::Error;
13
14type ItemStream = Pin<Box<dyn Stream<Item = Result<ResponseItem, Error>> + Send>>;
15
16pub async fn execute(ctx: &Context, request: Request) -> Result<ItemStream, Error> {
17 let default_parent = ctx.config.agent_instance_hierarchy.clone();
18 let db = ctx.db_client().await?.clone();
19 let after_id = request.after_id;
20 let limit = request.limit;
21 let stream = async_stream::stream! {
22 let mut inflight = FuturesUnordered::new();
23 for target in request.targets {
24 let db = db.clone();
25 let default_parent = default_parent.clone();
26 inflight.push(async move {
27 let (_parent, spawned, _leaf) =
31 resolve_target(&db, target, &default_parent).await?;
32 let items = crate::db::logs::read_pending_for_parent(
33 &db, &spawned, after_id, limit,
34 ).await.map_err(Error::from)?;
35 Ok::<Vec<ResponseItem>, Error>(items)
36 });
37 }
38 while let Some(result) = inflight.next().await {
39 match result {
40 Ok(items) => {
41 for item in items {
42 yield Ok(item);
43 }
44 }
45 Err(e) => yield Err(e),
46 }
47 }
48 };
49 Ok(Box::pin(stream))
50}
51
52async fn resolve_target(
56 db: &crate::db::Pool,
57 target: Target,
58 default_parent: &str,
59) -> Result<(String, String, String), Error> {
60 match target {
61 Target::Direct {
62 parent_agent_instance_hierarchy,
63 agent_instance,
64 } => {
65 let parent =
66 parent_agent_instance_hierarchy.unwrap_or_else(|| default_parent.to_string());
67 let spawned = format!("{parent}/{agent_instance}");
68 Ok((parent, spawned, agent_instance))
69 }
70 Target::Me => Ok((
72 tags::parent_of(default_parent).to_string(),
73 default_parent.to_string(),
74 tags::leaf_of(default_parent).to_string(),
75 )),
76 Target::Tag { agent_tag } => match tags::lookup(db, &agent_tag).await? {
77 tags::LookupState::Bound { agent_instance_hierarchy } => {
78 let parent = tags::parent_of(&agent_instance_hierarchy).to_string();
79 let leaf = tags::leaf_of(&agent_instance_hierarchy).to_string();
80 Ok((parent, agent_instance_hierarchy, leaf))
81 }
82 tags::LookupState::Grouped {
83 tag_group_id,
84 parent_agent_instance_hierarchy,
85 ..
86 } => Err(Error::TagGrouped {
87 tag: agent_tag,
88 tag_group_id,
89 parent_agent_instance_hierarchy,
90 }),
91 tags::LookupState::Absent => Err(Error::TagNotFound(agent_tag)),
92 },
93 }
94}
95
96pub mod request_schema {
97 use objectiveai_sdk::cli::command::agents::logs::read::pending as sdk;
98 use objectiveai_sdk::cli::command::agents::logs::read::pending::request_schema::{Request, Response};
99
100 use crate::context::Context;
101 use crate::error::Error;
102
103 pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
104 Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Request)))
105 }
106}
107
108pub mod response_schema {
109 use objectiveai_sdk::cli::command::agents::logs::read::pending as sdk;
110 use objectiveai_sdk::cli::command::agents::logs::read::pending::response_schema::{Request, Response};
111
112 use crate::context::Context;
113 use crate::error::Error;
114
115 pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
116 Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::ResponseItem)))
117 }
118}