use std::collections::HashMap;
use bevy_ecs::entity::Entity;
use crate::world::AgentId;
use serde::{Deserialize, Serialize};
use tokio::sync::oneshot;
use crate::components::{AgentStatus, WaitReason};
use crate::world::PipelineWorld;
use leviath_core::interaction::{InteractionRequest, InteractionResponse};
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)]
pub struct SpawnArgs {
pub run_id: String,
pub blueprint_path: String,
pub task: String,
#[serde(default)]
pub regions: HashMap<String, String>,
#[serde(default)]
pub model: Option<String>,
pub workdir: String,
#[serde(default)]
pub metadata: HashMap<String, String>,
#[serde(default)]
pub callback_url: Option<String>,
#[serde(default)]
pub callback_secret: Option<String>,
#[serde(default)]
pub yolo: bool,
#[serde(default)]
pub no_seed_commands: bool,
#[serde(default)]
pub allow: Vec<String>,
#[serde(default)]
pub max_depth: Option<usize>,
#[serde(default)]
pub parent_run_id: Option<String>,
#[serde(default)]
pub output: Option<leviath_core::output::OutputSpec>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct RunListEntry {
pub run_id: String,
#[serde(default)]
pub title: Option<String>,
pub status: AgentStatus,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub wait_reason: Option<WaitReason>,
pub stage: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub stage_index: Option<usize>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub num_stages: Option<usize>,
pub iteration: usize,
pub tool_calls: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub last_progress_at: Option<i64>,
#[serde(default)]
pub unattended: bool,
#[serde(default)]
pub empty_output: bool,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub read_paths: Option<leviath_core::run_meta::ReadPathGrantCounts>,
#[serde(default)]
pub has_final_output: bool,
}
#[derive(Debug, Clone, Default, PartialEq)]
pub struct RunListing {
pub runs: Vec<RunListEntry>,
pub finished: Vec<RunListEntry>,
pub health: DaemonHealth,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct DaemonHealth {
pub agents: crate::world::AgentCounts,
pub inference: Vec<crate::inference_pool::PoolOccupancy>,
pub tools_busy: usize,
pub tools_queued: usize,
pub tools_parked: usize,
pub tools_workers: usize,
pub dead_cycles: u32,
pub relief_granted: usize,
pub redrive_secs: u64,
#[serde(default)]
pub providers_down: Vec<crate::pipeline::ProviderCircuitState>,
}
pub type Spawner = Box<dyn FnMut(&mut PipelineWorld, &SpawnArgs) -> Result<Entity, String> + Send>;
pub type Reloader = Box<dyn FnMut(&mut PipelineWorld, &str) -> Option<AgentId> + Send>;
pub type ForceTerminator = Box<dyn FnMut(&str) -> bool + Send>;
pub type Reaper = Box<dyn FnMut(&mut PipelineWorld, Entity) + Send>;
pub type SpawnPreprocessor = Box<
dyn Fn(&SpawnArgs) -> std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>> + Send,
>;
pub enum SubAgentOp {
Spawn {
args: Box<SpawnArgs>,
parent_run_id: String,
max_depth: usize,
reply: oneshot::Sender<Result<String, String>>,
},
Check {
run_id: String,
reply: oneshot::Sender<Option<SubAgentReport>>,
},
Send {
run_id: String,
caller_run_id: String,
content: String,
target_region: Option<String>,
reply: oneshot::Sender<bool>,
},
Kill {
run_id: String,
caller_run_id: String,
reply: oneshot::Sender<bool>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct SubAgentReport {
pub status: AgentStatus,
pub final_output: Option<leviath_core::output::FinalOutput>,
}
pub enum ControlOp {
Spawn {
args: Box<SpawnArgs>,
reply: oneshot::Sender<Result<String, String>>,
},
Status {
run_id: String,
reply: oneshot::Sender<Option<AgentStatus>>,
},
Result {
run_id: String,
reply: oneshot::Sender<Option<leviath_core::output::FinalOutput>>,
},
Pause {
run_id: String,
reply: oneshot::Sender<bool>,
},
Resume {
run_id: String,
reply: oneshot::Sender<bool>,
},
Cancel {
run_id: String,
reply: oneshot::Sender<bool>,
},
List {
reply: oneshot::Sender<RunListing>,
},
Message {
agent_id: String,
content: String,
target_region: Option<String>,
reply: oneshot::Sender<bool>,
},
ListInteractions {
reply: oneshot::Sender<Vec<(String, InteractionRequest)>>,
},
AnswerInteraction {
response: InteractionResponse,
reply: oneshot::Sender<bool>,
},
CancelInteraction {
request_id: String,
reply: oneshot::Sender<bool>,
},
Shutdown {
reply: oneshot::Sender<bool>,
},
}