use crate::agent::AgentEvent;
use crate::llm::TokenUsage;
use crate::orchestrator::{ControlSignal, SubAgentConfig, SubAgentState};
use crate::planning::ExecutionPlan;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "event_type", rename_all = "snake_case")]
#[allow(clippy::large_enum_variant)]
pub enum OrchestratorEvent {
SubAgentStarted {
id: String,
agent_type: String,
description: String,
#[serde(skip_serializing_if = "Option::is_none")]
parent_id: Option<String>,
config: SubAgentConfig,
},
SubAgentCompleted {
id: String,
success: bool,
output: String,
duration_ms: u64,
#[serde(skip_serializing_if = "Option::is_none")]
token_usage: Option<TokenUsage>,
},
SubAgentStateChanged {
id: String,
old_state: SubAgentState,
new_state: SubAgentState,
},
SubAgentProgress {
id: String,
step: usize,
total_steps: usize,
message: String,
},
SubAgentInternalEvent {
id: String,
#[serde(flatten)]
event: AgentEvent,
},
PlanningStarted { id: String, goal: String },
PlanningCompleted { id: String, plan: ExecutionPlan },
ToolExecutionStarted {
id: String,
tool_id: String,
tool_name: String,
args: serde_json::Value,
},
ToolExecutionCompleted {
id: String,
tool_id: String,
tool_name: String,
result: String,
exit_code: i32,
duration_ms: u64,
},
ControlSignalReceived { id: String, signal: ControlSignal },
ControlSignalApplied {
id: String,
signal: ControlSignal,
success: bool,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<String>,
},
ExternalTaskPending {
id: String,
task_id: String,
lane: crate::hitl::SessionLane,
command_type: String,
payload: serde_json::Value,
timeout_ms: u64,
},
ExternalTaskCompleted {
id: String,
task_id: String,
success: bool,
},
}
impl OrchestratorEvent {
pub fn subagent_id(&self) -> Option<&str> {
match self {
OrchestratorEvent::SubAgentStarted { id, .. }
| OrchestratorEvent::SubAgentCompleted { id, .. }
| OrchestratorEvent::SubAgentStateChanged { id, .. }
| OrchestratorEvent::SubAgentProgress { id, .. }
| OrchestratorEvent::SubAgentInternalEvent { id, .. }
| OrchestratorEvent::PlanningStarted { id, .. }
| OrchestratorEvent::PlanningCompleted { id, .. }
| OrchestratorEvent::ToolExecutionStarted { id, .. }
| OrchestratorEvent::ToolExecutionCompleted { id, .. }
| OrchestratorEvent::ControlSignalReceived { id, .. }
| OrchestratorEvent::ControlSignalApplied { id, .. }
| OrchestratorEvent::ExternalTaskPending { id, .. }
| OrchestratorEvent::ExternalTaskCompleted { id, .. } => Some(id),
}
}
pub fn event_name(&self) -> &'static str {
match self {
OrchestratorEvent::SubAgentStarted { .. } => "subagent_started",
OrchestratorEvent::SubAgentCompleted { .. } => "subagent_completed",
OrchestratorEvent::SubAgentStateChanged { .. } => "subagent_state_changed",
OrchestratorEvent::SubAgentProgress { .. } => "subagent_progress",
OrchestratorEvent::SubAgentInternalEvent { .. } => "subagent_internal_event",
OrchestratorEvent::PlanningStarted { .. } => "planning_started",
OrchestratorEvent::PlanningCompleted { .. } => "planning_completed",
OrchestratorEvent::ToolExecutionStarted { .. } => "tool_execution_started",
OrchestratorEvent::ToolExecutionCompleted { .. } => "tool_execution_completed",
OrchestratorEvent::ControlSignalReceived { .. } => "control_signal_received",
OrchestratorEvent::ControlSignalApplied { .. } => "control_signal_applied",
OrchestratorEvent::ExternalTaskPending { .. } => "external_task_pending",
OrchestratorEvent::ExternalTaskCompleted { .. } => "external_task_completed",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SubAgentEventPayload {
pub subagent_id: String,
pub event: OrchestratorEvent,
pub timestamp: i64,
}