1use std::path::PathBuf;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum HostedSpoolKind {
11 Spool,
12}
13
14#[derive(Debug, Clone, Serialize, Deserialize)]
15pub struct HostedSpoolInfo {
16 pub spool_id: String,
17 pub full_path: String,
18 pub kind: String,
19 pub is_repo: bool,
20 pub display_name: Option<String>,
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize)]
24pub struct HostedNamespaceInfo {
25 pub namespace_id: String,
26 pub kind: String,
27 pub slug: String,
28 pub parent_id: Option<String>,
29 pub display_name: Option<String>,
30 pub full_path: String,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub struct HostedRepositoryInfo {
35 pub repo_id: String,
36 pub namespace_id: String,
37 pub slug: String,
38 pub path: PathBuf,
39 pub full_path: String,
40}
41
42#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct HostedGrantInfo {
44 pub subject: String,
45 pub role: String,
46 #[serde(default)]
47 pub namespace_path: Option<String>,
48 #[serde(default)]
49 pub repo_path: Option<String>,
50}
51
52#[derive(Debug, Clone, Default, Serialize, Deserialize)]
53pub struct HarnessIdentity {
54 #[serde(default)]
55 pub harness: Option<String>,
56 #[serde(default)]
57 pub provider: Option<String>,
58 #[serde(default)]
59 pub model: Option<String>,
60 #[serde(default)]
61 pub thinking_level: Option<String>,
62 #[serde(default)]
63 pub policy: Option<String>,
64}
65
66#[derive(Debug, Clone, Default, Serialize, Deserialize)]
67pub struct UsageTotals {
68 #[serde(default)]
69 pub input_tokens: Option<u64>,
70 #[serde(default)]
71 pub output_tokens: Option<u64>,
72 #[serde(default)]
73 pub reasoning_tokens: Option<u64>,
74 #[serde(default)]
75 pub cache_creation_tokens: Option<u64>,
76 #[serde(default)]
77 pub cache_read_tokens: Option<u64>,
78 #[serde(default)]
79 pub tool_calls: Option<u32>,
80 #[serde(default)]
81 pub cost_micros_usd: Option<u64>,
82}
83
84#[derive(Debug, Clone, Default, Serialize, Deserialize)]
85pub struct ProgressCheckpoint {
86 #[serde(default)]
87 pub status: Option<String>,
88 #[serde(default)]
89 pub message: Option<String>,
90 #[serde(default)]
91 pub completed_steps: Option<u32>,
92 #[serde(default)]
93 pub total_steps: Option<u32>,
94 #[serde(default)]
95 pub touched_paths: Vec<String>,
96 #[serde(default)]
97 pub tool_name: Option<String>,
98 #[serde(default)]
99 pub detail: Option<String>,
100 #[serde(default)]
101 pub captured_revision: Option<String>,
102 pub recorded_at: String,
103}
104
105#[derive(Debug, Clone, Default, Serialize, Deserialize)]
106pub struct TranscriptAttachmentRef {
107 pub attachment_id: String,
108 #[serde(default)]
109 pub kind: Option<String>,
110 #[serde(default)]
111 pub summary: Option<String>,
112}
113
114#[derive(Debug, Clone, Default, Serialize, Deserialize)]
115pub struct SessionDiffSummary {
116 #[serde(default)]
117 pub changed_file_count: u32,
118 #[serde(default)]
119 pub added_files: u32,
120 #[serde(default)]
121 pub modified_files: u32,
122 #[serde(default)]
123 pub deleted_files: u32,
124}
125
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct WorktreeChangeBaseline {
128 pub path: String,
129 pub kind: String,
130}
131
132#[cfg(test)]
133mod tests {
134 use super::HostedSpoolKind;
135
136 #[test]
137 fn spool_kind_does_not_determine_repository_capability() {
138 let kind = HostedSpoolKind::Spool;
139 let encoded = rmp_serde::to_vec(&kind).expect("encode spool kind");
140 assert_eq!(
141 rmp_serde::from_slice::<HostedSpoolKind>(&encoded).expect("decode spool kind"),
142 kind
143 );
144 for is_repo in [false, true] {
145 let spool = super::HostedSpoolInfo {
146 spool_id: "id".into(),
147 full_path: "spool/alice/notes".into(),
148 kind: "spool".into(),
149 is_repo,
150 display_name: None,
151 };
152 let bytes = rmp_serde::to_vec(&spool).expect("encode spool");
153 let decoded: super::HostedSpoolInfo =
154 rmp_serde::from_slice(&bytes).expect("decode spool");
155 assert_eq!(decoded.is_repo, is_repo);
156 assert_eq!(decoded.kind, "spool");
157 }
158 }
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct SessionReportEnvelope {
163 pub version: u32,
164 pub heddle_session_id: String,
165 #[serde(default)]
166 pub heddle_segment_id: Option<String>,
167 #[serde(default)]
168 pub agent_session_id: Option<String>,
169 #[serde(default)]
170 pub client_instance_id: Option<String>,
171 #[serde(default)]
172 pub native_actor_key: Option<String>,
173 #[serde(default)]
174 pub native_parent_actor_key: Option<String>,
175 #[serde(default)]
176 pub native_instance_key: Option<String>,
177 pub repo_root: String,
178 #[serde(default)]
179 pub thread: Option<String>,
180 #[serde(default)]
181 pub thread_id: Option<String>,
182 #[serde(default)]
183 pub task: Option<String>,
184 #[serde(default)]
185 pub summary: Option<String>,
186 pub opened_at: String,
187 #[serde(default)]
188 pub closed_at: Option<String>,
189 #[serde(default)]
190 pub base_state_at_open: Option<String>,
191 #[serde(default)]
192 pub worktree_changes_at_open: Vec<WorktreeChangeBaseline>,
193 #[serde(default)]
194 pub head_state_at_close: Option<String>,
195 pub transport_mode: String,
196 pub transcript_mode: String,
197 #[serde(default)]
198 pub outcome: Option<String>,
199 #[serde(default)]
200 pub owns_session: bool,
201 pub harness: HarnessIdentity,
202 #[serde(default)]
203 pub progress: Vec<ProgressCheckpoint>,
204 #[serde(default)]
205 pub usage: UsageTotals,
206 #[serde(default)]
207 pub touched_paths: Vec<String>,
208 #[serde(default)]
209 pub changed_paths: Vec<String>,
210 #[serde(default)]
211 pub diff_summary: Option<SessionDiffSummary>,
212 #[serde(default)]
213 pub transcript_refs: Vec<TranscriptAttachmentRef>,
214 #[serde(default)]
215 pub last_progress_at: Option<String>,
216 #[serde(default)]
217 pub report_flush_state: Option<String>,
218 #[serde(default)]
219 pub attach_reason: Option<String>,
220 #[serde(default)]
221 pub attach_precedence: Vec<String>,
222 #[serde(default)]
223 pub winning_attach_rule: Option<String>,
224 #[serde(default)]
225 pub probe_source: Option<String>,
226 #[serde(default)]
227 pub probe_confidence: Option<f32>,
228 #[serde(default)]
229 pub pending_flush: bool,
230 #[serde(default)]
231 pub last_flushed_at: Option<String>,
232}