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