agent_workspace_contract/environment/
ports.rs1use super::*;
2
3#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
4#[serde(deny_unknown_fields, rename_all = "camelCase")]
5pub enum EnvironmentIdempotencyState {
6 Pending,
7 Completed,
8}
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
11#[serde(deny_unknown_fields, rename_all = "camelCase")]
12pub struct EnvironmentIdempotencyRecord {
13 pub id: String,
14 pub scope: ResourceScope,
15 pub action: String,
16 pub key_hash: String,
18 pub request_hash: String,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub resource_id: Option<String>,
21 pub state: EnvironmentIdempotencyState,
22 pub claim_owner: String,
24 pub claim_expires_at_ms: u64,
26 pub attempt: u32,
27 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub result_json: Option<String>,
29 pub started_at_ms: u64,
30 #[serde(default, skip_serializing_if = "Option::is_none")]
31 pub completed_at_ms: Option<u64>,
32}
33
34#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(deny_unknown_fields, rename_all = "camelCase")]
41pub struct EnvironmentMetadataSnapshot {
42 pub version: u64,
43 #[serde(default)]
44 pub computers: Vec<ComputerRecord>,
45 #[serde(default)]
46 pub computer_bindings: Vec<ComputerBinding>,
47 #[serde(default)]
48 pub spaces: Vec<SpaceRecord>,
49 #[serde(default)]
50 pub sandboxes: Vec<SandboxRecord>,
51 #[serde(default)]
52 pub snapshots: Vec<SnapshotRecord>,
53 #[serde(default)]
54 pub templates: Vec<TemplateVersionRecord>,
55 #[serde(default)]
56 pub grants: Vec<SpaceGrant>,
57 #[serde(default)]
58 pub sessions: Vec<SpaceCollaborationSession>,
59 #[serde(default)]
60 pub tickets: Vec<SpaceAccessTicketRecord>,
61 #[serde(default)]
62 pub leases: Vec<SpaceWriteLease>,
63 #[serde(default)]
64 pub fencing_tokens: BTreeMap<String, u64>,
65 #[serde(default)]
66 pub delegations: Vec<DelegationRecord>,
67 #[serde(default)]
68 pub change_sets: Vec<SpaceChangeSetRecord>,
69 #[serde(default)]
70 pub idempotency: Vec<EnvironmentIdempotencyRecord>,
71}
72
73#[async_trait]
74pub trait EnvironmentMetadataRepository: Send + Sync + Debug {
75 async fn load(&self, scope: &ResourceScope) -> Result<EnvironmentMetadataSnapshot>;
76
77 async fn list_scopes(
79 &self,
80 after: Option<&ResourceScope>,
81 limit: usize,
82 ) -> Result<Vec<ResourceScope>>;
83
84 async fn compare_and_swap(
87 &self,
88 scope: &ResourceScope,
89 expected_version: u64,
90 snapshot: &EnvironmentMetadataSnapshot,
91 ) -> Result<bool>;
92}
93
94#[async_trait]
95pub trait ComputerProvider: Send + Sync + Debug {
96 fn kind(&self) -> &str;
97 fn capabilities(&self) -> ProviderCapabilities;
98 fn validate_create(&self, _request: &ProviderComputerRequest) -> Result<()> {
99 Ok(())
100 }
101 async fn create_computer(
102 &self,
103 scope: &ResourceScope,
104 request: &ProviderComputerRequest,
105 idempotency_key: &str,
106 ) -> Result<ProviderResourceRef>;
107 async fn delete_computer(&self, external_id: &str, idempotency_key: &str) -> Result<()>;
108}
109
110#[async_trait]
111pub trait SandboxProvider: Send + Sync + Debug {
112 fn kind(&self) -> &str;
113 fn capabilities(&self) -> ProviderCapabilities;
114 fn validate_create(&self, _request: &ProviderSandboxRequest) -> Result<()> {
115 Ok(())
116 }
117 async fn create_sandbox(
118 &self,
119 scope: &ResourceScope,
120 request: &ProviderSandboxRequest,
121 idempotency_key: &str,
122 ) -> Result<ProviderResourceRef>;
123 async fn stop_sandbox(&self, external_id: &str, idempotency_key: &str) -> Result<()>;
124}
125
126#[async_trait]
127pub trait SpaceProvider: Send + Sync + Debug {
128 fn kind(&self) -> &str;
129 fn capabilities(&self) -> ProviderCapabilities;
130 async fn create_space(
131 &self,
132 scope: &ResourceScope,
133 request: &ProviderSpaceRequest,
134 idempotency_key: &str,
135 ) -> Result<ProviderResourceRef>;
136 async fn read_file(&self, external_id: &str, path: &str) -> Result<ProviderFileContent>;
137 async fn write_file(
138 &self,
139 external_id: &str,
140 path: &str,
141 content: &[u8],
142 expected_provider_revision: Option<&str>,
143 idempotency_key: &str,
144 ) -> Result<ProviderWriteResult>;
145 async fn create_change_set(
146 &self,
147 source_external_id: &str,
148 target_external_id: &str,
149 idempotency_key: &str,
150 ) -> Result<String>;
151 async fn apply_change_set(
152 &self,
153 source_external_id: &str,
154 target_external_id: &str,
155 provider_change_ref: &str,
156 idempotency_key: &str,
157 ) -> Result<ProviderWriteResult>;
158 async fn delete_space(&self, external_id: &str, idempotency_key: &str) -> Result<()>;
159}
160
161#[async_trait]
162pub trait SnapshotProviderPort: Send + Sync + Debug {
163 fn kind(&self) -> &str;
164 async fn capture_snapshot(
165 &self,
166 source: &ProviderSnapshotSource,
167 idempotency_key: &str,
168 ) -> Result<ProviderResourceRef>;
169 async fn delete_snapshot(
170 &self,
171 snapshot_external_id: &str,
172 idempotency_key: &str,
173 ) -> Result<()>;
174}
175
176#[async_trait]
177pub trait TemplateProviderPort: Send + Sync + Debug {
178 fn kind(&self) -> &str;
179 async fn inspect_template(&self, external_id: &str) -> Result<ProviderCapabilities>;
180}
181
182pub trait EnvironmentProviderRegistry: Send + Sync + Debug {
183 fn computer(&self, provider: &str) -> Result<Arc<dyn ComputerProvider>>;
184 fn sandbox(&self, provider: &str) -> Result<Arc<dyn SandboxProvider>>;
185 fn space(&self, provider: &str) -> Result<Arc<dyn SpaceProvider>>;
186 fn snapshot(&self, provider: &str) -> Result<Arc<dyn SnapshotProviderPort>>;
187 fn template(&self, provider: &str) -> Result<Arc<dyn TemplateProviderPort>>;
188}