use super::envelope::{HandoffEnvelope, HandoffProof};
use crate::types::{AgentId, TenantId};
use async_trait::async_trait;
use ed25519_dalek::SigningKey;
use thiserror::Error;
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct HandoffState {
pub from_run: String,
pub merkle_root: String,
pub at_seq: Option<u64>,
pub redacted_state: Vec<u8>,
pub source_identity: AgentId,
pub tenant: Option<TenantId>,
}
impl HandoffState {
pub fn new(
from_run: impl Into<String>,
merkle_root: impl Into<String>,
redacted_state: Vec<u8>,
source_identity: AgentId,
tenant: Option<TenantId>,
at_seq: Option<u64>,
) -> Self {
Self {
from_run: from_run.into(),
merkle_root: merkle_root.into(),
at_seq,
redacted_state,
source_identity,
tenant,
}
}
}
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum HandoffError {
#[error("envelope expired at {expired_at}")]
Expired {
expired_at: String,
},
#[error("signature invalid: {0}")]
SignatureInvalid(String),
#[error("untrusted source identity: {0}")]
UntrustedSource(String),
#[error("serialisation: {0}")]
Serialisation(String),
#[error("storage unavailable: {0}")]
Storage(String),
#[error("internal: {0}")]
Internal(String),
}
#[async_trait]
pub trait Handoff: Send + Sync {
async fn package(
&self,
state: HandoffState,
signer: &SigningKey,
ttl: chrono::Duration,
) -> Result<HandoffEnvelope, HandoffError>;
async fn deliver(&self, envelope: HandoffEnvelope, to: AgentId)
-> Result<String, HandoffError>;
async fn verify(&self, envelope: &HandoffEnvelope) -> Result<HandoffProof, HandoffError>;
}