Skip to main content

atomr_agents_coding_cli_harness/
store.rs

1//! Persistence surface for completed (and in-flight) headless runs.
2
3use std::sync::Arc;
4
5use async_trait::async_trait;
6use dashmap::DashMap;
7
8use atomr_agents_coding_cli_core::{CliResult, CliRunId};
9
10use crate::error::HarnessError;
11
12#[async_trait]
13pub trait CliRunStore: Send + Sync {
14    async fn put(&self, result: &CliResult) -> Result<(), HarnessError>;
15    async fn get(&self, id: &CliRunId) -> Result<Option<CliResult>, HarnessError>;
16    async fn list(&self, limit: usize) -> Result<Vec<CliResult>, HarnessError>;
17}
18
19#[derive(Default, Clone)]
20pub struct InMemoryRunStore {
21    inner: Arc<DashMap<CliRunId, CliResult>>,
22}
23
24impl InMemoryRunStore {
25    pub fn new() -> Self {
26        Self::default()
27    }
28}
29
30#[async_trait]
31impl CliRunStore for InMemoryRunStore {
32    async fn put(&self, result: &CliResult) -> Result<(), HarnessError> {
33        self.inner.insert(result.run_id.clone(), result.clone());
34        Ok(())
35    }
36    async fn get(&self, id: &CliRunId) -> Result<Option<CliResult>, HarnessError> {
37        Ok(self.inner.get(id).map(|r| r.clone()))
38    }
39    async fn list(&self, limit: usize) -> Result<Vec<CliResult>, HarnessError> {
40        let mut all: Vec<CliResult> = self.inner.iter().map(|kv| kv.value().clone()).collect();
41        all.sort_by(|a, b| b.started_at.cmp(&a.started_at));
42        all.truncate(limit);
43        Ok(all)
44    }
45}