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