use std::sync::Arc;
use async_trait::async_trait;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::{RelationshipKind, TeamRuntimeError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub enum TeamLifecyclePhase {
Team,
Member,
Relationship,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase")]
pub struct TeamLifecycleContext {
pub team: String,
pub invocation_id: String,
pub phase: TeamLifecyclePhase,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub member: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub edge_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub from: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub to: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub kind: Option<RelationshipKind>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub attempt: Option<u32>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", tag = "status")]
pub enum TeamLifecycleOutcome {
Succeeded,
Failed {
#[serde(default, skip_serializing_if = "Option::is_none")]
code: Option<String>,
message: String,
},
Terminated {
reason: String,
},
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "camelCase", tag = "decision")]
pub enum TeamLifecycleDecision {
Continue,
Terminate {
reason: String,
},
}
#[async_trait]
pub trait TeamLifecycleHook: Send + Sync {
fn name(&self) -> &str;
fn priority(&self) -> i32 {
0
}
async fn before(
&self,
_context: &TeamLifecycleContext,
) -> adk_core::Result<TeamLifecycleDecision> {
Ok(TeamLifecycleDecision::Continue)
}
async fn after(
&self,
_context: &TeamLifecycleContext,
_outcome: &TeamLifecycleOutcome,
) -> adk_core::Result<()> {
Ok(())
}
}
pub(crate) struct TeamLifecycleManager {
hooks: Vec<Arc<dyn TeamLifecycleHook>>,
}
impl TeamLifecycleManager {
pub(crate) fn new(mut hooks: Vec<Arc<dyn TeamLifecycleHook>>) -> Self {
hooks.sort_by_key(|hook| hook.priority());
Self { hooks }
}
pub(crate) async fn before(
&self,
context: &TeamLifecycleContext,
) -> adk_core::Result<TeamLifecycleDecision> {
for hook in &self.hooks {
match hook.before(context).await.map_err(|error| TeamRuntimeError::LifecycleHook {
hook: hook.name().to_string(),
phase: context.phase,
message: error.to_string(),
})? {
TeamLifecycleDecision::Continue => {}
decision @ TeamLifecycleDecision::Terminate { .. } => return Ok(decision),
}
}
Ok(TeamLifecycleDecision::Continue)
}
pub(crate) async fn after(
&self,
context: &TeamLifecycleContext,
outcome: &TeamLifecycleOutcome,
) -> adk_core::Result<()> {
for hook in self.hooks.iter().rev() {
hook.after(context, outcome).await.map_err(|error| {
TeamRuntimeError::LifecycleHook {
hook: hook.name().to_string(),
phase: context.phase,
message: error.to_string(),
}
})?;
}
Ok(())
}
}