use serde::{Deserialize, Serialize};
pub use crate::agents::{
AgentCategory, AgentCost, AgentPromptMetadata, DelegationTrigger, ModelType, RoutingTier,
};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum AgentStatus {
Idle,
Running,
Completed,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AgentState {
pub name: String,
pub status: AgentStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub last_message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub start_time: Option<u64>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum TaskStatus {
Pending,
Running,
Completed,
Error,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BackgroundTask {
pub id: String,
pub agent_name: String,
pub prompt: String,
pub status: TaskStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub result: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum HookEvent {
PreToolUse,
PostToolUse,
Stop,
SessionStart,
SessionEnd,
UserPromptSubmit,
}
impl HookEvent {
pub fn as_str(&self) -> &'static str {
match self {
HookEvent::PreToolUse => "PreToolUse",
HookEvent::PostToolUse => "PostToolUse",
HookEvent::Stop => "Stop",
HookEvent::SessionStart => "SessionStart",
HookEvent::SessionEnd => "SessionEnd",
HookEvent::UserPromptSubmit => "UserPromptSubmit",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct HookContext {
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_name: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_input: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub tool_output: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub session_id: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HookResult {
#[serde(rename = "continue")]
pub should_continue: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub modified_input: Option<serde_json::Value>,
}
impl Default for HookResult {
fn default() -> Self {
Self {
should_continue: true,
message: None,
modified_input: None,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_model_type_serialize() {
let model = ModelType::Sonnet;
let json = serde_json::to_string(&model).unwrap();
assert_eq!(json, r#""sonnet""#);
}
#[test]
fn test_agent_category_default_model() {
assert_eq!(AgentCategory::Exploration.default_model(), ModelType::Haiku);
assert_eq!(AgentCategory::Advisor.default_model(), ModelType::Opus);
assert_eq!(AgentCategory::Specialist.default_model(), ModelType::Sonnet);
}
#[test]
fn test_hook_result_default() {
let result = HookResult::default();
assert!(result.should_continue);
assert!(result.message.is_none());
}
}