roder_api/
workspace_changes.rs1use serde::{Deserialize, Serialize};
2use time::OffsetDateTime;
3
4use crate::events::{ThreadId, TurnId};
5
6#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
7#[serde(rename_all = "camelCase")]
8pub enum WorkspaceChangeStatus {
9 Modified,
10 Added,
11 Deleted,
12 Renamed,
13 Untracked,
14}
15
16#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
17#[serde(rename_all = "camelCase")]
18pub enum WorkspaceChangeSource {
19 VersionControlReconciled,
20}
21
22#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
23#[serde(rename_all = "camelCase")]
24pub enum WorkspaceChangeConfidence {
25 ObservedAfterTool,
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
29#[serde(rename_all = "camelCase")]
30pub struct WorkspaceObservedFile {
31 pub path: String,
32 #[serde(default, skip_serializing_if = "Option::is_none")]
33 pub old_path: Option<String>,
34 pub status: WorkspaceChangeStatus,
35 pub additions: u32,
36 pub deletions: u32,
37 #[serde(default)]
38 pub binary: bool,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
42#[serde(rename_all = "camelCase")]
43pub struct WorkspaceChangeObservation {
44 pub id: String,
45 pub thread_id: ThreadId,
46 pub turn_id: TurnId,
47 pub tool_call_id: String,
48 pub tool_name: String,
49 pub source: WorkspaceChangeSource,
50 #[serde(default, skip_serializing_if = "Option::is_none")]
51 pub provider_id: Option<crate::version_control::VcsProviderId>,
52 pub confidence: WorkspaceChangeConfidence,
53 pub files: Vec<WorkspaceObservedFile>,
54 #[serde(with = "time::serde::rfc3339")]
55 pub created_at: OffsetDateTime,
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
63 fn version_control_reconciled_observation_round_trips_with_provider_identity() {
64 let observation = WorkspaceChangeObservation {
65 id: "obs-1".to_string(),
66 thread_id: "thread-1".to_string(),
67 turn_id: "turn-1".to_string(),
68 tool_call_id: "tool-1".to_string(),
69 tool_name: "shell".to_string(),
70 source: WorkspaceChangeSource::VersionControlReconciled,
71 provider_id: Some("git".to_string()),
72 confidence: WorkspaceChangeConfidence::ObservedAfterTool,
73 files: vec![WorkspaceObservedFile {
74 path: "src/lib.rs".to_string(),
75 old_path: None,
76 status: WorkspaceChangeStatus::Modified,
77 additions: 2,
78 deletions: 1,
79 binary: false,
80 }],
81 created_at: OffsetDateTime::UNIX_EPOCH,
82 };
83
84 let encoded = serde_json::to_value(&observation).expect("serialize observation");
85 let decoded = serde_json::from_value::<WorkspaceChangeObservation>(encoded)
86 .expect("deserialize observation");
87
88 assert_eq!(decoded, observation);
89 }
90}