Skip to main content

lash_remote_protocol/protocol/
usage_activity.rs

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