use std::{path::PathBuf, sync::Arc};
use serde_json::Value;
use crate::error_taxonomy::ErrorEnvelope;
use crate::models::{Message, SystemPrompt, Tool, Usage};
use crate::tools::goal::GoalSnapshot;
use crate::tools::spec::{ToolError, ToolResult};
use crate::tools::subagent::SubAgentResult;
use crate::tools::user_input::UserInputRequest;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TurnOutcomeStatus {
Completed,
Interrupted,
Failed,
}
#[derive(Debug, Clone)]
pub enum Event {
MessageStarted {
#[allow(dead_code)]
index: usize,
},
MessageDelta {
#[allow(dead_code)]
index: usize,
content: String,
},
MessageComplete {
#[allow(dead_code)]
index: usize,
},
ThinkingStarted {
#[allow(dead_code)]
index: usize,
},
ThinkingDelta {
#[allow(dead_code)]
index: usize,
content: String,
},
ThinkingComplete {
#[allow(dead_code)]
index: usize,
},
ToolCallStarted {
id: String,
name: String,
input: Value,
},
ToolCallComplete {
id: String,
name: String,
result: Result<ToolResult, ToolError>,
},
TurnStarted { turn_id: String },
TurnComplete {
usage: Usage,
status: TurnOutcomeStatus,
error: Option<String>,
tool_catalog: Option<Vec<Tool>>,
base_url: Option<String>,
},
GoalUpdated { snapshot: GoalSnapshot },
CompactionStarted {
id: String,
auto: bool,
message: String,
},
CompactionCompleted {
id: String,
auto: bool,
message: String,
#[allow(dead_code)]
messages_before: Option<usize>,
#[allow(dead_code)]
messages_after: Option<usize>,
},
PurgeStarted {
message: String,
},
PurgeCompleted {
messages_before: usize,
messages_after: usize,
removed_count: usize,
replaced_count: usize,
message: String,
},
PurgeFailed { message: String },
CompactionFailed {
id: String,
auto: bool,
message: String,
},
AgentSpawned {
id: String,
prompt: String,
parent_run_id: Option<String>,
spawn_depth: u32,
},
AgentProgress {
id: String,
status: String,
parent_run_id: Option<String>,
spawn_depth: u32,
},
AgentComplete { id: String, result: String },
AgentList { agents: Vec<SubAgentResult> },
SubAgentMailbox {
seq: u64,
message: crate::tools::subagent::MailboxMessage,
},
Error {
envelope: ErrorEnvelope,
#[allow(dead_code)]
recoverable: bool,
},
Status { message: String },
PauseEvents {
ack: Option<Arc<tokio::sync::Notify>>,
},
ResumeEvents,
ApprovalRequired {
id: String,
tool_name: String,
description: String,
input: Value,
approval_key: String,
approval_grouping_key: String,
intent_summary: Option<String>,
approval_force_prompt: bool,
},
UserInputRequired {
id: String,
request: UserInputRequest,
},
SessionUpdated {
session_id: String,
messages: Vec<Message>,
system_prompt: Option<SystemPrompt>,
model: String,
workspace: PathBuf,
},
#[allow(dead_code)]
ElevationRequired {
tool_id: String,
tool_name: String,
command: Option<String>,
denial_reason: String,
blocked_network: bool,
blocked_write: bool,
},
PrefixCacheChange {
description: String,
system_prompt_changed: bool,
tools_changed: bool,
stability_pct: u32,
changed: bool,
pinned_combined_hash: String,
},
}
impl Event {
pub fn error(envelope: ErrorEnvelope) -> Self {
let recoverable = envelope.recoverable;
Event::Error {
envelope,
recoverable,
}
}
pub fn status(message: impl Into<String>) -> Self {
Event::Status {
message: message.into(),
}
}
}