open-pincery 1.0.1

Multi-agent platform for durable, event-driven AI agents
Documentation
use crate::api_client::ApiClient;
use crate::error::AppError;

const EVENT_PAGE_LIMIT: i64 = 1000;

async fn fetch_incremental_events(
    client: &ApiClient,
    agent_id: &str,
    since: String,
) -> Result<Vec<serde_json::Value>, AppError> {
    let mut cursor = since;
    let mut collected = Vec::new();

    loop {
        let json = client
            .events(agent_id, EVENT_PAGE_LIMIT, Some(cursor.as_str()))
            .await?;
        let Some(events) = json["events"].as_array() else {
            break;
        };
        if events.is_empty() {
            break;
        }

        collected.extend(events.iter().cloned());
        let last_id = events
            .last()
            .and_then(|ev| ev["id"].as_str())
            .ok_or_else(|| AppError::Internal("event response missing id".into()))?;
        cursor = last_id.to_string();

        if events.len() < EVENT_PAGE_LIMIT as usize {
            break;
        }
    }

    Ok(collected)
}

pub async fn run(
    client: &ApiClient,
    agent_id: String,
    since: Option<String>,
    tail: bool,
) -> Result<(), AppError> {
    if tail {
        let mut last_seen = since;
        loop {
            if let Some(cursor) = last_seen.clone() {
                let events = fetch_incremental_events(client, &agent_id, cursor).await?;
                for ev in &events {
                    println!("{ev}");
                }
                if let Some(last_id) = events.last().and_then(|ev| ev["id"].as_str()) {
                    last_seen = Some(last_id.to_string());
                }
            } else {
                let json = client.events(&agent_id, EVENT_PAGE_LIMIT, None).await?;
                if let Some(events) = json["events"].as_array() {
                    for ev in events.iter().rev() {
                        println!("{ev}");
                    }
                    if let Some(first_id) = events.first().and_then(|ev| ev["id"].as_str()) {
                        last_seen = Some(first_id.to_string());
                    }
                }
            }
            tokio::time::sleep(std::time::Duration::from_secs(2)).await;
        }
    }

    if let Some(marker) = since {
        let events = fetch_incremental_events(client, &agent_id, marker).await?;
        for ev in &events {
            println!("{ev}");
        }
        return Ok(());
    }

    let json = client.events(&agent_id, 200, None).await?;
    println!("{json}");
    Ok(())
}