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 PatchProgress(crate::patch_progress::PatchProgress),
1506 FileChanged(FileChanged),
1507 TranscriptItemAppended(TranscriptItemAppended),
1508 TurnCompleted(TurnCompleted),
1509 TurnFailed(TurnFailed),
1510 TurnPartialResult(TurnPartialResult),
1511 TurnDeadlineExceeded(TurnDeadlineExceeded),
1512 TurnLifecycleUpdated(TurnLifecycleRecord),
1513 TurnInterrupted(TurnInterrupted),
1514 TurnSteered(TurnSteered),
1515 RunnerLifecycle(RunnerLifecycle),
1516 TeamStarted(TeamStarted),
1517 TeamMemberStarted(TeamMemberStarted),
1518 TeamMemberStatusChanged(TeamMemberStatusChanged),
1519 TeamMemberMessageDelta(TeamMemberMessageDelta),
1520 TeamMemberCompleted(TeamMemberCompleted),
1521 TeamDisplayModeChanged(TeamDisplayModeChanged),
1522 TeamTaskChanged(TeamTaskChanged),
1523 TeamCleanupCompleted(TeamCleanupCompleted),
1524 ReviewStarted(ReviewStarted),
1525 ReviewCompleted(ReviewCompleted),
1526 ReviewFailed(ReviewFailed),
1527 ReviewPublished(ReviewPublished),
1528}
1529
1530impl RoderEvent {
1531 pub fn kind(&self) -> &'static str {
1532 match self {
1533 RoderEvent::RuntimeStarted(_) => "runtime.started",
1534 RoderEvent::ExtensionRegistered(_) => "extension.registered",
1535 RoderEvent::ExtensionEventEmitted(_) => "extension.event",
1536 RoderEvent::EventSinkFailed(_) => "extension.event_sink_failed",
1537 RoderEvent::ThreadCreated(_) => "thread.created",
1538 RoderEvent::ThreadLoaded(_) => "thread.loaded",
1539 RoderEvent::ThreadForkRequested(_) => "thread.fork_requested",
1540 RoderEvent::ThreadForked(_) => "thread.forked",
1541 RoderEvent::ThreadForkFailed(_) => "thread.fork_failed",
1542 RoderEvent::ThreadForkRemoved(_) => "thread.fork_removed",
1543 RoderEvent::TurnStarted(_) => "turn.started",
1544 RoderEvent::ContextAssemblyStarted(_) => "context.assembly_started",
1545 RoderEvent::ContextBlockAdded(_) => "context.block_added",
1546 RoderEvent::ContextAssemblyCompleted(_) => "context.assembly_completed",
1547 RoderEvent::ContextEntrypointCandidatesInjected(_) => {
1548 "context.entrypoint_candidates_injected"
1549 }
1550 RoderEvent::ContextCompactionStarted(_) => "context.compaction_started",
1551 RoderEvent::ContextCompactionRecorded(_) => "context.compaction_recorded",
1552 RoderEvent::ContextCompactionSkipped(_) => "context.compaction_skipped",
1553 RoderEvent::InferenceRoutingDecision(_) => "inference.routing_decision",
1554 RoderEvent::InferenceStarted(_) => "inference.started",
1555 RoderEvent::InferenceEventReceived(_) => "inference.event_received",
1556 RoderEvent::ToolCallRequested(_) => "tool.call_requested",
1557 RoderEvent::HookRunRecorded(_) => "hook.run_recorded",
1558 RoderEvent::ToolCallValidationRecorded(_) => "tool.call_validation",
1559 RoderEvent::ReliabilityFailureRecorded(_) => "reliability.failure",
1560 RoderEvent::ReliabilityRetryRecorded(_) => "reliability.retry",
1561 RoderEvent::ReliabilityLimitRecorded(_) => "reliability.limit",
1562 RoderEvent::ReliabilityMetricRecorded(_) => "reliability.metric",
1563 RoderEvent::CodeIndexingStarted(_) => "code_index.started",
1564 RoderEvent::CodeIndexChunked(_) => "code_index.chunked",
1565 RoderEvent::CodeIndexEmbedded(_) => "code_index.embedded",
1566 RoderEvent::CodeIndexReady(_) => "code_index.ready",
1567 RoderEvent::CodeIndexStale(_) => "code_index.stale",
1568 RoderEvent::CodeIndexFailed(_) => "code_index.failed",
1569 RoderEvent::CodeIndexProofFilteredResultDropped(_) => {
1570 "code_index.proof_filtered_result_dropped"
1571 }
1572 RoderEvent::ApprovalRequested(_) => "approval.requested",
1573 RoderEvent::ApprovalResolved(_) => "approval.resolved",
1574 RoderEvent::ExternalToolCallRequested(_) => "external_tool.requested",
1575 RoderEvent::ExternalToolCallResolved(_) => "external_tool.resolved",
1576 RoderEvent::UserInputRequested(_) => "user_input.requested",
1577 RoderEvent::UserInputResolved(_) => "user_input.resolved",
1578 RoderEvent::TaskLedgerUpdated(_) => "task_ledger.updated",
1579 RoderEvent::VerificationRequired(_) => "verification.required",
1580 RoderEvent::VerificationCompleted(_) => "verification.completed",
1581 RoderEvent::VerificationSkipped(_) => "verification.skipped",
1582 RoderEvent::PolicyDecisionRecorded(_) => "policy.decision",
1583 RoderEvent::PolicyBypassActive(_) => "policy.bypass_active",
1584 RoderEvent::PolicyModeChanged(_) => "policy.mode_changed",
1585 RoderEvent::AgentSwarmModeChanged(_) => "agent_swarm.mode_changed",
1586 RoderEvent::AgentSwarmStarted(_) => "agent_swarm.started",
1587 RoderEvent::AgentSwarmProgress(_) => "agent_swarm.progress",
1588 RoderEvent::AgentSwarmCompleted(_) => "agent_swarm.completed",
1589 RoderEvent::UltraModeChanged(_) => "ultra.mode_changed",
1590 RoderEvent::PolicyExitPlanRequested(_) => "policy.exit_plan_requested",
1591 RoderEvent::PolicyExitPlanResolved(_) => "policy.exit_plan_resolved",
1592 RoderEvent::ToolCallStarted(_) => "tool.call_started",
1593 RoderEvent::ToolCallCompleted(_) => "tool.call_completed",
1594 RoderEvent::ToolOutputDelta(_) => "tool.output_delta",
1595 RoderEvent::ToolOutputTruncated(_) => "tool.output_truncated",
1596 RoderEvent::SubagentStarted(_) => "subagent.started",
1597 RoderEvent::SubagentMessage(_) => "subagent.message",
1598 RoderEvent::SubagentToolCall(_) => "subagent.tool_call",
1599 RoderEvent::SubagentCompleted(_) => "subagent.completed",
1600 RoderEvent::SubagentFailed(_) => "subagent.failed",
1601 RoderEvent::SubagentTraceCreated(_) => "turn/subagentTraceCreated",
1602 RoderEvent::SubagentTraceDelta(_) => "turn/subagentTraceDelta",
1603 RoderEvent::SubagentTraceStatusChanged(_) => "turn/subagentTraceStatusChanged",
1604 RoderEvent::SubagentTraceCompleted(_) => "turn/subagentTraceCompleted",
1605 RoderEvent::SubagentTraceFailed(_) => "turn/subagentTraceFailed",
1606 RoderEvent::PlanReviewCreated(_) => "plan/reviewCreated",
1607 RoderEvent::PlanReviewStatusChanged(_) => "plan/reviewStatusChanged",
1608 RoderEvent::PlanReviewCommentAdded(_) => "plan/reviewCommentAdded",
1609 RoderEvent::PlanReviewRewritten(_) => "plan/reviewRewritten",
1610 RoderEvent::PlanReviewApproved(_) => "plan/reviewApproved",
1611 RoderEvent::PlanReviewRejected(_) => "plan/reviewRejected",
1612 RoderEvent::HunkRecorded(_) => "hunk/recorded",
1613 RoderEvent::WorkspaceChangeObserved(_) => "workspace/changeObserved",
1614 RoderEvent::HunkRollbackRequested(_) => "hunk/rollbackRequested",
1615 RoderEvent::HunkRollbackCompleted(_) => "hunk/rollbackCompleted",
1616 RoderEvent::WorkflowImportsDetected(_) => "workflow/importsDetected",
1617 RoderEvent::WorkflowImportPreviewed(_) => "workflow/importPreviewed",
1618 RoderEvent::WorkflowImportEnabled(_) => "workflow/importEnabled",
1619 RoderEvent::WorkflowImportDisabled(_) => "workflow/importDisabled",
1620 RoderEvent::WorkflowImportStale(_) => "workflow/importStale",
1621 RoderEvent::WorkflowImportFailed(_) => "workflow/importFailed",
1622 RoderEvent::WorkflowRunDrafted(_) => "workflows/drafted",
1623 RoderEvent::WorkflowApprovalRequested(_) => "workflows/approvalRequested",
1624 RoderEvent::WorkflowRunApproved(_) => "workflows/approved",
1625 RoderEvent::WorkflowRunDenied(_) => "workflows/denied",
1626 RoderEvent::WorkflowRunQueued(_) => "workflows/queued",
1627 RoderEvent::WorkflowRunStarted(_) => "workflows/started",
1628 RoderEvent::WorkflowPhaseStarted(_) => "workflows/phaseStarted",
1629 RoderEvent::WorkflowPhaseCompleted(_) => "workflows/phaseCompleted",
1630 RoderEvent::WorkflowAgentQueued(_) => "workflows/agentQueued",
1631 RoderEvent::WorkflowAgentStarted(_) => "workflows/agentStarted",
1632 RoderEvent::WorkflowAgentCompleted(_) => "workflows/agentCompleted",
1633 RoderEvent::WorkflowAgentFailed(_) => "workflows/agentFailed",
1634 RoderEvent::WorkflowOutputRecorded(_) => "workflows/outputRecorded",
1635 RoderEvent::WorkflowCheckpointRecorded(_) => "workflows/checkpointRecorded",
1636 RoderEvent::WorkflowRunPaused(_) => "workflows/paused",
1637 RoderEvent::WorkflowRunResumed(_) => "workflows/resumed",
1638 RoderEvent::WorkflowRunStopped(_) => "workflows/stopped",
1639 RoderEvent::WorkflowRunCompleted(_) => "workflows/completed",
1640 RoderEvent::WorkflowRunFailed(_) => "workflows/failed",
1641 RoderEvent::MediaArtifactCreated(_) => "media/artifactCreated",
1642 RoderEvent::MediaArtifactUpdated(_) => "media/artifactUpdated",
1643 RoderEvent::MediaArtifactDeleted(_) => "media/artifactDeleted",
1644 RoderEvent::MediaPreviewReady(_) => "media/previewReady",
1645 RoderEvent::ContextArtifactCreated(_) => "artifact/created",
1646 RoderEvent::ContextArtifactAppended(_) => "artifact/appended",
1647 RoderEvent::ContextArtifactCapped(_) => "artifact/capped",
1648 RoderEvent::ContextArtifactDeleted(_) => "artifact/deleted",
1649 RoderEvent::ContextArtifactRetentionExpired(_) => "artifact/retentionExpired",
1650 RoderEvent::DiscoveryCatalogBuilt(_) => "discovery/catalogBuilt",
1651 RoderEvent::DiscoveryItemUpdated(_) => "discovery/itemUpdated",
1652 RoderEvent::DiscoveryAuthRequired(_) => "discovery/authRequired",
1653 RoderEvent::DiscoveryItemRead(_) => "discovery/itemRead",
1654 RoderEvent::DiscoveryItemPromoted(_) => "discovery/itemPromoted",
1655 RoderEvent::DiscoveryPromotionReused(_) => "discovery/promotionReused",
1656 RoderEvent::DiscoveryWarmCacheHit(_) => "discovery/warmCacheHit",
1657 RoderEvent::DiscoveryPromotionExpired(_) => "discovery/promotionExpired",
1658 RoderEvent::RetrievalRoutePlanned(_) => "retrieval/routePlanned",
1659 RoderEvent::RetrievalRouteAccepted(_) => "retrieval/routeAccepted",
1660 RoderEvent::RetrievalRouteIgnored(_) => "retrieval/routeIgnored",
1661 RoderEvent::RetrievalRouteFailed(_) => "retrieval/routeFailed",
1662 RoderEvent::RetrievalResultUsed(_) => "retrieval/resultUsed",
1663 RoderEvent::RetrievalDiscoveryItemPromoted(_) => "retrieval/discoveryItemPromoted",
1664 RoderEvent::RetrievalPromotionSkipped(_) => "retrieval/promotionSkipped",
1665 RoderEvent::MemorySaved(_) => "memory/saved",
1666 RoderEvent::MemoryUpdated(_) => "memory/updated",
1667 RoderEvent::MemoryDeleted(_) => "memory/deleted",
1668 RoderEvent::MemoryQueried(_) => "memory/queried",
1669 RoderEvent::MemoryRecallReady(_) => "memory/recallReady",
1670 RoderEvent::MemoryReembedQueued(_) => "memory/reembedQueued",
1671 RoderEvent::MemoryProviderChanged(_) => "memory/providerChanged",
1672 RoderEvent::MemoryObservationRecorded(_) => "memory/observationRecorded",
1673 RoderEvent::KnowledgeSaved(_) => "knowledge/saved",
1674 RoderEvent::KnowledgeUpdated(_) => "knowledge/updated",
1675 RoderEvent::KnowledgeArchived(_) => "knowledge/archived",
1676 RoderEvent::KnowledgeLinked(_) => "knowledge/linked",
1677 RoderEvent::RemoteServerStarted(_) => "remote/serverStarted",
1678 RoderEvent::RemoteServerStopped(_) => "remote/serverStopped",
1679 RoderEvent::RemoteAuthFailed(_) => "remote/authFailed",
1680 RoderEvent::RemoteClientConnected(_) => "remote/clientConnected",
1681 RoderEvent::RemoteClientDisconnected(_) => "remote/clientDisconnected",
1682 RoderEvent::ThreadGoalUpdated(_) => "thread/goal/updated",
1683 RoderEvent::ThreadGoalCleared(_) => "thread/goal/cleared",
1684 RoderEvent::RoadmapChanged(_) => "roadmap.changed",
1685 RoderEvent::AutomationCreated(_) => "automations/created",
1686 RoderEvent::AutomationUpdated(_) => "automations/updated",
1687 RoderEvent::AutomationDeleted(_) => "automations/deleted",
1688 RoderEvent::AutomationDue(_) => "automations/due",
1689 RoderEvent::AutomationLeased(_) => "automations/leased",
1690 RoderEvent::AutomationQueued(_) => "automations/queued",
1691 RoderEvent::AutomationStarted(_) => "automations/started",
1692 RoderEvent::AutomationCompleted(_) => "automations/completed",
1693 RoderEvent::AutomationFailed(_) => "automations/failed",
1694 RoderEvent::AutomationSkipped(_) => "automations/skipped",
1695 RoderEvent::AutomationLeaseExpired(_) => "automations/leaseExpired",
1696 RoderEvent::SkillsCatalogLoaded(_) => "skills/catalogLoaded",
1697 RoderEvent::SkillConfigApplied(_) => "skills/configApplied",
1698 RoderEvent::SkillActivationResolved(_) => "skills/activationResolved",
1699 RoderEvent::SkillIndexRendered(_) => "skills/indexRendered",
1700 RoderEvent::SkillInvoked(_) => "skills/invoked",
1701 RoderEvent::SkillAutoActivated(_) => "skills/autoActivated",
1702 RoderEvent::SkillSkipped(_) => "skills/skipped",
1703 RoderEvent::TaskStarted(_) => "task.started",
1704 RoderEvent::TaskOutput(_) => "task.output",
1705 RoderEvent::TaskCompleted(_) => "task.completed",
1706 RoderEvent::TaskFailed(_) => "task.failed",
1707 RoderEvent::TaskCancelled(_) => "task.cancelled",
1708 RoderEvent::ProcessStarted(_) => "process.started",
1709 RoderEvent::ProcessOutput(_) => "process.output",
1710 RoderEvent::ProcessExited(_) => "process.exited",
1711 RoderEvent::ProcessStopping(_) => "process.stopping",
1712 RoderEvent::ProcessStopped(_) => "process.stopped",
1713 RoderEvent::ProcessFailed(_) => "process.failed",
1714 RoderEvent::FileChangePreviewReady(_) => "file.change_preview_ready",
1715 RoderEvent::PatchProgress(_) => "patch/progress",
1716 RoderEvent::FileChanged(_) => "file.changed",
1717 RoderEvent::TranscriptItemAppended(_) => "turn.transcript_item_appended",
1718 RoderEvent::TurnCompleted(_) => "turn.completed",
1719 RoderEvent::TurnFailed(_) => "turn.failed",
1720 RoderEvent::TurnPartialResult(_) => "turn.partial_result",
1721 RoderEvent::TurnDeadlineExceeded(_) => "turn.deadline_exceeded",
1722 RoderEvent::TurnLifecycleUpdated(_) => "turn.lifecycle_updated",
1723 RoderEvent::TurnInterrupted(_) => "turn.interrupted",
1724 RoderEvent::TurnSteered(_) => "turn.steered",
1725 RoderEvent::RunnerLifecycle(_) => "runner.lifecycle",
1726 RoderEvent::TeamStarted(_) => "team.started",
1727 RoderEvent::TeamMemberStarted(_) => "team.member_started",
1728 RoderEvent::TeamMemberStatusChanged(_) => "team.member_status_changed",
1729 RoderEvent::TeamMemberMessageDelta(_) => "team.member_message_delta",
1730 RoderEvent::TeamMemberCompleted(_) => "team.member_completed",
1731 RoderEvent::TeamDisplayModeChanged(_) => "team.display_mode_changed",
1732 RoderEvent::TeamTaskChanged(_) => "team.task_changed",
1733 RoderEvent::TeamCleanupCompleted(_) => "team.cleanup_completed",
1734 RoderEvent::ReviewStarted(_) => "review.started",
1735 RoderEvent::ReviewCompleted(_) => "review.completed",
1736 RoderEvent::ReviewFailed(_) => "review.failed",
1737 RoderEvent::ReviewPublished(_) => "review.published",
1738 }
1739 }
1740
1741 pub fn source(&self) -> EventSource {
1742 match self {
1743 RoderEvent::InferenceEventReceived(_) | RoderEvent::InferenceStarted(_) => {
1744 EventSource::Provider
1745 }
1746 RoderEvent::InferenceRoutingDecision(_) => EventSource::Core,
1747 RoderEvent::ReliabilityRetryRecorded(_) => EventSource::Provider,
1748 RoderEvent::ReliabilityFailureRecorded(_)
1749 | RoderEvent::ReliabilityLimitRecorded(_)
1750 | RoderEvent::ReliabilityMetricRecorded(_) => EventSource::Core,
1751 RoderEvent::ToolCallRequested(_)
1752 | RoderEvent::ToolCallValidationRecorded(_)
1753 | RoderEvent::ToolCallStarted(_)
1754 | RoderEvent::ToolCallCompleted(_) => EventSource::Tool,
1755 RoderEvent::ToolOutputDelta(_) => EventSource::Tool,
1756 RoderEvent::SubagentStarted(_)
1757 | RoderEvent::SubagentMessage(_)
1758 | RoderEvent::SubagentToolCall(_)
1759 | RoderEvent::SubagentCompleted(_)
1760 | RoderEvent::SubagentFailed(_)
1761 | RoderEvent::SubagentTraceCreated(_)
1762 | RoderEvent::SubagentTraceDelta(_)
1763 | RoderEvent::SubagentTraceStatusChanged(_)
1764 | RoderEvent::SubagentTraceCompleted(_)
1765 | RoderEvent::SubagentTraceFailed(_)
1766 | RoderEvent::PlanReviewCreated(_)
1767 | RoderEvent::PlanReviewStatusChanged(_)
1768 | RoderEvent::PlanReviewCommentAdded(_)
1769 | RoderEvent::PlanReviewRewritten(_)
1770 | RoderEvent::PlanReviewApproved(_)
1771 | RoderEvent::PlanReviewRejected(_)
1772 | RoderEvent::HunkRecorded(_)
1773 | RoderEvent::WorkspaceChangeObserved(_)
1774 | RoderEvent::HunkRollbackRequested(_)
1775 | RoderEvent::HunkRollbackCompleted(_)
1776 | RoderEvent::WorkflowImportsDetected(_)
1777 | RoderEvent::WorkflowImportPreviewed(_)
1778 | RoderEvent::WorkflowImportEnabled(_)
1779 | RoderEvent::WorkflowImportDisabled(_)
1780 | RoderEvent::WorkflowImportStale(_)
1781 | RoderEvent::WorkflowImportFailed(_)
1782 | RoderEvent::MediaArtifactCreated(_)
1783 | RoderEvent::MediaArtifactUpdated(_)
1784 | RoderEvent::MediaArtifactDeleted(_)
1785 | RoderEvent::MediaPreviewReady(_)
1786 | RoderEvent::ContextArtifactCreated(_)
1787 | RoderEvent::ContextArtifactAppended(_)
1788 | RoderEvent::ContextArtifactCapped(_)
1789 | RoderEvent::ContextArtifactDeleted(_)
1790 | RoderEvent::ContextArtifactRetentionExpired(_)
1791 | RoderEvent::DiscoveryCatalogBuilt(_)
1792 | RoderEvent::DiscoveryItemUpdated(_)
1793 | RoderEvent::DiscoveryAuthRequired(_)
1794 | RoderEvent::DiscoveryItemRead(_)
1795 | RoderEvent::DiscoveryItemPromoted(_)
1796 | RoderEvent::DiscoveryPromotionReused(_)
1797 | RoderEvent::DiscoveryWarmCacheHit(_)
1798 | RoderEvent::DiscoveryPromotionExpired(_)
1799 | RoderEvent::RetrievalRoutePlanned(_)
1800 | RoderEvent::RetrievalRouteAccepted(_)
1801 | RoderEvent::RetrievalRouteIgnored(_)
1802 | RoderEvent::RetrievalRouteFailed(_)
1803 | RoderEvent::RetrievalResultUsed(_)
1804 | RoderEvent::RetrievalDiscoveryItemPromoted(_)
1805 | RoderEvent::RetrievalPromotionSkipped(_)
1806 | RoderEvent::MemorySaved(_)
1807 | RoderEvent::MemoryUpdated(_)
1808 | RoderEvent::MemoryDeleted(_)
1809 | RoderEvent::MemoryQueried(_)
1810 | RoderEvent::MemoryRecallReady(_)
1811 | RoderEvent::MemoryReembedQueued(_)
1812 | RoderEvent::MemoryProviderChanged(_)
1813 | RoderEvent::MemoryObservationRecorded(_)
1814 | RoderEvent::TaskStarted(_)
1815 | RoderEvent::TaskOutput(_)
1816 | RoderEvent::TaskCompleted(_)
1817 | RoderEvent::TaskFailed(_)
1818 | RoderEvent::TaskCancelled(_)
1819 | RoderEvent::ProcessStarted(_)
1820 | RoderEvent::ProcessOutput(_)
1821 | RoderEvent::ProcessExited(_)
1822 | RoderEvent::ProcessStopping(_)
1823 | RoderEvent::ProcessStopped(_)
1824 | RoderEvent::ProcessFailed(_) => EventSource::Extension,
1825 RoderEvent::RemoteServerStarted(_)
1826 | RoderEvent::RemoteServerStopped(_)
1827 | RoderEvent::RemoteAuthFailed(_)
1828 | RoderEvent::RemoteClientConnected(_)
1829 | RoderEvent::RemoteClientDisconnected(_) => EventSource::AppServer,
1830 RoderEvent::RoadmapChanged(_)
1831 | RoderEvent::ThreadGoalUpdated(_)
1832 | RoderEvent::ThreadGoalCleared(_)
1833 | RoderEvent::AutomationCreated(_)
1834 | RoderEvent::AutomationUpdated(_)
1835 | RoderEvent::AutomationDeleted(_)
1836 | RoderEvent::AutomationDue(_)
1837 | RoderEvent::AutomationLeased(_)
1838 | RoderEvent::AutomationQueued(_)
1839 | RoderEvent::AutomationStarted(_)
1840 | RoderEvent::AutomationCompleted(_)
1841 | RoderEvent::AutomationFailed(_)
1842 | RoderEvent::AutomationSkipped(_)
1843 | RoderEvent::AutomationLeaseExpired(_)
1844 | RoderEvent::SkillsCatalogLoaded(_)
1845 | RoderEvent::SkillConfigApplied(_)
1846 | RoderEvent::SkillActivationResolved(_)
1847 | RoderEvent::SkillIndexRendered(_)
1848 | RoderEvent::SkillInvoked(_)
1849 | RoderEvent::SkillAutoActivated(_)
1850 | RoderEvent::SkillSkipped(_) => EventSource::Core,
1851 RoderEvent::FileChangePreviewReady(_) | RoderEvent::PatchProgress(_) => {
1852 EventSource::Tool
1853 }
1854 RoderEvent::UserInputRequested(_)
1855 | RoderEvent::UserInputResolved(_)
1856 | RoderEvent::TaskLedgerUpdated(_)
1857 | RoderEvent::TurnPartialResult(_)
1858 | RoderEvent::TurnDeadlineExceeded(_)
1859 | RoderEvent::TurnLifecycleUpdated(_)
1860 | RoderEvent::VerificationRequired(_)
1861 | RoderEvent::VerificationCompleted(_)
1862 | RoderEvent::VerificationSkipped(_) => EventSource::Core,
1863 RoderEvent::ExtensionRegistered(_) => EventSource::Extension,
1864 RoderEvent::RunnerLifecycle(_) => EventSource::Extension,
1865 RoderEvent::TeamStarted(_)
1866 | RoderEvent::TeamMemberStarted(_)
1867 | RoderEvent::TeamMemberStatusChanged(_)
1868 | RoderEvent::TeamMemberMessageDelta(_)
1869 | RoderEvent::TeamMemberCompleted(_)
1870 | RoderEvent::TeamDisplayModeChanged(_)
1871 | RoderEvent::TeamTaskChanged(_)
1872 | RoderEvent::TeamCleanupCompleted(_) => EventSource::Core,
1873 RoderEvent::ReviewStarted(_)
1874 | RoderEvent::ReviewCompleted(_)
1875 | RoderEvent::ReviewFailed(_) => EventSource::Core,
1876 RoderEvent::ReviewPublished(_) => EventSource::Extension,
1877 _ => EventSource::Core,
1878 }
1879 }
1880
1881 pub fn thread_id(&self) -> Option<&ThreadId> {
1882 match self {
1883 RoderEvent::ExtensionEventEmitted(_) | RoderEvent::EventSinkFailed(_) => None,
1884 RoderEvent::ThreadCreated(e) => Some(&e.thread_id),
1885 RoderEvent::ThreadLoaded(e) => Some(&e.thread_id),
1886 RoderEvent::ThreadForkRequested(e) => Some(&e.parent_thread_id),
1887 RoderEvent::ThreadForked(e) => Some(&e.child_thread_id),
1888 RoderEvent::ThreadForkFailed(e) => Some(&e.parent_thread_id),
1889 RoderEvent::ThreadForkRemoved(e) => Some(&e.thread_id),
1890 RoderEvent::TurnStarted(e) => Some(&e.thread_id),
1891 RoderEvent::ContextAssemblyStarted(e) => Some(&e.thread_id),
1892 RoderEvent::ContextBlockAdded(e) => Some(&e.thread_id),
1893 RoderEvent::ContextAssemblyCompleted(e) => Some(&e.thread_id),
1894 RoderEvent::ContextEntrypointCandidatesInjected(e) => Some(&e.thread_id),
1895 RoderEvent::ContextCompactionStarted(e) => Some(&e.thread_id),
1896 RoderEvent::ContextCompactionRecorded(e) => Some(&e.thread_id),
1897 RoderEvent::ContextCompactionSkipped(e) => Some(&e.thread_id),
1898 RoderEvent::InferenceRoutingDecision(e) => Some(&e.thread_id),
1899 RoderEvent::InferenceStarted(e) => Some(&e.thread_id),
1900 RoderEvent::InferenceEventReceived(e) => Some(&e.thread_id),
1901 RoderEvent::ToolCallRequested(e) => Some(&e.thread_id),
1902 RoderEvent::HookRunRecorded(e) => Some(&e.thread_id),
1903 RoderEvent::ToolCallValidationRecorded(e) => Some(&e.thread_id),
1904 RoderEvent::ReliabilityFailureRecorded(e) => Some(&e.context.thread_id),
1905 RoderEvent::ReliabilityRetryRecorded(e) => Some(&e.context.thread_id),
1906 RoderEvent::ReliabilityLimitRecorded(e) => Some(&e.context.thread_id),
1907 RoderEvent::ReliabilityMetricRecorded(e) => Some(&e.context.thread_id),
1908 RoderEvent::CodeIndexingStarted(e) => e.context.thread_id.as_ref(),
1909 RoderEvent::CodeIndexChunked(e) => e.context.thread_id.as_ref(),
1910 RoderEvent::CodeIndexEmbedded(e) => e.context.thread_id.as_ref(),
1911 RoderEvent::CodeIndexReady(_) => None,
1912 RoderEvent::CodeIndexStale(e) => e.context.thread_id.as_ref(),
1913 RoderEvent::CodeIndexFailed(e) => e.context.thread_id.as_ref(),
1914 RoderEvent::CodeIndexProofFilteredResultDropped(e) => e.context.thread_id.as_ref(),
1915 RoderEvent::ApprovalRequested(e) => Some(&e.thread_id),
1916 RoderEvent::ApprovalResolved(e) => Some(&e.thread_id),
1917 RoderEvent::ExternalToolCallRequested(e) => Some(&e.thread_id),
1918 RoderEvent::ExternalToolCallResolved(e) => Some(&e.thread_id),
1919 RoderEvent::UserInputRequested(e) => Some(&e.thread_id),
1920 RoderEvent::UserInputResolved(e) => Some(&e.thread_id),
1921 RoderEvent::TaskLedgerUpdated(e) => Some(&e.thread_id),
1922 RoderEvent::VerificationRequired(e) => Some(&e.thread_id),
1923 RoderEvent::VerificationCompleted(e) => Some(&e.thread_id),
1924 RoderEvent::VerificationSkipped(e) => Some(&e.thread_id),
1925 RoderEvent::PolicyDecisionRecorded(e) => Some(&e.thread_id),
1926 RoderEvent::PolicyBypassActive(e) => Some(&e.thread_id),
1927 RoderEvent::PolicyModeChanged(e) => Some(&e.thread_id),
1928 RoderEvent::AgentSwarmModeChanged(e) => Some(&e.thread_id),
1929 RoderEvent::AgentSwarmStarted(e) => Some(&e.thread_id),
1930 RoderEvent::AgentSwarmProgress(e) => Some(&e.thread_id),
1931 RoderEvent::AgentSwarmCompleted(e) => Some(&e.thread_id),
1932 RoderEvent::UltraModeChanged(e) => Some(&e.thread_id),
1933 RoderEvent::PolicyExitPlanRequested(e) => Some(&e.thread_id),
1934 RoderEvent::PolicyExitPlanResolved(e) => Some(&e.thread_id),
1935 RoderEvent::ToolCallStarted(e) => Some(&e.thread_id),
1936 RoderEvent::ToolCallCompleted(e) => Some(&e.thread_id),
1937 RoderEvent::ToolOutputDelta(e) => Some(&e.thread_id),
1938 RoderEvent::ToolOutputTruncated(e) => Some(&e.thread_id),
1939 RoderEvent::SubagentStarted(e) => Some(&e.thread_id),
1940 RoderEvent::SubagentMessage(e) => Some(&e.thread_id),
1941 RoderEvent::SubagentToolCall(e) => Some(&e.thread_id),
1942 RoderEvent::SubagentCompleted(e) => Some(&e.thread_id),
1943 RoderEvent::SubagentFailed(e) => Some(&e.thread_id),
1944 RoderEvent::SubagentTraceCreated(e) => Some(&e.summary.parent.thread_id),
1945 RoderEvent::SubagentTraceDelta(e) => Some(&e.delta.parent.thread_id),
1946 RoderEvent::SubagentTraceStatusChanged(e) => Some(&e.parent.thread_id),
1947 RoderEvent::SubagentTraceCompleted(e) => Some(&e.summary.parent.thread_id),
1948 RoderEvent::SubagentTraceFailed(e) => Some(&e.summary.parent.thread_id),
1949 RoderEvent::PlanReviewCreated(e) => Some(&e.review.thread_id),
1950 RoderEvent::PlanReviewStatusChanged(e) => Some(&e.thread_id),
1951 RoderEvent::PlanReviewCommentAdded(e) => Some(&e.thread_id),
1952 RoderEvent::PlanReviewRewritten(e) => Some(&e.thread_id),
1953 RoderEvent::PlanReviewApproved(e) => Some(&e.thread_id),
1954 RoderEvent::PlanReviewRejected(e) => Some(&e.thread_id),
1955 RoderEvent::HunkRecorded(e) => Some(&e.hunk.thread_id),
1956 RoderEvent::WorkspaceChangeObserved(e) => Some(&e.change.thread_id),
1957 RoderEvent::HunkRollbackRequested(e) => Some(&e.thread_id),
1958 RoderEvent::HunkRollbackCompleted(e) => Some(&e.thread_id),
1959 RoderEvent::MediaArtifactCreated(e) => Some(&e.thread_id),
1960 RoderEvent::MediaArtifactUpdated(e) => Some(&e.thread_id),
1961 RoderEvent::MediaPreviewReady(e) => Some(&e.thread_id),
1962 RoderEvent::ContextArtifactCreated(e) => Some(&e.thread_id),
1963 RoderEvent::ContextArtifactAppended(e) => Some(&e.thread_id),
1964 RoderEvent::ContextArtifactCapped(e) => Some(&e.thread_id),
1965 RoderEvent::ContextArtifactDeleted(e) => Some(&e.thread_id),
1966 RoderEvent::ContextArtifactRetentionExpired(e) => Some(&e.thread_id),
1967 RoderEvent::DiscoveryItemRead(e) => Some(&e.thread_id),
1968 RoderEvent::DiscoveryItemPromoted(e) => Some(&e.record.thread_id),
1969 RoderEvent::DiscoveryPromotionReused(e) => Some(&e.record.thread_id),
1970 RoderEvent::DiscoveryWarmCacheHit(e) => Some(&e.record.thread_id),
1971 RoderEvent::DiscoveryPromotionExpired(e) => Some(&e.record.thread_id),
1972 RoderEvent::RetrievalRoutePlanned(e) => Some(&e.plan.thread_id),
1973 RoderEvent::RetrievalRouteAccepted(e) => Some(&e.thread_id),
1974 RoderEvent::RetrievalRouteIgnored(e) => Some(&e.thread_id),
1975 RoderEvent::RetrievalRouteFailed(e) => Some(&e.thread_id),
1976 RoderEvent::RetrievalResultUsed(e) => Some(&e.thread_id),
1977 RoderEvent::RetrievalDiscoveryItemPromoted(e) => Some(&e.thread_id),
1978 RoderEvent::RetrievalPromotionSkipped(e) => Some(&e.thread_id),
1979 RoderEvent::MemoryRecallReady(e) => Some(&e.thread_id),
1980 RoderEvent::MemoryObservationRecorded(e) => Some(&e.thread_id),
1981 RoderEvent::TaskStarted(e) => e.thread_id.as_ref(),
1982 RoderEvent::TaskOutput(e) => e.thread_id.as_ref(),
1983 RoderEvent::TaskCompleted(e) => e.thread_id.as_ref(),
1984 RoderEvent::TaskFailed(e) => e.thread_id.as_ref(),
1985 RoderEvent::TaskCancelled(e) => e.thread_id.as_ref(),
1986 RoderEvent::FileChangePreviewReady(e) => Some(&e.thread_id),
1987 RoderEvent::PatchProgress(e) => Some(&e.thread_id),
1988 RoderEvent::FileChanged(e) => Some(&e.thread_id),
1989 RoderEvent::TranscriptItemAppended(e) => Some(&e.thread_id),
1990 RoderEvent::TurnCompleted(e) => Some(&e.thread_id),
1991 RoderEvent::TurnFailed(e) => Some(&e.thread_id),
1992 RoderEvent::TurnPartialResult(e) => Some(&e.thread_id),
1993 RoderEvent::TurnDeadlineExceeded(e) => Some(&e.thread_id),
1994 RoderEvent::TurnLifecycleUpdated(e) => Some(&e.thread_id),
1995 RoderEvent::TurnInterrupted(e) => Some(&e.thread_id),
1996 RoderEvent::TurnSteered(e) => Some(&e.thread_id),
1997 RoderEvent::ThreadGoalUpdated(e) => Some(&e.thread_id),
1998 RoderEvent::ThreadGoalCleared(e) => Some(&e.thread_id),
1999 RoderEvent::TeamStarted(e) => Some(&e.lead_thread_id),
2000 RoderEvent::TeamMemberStarted(e) => Some(&e.member.thread_id),
2001 RoderEvent::TeamMemberStatusChanged(e) => Some(&e.member_thread_id),
2002 RoderEvent::TeamMemberMessageDelta(e) => Some(&e.member_thread_id),
2003 RoderEvent::TeamMemberCompleted(e) => Some(&e.member_thread_id),
2004 RoderEvent::SkillActivationResolved(e) => Some(&e.thread_id),
2005 RoderEvent::SkillIndexRendered(e) => Some(&e.thread_id),
2006 RoderEvent::SkillInvoked(e) => Some(&e.thread_id),
2007 RoderEvent::SkillAutoActivated(e) => Some(&e.thread_id),
2008 RoderEvent::SkillSkipped(e) => Some(&e.thread_id),
2009 RoderEvent::RuntimeStarted(_)
2010 | RoderEvent::ExtensionRegistered(_)
2011 | RoderEvent::WorkflowImportsDetected(_)
2012 | RoderEvent::WorkflowImportPreviewed(_)
2013 | RoderEvent::WorkflowImportEnabled(_)
2014 | RoderEvent::WorkflowImportDisabled(_)
2015 | RoderEvent::WorkflowImportStale(_)
2016 | RoderEvent::WorkflowImportFailed(_)
2017 | RoderEvent::MediaArtifactDeleted(_)
2018 | RoderEvent::DiscoveryCatalogBuilt(_)
2019 | RoderEvent::DiscoveryItemUpdated(_)
2020 | RoderEvent::DiscoveryAuthRequired(_)
2021 | RoderEvent::MemorySaved(_)
2022 | RoderEvent::MemoryUpdated(_)
2023 | RoderEvent::MemoryDeleted(_)
2024 | RoderEvent::MemoryQueried(_)
2025 | RoderEvent::MemoryReembedQueued(_)
2026 | RoderEvent::MemoryProviderChanged(_)
2027 | RoderEvent::KnowledgeSaved(_)
2028 | RoderEvent::KnowledgeUpdated(_)
2029 | RoderEvent::KnowledgeArchived(_)
2030 | RoderEvent::KnowledgeLinked(_)
2031 | RoderEvent::RemoteServerStarted(_)
2032 | RoderEvent::RemoteServerStopped(_)
2033 | RoderEvent::RemoteAuthFailed(_)
2034 | RoderEvent::RemoteClientConnected(_)
2035 | RoderEvent::RemoteClientDisconnected(_)
2036 | RoderEvent::RoadmapChanged(_)
2037 | RoderEvent::AutomationCreated(_)
2038 | RoderEvent::AutomationUpdated(_)
2039 | RoderEvent::AutomationDeleted(_)
2040 | RoderEvent::AutomationDue(_)
2041 | RoderEvent::AutomationLeased(_)
2042 | RoderEvent::AutomationQueued(_)
2043 | RoderEvent::AutomationSkipped(_)
2044 | RoderEvent::AutomationLeaseExpired(_)
2045 | RoderEvent::SkillsCatalogLoaded(_)
2046 | RoderEvent::SkillConfigApplied(_)
2047 | RoderEvent::RunnerLifecycle(_)
2048 | RoderEvent::TeamDisplayModeChanged(_)
2049 | RoderEvent::TeamTaskChanged(_)
2050 | RoderEvent::TeamCleanupCompleted(_) => None,
2051 RoderEvent::ProcessStarted(e) => e.process.thread_id.as_ref(),
2052 RoderEvent::ProcessOutput(e) => e.thread_id.as_ref(),
2053 RoderEvent::ProcessExited(e) => e.process.thread_id.as_ref(),
2054 RoderEvent::ProcessStopping(_) => None,
2055 RoderEvent::ProcessStopped(e) => e.process.thread_id.as_ref(),
2056 RoderEvent::ProcessFailed(e) => e.process.thread_id.as_ref(),
2057 RoderEvent::AutomationStarted(e) => e.run.thread_id.as_ref(),
2058 RoderEvent::AutomationCompleted(e) => e.run.thread_id.as_ref(),
2059 RoderEvent::AutomationFailed(e) => e.run.thread_id.as_ref(),
2060 RoderEvent::WorkflowRunDrafted(e) => e.thread_id.as_ref(),
2061 RoderEvent::WorkflowApprovalRequested(e) => e.thread_id.as_ref(),
2062 RoderEvent::WorkflowRunApproved(e) => e.thread_id.as_ref(),
2063 RoderEvent::WorkflowRunDenied(e) => e.thread_id.as_ref(),
2064 RoderEvent::WorkflowRunQueued(e) => e.thread_id.as_ref(),
2065 RoderEvent::WorkflowRunStarted(e) => e.thread_id.as_ref(),
2066 RoderEvent::WorkflowPhaseStarted(e) => e.thread_id.as_ref(),
2067 RoderEvent::WorkflowPhaseCompleted(e) => e.thread_id.as_ref(),
2068 RoderEvent::WorkflowAgentQueued(e) => e.thread_id.as_ref(),
2069 RoderEvent::WorkflowAgentStarted(e) => e.thread_id.as_ref(),
2070 RoderEvent::WorkflowAgentCompleted(e) => e.thread_id.as_ref(),
2071 RoderEvent::WorkflowAgentFailed(e) => e.thread_id.as_ref(),
2072 RoderEvent::WorkflowOutputRecorded(e) => e.thread_id.as_ref(),
2073 RoderEvent::WorkflowCheckpointRecorded(e) => e.thread_id.as_ref(),
2074 RoderEvent::WorkflowRunPaused(e) => e.thread_id.as_ref(),
2075 RoderEvent::WorkflowRunResumed(e) => e.thread_id.as_ref(),
2076 RoderEvent::WorkflowRunStopped(e) => e.thread_id.as_ref(),
2077 RoderEvent::WorkflowRunCompleted(e) => e.thread_id.as_ref(),
2078 RoderEvent::WorkflowRunFailed(e) => e.thread_id.as_ref(),
2079 RoderEvent::ReviewStarted(e) => Some(&e.thread_id),
2080 RoderEvent::ReviewCompleted(e) => Some(&e.thread_id),
2081 RoderEvent::ReviewFailed(e) => Some(&e.thread_id),
2082 RoderEvent::ReviewPublished(e) => e.thread_id.as_ref(),
2083 }
2084 }
2085
2086 pub fn turn_id(&self) -> Option<&TurnId> {
2087 match self {
2088 RoderEvent::ExtensionEventEmitted(_) | RoderEvent::EventSinkFailed(_) => None,
2089 RoderEvent::ThreadForkRequested(_)
2090 | RoderEvent::ThreadForked(_)
2091 | RoderEvent::ThreadForkFailed(_)
2092 | RoderEvent::ThreadForkRemoved(_) => None,
2093 RoderEvent::TurnStarted(e) => Some(&e.turn_id),
2094 RoderEvent::ContextAssemblyStarted(e) => Some(&e.turn_id),
2095 RoderEvent::ContextBlockAdded(e) => Some(&e.turn_id),
2096 RoderEvent::ContextAssemblyCompleted(e) => Some(&e.turn_id),
2097 RoderEvent::ContextEntrypointCandidatesInjected(e) => Some(&e.turn_id),
2098 RoderEvent::ContextCompactionStarted(e) => Some(&e.turn_id),
2099 RoderEvent::ContextCompactionRecorded(e) => Some(&e.turn_id),
2100 RoderEvent::ContextCompactionSkipped(e) => Some(&e.turn_id),
2101 RoderEvent::InferenceRoutingDecision(e) => Some(&e.turn_id),
2102 RoderEvent::InferenceStarted(e) => Some(&e.turn_id),
2103 RoderEvent::InferenceEventReceived(e) => Some(&e.turn_id),
2104 RoderEvent::ToolCallRequested(e) => Some(&e.turn_id),
2105 RoderEvent::HookRunRecorded(e) => Some(&e.turn_id),
2106 RoderEvent::ToolCallValidationRecorded(e) => Some(&e.turn_id),
2107 RoderEvent::ReliabilityFailureRecorded(e) => Some(&e.context.turn_id),
2108 RoderEvent::ReliabilityRetryRecorded(e) => Some(&e.context.turn_id),
2109 RoderEvent::ReliabilityLimitRecorded(e) => Some(&e.context.turn_id),
2110 RoderEvent::ReliabilityMetricRecorded(e) => Some(&e.context.turn_id),
2111 RoderEvent::CodeIndexingStarted(e) => e.context.turn_id.as_ref(),
2112 RoderEvent::CodeIndexChunked(e) => e.context.turn_id.as_ref(),
2113 RoderEvent::CodeIndexEmbedded(e) => e.context.turn_id.as_ref(),
2114 RoderEvent::CodeIndexReady(_) => None,
2115 RoderEvent::CodeIndexStale(e) => e.context.turn_id.as_ref(),
2116 RoderEvent::CodeIndexFailed(e) => e.context.turn_id.as_ref(),
2117 RoderEvent::CodeIndexProofFilteredResultDropped(e) => e.context.turn_id.as_ref(),
2118 RoderEvent::ApprovalRequested(e) => Some(&e.turn_id),
2119 RoderEvent::ApprovalResolved(e) => Some(&e.turn_id),
2120 RoderEvent::ExternalToolCallRequested(e) => Some(&e.turn_id),
2121 RoderEvent::ExternalToolCallResolved(e) => Some(&e.turn_id),
2122 RoderEvent::UserInputRequested(e) => Some(&e.turn_id),
2123 RoderEvent::UserInputResolved(e) => Some(&e.turn_id),
2124 RoderEvent::TaskLedgerUpdated(e) => Some(&e.turn_id),
2125 RoderEvent::VerificationRequired(e) => Some(&e.turn_id),
2126 RoderEvent::VerificationCompleted(e) => Some(&e.turn_id),
2127 RoderEvent::VerificationSkipped(e) => Some(&e.turn_id),
2128 RoderEvent::PolicyDecisionRecorded(e) => Some(&e.turn_id),
2129 RoderEvent::PolicyBypassActive(e) => Some(&e.turn_id),
2130 RoderEvent::PolicyModeChanged(e) => e.turn_id.as_ref(),
2131 RoderEvent::AgentSwarmModeChanged(e) => e.turn_id.as_ref(),
2132 RoderEvent::AgentSwarmStarted(e) => Some(&e.turn_id),
2133 RoderEvent::AgentSwarmProgress(e) => Some(&e.turn_id),
2134 RoderEvent::AgentSwarmCompleted(e) => Some(&e.turn_id),
2135 RoderEvent::UltraModeChanged(e) => e.turn_id.as_ref(),
2136 RoderEvent::PolicyExitPlanRequested(e) => Some(&e.turn_id),
2137 RoderEvent::PolicyExitPlanResolved(e) => Some(&e.turn_id),
2138 RoderEvent::ToolCallStarted(e) => Some(&e.turn_id),
2139 RoderEvent::ToolCallCompleted(e) => Some(&e.turn_id),
2140 RoderEvent::ToolOutputDelta(e) => Some(&e.turn_id),
2141 RoderEvent::ToolOutputTruncated(e) => Some(&e.turn_id),
2142 RoderEvent::SubagentStarted(e) => Some(&e.turn_id),
2143 RoderEvent::SubagentMessage(e) => Some(&e.turn_id),
2144 RoderEvent::SubagentToolCall(e) => Some(&e.turn_id),
2145 RoderEvent::SubagentCompleted(e) => Some(&e.turn_id),
2146 RoderEvent::SubagentFailed(e) => Some(&e.turn_id),
2147 RoderEvent::SubagentTraceCreated(e) => Some(&e.summary.parent.turn_id),
2148 RoderEvent::SubagentTraceDelta(e) => Some(&e.delta.parent.turn_id),
2149 RoderEvent::SubagentTraceStatusChanged(e) => Some(&e.parent.turn_id),
2150 RoderEvent::SubagentTraceCompleted(e) => Some(&e.summary.parent.turn_id),
2151 RoderEvent::SubagentTraceFailed(e) => Some(&e.summary.parent.turn_id),
2152 RoderEvent::PlanReviewCreated(e) => Some(&e.review.turn_id),
2153 RoderEvent::PlanReviewStatusChanged(e) => Some(&e.turn_id),
2154 RoderEvent::PlanReviewCommentAdded(e) => Some(&e.turn_id),
2155 RoderEvent::PlanReviewRewritten(e) => Some(&e.turn_id),
2156 RoderEvent::PlanReviewApproved(e) => Some(&e.turn_id),
2157 RoderEvent::PlanReviewRejected(e) => Some(&e.turn_id),
2158 RoderEvent::HunkRecorded(e) => Some(&e.hunk.turn_id),
2159 RoderEvent::WorkspaceChangeObserved(e) => Some(&e.change.turn_id),
2160 RoderEvent::HunkRollbackRequested(e) => Some(&e.turn_id),
2161 RoderEvent::HunkRollbackCompleted(e) => Some(&e.turn_id),
2162 RoderEvent::MediaArtifactCreated(e) => Some(&e.turn_id),
2163 RoderEvent::MediaArtifactUpdated(e) => Some(&e.turn_id),
2164 RoderEvent::MediaPreviewReady(e) => Some(&e.turn_id),
2165 RoderEvent::ContextArtifactCreated(e) => Some(&e.turn_id),
2166 RoderEvent::ContextArtifactAppended(e) => Some(&e.turn_id),
2167 RoderEvent::ContextArtifactCapped(e) => Some(&e.turn_id),
2168 RoderEvent::DiscoveryItemRead(e) => Some(&e.turn_id),
2169 RoderEvent::DiscoveryItemPromoted(e) => e.record.turn_id.as_ref(),
2170 RoderEvent::DiscoveryPromotionReused(e) => e.record.turn_id.as_ref(),
2171 RoderEvent::DiscoveryWarmCacheHit(e) => e.record.turn_id.as_ref(),
2172 RoderEvent::DiscoveryPromotionExpired(e) => e.record.turn_id.as_ref(),
2173 RoderEvent::RetrievalRoutePlanned(e) => Some(&e.plan.turn_id),
2174 RoderEvent::RetrievalRouteAccepted(e) => Some(&e.turn_id),
2175 RoderEvent::RetrievalRouteIgnored(e) => Some(&e.turn_id),
2176 RoderEvent::RetrievalRouteFailed(e) => Some(&e.turn_id),
2177 RoderEvent::RetrievalResultUsed(e) => Some(&e.turn_id),
2178 RoderEvent::RetrievalDiscoveryItemPromoted(e) => Some(&e.turn_id),
2179 RoderEvent::RetrievalPromotionSkipped(e) => Some(&e.turn_id),
2180 RoderEvent::MemoryRecallReady(e) => Some(&e.turn_id),
2181 RoderEvent::MemoryObservationRecorded(e) => Some(&e.turn_id),
2182 RoderEvent::TaskStarted(e) => e.turn_id.as_ref(),
2183 RoderEvent::TaskOutput(e) => e.turn_id.as_ref(),
2184 RoderEvent::TaskCompleted(e) => e.turn_id.as_ref(),
2185 RoderEvent::TaskFailed(e) => e.turn_id.as_ref(),
2186 RoderEvent::TaskCancelled(e) => e.turn_id.as_ref(),
2187 RoderEvent::FileChangePreviewReady(e) => Some(&e.turn_id),
2188 RoderEvent::PatchProgress(e) => Some(&e.turn_id),
2189 RoderEvent::FileChanged(e) => Some(&e.turn_id),
2190 RoderEvent::TranscriptItemAppended(e) => Some(&e.turn_id),
2191 RoderEvent::TurnCompleted(e) => Some(&e.turn_id),
2192 RoderEvent::TurnFailed(e) => Some(&e.turn_id),
2193 RoderEvent::TurnPartialResult(e) => Some(&e.turn_id),
2194 RoderEvent::TurnDeadlineExceeded(e) => Some(&e.turn_id),
2195 RoderEvent::TurnLifecycleUpdated(e) => Some(&e.turn_id),
2196 RoderEvent::TurnInterrupted(e) => Some(&e.turn_id),
2197 RoderEvent::TurnSteered(e) => Some(&e.turn_id),
2198 RoderEvent::TeamMemberMessageDelta(e) => Some(&e.turn_id),
2199 RoderEvent::TeamMemberCompleted(e) => e.turn_id.as_ref(),
2200 RoderEvent::SkillActivationResolved(e) => Some(&e.turn_id),
2201 RoderEvent::SkillIndexRendered(e) => Some(&e.turn_id),
2202 RoderEvent::SkillInvoked(e) => Some(&e.turn_id),
2203 RoderEvent::SkillAutoActivated(e) => Some(&e.turn_id),
2204 RoderEvent::SkillSkipped(e) => Some(&e.turn_id),
2205 RoderEvent::RuntimeStarted(_)
2206 | RoderEvent::ExtensionRegistered(_)
2207 | RoderEvent::ThreadCreated(_)
2208 | RoderEvent::ThreadLoaded(_)
2209 | RoderEvent::WorkflowImportsDetected(_)
2210 | RoderEvent::WorkflowImportPreviewed(_)
2211 | RoderEvent::WorkflowImportEnabled(_)
2212 | RoderEvent::WorkflowImportDisabled(_)
2213 | RoderEvent::WorkflowImportStale(_)
2214 | RoderEvent::WorkflowImportFailed(_)
2215 | RoderEvent::MediaArtifactDeleted(_)
2216 | RoderEvent::ContextArtifactDeleted(_)
2217 | RoderEvent::ContextArtifactRetentionExpired(_)
2218 | RoderEvent::DiscoveryCatalogBuilt(_)
2219 | RoderEvent::DiscoveryItemUpdated(_)
2220 | RoderEvent::DiscoveryAuthRequired(_)
2221 | RoderEvent::MemorySaved(_)
2222 | RoderEvent::MemoryUpdated(_)
2223 | RoderEvent::MemoryDeleted(_)
2224 | RoderEvent::MemoryQueried(_)
2225 | RoderEvent::MemoryReembedQueued(_)
2226 | RoderEvent::MemoryProviderChanged(_)
2227 | RoderEvent::KnowledgeSaved(_)
2228 | RoderEvent::KnowledgeUpdated(_)
2229 | RoderEvent::KnowledgeArchived(_)
2230 | RoderEvent::KnowledgeLinked(_)
2231 | RoderEvent::RemoteServerStarted(_)
2232 | RoderEvent::RemoteServerStopped(_)
2233 | RoderEvent::RemoteAuthFailed(_)
2234 | RoderEvent::RemoteClientConnected(_)
2235 | RoderEvent::RemoteClientDisconnected(_)
2236 | RoderEvent::ThreadGoalUpdated(_)
2237 | RoderEvent::ThreadGoalCleared(_)
2238 | RoderEvent::RoadmapChanged(_)
2239 | RoderEvent::AutomationCreated(_)
2240 | RoderEvent::AutomationUpdated(_)
2241 | RoderEvent::AutomationDeleted(_)
2242 | RoderEvent::AutomationDue(_)
2243 | RoderEvent::AutomationLeased(_)
2244 | RoderEvent::AutomationQueued(_)
2245 | RoderEvent::AutomationSkipped(_)
2246 | RoderEvent::AutomationLeaseExpired(_)
2247 | RoderEvent::SkillsCatalogLoaded(_)
2248 | RoderEvent::SkillConfigApplied(_)
2249 | RoderEvent::RunnerLifecycle(_)
2250 | RoderEvent::TeamStarted(_)
2251 | RoderEvent::TeamMemberStarted(_)
2252 | RoderEvent::TeamMemberStatusChanged(_)
2253 | RoderEvent::TeamDisplayModeChanged(_)
2254 | RoderEvent::TeamTaskChanged(_)
2255 | RoderEvent::TeamCleanupCompleted(_) => None,
2256 RoderEvent::ProcessStarted(e) => e.process.turn_id.as_ref(),
2257 RoderEvent::ProcessOutput(e) => e.turn_id.as_ref(),
2258 RoderEvent::ProcessExited(e) => e.process.turn_id.as_ref(),
2259 RoderEvent::ProcessStopping(_) => None,
2260 RoderEvent::ProcessStopped(e) => e.process.turn_id.as_ref(),
2261 RoderEvent::ProcessFailed(e) => e.process.turn_id.as_ref(),
2262 RoderEvent::AutomationStarted(e) => e.run.turn_id.as_ref(),
2263 RoderEvent::AutomationCompleted(e) => e.run.turn_id.as_ref(),
2264 RoderEvent::AutomationFailed(e) => e.run.turn_id.as_ref(),
2265 RoderEvent::WorkflowRunDrafted(e) => e.turn_id.as_ref(),
2266 RoderEvent::WorkflowApprovalRequested(e) => e.turn_id.as_ref(),
2267 RoderEvent::WorkflowRunApproved(e) => e.turn_id.as_ref(),
2268 RoderEvent::WorkflowRunDenied(e) => e.turn_id.as_ref(),
2269 RoderEvent::WorkflowRunQueued(e) => e.turn_id.as_ref(),
2270 RoderEvent::WorkflowRunStarted(e) => e.turn_id.as_ref(),
2271 RoderEvent::WorkflowPhaseStarted(e) => e.turn_id.as_ref(),
2272 RoderEvent::WorkflowPhaseCompleted(e) => e.turn_id.as_ref(),
2273 RoderEvent::WorkflowAgentQueued(e) => e.turn_id.as_ref(),
2274 RoderEvent::WorkflowAgentStarted(e) => e.turn_id.as_ref(),
2275 RoderEvent::WorkflowAgentCompleted(e) => e.turn_id.as_ref(),
2276 RoderEvent::WorkflowAgentFailed(e) => e.turn_id.as_ref(),
2277 RoderEvent::WorkflowOutputRecorded(e) => e.turn_id.as_ref(),
2278 RoderEvent::WorkflowCheckpointRecorded(e) => e.turn_id.as_ref(),
2279 RoderEvent::WorkflowRunPaused(e) => e.turn_id.as_ref(),
2280 RoderEvent::WorkflowRunResumed(e) => e.turn_id.as_ref(),
2281 RoderEvent::WorkflowRunStopped(e) => e.turn_id.as_ref(),
2282 RoderEvent::WorkflowRunCompleted(e) => e.turn_id.as_ref(),
2283 RoderEvent::WorkflowRunFailed(e) => e.turn_id.as_ref(),
2284 RoderEvent::ReviewStarted(e) => Some(&e.turn_id),
2285 RoderEvent::ReviewCompleted(e) => Some(&e.turn_id),
2286 RoderEvent::ReviewFailed(e) => e.turn_id.as_ref(),
2287 RoderEvent::ReviewPublished(_) => None,
2288 }
2289 }
2290}
2291
2292#[derive(Debug, Clone, Serialize, Deserialize)]
2293pub struct EventEnvelope {
2294 pub event_id: EventId,
2295 pub seq: u64,
2296 #[serde(with = "time::serde::rfc3339")]
2297 pub timestamp: OffsetDateTime,
2298 pub source: EventSource,
2299 pub kind: String,
2300 pub thread_id: Option<ThreadId>,
2301 pub turn_id: Option<TurnId>,
2302 pub event: RoderEvent,
2303}
2304
2305impl EventEnvelope {
2306 pub fn matches_filter(&self, filter: &EventFilter) -> bool {
2307 filter.matches(self)
2308 }
2309}
2310
2311#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
2312pub struct EventFilter {
2313 pub thread_id: Option<ThreadId>,
2314 pub turn_id: Option<TurnId>,
2315 pub source: Option<EventSource>,
2316 pub kinds: Vec<String>,
2317}
2318
2319impl EventFilter {
2320 pub fn for_thread(thread_id: impl Into<ThreadId>) -> Self {
2321 Self {
2322 thread_id: Some(thread_id.into()),
2323 ..Self::default()
2324 }
2325 }
2326
2327 pub fn for_turn(thread_id: impl Into<ThreadId>, turn_id: impl Into<TurnId>) -> Self {
2328 Self {
2329 thread_id: Some(thread_id.into()),
2330 turn_id: Some(turn_id.into()),
2331 ..Self::default()
2332 }
2333 }
2334
2335 pub fn with_source(mut self, source: EventSource) -> Self {
2336 self.source = Some(source);
2337 self
2338 }
2339
2340 pub fn with_kind(mut self, kind: impl Into<String>) -> Self {
2341 self.kinds.push(kind.into());
2342 self
2343 }
2344
2345 pub fn matches(&self, envelope: &EventEnvelope) -> bool {
2346 if self
2347 .thread_id
2348 .as_ref()
2349 .is_some_and(|thread_id| envelope.thread_id.as_ref() != Some(thread_id))
2350 {
2351 return false;
2352 }
2353 if self
2354 .turn_id
2355 .as_ref()
2356 .is_some_and(|turn_id| envelope.turn_id.as_ref() != Some(turn_id))
2357 {
2358 return false;
2359 }
2360 if self
2361 .source
2362 .as_ref()
2363 .is_some_and(|source| &envelope.source != source)
2364 {
2365 return false;
2366 }
2367 if !self.kinds.is_empty() && !self.kinds.iter().any(|kind| kind == &envelope.kind) {
2368 return false;
2369 }
2370 true
2371 }
2372}
2373
2374#[cfg(test)]
2375mod tests {
2376 use super::*;
2377
2378 fn envelope(thread_id: Option<&str>, turn_id: Option<&str>, kind: &str) -> EventEnvelope {
2379 EventEnvelope {
2380 event_id: "event-1".to_string(),
2381 seq: 1,
2382 timestamp: OffsetDateTime::UNIX_EPOCH,
2383 source: EventSource::Core,
2384 kind: kind.to_string(),
2385 thread_id: thread_id.map(str::to_string),
2386 turn_id: turn_id.map(str::to_string),
2387 event: RoderEvent::TurnStarted(TurnStarted {
2388 thread_id: thread_id.unwrap_or("thread-a").to_string(),
2389 turn_id: turn_id.unwrap_or("turn-a").to_string(),
2390 runtime_profile: RuntimeProfile::Interactive,
2391 timestamp: OffsetDateTime::UNIX_EPOCH,
2392 }),
2393 }
2394 }
2395
2396 #[test]
2397 fn event_filter_matches_thread_turn_source_and_kind() {
2398 let envelope = envelope(Some("thread-a"), Some("turn-a"), "turn.started");
2399 let filter = EventFilter::for_turn("thread-a", "turn-a")
2400 .with_source(EventSource::Core)
2401 .with_kind("turn.started");
2402
2403 assert!(filter.matches(&envelope));
2404 assert!(envelope.matches_filter(&filter));
2405 assert!(!EventFilter::for_thread("thread-b").matches(&envelope));
2406 assert!(!EventFilter::for_turn("thread-a", "turn-b").matches(&envelope));
2407 assert!(
2408 !EventFilter::default()
2409 .with_source(EventSource::Provider)
2410 .matches(&envelope)
2411 );
2412 assert!(
2413 !EventFilter::default()
2414 .with_kind("turn.completed")
2415 .matches(&envelope)
2416 );
2417 }
2418
2419 #[test]
2420 fn empty_event_filter_matches_everything() {
2421 assert!(EventFilter::default().matches(&envelope(None, None, "runtime.started")));
2422 }
2423
2424 #[test]
2425 fn code_index_event_kind_and_scope_are_visible() {
2426 let event = RoderEvent::CodeIndexProofFilteredResultDropped(
2427 crate::code_index::CodeIndexProofFilteredResultDropped {
2428 context: crate::code_index::CodeIndexEventContext {
2429 workspace_root: std::path::PathBuf::from("/repo"),
2430 generation_id: Some("gen-1".to_string()),
2431 thread_id: Some("thread-1".to_string()),
2432 turn_id: Some("turn-1".to_string()),
2433 },
2434 drop: crate::code_index::ProofFilteredDrop {
2435 query_id: "query-1".to_string(),
2436 path_hash: "path-hash".to_string(),
2437 content_hash: "content-hash".to_string(),
2438 reason: "proof missing".to_string(),
2439 },
2440 timestamp: OffsetDateTime::UNIX_EPOCH,
2441 },
2442 );
2443
2444 assert_eq!(event.kind(), "code_index.proof_filtered_result_dropped");
2445 assert_eq!(event.thread_id().map(String::as_str), Some("thread-1"));
2446 assert_eq!(event.turn_id().map(String::as_str), Some("turn-1"));
2447 assert_eq!(event.source(), EventSource::Core);
2448 }
2449
2450 #[test]
2451 fn workflow_event_kind_scope_and_agent_metadata_are_visible() {
2452 let agent = crate::dynamic_workflows::WorkflowAgentRun {
2453 agent_id: "agent-1".to_string(),
2454 phase_id: "phase-1".to_string(),
2455 description: "Review findings".to_string(),
2456 status: crate::dynamic_workflows::WorkflowAgentStatus::Completed,
2457 lane: Some(crate::subagents::SubagentLane::Reviewer),
2458 model: Some("mock-model".to_string()),
2459 thread_id: Some("child-thread".to_string()),
2460 turn_id: Some("child-turn".to_string()),
2461 usage: Some(crate::inference::TokenUsage::new(10, 5, 15)),
2462 exit_reason: None,
2463 error: None,
2464 started_at: Some(OffsetDateTime::UNIX_EPOCH),
2465 completed_at: Some(OffsetDateTime::UNIX_EPOCH),
2466 };
2467 let event = RoderEvent::WorkflowAgentCompleted(WorkflowAgentCompleted {
2468 run_id: "run-1".to_string(),
2469 thread_id: Some("thread-1".to_string()),
2470 turn_id: Some("turn-1".to_string()),
2471 agent,
2472 timestamp: OffsetDateTime::UNIX_EPOCH,
2473 });
2474
2475 assert_eq!(event.kind(), "workflows/agentCompleted");
2476 assert_eq!(event.source(), EventSource::Core);
2477 assert_eq!(event.thread_id().map(String::as_str), Some("thread-1"));
2478 assert_eq!(event.turn_id().map(String::as_str), Some("turn-1"));
2479
2480 let value = serde_json::to_value(&event).unwrap();
2481 let event_value = &value["WorkflowAgentCompleted"];
2482 assert_eq!(event_value["runId"], "run-1");
2483 assert_eq!(event_value["agent"]["phaseId"], "phase-1");
2484 assert_eq!(event_value["agent"]["agentId"], "agent-1");
2485 assert_eq!(event_value["agent"]["status"], "completed");
2486 assert_eq!(event_value["agent"]["usage"]["total_tokens"], 15);
2487 }
2488
2489 #[test]
2490 fn event_timestamps_serialize_as_rfc3339_strings() {
2491 let value =
2492 serde_json::to_value(envelope(Some("thread-a"), Some("turn-a"), "turn.started"))
2493 .unwrap();
2494
2495 assert_eq!(value["timestamp"], "1970-01-01T00:00:00Z");
2496 assert_eq!(
2497 value["event"]["TurnStarted"]["timestamp"],
2498 "1970-01-01T00:00:00Z"
2499 );
2500 }
2501
2502 #[test]
2503 fn subagent_event_envelope_round_trips_parent_ids() {
2504 let event = RoderEvent::SubagentStarted(SubagentStarted {
2505 thread_id: "child-thread".to_string(),
2506 turn_id: "child-turn".to_string(),
2507 parent_thread_id: "parent-thread".to_string(),
2508 parent_turn_id: "parent-turn".to_string(),
2509 agent_type: "explore".to_string(),
2510 description: "Inspect repository".to_string(),
2511 model: Some("test-model".to_string()),
2512 timestamp: OffsetDateTime::UNIX_EPOCH,
2513 });
2514 let envelope = EventEnvelope {
2515 event_id: "event-subagent-started".to_string(),
2516 seq: 7,
2517 timestamp: OffsetDateTime::UNIX_EPOCH,
2518 source: event.source(),
2519 kind: event.kind().to_string(),
2520 thread_id: event.thread_id().cloned(),
2521 turn_id: event.turn_id().cloned(),
2522 event,
2523 };
2524
2525 let serialized = serde_json::to_string(&envelope).unwrap();
2526 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2527
2528 assert_eq!(round_trip.kind, "subagent.started");
2529 assert_eq!(round_trip.source, EventSource::Extension);
2530 assert_eq!(round_trip.thread_id.as_deref(), Some("child-thread"));
2531 assert_eq!(round_trip.turn_id.as_deref(), Some("child-turn"));
2532
2533 match round_trip.event {
2534 RoderEvent::SubagentStarted(started) => {
2535 assert_eq!(started.parent_thread_id, "parent-thread");
2536 assert_eq!(started.parent_turn_id, "parent-turn");
2537 }
2538 other => panic!("unexpected event: {other:?}"),
2539 }
2540 }
2541
2542 #[test]
2543 fn subagent_trace_event_uses_parent_turn_for_filtering() {
2544 let summary = SubagentTraceSummary {
2545 trace_id: "trace-1".to_string(),
2546 parent: ParentTurnRef {
2547 thread_id: "parent-thread".to_string(),
2548 turn_id: "parent-turn".to_string(),
2549 },
2550 child_thread_id: "child-thread".to_string(),
2551 child_turn_id: "child-turn".to_string(),
2552 title: "Inspect repository".to_string(),
2553 role: "explorer".to_string(),
2554 model: Some("test-model".to_string()),
2555 lane: None,
2556 status: SubagentTraceStatus::Running,
2557 elapsed_ms: 10,
2558 usage: None,
2559 destination: None,
2560 latest_activity: None,
2561 error_summary: None,
2562 exit_reason: None,
2563 };
2564 let event = RoderEvent::SubagentTraceCreated(SubagentTraceCreated {
2565 summary,
2566 timestamp: OffsetDateTime::UNIX_EPOCH,
2567 });
2568
2569 assert_eq!(event.kind(), "turn/subagentTraceCreated");
2570 assert_eq!(event.source(), EventSource::Extension);
2571 assert_eq!(event.thread_id().map(String::as_str), Some("parent-thread"));
2572 assert_eq!(event.turn_id().map(String::as_str), Some("parent-turn"));
2573 }
2574
2575 #[test]
2576 fn task_events_round_trip_with_replay_ids() {
2577 let event = RoderEvent::TaskOutput(TaskOutput {
2578 task_id: "task-1".to_string(),
2579 stream: crate::tasks::TaskOutputStream::Stdout,
2580 chunk: "building\n".to_string(),
2581 dropped_bytes: 0,
2582 thread_id: Some("thread-a".to_string()),
2583 turn_id: Some("turn-a".to_string()),
2584 timestamp: OffsetDateTime::UNIX_EPOCH,
2585 });
2586 let envelope = EventEnvelope {
2587 event_id: "event-task-output".to_string(),
2588 seq: 9,
2589 timestamp: OffsetDateTime::UNIX_EPOCH,
2590 source: event.source(),
2591 kind: event.kind().to_string(),
2592 thread_id: event.thread_id().cloned(),
2593 turn_id: event.turn_id().cloned(),
2594 event,
2595 };
2596
2597 let serialized = serde_json::to_string(&envelope).unwrap();
2598 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2599
2600 assert_eq!(round_trip.kind, "task.output");
2601 assert_eq!(round_trip.source, EventSource::Extension);
2602 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2603 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2604 match round_trip.event {
2605 RoderEvent::TaskOutput(output) => {
2606 assert_eq!(output.task_id, "task-1");
2607 assert_eq!(output.stream, crate::tasks::TaskOutputStream::Stdout);
2608 assert_eq!(output.chunk, "building\n");
2609 }
2610 other => panic!("unexpected event: {other:?}"),
2611 }
2612 }
2613
2614 #[test]
2615 fn automations_event_exposes_kind_source_and_replay_scope() {
2616 let run = crate::automations::AutomationRunSummary {
2617 run_id: "run-1".to_string(),
2618 automation_id: "automation-1".to_string(),
2619 occurrence_key: "automation-1:1970-01-01T00:00:00Z".to_string(),
2620 state: crate::automations::AutomationRunState::Completed,
2621 scheduled_for: OffsetDateTime::UNIX_EPOCH,
2622 queued_at: Some(OffsetDateTime::UNIX_EPOCH),
2623 started_at: Some(OffsetDateTime::UNIX_EPOCH),
2624 finished_at: Some(OffsetDateTime::UNIX_EPOCH),
2625 thread_id: Some("thread-a".to_string()),
2626 turn_id: Some("turn-a".to_string()),
2627 task_id: Some("task-1".to_string()),
2628 server_id: Some("desktop-main".to_string()),
2629 server_role: Some("desktop".to_string()),
2630 exit_code: Some(0),
2631 error: None,
2632 skip_reason: None,
2633 };
2634 let event = RoderEvent::AutomationCompleted(crate::automations::AutomationCompleted {
2635 run,
2636 timestamp: OffsetDateTime::UNIX_EPOCH,
2637 });
2638
2639 assert_eq!(event.kind(), "automations/completed");
2640 assert_eq!(event.source(), EventSource::Core);
2641 assert_eq!(event.thread_id().map(String::as_str), Some("thread-a"));
2642 assert_eq!(event.turn_id().map(String::as_str), Some("turn-a"));
2643
2644 let value = serde_json::to_value(&event).unwrap();
2645 assert_eq!(
2646 value["AutomationCompleted"]["run"]["occurrenceKey"],
2647 "automation-1:1970-01-01T00:00:00Z"
2648 );
2649 assert_eq!(
2650 value["AutomationCompleted"]["run"]["serverId"],
2651 "desktop-main"
2652 );
2653 }
2654
2655 #[test]
2656 fn tool_call_completed_round_trips_error_status() {
2657 let event = RoderEvent::ToolCallCompleted(ToolCallCompleted {
2658 thread_id: "thread-a".to_string(),
2659 turn_id: "turn-a".to_string(),
2660 tool_id: "tool-a".to_string(),
2661 tool_name: Some("list_files".to_string()),
2662 display_payload: Some(serde_json::json!({ "path": "." })),
2663 is_error: true,
2664 output: Some("tool failed".to_string()),
2665 timestamp: OffsetDateTime::UNIX_EPOCH,
2666 });
2667 let envelope = EventEnvelope {
2668 event_id: "event-tool-completed".to_string(),
2669 seq: 10,
2670 timestamp: OffsetDateTime::UNIX_EPOCH,
2671 source: event.source(),
2672 kind: event.kind().to_string(),
2673 thread_id: event.thread_id().cloned(),
2674 turn_id: event.turn_id().cloned(),
2675 event,
2676 };
2677
2678 let serialized = serde_json::to_string(&envelope).unwrap();
2679 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2680
2681 assert_eq!(round_trip.kind, "tool.call_completed");
2682 match round_trip.event {
2683 RoderEvent::ToolCallCompleted(completed) => {
2684 assert_eq!(completed.tool_id, "tool-a");
2685 assert!(completed.is_error);
2686 assert_eq!(completed.output.as_deref(), Some("tool failed"));
2687 }
2688 other => panic!("unexpected event: {other:?}"),
2689 }
2690 }
2691
2692 #[test]
2693 fn file_change_preview_event_round_trips_public_metadata() {
2694 let event = RoderEvent::FileChangePreviewReady(FileChangePreviewReady {
2695 thread_id: "thread-a".to_string(),
2696 turn_id: "turn-a".to_string(),
2697 tool_id: "tool-a".to_string(),
2698 tool_name: "edit".to_string(),
2699 path: "src/lib.rs".to_string(),
2700 change_type: "modify".to_string(),
2701 before: Some("old\n".to_string()),
2702 after: "new\n".to_string(),
2703 supports_partial: false,
2704 timestamp: OffsetDateTime::UNIX_EPOCH,
2705 });
2706 let envelope = EventEnvelope {
2707 event_id: "event-file-preview".to_string(),
2708 seq: 8,
2709 timestamp: OffsetDateTime::UNIX_EPOCH,
2710 source: event.source(),
2711 kind: event.kind().to_string(),
2712 thread_id: event.thread_id().cloned(),
2713 turn_id: event.turn_id().cloned(),
2714 event,
2715 };
2716
2717 let serialized = serde_json::to_string(&envelope).unwrap();
2718 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2719
2720 assert_eq!(round_trip.kind, "file.change_preview_ready");
2721 assert_eq!(round_trip.source, EventSource::Tool);
2722 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2723 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2724 match round_trip.event {
2725 RoderEvent::FileChangePreviewReady(preview) => {
2726 assert_eq!(preview.tool_id, "tool-a");
2727 assert_eq!(preview.tool_name, "edit");
2728 assert_eq!(preview.path, "src/lib.rs");
2729 assert_eq!(preview.change_type, "modify");
2730 assert_eq!(preview.before.as_deref(), Some("old\n"));
2731 assert_eq!(preview.after, "new\n");
2732 assert!(!preview.supports_partial);
2733 }
2734 other => panic!("unexpected event: {other:?}"),
2735 }
2736 }
2737
2738 #[test]
2739 fn inference_started_deserializes_older_records_without_model_fields() {
2740 let value = serde_json::json!({
2741 "InferenceStarted": {
2742 "thread_id": "thread-a",
2743 "turn_id": "turn-a",
2744 "engine_id": "mock",
2745 "timestamp": "1970-01-01T00:00:00Z"
2746 }
2747 });
2748
2749 let event: RoderEvent = serde_json::from_value(value).unwrap();
2750
2751 match event {
2752 RoderEvent::InferenceStarted(started) => {
2753 assert_eq!(started.model.provider, "");
2754 assert_eq!(started.model.model, "");
2755 assert_eq!(started.reasoning, ReasoningConfig::default());
2756 }
2757 other => panic!("expected inference started, got {other:?}"),
2758 }
2759 }
2760
2761 #[test]
2762 fn team_member_completed_round_trips_optional_result_details() {
2763 let event = RoderEvent::TeamMemberCompleted(TeamMemberCompleted {
2764 team_id: "team-a".to_string(),
2765 member_id: "member-a".to_string(),
2766 member_thread_id: "thread-a".to_string(),
2767 turn_id: Some("turn-a".to_string()),
2768 status: TeamMemberStatus::Failed,
2769 final_message: Some("Partial review result.".to_string()),
2770 error: Some("provider request failed".to_string()),
2771 timestamp: OffsetDateTime::UNIX_EPOCH,
2772 });
2773
2774 let value = serde_json::to_value(&event).unwrap();
2775 assert_eq!(
2776 value["TeamMemberCompleted"]["final_message"],
2777 "Partial review result."
2778 );
2779 assert_eq!(
2780 value["TeamMemberCompleted"]["error"],
2781 "provider request failed"
2782 );
2783 let round_trip: RoderEvent = serde_json::from_value(value).unwrap();
2784 match round_trip {
2785 RoderEvent::TeamMemberCompleted(completed) => {
2786 assert_eq!(
2787 completed.final_message.as_deref(),
2788 Some("Partial review result.")
2789 );
2790 assert_eq!(completed.error.as_deref(), Some("provider request failed"));
2791 }
2792 other => panic!("expected team completion, got {other:?}"),
2793 }
2794
2795 let legacy: RoderEvent = serde_json::from_value(serde_json::json!({
2796 "TeamMemberCompleted": {
2797 "team_id": "team-a",
2798 "member_id": "member-a",
2799 "member_thread_id": "thread-a",
2800 "turn_id": "turn-a",
2801 "status": "completed",
2802 "timestamp": "1970-01-01T00:00:00Z"
2803 }
2804 }))
2805 .unwrap();
2806 match legacy {
2807 RoderEvent::TeamMemberCompleted(completed) => {
2808 assert!(completed.final_message.is_none());
2809 assert!(completed.error.is_none());
2810 }
2811 other => panic!("expected team completion, got {other:?}"),
2812 }
2813 }
2814
2815 #[test]
2816 fn processes_events_expose_kind_source_scope_and_round_trip() {
2817 let descriptor = crate::processes::ProcessDescriptor {
2818 process_id: "process-1".to_string(),
2819 origin: crate::processes::ProcessOrigin::CommandExec,
2820 state: crate::processes::ProcessState::Running,
2821 command: vec!["sleep".to_string(), "10".to_string()],
2822 command_summary: "sleep 10".to_string(),
2823 cwd: Some("/repo".to_string()),
2824 pid: Some(1234),
2825 task_id: Some("task-1".to_string()),
2826 thread_id: Some("thread-a".to_string()),
2827 turn_id: Some("turn-a".to_string()),
2828 runner_destination_id: None,
2829 runner_session_id: None,
2830 stoppable: true,
2831 started_at: OffsetDateTime::UNIX_EPOCH,
2832 updated_at: OffsetDateTime::UNIX_EPOCH,
2833 stdout_tail: None,
2834 stderr_tail: None,
2835 };
2836 let event = RoderEvent::ProcessStarted(crate::processes::ProcessStarted {
2837 process: descriptor,
2838 timestamp: OffsetDateTime::UNIX_EPOCH,
2839 });
2840 let envelope = EventEnvelope {
2841 event_id: "event-process-started".to_string(),
2842 seq: 11,
2843 timestamp: OffsetDateTime::UNIX_EPOCH,
2844 source: event.source(),
2845 kind: event.kind().to_string(),
2846 thread_id: event.thread_id().cloned(),
2847 turn_id: event.turn_id().cloned(),
2848 event,
2849 };
2850
2851 let serialized = serde_json::to_string(&envelope).unwrap();
2852 let round_trip: EventEnvelope = serde_json::from_str(&serialized).unwrap();
2853
2854 assert_eq!(round_trip.kind, "process.started");
2855 assert_eq!(round_trip.source, EventSource::Extension);
2856 assert_eq!(round_trip.thread_id.as_deref(), Some("thread-a"));
2857 assert_eq!(round_trip.turn_id.as_deref(), Some("turn-a"));
2858 match round_trip.event {
2859 RoderEvent::ProcessStarted(started) => {
2860 assert_eq!(started.process.process_id, "process-1");
2861 assert_eq!(started.process.pid, Some(1234));
2862 }
2863 other => panic!("unexpected event: {other:?}"),
2864 }
2865
2866 let output = RoderEvent::ProcessOutput(crate::processes::ProcessOutput {
2867 process_id: "process-1".to_string(),
2868 stream: crate::tasks::TaskOutputStream::Stdout,
2869 chunk: "ready\n".to_string(),
2870 dropped_bytes: 0,
2871 thread_id: Some("thread-a".to_string()),
2872 turn_id: Some("turn-a".to_string()),
2873 timestamp: OffsetDateTime::UNIX_EPOCH,
2874 });
2875 assert_eq!(output.kind(), "process.output");
2876 assert_eq!(output.thread_id().map(String::as_str), Some("thread-a"));
2877 assert_eq!(output.turn_id().map(String::as_str), Some("turn-a"));
2878 }
2879
2880 #[test]
2881 fn skill_activation_event_exposes_kind_source_and_turn_scope() {
2882 let descriptor = crate::skills::SkillDescriptor {
2883 id: "builtin:commit".to_string(),
2884 name: "commit".to_string(),
2885 canonical_path: "roder-builtin://commit/SKILL.md".to_string(),
2886 source: crate::skills::SkillSource::BuiltIn,
2887 exposure: crate::skills::SkillExposure::DirectOnly,
2888 activation: crate::skills::SkillActivationState::Enabled,
2889 description: "Commit staged changes safely.".to_string(),
2890 short_description: Some("Commit safely".to_string()),
2891 experimental: false,
2892 diagnostics: Vec::new(),
2893 agent_metadata: None,
2894 };
2895 let event = RoderEvent::SkillActivationResolved(crate::skills::SkillActivationResolved {
2896 thread_id: "thread-a".to_string(),
2897 turn_id: "turn-a".to_string(),
2898 selector: crate::skills::SkillSelector::Name {
2899 name: "commit".to_string(),
2900 },
2901 activation_reason: crate::skills::SkillActivationReason::FeatureBinding,
2902 activated: true,
2903 descriptor: Some(descriptor),
2904 diagnostic: None,
2905 timestamp: OffsetDateTime::UNIX_EPOCH,
2906 });
2907
2908 assert_eq!(event.kind(), "skills/activationResolved");
2909 assert_eq!(event.source(), EventSource::Core);
2910 assert_eq!(event.thread_id().map(String::as_str), Some("thread-a"));
2911 assert_eq!(event.turn_id().map(String::as_str), Some("turn-a"));
2912 }
2913}