objectiveai_cli/command/agents/logs/token_usage/
subscribe.rs1use std::pin::Pin;
15
16use futures::Stream;
17use objectiveai_sdk::cli::command::agents::logs::token_usage::subscribe::{
18 AgentsInactiveTag, Request, ResponseItem, TokenUsage,
19};
20
21use crate::context::Context;
22use crate::error::Error;
23
24type ItemStream = Pin<Box<dyn Stream<Item = Result<ResponseItem, Error>> + Send>>;
25
26fn once(item: Result<ResponseItem, Error>) -> ItemStream {
27 Box::pin(futures::stream::once(async move { item }))
28}
29
30pub async fn execute(ctx: &Context, request: Request) -> Result<ItemStream, Error> {
31 let db = ctx.db_client().await?.clone();
32 let state_dir = ctx.filesystem.state_dir();
33 let aih = request.agent_instance_hierarchy;
34 let previous = request.previous;
35
36 let baseline = crate::db::logs::get_agent_token_usage(&db, &aih).await?;
37
38 if let (Some(prev), Some(current)) = (previous, baseline) {
41 if current != prev {
42 return Ok(once(Ok(ResponseItem::Item(TokenUsage {
43 agent_instance_hierarchy: aih,
44 total_tokens: current,
45 }))));
46 }
47 }
48
49 let (lock_dir, lock_key) =
53 crate::command::agents::locks::agent_instance_lock(&state_dir, &aih);
54
55 let item: Result<ResponseItem, Error> = tokio::select! {
56 result = crate::db::logs::wait_for_token_usage_change(&db, &aih, baseline) => {
57 result
58 .map(|total_tokens| ResponseItem::Item(TokenUsage {
59 agent_instance_hierarchy: aih.clone(),
60 total_tokens,
61 }))
62 .map_err(Error::from)
63 }
64 result = objectiveai_sdk::lockfile::wait_released(&lock_dir, &lock_key) => {
65 match result {
66 Ok(()) => {
67 match crate::db::logs::get_agent_token_usage(&db, &aih).await {
70 Ok(current) if current != baseline => match current {
71 Some(total_tokens) => Ok(ResponseItem::Item(TokenUsage {
72 agent_instance_hierarchy: aih.clone(),
73 total_tokens,
74 })),
75 None => Ok(ResponseItem::AgentsInactive(
76 AgentsInactiveTag::AgentsInactive,
77 )),
78 },
79 Ok(_) => Ok(ResponseItem::AgentsInactive(
80 AgentsInactiveTag::AgentsInactive,
81 )),
82 Err(e) => Err(Error::from(e)),
83 }
84 }
85 Err(e) => Err(Error::Lockfile { key: lock_key.clone(), source: e }),
86 }
87 }
88 };
89
90 Ok(once(item))
91}
92
93pub mod request_schema {
94 use objectiveai_sdk::cli::command::agents::logs::token_usage::subscribe as sdk;
95 use objectiveai_sdk::cli::command::agents::logs::token_usage::subscribe::request_schema::{
96 Request, Response,
97 };
98
99 use crate::context::Context;
100 use crate::error::Error;
101
102 pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
103 Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::Request)))
104 }
105}
106
107pub mod response_schema {
108 use objectiveai_sdk::cli::command::agents::logs::token_usage::subscribe as sdk;
109 use objectiveai_sdk::cli::command::agents::logs::token_usage::subscribe::response_schema::{
110 Request, Response,
111 };
112
113 use crate::context::Context;
114 use crate::error::Error;
115
116 pub async fn execute(_ctx: &Context, _request: Request) -> Result<Response, Error> {
117 Ok(objectiveai_sdk::cli::command::ResponseSchema(schemars::schema_for!(sdk::ResponseItem)))
118 }
119}