use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use zagens_core::subagent::{
CompletionReason, SubAgentAssignment, SubAgentResult, SubAgentStatus, SubAgentType,
};
use super::constants::SUBAGENT_STATE_SCHEMA_VERSION;
#[derive(Debug, Clone, Default)]
pub(crate) struct SubAgentSpawnOptions {
pub model: Option<String>,
pub nickname: Option<String>,
pub task_id: Option<String>,
pub scratchpad_run_id: Option<String>,
pub cwd_label: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum WaitMode {
Any,
All,
}
impl WaitMode {
pub(crate) fn from_str(value: &str) -> Option<Self> {
match value.to_ascii_lowercase().as_str() {
"any" | "first" => Some(Self::Any),
"all" => Some(Self::All),
_ => None,
}
}
pub(crate) fn as_str(self) -> &'static str {
match self {
Self::Any => "any",
Self::All => "all",
}
}
pub(crate) fn condition_met(self, snapshots: &[SubAgentResult]) -> bool {
match self {
Self::Any => snapshots
.iter()
.any(|snapshot| snapshot.status != SubAgentStatus::Running),
Self::All => snapshots
.iter()
.all(|snapshot| snapshot.status != SubAgentStatus::Running),
}
}
}
#[derive(Debug, Clone)]
pub(crate) struct SubAgentInput {
pub(crate) text: String,
pub(crate) interrupt: bool,
}
#[derive(Debug, Clone)]
pub(crate) struct SpawnRequest {
pub(crate) prompt: String,
pub(crate) agent_type: SubAgentType,
pub(crate) assignment: SubAgentAssignment,
pub(crate) allowed_tools: Option<Vec<String>>,
pub(crate) model: Option<String>,
pub(crate) cwd: Option<PathBuf>,
pub(crate) resident_file: Option<String>,
pub(crate) task_id: Option<String>,
pub(crate) nickname: Option<String>,
}
#[derive(Debug, Clone)]
pub(crate) struct AssignRequest {
pub(crate) agent_id: String,
pub(crate) objective: Option<String>,
pub(crate) role: Option<String>,
pub(crate) message: Option<String>,
pub(crate) interrupt: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct PersistedSubAgent {
pub(crate) id: String,
pub(crate) agent_type: SubAgentType,
pub(crate) prompt: String,
pub(crate) assignment: SubAgentAssignment,
#[serde(default)]
pub(crate) model: String,
#[serde(default)]
pub(crate) nickname: Option<String>,
pub(crate) status: SubAgentStatus,
pub(crate) result: Option<String>,
pub(crate) steps_taken: u32,
pub(crate) duration_ms: u64,
pub(crate) allowed_tools: Vec<String>,
pub(crate) updated_at_ms: u64,
#[serde(default)]
pub(crate) session_boot_id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) completion_reason: Option<CompletionReason>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) blackboard_task_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) scratchpad_run_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) parent_thread_id: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub(crate) progress_status: Option<String>,
#[serde(default = "default_persisted_max_steps")]
pub(crate) max_steps: u32,
#[serde(default = "default_persisted_step_timeout_ms")]
pub(crate) step_timeout_ms: u64,
}
fn default_persisted_max_steps() -> u32 {
super::constants::DEFAULT_MAX_STEPS
}
fn default_persisted_step_timeout_ms() -> u64 {
u64::try_from(super::constants::STEP_API_TIMEOUT.as_millis()).unwrap_or(600_000)
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub(crate) struct PersistedSubAgentState {
pub(crate) schema_version: u32,
pub(crate) agents: Vec<PersistedSubAgent>,
}
impl Default for PersistedSubAgentState {
fn default() -> Self {
Self {
schema_version: SUBAGENT_STATE_SCHEMA_VERSION,
agents: Vec::new(),
}
}
}
pub const DEFAULT_MAX_SPAWN_DEPTH: u32 = 3;