use std::collections::BTreeMap;
use std::sync::Arc;
use async_trait::async_trait;
use super::types::{
AgentBuildContext, AgentBuildDraft, AgentIdentity, CheckpointVersion, ContinuityGeneration,
ContinuityRecord, ContinuityResolveState, ContinuityStoreError, CustomizerError,
DurableAgentSpec, FencingToken, LeaseAcquireResult, LeaseError, LeaseGrant, LeaseRenewResult,
ManagedPeerEdge, RosterContext, RosterError, SessionSnapshot, TopologyContext, TopologyError,
};
use crate::mob_handle_runtime::SessionCreatedContext;
#[derive(Debug, Clone)]
pub struct SessionSnapshotMatchCandidate {
pub identity: AgentIdentity,
pub session_id: meerkat_core::types::SessionId,
pub generation: ContinuityGeneration,
pub checkpoint_version: CheckpointVersion,
pub fencing_token: FencingToken,
pub snapshot: Arc<SessionSnapshot>,
}
#[async_trait]
pub trait ContinuityStore: Send + Sync {
async fn resolve_many(
&self,
identities: &[AgentIdentity],
) -> Result<BTreeMap<AgentIdentity, ContinuityResolveState>, ContinuityStoreError>;
async fn load_session_snapshot(
&self,
session_id: &meerkat_core::types::SessionId,
) -> Result<Option<SessionSnapshot>, ContinuityStoreError>;
async fn session_snapshot_matches_current(
&self,
_candidate: SessionSnapshotMatchCandidate,
) -> Result<bool, ContinuityStoreError> {
Ok(false)
}
async fn delete_session_snapshot_if_current_revision(
&self,
_session_id: &meerkat_core::types::SessionId,
_expected_current_revision: &str,
) -> Result<bool, ContinuityStoreError> {
Ok(false)
}
async fn save_session_snapshot(
&self,
identity: &AgentIdentity,
session_id: &meerkat_core::types::SessionId,
generation: ContinuityGeneration,
version: CheckpointVersion,
fencing_token: FencingToken,
snapshot: &SessionSnapshot,
) -> Result<(), ContinuityStoreError>;
async fn save_session_snapshot_owned(
&self,
identity: AgentIdentity,
session_id: meerkat_core::types::SessionId,
generation: ContinuityGeneration,
version: CheckpointVersion,
fencing_token: FencingToken,
snapshot: SessionSnapshot,
) -> Result<(), ContinuityStoreError> {
self.save_session_snapshot(
&identity,
&session_id,
generation,
version,
fencing_token,
&snapshot,
)
.await
}
async fn upsert_continuity_record(
&self,
record: &ContinuityRecord,
fencing_token: FencingToken,
) -> Result<(), ContinuityStoreError>;
async fn rollback_continuity_record(
&self,
expected_attempt: &ContinuityRecord,
previous: Option<&ContinuityRecord>,
fencing_token: FencingToken,
) -> Result<(), ContinuityStoreError> {
let resolved = self
.resolve_many(std::slice::from_ref(&expected_attempt.identity))
.await?;
let Some(ContinuityResolveState::Ready { record: current }) =
resolved.get(&expected_attempt.identity)
else {
return Err(ContinuityStoreError::NotFound {
identity: expected_attempt.identity.clone(),
});
};
if current.agent_runtime_id != expected_attempt.agent_runtime_id
|| current.session_id != expected_attempt.session_id
|| current.generation != expected_attempt.generation
{
return Err(ContinuityStoreError::StaleContinuityGeneration {
identity: expected_attempt.identity.clone(),
presented: expected_attempt.generation,
current: current.generation,
});
}
match previous {
Some(previous) => self.upsert_continuity_record(previous, fencing_token).await,
None => {
self.delete_continuity_record(&expected_attempt.identity, fencing_token)
.await
}
}
}
async fn delete_continuity_record(
&self,
identity: &AgentIdentity,
fencing_token: FencingToken,
) -> Result<(), ContinuityStoreError>;
}
#[async_trait]
pub trait LeaseProvider: Send + Sync {
async fn acquire_leases(
&self,
identities: &[AgentIdentity],
runtime_instance: &str,
) -> Result<BTreeMap<AgentIdentity, LeaseAcquireResult>, LeaseError>;
async fn renew_leases(
&self,
grants: &[LeaseGrant],
) -> Result<BTreeMap<AgentIdentity, LeaseRenewResult>, LeaseError>;
async fn release_leases(&self, grants: &[LeaseGrant]) -> Result<(), LeaseError>;
}
#[async_trait]
pub trait RosterProvider: Send + Sync {
async fn roster(&self, context: &RosterContext) -> Result<Vec<DurableAgentSpec>, RosterError>;
}
#[async_trait]
pub trait AgentCustomizer: Send + Sync {
async fn customize_build(
&self,
context: &AgentBuildContext,
spec: &DurableAgentSpec,
draft: &mut AgentBuildDraft,
) -> Result<(), CustomizerError>;
async fn after_create(
&self,
identity: &AgentIdentity,
session_id: &meerkat_core::types::SessionId,
context: &SessionCreatedContext,
) -> Result<(), CustomizerError> {
let _ = (identity, session_id, context);
Ok(())
}
}
#[async_trait]
pub trait TopologyProvider: Send + Sync {
async fn compute_edges(
&self,
target_identities: &[AgentIdentity],
context: &TopologyContext,
) -> Result<Vec<ManagedPeerEdge>, TopologyError>;
}