1use serde::{Deserialize, Serialize};
2use time::OffsetDateTime;
3
4use crate::artifacts::{ContextArtifact, ContextArtifactId};
5use crate::automations::{
6 AutomationCompleted, AutomationCreated, AutomationDeleted, AutomationDue, AutomationFailed,
7 AutomationLeaseExpired, AutomationLeased, AutomationQueued, AutomationSkipped,
8 AutomationStarted, AutomationUpdated,
9};
10use crate::code_index::{
11 CodeIndexChunked, CodeIndexEmbedded, CodeIndexFailed, CodeIndexProofFilteredResultDropped,
12 CodeIndexReady, CodeIndexStale, CodeIndexingStarted,
13};
14use crate::discovery::{
15 DiscoveryAuthRequired, DiscoveryCatalogBuilt, DiscoveryItemPromoted, DiscoveryItemRead,
16 DiscoveryItemUpdated, DiscoveryPromotionExpired, DiscoveryPromotionReused,
17 DiscoveryWarmCacheHit,
18};
19use crate::dynamic_workflows::{
20 WorkflowAgentCompleted, WorkflowAgentFailed, WorkflowAgentQueued, WorkflowAgentStarted,
21 WorkflowApprovalRequested, WorkflowCheckpointRecorded, WorkflowOutputRecorded,
22 WorkflowPhaseCompleted, WorkflowPhaseStarted, WorkflowRunApproved, WorkflowRunCompleted,
23 WorkflowRunDenied, WorkflowRunDrafted, WorkflowRunFailed, WorkflowRunPaused, WorkflowRunQueued,
24 WorkflowRunResumed, WorkflowRunStarted, WorkflowRunStopped,
25};
26use crate::extension::{ExtensionId, InferenceEngineId};
27use crate::goals::{ThreadGoalCleared, ThreadGoalUpdated};
28use crate::inference::{
29 InferenceEvent, ModelSelection, ReasoningConfig, RuntimeProfile, SpeedPolicyDecision,
30 TokenUsage,
31};
32use crate::inference_routing::InferenceRoutingDecision;
33use crate::knowledge::{KnowledgeDocId, KnowledgeDocSummary, KnowledgeLinkType};
34use crate::lifecycle::TurnLifecycleRecord;
35use crate::media::{MediaArtifact, MediaArtifactId, MediaPreview};
36use crate::memory::{MemoryCitation, MemoryId, MemoryProviderSelection, MemoryRecord, MemoryScope};
37use crate::plan_review::{
38 HunkId, HunkRecord, PlanComment, PlanReview, PlanReviewId, PlanReviewStatus, PlanRewrite,
39};
40use crate::processes::{
41 ProcessExited, ProcessFailed, ProcessOutput, ProcessStarted, ProcessStopped, ProcessStopping,
42};
43use crate::reliability::{
44 ReliabilityFailureRecorded, ReliabilityLimitRecorded, ReliabilityMetricRecorded,
45 ReliabilityRetryRecorded,
46};
47use crate::retrieval::{
48 RetrievalDiscoveryItemPromoted, RetrievalPromotionSkipped, RetrievalResultUsed,
49 RetrievalRouteAccepted, RetrievalRouteFailed, RetrievalRouteIgnored, RetrievalRoutePlanned,
50};
51use crate::review::{ReviewId, ReviewOutput, ReviewPublishSkip, ReviewPublisherId, ReviewTarget};
52use crate::skills::{
53 SkillActivationResolved, SkillAutoActivated, SkillConfigApplied, SkillIndexRendered,
54 SkillInvoked, SkillSkipped, SkillsCatalogLoaded,
55};
56use crate::subagents::{
57 AgentSwarmCompleted, AgentSwarmModeChanged, AgentSwarmProgress, AgentSwarmStarted,
58 SubagentExitReason, UltraModeChanged,
59};
60use crate::task_ledger::TaskLedgerItem;
61use crate::teams::{
62 AgentTeamDisplayMode, TeamId, TeamMemberDescriptor, TeamMemberId, TeamMemberStatus,
63 TeamTaskDescriptor,
64};
65use crate::trace::{
66 ParentTurnRef, SubagentTraceDelta, SubagentTraceId, SubagentTraceStatus, SubagentTraceSummary,
67};
68use crate::transcript::TranscriptItem;
69use crate::workflow::{WorkflowImportDecision, WorkflowImportError, WorkflowImportItem};
70use crate::workspace_changes::WorkspaceChangeObservation;
71
72pub use crate::policy_mode::{
73 PolicyBypassActive, PolicyDecisionRecorded, PolicyExitPlanRequested, PolicyExitPlanResolved,
74 PolicyModeChanged,
75};
76pub use crate::tasks::{TaskCancelled, TaskCompleted, TaskFailed, TaskOutput, TaskStarted};
77
78pub type ThreadId = String;
79pub type TurnId = String;
80pub type EventId = String;
81
82#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
83pub enum EventSource {
84 Runtime,
85 Core,
86 Provider,
87 Tool,
88 AppServer,
89 Tui,
90 Extension,
91 System,
92}
93
94#[derive(Debug, Clone, Serialize, Deserialize)]
95pub struct RuntimeStarted {
96 #[serde(with = "time::serde::rfc3339")]
97 pub timestamp: OffsetDateTime,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
102pub struct HookRunRecorded {
103 pub thread_id: ThreadId,
104 pub turn_id: TurnId,
105 pub tool_id: String,
106 pub tool_name: String,
107 pub hook_event_name: String,
108 pub handler_type: String,
109 pub status: String,
110 pub detail: String,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 pub output: Option<String>,
113 #[serde(with = "time::serde::rfc3339")]
114 pub timestamp: OffsetDateTime,
115}
116
117#[derive(Debug, Clone, Serialize, Deserialize)]
118pub struct ExtensionRegistered {
119 pub extension_id: ExtensionId,
120 #[serde(with = "time::serde::rfc3339")]
121 pub timestamp: OffsetDateTime,
122}
123
124#[derive(Debug, Clone, Serialize, Deserialize)]
125pub struct ThreadCreated {
126 pub thread_id: ThreadId,
127 #[serde(with = "time::serde::rfc3339")]
128 pub timestamp: OffsetDateTime,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
133pub struct ThreadForkRequested {
134 pub parent_thread_id: ThreadId,
135 pub name: String,
136 #[serde(with = "time::serde::rfc3339")]
137 pub timestamp: OffsetDateTime,
138}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct ThreadForked {
143 pub parent_thread_id: ThreadId,
144 pub child_thread_id: ThreadId,
145 pub fork: crate::forks::WorkspaceFork,
146 #[serde(with = "time::serde::rfc3339")]
147 pub timestamp: OffsetDateTime,
148}
149
150#[derive(Debug, Clone, Serialize, Deserialize)]
152pub struct ThreadForkFailed {
153 pub parent_thread_id: ThreadId,
154 pub name: String,
155 pub message: String,
156 #[serde(with = "time::serde::rfc3339")]
157 pub timestamp: OffsetDateTime,
158}
159
160#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct ThreadForkRemoved {
163 pub thread_id: ThreadId,
164 pub fork_id: String,
165 pub worktree_path: String,
166 #[serde(with = "time::serde::rfc3339")]
167 pub timestamp: OffsetDateTime,
168}
169
170#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct ExtensionEventEmitted {
175 pub extension_id: String,
176 pub event_kind: String,
177 pub schema_version: u32,
178 pub payload: serde_json::Value,
179 #[serde(with = "time::serde::rfc3339")]
180 pub timestamp: OffsetDateTime,
181}
182
183#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct EventSinkFailed {
188 pub sink_id: String,
189 pub event_kind: String,
190 pub message: String,
191 #[serde(with = "time::serde::rfc3339")]
192 pub timestamp: OffsetDateTime,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
196pub struct ThreadLoaded {
197 pub thread_id: ThreadId,
198 #[serde(with = "time::serde::rfc3339")]
199 pub timestamp: OffsetDateTime,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
203pub struct TurnStarted {
204 pub thread_id: ThreadId,
205 pub turn_id: TurnId,
206 #[serde(default)]
207 pub runtime_profile: RuntimeProfile,
208 #[serde(with = "time::serde::rfc3339")]
209 pub timestamp: OffsetDateTime,
210}
211
212#[derive(Debug, Clone, Serialize, Deserialize)]
213pub struct ContextAssemblyStarted {
214 pub thread_id: ThreadId,
215 pub turn_id: TurnId,
216 #[serde(with = "time::serde::rfc3339")]
217 pub timestamp: OffsetDateTime,
218}
219
220#[derive(Debug, Clone, Serialize, Deserialize)]
221pub struct ContextBlockAdded {
222 pub thread_id: ThreadId,
223 pub turn_id: TurnId,
224 pub block_type: String,
225 #[serde(default)]
226 pub byte_count: u64,
227 #[serde(default)]
228 pub estimated_tokens: u32,
229 #[serde(default)]
230 pub priority: i32,
231 #[serde(with = "time::serde::rfc3339")]
232 pub timestamp: OffsetDateTime,
233}
234
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct ContextAssemblyCompleted {
237 pub thread_id: ThreadId,
238 pub turn_id: TurnId,
239 #[serde(default)]
240 pub block_count: u64,
241 #[serde(default)]
242 pub total_byte_count: u64,
243 #[serde(default)]
244 pub estimated_tokens: u32,
245 #[serde(default)]
246 pub prompt_estimated_tokens: u32,
247 #[serde(default, skip_serializing_if = "Option::is_none")]
248 pub token_budget: Option<u32>,
249 #[serde(with = "time::serde::rfc3339")]
250 pub timestamp: OffsetDateTime,
251}
252
253#[derive(Debug, Clone, Serialize, Deserialize)]
254pub struct ContextEntrypointCandidatesInjected {
255 pub thread_id: ThreadId,
256 pub turn_id: TurnId,
257 pub candidate_count: u64,
258 pub block_byte_count: u64,
259 pub estimated_tokens: u32,
260 #[serde(with = "time::serde::rfc3339")]
261 pub timestamp: OffsetDateTime,
262}
263
264#[derive(Debug, Clone, Serialize, Deserialize)]
265pub struct ContextCompactionStarted {
266 pub thread_id: ThreadId,
267 pub turn_id: TurnId,
268 pub original_item_count: u64,
269 pub original_estimated_tokens: u32,
270 #[serde(with = "time::serde::rfc3339")]
271 pub timestamp: OffsetDateTime,
272}
273
274#[derive(Debug, Clone, Serialize, Deserialize)]
275pub struct ContextCompactionRecorded {
276 pub thread_id: ThreadId,
277 pub turn_id: TurnId,
278 pub original_item_count: u64,
279 pub original_estimated_tokens: u32,
280 pub compacted_item_count: u64,
281 pub compacted_estimated_tokens: u32,
282 pub file_backed: bool,
283 #[serde(default, skip_serializing_if = "Option::is_none")]
284 pub strategy: Option<String>,
285 #[serde(default, skip_serializing_if = "Option::is_none")]
286 pub pruned_tool_count: Option<u32>,
287 #[serde(default, skip_serializing_if = "Option::is_none")]
289 pub duration_ms: Option<u64>,
290 #[serde(with = "time::serde::rfc3339")]
291 pub timestamp: OffsetDateTime,
292}
293
294#[derive(Debug, Clone, Serialize, Deserialize)]
295pub struct ContextCompactionSkipped {
296 pub thread_id: ThreadId,
297 pub turn_id: TurnId,
298 pub reason: String,
299 pub estimated_tokens: u32,
300 #[serde(default, skip_serializing_if = "Option::is_none")]
301 pub threshold: Option<u32>,
302 #[serde(default, skip_serializing_if = "Option::is_none")]
303 pub pruned_tool_count: Option<u32>,
304 #[serde(with = "time::serde::rfc3339")]
305 pub timestamp: OffsetDateTime,
306}
307
308#[derive(Debug, Clone, Serialize, Deserialize)]
309pub struct InferenceStarted {
310 pub thread_id: ThreadId,
311 pub turn_id: TurnId,
312 pub engine_id: InferenceEngineId,
313 #[serde(default = "default_model_selection")]
314 pub model: ModelSelection,
315 #[serde(default)]
316 pub reasoning: ReasoningConfig,
317 #[serde(default, skip_serializing_if = "Option::is_none")]
318 pub speed_policy: Option<SpeedPolicyDecision>,
319 #[serde(default, skip_serializing_if = "Option::is_none")]
320 pub deadline_remaining_seconds: Option<u64>,
321 #[serde(with = "time::serde::rfc3339")]
322 pub timestamp: OffsetDateTime,
323}
324
325fn default_model_selection() -> ModelSelection {
326 ModelSelection {
327 provider: String::new(),
328 model: String::new(),
329 }
330}
331
332#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
333pub struct InferenceRoutingDecisionEvent {
334 pub thread_id: ThreadId,
335 pub turn_id: TurnId,
336 #[serde(default)]
337 pub round_index: u32,
338 pub default_selection: ModelSelection,
339 pub selected_selection: ModelSelection,
340 pub decision: InferenceRoutingDecision,
341 #[serde(with = "time::serde::rfc3339")]
342 pub timestamp: OffsetDateTime,
343}
344
345#[derive(Debug, Clone, Serialize, Deserialize)]
346pub struct InferenceEventReceived {
347 pub thread_id: ThreadId,
348 pub turn_id: TurnId,
349 pub event: InferenceEvent,
350 #[serde(with = "time::serde::rfc3339")]
351 pub timestamp: OffsetDateTime,
352}
353
354#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct ToolCallRequested {
356 pub thread_id: ThreadId,
357 pub turn_id: TurnId,
358 pub tool_id: String,
359 pub tool_name: String,
360 #[serde(default, skip_serializing_if = "Option::is_none")]
361 pub display_payload: Option<serde_json::Value>,
362 #[serde(with = "time::serde::rfc3339")]
363 pub timestamp: OffsetDateTime,
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
367#[serde(rename_all = "snake_case")]
368pub enum ToolCallValidationFailureClass {
369 InvalidJson,
370 UnknownTool,
371 MissingRequired,
372 UnexpectedProperty,
373 WrongType,
374 EmptyRequiredString,
375 SchemaRepairApplied,
376 SchemaRepairRejected,
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
380#[serde(rename_all = "snake_case")]
381pub enum ToolCallValidationRepairStatus {
382 NotNeeded,
383 Applied,
384 Rejected,
385}
386
387#[derive(Debug, Clone, Serialize, Deserialize)]
388pub struct ToolCallValidationRecorded {
389 pub thread_id: ThreadId,
390 pub turn_id: TurnId,
391 pub tool_id: String,
392 pub tool_name: String,
393 pub failure_class: ToolCallValidationFailureClass,
394 pub repair_status: ToolCallValidationRepairStatus,
395 pub message: String,
396 #[serde(with = "time::serde::rfc3339")]
397 pub timestamp: OffsetDateTime,
398}
399
400#[derive(Debug, Clone, Serialize, Deserialize)]
401pub struct ApprovalRequested {
402 pub thread_id: ThreadId,
403 pub turn_id: TurnId,
404 pub approval_id: String,
405 pub tool_id: String,
406 pub tool_name: String,
407 pub reason: Option<String>,
408 #[serde(with = "time::serde::rfc3339")]
409 pub timestamp: OffsetDateTime,
410}
411
412#[derive(Debug, Clone, Serialize, Deserialize)]
413pub struct ApprovalResolved {
414 pub thread_id: ThreadId,
415 pub turn_id: TurnId,
416 pub approval_id: String,
417 pub tool_id: String,
418 pub tool_name: String,
419 pub approved: bool,
420 #[serde(with = "time::serde::rfc3339")]
421 pub timestamp: OffsetDateTime,
422}
423
424#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
425#[serde(rename_all = "camelCase")]
426pub enum ExternalToolCallOutcome {
427 Resolved,
428 TimedOut,
429 Cancelled,
430}
431
432#[derive(Debug, Clone, Serialize, Deserialize)]
433pub struct ExternalToolCallRequested {
434 pub thread_id: ThreadId,
435 pub turn_id: TurnId,
436 pub request_id: String,
437 pub tool_id: String,
438 pub tool_name: String,
439 pub arguments: serde_json::Value,
440 #[serde(with = "time::serde::rfc3339")]
441 pub timestamp: OffsetDateTime,
442}
443
444#[derive(Debug, Clone, Serialize, Deserialize)]
445pub struct ExternalToolCallResolved {
446 pub thread_id: ThreadId,
447 pub turn_id: TurnId,
448 pub request_id: String,
449 pub tool_id: String,
450 pub tool_name: String,
451 pub outcome: ExternalToolCallOutcome,
452 pub is_error: bool,
453 #[serde(with = "time::serde::rfc3339")]
454 pub timestamp: OffsetDateTime,
455}
456
457#[derive(Debug, Clone, Serialize, Deserialize)]
458pub struct UserInputRequested {
459 pub thread_id: ThreadId,
460 pub turn_id: TurnId,
461 pub request_id: String,
462 pub questions: serde_json::Value,
463 #[serde(with = "time::serde::rfc3339")]
464 pub timestamp: OffsetDateTime,
465}
466
467#[derive(Debug, Clone, Serialize, Deserialize)]
468pub struct UserInputResolved {
469 pub thread_id: ThreadId,
470 pub turn_id: TurnId,
471 pub request_id: String,
472 pub answers: serde_json::Value,
473 #[serde(with = "time::serde::rfc3339")]
474 pub timestamp: OffsetDateTime,
475}
476
477#[derive(Debug, Clone, Serialize, Deserialize)]
478pub struct TaskLedgerUpdated {
479 pub thread_id: ThreadId,
480 pub turn_id: TurnId,
481 pub tasks: Vec<TaskLedgerItem>,
482 pub completed_count: u64,
483 #[serde(with = "time::serde::rfc3339")]
484 pub timestamp: OffsetDateTime,
485}
486
487#[derive(Debug, Clone, Serialize, Deserialize)]
488pub struct VerificationRequired {
489 pub thread_id: ThreadId,
490 pub turn_id: TurnId,
491 pub reason: String,
492 pub changed_files: Vec<String>,
493 pub tool_evidence: Vec<String>,
494 pub tests_run: Vec<String>,
495 pub open_gaps: Vec<String>,
496 #[serde(with = "time::serde::rfc3339")]
497 pub timestamp: OffsetDateTime,
498}
499
500#[derive(Debug, Clone, Serialize, Deserialize)]
501pub struct VerificationCompleted {
502 pub thread_id: ThreadId,
503 pub turn_id: TurnId,
504 pub passed: bool,
505 pub changed_files: Vec<String>,
506 pub tool_evidence: Vec<String>,
507 pub tests_run: Vec<String>,
508 pub open_gaps: Vec<String>,
509 #[serde(with = "time::serde::rfc3339")]
510 pub timestamp: OffsetDateTime,
511}
512
513#[derive(Debug, Clone, Serialize, Deserialize)]
514pub struct VerificationSkipped {
515 pub thread_id: ThreadId,
516 pub turn_id: TurnId,
517 pub reason: String,
518 #[serde(with = "time::serde::rfc3339")]
519 pub timestamp: OffsetDateTime,
520}
521
522#[derive(Debug, Clone, Serialize, Deserialize)]
523pub struct ToolCallStarted {
524 pub thread_id: ThreadId,
525 pub turn_id: TurnId,
526 pub tool_id: String,
527 #[serde(default, skip_serializing_if = "Option::is_none")]
528 pub tool_name: Option<String>,
529 #[serde(default, skip_serializing_if = "Option::is_none")]
530 pub display_payload: Option<serde_json::Value>,
531 #[serde(with = "time::serde::rfc3339")]
532 pub timestamp: OffsetDateTime,
533}
534
535#[derive(Debug, Clone, Serialize, Deserialize)]
536pub struct ToolCallCompleted {
537 pub thread_id: ThreadId,
538 pub turn_id: TurnId,
539 pub tool_id: String,
540 #[serde(default, skip_serializing_if = "Option::is_none")]
541 pub tool_name: Option<String>,
542 #[serde(default, skip_serializing_if = "Option::is_none")]
543 pub display_payload: Option<serde_json::Value>,
544 #[serde(default)]
545 pub is_error: bool,
546 #[serde(default)]
547 pub output: Option<String>,
548 #[serde(with = "time::serde::rfc3339")]
549 pub timestamp: OffsetDateTime,
550}
551
552#[derive(Debug, Clone, Serialize, Deserialize)]
553pub struct ToolOutputDelta {
554 pub thread_id: ThreadId,
555 pub turn_id: TurnId,
556 pub tool_id: String,
557 pub delta: String,
558 #[serde(with = "time::serde::rfc3339")]
559 pub timestamp: OffsetDateTime,
560}
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
563pub struct ToolOutputTruncated {
564 pub thread_id: ThreadId,
565 pub turn_id: TurnId,
566 pub tool_id: String,
567 #[serde(default, skip_serializing_if = "Option::is_none")]
568 pub tool_name: Option<String>,
569 pub original_line_count: u64,
570 pub original_char_count: u64,
571 pub inline_char_count: u64,
572 pub artifact_backed: bool,
573 #[serde(with = "time::serde::rfc3339")]
574 pub timestamp: OffsetDateTime,
575}
576
577#[derive(Debug, Clone, Serialize, Deserialize)]
578pub struct SubagentStarted {
579 pub thread_id: ThreadId,
580 pub turn_id: TurnId,
581 pub parent_thread_id: ThreadId,
582 pub parent_turn_id: TurnId,
583 pub agent_type: String,
584 pub description: String,
585 pub model: Option<String>,
586 #[serde(with = "time::serde::rfc3339")]
587 pub timestamp: OffsetDateTime,
588}
589
590#[derive(Debug, Clone, Serialize, Deserialize)]
591pub struct SubagentMessage {
592 pub thread_id: ThreadId,
593 pub turn_id: TurnId,
594 pub parent_thread_id: ThreadId,
595 pub parent_turn_id: TurnId,
596 pub agent_type: String,
597 pub text: String,
598 #[serde(with = "time::serde::rfc3339")]
599 pub timestamp: OffsetDateTime,
600}
601
602#[derive(Debug, Clone, Serialize, Deserialize)]
603pub struct SubagentToolCall {
604 pub thread_id: ThreadId,
605 pub turn_id: TurnId,
606 pub parent_thread_id: ThreadId,
607 pub parent_turn_id: TurnId,
608 pub agent_type: String,
609 pub tool_id: String,
610 pub tool_name: String,
611 #[serde(with = "time::serde::rfc3339")]
612 pub timestamp: OffsetDateTime,
613}
614
615#[derive(Debug, Clone, Serialize, Deserialize)]
616pub struct SubagentCompleted {
617 pub thread_id: ThreadId,
618 pub turn_id: TurnId,
619 pub parent_thread_id: ThreadId,
620 pub parent_turn_id: TurnId,
621 pub agent_type: String,
622 pub exit_reason: SubagentExitReason,
623 #[serde(with = "time::serde::rfc3339")]
624 pub timestamp: OffsetDateTime,
625}
626
627#[derive(Debug, Clone, Serialize, Deserialize)]
628pub struct SubagentFailed {
629 pub thread_id: ThreadId,
630 pub turn_id: TurnId,
631 pub parent_thread_id: ThreadId,
632 pub parent_turn_id: TurnId,
633 pub agent_type: String,
634 pub error: String,
635 #[serde(with = "time::serde::rfc3339")]
636 pub timestamp: OffsetDateTime,
637}
638
639#[derive(Debug, Clone, Serialize, Deserialize)]
640pub struct SubagentTraceCreated {
641 pub summary: SubagentTraceSummary,
642 #[serde(with = "time::serde::rfc3339")]
643 pub timestamp: OffsetDateTime,
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
647pub struct SubagentTraceDeltaEvent {
648 pub delta: SubagentTraceDelta,
649 #[serde(with = "time::serde::rfc3339")]
650 pub timestamp: OffsetDateTime,
651}
652
653#[derive(Debug, Clone, Serialize, Deserialize)]
654pub struct SubagentTraceStatusChanged {
655 pub trace_id: SubagentTraceId,
656 pub parent: ParentTurnRef,
657 pub status: SubagentTraceStatus,
658 #[serde(default, skip_serializing_if = "Option::is_none")]
659 pub detail: Option<String>,
660 #[serde(with = "time::serde::rfc3339")]
661 pub timestamp: OffsetDateTime,
662}
663
664#[derive(Debug, Clone, Serialize, Deserialize)]
665pub struct SubagentTraceCompleted {
666 pub summary: SubagentTraceSummary,
667 #[serde(with = "time::serde::rfc3339")]
668 pub timestamp: OffsetDateTime,
669}
670
671#[derive(Debug, Clone, Serialize, Deserialize)]
672pub struct SubagentTraceFailed {
673 pub summary: SubagentTraceSummary,
674 pub error: String,
675 #[serde(with = "time::serde::rfc3339")]
676 pub timestamp: OffsetDateTime,
677}
678
679#[derive(Debug, Clone, Serialize, Deserialize)]
680#[serde(rename_all = "camelCase")]
681pub struct PlanReviewCreated {
682 pub review: PlanReview,
683 #[serde(with = "time::serde::rfc3339")]
684 pub timestamp: OffsetDateTime,
685}
686
687#[derive(Debug, Clone, Serialize, Deserialize)]
688#[serde(rename_all = "camelCase")]
689pub struct PlanReviewStatusChanged {
690 pub thread_id: ThreadId,
691 pub turn_id: TurnId,
692 pub review_id: PlanReviewId,
693 pub status: PlanReviewStatus,
694 #[serde(default, skip_serializing_if = "Option::is_none")]
695 pub detail: Option<String>,
696 #[serde(with = "time::serde::rfc3339")]
697 pub timestamp: OffsetDateTime,
698}
699
700#[derive(Debug, Clone, Serialize, Deserialize)]
701#[serde(rename_all = "camelCase")]
702pub struct PlanReviewCommentAdded {
703 pub thread_id: ThreadId,
704 pub turn_id: TurnId,
705 pub review_id: PlanReviewId,
706 pub comment: PlanComment,
707 #[serde(with = "time::serde::rfc3339")]
708 pub timestamp: OffsetDateTime,
709}
710
711#[derive(Debug, Clone, Serialize, Deserialize)]
712#[serde(rename_all = "camelCase")]
713pub struct PlanReviewRewritten {
714 pub thread_id: ThreadId,
715 pub turn_id: TurnId,
716 pub review_id: PlanReviewId,
717 pub rewrite: PlanRewrite,
718 #[serde(with = "time::serde::rfc3339")]
719 pub timestamp: OffsetDateTime,
720}
721
722#[derive(Debug, Clone, Serialize, Deserialize)]
723#[serde(rename_all = "camelCase")]
724pub struct PlanReviewApproved {
725 pub thread_id: ThreadId,
726 pub turn_id: TurnId,
727 pub review_id: PlanReviewId,
728 #[serde(with = "time::serde::rfc3339")]
729 pub timestamp: OffsetDateTime,
730}
731
732#[derive(Debug, Clone, Serialize, Deserialize)]
733#[serde(rename_all = "camelCase")]
734pub struct PlanReviewRejected {
735 pub thread_id: ThreadId,
736 pub turn_id: TurnId,
737 pub review_id: PlanReviewId,
738 #[serde(default, skip_serializing_if = "Option::is_none")]
739 pub reason: Option<String>,
740 #[serde(with = "time::serde::rfc3339")]
741 pub timestamp: OffsetDateTime,
742}
743
744#[derive(Debug, Clone, Serialize, Deserialize)]
745#[serde(rename_all = "camelCase")]
746pub struct HunkRecorded {
747 pub hunk: HunkRecord,
748 #[serde(with = "time::serde::rfc3339")]
749 pub timestamp: OffsetDateTime,
750}
751
752#[derive(Debug, Clone, Serialize, Deserialize)]
753#[serde(rename_all = "camelCase")]
754pub struct WorkspaceChangeObserved {
755 pub change: WorkspaceChangeObservation,
756 #[serde(with = "time::serde::rfc3339")]
757 pub timestamp: OffsetDateTime,
758}
759
760#[derive(Debug, Clone, Serialize, Deserialize)]
761#[serde(rename_all = "camelCase")]
762pub struct HunkRollbackRequested {
763 pub thread_id: ThreadId,
764 pub turn_id: TurnId,
765 pub hunk_id: HunkId,
766 #[serde(with = "time::serde::rfc3339")]
767 pub timestamp: OffsetDateTime,
768}
769
770#[derive(Debug, Clone, Serialize, Deserialize)]
771#[serde(rename_all = "camelCase")]
772pub struct HunkRollbackCompleted {
773 pub thread_id: ThreadId,
774 pub turn_id: TurnId,
775 pub hunk_id: HunkId,
776 #[serde(default, skip_serializing_if = "Option::is_none")]
777 pub error: Option<String>,
778 #[serde(with = "time::serde::rfc3339")]
779 pub timestamp: OffsetDateTime,
780}
781
782#[derive(Debug, Clone, Serialize, Deserialize)]
783#[serde(rename_all = "camelCase")]
784pub struct WorkflowImportsDetected {
785 pub workspace: String,
786 pub items: Vec<WorkflowImportItem>,
787 #[serde(default, skip_serializing_if = "Vec::is_empty")]
788 pub errors: Vec<WorkflowImportError>,
789 #[serde(with = "time::serde::rfc3339")]
790 pub timestamp: OffsetDateTime,
791}
792
793#[derive(Debug, Clone, Serialize, Deserialize)]
794#[serde(rename_all = "camelCase")]
795pub struct WorkflowImportPreviewed {
796 pub item: WorkflowImportItem,
797 #[serde(with = "time::serde::rfc3339")]
798 pub timestamp: OffsetDateTime,
799}
800
801#[derive(Debug, Clone, Serialize, Deserialize)]
802#[serde(rename_all = "camelCase")]
803pub struct WorkflowImportEnabled {
804 pub item: WorkflowImportItem,
805 pub decision: WorkflowImportDecision,
806 #[serde(with = "time::serde::rfc3339")]
807 pub timestamp: OffsetDateTime,
808}
809
810#[derive(Debug, Clone, Serialize, Deserialize)]
811#[serde(rename_all = "camelCase")]
812pub struct WorkflowImportDisabled {
813 pub item_id: String,
814 pub decision: WorkflowImportDecision,
815 #[serde(with = "time::serde::rfc3339")]
816 pub timestamp: OffsetDateTime,
817}
818
819#[derive(Debug, Clone, Serialize, Deserialize)]
820#[serde(rename_all = "camelCase")]
821pub struct WorkflowImportStale {
822 pub item: WorkflowImportItem,
823 pub previous_hash: String,
824 #[serde(with = "time::serde::rfc3339")]
825 pub timestamp: OffsetDateTime,
826}
827
828#[derive(Debug, Clone, Serialize, Deserialize)]
829#[serde(rename_all = "camelCase")]
830pub struct WorkflowImportFailed {
831 pub item_id: Option<String>,
832 pub error: WorkflowImportError,
833 #[serde(with = "time::serde::rfc3339")]
834 pub timestamp: OffsetDateTime,
835}
836
837#[derive(Debug, Clone, Serialize, Deserialize)]
838#[serde(rename_all = "camelCase")]
839pub struct MediaArtifactCreated {
840 pub thread_id: ThreadId,
841 pub turn_id: TurnId,
842 pub artifact: MediaArtifact,
843 #[serde(with = "time::serde::rfc3339")]
844 pub timestamp: OffsetDateTime,
845}
846
847#[derive(Debug, Clone, Serialize, Deserialize)]
848#[serde(rename_all = "camelCase")]
849pub struct MediaArtifactUpdated {
850 pub thread_id: ThreadId,
851 pub turn_id: TurnId,
852 pub artifact: MediaArtifact,
853 #[serde(with = "time::serde::rfc3339")]
854 pub timestamp: OffsetDateTime,
855}
856
857#[derive(Debug, Clone, Serialize, Deserialize)]
858#[serde(rename_all = "camelCase")]
859pub struct MediaArtifactDeleted {
860 pub artifact_id: MediaArtifactId,
861 #[serde(with = "time::serde::rfc3339")]
862 pub timestamp: OffsetDateTime,
863}
864
865#[derive(Debug, Clone, Serialize, Deserialize)]
866#[serde(rename_all = "camelCase")]
867pub struct MediaPreviewReady {
868 pub thread_id: ThreadId,
869 pub turn_id: TurnId,
870 pub preview: MediaPreview,
871 #[serde(with = "time::serde::rfc3339")]
872 pub timestamp: OffsetDateTime,
873}
874
875#[derive(Debug, Clone, Serialize, Deserialize)]
876#[serde(rename_all = "camelCase")]
877pub struct ContextArtifactCreated {
878 pub thread_id: ThreadId,
879 pub turn_id: TurnId,
880 pub artifact: ContextArtifact,
881 #[serde(with = "time::serde::rfc3339")]
882 pub timestamp: OffsetDateTime,
883}
884
885#[derive(Debug, Clone, Serialize, Deserialize)]
886#[serde(rename_all = "camelCase")]
887pub struct ContextArtifactAppended {
888 pub thread_id: ThreadId,
889 pub turn_id: TurnId,
890 pub artifact_id: ContextArtifactId,
891 pub appended_bytes: u64,
892 pub byte_count: u64,
893 pub line_count: u64,
894 #[serde(with = "time::serde::rfc3339")]
895 pub timestamp: OffsetDateTime,
896}
897
898#[derive(Debug, Clone, Serialize, Deserialize)]
899#[serde(rename_all = "camelCase")]
900pub struct ContextArtifactCapped {
901 pub thread_id: ThreadId,
902 pub turn_id: TurnId,
903 pub artifact_id: ContextArtifactId,
904 pub inline_byte_count: u64,
905 pub original_byte_count: u64,
906 #[serde(with = "time::serde::rfc3339")]
907 pub timestamp: OffsetDateTime,
908}
909
910#[derive(Debug, Clone, Serialize, Deserialize)]
911#[serde(rename_all = "camelCase")]
912pub struct ContextArtifactDeleted {
913 pub thread_id: ThreadId,
914 pub artifact_id: ContextArtifactId,
915 #[serde(with = "time::serde::rfc3339")]
916 pub timestamp: OffsetDateTime,
917}
918
919#[derive(Debug, Clone, Serialize, Deserialize)]
920#[serde(rename_all = "camelCase")]
921pub struct ContextArtifactRetentionExpired {
922 pub thread_id: ThreadId,
923 pub artifact_id: ContextArtifactId,
924 #[serde(with = "time::serde::rfc3339")]
925 pub timestamp: OffsetDateTime,
926}
927
928#[derive(Debug, Clone, Serialize, Deserialize)]
929pub struct FileChanged {
930 pub thread_id: ThreadId,
931 pub turn_id: TurnId,
932 pub path: String,
933 pub change_type: String,
934 #[serde(with = "time::serde::rfc3339")]
935 pub timestamp: OffsetDateTime,
936}
937
938#[derive(Debug, Clone, Serialize, Deserialize)]
939pub struct FileChangePreviewReady {
940 pub thread_id: ThreadId,
941 pub turn_id: TurnId,
942 pub tool_id: String,
943 pub tool_name: String,
944 pub path: String,
945 pub change_type: String,
946 pub before: Option<String>,
947 pub after: String,
948 pub supports_partial: bool,
949 #[serde(with = "time::serde::rfc3339")]
950 pub timestamp: OffsetDateTime,
951}
952
953#[derive(Debug, Clone, Serialize, Deserialize)]
954pub struct TranscriptItemAppended {
955 pub thread_id: ThreadId,
956 pub turn_id: TurnId,
957 pub item_type: String,
958 #[serde(default, skip_serializing_if = "Option::is_none")]
959 pub item_index: Option<usize>,
960 #[serde(default, skip_serializing_if = "Option::is_none")]
963 pub item: Option<TranscriptItem>,
964 #[serde(with = "time::serde::rfc3339")]
965 pub timestamp: OffsetDateTime,
966}
967
968#[derive(Debug, Clone, Serialize, Deserialize)]
969pub struct TurnCompleted {
970 pub thread_id: ThreadId,
971 pub turn_id: TurnId,
972 #[serde(default, skip_serializing_if = "Option::is_none")]
973 pub usage: Option<TokenUsage>,
974 #[serde(default, skip_serializing_if = "Option::is_none")]
979 pub finish_reason: Option<String>,
980 #[serde(with = "time::serde::rfc3339")]
981 pub timestamp: OffsetDateTime,
982}
983
984#[derive(Debug, Clone, Serialize, Deserialize)]
985pub struct TurnFailed {
986 pub thread_id: ThreadId,
987 pub turn_id: TurnId,
988 pub error: String,
989 #[serde(default, skip_serializing_if = "Option::is_none")]
990 pub error_kind: Option<String>,
991 #[serde(default, skip_serializing_if = "Option::is_none")]
992 pub usage: Option<TokenUsage>,
993 #[serde(with = "time::serde::rfc3339")]
994 pub timestamp: OffsetDateTime,
995}
996
997#[derive(Debug, Clone, Serialize, Deserialize)]
998pub struct TurnPartialResult {
999 pub thread_id: ThreadId,
1000 pub turn_id: TurnId,
1001 pub summary: String,
1002 #[serde(with = "time::serde::rfc3339")]
1003 pub timestamp: OffsetDateTime,
1004}
1005
1006#[derive(Debug, Clone, Serialize, Deserialize)]
1007pub struct TurnDeadlineExceeded {
1008 pub thread_id: ThreadId,
1009 pub turn_id: TurnId,
1010 #[serde(with = "time::serde::rfc3339")]
1011 pub deadline: OffsetDateTime,
1012 pub partial_result: String,
1013 #[serde(with = "time::serde::rfc3339")]
1014 pub timestamp: OffsetDateTime,
1015}
1016
1017#[derive(Debug, Clone, Serialize, Deserialize)]
1018pub struct TurnInterrupted {
1019 pub thread_id: ThreadId,
1020 pub turn_id: TurnId,
1021 #[serde(with = "time::serde::rfc3339")]
1022 pub timestamp: OffsetDateTime,
1023}
1024
1025#[derive(Debug, Clone, Serialize, Deserialize)]
1026pub struct TurnSteered {
1027 pub thread_id: ThreadId,
1028 pub turn_id: TurnId,
1029 pub message: String,
1030 #[serde(with = "time::serde::rfc3339")]
1031 pub timestamp: OffsetDateTime,
1032}
1033
1034#[derive(Debug, Clone, Serialize, Deserialize)]
1035pub struct RunnerLifecycle {
1036 pub destination_id: String,
1037 pub provider_id: String,
1038 pub state: String,
1039 #[serde(default, skip_serializing_if = "Option::is_none")]
1040 pub session_id: Option<String>,
1041 #[serde(with = "time::serde::rfc3339")]
1042 pub timestamp: OffsetDateTime,
1043}
1044
1045#[derive(Debug, Clone, Serialize, Deserialize)]
1046pub struct TeamStarted {
1047 pub team_id: TeamId,
1048 pub lead_thread_id: ThreadId,
1049 pub display_mode: AgentTeamDisplayMode,
1050 pub members: Vec<TeamMemberDescriptor>,
1051 pub tasks: Vec<TeamTaskDescriptor>,
1052 #[serde(with = "time::serde::rfc3339")]
1053 pub timestamp: OffsetDateTime,
1054}
1055
1056#[derive(Debug, Clone, Serialize, Deserialize)]
1057pub struct TeamMemberStarted {
1058 pub team_id: TeamId,
1059 pub member: TeamMemberDescriptor,
1060 #[serde(with = "time::serde::rfc3339")]
1061 pub timestamp: OffsetDateTime,
1062}
1063
1064#[derive(Debug, Clone, Serialize, Deserialize)]
1065pub struct TeamMemberStatusChanged {
1066 pub team_id: TeamId,
1067 pub member_id: TeamMemberId,
1068 pub member_thread_id: ThreadId,
1069 pub status: TeamMemberStatus,
1070 #[serde(with = "time::serde::rfc3339")]
1071 pub timestamp: OffsetDateTime,
1072}
1073
1074#[derive(Debug, Clone, Serialize, Deserialize)]
1075pub struct TeamMemberMessageDelta {
1076 pub team_id: TeamId,
1077 pub member_id: TeamMemberId,
1078 pub member_thread_id: ThreadId,
1079 pub turn_id: TurnId,
1080 pub delta: String,
1081 #[serde(with = "time::serde::rfc3339")]
1082 pub timestamp: OffsetDateTime,
1083}
1084
1085#[derive(Debug, Clone, Serialize, Deserialize)]
1086pub struct TeamMemberCompleted {
1087 pub team_id: TeamId,
1088 pub member_id: TeamMemberId,
1089 pub member_thread_id: ThreadId,
1090 pub turn_id: Option<TurnId>,
1091 pub status: TeamMemberStatus,
1092 #[serde(default, skip_serializing_if = "Option::is_none")]
1093 pub final_message: Option<String>,
1094 #[serde(default, skip_serializing_if = "Option::is_none")]
1095 pub error: Option<String>,
1096 #[serde(with = "time::serde::rfc3339")]
1097 pub timestamp: OffsetDateTime,
1098}
1099
1100#[derive(Debug, Clone, Serialize, Deserialize)]
1101pub struct TeamDisplayModeChanged {
1102 pub team_id: TeamId,
1103 pub display_mode: AgentTeamDisplayMode,
1104 #[serde(with = "time::serde::rfc3339")]
1105 pub timestamp: OffsetDateTime,
1106}
1107
1108#[derive(Debug, Clone, Serialize, Deserialize)]
1109pub struct TeamTaskChanged {
1110 pub team_id: TeamId,
1111 pub task: TeamTaskDescriptor,
1112 #[serde(with = "time::serde::rfc3339")]
1113 pub timestamp: OffsetDateTime,
1114}
1115
1116#[derive(Debug, Clone, Serialize, Deserialize)]
1117pub struct TeamCleanupCompleted {
1118 pub team_id: TeamId,
1119 pub forced: bool,
1120 #[serde(with = "time::serde::rfc3339")]
1121 pub timestamp: OffsetDateTime,
1122}
1123
1124#[derive(Debug, Clone, Serialize, Deserialize)]
1125pub struct MemorySaved {
1126 pub memory: MemoryRecord,
1127 #[serde(with = "time::serde::rfc3339")]
1128 pub timestamp: OffsetDateTime,
1129}
1130
1131#[derive(Debug, Clone, Serialize, Deserialize)]
1132pub struct MemoryUpdated {
1133 pub memory: MemoryRecord,
1134 #[serde(with = "time::serde::rfc3339")]
1135 pub timestamp: OffsetDateTime,
1136}
1137
1138#[derive(Debug, Clone, Serialize, Deserialize)]
1139pub struct MemoryDeleted {
1140 pub memory_id: MemoryId,
1141 #[serde(with = "time::serde::rfc3339")]
1142 pub timestamp: OffsetDateTime,
1143}
1144
1145#[derive(Debug, Clone, Serialize, Deserialize)]
1146pub struct MemoryQueried {
1147 pub scope: Option<MemoryScope>,
1148 pub query: String,
1149 pub result_count: usize,
1150 #[serde(with = "time::serde::rfc3339")]
1151 pub timestamp: OffsetDateTime,
1152}
1153
1154#[derive(Debug, Clone, Serialize, Deserialize)]
1155pub struct MemoryRecallReady {
1156 pub thread_id: ThreadId,
1157 pub turn_id: TurnId,
1158 pub citations: Vec<MemoryCitation>,
1159 #[serde(with = "time::serde::rfc3339")]
1160 pub timestamp: OffsetDateTime,
1161}
1162
1163#[derive(Debug, Clone, Serialize, Deserialize)]
1164pub struct MemoryReembedQueued {
1165 pub scope: Option<MemoryScope>,
1166 pub provider: MemoryProviderSelection,
1167 #[serde(with = "time::serde::rfc3339")]
1168 pub timestamp: OffsetDateTime,
1169}
1170
1171#[derive(Debug, Clone, Serialize, Deserialize)]
1172pub struct MemoryProviderChanged {
1173 pub provider: MemoryProviderSelection,
1174 #[serde(with = "time::serde::rfc3339")]
1175 pub timestamp: OffsetDateTime,
1176}
1177
1178#[derive(Debug, Clone, Serialize, Deserialize)]
1179pub struct MemoryObservationRecorded {
1180 pub thread_id: ThreadId,
1181 pub turn_id: TurnId,
1182 pub memory_id: MemoryId,
1183 #[serde(with = "time::serde::rfc3339")]
1184 pub timestamp: OffsetDateTime,
1185}
1186
1187#[derive(Debug, Clone, Serialize, Deserialize)]
1188pub struct KnowledgeSaved {
1189 pub document: KnowledgeDocSummary,
1190 #[serde(with = "time::serde::rfc3339")]
1191 pub timestamp: OffsetDateTime,
1192}
1193
1194#[derive(Debug, Clone, Serialize, Deserialize)]
1195pub struct KnowledgeUpdated {
1196 pub document: KnowledgeDocSummary,
1197 #[serde(with = "time::serde::rfc3339")]
1198 pub timestamp: OffsetDateTime,
1199}
1200
1201#[derive(Debug, Clone, Serialize, Deserialize)]
1202pub struct KnowledgeArchived {
1203 pub doc_id: KnowledgeDocId,
1204 #[serde(with = "time::serde::rfc3339")]
1205 pub timestamp: OffsetDateTime,
1206}
1207
1208#[derive(Debug, Clone, Serialize, Deserialize)]
1209pub struct KnowledgeLinked {
1210 pub from: KnowledgeDocId,
1211 pub to: KnowledgeDocId,
1212 pub link_type: KnowledgeLinkType,
1213 pub removed: bool,
1214 #[serde(with = "time::serde::rfc3339")]
1215 pub timestamp: OffsetDateTime,
1216}
1217
1218#[derive(Debug, Clone, Serialize, Deserialize)]
1219pub struct RemoteServerStarted {
1220 pub listen_addr: String,
1221 pub connect_urls: Vec<String>,
1222 pub token_preview: String,
1223 #[serde(with = "time::serde::rfc3339")]
1224 pub timestamp: OffsetDateTime,
1225}
1226
1227#[derive(Debug, Clone, Serialize, Deserialize)]
1228pub struct RemoteServerStopped {
1229 pub listen_addr: String,
1230 #[serde(with = "time::serde::rfc3339")]
1231 pub timestamp: OffsetDateTime,
1232}
1233
1234#[derive(Debug, Clone, Serialize, Deserialize)]
1235pub struct RemoteAuthFailed {
1236 pub remote_addr: Option<String>,
1237 #[serde(with = "time::serde::rfc3339")]
1238 pub timestamp: OffsetDateTime,
1239}
1240
1241#[derive(Debug, Clone, Serialize, Deserialize)]
1242pub struct RemoteClientConnected {
1243 pub remote_addr: Option<String>,
1244 #[serde(with = "time::serde::rfc3339")]
1245 pub timestamp: OffsetDateTime,
1246}
1247
1248#[derive(Debug, Clone, Serialize, Deserialize)]
1249pub struct RemoteClientDisconnected {
1250 pub remote_addr: Option<String>,
1251 #[serde(with = "time::serde::rfc3339")]
1252 pub timestamp: OffsetDateTime,
1253}
1254
1255#[derive(Debug, Clone, Serialize, Deserialize)]
1256pub struct RoadmapChanged {
1257 pub event_kind: String,
1258 pub path: String,
1259 pub task_id: Option<String>,
1260 pub thread_id: Option<String>,
1261 #[serde(with = "time::serde::rfc3339")]
1262 pub timestamp: OffsetDateTime,
1263}
1264
1265#[derive(Debug, Clone, Serialize, Deserialize)]
1269#[serde(rename_all = "camelCase")]
1270pub struct ReviewStarted {
1271 pub thread_id: ThreadId,
1272 pub turn_id: TurnId,
1273 pub review_id: ReviewId,
1274 pub review_thread_id: ThreadId,
1275 pub target: ReviewTarget,
1276 pub label: String,
1277 #[serde(with = "time::serde::rfc3339")]
1278 pub timestamp: OffsetDateTime,
1279}
1280
1281#[derive(Debug, Clone, Serialize, Deserialize)]
1282#[serde(rename_all = "camelCase")]
1283pub struct ReviewCompleted {
1284 pub thread_id: ThreadId,
1285 pub turn_id: TurnId,
1286 pub review_id: ReviewId,
1287 pub review_thread_id: ThreadId,
1288 pub output: ReviewOutput,
1289 #[serde(with = "time::serde::rfc3339")]
1290 pub timestamp: OffsetDateTime,
1291}
1292
1293#[derive(Debug, Clone, Serialize, Deserialize)]
1294#[serde(rename_all = "camelCase")]
1295pub struct ReviewFailed {
1296 pub thread_id: ThreadId,
1297 #[serde(default, skip_serializing_if = "Option::is_none")]
1299 pub turn_id: Option<TurnId>,
1300 pub review_id: ReviewId,
1301 #[serde(default, skip_serializing_if = "Option::is_none")]
1302 pub review_thread_id: Option<ThreadId>,
1303 pub error: String,
1304 #[serde(with = "time::serde::rfc3339")]
1305 pub timestamp: OffsetDateTime,
1306}
1307
1308#[derive(Debug, Clone, Serialize, Deserialize)]
1309#[serde(rename_all = "camelCase")]
1310pub struct ReviewPublished {
1311 #[serde(default, skip_serializing_if = "Option::is_none")]
1312 pub thread_id: Option<ThreadId>,
1313 pub review_id: ReviewId,
1314 pub publisher_id: ReviewPublisherId,
1315 #[serde(default, skip_serializing_if = "Option::is_none")]
1316 pub url: Option<String>,
1317 pub published_findings: usize,
1318 #[serde(default)]
1319 pub skipped: Vec<ReviewPublishSkip>,
1320 pub dry_run: bool,
1321 #[serde(with = "time::serde::rfc3339")]
1322 pub timestamp: OffsetDateTime,
1323}
1324
1325#[derive(Debug, Clone, Serialize, Deserialize)]
1326pub enum RoderEvent {
1327 RuntimeStarted(RuntimeStarted),
1328 ExtensionRegistered(ExtensionRegistered),
1329 ExtensionEventEmitted(ExtensionEventEmitted),
1330 EventSinkFailed(EventSinkFailed),
1331 ThreadCreated(ThreadCreated),
1332 ThreadLoaded(ThreadLoaded),
1333 ThreadForkRequested(ThreadForkRequested),
1334 ThreadForked(ThreadForked),
1335 ThreadForkFailed(ThreadForkFailed),
1336 ThreadForkRemoved(ThreadForkRemoved),
1337 TurnStarted(TurnStarted),
1338 ContextAssemblyStarted(ContextAssemblyStarted),
1339 ContextBlockAdded(ContextBlockAdded),
1340 ContextAssemblyCompleted(ContextAssemblyCompleted),
1341 ContextEntrypointCandidatesInjected(ContextEntrypointCandidatesInjected),
1342 ContextCompactionStarted(ContextCompactionStarted),
1343 ContextCompactionRecorded(ContextCompactionRecorded),
1344 ContextCompactionSkipped(ContextCompactionSkipped),
1345 InferenceRoutingDecision(InferenceRoutingDecisionEvent),
1346 InferenceStarted(InferenceStarted),
1347 InferenceEventReceived(InferenceEventReceived),
1348 ToolCallRequested(ToolCallRequested),
1349 HookRunRecorded(HookRunRecorded),
1350 ToolCallValidationRecorded(ToolCallValidationRecorded),
1351 ReliabilityFailureRecorded(ReliabilityFailureRecorded),
1352 ReliabilityRetryRecorded(ReliabilityRetryRecorded),
1353 ReliabilityLimitRecorded(ReliabilityLimitRecorded),
1354 ReliabilityMetricRecorded(ReliabilityMetricRecorded),
1355 CodeIndexingStarted(CodeIndexingStarted),
1356 CodeIndexChunked(CodeIndexChunked),
1357 CodeIndexEmbedded(CodeIndexEmbedded),
1358 CodeIndexReady(CodeIndexReady),
1359 CodeIndexStale(CodeIndexStale),
1360 CodeIndexFailed(CodeIndexFailed),
1361 CodeIndexProofFilteredResultDropped(CodeIndexProofFilteredResultDropped),
1362 ApprovalRequested(ApprovalRequested),
1363 ApprovalResolved(ApprovalResolved),
1364 ExternalToolCallRequested(ExternalToolCallRequested),
1365 ExternalToolCallResolved(ExternalToolCallResolved),
1366 UserInputRequested(UserInputRequested),
1367 UserInputResolved(UserInputResolved),
1368 TaskLedgerUpdated(TaskLedgerUpdated),
1369 VerificationRequired(VerificationRequired),
1370 VerificationCompleted(VerificationCompleted),
1371 VerificationSkipped(VerificationSkipped),
1372 PolicyDecisionRecorded(PolicyDecisionRecorded),
1373 PolicyBypassActive(PolicyBypassActive),
1374 PolicyModeChanged(PolicyModeChanged),
1375 AgentSwarmModeChanged(AgentSwarmModeChanged),
1376 AgentSwarmStarted(AgentSwarmStarted),
1377 AgentSwarmProgress(AgentSwarmProgress),
1378 AgentSwarmCompleted(AgentSwarmCompleted),
1379 UltraModeChanged(UltraModeChanged),
1380 PolicyExitPlanRequested(PolicyExitPlanRequested),
1381 PolicyExitPlanResolved(PolicyExitPlanResolved),
1382 ToolCallStarted(ToolCallStarted),
1383 ToolCallCompleted(ToolCallCompleted),
1384 ToolOutputDelta(ToolOutputDelta),
1385 ToolOutputTruncated(ToolOutputTruncated),
1386 SubagentStarted(SubagentStarted),
1387 SubagentMessage(SubagentMessage),
1388 SubagentToolCall(SubagentToolCall),
1389 SubagentCompleted(SubagentCompleted),
1390 SubagentFailed(SubagentFailed),
1391 SubagentTraceCreated(SubagentTraceCreated),
1392 SubagentTraceDelta(SubagentTraceDeltaEvent),
1393 SubagentTraceStatusChanged(SubagentTraceStatusChanged),
1394 SubagentTraceCompleted(SubagentTraceCompleted),
1395 SubagentTraceFailed(SubagentTraceFailed),
1396 PlanReviewCreated(PlanReviewCreated),
1397 PlanReviewStatusChanged(PlanReviewStatusChanged),
1398 PlanReviewCommentAdded(PlanReviewCommentAdded),
1399 PlanReviewRewritten(PlanReviewRewritten),
1400 PlanReviewApproved(PlanReviewApproved),
1401 PlanReviewRejected(PlanReviewRejected),
1402 HunkRecorded(HunkRecorded),
1403 WorkspaceChangeObserved(WorkspaceChangeObserved),
1404 HunkRollbackRequested(HunkRollbackRequested),
1405 HunkRollbackCompleted(HunkRollbackCompleted),
1406 WorkflowImportsDetected(WorkflowImportsDetected),
1407 WorkflowImportPreviewed(WorkflowImportPreviewed),
1408 WorkflowImportEnabled(WorkflowImportEnabled),
1409 WorkflowImportDisabled(WorkflowImportDisabled),
1410 WorkflowImportStale(WorkflowImportStale),
1411 WorkflowImportFailed(WorkflowImportFailed),
1412 WorkflowRunDrafted(WorkflowRunDrafted),
1413 WorkflowApprovalRequested(WorkflowApprovalRequested),
1414 WorkflowRunApproved(WorkflowRunApproved),
1415 WorkflowRunDenied(WorkflowRunDenied),
1416 WorkflowRunQueued(WorkflowRunQueued),
1417 WorkflowRunStarted(WorkflowRunStarted),
1418 WorkflowPhaseStarted(WorkflowPhaseStarted),
1419 WorkflowPhaseCompleted(WorkflowPhaseCompleted),
1420 WorkflowAgentQueued(WorkflowAgentQueued),
1421 WorkflowAgentStarted(WorkflowAgentStarted),
1422 WorkflowAgentCompleted(WorkflowAgentCompleted),
1423 WorkflowAgentFailed(WorkflowAgentFailed),
1424 WorkflowOutputRecorded(WorkflowOutputRecorded),
1425 WorkflowCheckpointRecorded(WorkflowCheckpointRecorded),
1426 WorkflowRunPaused(WorkflowRunPaused),
1427 WorkflowRunResumed(WorkflowRunResumed),
1428 WorkflowRunStopped(WorkflowRunStopped),
1429 WorkflowRunCompleted(WorkflowRunCompleted),
1430 WorkflowRunFailed(WorkflowRunFailed),
1431 MediaArtifactCreated(MediaArtifactCreated),
1432 MediaArtifactUpdated(MediaArtifactUpdated),
1433 MediaArtifactDeleted(MediaArtifactDeleted),
1434 MediaPreviewReady(MediaPreviewReady),
1435 ContextArtifactCreated(ContextArtifactCreated),
1436 ContextArtifactAppended(ContextArtifactAppended),
1437 ContextArtifactCapped(ContextArtifactCapped),
1438 ContextArtifactDeleted(ContextArtifactDeleted),
1439 ContextArtifactRetentionExpired(ContextArtifactRetentionExpired),
1440 DiscoveryCatalogBuilt(DiscoveryCatalogBuilt),
1441 DiscoveryItemUpdated(DiscoveryItemUpdated),
1442 DiscoveryAuthRequired(DiscoveryAuthRequired),
1443 DiscoveryItemRead(DiscoveryItemRead),
1444 DiscoveryItemPromoted(DiscoveryItemPromoted),
1445 DiscoveryPromotionReused(DiscoveryPromotionReused),
1446 DiscoveryWarmCacheHit(DiscoveryWarmCacheHit),
1447 DiscoveryPromotionExpired(DiscoveryPromotionExpired),
1448 RetrievalRoutePlanned(RetrievalRoutePlanned),
1449 RetrievalRouteAccepted(RetrievalRouteAccepted),
1450 RetrievalRouteIgnored(RetrievalRouteIgnored),
1451 RetrievalRouteFailed(RetrievalRouteFailed),
1452 RetrievalResultUsed(RetrievalResultUsed),
1453 RetrievalDiscoveryItemPromoted(RetrievalDiscoveryItemPromoted),
1454 RetrievalPromotionSkipped(RetrievalPromotionSkipped),
1455 MemorySaved(MemorySaved),
1456 MemoryUpdated(MemoryUpdated),
1457 MemoryDeleted(MemoryDeleted),
1458 MemoryQueried(MemoryQueried),
1459 MemoryRecallReady(MemoryRecallReady),
1460 MemoryReembedQueued(MemoryReembedQueued),
1461 MemoryProviderChanged(MemoryProviderChanged),
1462 MemoryObservationRecorded(MemoryObservationRecorded),
1463 KnowledgeSaved(KnowledgeSaved),
1464 KnowledgeUpdated(KnowledgeUpdated),
1465 KnowledgeArchived(KnowledgeArchived),
1466 KnowledgeLinked(KnowledgeLinked),
1467 RemoteServerStarted(RemoteServerStarted),
1468 RemoteServerStopped(RemoteServerStopped),
1469 RemoteAuthFailed(RemoteAuthFailed),
1470 RemoteClientConnected(RemoteClientConnected),
1471 RemoteClientDisconnected(RemoteClientDisconnected),
1472 ThreadGoalUpdated(ThreadGoalUpdated),
1473 ThreadGoalCleared(ThreadGoalCleared),
1474 RoadmapChanged(RoadmapChanged),
1475 AutomationCreated(AutomationCreated),
1476 AutomationUpdated(AutomationUpdated),
1477 AutomationDeleted(AutomationDeleted),
1478 AutomationDue(AutomationDue),
1479 AutomationLeased(AutomationLeased),
1480 AutomationQueued(AutomationQueued),
1481 AutomationStarted(AutomationStarted),
1482 AutomationCompleted(AutomationCompleted),
1483 AutomationFailed(AutomationFailed),
1484 AutomationSkipped(AutomationSkipped),
1485 AutomationLeaseExpired(AutomationLeaseExpired),
1486 SkillsCatalogLoaded(SkillsCatalogLoaded),
1487 SkillConfigApplied(SkillConfigApplied),
1488 SkillActivationResolved(SkillActivationResolved),
1489 SkillIndexRendered(SkillIndexRendered),
1490 SkillInvoked(SkillInvoked),
1491 SkillAutoActivated(SkillAutoActivated),
1492 SkillSkipped(SkillSkipped),
1493 TaskStarted(TaskStarted),
1494 TaskOutput(TaskOutput),
1495 TaskCompleted(TaskCompleted),
1496 TaskFailed(TaskFailed),
1497 TaskCancelled(TaskCancelled),
1498 ProcessStarted(ProcessStarted),
1499 ProcessOutput(ProcessOutput),
1500 ProcessExited(ProcessExited),
1501 ProcessStopping(ProcessStopping),
1502 ProcessStopped(ProcessStopped),
1503 ProcessFailed(ProcessFailed),
1504 FileChangePreviewReady(FileChangePreviewReady),
1505 FileChanged(FileChanged),
1506 TranscriptItemAppended(TranscriptItemAppended),
1507 TurnCompleted(TurnCompleted),
1508 TurnFailed(TurnFailed),
1509 TurnPartialResult(TurnPartialResult),
1510 TurnDeadlineExceeded(TurnDeadlineExceeded),
1511 TurnLifecycleUpdated(TurnLifecycleRecord),
1512 TurnInterrupted(TurnInterrupted),
1513 TurnSteered(TurnSteered),
1514 RunnerLifecycle(RunnerLifecycle),
1515 TeamStarted(TeamStarted),
1516 TeamMemberStarted(TeamMemberStarted),
1517 TeamMemberStatusChanged(TeamMemberStatusChanged),
1518 TeamMemberMessageDelta(TeamMemberMessageDelta),
1519 TeamMemberCompleted(TeamMemberCompleted),
1520 TeamDisplayModeChanged(TeamDisplayModeChanged),
1521 TeamTaskChanged(TeamTaskChanged),
1522 TeamCleanupCompleted(TeamCleanupCompleted),
1523 ReviewStarted(ReviewStarted),
1524 ReviewCompleted(ReviewCompleted),
1525 ReviewFailed(ReviewFailed),
1526 ReviewPublished(ReviewPublished),
1527}
1528
1529impl RoderEvent {
1530 pub fn kind(&self) -> &'static str {
1531 match self {
1532 RoderEvent::RuntimeStarted(_) => "runtime.started",
1533 RoderEvent::ExtensionRegistered(_) => "extension.registered",
1534 RoderEvent::ExtensionEventEmitted(_) => "extension.event",
1535 RoderEvent::EventSinkFailed(_) => "extension.event_sink_failed",
1536 RoderEvent::ThreadCreated(_) => "thread.created",
1537 RoderEvent::ThreadLoaded(_) => "thread.loaded",
1538 RoderEvent::ThreadForkRequested(_) => "thread.fork_requested",
1539 RoderEvent::ThreadForked(_) => "thread.forked",
1540 RoderEvent::ThreadForkFailed(_) => "thread.fork_failed",
1541 RoderEvent::ThreadForkRemoved(_) => "thread.fork_removed",
1542 RoderEvent::TurnStarted(_) => "turn.started",
1543 RoderEvent::ContextAssemblyStarted(_) => "context.assembly_started",
1544 RoderEvent::ContextBlockAdded(_) => "context.block_added",
1545 RoderEvent::ContextAssemblyCompleted(_) => "context.assembly_completed",
1546 RoderEvent::ContextEntrypointCandidatesInjected(_) => {
1547 "context.entrypoint_candidates_injected"
1548 }
1549 RoderEvent::ContextCompactionStarted(_) => "context.compaction_started",
1550 RoderEvent::ContextCompactionRecorded(_) => "context.compaction_recorded",
1551 RoderEvent::ContextCompactionSkipped(_) => "context.compaction_skipped",
1552 RoderEvent::InferenceRoutingDecision(_) => "inference.routing_decision",
1553 RoderEvent::InferenceStarted(_) => "inference.started",
1554 RoderEvent::InferenceEventReceived(_) => "inference.event_received",
1555 RoderEvent::ToolCallRequested(_) => "tool.call_requested",
1556 RoderEvent::HookRunRecorded(_) => "hook.run_recorded",
1557 RoderEvent::ToolCallValidationRecorded(_) => "tool.call_validation",
1558 RoderEvent::ReliabilityFailureRecorded(_) => "reliability.failure",
1559 RoderEvent::ReliabilityRetryRecorded(_) => "reliability.retry",
1560 RoderEvent::ReliabilityLimitRecorded(_) => "reliability.limit",
1561 RoderEvent::ReliabilityMetricRecorded(_) => "reliability.metric",
1562 RoderEvent::CodeIndexingStarted(_) => "code_index.started",
1563 RoderEvent::CodeIndexChunked(_) => "code_index.chunked",
1564 RoderEvent::CodeIndexEmbedded(_) => "code_index.embedded",
1565 RoderEvent::CodeIndexReady(_) => "code_index.ready",
1566 RoderEvent::CodeIndexStale(_) => "code_index.stale",
1567 RoderEvent::CodeIndexFailed(_) => "code_index.failed",
1568 RoderEvent::CodeIndexProofFilteredResultDropped(_) => {
1569 "code_index.proof_filtered_result_dropped"
1570 }
1571 RoderEvent::ApprovalRequested(_) => "approval.requested",
1572 RoderEvent::ApprovalResolved(_) => "approval.resolved",
1573 RoderEvent::ExternalToolCallRequested(_) => "external_tool.requested",
1574 RoderEvent::ExternalToolCallResolved(_) => "external_tool.resolved",
1575 RoderEvent::UserInputRequested(_) => "user_input.requested",
1576 RoderEvent::UserInputResolved(_) => "user_input.resolved",
1577 RoderEvent::TaskLedgerUpdated(_) => "task_ledger.updated",
1578 RoderEvent::VerificationRequired(_) => "verification.required",
1579 RoderEvent::VerificationCompleted(_) => "verification.completed",
1580 RoderEvent::VerificationSkipped(_) => "verification.skipped",
1581 RoderEvent::PolicyDecisionRecorded(_) => "policy.decision",
1582 RoderEvent::PolicyBypassActive(_) => "policy.bypass_active",
1583 RoderEvent::PolicyModeChanged(_) => "policy.mode_changed",
1584 RoderEvent::AgentSwarmModeChanged(_) => "agent_swarm.mode_changed",
1585 RoderEvent::AgentSwarmStarted(_) => "agent_swarm.started",
1586 RoderEvent::AgentSwarmProgress(_) => "agent_swarm.progress",
1587 RoderEvent::AgentSwarmCompleted(_) => "agent_swarm.completed",
1588 RoderEvent::UltraModeChanged(_) => "ultra.mode_changed",
1589 RoderEvent::PolicyExitPlanRequested(_) => "policy.exit_plan_requested",
1590 RoderEvent::PolicyExitPlanResolved(_) => "policy.exit_plan_resolved",
1591 RoderEvent::ToolCallStarted(_) => "tool.call_started",
1592 RoderEvent::ToolCallCompleted(_) => "tool.call_completed",
1593 RoderEvent::ToolOutputDelta(_) => "tool.output_delta",
1594 RoderEvent::ToolOutputTruncated(_) => "tool.output_truncated",
1595 RoderEvent::SubagentStarted(_) => "subagent.started",
1596 RoderEvent::SubagentMessage(_) => "subagent.message",
1597 RoderEvent::SubagentToolCall(_) => "subagent.tool_call",
1598 RoderEvent::SubagentCompleted(_) => "subagent.completed",
1599 RoderEvent::SubagentFailed(_) => "subagent.failed",
1600 RoderEvent::SubagentTraceCreated(_) => "turn/subagentTraceCreated",
1601 RoderEvent::SubagentTraceDelta(_) => "turn/subagentTraceDelta",
1602 RoderEvent::SubagentTraceStatusChanged(_) => "turn/subagentTraceStatusChanged",
1603 RoderEvent::SubagentTraceCompleted(_) => "turn/subagentTraceCompleted",
1604 RoderEvent::SubagentTraceFailed(_) => "turn/subagentTraceFailed",
1605 RoderEvent::PlanReviewCreated(_) => "plan/reviewCreated",
1606 RoderEvent::PlanReviewStatusChanged(_) => "plan/reviewStatusChanged",
1607 RoderEvent::PlanReviewCommentAdded(_) => "plan/reviewCommentAdded",
1608 RoderEvent::PlanReviewRewritten(_) => "plan/reviewRewritten",
1609 RoderEvent::PlanReviewApproved(_) => "plan/reviewApproved",
1610 RoderEvent::PlanReviewRejected(_) => "plan/reviewRejected",
1611 RoderEvent::HunkRecorded(_) => "hunk/recorded",
1612 RoderEvent::WorkspaceChangeObserved(_) => "workspace/changeObserved",
1613 RoderEvent::HunkRollbackRequested(_) => "hunk/rollbackRequested",
1614 RoderEvent::HunkRollbackCompleted(_) => "hunk/rollbackCompleted",
1615 RoderEvent::WorkflowImportsDetected(_) => "workflow/importsDetected",
1616 RoderEvent::WorkflowImportPreviewed(_) => "workflow/importPreviewed",
1617 RoderEvent::WorkflowImportEnabled(_) => "workflow/importEnabled",
1618 RoderEvent::WorkflowImportDisabled(_) => "workflow/importDisabled",
1619 RoderEvent::WorkflowImportStale(_) => "workflow/importStale",
1620 RoderEvent::WorkflowImportFailed(_) => "workflow/importFailed",
1621 RoderEvent::WorkflowRunDrafted(_) => "workflows/drafted",
1622 RoderEvent::WorkflowApprovalRequested(_) => "workflows/approvalRequested",
1623 RoderEvent::WorkflowRunApproved(_) => "workflows/approved",
1624 RoderEvent::WorkflowRunDenied(_) => "workflows/denied",
1625 RoderEvent::WorkflowRunQueued(_) => "workflows/queued",
1626 RoderEvent::WorkflowRunStarted(_) => "workflows/started",
1627 RoderEvent::WorkflowPhaseStarted(_) => "workflows/phaseStarted",
1628 RoderEvent::WorkflowPhaseCompleted(_) => "workflows/phaseCompleted",
1629 RoderEvent::WorkflowAgentQueued(_) => "workflows/agentQueued",
1630 RoderEvent::WorkflowAgentStarted(_) => "workflows/agentStarted",
1631 RoderEvent::WorkflowAgentCompleted(_) => "workflows/agentCompleted",
1632 RoderEvent::WorkflowAgentFailed(_) => "workflows/agentFailed",
1633 RoderEvent::WorkflowOutputRecorded(_) => "workflows/outputRecorded",
1634 RoderEvent::WorkflowCheckpointRecorded(_) => "workflows/checkpointRecorded",
1635 RoderEvent::WorkflowRunPaused(_) => "workflows/paused",
1636 RoderEvent::WorkflowRunResumed(_) => "workflows/resumed",
1637 RoderEvent::WorkflowRunStopped(_) => "workflows/stopped",
1638 RoderEvent::WorkflowRunCompleted(_) => "workflows/completed",
1639 RoderEvent::WorkflowRunFailed(_) => "workflows/failed",
1640 RoderEvent::MediaArtifactCreated(_) => "media/artifactCreated",
1641 RoderEvent::MediaArtifactUpdated(_) => "media/artifactUpdated",
1642 RoderEvent::MediaArtifactDeleted(_) => "media/artifactDeleted",
1643 RoderEvent::MediaPreviewReady(_) => "media/previewReady",
1644 RoderEvent::ContextArtifactCreated(_) => "artifact/created",
1645 RoderEvent::ContextArtifactAppended(_) => "artifact/appended",
1646 RoderEvent::ContextArtifactCapped(_) => "artifact/capped",
1647 RoderEvent::ContextArtifactDeleted(_) => "artifact/deleted",
1648 RoderEvent::ContextArtifactRetentionExpired(_) => "artifact/retentionExpired",
1649 RoderEvent::DiscoveryCatalogBuilt(_) => "discovery/catalogBuilt",
1650 RoderEvent::DiscoveryItemUpdated(_) => "discovery/itemUpdated",
1651 RoderEvent::DiscoveryAuthRequired(_) => "discovery/authRequired",
1652 RoderEvent::DiscoveryItemRead(_) => "discovery/itemRead",
1653 RoderEvent::DiscoveryItemPromoted(_) => "discovery/itemPromoted",
1654 RoderEvent::DiscoveryPromotionReused(_) => "discovery/promotionReused",
1655 RoderEvent::DiscoveryWarmCacheHit(_) => "discovery/warmCacheHit",
1656 RoderEvent::DiscoveryPromotionExpired(_) => "discovery/promotionExpired",
1657 RoderEvent::RetrievalRoutePlanned(_) => "retrieval/routePlanned",
1658 RoderEvent::RetrievalRouteAccepted(_) => "retrieval/routeAccepted",
1659 RoderEvent::RetrievalRouteIgnored(_) => "retrieval/routeIgnored",
1660 RoderEvent::RetrievalRouteFailed(_) => "retrieval/routeFailed",
1661 RoderEvent::RetrievalResultUsed(_) => "retrieval/resultUsed",
1662 RoderEvent::RetrievalDiscoveryItemPromoted(_) => "retrieval/discoveryItemPromoted",
1663 RoderEvent::RetrievalPromotionSkipped(_) => "retrieval/promotionSkipped",
1664 RoderEvent::MemorySaved(_) => "memory/saved",
1665 RoderEvent::MemoryUpdated(_) => "memory/updated",
1666 RoderEvent::MemoryDeleted(_) => "memory/deleted",
1667 RoderEvent::MemoryQueried(_) => "memory/queried",
1668 RoderEvent::MemoryRecallReady(_) => "memory/recallReady",
1669 RoderEvent::MemoryReembedQueued(_) => "memory/reembedQueued",
1670 RoderEvent::MemoryProviderChanged(_) => "memory/providerChanged",
1671 RoderEvent::MemoryObservationRecorded(_) => "memory/observationRecorded",
1672 RoderEvent::KnowledgeSaved(_) => "knowledge/saved",
1673 RoderEvent::KnowledgeUpdated(_) => "knowledge/updated",
1674 RoderEvent::KnowledgeArchived(_) => "knowledge/archived",
1675 RoderEvent::KnowledgeLinked(_) => "knowledge/linked",
1676 RoderEvent::RemoteServerStarted(_) => "remote/serverStarted",
1677 RoderEvent::RemoteServerStopped(_) => "remote/serverStopped",
1678 RoderEvent::RemoteAuthFailed(_) => "remote/authFailed",
1679 RoderEvent::RemoteClientConnected(_) => "remote/clientConnected",
1680 RoderEvent::RemoteClientDisconnected(_) => "remote/clientDisconnected",
1681 RoderEvent::ThreadGoalUpdated(_) => "thread/goal/updated",
1682 RoderEvent::ThreadGoalCleared(_) => "thread/goal/cleared",
1683 RoderEvent::RoadmapChanged(_) => "roadmap.changed",
1684 RoderEvent::AutomationCreated(_) => "automations/created",
1685 RoderEvent::AutomationUpdated(_) => "automations/updated",
1686 RoderEvent::AutomationDeleted(_) => "automations/deleted",
1687 RoderEvent::AutomationDue(_) => "automations/due",
1688 RoderEvent::AutomationLeased(_) => "automations/leased",
1689 RoderEvent::AutomationQueued(_) => "automations/queued",
1690 RoderEvent::AutomationStarted(_) => "automations/started",
1691 RoderEvent::AutomationCompleted(_) => "automations/completed",
1692 RoderEvent::AutomationFailed(_) => "automations/failed",
1693 RoderEvent::AutomationSkipped(_) => "automations/skipped",
1694 RoderEvent::AutomationLeaseExpired(_) => "automations/leaseExpired",
1695 RoderEvent::SkillsCatalogLoaded(_) => "skills/catalogLoaded",
1696 RoderEvent::SkillConfigApplied(_) => "skills/configApplied",
1697 RoderEvent::SkillActivationResolved(_) => "skills/activationResolved",
1698 RoderEvent::SkillIndexRendered(_) => "skills/indexRendered",
1699 RoderEvent::SkillInvoked(_) => "skills/invoked",
1700 RoderEvent::SkillAutoActivated(_) => "skills/autoActivated",
1701 RoderEvent::SkillSkipped(_) => "skills/skipped",
1702 RoderEvent::TaskStarted(_) => "task.started",
1703 RoderEvent::TaskOutput(_) => "task.output",
1704 RoderEvent::TaskCompleted(_) => "task.completed",
1705 RoderEvent::TaskFailed(_) => "task.failed",
1706 RoderEvent::TaskCancelled(_) => "task.cancelled",
1707 RoderEvent::ProcessStarted(_) => "process.started",
1708 RoderEvent::ProcessOutput(_) => "process.output",
1709 RoderEvent::ProcessExited(_) => "process.exited",
1710 RoderEvent::ProcessStopping(_) => "process.stopping",
1711 RoderEvent::ProcessStopped(_) => "process.stopped",
1712 RoderEvent::ProcessFailed(_) => "process.failed",
1713 RoderEvent::FileChangePreviewReady(_) => "file.change_preview_ready",
1714 RoderEvent::FileChanged(_) => "file.changed",
1715 RoderEvent::TranscriptItemAppended(_) => "turn.transcript_item_appended",
1716 RoderEvent::TurnCompleted(_) => "turn.completed",
1717 RoderEvent::TurnFailed(_) => "turn.failed",
1718 RoderEvent::TurnPartialResult(_) => "turn.partial_result",
1719 RoderEvent::TurnDeadlineExceeded(_) => "turn.deadline_exceeded",
1720 RoderEvent::TurnLifecycleUpdated(_) => "turn.lifecycle_updated",
1721 RoderEvent::TurnInterrupted(_) => "turn.interrupted",
1722 RoderEvent::TurnSteered(_) => "turn.steered",
1723 RoderEvent::RunnerLifecycle(_) => "runner.lifecycle",
1724 RoderEvent::TeamStarted(_) => "team.started",
1725 RoderEvent::TeamMemberStarted(_) => "team.member_started",
1726 RoderEvent::TeamMemberStatusChanged(_) => "team.member_status_changed",
1727 RoderEvent::TeamMemberMessageDelta(_) => "team.member_message_delta",
1728 RoderEvent::TeamMemberCompleted(_) => "team.member_completed",
1729 RoderEvent::TeamDisplayModeChanged(_) => "team.display_mode_changed",
1730 RoderEvent::TeamTaskChanged(_) => "team.task_changed",
1731 RoderEvent::TeamCleanupCompleted(_) => "team.cleanup_completed",
1732 RoderEvent::ReviewStarted(_) => "review.started",
1733 RoderEvent::ReviewCompleted(_) => "review.completed",
1734 RoderEvent::ReviewFailed(_) => "review.failed",
1735 RoderEvent::ReviewPublished(_) => "review.published",
1736 }
1737 }
1738
1739 pub fn source(&self) -> EventSource {
1740 match self {
1741 RoderEvent::InferenceEventReceived(_) | RoderEvent::InferenceStarted(_) => {
1742 EventSource::Provider
1743 }
1744 RoderEvent::InferenceRoutingDecision(_) => EventSource::Core,
1745 RoderEvent::ReliabilityRetryRecorded(_) => EventSource::Provider,
1746 RoderEvent::ReliabilityFailureRecorded(_)
1747 | RoderEvent::ReliabilityLimitRecorded(_)
1748 | RoderEvent::ReliabilityMetricRecorded(_) => EventSource::Core,
1749 RoderEvent::ToolCallRequested(_)
1750 | RoderEvent::ToolCallValidationRecorded(_)
1751 | RoderEvent::ToolCallStarted(_)
1752 | RoderEvent::ToolCallCompleted(_) => EventSource::Tool,
1753 RoderEvent::ToolOutputDelta(_) => EventSource::Tool,
1754 RoderEvent::SubagentStarted(_)
1755 | RoderEvent::SubagentMessage(_)
1756 | RoderEvent::SubagentToolCall(_)
1757 | RoderEvent::SubagentCompleted(_)
1758 | RoderEvent::SubagentFailed(_)
1759 | RoderEvent::SubagentTraceCreated(_)
1760 | RoderEvent::SubagentTraceDelta(_)
1761 | RoderEvent::SubagentTraceStatusChanged(_)
1762 | RoderEvent::SubagentTraceCompleted(_)
1763 | RoderEvent::SubagentTraceFailed(_)
1764 | RoderEvent::PlanReviewCreated(_)
1765 | RoderEvent::PlanReviewStatusChanged(_)
1766 | RoderEvent::PlanReviewCommentAdded(_)
1767 | RoderEvent::PlanReviewRewritten(_)
1768 | RoderEvent::PlanReviewApproved(_)
1769 | RoderEvent::PlanReviewRejected(_)
1770 | RoderEvent::HunkRecorded(_)
1771 | RoderEvent::WorkspaceChangeObserved(_)
1772 | RoderEvent::HunkRollbackRequested(_)
1773 | RoderEvent::HunkRollbackCompleted(_)
1774 | RoderEvent::WorkflowImportsDetected(_)
1775 | RoderEvent::WorkflowImportPreviewed(_)
1776 | RoderEvent::WorkflowImportEnabled(_)
1777 | RoderEvent::WorkflowImportDisabled(_)
1778 | RoderEvent::WorkflowImportStale(_)
1779 | RoderEvent::WorkflowImportFailed(_)
1780 | RoderEvent::MediaArtifactCreated(_)
1781 | RoderEvent::MediaArtifactUpdated(_)
1782 | RoderEvent::MediaArtifactDeleted(_)
1783 | RoderEvent::MediaPreviewReady(_)
1784 | RoderEvent::ContextArtifactCreated(_)
1785 | RoderEvent::ContextArtifactAppended(_)
1786 | RoderEvent::ContextArtifactCapped(_)
1787 | RoderEvent::ContextArtifactDeleted(_)
1788 | RoderEvent::ContextArtifactRetentionExpired(_)
1789 | RoderEvent::DiscoveryCatalogBuilt(_)
1790 | RoderEvent::DiscoveryItemUpdated(_)
1791 | RoderEvent::DiscoveryAuthRequired(_)
1792 | RoderEvent::DiscoveryItemRead(_)
1793 | RoderEvent::DiscoveryItemPromoted(_)
1794 | RoderEvent::DiscoveryPromotionReused(_)
1795 | RoderEvent::DiscoveryWarmCacheHit(_)
1796 | RoderEvent::DiscoveryPromotionExpired(_)
1797 | RoderEvent::RetrievalRoutePlanned(_)
1798 | RoderEvent::RetrievalRouteAccepted(_)
1799 | RoderEvent::RetrievalRouteIgnored(_)
1800 | RoderEvent::RetrievalRouteFailed(_)
1801 | RoderEvent::RetrievalResultUsed(_)
1802 | RoderEvent::RetrievalDiscoveryItemPromoted(_)
1803 | RoderEvent::RetrievalPromotionSkipped(_)
1804 | RoderEvent::MemorySaved(_)
1805 | RoderEvent::MemoryUpdated(_)
1806 | RoderEvent::MemoryDeleted(_)
1807 | RoderEvent::MemoryQueried(_)
1808 | RoderEvent::MemoryRecallReady(_)
1809 | RoderEvent::MemoryReembedQueued(_)
1810 | RoderEvent::MemoryProviderChanged(_)
1811 | RoderEvent::MemoryObservationRecorded(_)
1812 | RoderEvent::TaskStarted(_)
1813 | RoderEvent::TaskOutput(_)
1814 | RoderEvent::TaskCompleted(_)
1815 | RoderEvent::TaskFailed(_)
1816 | RoderEvent::TaskCancelled(_)
1817 | RoderEvent::ProcessStarted(_)
1818 | RoderEvent::ProcessOutput(_)
1819 | RoderEvent::ProcessExited(_)
1820 | RoderEvent::ProcessStopping(_)
1821 | RoderEvent::ProcessStopped(_)
1822 | RoderEvent::ProcessFailed(_) => EventSource::Extension,
1823 RoderEvent::RemoteServerStarted(_)
1824 | RoderEvent::RemoteServerStopped(_)
1825 | RoderEvent::RemoteAuthFailed(_)
1826 | RoderEvent::RemoteClientConnected(_)
1827 | RoderEvent::RemoteClientDisconnected(_) => EventSource::AppServer,
1828 RoderEvent::RoadmapChanged(_)
1829 | RoderEvent::ThreadGoalUpdated(_)
1830 | RoderEvent::ThreadGoalCleared(_)
1831 | RoderEvent::AutomationCreated(_)
1832 | RoderEvent::AutomationUpdated(_)
1833 | RoderEvent::AutomationDeleted(_)
1834 | RoderEvent::AutomationDue(_)
1835 | RoderEvent::AutomationLeased(_)
1836 | RoderEvent::AutomationQueued(_)
1837 | RoderEvent::AutomationStarted(_)
1838 | RoderEvent::AutomationCompleted(_)
1839 | RoderEvent::AutomationFailed(_)
1840 | RoderEvent::AutomationSkipped(_)
1841 | RoderEvent::AutomationLeaseExpired(_)
1842 | RoderEvent::SkillsCatalogLoaded(_)
1843 | RoderEvent::SkillConfigApplied(_)
1844 | RoderEvent::SkillActivationResolved(_)
1845 | RoderEvent::SkillIndexRendered(_)
1846 | RoderEvent::SkillInvoked(_)
1847 | RoderEvent::SkillAutoActivated(_)
1848 | RoderEvent::SkillSkipped(_) => EventSource::Core,
1849 RoderEvent::FileChangePreviewReady(_) => EventSource::Tool,
1850 RoderEvent::UserInputRequested(_)
1851 | RoderEvent::UserInputResolved(_)
1852 | RoderEvent::TaskLedgerUpdated(_)
1853 | RoderEvent::TurnPartialResult(_)
1854 | RoderEvent::TurnDeadlineExceeded(_)
1855 | RoderEvent::TurnLifecycleUpdated(_)
1856 | RoderEvent::VerificationRequired(_)
1857 | RoderEvent::VerificationCompleted(_)
1858 | RoderEvent::VerificationSkipped(_) => EventSource::Core,
1859 RoderEvent::ExtensionRegistered(_) => EventSource::Extension,
1860 RoderEvent::RunnerLifecycle(_) => EventSource::Extension,
1861 RoderEvent::TeamStarted(_)
1862 | RoderEvent::TeamMemberStarted(_)
1863 | RoderEvent::TeamMemberStatusChanged(_)
1864 | RoderEvent::TeamMemberMessageDelta(_)
1865 | RoderEvent::TeamMemberCompleted(_)
1866 | RoderEvent::TeamDisplayModeChanged(_)
1867 | RoderEvent::TeamTaskChanged(_)
1868 | RoderEvent::TeamCleanupCompleted(_) => EventSource::Core,
1869 RoderEvent::ReviewStarted(_)
1870 | RoderEvent::ReviewCompleted(_)
1871 | RoderEvent::ReviewFailed(_) => EventSource::Core,
1872 RoderEvent::ReviewPublished(_) => EventSource::Extension,
1873 _ => EventSource::Core,
1874 }
1875 }
1876
1877 pub fn thread_id(&self) -> Option<&ThreadId> {
1878 match self {
1879 RoderEvent::ExtensionEventEmitted(_) | RoderEvent::EventSinkFailed(_) => None,
1880 RoderEvent::ThreadCreated(e) => Some(&e.thread_id),
1881 RoderEvent::ThreadLoaded(e) => Some(&e.thread_id),
1882 RoderEvent::ThreadForkRequested(e) => Some(&e.parent_thread_id),
1883 RoderEvent::ThreadForked(e) => Some(&e.child_thread_id),
1884 RoderEvent::ThreadForkFailed(e) => Some(&e.parent_thread_id),
1885 RoderEvent::ThreadForkRemoved(e) => Some(&e.thread_id),
1886 RoderEvent::TurnStarted(e) => Some(&e.thread_id),
1887 RoderEvent::ContextAssemblyStarted(e) => Some(&e.thread_id),
1888 RoderEvent::ContextBlockAdded(e) => Some(&e.thread_id),
1889 RoderEvent::ContextAssemblyCompleted(e) => Some(&e.thread_id),
1890 RoderEvent::ContextEntrypointCandidatesInjected(e) => Some(&e.thread_id),
1891 RoderEvent::ContextCompactionStarted(e) => Some(&e.thread_id),
1892 RoderEvent::ContextCompactionRecorded(e) => Some(&e.thread_id),
1893 RoderEvent::ContextCompactionSkipped(e) => Some(&e.thread_id),
1894 RoderEvent::InferenceRoutingDecision(e) => Some(&e.thread_id),
1895 RoderEvent::InferenceStarted(e) => Some(&e.thread_id),
1896 RoderEvent::InferenceEventReceived(e) => Some(&e.thread_id),
1897 RoderEvent::ToolCallRequested(e) => Some(&e.thread_id),
1898 RoderEvent::HookRunRecorded(e) => Some(&e.thread_id),
1899 RoderEvent::ToolCallValidationRecorded(e) => Some(&e.thread_id),
1900 RoderEvent::ReliabilityFailureRecorded(e) => Some(&e.context.thread_id),
1901 RoderEvent::ReliabilityRetryRecorded(e) => Some(&e.context.thread_id),
1902 RoderEvent::ReliabilityLimitRecorded(e) => Some(&e.context.thread_id),
1903 RoderEvent::ReliabilityMetricRecorded(e) => Some(&e.context.thread_id),
1904 RoderEvent::CodeIndexingStarted(e) => e.context.thread_id.as_ref(),
1905 RoderEvent::CodeIndexChunked(e) => e.context.thread_id.as_ref(),
1906 RoderEvent::CodeIndexEmbedded(e) => e.context.thread_id.as_ref(),
1907 RoderEvent::CodeIndexReady(_) => None,
1908 RoderEvent::CodeIndexStale(e) => e.context.thread_id.as_ref(),
1909 RoderEvent::CodeIndexFailed(e) => e.context.thread_id.as_ref(),
1910 RoderEvent::CodeIndexProofFilteredResultDropped(e) => e.context.thread_id.as_ref(),
1911 RoderEvent::ApprovalRequested(e) => Some(&e.thread_id),
1912 RoderEvent::ApprovalResolved(e) => Some(&e.thread_id),
1913 RoderEvent::ExternalToolCallRequested(e) => Some(&e.thread_id),
1914 RoderEvent::ExternalToolCallResolved(e) => Some(&e.thread_id),
1915 RoderEvent::UserInputRequested(e) => Some(&e.thread_id),
1916 RoderEvent::UserInputResolved(e) => Some(&e.thread_id),
1917 RoderEvent::TaskLedgerUpdated(e) => Some(&e.thread_id),
1918 RoderEvent::VerificationRequired(e) => Some(&e.thread_id),
1919 RoderEvent::VerificationCompleted(e) => Some(&e.thread_id),
1920 RoderEvent::VerificationSkipped(e) => Some(&e.thread_id),
1921 RoderEvent::PolicyDecisionRecorded(e) => Some(&e.thread_id),
1922 RoderEvent::PolicyBypassActive(e) => Some(&e.thread_id),
1923 RoderEvent::PolicyModeChanged(e) => Some(&e.thread_id),
1924 RoderEvent::AgentSwarmModeChanged(e) => Some(&e.thread_id),
1925 RoderEvent::AgentSwarmStarted(e) => Some(&e.thread_id),
1926 RoderEvent::AgentSwarmProgress(e) => Some(&e.thread_id),
1927 RoderEvent::AgentSwarmCompleted(e) => Some(&e.thread_id),
1928 RoderEvent::UltraModeChanged(e) => Some(&e.thread_id),
1929 RoderEvent::PolicyExitPlanRequested(e) => Some(&e.thread_id),
1930 RoderEvent::PolicyExitPlanResolved(e) => Some(&e.thread_id),
1931 RoderEvent::ToolCallStarted(e) => Some(&e.thread_id),
1932 RoderEvent::ToolCallCompleted(e) => Some(&e.thread_id),
1933 RoderEvent::ToolOutputDelta(e) => Some(&e.thread_id),
1934 RoderEvent::ToolOutputTruncated(e) => Some(&e.thread_id),
1935 RoderEvent::SubagentStarted(e) => Some(&e.thread_id),
1936 RoderEvent::SubagentMessage(e) => Some(&e.thread_id),
1937 RoderEvent::SubagentToolCall(e) => Some(&e.thread_id),
1938 RoderEvent::SubagentCompleted(e) => Some(&e.thread_id),
1939 RoderEvent::SubagentFailed(e) => Some(&e.thread_id),
1940 RoderEvent::SubagentTraceCreated(e) => Some(&e.summary.parent.thread_id),
1941 RoderEvent::SubagentTraceDelta(e) => Some(&e.delta.parent.thread_id),
1942 RoderEvent::SubagentTraceStatusChanged(e) => Some(&e.parent.thread_id),
1943 RoderEvent::SubagentTraceCompleted(e) => Some(&e.summary.parent.thread_id),
1944 RoderEvent::SubagentTraceFailed(e) => Some(&e.summary.parent.thread_id),
1945 RoderEvent::PlanReviewCreated(e) => Some(&e.review.thread_id),
1946 RoderEvent::PlanReviewStatusChanged(e) => Some(&e.thread_id),
1947 RoderEvent::PlanReviewCommentAdded(e) => Some(&e.thread_id),
1948 RoderEvent::PlanReviewRewritten(e) => Some(&e.thread_id),
1949 RoderEvent::PlanReviewApproved(e) => Some(&e.thread_id),
1950 RoderEvent::PlanReviewRejected(e) => Some(&e.thread_id),
1951 RoderEvent::HunkRecorded(e) => Some(&e.hunk.thread_id),
1952 RoderEvent::WorkspaceChangeObserved(e) => Some(&e.change.thread_id),
1953 RoderEvent::HunkRollbackRequested(e) => Some(&e.thread_id),
1954 RoderEvent::HunkRollbackCompleted(e) => Some(&e.thread_id),
1955 RoderEvent::MediaArtifactCreated(e) => Some(&e.thread_id),
1956 RoderEvent::MediaArtifactUpdated(e) => Some(&e.thread_id),
1957 RoderEvent::MediaPreviewReady(e) => Some(&e.thread_id),
1958 RoderEvent::ContextArtifactCreated(e) => Some(&e.thread_id),
1959 RoderEvent::ContextArtifactAppended(e) => Some(&e.thread_id),
1960 RoderEvent::ContextArtifactCapped(e) => Some(&e.thread_id),
1961 RoderEvent::ContextArtifactDeleted(e) => Some(&e.thread_id),
1962 RoderEvent::ContextArtifactRetentionExpired(e) => Some(&e.thread_id),
1963 RoderEvent::DiscoveryItemRead(e) => Some(&e.thread_id),
1964 RoderEvent::DiscoveryItemPromoted(e) => Some(&e.record.thread_id),
1965 RoderEvent::DiscoveryPromotionReused(e) => Some(&e.record.thread_id),
1966 RoderEvent::DiscoveryWarmCacheHit(e) => Some(&e.record.thread_id),
1967 RoderEvent::DiscoveryPromotionExpired(e) => Some(&e.record.thread_id),
1968 RoderEvent::RetrievalRoutePlanned(e) => Some(&e.plan.thread_id),
1969 RoderEvent::RetrievalRouteAccepted(e) => Some(&e.thread_id),
1970 RoderEvent::RetrievalRouteIgnored(e) => Some(&e.thread_id),
1971 RoderEvent::RetrievalRouteFailed(e) => Some(&e.thread_id),
1972 RoderEvent::RetrievalResultUsed(e) => Some(&e.thread_id),
1973 RoderEvent::RetrievalDiscoveryItemPromoted(e) => Some(&e.thread_id),
1974 RoderEvent::RetrievalPromotionSkipped(e) => Some(&e.thread_id),
1975 RoderEvent::MemoryRecallReady(e) => Some(&e.thread_id),
1976 RoderEvent::MemoryObservationRecorded(e) => Some(&e.thread_id),
1977 RoderEvent::TaskStarted(e) => e.thread_id.as_ref(),
1978 RoderEvent::TaskOutput(e) => e.thread_id.as_ref(),
1979 RoderEvent::TaskCompleted(e) => e.thread_id.as_ref(),
1980 RoderEvent::TaskFailed(e) => e.thread_id.as_ref(),
1981 RoderEvent::TaskCancelled(e) => e.thread_id.as_ref(),
1982 RoderEvent::FileChangePreviewReady(e) => Some(&e.thread_id),
1983 RoderEvent::FileChanged(e) => Some(&e.thread_id),
1984 RoderEvent::TranscriptItemAppended(e) => Some(&e.thread_id),
1985 RoderEvent::TurnCompleted(e) => Some(&e.thread_id),
1986 RoderEvent::TurnFailed(e) => Some(&e.thread_id),
1987 RoderEvent::TurnPartialResult(e) => Some(&e.thread_id),
1988 RoderEvent::TurnDeadlineExceeded(e) => Some(&e.thread_id),
1989 RoderEvent::TurnLifecycleUpdated(e) => Some(&e.thread_id),
1990 RoderEvent::TurnInterrupted(e) => Some(&e.thread_id),
1991 RoderEvent::TurnSteered(e) => Some(&e.thread_id),
1992 RoderEvent::ThreadGoalUpdated(e) => Some(&e.thread_id),
1993 RoderEvent::ThreadGoalCleared(e) => Some(&e.thread_id),
1994 RoderEvent::TeamStarted(e) => Some(&e.lead_thread_id),
1995 RoderEvent::TeamMemberStarted(e) => Some(&e.member.thread_id),
1996 RoderEvent::TeamMemberStatusChanged(e) => Some(&e.member_thread_id),
1997 RoderEvent::TeamMemberMessageDelta(e) => Some(&e.member_thread_id),
1998 RoderEvent::TeamMemberCompleted(e) => Some(&e.member_thread_id),
1999 RoderEvent::SkillActivationResolved(e) => Some(&e.thread_id),
2000 RoderEvent::SkillIndexRendered(e) => Some(&e.thread_id),
2001 RoderEvent::SkillInvoked(e) => Some(&e.thread_id),
2002 RoderEvent::SkillAutoActivated(e) => Some(&e.thread_id),
2003 RoderEvent::SkillSkipped(e) => Some(&e.thread_id),
2004 RoderEvent::RuntimeStarted(_)
2005 | RoderEvent::ExtensionRegistered(_)
2006 | RoderEvent::WorkflowImportsDetected(_)
2007 | RoderEvent::WorkflowImportPreviewed(_)
2008 | RoderEvent::WorkflowImportEnabled(_)
2009 | RoderEvent::WorkflowImportDisabled(_)
2010 | RoderEvent::WorkflowImportStale(_)
2011 | RoderEvent::WorkflowImportFailed(_)
2012 | RoderEvent::MediaArtifactDeleted(_)
2013 | RoderEvent::DiscoveryCatalogBuilt(_)
2014 | RoderEvent::DiscoveryItemUpdated(_)
2015 | RoderEvent::DiscoveryAuthRequired(_)
2016 | RoderEvent::MemorySaved(_)
2017 | RoderEvent::MemoryUpdated(_)
2018 | RoderEvent::MemoryDeleted(_)
2019 | RoderEvent::MemoryQueried(_)
2020 | RoderEvent::MemoryReembedQueued(_)
2021 | RoderEvent::MemoryProviderChanged(_)
2022 | RoderEvent::KnowledgeSaved(_)
2023 | RoderEvent::KnowledgeUpdated(_)
2024 | RoderEvent::KnowledgeArchived(_)
2025 | RoderEvent::KnowledgeLinked(_)
2026 | RoderEvent::RemoteServerStarted(_)
2027 | RoderEvent::RemoteServerStopped(_)
2028 | RoderEvent::RemoteAuthFailed(_)
2029 | RoderEvent::RemoteClientConnected(_)
2030 | RoderEvent::RemoteClientDisconnected(_)
2031 | RoderEvent::RoadmapChanged(_)
2032 | RoderEvent::AutomationCreated(_)
2033 | RoderEvent::AutomationUpdated(_)
2034 | RoderEvent::AutomationDeleted(_)
2035 | RoderEvent::AutomationDue(_)
2036 | RoderEvent::AutomationLeased(_)
2037 | RoderEvent::AutomationQueued(_)
2038 | RoderEvent::AutomationSkipped(_)
2039 | RoderEvent::AutomationLeaseExpired(_)
2040 | RoderEvent::SkillsCatalogLoaded(_)
2041 | RoderEvent::SkillConfigApplied(_)
2042 | RoderEvent::RunnerLifecycle(_)
2043 | RoderEvent::TeamDisplayModeChanged(_)
2044 | RoderEvent::TeamTaskChanged(_)
2045 | RoderEvent::TeamCleanupCompleted(_) => None,
2046 RoderEvent::ProcessStarted(e) => e.process.thread_id.as_ref(),
2047 RoderEvent::ProcessOutput(e) => e.thread_id.as_ref(),
2048 RoderEvent::ProcessExited(e) => e.process.thread_id.as_ref(),
2049 RoderEvent::ProcessStopping(_) => None,
2050 RoderEvent::ProcessStopped(e) => e.process.thread_id.as_ref(),
2051 RoderEvent::ProcessFailed(e) => e.process.thread_id.as_ref(),
2052 RoderEvent::AutomationStarted(e) => e.run.thread_id.as_ref(),
2053 RoderEvent::AutomationCompleted(e) => e.run.thread_id.as_ref(),
2054 RoderEvent::AutomationFailed(e) => e.run.thread_id.as_ref(),
2055 RoderEvent::WorkflowRunDrafted(e) => e.thread_id.as_ref(),
2056 RoderEvent::WorkflowApprovalRequested(e) => e.thread_id.as_ref(),
2057 RoderEvent::WorkflowRunApproved(e) => e.thread_id.as_ref(),
2058 RoderEvent::WorkflowRunDenied(e) => e.thread_id.as_ref(),
2059 RoderEvent::WorkflowRunQueued(e) => e.thread_id.as_ref(),
2060 RoderEvent::WorkflowRunStarted(e) => e.thread_id.as_ref(),
2061 RoderEvent::WorkflowPhaseStarted(e) => e.thread_id.as_ref(),
2062 RoderEvent::WorkflowPhaseCompleted(e) => e.thread_id.as_ref(),
2063 RoderEvent::WorkflowAgentQueued(e) => e.thread_id.as_ref(),
2064 RoderEvent::WorkflowAgentStarted(e) => e.thread_id.as_ref(),
2065 RoderEvent::WorkflowAgentCompleted(e) => e.thread_id.as_ref(),
2066 RoderEvent::WorkflowAgentFailed(e) => e.thread_id.as_ref(),
2067 RoderEvent::WorkflowOutputRecorded(e) => e.thread_id.as_ref(),
2068 RoderEvent::WorkflowCheckpointRecorded(e) => e.thread_id.as_ref(),
2069 RoderEvent::WorkflowRunPaused(e) => e.thread_id.as_ref(),
2070 RoderEvent::WorkflowRunResumed(e) => e.thread_id.as_ref(),
2071 RoderEvent::WorkflowRunStopped(e) => e.thread_id.as_ref(),
2072 RoderEvent::WorkflowRunCompleted(e) => e.thread_id.as_ref(),
2073 RoderEvent::WorkflowRunFailed(e) => e.thread_id.as_ref(),
2074 RoderEvent::ReviewStarted(e) => Some(&e.thread_id),
2075 RoderEvent::ReviewCompleted(e) => Some(&e.thread_id),
2076 RoderEvent::ReviewFailed(e) => Some(&e.thread_id),
2077 RoderEvent::ReviewPublished(e) => e.thread_id.as_ref(),
2078 }
2079 }
2080
2081 pub fn turn_id(&self) -> Option<&TurnId> {
2082 match self {
2083 RoderEvent::ExtensionEventEmitted(_) | RoderEvent::EventSinkFailed(_) => None,
2084 RoderEvent::ThreadForkRequested(_)
2085 | RoderEvent::ThreadForked(_)
2086 | RoderEvent::ThreadForkFailed(_)
2087 | RoderEvent::ThreadForkRemoved(_) => None,
2088 RoderEvent::TurnStarted(e) => Some(&e.turn_id),
2089 RoderEvent::ContextAssemblyStarted(e) => Some(&e.turn_id),
2090 RoderEvent::ContextBlockAdded(e) => Some(&e.turn_id),
2091 RoderEvent::ContextAssemblyCompleted(e) => Some(&e.turn_id),
2092 RoderEvent::ContextEntrypointCandidatesInjected(e) => Some(&e.turn_id),
2093 RoderEvent::ContextCompactionStarted(e) => Some(&e.turn_id),
2094 RoderEvent::ContextCompactionRecorded(e) => Some(&e.turn_id),
2095 RoderEvent::ContextCompactionSkipped(e) => Some(&e.turn_id),
2096 RoderEvent::InferenceRoutingDecision(e) => Some(&e.turn_id),
2097 RoderEvent::InferenceStarted(e) => Some(&e.turn_id),
2098 RoderEvent::InferenceEventReceived(e) => Some(&e.turn_id),
2099 RoderEvent::ToolCallRequested(e) => Some(&e.turn_id),
2100 RoderEvent::HookRunRecorded(e) => Some(&e.turn_id),
2101 RoderEvent::ToolCallValidationRecorded(e) => Some(&e.turn_id),
2102 RoderEvent::ReliabilityFailureRecorded(e) => Some(&e.context.turn_id),
2103 RoderEvent::ReliabilityRetryRecorded(e) => Some(&e.context.turn_id),
2104 RoderEvent::ReliabilityLimitRecorded(e) => Some(&e.context.turn_id),
2105 RoderEvent::ReliabilityMetricRecorded(e) => Some(&e.context.turn_id),
2106 RoderEvent::CodeIndexingStarted(e) => e.context.turn_id.as_ref(),
2107 RoderEvent::CodeIndexChunked(e) => e.context.turn_id.as_ref(),
2108 RoderEvent::CodeIndexEmbedded(e) => e.context.turn_id.as_ref(),
2109 RoderEvent::CodeIndexReady(_) => None,
2110 RoderEvent::CodeIndexStale(e) => e.context.turn_id.as_ref(),
2111 RoderEvent::CodeIndexFailed(e) => e.context.turn_id.as_ref(),
2112 RoderEvent::CodeIndexProofFilteredResultDropped(e) => e.context.turn_id.as_ref(),
2113 RoderEvent::ApprovalRequested(e) => Some(&e.turn_id),
2114 RoderEvent::ApprovalResolved(e) => Some(&e.turn_id),
2115 RoderEvent::ExternalToolCallRequested(e) => Some(&e.turn_id),
2116 RoderEvent::ExternalToolCallResolved(e) => Some(&e.turn_id),
2117 RoderEvent::UserInputRequested(e) => Some(&e.turn_id),
2118 RoderEvent::UserInputResolved(e) => Some(&e.turn_id),
2119 RoderEvent::TaskLedgerUpdated(e) => Some(&e.turn_id),
2120 RoderEvent::VerificationRequired(e) => Some(&e.turn_id),
2121 RoderEvent::VerificationCompleted(e) => Some(&e.turn_id),
2122 RoderEvent::VerificationSkipped(e) => Some(&e.turn_id),
2123 RoderEvent::PolicyDecisionRecorded(e) => Some(&e.turn_id),
2124 RoderEvent::PolicyBypassActive(e) => Some(&e.turn_id),
2125 RoderEvent::PolicyModeChanged(e) => e.turn_id.as_ref(),
2126 RoderEvent::AgentSwarmModeChanged(e) => e.turn_id.as_ref(),
2127 RoderEvent::AgentSwarmStarted(e) => Some(&e.turn_id),
2128 RoderEvent::AgentSwarmProgress(e) => Some(&e.turn_id),
2129 RoderEvent::AgentSwarmCompleted(e) => Some(&e.turn_id),
2130 RoderEvent::UltraModeChanged(e) => e.turn_id.as_ref(),
2131 RoderEvent::PolicyExitPlanRequested(e) => Some(&e.turn_id),
2132 RoderEvent::PolicyExitPlanResolved(e) => Some(&e.turn_id),
2133 RoderEvent::ToolCallStarted(e) => Some(&e.turn_id),
2134 RoderEvent::ToolCallCompleted(e) => Some(&e.turn_id),
2135 RoderEvent::ToolOutputDelta(e) => Some(&e.turn_id),
2136 RoderEvent::ToolOutputTruncated(e) => Some(&e.turn_id),
2137 RoderEvent::SubagentStarted(e) => Some(&e.turn_id),
2138 RoderEvent::SubagentMessage(e) => Some(&e.turn_id),
2139 RoderEvent::SubagentToolCall(e) => Some(&e.turn_id),
2140 RoderEvent::SubagentCompleted(e) => Some(&e.turn_id),
2141 RoderEvent::SubagentFailed(e) => Some(&e.turn_id),
2142 RoderEvent::SubagentTraceCreated(e) => Some(&e.summary.parent.turn_id),
2143 RoderEvent::SubagentTraceDelta(e) => Some(&e.delta.parent.turn_id),
2144 RoderEvent::SubagentTraceStatusChanged(e) => Some(&e.parent.turn_id),
2145 RoderEvent::SubagentTraceCompleted(e) => Some(&e.summary.parent.turn_id),
2146 RoderEvent::SubagentTraceFailed(e) => Some(&e.summary.parent.turn_id),
2147 RoderEvent::PlanReviewCreated(e) => Some(&e.review.turn_id),
2148 RoderEvent::PlanReviewStatusChanged(e) => Some(&e.turn_id),
2149 RoderEvent::PlanReviewCommentAdded(e) => Some(&e.turn_id),
2150 RoderEvent::PlanReviewRewritten(e) => Some(&e.turn_id),
2151 RoderEvent::PlanReviewApproved(e) => Some(&e.turn_id),
2152 RoderEvent::PlanReviewRejected(e) => Some(&e.turn_id),
2153 RoderEvent::HunkRecorded(e) => Some(&e.hunk.turn_id),
2154 RoderEvent::WorkspaceChangeObserved(e) => Some(&e.change.turn_id),
2155 RoderEvent::HunkRollbackRequested(e) => Some(&e.turn_id),
2156 RoderEvent::HunkRollbackCompleted(e) => Some(&e.turn_id),
2157 RoderEvent::MediaArtifactCreated(e) => Some(&e.turn_id),
2158 RoderEvent::MediaArtifactUpdated(e) => Some(&e.turn_id),
2159 RoderEvent::MediaPreviewReady(e) => Some(&e.turn_id),
2160 RoderEvent::ContextArtifactCreated(e) => Some(&e.turn_id),
2161 RoderEvent::ContextArtifactAppended(e) => Some(&e.turn_id),
2162 RoderEvent::ContextArtifactCapped(e) => Some(&e.turn_id),
2163 RoderEvent::DiscoveryItemRead(e) => Some(&e.turn_id),
2164 RoderEvent::DiscoveryItemPromoted(e) => e.record.turn_id.as_ref(),
2165 RoderEvent::DiscoveryPromotionReused(e) => e.record.turn_id.as_ref(),
2166 RoderEvent::DiscoveryWarmCacheHit(e) => e.record.turn_id.as_ref(),
2167 RoderEvent::DiscoveryPromotionExpired(e) => e.record.turn_id.as_ref(),
2168 RoderEvent::RetrievalRoutePlanned(e) => Some(&e.plan.turn_id),
2169 RoderEvent::RetrievalRouteAccepted(e) => Some(&e.turn_id),
2170 RoderEvent::RetrievalRouteIgnored(e) => Some(&e.turn_id),
2171 RoderEvent::RetrievalRouteFailed(e) => Some(&e.turn_id),
2172 RoderEvent::RetrievalResultUsed(e) => Some(&e.turn_id),
2173 RoderEvent::RetrievalDiscoveryItemPromoted(e) => Some(&e.turn_id),
2174 RoderEvent::RetrievalPromotionSkipped(e) => Some(&e.turn_id),
2175 RoderEvent::MemoryRecallReady(e) => Some(&e.turn_id),
2176 RoderEvent::MemoryObservationRecorded(e) => Some(&e.turn_id),
2177 RoderEvent::TaskStarted(e) => e.turn_id.as_ref(),
2178 RoderEvent::TaskOutput(e) => e.turn_id.as_ref(),
2179 RoderEvent::TaskCompleted(e) => e.turn_id.as_ref(),
2180 RoderEvent::TaskFailed(e) => e.turn_id.as_ref(),
2181 RoderEvent::TaskCancelled(e) => e.turn_id.as_ref(),
2182 RoderEvent::FileChangePreviewReady(e) => Some(&e.turn_id),
2183 RoderEvent::FileChanged(e) => Some(&e.turn_id),
2184 RoderEvent::TranscriptItemAppended(e) => Some(&e.turn_id),
2185 RoderEvent::TurnCompleted(e) => Some(&e.turn_id),
2186 RoderEvent::TurnFailed(e) => Some(&e.turn_id),
2187 RoderEvent::TurnPartialResult(e) => Some(&e.turn_id),
2188 RoderEvent::TurnDeadlineExceeded(e) => Some(&e.turn_id),
2189 RoderEvent::TurnLifecycleUpdated(e) => Some(&e.turn_id),
2190 RoderEvent::TurnInterrupted(e) => Some(&e.turn_id),
2191 RoderEvent::TurnSteered(e) => Some(&e.turn_id),
2192 RoderEvent::TeamMemberMessageDelta(e) => Some(&e.turn_id),
2193 RoderEvent::TeamMemberCompleted(e) => e.turn_id.as_ref(),
2194 RoderEvent::SkillActivationResolved(e) => Some(&e.turn_id),
2195 RoderEvent::SkillIndexRendered(e) => Some(&e.turn_id),
2196 RoderEvent::SkillInvoked(e) => Some(&e.turn_id),
2197 RoderEvent::SkillAutoActivated(e) => Some(&e.turn_id),
2198 RoderEvent::SkillSkipped(e) => Some(&e.turn_id),
2199 RoderEvent::RuntimeStarted(_)
2200 | RoderEvent::ExtensionRegistered(_)
2201 | RoderEvent::ThreadCreated(_)
2202 | RoderEvent::ThreadLoaded(_)
2203 | RoderEvent::WorkflowImportsDetected(_)
2204 | RoderEvent::WorkflowImportPreviewed(_)
2205 | RoderEvent::WorkflowImportEnabled(_)
2206 | RoderEvent::WorkflowImportDisabled(_)
2207 | RoderEvent::WorkflowImportStale(_)
2208 | RoderEvent::WorkflowImportFailed(_)
2209 | RoderEvent::MediaArtifactDeleted(_)
2210 | RoderEvent::ContextArtifactDeleted(_)
2211 | RoderEvent::ContextArtifactRetentionExpired(_)
2212 | RoderEvent::DiscoveryCatalogBuilt(_)
2213 | RoderEvent::DiscoveryItemUpdated(_)
2214 | RoderEvent::DiscoveryAuthRequired(_)
2215 | RoderEvent::MemorySaved(_)
2216 | RoderEvent::MemoryUpdated(_)
2217 | RoderEvent::MemoryDeleted(_)
2218 | RoderEvent::MemoryQueried(_)
2219 | RoderEvent::MemoryReembedQueued(_)
2220 | RoderEvent::MemoryProviderChanged(_)
2221 | RoderEvent::KnowledgeSaved(_)
2222 | RoderEvent::KnowledgeUpdated(_)
2223 | RoderEvent::KnowledgeArchived(_)
2224 | RoderEvent::KnowledgeLinked(_)
2225 | RoderEvent::RemoteServerStarted(_)
2226 | RoderEvent::RemoteServerStopped(_)
2227 | RoderEvent::RemoteAuthFailed(_)
2228 | RoderEvent::RemoteClientConnected(_)
2229 | RoderEvent::RemoteClientDisconnected(_)
2230 | RoderEvent::ThreadGoalUpdated(_)
2231 | RoderEvent::ThreadGoalCleared(_)
2232 | RoderEvent::RoadmapChanged(_)
2233 | RoderEvent::AutomationCreated(_)
2234 | RoderEvent::AutomationUpdated(_)
2235 | RoderEvent::AutomationDeleted(_)
2236 | RoderEvent::AutomationDue(_)
2237 | RoderEvent::AutomationLeased(_)
2238 | RoderEvent::AutomationQueued(_)
2239 | RoderEvent::AutomationSkipped(_)
2240 | RoderEvent::AutomationLeaseExpired(_)
2241 | RoderEvent::SkillsCatalogLoaded(_)
2242 | RoderEvent::SkillConfigApplied(_)
2243 | RoderEvent::RunnerLifecycle(_)
2244 | RoderEvent::TeamStarted(_)
2245 | RoderEvent::TeamMemberStarted(_)
2246 | RoderEvent::TeamMemberStatusChanged(_)
2247 | RoderEvent::TeamDisplayModeChanged(_)
2248 | RoderEvent::TeamTaskChanged(_)
2249 | RoderEvent::TeamCleanupCompleted(_) => None,
2250 RoderEvent::ProcessStarted(e) => e.process.turn_id.as_ref(),
2251 RoderEvent::ProcessOutput(e) => e.turn_id.as_ref(),
2252 RoderEvent::ProcessExited(e) => e.process.turn_id.as_ref(),
2253 RoderEvent::ProcessStopping(_) => None,
2254 RoderEvent::ProcessStopped(e) => e.process.turn_id.as_ref(),
2255 RoderEvent::ProcessFailed(e) => e.process.turn_id.as_ref(),
2256 RoderEvent::AutomationStarted(e) => e.run.turn_id.as_ref(),
2257 RoderEvent::AutomationCompleted(e) => e.run.turn_id.as_ref(),
2258 RoderEvent::AutomationFailed(e) => e.run.turn_id.as_ref(),
2259 RoderEvent::WorkflowRunDrafted(e) => e.turn_id.as_ref(),
2260 RoderEvent::WorkflowApprovalRequested(e) => e.turn_id.as_ref(),
2261 RoderEvent::WorkflowRunApproved(e) => e.turn_id.as_ref(),
2262 RoderEvent::WorkflowRunDenied(e) => e.turn_id.as_ref(),
2263 RoderEvent::WorkflowRunQueued(e) => e.turn_id.as_ref(),
2264 RoderEvent::WorkflowRunStarted(e) => e.turn_id.as_ref(),
2265 RoderEvent::WorkflowPhaseStarted(e) => e.turn_id.as_ref(),
2266 RoderEvent::WorkflowPhaseCompleted(e) => e.turn_id.as_ref(),
2267 RoderEvent::WorkflowAgentQueued(e) => e.turn_id.as_ref(),
2268 RoderEvent::WorkflowAgentStarted(e) => e.turn_id.as_ref(),
2269 RoderEvent::WorkflowAgentCompleted(e) => e.turn_id.as_ref(),
2270 RoderEvent::WorkflowAgentFailed(e) => e.turn_id.as_ref(),
2271 RoderEvent::WorkflowOutputRecorded(e) => e.turn_id.as_ref(),
2272 RoderEvent::WorkflowCheckpointRecorded(e) => e.turn_id.as_ref(),
2273 RoderEvent::WorkflowRunPaused(e) => e.turn_id.as_ref(),
2274 RoderEvent::WorkflowRunResumed(e) => e.turn_id.as_ref(),
2275 RoderEvent::WorkflowRunStopped(e) => e.turn_id.as_ref(),
2276 RoderEvent::WorkflowRunCompleted(e) => e.turn_id.as_ref(),
2277 RoderEvent::WorkflowRunFailed(e) => e.turn_id.as_ref(),
2278 RoderEvent::ReviewStarted(e) => Some(&e.turn_id),
2279 RoderEvent::ReviewCompleted(e) => Some(&e.turn_id),
2280 RoderEvent::ReviewFailed(e) => e.turn_id.as_ref(),
2281 RoderEvent::ReviewPublished(_) => None,
2282 }
2283 }
2284}
2285
2286#[derive(Debug, Clone, Serialize, Deserialize)]
2287pub struct EventEnvelope {
2288 pub event_id: EventId,
2289 pub seq: u64,
2290 #[serde(with = "time::serde::rfc3339")]
2291 pub timestamp: OffsetDateTime,
2292 pub source: EventSource,
2293 pub kind: String,
2294 pub thread_id: Option<ThreadId>,
2295 pub turn_id: Option<TurnId>,
2296 pub event: RoderEvent,
2297}
2298
2299impl EventEnvelope {
2300 pub fn matches_filter(&self, filter: &EventFilter) -> bool {
2301 filter.matches(self)
2302 }
2303}
2304
2305#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
2306pub struct EventFilter {
2307 pub thread_id: Option<ThreadId>,
2308 pub turn_id: Option<TurnId>,
2309 pub source: Option<EventSource>,
2310 pub kinds: Vec<String>,
2311}
2312
2313impl EventFilter {
2314 pub fn for_thread(thread_id: impl Into<ThreadId>) -> Self {
2315 Self {
2316 thread_id: Some(thread_id.into()),
2317 ..Self::default()
2318 }
2319 }
2320
2321 pub fn for_turn(thread_id: impl Into<ThreadId>, turn_id: impl Into<TurnId>) -> Self {
2322 Self {
2323 thread_id: Some(thread_id.into()),
2324 turn_id: Some(turn_id.into()),
2325 ..Self::default()
2326 }
2327 }
2328
2329 pub fn with_source(mut self, source: EventSource) -> Self {
2330 self.source = Some(source);
2331 self
2332 }
2333
2334 pub fn with_kind(mut self, kind: impl Into<String>) -> Self {
2335 self.kinds.push(kind.into());
2336 self
2337 }
2338
2339 pub fn matches(&self, envelope: &EventEnvelope) -> bool {
2340 if self
2341 .thread_id
2342 .as_ref()
2343 .is_some_and(|thread_id| envelope.thread_id.as_ref() != Some(thread_id))
2344 {
2345 return false;
2346 }
2347 if self
2348 .turn_id
2349 .as_ref()
2350 .is_some_and(|turn_id| envelope.turn_id.as_ref() != Some(turn_id))
2351 {
2352 return false;
2353 }
2354 if self
2355 .source
2356 .as_ref()
2357 .is_some_and(|source| &envelope.source != source)
2358 {
2359 return false;
2360 }
2361 if !self.kinds.is_empty() && !self.kinds.iter().any(|kind| kind == &envelope.kind) {
2362 return false;
2363 }
2364 true
2365 }
2366}
2367
2368#[cfg(test)]
2369mod tests {
2370 use super::*;
2371
2372 fn envelope(thread_id: Option<&str>, turn_id: Option<&str>, kind: &str) -> EventEnvelope {
2373 EventEnvelope {
2374 event_id: "event-1".to_string(),
2375 seq: 1,
2376 timestamp: OffsetDateTime::UNIX_EPOCH,
2377 source: EventSource::Core,
2378 kind: kind.to_string(),
2379 thread_id: thread_id.map(str::to_string),
2380 turn_id: turn_id.map(str::to_string),
2381 event: RoderEvent::TurnStarted(TurnStarted {
2382 thread_id: thread_id.unwrap_or("thread-a").to_string(),
2383 turn_id: turn_id.unwrap_or("turn-a").to_string(),
2384 runtime_profile: RuntimeProfile::Interactive,
2385 timestamp: OffsetDateTime::UNIX_EPOCH,
2386 }),
2387 }
2388 }
2389
2390 #[test]
2391 fn event_filter_matches_thread_turn_source_and_kind() {
2392 let envelope = envelope(Some("thread-a"), Some("turn-a"), "turn.started");
2393 let filter = EventFilter::for_turn("thread-a", "turn-a")
2394 .with_source(EventSource::Core)
2395 .with_kind("turn.started");
2396
2397 assert!(filter.matches(&envelope));
2398 assert!(envelope.matches_filter(&filter));
2399 assert!(!EventFilter::for_thread("thread-b").matches(&envelope));
2400 assert!(!EventFilter::for_turn("thread-a", "turn-b").matches(&envelope));
2401 assert!(
2402 !EventFilter::default()
2403 .with_source(EventSource::Provider)
2404 .matches(&envelope)
2405 );
2406 assert!(
2407 !EventFilter::default()
2408 .with_kind("turn.completed")
2409 .matches(&envelope)
2410 );
2411 }
2412
2413 #[test]
2414 fn empty_event_filter_matches_everything() {
2415 assert!(EventFilter::default().matches(&envelope(None, None, "runtime.started")));
2416 }
2417
2418 #[test]
2419 fn code_index_event_kind_and_scope_are_visible() {
2420 let event = RoderEvent::CodeIndexProofFilteredResultDropped(
2421 crate::code_index::CodeIndexProofFilteredResultDropped {
2422 context: crate::code_index::CodeIndexEventContext {
2423 workspace_root: std::path::PathBuf::from("/repo"),
2424 generation_id: Some("gen-1".to_string()),
2425 thread_id: Some("thread-1".to_string()),
2426 turn_id: Some("turn-1".to_string()),
2427 },
2428 drop: crate::code_index::ProofFilteredDrop {
2429 query_id: "query-1".to_string(),
2430 path_hash: "path-hash".to_string(),
2431 content_hash: "content-hash".to_string(),
2432 reason: "proof missing".to_string(),
2433 },
2434 timestamp: OffsetDateTime::UNIX_EPOCH,
2435 },
2436 );
2437
2438 assert_eq!(event.kind(), "code_index.proof_filtered_result_dropped");
2439 assert_eq!(event.thread_id().map(String::as_str), Some("thread-1"));
2440 assert_eq!(event.turn_id().map(String::as_str), Some("turn-1"));
2441 assert_eq!(event.source(), EventSource::Core);
2442 }
2443
2444 #[test]
2445 fn workflow_event_kind_scope_and_agent_metadata_are_visible() {
2446 let agent = crate::dynamic_workflows::WorkflowAgentRun {
2447 agent_id: "agent-1".to_string(),
2448 phase_id: "phase-1".to_string(),
2449 description: "Review findings".to_string(),
2450 status: crate::dynamic_workflows::WorkflowAgentStatus::Completed,
2451 lane: Some(crate::subagents::SubagentLane::Reviewer),
2452 model: Some("mock-model".to_string()),
2453 thread_id: Some("child-thread".to_string()),
2454 turn_id: Some("child-turn".to_string()),
2455 usage: Some(crate::inference::TokenUsage::new(10, 5, 15)),
2456 exit_reason: None,
2457 error: None,
2458 started_at: Some(OffsetDateTime::UNIX_EPOCH),
2459 completed_at: Some(OffsetDateTime::UNIX_EPOCH),
2460 };
2461 let event = RoderEvent::WorkflowAgentCompleted(WorkflowAgentCompleted {
2462 run_id: "run-1".to_string(),
2463 thread_id: Some("thread-1".to_string()),
2464 turn_id: Some("turn-1".to_string()),
2465 agent,
2466 timestamp: OffsetDateTime::UNIX_EPOCH,
2467 });
2468
2469 assert_eq!(event.kind(), "workflows/agentCompleted");
2470 assert_eq!(event.source(), EventSource::Core);
2471 assert_eq!(event.thread_id().map(String::as_str), Some("thread-1"));
2472 assert_eq!(event.turn_id().map(String::as_str), Some("turn-1"));
2473
2474 let value = serde_json::to_value(&event).unwrap();
2475 let event_value = &value["WorkflowAgentCompleted"];
2476 assert_eq!(event_value["runId"], "run-1");
2477 assert_eq!(event_value["agent"]["phaseId"], "phase-1");
2478 assert_eq!(event_value["agent"]["agentId"], "agent-1");
2479 assert_eq!(event_value["agent"]["status"], "completed");
2480 assert_eq!(event_value["agent"]["usage"]["total_tokens"], 15);
2481 }
2482
2483 #[test]
2484 fn event_timestamps_serialize_as_rfc3339_strings() {
2485 let value =
2486 serde_json::to_value(envelope(Some("thread-a"), Some("turn-a"), "turn.started"))
2487 .unwrap();
2488
2489 assert_eq!(value["timestamp"], "1970-01-01T00:00:00Z");
2490 assert_eq!(
2491 value["event"]["TurnStarted"]["timestamp"],
2492 "1970-01-01T00:00:00Z"
2493 );
2494 }
2495
2496 #[test]
2497 fn subagent_event_envelope_round_trips_parent_ids() {
2498 let event = RoderEvent::SubagentStarted(SubagentStarted {
2499 thread_id: "child-thread".to_string(),
2500 turn_id: "child-turn".to_string(),
2501 parent_thread_id: "parent-thread".to_string(),
2502 parent_turn_id: "parent-turn".to_string(),
2503 agent_type: "explore".to_string(),
2504 description: "Inspect repository".to_string(),
2505 model: Some("test-model".to_string()),
2506 timestamp: OffsetDateTime::UNIX_EPOCH,
2507 });
2508 let envelope = EventEnvelope {
2509 event_id: "event-subagent-started".to_string(),
2510 seq: 7,
2511 timestamp: OffsetDateTime::UNIX_EPOCH,
2512 source: event.source(),
2513 kind: event.kind().to_string(),
2514 thread_id: event.thread_id().cloned(),
2515 turn_id: event.turn_id().cloned(),
2516 event,
2517 };
2518
2519 let serialized = serde_json::to_string(&envelope).unwrap();
2520 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2521
2522 assert_eq!(round_trip.kind, "subagent.started");
2523 assert_eq!(round_trip.source, EventSource::Extension);
2524 assert_eq!(round_trip.thread_id.as_deref(), Some("child-thread"));
2525 assert_eq!(round_trip.turn_id.as_deref(), Some("child-turn"));
2526
2527 match round_trip.event {
2528 RoderEvent::SubagentStarted(started) => {
2529 assert_eq!(started.parent_thread_id, "parent-thread");
2530 assert_eq!(started.parent_turn_id, "parent-turn");
2531 }
2532 other => panic!("unexpected event: {other:?}"),
2533 }
2534 }
2535
2536 #[test]
2537 fn subagent_trace_event_uses_parent_turn_for_filtering() {
2538 let summary = SubagentTraceSummary {
2539 trace_id: "trace-1".to_string(),
2540 parent: ParentTurnRef {
2541 thread_id: "parent-thread".to_string(),
2542 turn_id: "parent-turn".to_string(),
2543 },
2544 child_thread_id: "child-thread".to_string(),
2545 child_turn_id: "child-turn".to_string(),
2546 title: "Inspect repository".to_string(),
2547 role: "explorer".to_string(),
2548 model: Some("test-model".to_string()),
2549 lane: None,
2550 status: SubagentTraceStatus::Running,
2551 elapsed_ms: 10,
2552 usage: None,
2553 destination: None,
2554 latest_activity: None,
2555 error_summary: None,
2556 exit_reason: None,
2557 };
2558 let event = RoderEvent::SubagentTraceCreated(SubagentTraceCreated {
2559 summary,
2560 timestamp: OffsetDateTime::UNIX_EPOCH,
2561 });
2562
2563 assert_eq!(event.kind(), "turn/subagentTraceCreated");
2564 assert_eq!(event.source(), EventSource::Extension);
2565 assert_eq!(event.thread_id().map(String::as_str), Some("parent-thread"));
2566 assert_eq!(event.turn_id().map(String::as_str), Some("parent-turn"));
2567 }
2568
2569 #[test]
2570 fn task_events_round_trip_with_replay_ids() {
2571 let event = RoderEvent::TaskOutput(TaskOutput {
2572 task_id: "task-1".to_string(),
2573 stream: crate::tasks::TaskOutputStream::Stdout,
2574 chunk: "building\n".to_string(),
2575 dropped_bytes: 0,
2576 thread_id: Some("thread-a".to_string()),
2577 turn_id: Some("turn-a".to_string()),
2578 timestamp: OffsetDateTime::UNIX_EPOCH,
2579 });
2580 let envelope = EventEnvelope {
2581 event_id: "event-task-output".to_string(),
2582 seq: 9,
2583 timestamp: OffsetDateTime::UNIX_EPOCH,
2584 source: event.source(),
2585 kind: event.kind().to_string(),
2586 thread_id: event.thread_id().cloned(),
2587 turn_id: event.turn_id().cloned(),
2588 event,
2589 };
2590
2591 let serialized = serde_json::to_string(&envelope).unwrap();
2592 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2593
2594 assert_eq!(round_trip.kind, "task.output");
2595 assert_eq!(round_trip.source, EventSource::Extension);
2596 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2597 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2598 match round_trip.event {
2599 RoderEvent::TaskOutput(output) => {
2600 assert_eq!(output.task_id, "task-1");
2601 assert_eq!(output.stream, crate::tasks::TaskOutputStream::Stdout);
2602 assert_eq!(output.chunk, "building\n");
2603 }
2604 other => panic!("unexpected event: {other:?}"),
2605 }
2606 }
2607
2608 #[test]
2609 fn automations_event_exposes_kind_source_and_replay_scope() {
2610 let run = crate::automations::AutomationRunSummary {
2611 run_id: "run-1".to_string(),
2612 automation_id: "automation-1".to_string(),
2613 occurrence_key: "automation-1:1970-01-01T00:00:00Z".to_string(),
2614 state: crate::automations::AutomationRunState::Completed,
2615 scheduled_for: OffsetDateTime::UNIX_EPOCH,
2616 queued_at: Some(OffsetDateTime::UNIX_EPOCH),
2617 started_at: Some(OffsetDateTime::UNIX_EPOCH),
2618 finished_at: Some(OffsetDateTime::UNIX_EPOCH),
2619 thread_id: Some("thread-a".to_string()),
2620 turn_id: Some("turn-a".to_string()),
2621 task_id: Some("task-1".to_string()),
2622 server_id: Some("desktop-main".to_string()),
2623 server_role: Some("desktop".to_string()),
2624 exit_code: Some(0),
2625 error: None,
2626 skip_reason: None,
2627 };
2628 let event = RoderEvent::AutomationCompleted(crate::automations::AutomationCompleted {
2629 run,
2630 timestamp: OffsetDateTime::UNIX_EPOCH,
2631 });
2632
2633 assert_eq!(event.kind(), "automations/completed");
2634 assert_eq!(event.source(), EventSource::Core);
2635 assert_eq!(event.thread_id().map(String::as_str), Some("thread-a"));
2636 assert_eq!(event.turn_id().map(String::as_str), Some("turn-a"));
2637
2638 let value = serde_json::to_value(&event).unwrap();
2639 assert_eq!(
2640 value["AutomationCompleted"]["run"]["occurrenceKey"],
2641 "automation-1:1970-01-01T00:00:00Z"
2642 );
2643 assert_eq!(
2644 value["AutomationCompleted"]["run"]["serverId"],
2645 "desktop-main"
2646 );
2647 }
2648
2649 #[test]
2650 fn tool_call_completed_round_trips_error_status() {
2651 let event = RoderEvent::ToolCallCompleted(ToolCallCompleted {
2652 thread_id: "thread-a".to_string(),
2653 turn_id: "turn-a".to_string(),
2654 tool_id: "tool-a".to_string(),
2655 tool_name: Some("list_files".to_string()),
2656 display_payload: Some(serde_json::json!({ "path": "." })),
2657 is_error: true,
2658 output: Some("tool failed".to_string()),
2659 timestamp: OffsetDateTime::UNIX_EPOCH,
2660 });
2661 let envelope = EventEnvelope {
2662 event_id: "event-tool-completed".to_string(),
2663 seq: 10,
2664 timestamp: OffsetDateTime::UNIX_EPOCH,
2665 source: event.source(),
2666 kind: event.kind().to_string(),
2667 thread_id: event.thread_id().cloned(),
2668 turn_id: event.turn_id().cloned(),
2669 event,
2670 };
2671
2672 let serialized = serde_json::to_string(&envelope).unwrap();
2673 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2674
2675 assert_eq!(round_trip.kind, "tool.call_completed");
2676 match round_trip.event {
2677 RoderEvent::ToolCallCompleted(completed) => {
2678 assert_eq!(completed.tool_id, "tool-a");
2679 assert!(completed.is_error);
2680 assert_eq!(completed.output.as_deref(), Some("tool failed"));
2681 }
2682 other => panic!("unexpected event: {other:?}"),
2683 }
2684 }
2685
2686 #[test]
2687 fn file_change_preview_event_round_trips_public_metadata() {
2688 let event = RoderEvent::FileChangePreviewReady(FileChangePreviewReady {
2689 thread_id: "thread-a".to_string(),
2690 turn_id: "turn-a".to_string(),
2691 tool_id: "tool-a".to_string(),
2692 tool_name: "edit".to_string(),
2693 path: "src/lib.rs".to_string(),
2694 change_type: "modify".to_string(),
2695 before: Some("old\n".to_string()),
2696 after: "new\n".to_string(),
2697 supports_partial: false,
2698 timestamp: OffsetDateTime::UNIX_EPOCH,
2699 });
2700 let envelope = EventEnvelope {
2701 event_id: "event-file-preview".to_string(),
2702 seq: 8,
2703 timestamp: OffsetDateTime::UNIX_EPOCH,
2704 source: event.source(),
2705 kind: event.kind().to_string(),
2706 thread_id: event.thread_id().cloned(),
2707 turn_id: event.turn_id().cloned(),
2708 event,
2709 };
2710
2711 let serialized = serde_json::to_string(&envelope).unwrap();
2712 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2713
2714 assert_eq!(round_trip.kind, "file.change_preview_ready");
2715 assert_eq!(round_trip.source, EventSource::Tool);
2716 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2717 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2718 match round_trip.event {
2719 RoderEvent::FileChangePreviewReady(preview) => {
2720 assert_eq!(preview.tool_id, "tool-a");
2721 assert_eq!(preview.tool_name, "edit");
2722 assert_eq!(preview.path, "src/lib.rs");
2723 assert_eq!(preview.change_type, "modify");
2724 assert_eq!(preview.before.as_deref(), Some("old\n"));
2725 assert_eq!(preview.after, "new\n");
2726 assert!(!preview.supports_partial);
2727 }
2728 other => panic!("unexpected event: {other:?}"),
2729 }
2730 }
2731
2732 #[test]
2733 fn inference_started_deserializes_older_records_without_model_fields() {
2734 let value = serde_json::json!({
2735 "InferenceStarted": {
2736 "thread_id": "thread-a",
2737 "turn_id": "turn-a",
2738 "engine_id": "mock",
2739 "timestamp": "1970-01-01T00:00:00Z"
2740 }
2741 });
2742
2743 let event: RoderEvent = serde_json::from_value(value).unwrap();
2744
2745 match event {
2746 RoderEvent::InferenceStarted(started) => {
2747 assert_eq!(started.model.provider, "");
2748 assert_eq!(started.model.model, "");
2749 assert_eq!(started.reasoning, ReasoningConfig::default());
2750 }
2751 other => panic!("expected inference started, got {other:?}"),
2752 }
2753 }
2754
2755 #[test]
2756 fn team_member_completed_round_trips_optional_result_details() {
2757 let event = RoderEvent::TeamMemberCompleted(TeamMemberCompleted {
2758 team_id: "team-a".to_string(),
2759 member_id: "member-a".to_string(),
2760 member_thread_id: "thread-a".to_string(),
2761 turn_id: Some("turn-a".to_string()),
2762 status: TeamMemberStatus::Failed,
2763 final_message: Some("Partial review result.".to_string()),
2764 error: Some("provider request failed".to_string()),
2765 timestamp: OffsetDateTime::UNIX_EPOCH,
2766 });
2767
2768 let value = serde_json::to_value(&event).unwrap();
2769 assert_eq!(
2770 value["TeamMemberCompleted"]["final_message"],
2771 "Partial review result."
2772 );
2773 assert_eq!(
2774 value["TeamMemberCompleted"]["error"],
2775 "provider request failed"
2776 );
2777 let round_trip: RoderEvent = serde_json::from_value(value).unwrap();
2778 match round_trip {
2779 RoderEvent::TeamMemberCompleted(completed) => {
2780 assert_eq!(
2781 completed.final_message.as_deref(),
2782 Some("Partial review result.")
2783 );
2784 assert_eq!(completed.error.as_deref(), Some("provider request failed"));
2785 }
2786 other => panic!("expected team completion, got {other:?}"),
2787 }
2788
2789 let legacy: RoderEvent = serde_json::from_value(serde_json::json!({
2790 "TeamMemberCompleted": {
2791 "team_id": "team-a",
2792 "member_id": "member-a",
2793 "member_thread_id": "thread-a",
2794 "turn_id": "turn-a",
2795 "status": "completed",
2796 "timestamp": "1970-01-01T00:00:00Z"
2797 }
2798 }))
2799 .unwrap();
2800 match legacy {
2801 RoderEvent::TeamMemberCompleted(completed) => {
2802 assert!(completed.final_message.is_none());
2803 assert!(completed.error.is_none());
2804 }
2805 other => panic!("expected team completion, got {other:?}"),
2806 }
2807 }
2808
2809 #[test]
2810 fn processes_events_expose_kind_source_scope_and_round_trip() {
2811 let descriptor = crate::processes::ProcessDescriptor {
2812 process_id: "process-1".to_string(),
2813 origin: crate::processes::ProcessOrigin::CommandExec,
2814 state: crate::processes::ProcessState::Running,
2815 command: vec!["sleep".to_string(), "10".to_string()],
2816 command_summary: "sleep 10".to_string(),
2817 cwd: Some("/repo".to_string()),
2818 pid: Some(1234),
2819 task_id: Some("task-1".to_string()),
2820 thread_id: Some("thread-a".to_string()),
2821 turn_id: Some("turn-a".to_string()),
2822 runner_destination_id: None,
2823 runner_session_id: None,
2824 stoppable: true,
2825 started_at: OffsetDateTime::UNIX_EPOCH,
2826 updated_at: OffsetDateTime::UNIX_EPOCH,
2827 stdout_tail: None,
2828 stderr_tail: None,
2829 };
2830 let event = RoderEvent::ProcessStarted(crate::processes::ProcessStarted {
2831 process: descriptor,
2832 timestamp: OffsetDateTime::UNIX_EPOCH,
2833 });
2834 let envelope = EventEnvelope {
2835 event_id: "event-process-started".to_string(),
2836 seq: 11,
2837 timestamp: OffsetDateTime::UNIX_EPOCH,
2838 source: event.source(),
2839 kind: event.kind().to_string(),
2840 thread_id: event.thread_id().cloned(),
2841 turn_id: event.turn_id().cloned(),
2842 event,
2843 };
2844
2845 let serialized = serde_json::to_string(&envelope).unwrap();
2846 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2847
2848 assert_eq!(round_trip.kind, "process.started");
2849 assert_eq!(round_trip.source, EventSource::Extension);
2850 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2851 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2852 match round_trip.event {
2853 RoderEvent::ProcessStarted(started) => {
2854 assert_eq!(started.process.process_id, "process-1");
2855 assert_eq!(started.process.pid, Some(1234));
2856 }
2857 other => panic!("unexpected event: {other:?}"),
2858 }
2859
2860 let output = RoderEvent::ProcessOutput(crate::processes::ProcessOutput {
2861 process_id: "process-1".to_string(),
2862 stream: crate::tasks::TaskOutputStream::Stdout,
2863 chunk: "ready\n".to_string(),
2864 dropped_bytes: 0,
2865 thread_id: Some("thread-a".to_string()),
2866 turn_id: Some("turn-a".to_string()),
2867 timestamp: OffsetDateTime::UNIX_EPOCH,
2868 });
2869 assert_eq!(output.kind(), "process.output");
2870 assert_eq!(output.thread_id().map(String::as_str), Some("thread-a"));
2871 assert_eq!(output.turn_id().map(String::as_str), Some("turn-a"));
2872 }
2873
2874 #[test]
2875 fn skill_activation_event_exposes_kind_source_and_turn_scope() {
2876 let descriptor = crate::skills::SkillDescriptor {
2877 id: "builtin:commit".to_string(),
2878 name: "commit".to_string(),
2879 canonical_path: "roder-builtin://commit/SKILL.md".to_string(),
2880 source: crate::skills::SkillSource::BuiltIn,
2881 exposure: crate::skills::SkillExposure::DirectOnly,
2882 activation: crate::skills::SkillActivationState::Enabled,
2883 description: "Commit staged changes safely.".to_string(),
2884 short_description: Some("Commit safely".to_string()),
2885 experimental: false,
2886 diagnostics: Vec::new(),
2887 agent_metadata: None,
2888 };
2889 let event = RoderEvent::SkillActivationResolved(crate::skills::SkillActivationResolved {
2890 thread_id: "thread-a".to_string(),
2891 turn_id: "turn-a".to_string(),
2892 selector: crate::skills::SkillSelector::Name {
2893 name: "commit".to_string(),
2894 },
2895 activation_reason: crate::skills::SkillActivationReason::FeatureBinding,
2896 activated: true,
2897 descriptor: Some(descriptor),
2898 diagnostic: None,
2899 timestamp: OffsetDateTime::UNIX_EPOCH,
2900 });
2901
2902 assert_eq!(event.kind(), "skills/activationResolved");
2903 assert_eq!(event.source(), EventSource::Core);
2904 assert_eq!(event.thread_id().map(String::as_str), Some("thread-a"));
2905 assert_eq!(event.turn_id().map(String::as_str), Some("turn-a"));
2906 }
2907}