1use super::{
2 types::{
3 AgentRosterRow, MiddlewareDecisionEvidence, ModelRouteDecisionPayload,
4 OrchestrationObservation, ProtocolEventMeta, SelfReviewProposalDraft,
5 },
6 UserQuestion, VerificationIssue,
7};
8use crate::message::TranscriptMessage;
9use crate::task::TaskNode;
10use crate::tool::ToolCall;
11use crate::trust::TrustEnvelope;
12use serde::{Deserialize, Serialize};
13use serde_json::Value;
14
15#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17#[serde(rename_all = "camelCase")]
18pub struct GoalStepV1 {
19 pub id: String,
20 pub label: String,
21 pub weight: i64,
22 pub state: String,
23 pub verification_state: String,
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
28#[serde(rename_all = "camelCase")]
29pub struct GoalSnapshotV1 {
30 pub goal_id: String,
31 pub objective: String,
32 pub status: String,
33 pub started_at: String,
34 pub closed_at: Option<String>,
35 pub dismissed_at: Option<String>,
36 pub decomposition_state: String,
37 pub plan_revision: i64,
38 pub completion_percent: Option<i64>,
39 pub now: Option<String>,
40 pub next: Option<String>,
41 pub steps: Vec<GoalStepV1>,
42 pub verification_state: String,
43 pub budget_tokens: i64,
44 pub tokens_used: i64,
45 pub continuation_count: i64,
46 pub no_progress_count: i64,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
53#[serde(rename_all = "camelCase")]
54pub struct CompactionFederationSelectionReceiptV1 {
55 pub selected_item_ids: Vec<String>,
56 pub selection_hash: String,
57}
58
59pub const COMPACTION_FEDERATION_SCHEMA_V1: &str = "compaction-federation-v1";
76
77fn compaction_federation_schema_v1() -> String {
78 COMPACTION_FEDERATION_SCHEMA_V1.to_string()
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
82#[serde(rename_all = "camelCase")]
83pub struct CompactionFederationDecisionV1 {
84 #[serde(rename = "$schema", default = "compaction_federation_schema_v1")]
86 pub schema: String,
87 pub identity: String,
89 pub fence: String,
91 pub scope: String,
93 pub decision: String,
95 pub selection_receipt: CompactionFederationSelectionReceiptV1,
96 pub issued_monotonic_elapsed_ms: u64,
99 pub expires_after_elapsed_ms: u64,
102 pub restart_epoch: u64,
105}
106
107impl CompactionFederationDecisionV1 {
108 pub fn is_live(&self, now_monotonic_elapsed_ms: u64, current_restart_epoch: u64) -> bool {
113 if current_restart_epoch != self.restart_epoch {
114 return false;
115 }
116 match now_monotonic_elapsed_ms.checked_sub(self.issued_monotonic_elapsed_ms) {
117 Some(elapsed) => elapsed <= self.expires_after_elapsed_ms,
118 None => false,
119 }
120 }
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124#[serde(tag = "$kind")]
125pub enum ProtocolEvent {
126 #[serde(rename = "sessionStarted", rename_all = "camelCase")]
127 SessionStarted {
128 session_id: String,
129 seq: i64,
130 created_at: String,
131 title: Option<String>,
132 },
133
134 #[serde(rename = "sessionTitleUpdated", rename_all = "camelCase")]
135 SessionTitleUpdated {
136 session_id: String,
137 seq: i64,
138 created_at: String,
139 title: String,
140 },
141
142 #[serde(rename = "assistantDelta", rename_all = "camelCase")]
143 AssistantDelta {
144 session_id: String,
145 seq: i64,
146 created_at: String,
147 text: String,
148 is_reasoning: bool,
149 },
150
151 #[serde(rename = "assistantMessageCompleted", rename_all = "camelCase")]
152 AssistantMessageCompleted {
153 session_id: String,
154 seq: i64,
155 created_at: String,
156 message: TranscriptMessage,
157 },
158
159 #[serde(rename = "toolCallStarted", rename_all = "camelCase")]
160 ToolCallStarted {
161 session_id: String,
162 seq: i64,
163 created_at: String,
164 call: ToolCall,
165 },
166
167 #[serde(rename = "toolApprovalRequested", rename_all = "camelCase")]
168 ToolApprovalRequested {
169 session_id: String,
170 seq: i64,
171 created_at: String,
172 call: ToolCall,
173 risk_label: String,
174 proposed_change: Option<String>,
175 policy_source: Option<String>,
176 #[serde(default)]
177 middleware_decisions: Vec<MiddlewareDecisionEvidence>,
178 },
179
180 #[serde(rename = "toolApprovalResolved", rename_all = "camelCase")]
181 ToolApprovalResolved {
182 session_id: String,
183 seq: i64,
184 created_at: String,
185 tool_call_id: String,
186 approved: bool,
187 },
188
189 #[serde(rename = "toolApprovalReviewed", rename_all = "camelCase")]
198 ToolApprovalReviewed {
199 session_id: String,
200 seq: i64,
201 created_at: String,
202 tool_call_id: String,
203 tool_name: String,
204 correlation_id: String,
205 verdict: String,
206 reason: String,
207 reviewer_configured: bool,
208 },
209
210 #[serde(rename = "toolResultAdded", rename_all = "camelCase")]
211 ToolResultAdded {
212 session_id: String,
213 seq: i64,
214 created_at: String,
215 result: TranscriptMessage,
216 },
217
218 #[serde(rename = "sessionTurnFinished", rename_all = "camelCase")]
222 SessionTurnFinished {
223 session_id: String,
224 seq: i64,
225 created_at: String,
226 turn_id: String,
227 status: String,
228 },
229
230 #[serde(rename = "streamResyncRequired", rename_all = "camelCase")]
233 StreamResyncRequired {
234 session_id: String,
235 seq: i64,
236 created_at: String,
237 after_seq: i64,
238 oldest_available_seq: i64,
239 high_water_mark: i64,
240 },
241
242 #[serde(rename = "persistenceFailed", rename_all = "camelCase")]
246 PersistenceFailed {
247 session_id: String,
248 seq: i64,
249 created_at: String,
250 reason: String,
251 },
252
253 #[serde(rename = "overloaded", rename_all = "camelCase")]
255 Overloaded {
256 session_id: String,
257 seq: i64,
258 created_at: String,
259 scope: String,
260 limit: u64,
261 current: u64,
262 #[serde(default)]
263 retry_after_ms: u64,
264 },
265
266 #[serde(rename = "providerRetrying", rename_all = "camelCase")]
269 ProviderRetrying {
270 session_id: String,
271 seq: i64,
272 created_at: String,
273 provider: String,
274 reason: String,
275 attempt: u32,
276 max_attempts: u32,
277 delay_ms: u64,
278 },
279
280 #[serde(rename = "sessionCompactionStarted", rename_all = "camelCase")]
283 SessionCompactionStarted {
284 session_id: String,
285 seq: i64,
286 created_at: String,
287 #[serde(default)]
288 trigger: String,
289 #[serde(default)]
290 command_id: String,
291 },
292
293 #[serde(rename = "verificationFinished", rename_all = "camelCase")]
294 VerificationFinished {
295 session_id: String,
296 seq: i64,
297 created_at: String,
298 summary: String,
299 passed: bool,
300 #[serde(default)]
301 tool: String,
302 #[serde(default)]
303 issue_count: i32,
304 #[serde(default)]
305 issues: Vec<VerificationIssue>,
306 },
307
308 #[serde(rename = "taskGraphUpdated", rename_all = "camelCase")]
309 TaskGraphUpdated {
310 session_id: String,
311 seq: i64,
312 created_at: String,
313 summary: String,
314 #[serde(default)]
315 tasks: Vec<TaskNode>,
316 },
317
318 #[serde(rename = "taskStatusUpdated", rename_all = "camelCase")]
319 TaskStatusUpdated {
320 session_id: String,
321 seq: i64,
322 created_at: String,
323 task_id: String,
324 context_id: String,
325 state: String,
326 task: Value,
327 },
328
329 #[serde(rename = "taskArtifactUpdated", rename_all = "camelCase")]
330 TaskArtifactUpdated {
331 session_id: String,
332 seq: i64,
333 created_at: String,
334 task_id: String,
335 context_id: String,
336 artifact_id: String,
337 artifact: Value,
338 },
339
340 #[serde(rename = "artifactLineageUpdated", rename_all = "camelCase")]
341 ArtifactLineageUpdated {
342 session_id: String,
343 seq: i64,
344 created_at: String,
345 task_id: String,
346 context_id: String,
347 artifact_id: String,
348 lineage: Value,
349 },
350
351 #[serde(rename = "runInterrupted", rename_all = "camelCase")]
352 RunInterrupted {
353 session_id: String,
354 seq: i64,
355 created_at: String,
356 reason: Option<String>,
357 },
358
359 #[serde(rename = "runFailed", rename_all = "camelCase")]
360 RunFailed {
361 session_id: String,
362 seq: i64,
363 created_at: String,
364 error: String,
365 #[serde(default)]
368 kind: String,
369 #[serde(default)]
370 hint: String,
371 },
372
373 #[serde(rename = "sessionCompacted", rename_all = "camelCase")]
374 SessionCompacted {
375 session_id: String,
376 seq: i64,
377 created_at: String,
378 summary: String,
379 #[serde(default)]
380 dropped_count: i32,
381 #[serde(default)]
385 tier: String,
386 #[serde(default)]
388 tokens_before: u64,
389 #[serde(default)]
391 tokens_after: u64,
392 #[serde(default)]
396 epoch: u64,
397 #[serde(default)]
398 command_id: String,
399 retained_turns: u32,
404 },
405
406 #[serde(rename = "sessionContextFolded", rename_all = "camelCase")]
410 SessionContextFolded {
411 session_id: String,
412 seq: i64,
413 created_at: String,
414 subtask_id: String,
415 start_marker: String,
416 end_marker: String,
417 fold: TranscriptMessage,
418 },
419
420 #[serde(rename = "usageUpdated", rename_all = "camelCase")]
421 UsageUpdated {
422 session_id: String,
423 seq: i64,
424 created_at: String,
425 prompt_tokens: i32,
426 completion_tokens: i32,
427 cost_usd: f64,
428 context_tokens: i32,
429 context_percent: f64,
430 #[serde(default)]
431 cache_read_tokens: i32,
432 #[serde(default)]
433 cache_creation_tokens: i32,
434 #[serde(default = "default_cost_known")]
441 cost_known: bool,
442 },
443
444 #[serde(rename = "turnUsage", rename_all = "camelCase")]
452 TurnUsage {
453 session_id: String,
454 seq: i64,
455 created_at: String,
456 input_tokens: i64,
457 cached_input_tokens: i64,
458 #[serde(default)]
459 cache_creation_tokens: i64,
460 output_tokens: i64,
461 #[serde(default)]
462 reasoning_tokens: i64,
463 #[serde(default)]
464 context_window: i64,
465 #[serde(default)]
466 context_used_tokens: i64,
467 #[serde(default)]
468 context_used_pct: f64,
469 #[serde(default)]
473 cache_hit_pct: f64,
474 #[serde(default)]
477 session_cache_hit_pct: f64,
478 },
479
480 #[serde(rename = "promptCacheBreak", rename_all = "camelCase")]
492 PromptCacheBreak {
493 session_id: String,
494 seq: i64,
495 created_at: String,
496 reason: String,
497 expected: bool,
498 tokens_lost: i64,
499 #[serde(default, skip_serializing_if = "Option::is_none")]
500 estimated_cost_lost: Option<f64>,
501 turn: i64,
502 #[serde(default)]
503 detail: String,
504 #[serde(default)]
505 previous_cache_read_tokens: i64,
506 #[serde(default)]
507 cache_read_tokens: i64,
508 #[serde(default)]
509 cache_creation_tokens: i64,
510 },
511
512 #[serde(rename = "toolOutputDelta", rename_all = "camelCase")]
516 ToolOutputDelta {
517 session_id: String,
518 seq: i64,
519 created_at: String,
520 call_id: String,
521 stream: String,
523 text: String,
524 },
525
526 #[serde(rename = "backgroundShellExited", rename_all = "camelCase")]
531 BackgroundShellExited {
532 session_id: String,
533 seq: i64,
534 created_at: String,
535 shell_id: String,
536 #[serde(default)]
537 command: String,
538 status: super::types::ShellExitStatus,
539 #[serde(default)]
540 output_bytes: u64,
541 },
542
543 #[serde(rename = "budgetExceeded", rename_all = "camelCase")]
544 BudgetExceeded {
545 session_id: String,
546 seq: i64,
547 created_at: String,
548 #[serde(default)]
549 scope: String,
550 current_usd: f64,
551 ceiling_usd: f64,
552 #[serde(default)]
553 hint: String,
554 },
555
556 #[serde(rename = "providerRouteUpdated", rename_all = "camelCase")]
557 ProviderRouteUpdated {
558 session_id: String,
559 seq: i64,
560 created_at: String,
561 #[serde(default)]
562 state: String,
563 #[serde(default)]
564 provider: String,
565 #[serde(default)]
566 model: String,
567 #[serde(default)]
568 failure_kind: String,
569 #[serde(default)]
570 detail: String,
571 },
572
573 #[serde(rename = "accountRateLimited", rename_all = "camelCase")]
579 AccountRateLimited {
580 session_id: String,
581 seq: i64,
582 created_at: String,
583 #[serde(default)]
584 provider: String,
585 #[serde(default)]
587 account: String,
588 #[serde(default)]
590 account_id: Option<String>,
591 #[serde(default)]
593 account_kind: Option<String>,
594 #[serde(default)]
596 email: Option<String>,
597 #[serde(default)]
598 organization: Option<String>,
599 #[serde(default)]
600 status: String,
601 #[serde(default)]
602 rate_limit_type: Option<String>,
603 #[serde(default)]
605 resets_at: Option<u64>,
606 #[serde(default)]
607 utilization: Option<f64>,
608 #[serde(default)]
609 overage_status: Option<String>,
610 #[serde(default)]
611 error_code: Option<String>,
612 },
613
614 #[serde(rename = "accountUsageReported", rename_all = "camelCase")]
617 AccountUsageReported {
618 session_id: String,
619 seq: i64,
620 created_at: String,
621 #[serde(default)]
622 provider: String,
623 #[serde(default)]
624 account: String,
625 #[serde(default)]
626 account_id: Option<String>,
627 #[serde(default)]
628 account_kind: Option<String>,
629 #[serde(default)]
630 email: Option<String>,
631 #[serde(default)]
632 total_cost_usd: Option<f64>,
633 #[serde(default)]
634 duration_ms: Option<u64>,
635 #[serde(default)]
636 num_turns: Option<u64>,
637 #[serde(default)]
638 input_tokens: u64,
639 #[serde(default)]
640 output_tokens: u64,
641 #[serde(default)]
642 cache_read_tokens: u64,
643 #[serde(default)]
644 cache_creation_tokens: u64,
645 #[serde(default)]
646 models: Vec<String>,
647 },
648
649 #[serde(rename = "dispatchDecided", rename_all = "camelCase")]
650 DispatchDecided {
651 session_id: String,
652 seq: i64,
653 created_at: String,
654 strategy: String,
655 rationale: String,
656 },
657
658 #[serde(rename = "orchestrationObservationRecorded", rename_all = "camelCase")]
659 OrchestrationObservationRecorded {
660 session_id: String,
661 seq: i64,
662 created_at: String,
663 observation: OrchestrationObservation,
664 },
665
666 #[serde(rename = "agentQueryIssued", rename_all = "camelCase")]
667 AgentQueryIssued {
668 session_id: String,
669 seq: i64,
670 created_at: String,
671 query_id: String,
672 from_role: String,
673 to_role: String,
674 query_type: String,
675 expected_format: String,
676 },
677
678 #[serde(rename = "agentQueryResponded", rename_all = "camelCase")]
679 AgentQueryResponded {
680 session_id: String,
681 seq: i64,
682 created_at: String,
683 query_id: String,
684 from_role: String,
685 to_role: String,
686 confidence: f64,
687 },
688
689 #[serde(rename = "humanSteeringInjected", rename_all = "camelCase")]
690 HumanSteeringInjected {
691 session_id: String,
692 seq: i64,
693 created_at: String,
694 injected_by: String,
695 content_preview: String,
696 #[serde(default, skip_serializing_if = "Option::is_none")]
701 text: Option<String>,
702 },
703
704 #[serde(rename = "subAgentSpawned", rename_all = "camelCase")]
706 SubAgentSpawned {
707 session_id: String,
708 seq: i64,
709 created_at: String,
710 sub_session_id: String,
711 role: String,
712 task_title: String,
713 },
714
715 #[serde(rename = "subAgentCompleted", rename_all = "camelCase")]
717 SubAgentCompleted {
718 session_id: String,
719 seq: i64,
720 created_at: String,
721 sub_session_id: String,
722 role: String,
723 success: bool,
724 summary: String,
725 #[serde(default = "default_worker_outcome")]
731 outcome: String,
732 #[serde(default)]
736 outcome_detail: String,
737 },
738
739 #[serde(rename = "subAgentCancelled", rename_all = "camelCase")]
742 SubAgentCancelled {
743 session_id: String,
744 seq: i64,
745 created_at: String,
746 sub_session_id: String,
747 role: String,
748 cancelled_by: String,
749 },
750
751 #[serde(rename = "userMessageSubmitted", rename_all = "camelCase")]
755 UserMessageSubmitted {
756 session_id: String,
757 seq: i64,
758 created_at: String,
759 text: String,
760 #[serde(default, skip_serializing_if = "Option::is_none")]
761 nonce: Option<String>,
762 #[serde(default, skip_serializing_if = "Option::is_none")]
763 trust: Option<TrustEnvelope>,
764 #[serde(default, skip_serializing_if = "Vec::is_empty")]
768 attachments: Vec<crate::ReferenceMeta>,
769 },
770
771 #[serde(rename = "userQuestionAsked", rename_all = "camelCase")]
774 UserQuestionAsked {
775 session_id: String,
776 seq: i64,
777 created_at: String,
778 question_id: String,
779 questions: Vec<UserQuestion>,
780 },
781
782 #[serde(rename = "mcpElicitationRequested", rename_all = "camelCase")]
786 McpElicitationRequested {
787 session_id: String,
788 seq: i64,
789 created_at: String,
790 request: crate::approvals::ElicitationRequestEvent,
791 },
792
793 #[serde(rename = "credentialRequested", rename_all = "camelCase")]
797 CredentialRequested {
798 session_id: String,
799 seq: i64,
800 created_at: String,
801 tool_call_id: String,
802 provider: String,
803 },
804
805 #[serde(rename = "credentialResolved", rename_all = "camelCase")]
806 CredentialResolved {
807 session_id: String,
808 seq: i64,
809 created_at: String,
810 tool_call_id: String,
811 outcome: String,
812 },
813
814 #[serde(rename = "userQuestionAnswered", rename_all = "camelCase")]
816 UserQuestionAnswered {
817 session_id: String,
818 seq: i64,
819 created_at: String,
820 question_id: String,
821 },
822
823 #[serde(rename = "planPresented", rename_all = "camelCase")]
827 PlanPresented {
828 session_id: String,
829 seq: i64,
830 created_at: String,
831 plan_id: String,
832 plan: String,
833 },
834
835 #[serde(rename = "agentRosterUpdated", rename_all = "camelCase")]
837 AgentRosterUpdated {
838 session_id: String,
839 seq: i64,
840 created_at: String,
841 agents: Vec<AgentRosterRow>,
842 },
843
844 #[serde(rename = "checkRunCompleted", rename_all = "camelCase")]
847 CheckRunCompleted {
848 session_id: String,
849 seq: i64,
850 created_at: String,
851 check_id: String,
852 command: String,
853 exit_code: i32,
854 attempts: u32,
855 duration_ms: u64,
856 passed: bool,
857 jury_skipped: bool,
858 },
859
860 #[serde(rename = "goalProgressUpdated", rename_all = "camelCase")]
863 GoalProgressUpdated {
864 session_id: String,
865 seq: i64,
866 created_at: String,
867 #[serde(flatten)]
868 snapshot: GoalSnapshotV1,
869 },
870
871 #[serde(rename = "selfReviewProposalReceived", rename_all = "camelCase")]
873 SelfReviewProposalReceived {
874 session_id: String,
875 seq: i64,
876 created_at: String,
877 proposal: SelfReviewProposalDraft,
878 },
879
880 #[serde(rename = "modelRouteDecision", rename_all = "camelCase")]
887 ModelRouteDecision {
888 session_id: String,
889 seq: i64,
890 created_at: String,
891 #[serde(flatten)]
892 decision: ModelRouteDecisionPayload,
893 },
894
895 #[serde(rename = "runGovernanceRejected", rename_all = "camelCase")]
900 RunGovernanceRejected {
901 session_id: String,
902 seq: i64,
903 created_at: String,
904 kind: super::types::RunFailureKind,
905 tool_call_id: String,
906 #[serde(default)]
907 budget: Option<super::types::RunBudgetExhausted>,
908 #[serde(default)]
909 ownership: Option<super::types::RunOwnershipFailure>,
910 #[serde(default)]
911 origin: Option<super::types::RunOriginFailure>,
912 },
913}
914
915fn default_cost_known() -> bool {
916 true
917}
918
919fn default_worker_outcome() -> String {
920 "complete".to_string()
921}
922
923mod methods;