use std::sync::Arc;
use async_trait::async_trait;
use crate::identity_first::agent_memory::AgentMemoryError;
use crate::memory::distiller::TombstoneSource;
use crate::memory::events::MemoryEventSink;
use crate::memory::records::{
InjectionLogEntry, MemoryAuthor, MemoryId, MemoryRecord, MemoryScope, NewMemoryRecord,
ProposalId,
};
use crate::memory::staged::{StageToken, StagedMemoryStore};
use crate::memory::taint::LlmWriteGate;
pub trait EvidenceRefResolver: Send + Sync {
fn resolves(&self, evidence: &crate::memory::records::EvidenceRef) -> Result<(), String>;
}
pub trait TaintableStore: Send + Sync {
fn set_llm_write_gate(&self, gate: Arc<dyn LlmWriteGate>);
fn set_llm_write_gate_if_absent(&self, gate: Arc<dyn LlmWriteGate>) -> bool;
fn set_evidence_resolver(&self, resolver: Arc<dyn EvidenceRefResolver>);
fn set_event_sink(&self, sink: Arc<dyn MemoryEventSink>);
fn set_event_sink_if_absent(&self, sink: Arc<dyn MemoryEventSink>) -> bool;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ScopeOverview {
pub scope: MemoryScope,
pub active: u64,
pub quarantined: u64,
pub superseded: u64,
pub tombstoned: u64,
pub body_bytes: u64,
}
#[derive(Debug, Clone, PartialEq)]
pub struct PendingProposal {
pub proposal_id: ProposalId,
pub scope: MemoryScope,
pub record: NewMemoryRecord,
pub author: MemoryAuthor,
pub status: String,
pub created_at_ms: u64,
pub taint: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PendingHarvest {
pub identity: String,
pub session_key: Option<String>,
pub cause: String,
pub retired_at_ms: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PendingPromotion {
pub pending_id: String,
pub stage_token: String,
pub record_id: MemoryId,
pub scope_kind: String,
pub scope_key: String,
pub rationale: Option<String>,
pub status: String,
pub created_at_ms: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PersistedDreamRun {
pub run_id: String,
pub partition_label: String,
pub started_at_ms: u64,
pub completed_at_ms: u64,
pub ops_committed: u64,
pub detail: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DreamAuditVerdict {
pub run_id: String,
pub record_id: String,
pub verdict: String,
pub rationale: String,
pub created_at_ms: u64,
pub resolved_at_ms: Option<u64>,
pub resolution: Option<String>,
}
#[async_trait]
pub trait StewardStore: StagedMemoryStore + TombstoneSource {
fn scope_floors(&self) -> (usize, usize);
async fn scope_overview(&self, realm: &str) -> Result<Vec<ScopeOverview>, AgentMemoryError>;
async fn pending_proposals(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<PendingProposal>, AgentMemoryError>;
async fn set_proposal_status(
&self,
realm: &str,
proposal_id: &str,
status: &str,
) -> Result<(), AgentMemoryError>;
async fn quarantined_records(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<MemoryRecord>, AgentMemoryError>;
async fn records_by_ids(
&self,
realm: &str,
ids: &[String],
) -> Result<Vec<MemoryRecord>, AgentMemoryError>;
async fn recent_records(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<MemoryRecord>, AgentMemoryError>;
async fn injection_log(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<InjectionLogEntry>, AgentMemoryError>;
async fn record_pending_harvest(
&self,
realm: &str,
identity: &str,
session_key: Option<&str>,
cause: &str,
) -> Result<(), AgentMemoryError>;
async fn pending_harvests(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<PendingHarvest>, AgentMemoryError>;
async fn mark_harvest_complete(
&self,
realm: &str,
identity: &str,
retired_at_ms: u64,
) -> Result<(), AgentMemoryError>;
async fn record_pending_promotion(
&self,
realm: &str,
promotion: PendingPromotion,
) -> Result<(), AgentMemoryError>;
async fn pending_promotion_by_id(
&self,
realm: &str,
pending_id: &str,
) -> Result<Option<PendingPromotion>, AgentMemoryError>;
async fn pending_promotions(
&self,
realm: &str,
) -> Result<Vec<PendingPromotion>, AgentMemoryError>;
async fn resolve_pending_promotion(
&self,
realm: &str,
pending_id: &str,
status: &str,
) -> Result<(), AgentMemoryError>;
async fn rekey_pending_promotion(
&self,
realm: &str,
old_pending_id: &str,
new_pending_id: &str,
) -> Result<(), AgentMemoryError>;
async fn discard_stage(&self, token: StageToken) -> Result<(), AgentMemoryError>;
async fn save_dream_run(
&self,
realm: &str,
run: PersistedDreamRun,
) -> Result<(), AgentMemoryError>;
async fn save_dream_audit_verdicts(
&self,
realm: &str,
run_id: &str,
verdicts: Vec<(String, String, String)>,
) -> Result<(), AgentMemoryError>;
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct PanelRecordsPage {
pub records: Vec<MemoryRecord>,
pub next_cursor: Option<(u64, String)>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct DreamRunAudit {
pub run_id: String,
pub first_op_at_ms: u64,
pub last_op_at_ms: u64,
pub ops: u64,
pub op_kinds: std::collections::BTreeMap<String, u64>,
pub quarantined_ops: u64,
pub memory_ids: Vec<String>,
pub rationales: Vec<String>,
}
#[async_trait]
pub trait MemoryPanelStore: StewardStore {
async fn panel_realms(&self) -> Result<Vec<String>, AgentMemoryError>;
async fn record_by_id(
&self,
realm: &str,
memory_id: &str,
) -> Result<Option<MemoryRecord>, AgentMemoryError>;
async fn records_page(
&self,
realm: &str,
scope_kind: Option<&str>,
scope_key: Option<&str>,
status_kind: Option<&str>,
limit: usize,
cursor: Option<(u64, String)>,
) -> Result<PanelRecordsPage, AgentMemoryError>;
async fn supersede_chain(
&self,
realm: &str,
memory_id: &str,
max_len: usize,
) -> Result<Vec<MemoryRecord>, AgentMemoryError>;
async fn injection_log_for_record(
&self,
realm: &str,
record_id: &str,
limit: usize,
) -> Result<Vec<InjectionLogEntry>, AgentMemoryError>;
async fn dream_runs(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<PersistedDreamRun>, AgentMemoryError>;
async fn open_dream_audit_verdicts(
&self,
realm: &str,
limit: usize,
) -> Result<Vec<DreamAuditVerdict>, AgentMemoryError>;
async fn dream_history(
&self,
realm: &str,
max_runs: usize,
) -> Result<Vec<DreamRunAudit>, AgentMemoryError>;
}