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 CodeBlockStarted {
72 language: String,
73 code: String,
74 #[serde(default, skip_serializing_if = "Option::is_none")]
75 graph_key: Option<String>,
76 },
77 CodeBlockCompleted {
78 language: String,
79 output: String,
80 #[serde(default, skip_serializing_if = "Option::is_none")]
81 error: Option<String>,
82 success: bool,
83 duration_ms: u64,
84 tool_call_ids: Vec<String>,
85 #[serde(default, skip_serializing_if = "Option::is_none")]
86 graph_key: Option<String>,
87 },
88 ToolCallStarted {
89 #[serde(default, skip_serializing_if = "Option::is_none")]
90 call_id: Option<String>,
91 name: String,
92 args: serde_json::Value,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
94 graph_key: Option<String>,
95 #[serde(default, skip_serializing_if = "Option::is_none")]
96 parent_call_id: Option<String>,
97 },
98 ToolCallCompleted {
99 #[serde(default, skip_serializing_if = "Option::is_none")]
100 call_id: Option<String>,
101 name: String,
102 args: serde_json::Value,
103 output: serde_json::Value,
104 duration_ms: u64,
105 #[serde(default, skip_serializing_if = "Option::is_none")]
106 graph_key: Option<String>,
107 #[serde(default, skip_serializing_if = "Option::is_none")]
108 parent_call_id: Option<String>,
109 },
110 FinalValue {
111 value: serde_json::Value,
112 },
113 ToolValue {
114 tool_name: String,
115 value: serde_json::Value,
116 },
117 Usage {
118 protocol_iteration: usize,
119 usage: RemoteUsage,
120 cumulative: RemoteUsage,
121 },
122 ChildUsage {
123 session_id: String,
124 source: String,
125 model: String,
126 protocol_iteration: usize,
127 usage: RemoteUsage,
128 cumulative: RemoteUsage,
129 },
130 RetryStatus {
131 wait_seconds: u64,
132 attempt: usize,
133 max_attempts: usize,
134 reason: String,
135 },
136 RuntimeDiagnostic {
137 kind: String,
138 data: serde_json::Value,
139 },
140 Error {
141 message: String,
142 },
143}