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