Skip to main content

agent_workspace_contract/environment/
resources.rs

1//! Developer-facing Environment resource projections returned by Workspace APIs.
2
3use super::*;
4
5// Product response DTOs. Provider references (external ids), credential hashes
6// and provider revisions stay off this plane. The provider name is public
7// resource identity and is included so callers can tell moulin from e2b.
8
9#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
10#[serde(deny_unknown_fields, rename_all = "camelCase")]
11pub struct SpaceGrantResource {
12    pub id: String,
13    pub space_id: String,
14    pub principal: PrincipalRef,
15    pub capabilities: BTreeSet<SpaceCapability>,
16    pub path_prefixes: Vec<String>,
17    pub expires_at_ms: Option<u64>,
18    pub active: bool,
19    pub version: u64,
20}
21
22impl From<SpaceGrant> for SpaceGrantResource {
23    fn from(record: SpaceGrant) -> Self {
24        Self {
25            id: record.id,
26            space_id: record.space_id,
27            principal: record.principal,
28            capabilities: record.capabilities,
29            path_prefixes: record.path_prefixes,
30            expires_at_ms: record.expires_at_ms,
31            active: record.active,
32            version: record.version,
33        }
34    }
35}
36
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(deny_unknown_fields, rename_all = "camelCase")]
39pub struct SpaceCollaborationSessionResource {
40    pub id: String,
41    pub space_id: String,
42    pub principal: PrincipalRef,
43    pub delegation_id: Option<String>,
44    pub requested_mode: SpaceAccessMode,
45    pub effective_mode: SpaceAccessMode,
46    pub lifecycle: SpaceSessionLifecycle,
47    pub last_heartbeat_at_ms: u64,
48    pub expires_at_ms: u64,
49    pub version: u64,
50}
51
52impl From<SpaceCollaborationSession> for SpaceCollaborationSessionResource {
53    fn from(record: SpaceCollaborationSession) -> Self {
54        Self {
55            id: record.id,
56            space_id: record.space_id,
57            principal: record.principal,
58            delegation_id: record.delegation_id,
59            requested_mode: record.requested_mode,
60            effective_mode: record.effective_mode,
61            lifecycle: record.lifecycle,
62            last_heartbeat_at_ms: record.last_heartbeat_at_ms,
63            expires_at_ms: record.expires_at_ms,
64            version: record.version,
65        }
66    }
67}
68
69#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
70#[serde(deny_unknown_fields, rename_all = "camelCase")]
71pub struct SpaceWriteLeaseResource {
72    pub id: String,
73    pub space_id: String,
74    pub session_id: String,
75    pub fencing_token: u64,
76    pub version: u64,
77    pub acquired_at_ms: u64,
78    pub expires_at_ms: u64,
79    pub active: bool,
80}
81
82impl From<SpaceWriteLease> for SpaceWriteLeaseResource {
83    fn from(record: SpaceWriteLease) -> Self {
84        Self {
85            id: record.id,
86            space_id: record.space_id,
87            session_id: record.session_id,
88            fencing_token: record.fencing_token,
89            version: record.version,
90            acquired_at_ms: record.acquired_at_ms,
91            expires_at_ms: record.expires_at_ms,
92            active: record.active,
93        }
94    }
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
98#[serde(deny_unknown_fields, rename_all = "camelCase")]
99pub struct DelegationResource {
100    pub id: String,
101    pub grantor_user_id: String,
102    pub delegate_agent_id: String,
103    pub computer_ids: BTreeSet<String>,
104    pub space_ids: BTreeSet<String>,
105    pub capabilities: BTreeSet<SpaceCapability>,
106    pub path_prefixes: Vec<String>,
107    pub purpose: String,
108    pub expires_at_ms: u64,
109    pub revoked_at_ms: Option<u64>,
110}
111
112impl From<DelegationRecord> for DelegationResource {
113    fn from(record: DelegationRecord) -> Self {
114        Self {
115            id: record.id,
116            grantor_user_id: record.grantor_user_id,
117            delegate_agent_id: record.delegate_agent_id,
118            computer_ids: record.computer_ids,
119            space_ids: record.space_ids,
120            capabilities: record.capabilities,
121            path_prefixes: record.path_prefixes,
122            purpose: record.purpose,
123            expires_at_ms: record.expires_at_ms,
124            revoked_at_ms: record.revoked_at_ms,
125        }
126    }
127}
128
129#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
130#[serde(deny_unknown_fields, rename_all = "camelCase")]
131pub struct ComputerResource {
132    pub id: String,
133    #[serde(default, skip_serializing_if = "Option::is_none")]
134    pub alias: Option<String>,
135    pub provider: String,
136    pub resources: SandboxResources,
137    pub lifecycle: ComputerLifecycle,
138    pub capabilities: ProviderCapabilities,
139    pub owners: Vec<OwnerRef>,
140    pub version: u64,
141    pub created_at_ms: u64,
142    pub updated_at_ms: u64,
143}
144
145impl From<ComputerRecord> for ComputerResource {
146    fn from(record: ComputerRecord) -> Self {
147        Self {
148            id: record.id,
149            alias: record.alias,
150            provider: record.provider_ref.provider,
151            resources: record.resources,
152            lifecycle: record.lifecycle,
153            capabilities: record.capabilities,
154            owners: record.owners,
155            version: record.version,
156            created_at_ms: record.created_at_ms,
157            updated_at_ms: record.updated_at_ms,
158        }
159    }
160}
161
162#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(deny_unknown_fields, rename_all = "camelCase")]
164pub struct SpaceResource {
165    pub id: String,
166    #[serde(default, skip_serializing_if = "Option::is_none")]
167    pub alias: Option<String>,
168    pub computer_id: String,
169    #[serde(default)]
170    pub provider: String,
171    pub persistence: SpacePersistence,
172    pub lifecycle: SpaceLifecycle,
173    pub capabilities: ProviderCapabilities,
174    pub owners: Vec<OwnerRef>,
175    pub source_snapshot_id: Option<String>,
176    pub revision: u64,
177    pub version: u64,
178    pub created_at_ms: u64,
179    pub updated_at_ms: u64,
180}
181
182impl SpaceResource {
183    pub fn from_record(record: SpaceRecord, provider: impl Into<String>) -> Self {
184        Self {
185            id: record.id,
186            alias: record.alias,
187            computer_id: record.computer_id,
188            provider: provider.into(),
189            persistence: record.persistence,
190            lifecycle: record.lifecycle,
191            capabilities: record.capabilities,
192            owners: record.owners,
193            source_snapshot_id: record.source_snapshot_id,
194            revision: record.revision,
195            version: record.version,
196            created_at_ms: record.created_at_ms,
197            updated_at_ms: record.updated_at_ms,
198        }
199    }
200}
201
202#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
203#[serde(deny_unknown_fields, rename_all = "camelCase")]
204pub struct SandboxResource {
205    pub id: String,
206    #[serde(default, skip_serializing_if = "Option::is_none")]
207    pub alias: Option<String>,
208    pub resources: SandboxResources,
209    pub placement: SandboxPlacement,
210    pub lifecycle: SandboxLifecycle,
211    pub owners: Vec<OwnerRef>,
212    pub capabilities: ProviderCapabilities,
213    pub mounts: Vec<SandboxMountRecord>,
214    pub expires_at_ms: u64,
215    pub version: u64,
216    pub created_at_ms: u64,
217    pub updated_at_ms: u64,
218}
219
220impl From<SandboxRecord> for SandboxResource {
221    fn from(record: SandboxRecord) -> Self {
222        Self {
223            id: record.id,
224            alias: record.alias,
225            resources: record.resources,
226            placement: record.placement,
227            lifecycle: record.lifecycle,
228            owners: record.owners,
229            capabilities: record.capabilities,
230            mounts: record.mounts,
231            expires_at_ms: record.expires_at_ms,
232            version: record.version,
233            created_at_ms: record.created_at_ms,
234            updated_at_ms: record.updated_at_ms,
235        }
236    }
237}
238
239#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
240#[serde(deny_unknown_fields, rename_all = "camelCase")]
241pub struct SnapshotResource {
242    pub id: String,
243    pub alias: Option<String>,
244    pub provider: String,
245    pub visibility: SnapshotVisibility,
246    pub owners: Vec<OwnerRef>,
247    pub builtin: bool,
248    pub created_by: PrincipalRef,
249    pub lifecycle: SnapshotLifecycle,
250    pub digest: Option<String>,
251    pub size_bytes: Option<u64>,
252    pub error: Option<String>,
253    pub provider_build_id: Option<String>,
254    pub build_stage: Option<String>,
255    pub build_logs: Vec<String>,
256    pub created_at_ms: u64,
257}
258
259impl From<SnapshotRecord> for SnapshotResource {
260    fn from(record: SnapshotRecord) -> Self {
261        Self {
262            id: record.id,
263            alias: record.alias,
264            provider: record.provider,
265            visibility: record.visibility,
266            owners: record.owners,
267            builtin: record.builtin,
268            created_by: record.created_by,
269            lifecycle: record.lifecycle,
270            digest: record.digest,
271            size_bytes: record.size_bytes,
272            error: record.error,
273            provider_build_id: record.provider_build_id,
274            build_stage: record.build_stage,
275            build_logs: record.build_logs,
276            created_at_ms: record.created_at_ms,
277        }
278    }
279}
280
281#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
282#[serde(deny_unknown_fields, rename_all = "camelCase")]
283pub struct TemplateVersionResource {
284    pub template_id: String,
285    pub version: String,
286    pub provider: String,
287    pub created_by: PrincipalRef,
288    pub target: TemplateTarget,
289    pub base_snapshot_id: Option<String>,
290    pub resource_profile: BTreeMap<String, String>,
291    pub parameter_schema: BTreeMap<String, String>,
292    pub state: TemplateVersionState,
293    pub created_at_ms: u64,
294}
295
296impl From<TemplateVersionRecord> for TemplateVersionResource {
297    fn from(record: TemplateVersionRecord) -> Self {
298        Self {
299            template_id: record.template_id,
300            version: record.version,
301            provider: record.provider,
302            created_by: record.created_by,
303            target: record.target,
304            base_snapshot_id: record.base_snapshot_id,
305            resource_profile: record.resource_profile,
306            parameter_schema: record.parameter_schema,
307            state: record.state,
308            created_at_ms: record.created_at_ms,
309        }
310    }
311}
312
313#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
314#[serde(deny_unknown_fields, rename_all = "camelCase")]
315pub struct SpaceChangeSetResource {
316    pub id: String,
317    pub source_space_id: String,
318    pub target_space_id: String,
319    pub base_revision: u64,
320    pub created_by_session_id: String,
321    pub lifecycle: ChangeSetLifecycle,
322    pub created_at_ms: u64,
323}
324
325impl From<SpaceChangeSetRecord> for SpaceChangeSetResource {
326    fn from(record: SpaceChangeSetRecord) -> Self {
327        Self {
328            id: record.id,
329            source_space_id: record.source_space_id,
330            target_space_id: record.target_space_id,
331            base_revision: record.base_revision,
332            created_by_session_id: record.created_by_session_id,
333            lifecycle: record.lifecycle,
334            created_at_ms: record.created_at_ms,
335        }
336    }
337}
338
339#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
340#[serde(deny_unknown_fields, rename_all = "camelCase")]
341pub struct SpaceAccessTicketResource {
342    pub id: String,
343    pub space_id: String,
344    pub session_id: String,
345    pub mode: SpaceAccessMode,
346    pub capability_paths: BTreeMap<SpaceCapability, Vec<String>>,
347    pub fencing_token: Option<u64>,
348    pub expires_at_ms: u64,
349}
350
351#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
352#[serde(deny_unknown_fields, rename_all = "camelCase")]
353pub struct IssuedSpaceAccessTicketResource {
354    pub ticket: SpaceAccessTicketResource,
355    pub token: String,
356}
357
358impl From<IssuedSpaceAccessTicket> for IssuedSpaceAccessTicketResource {
359    fn from(issued: IssuedSpaceAccessTicket) -> Self {
360        Self {
361            ticket: SpaceAccessTicketResource {
362                id: issued.ticket.id,
363                space_id: issued.ticket.space_id,
364                session_id: issued.ticket.session_id,
365                mode: issued.ticket.mode,
366                capability_paths: issued.ticket.capability_paths,
367                fencing_token: issued.ticket.fencing_token,
368                expires_at_ms: issued.ticket.expires_at_ms,
369            },
370            token: issued.token,
371        }
372    }
373}
374
375#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
376#[serde(deny_unknown_fields, rename_all = "camelCase")]
377pub struct SpaceFileContent {
378    #[serde(with = "super::base64_bytes")]
379    pub bytes: Vec<u8>,
380}
381
382#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
383#[serde(deny_unknown_fields, rename_all = "camelCase")]
384pub struct SpaceFileEntry {
385    pub path: String,
386    pub is_dir: bool,
387    #[serde(default, skip_serializing_if = "Option::is_none")]
388    pub size_bytes: Option<u64>,
389}
390
391impl From<ProviderFileEntry> for SpaceFileEntry {
392    fn from(entry: ProviderFileEntry) -> Self {
393        Self {
394            path: entry.path,
395            is_dir: entry.is_dir,
396            size_bytes: entry.size_bytes,
397        }
398    }
399}
400
401impl From<ProviderFileContent> for SpaceFileContent {
402    fn from(content: ProviderFileContent) -> Self {
403        Self {
404            bytes: content.bytes,
405        }
406    }
407}