use crate::clock::{SharedClock, SystemClock};
use crate::error::BuildError;
use crate::redactor::{DefaultRedactor, SharedRedactor};
use crate::runtime::supervised::SupervisedAgent;
use crate::tenant::TenantResolver;
use crate::types::{AgentId, ProviderId};
use klieo_core::Agent;
use std::sync::Arc;
use std::time::Duration;
#[cfg(feature = "gates")]
const DEFAULT_APPROVAL_TIMEOUT: Duration = Duration::from_secs(600);
pub struct OpsRuntime;
impl OpsRuntime {
#[must_use]
pub fn builder() -> OpsRuntimeBuilder {
OpsRuntimeBuilder::default()
}
}
pub struct OpsRuntimeBuilder {
tenant_resolver: Option<Arc<dyn TenantResolver>>,
redactor: SharedRedactor,
clock: SharedClock,
agent_id: Option<AgentId>,
#[cfg(feature = "governor")]
governor: Option<Arc<dyn crate::governor::Governor>>,
#[cfg(feature = "governor")]
governor_provider: Option<ProviderId>,
#[cfg(feature = "escalation")]
escalation: Option<Arc<dyn crate::escalation::Escalation>>,
#[cfg(feature = "gates")]
gates: Vec<Arc<dyn crate::gates::Gate>>,
#[cfg(feature = "gates")]
approval_timeout: Duration,
#[cfg(feature = "gates")]
approval_timeout_policy: crate::gates::ApprovalTimeoutPolicy,
}
impl Default for OpsRuntimeBuilder {
fn default() -> Self {
Self {
tenant_resolver: None,
redactor: Arc::new(DefaultRedactor::new()),
clock: Arc::new(SystemClock::default()),
agent_id: None,
#[cfg(feature = "governor")]
governor: None,
#[cfg(feature = "governor")]
governor_provider: None,
#[cfg(feature = "escalation")]
escalation: None,
#[cfg(feature = "gates")]
gates: Vec::new(),
#[cfg(feature = "gates")]
approval_timeout: DEFAULT_APPROVAL_TIMEOUT,
#[cfg(feature = "gates")]
approval_timeout_policy: crate::gates::ApprovalTimeoutPolicy::default(),
}
}
}
impl OpsRuntimeBuilder {
#[must_use]
pub fn tenant_resolver(mut self, r: Arc<dyn TenantResolver>) -> Self {
self.tenant_resolver = Some(r);
self
}
#[must_use]
pub fn redactor(mut self, r: SharedRedactor) -> Self {
self.redactor = r;
self
}
#[must_use]
pub fn clock(mut self, c: SharedClock) -> Self {
self.clock = c;
self
}
#[must_use]
pub fn agent_id(mut self, id: AgentId) -> Self {
self.agent_id = Some(id);
self
}
#[cfg(feature = "governor")]
#[must_use]
pub fn governor(mut self, g: Arc<dyn crate::governor::Governor>) -> Self {
self.governor = Some(g);
self
}
#[cfg(feature = "governor")]
#[must_use]
pub fn governor_provider(mut self, p: ProviderId) -> Self {
self.governor_provider = Some(p);
self
}
#[cfg(feature = "escalation")]
#[must_use]
pub fn escalation(mut self, e: Arc<dyn crate::escalation::Escalation>) -> Self {
self.escalation = Some(e);
self
}
#[cfg(feature = "gates")]
#[must_use]
pub fn gate(mut self, gate: Arc<dyn crate::gates::Gate>) -> Self {
self.gates.push(gate);
self
}
#[cfg(feature = "gates")]
#[must_use]
pub fn approval_timeout(mut self, timeout: Duration) -> Self {
self.approval_timeout = timeout;
self
}
#[cfg(feature = "gates")]
#[must_use]
pub fn approval_timeout_policy(mut self, policy: crate::gates::ApprovalTimeoutPolicy) -> Self {
self.approval_timeout_policy = policy;
self
}
pub fn spawn<A>(self, agent: A) -> Result<SupervisedAgent<A>, BuildError>
where
A: Agent,
{
#[cfg(all(feature = "escalation", feature = "gates"))]
if self.escalation.is_none() && self.gates.iter().any(|g| g.may_require_approval()) {
return Err(BuildError::MissingDependency {
needed_by: "Gate (may_require_approval == true)".into(),
missing: "escalation".into(),
});
}
let tenant_resolver =
self.tenant_resolver
.ok_or_else(|| BuildError::MissingDependency {
needed_by: "OpsRuntime".into(),
missing: "tenant_resolver".into(),
})?;
let agent_id = self
.agent_id
.unwrap_or_else(|| AgentId(agent.name().to_string()));
let _ = (&self.redactor, &self.clock);
Ok(SupervisedAgent {
inner: agent,
tenant_resolver,
agent_id,
#[cfg(feature = "governor")]
governor: self.governor,
#[cfg(feature = "governor")]
governor_provider: self
.governor_provider
.unwrap_or_else(|| ProviderId("default".into())),
#[cfg(feature = "gates")]
gates: self.gates,
#[cfg(feature = "gates")]
approval_timeout: self.approval_timeout,
#[cfg(feature = "gates")]
approval_timeout_policy: self.approval_timeout_policy,
})
}
}