use crate::error::Result;
use crate::typed_id::SessionId;
use async_trait::async_trait;
use std::sync::Arc;
pub const DEFAULT_MAX_SUBAGENT_DEPTH: u32 = 2;
pub const DEFAULT_MAX_ACTIVE_DESCENDANT_SUBAGENT_TASKS: u32 = 16;
pub const DEFAULT_MAX_TOTAL_DESCENDANT_SUBAGENT_TASKS: u32 = 200;
pub const DEFAULT_MAX_ACTIVE_DETACHED_TASKS: u32 = 8;
pub const DEFAULT_MAX_TOTAL_DETACHED_TASKS: u32 = 50;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SubagentNestingPolicy {
pub platform_default: u32,
pub org_override: Option<u32>,
pub agent_override: Option<u32>,
pub platform_default_max_active_descendant_tasks: u32,
pub org_override_max_active_descendant_tasks: Option<u32>,
pub agent_override_max_active_descendant_tasks: Option<u32>,
pub platform_default_max_total_descendant_tasks: u32,
pub org_override_max_total_descendant_tasks: Option<u32>,
pub agent_override_max_total_descendant_tasks: Option<u32>,
pub platform_default_max_active_detached_tasks: u32,
pub org_override_max_active_detached_tasks: Option<u32>,
pub agent_override_max_active_detached_tasks: Option<u32>,
pub platform_default_max_total_detached_tasks: u32,
pub org_override_max_total_detached_tasks: Option<u32>,
pub agent_override_max_total_detached_tasks: Option<u32>,
}
impl Default for SubagentNestingPolicy {
fn default() -> Self {
Self {
platform_default: DEFAULT_MAX_SUBAGENT_DEPTH,
org_override: None,
agent_override: None,
platform_default_max_active_descendant_tasks:
DEFAULT_MAX_ACTIVE_DESCENDANT_SUBAGENT_TASKS,
org_override_max_active_descendant_tasks: None,
agent_override_max_active_descendant_tasks: None,
platform_default_max_total_descendant_tasks:
DEFAULT_MAX_TOTAL_DESCENDANT_SUBAGENT_TASKS,
org_override_max_total_descendant_tasks: None,
agent_override_max_total_descendant_tasks: None,
platform_default_max_active_detached_tasks: DEFAULT_MAX_ACTIVE_DETACHED_TASKS,
org_override_max_active_detached_tasks: None,
agent_override_max_active_detached_tasks: None,
platform_default_max_total_detached_tasks: DEFAULT_MAX_TOTAL_DETACHED_TASKS,
org_override_max_total_detached_tasks: None,
agent_override_max_total_detached_tasks: None,
}
}
}
impl SubagentNestingPolicy {
pub fn max_subagent_depth(self) -> u32 {
self.agent_override
.or(self.org_override)
.unwrap_or(self.platform_default)
}
pub fn max_active_descendant_tasks(self) -> u32 {
self.agent_override_max_active_descendant_tasks
.or(self.org_override_max_active_descendant_tasks)
.unwrap_or(self.platform_default_max_active_descendant_tasks)
}
pub fn max_total_descendant_tasks(self) -> u32 {
self.agent_override_max_total_descendant_tasks
.or(self.org_override_max_total_descendant_tasks)
.unwrap_or(self.platform_default_max_total_descendant_tasks)
}
pub fn max_active_detached_tasks(self) -> u32 {
self.agent_override_max_active_detached_tasks
.or(self.org_override_max_active_detached_tasks)
.unwrap_or(self.platform_default_max_active_detached_tasks)
}
pub fn max_total_detached_tasks(self) -> u32 {
self.agent_override_max_total_detached_tasks
.or(self.org_override_max_total_detached_tasks)
.unwrap_or(self.platform_default_max_total_detached_tasks)
}
pub fn with_platform_default(mut self, depth: u32) -> Self {
self.platform_default = depth;
self
}
pub fn with_org_override(mut self, depth: Option<u32>) -> Self {
self.org_override = depth;
self
}
pub fn with_agent_override(mut self, depth: Option<u32>) -> Self {
self.agent_override = depth;
self
}
pub fn with_agent_task_caps_override(
mut self,
max_active: Option<u32>,
max_total: Option<u32>,
) -> Self {
self.agent_override_max_active_descendant_tasks = max_active;
self.agent_override_max_total_descendant_tasks = max_total;
self
}
pub fn with_agent_detached_task_caps_override(
mut self,
max_active: Option<u32>,
max_total: Option<u32>,
) -> Self {
self.agent_override_max_active_detached_tasks = max_active;
self.agent_override_max_total_detached_tasks = max_total;
self
}
}
#[async_trait]
pub trait SessionCreationAuthority: Send + Sync {
async fn authorize_session_creation(&self, session_id: SessionId) -> Result<SessionId>;
}
#[derive(Debug)]
pub enum SpawnClaimResult {
Claimed {
spawn_handle_id: uuid::Uuid,
claim_token: uuid::Uuid,
},
ClaimedPendingChild {
spawn_handle_id: uuid::Uuid,
claim_token: uuid::Uuid,
},
AlreadyRunning {
child_session_id: crate::typed_id::SessionId,
claim_token: uuid::Uuid,
},
AlreadySettled {
child_session_id: crate::typed_id::SessionId,
terminal_status: String,
terminal_result: String,
},
}
#[async_trait]
pub trait SubagentSpawnStore: Send + Sync + 'static {
async fn try_claim_spawn(
&self,
parent_session_id: crate::typed_id::SessionId,
tool_call_id: &str,
claim_token: uuid::Uuid,
) -> Result<SpawnClaimResult>;
async fn register_child_session(
&self,
spawn_handle_id: uuid::Uuid,
claim_token: uuid::Uuid,
child_session_id: crate::typed_id::SessionId,
) -> Result<()>;
async fn settle_spawn(
&self,
parent_session_id: crate::typed_id::SessionId,
tool_call_id: &str,
claim_token: uuid::Uuid,
terminal_status: &str,
terminal_result: &str,
) -> Result<()>;
}
#[async_trait]
impl<S: SubagentSpawnStore + ?Sized> SubagentSpawnStore for Arc<S> {
async fn try_claim_spawn(
&self,
parent_session_id: crate::typed_id::SessionId,
tool_call_id: &str,
claim_token: uuid::Uuid,
) -> Result<SpawnClaimResult> {
(**self)
.try_claim_spawn(parent_session_id, tool_call_id, claim_token)
.await
}
async fn register_child_session(
&self,
spawn_handle_id: uuid::Uuid,
claim_token: uuid::Uuid,
child_session_id: crate::typed_id::SessionId,
) -> Result<()> {
(**self)
.register_child_session(spawn_handle_id, claim_token, child_session_id)
.await
}
async fn settle_spawn(
&self,
parent_session_id: crate::typed_id::SessionId,
tool_call_id: &str,
claim_token: uuid::Uuid,
terminal_status: &str,
terminal_result: &str,
) -> Result<()> {
(**self)
.settle_spawn(
parent_session_id,
tool_call_id,
claim_token,
terminal_status,
terminal_result,
)
.await
}
}