1use schemars::JsonSchema;
4use serde::{Deserialize, Serialize};
5
6use crate::ensure_protocol_version;
7use crate::registry_errors::{RemoteProtocolError, require_non_empty};
8
9#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
16pub struct RemoteUsage {
17 pub input_tokens: i64,
18 pub output_tokens: i64,
19 pub cache_read_input_tokens: i64,
20 pub cache_write_input_tokens: i64,
21 pub reasoning_output_tokens: i64,
22}
23
24impl RemoteUsage {
25 pub fn add(&mut self, other: &Self) {
26 self.input_tokens += other.input_tokens;
27 self.output_tokens += other.output_tokens;
28 self.cache_read_input_tokens += other.cache_read_input_tokens;
29 self.cache_write_input_tokens += other.cache_write_input_tokens;
30 self.reasoning_output_tokens += other.reasoning_output_tokens;
31 }
32}
33
34#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
35pub struct RemoteTokenLedgerEntry {
36 pub source: String,
37 pub model: String,
38 pub usage: RemoteUsage,
39}
40
41#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
42pub struct RemoteTurnActivity {
43 pub protocol_version: u32,
44 pub sequence: u64,
45 pub id: String,
46 pub correlation_id: String,
47 #[serde(flatten)]
48 pub event: RemoteTurnEvent,
49}
50
51impl RemoteTurnActivity {
52 pub fn validate(&self) -> Result<(), RemoteProtocolError> {
53 ensure_protocol_version(self.protocol_version)?;
54 require_non_empty("RemoteTurnActivity", "id", &self.id)?;
55 require_non_empty("RemoteTurnActivity", "correlation_id", &self.correlation_id)
56 }
57}
58
59#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
60#[serde(tag = "type", rename_all = "snake_case")]
61pub enum RemoteTurnEvent {
62 ModelRequestStarted {
63 protocol_iteration: usize,
64 },
65 AssistantProseDelta {
66 text: String,
67 },
68 ReasoningDelta {
69 text: String,
70 },
71 ModelAttemptReset {
72 assistant_prose_correlation_ids: Vec<String>,
73 reasoning_correlation_ids: Vec<String>,
74 },
75 CodeBlockStarted {
76 language: String,
77 code: String,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
79 graph_key: Option<String>,
80 },
81 CodeBlockCompleted {
82 language: String,
83 output: String,
84 #[serde(default, skip_serializing_if = "Option::is_none")]
85 error: Option<String>,
86 success: bool,
87 duration_ms: u64,
88 tool_call_ids: Vec<String>,
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 graph_key: Option<String>,
91 },
92 ToolCallStarted {
93 #[serde(default, skip_serializing_if = "Option::is_none")]
94 call_id: Option<String>,
95 name: String,
96 args: serde_json::Value,
97 #[serde(default, skip_serializing_if = "Option::is_none")]
98 graph_key: Option<String>,
99 #[serde(default, skip_serializing_if = "Option::is_none")]
100 parent_call_id: Option<String>,
101 },
102 ToolCallCompleted {
103 #[serde(default, skip_serializing_if = "Option::is_none")]
104 call_id: Option<String>,
105 name: String,
106 args: serde_json::Value,
107 output: serde_json::Value,
108 duration_ms: u64,
109 #[serde(default, skip_serializing_if = "Option::is_none")]
110 graph_key: Option<String>,
111 #[serde(default, skip_serializing_if = "Option::is_none")]
112 parent_call_id: Option<String>,
113 },
114 FinalValue {
115 value: serde_json::Value,
116 },
117 ToolValue {
118 tool_name: String,
119 value: serde_json::Value,
120 },
121 Usage {
122 protocol_iteration: usize,
123 usage: RemoteUsage,
124 cumulative: RemoteUsage,
125 },
126 ChildUsage {
127 session_id: String,
128 source: String,
129 model: String,
130 protocol_iteration: usize,
131 usage: RemoteUsage,
132 cumulative: RemoteUsage,
133 },
134 RetryStatus {
135 wait_seconds: u64,
136 attempt: usize,
137 max_attempts: usize,
138 reason: String,
139 },
140 RuntimeDiagnostic {
141 kind: String,
142 data: serde_json::Value,
143 },
144 Error {
145 message: String,
146 },
147}