Skip to main content

vv_agent/events/
payload.rs

1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4use crate::budget::{BudgetEnforcementBoundary, BudgetExhaustion, BudgetUsageSnapshot};
5use crate::checkpoint::{
6    OperationKind, OperationState, ReconciliationDecisionKind, ResumeObservation, ToolIdempotency,
7};
8use crate::types::{AgentStatus, ModelCallOperation, TokenUsage, ToolDirective};
9
10#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11#[serde(tag = "type", rename_all = "snake_case")]
12pub enum RunEventPayload {
13    RunStarted {
14        input: String,
15    },
16    RunStateChanged {
17        state: String,
18    },
19    AgentStarted,
20    CycleStarted,
21    ModelCallStarted {
22        call_id: String,
23        operation_id: String,
24        attempt: u32,
25        operation: ModelCallOperation,
26        backend: String,
27        model: String,
28    },
29    ModelCallCompleted {
30        call_id: String,
31        operation_id: String,
32        attempt: u32,
33        operation: ModelCallOperation,
34        backend: String,
35        model: String,
36        usage: TokenUsage,
37    },
38    ModelCallFailed {
39        call_id: String,
40        operation_id: String,
41        attempt: u32,
42        operation: ModelCallOperation,
43        backend: String,
44        model: String,
45        outcome: ModelCallFailureOutcome,
46        usage: TokenUsage,
47        error_code: String,
48    },
49    Diagnostic {
50        level: DiagnosticLevel,
51        code: String,
52        details: serde_json::Map<String, Value>,
53    },
54    AssistantDelta {
55        delta: String,
56        #[serde(default, skip_serializing_if = "Option::is_none")]
57        content_chars: Option<u64>,
58        #[serde(default, skip_serializing_if = "Option::is_none")]
59        estimated_tokens: Option<u64>,
60    },
61    ReasoningDelta {
62        delta: String,
63        #[serde(default, skip_serializing_if = "Option::is_none")]
64        reasoning_chars: Option<u64>,
65        #[serde(default, skip_serializing_if = "Option::is_none")]
66        estimated_tokens: Option<u64>,
67    },
68    ModelToolCallStarted {
69        tool_call_id: String,
70        #[serde(default, skip_serializing_if = "Option::is_none")]
71        tool_call_index: Option<u64>,
72        tool_name: String,
73        #[serde(default, skip_serializing_if = "Option::is_none")]
74        arguments_chars: Option<u64>,
75        #[serde(default, skip_serializing_if = "Option::is_none")]
76        estimated_tokens: Option<u64>,
77    },
78    ModelToolCallProgress {
79        tool_call_id: String,
80        #[serde(default, skip_serializing_if = "Option::is_none")]
81        tool_call_index: Option<u64>,
82        tool_name: String,
83        #[serde(default, skip_serializing_if = "Option::is_none")]
84        arguments_chars: Option<u64>,
85        #[serde(default, skip_serializing_if = "Option::is_none")]
86        estimated_tokens: Option<u64>,
87    },
88    ToolCallPlanned {
89        tool_call_id: String,
90        tool_name: String,
91        arguments: Value,
92    },
93    ToolCallStarted {
94        tool_call_id: String,
95        tool_name: String,
96        arguments: Value,
97    },
98    ApprovalRequested {
99        request_id: String,
100        tool_call_id: String,
101        tool_name: String,
102        message: String,
103    },
104    ApprovalResolved {
105        request_id: String,
106        tool_name: String,
107        tool_call_id: String,
108        action: ApprovalAction,
109    },
110    ToolCallCompleted {
111        tool_call_id: String,
112        tool_name: String,
113        status: ToolStatus,
114        directive: ToolDirective,
115        error_code: Option<String>,
116        execution_started: bool,
117        duration_ms: Option<u64>,
118    },
119    MemoryCompactStarted {
120        message_count: usize,
121        #[serde(default, skip_serializing_if = "Option::is_none")]
122        estimated_tokens: Option<u64>,
123        trigger: MemoryCompactTrigger,
124        configured_threshold: u64,
125        effective_threshold: u64,
126        microcompact_threshold: u64,
127        model_context_window: u64,
128        model_max_output_tokens: Option<u64>,
129        reserved_output_tokens: u64,
130        reserved_output_source: ReservedOutputSource,
131        autocompact_buffer_tokens: u64,
132    },
133    MemoryCompactCompleted {
134        before_count: usize,
135        after_count: usize,
136        #[serde(default, skip_serializing_if = "Option::is_none")]
137        summary_tokens: Option<u64>,
138        mode: MemoryCompactMode,
139        changed: bool,
140    },
141    SubRunStarted {
142        parent_tool_call_id: String,
143        #[serde(default, skip_serializing_if = "Option::is_none")]
144        child_session_id: Option<String>,
145        #[serde(default, skip_serializing_if = "Option::is_none")]
146        task_id: Option<String>,
147    },
148    SubRunCompleted {
149        parent_tool_call_id: String,
150        status: AgentStatus,
151        #[serde(default, skip_serializing_if = "Option::is_none")]
152        final_output: Option<String>,
153    },
154    HandoffStarted {
155        source_agent: String,
156        target_agent: String,
157        tool_call_id: String,
158    },
159    HandoffCompleted {
160        source_agent: String,
161        target_agent: String,
162        tool_call_id: String,
163    },
164    SessionPersisted,
165    BudgetSnapshot {
166        enforcement_boundary: BudgetEnforcementBoundary,
167        budget_usage: BudgetUsageSnapshot,
168    },
169    BudgetExhausted {
170        enforcement_boundary: BudgetEnforcementBoundary,
171        budget_usage: BudgetUsageSnapshot,
172        budget_exhaustion: BudgetExhaustion,
173    },
174    CheckpointCreated {
175        checkpoint_key: String,
176        resume_attempt: u64,
177    },
178    CheckpointResumed {
179        checkpoint_key: String,
180        resume_attempt: u64,
181    },
182    OperationReplayed {
183        checkpoint_key: String,
184        operation_id: String,
185        operation_kind: OperationKind,
186        receipt_state: OperationState,
187    },
188    OperationAmbiguous {
189        checkpoint_key: String,
190        operation_id: String,
191        operation_kind: OperationKind,
192        risk: String,
193        idempotency_support: Option<ToolIdempotency>,
194    },
195    ReconciliationRequired {
196        checkpoint_key: String,
197        operation_id: String,
198        operation_kind: OperationKind,
199        interruption_reason: String,
200        resume_observation: ResumeObservation,
201    },
202    ModelRetryDuplicateRisk {
203        checkpoint_key: String,
204        operation_id: String,
205        operation_kind: OperationKind,
206        risk: String,
207    },
208    ReconciliationResolved {
209        checkpoint_key: String,
210        operation_id: String,
211        operation_kind: OperationKind,
212        decision: ReconciliationDecisionKind,
213    },
214    RunCompleted {
215        status: AgentStatus,
216    },
217    RunFailed {
218        error: String,
219    },
220    RunCancelled {
221        reason: String,
222    },
223}
224
225#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
226#[serde(rename_all = "snake_case")]
227pub enum MemoryCompactTrigger {
228    MicroThreshold,
229    FullThreshold,
230    PromptTooLong,
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
234#[serde(rename_all = "snake_case")]
235pub enum MemoryCompactMode {
236    None,
237    Micro,
238    Structural,
239    Summary,
240    Emergency,
241}
242
243#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
244#[serde(rename_all = "snake_case")]
245pub enum ReservedOutputSource {
246    ModelSettings,
247    TaskMetadata,
248    FrameworkFallback,
249    FrameworkFallbackCappedByModelCapability,
250}
251
252#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
253#[serde(rename_all = "snake_case")]
254pub enum ModelCallFailureOutcome {
255    Definitive,
256    Ambiguous,
257}
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
260#[serde(rename_all = "snake_case")]
261pub enum DiagnosticLevel {
262    Debug,
263    Info,
264    Warning,
265    Error,
266}
267
268impl DiagnosticLevel {
269    pub fn as_str(self) -> &'static str {
270        match self {
271            Self::Debug => "debug",
272            Self::Info => "info",
273            Self::Warning => "warning",
274            Self::Error => "error",
275        }
276    }
277}
278
279#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
280#[serde(rename_all = "snake_case")]
281pub enum ApprovalAction {
282    Allow,
283    AllowSession,
284    Deny,
285    Timeout,
286}
287
288impl ApprovalAction {
289    pub fn parse(value: &str) -> Option<Self> {
290        match value {
291            "allow" => Some(Self::Allow),
292            "allow_session" => Some(Self::AllowSession),
293            "deny" => Some(Self::Deny),
294            "timeout" => Some(Self::Timeout),
295            _ => None,
296        }
297    }
298
299    pub fn as_str(self) -> &'static str {
300        match self {
301            Self::Allow => "allow",
302            Self::AllowSession => "allow_session",
303            Self::Deny => "deny",
304            Self::Timeout => "timeout",
305        }
306    }
307
308    pub fn is_approved(self) -> bool {
309        matches!(self, Self::Allow | Self::AllowSession)
310    }
311}
312
313#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
314#[serde(rename_all = "snake_case")]
315pub enum ToolStatus {
316    Started,
317    Success,
318    Error,
319    WaitResponse,
320    Running,
321    PendingCompress,
322}
323
324#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
325pub struct AgentErrorPayload {
326    pub message: String,
327    pub code: Option<String>,
328}
329
330impl AgentErrorPayload {
331    pub fn new(message: impl Into<String>) -> Self {
332        Self {
333            message: message.into(),
334            code: None,
335        }
336    }
337}