Skip to main content

agent_workspace_contract/environment/
catalog.rs

1use super::*;
2
3/// Provider-owned images used when product create APIs omit every Workspace
4/// catalog snapshot/template selector. A configured catalog default still
5/// takes precedence and is resolved to its provider external id by Runtime.
6pub const E2B_PLATFORM_TEMPLATE_ID: &str = "code-interpreter-v1";
7pub const E2B_BUILTIN_TEMPLATE_IDS: [&str; 3] = [
8    E2B_PLATFORM_TEMPLATE_ID,
9    "context-management-moc",
10    "vpc-sandbox",
11];
12pub const MOULIN_PLATFORM_SNAPSHOT_ID: &str = "python";
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
15#[serde(rename_all = "snake_case")]
16pub enum SnapshotVisibility {
17    #[default]
18    Private,
19    Public,
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(tag = "kind", rename_all = "snake_case")]
24pub enum SnapshotBuildSpec {
25    Dockerfile {
26        dockerfile: String,
27    },
28    Template {
29        #[serde(alias = "pipPackages")]
30        pip_packages: String,
31    },
32    Git {
33        #[serde(rename = "gitUrl", alias = "git_url")]
34        git_url: String,
35        #[serde(default, rename = "gitRef", alias = "git_ref")]
36        git_ref: String,
37    },
38}
39
40/// Product-facing snapshot recipe size limits. The build adapters impose
41/// additional limits on fetched repository contents and generated archives.
42pub const SNAPSHOT_DOCKERFILE_MAX_BYTES: usize = 1024 * 1024;
43pub const SNAPSHOT_TEMPLATE_PACKAGES_MAX_BYTES: usize = 64 * 1024;
44
45#[derive(Debug, Clone, Default, PartialEq, Eq)]
46pub struct EnvironmentCatalogConfig {
47    pub default_provider: Option<String>,
48    pub default_snapshot_id: Option<String>,
49    pub default_builds: BTreeMap<String, SnapshotBuildSpec>,
50}
51
52#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(deny_unknown_fields, rename_all = "camelCase")]
54pub struct CreateSnapshotResourceRequest {
55    #[serde(default, skip_serializing_if = "Option::is_none")]
56    pub provider: Option<String>,
57    #[serde(default)]
58    pub visibility: SnapshotVisibility,
59    #[serde(default)]
60    pub owners: Vec<OwnerRef>,
61    #[serde(default)]
62    pub builtin: bool,
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub build: Option<SnapshotBuildSpec>,
65}
66
67#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
68#[serde(deny_unknown_fields, rename_all = "camelCase")]
69pub struct BuildBuiltinSnapshotRequest {
70    pub provider: String,
71    #[serde(default)]
72    pub set_default: bool,
73    #[serde(default, skip_serializing_if = "Option::is_none")]
74    pub git_url: Option<String>,
75    #[serde(default, skip_serializing_if = "Option::is_none")]
76    pub git_ref: Option<String>,
77    #[serde(default, skip_serializing_if = "Option::is_none")]
78    pub dockerfile: Option<String>,
79}
80
81pub const ADMIN_BUILD_BUILTIN_SNAPSHOTS_PATH: &str = "/admin/api/workspace-snapshots:build-builtin";
82pub const ADMIN_SNAPSHOTS_PATH: &str = "/admin/api/workspace-snapshots";
83pub const ADMIN_SNAPSHOT_PATH: &str = "/admin/api/workspace-snapshots/{snapshotId}";
84pub const CATALOG_SNAPSHOT_PATH: &str = "/internal/v1/workspace/snapshots:catalog/{snapshotId}";
85
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87#[serde(deny_unknown_fields, rename_all = "camelCase")]
88pub struct ProviderBuildHandle {
89    pub build_id: String,
90    #[serde(default, skip_serializing_if = "Option::is_none")]
91    pub resource_external_id: Option<String>,
92}
93
94#[derive(Debug, Clone, PartialEq, Eq)]
95pub enum EnvironmentBuildStatus {
96    Building(ProviderBuildHandle),
97    Ready(ProviderResourceRef),
98    Failed(String),
99}
100
101/// Build-only port. Implementations must not create Computer or Sandbox instances.
102#[async_trait]
103pub trait EnvironmentBuildPort: Send + Sync + Debug {
104    async fn submit_environment_image(
105        &self,
106        provider: &str,
107        spec: &SnapshotBuildSpec,
108        idempotency_key: &str,
109    ) -> Result<EnvironmentBuildStatus>;
110
111    async fn poll_environment_image(
112        &self,
113        _provider: &str,
114        _handle: &ProviderBuildHandle,
115    ) -> Result<EnvironmentBuildStatus> {
116        Err(anyhow::anyhow!(
117            "build provider does not support caller-driven status polling"
118        ))
119    }
120}