everruns_integrations_e2b/
lib.rs1pub mod client;
28pub mod connection;
29pub mod state;
30mod tools;
31
32use everruns_core::LEASED_RESOURCES_FEATURE;
33use everruns_core::capabilities::{
34 Capability, CapabilityLocalization, CapabilityStatus, IntegrationPlugin, RiskLevel,
35};
36use everruns_core::connector::ConnectorPlugin;
37use everruns_core::tools::Tool;
38
39use std::sync::LazyLock;
40
41use connection::E2BConnector;
42use tools::{
43 E2BCreateSandboxTool, E2BExecTool, E2BListSandboxesTool, E2BManageSandboxTool, E2BReadFileTool,
44 E2BWriteFileTool,
45};
46
47inventory::submit! {
48 IntegrationPlugin {
49 experimental_only: false,
50 feature_flag: None,
51 factory: || Box::new(E2BCapability),
52 }
53}
54
55inventory::submit! {
56 ConnectorPlugin {
57 experimental_only: false,
58 factory: || Box::new(E2BConnector),
59 }
60}
61
62pub const E2B_API_BASE: &str = "https://api.e2b.app";
63pub const E2B_SANDBOX_SECRET_PREFIX: &str = "e2b_sandbox:";
64pub const E2B_DEFAULT_TEMPLATE: &str = "base";
65pub const E2B_DEFAULT_TIMEOUT_SECS: u64 = 60 * 60;
66pub const E2B_DEFAULT_WORKSPACE_PATH: &str = "/home/user";
67pub const E2B_ENVD_PORT: u16 = 49_983;
68
69static SYSTEM_PROMPT: LazyLock<String> = LazyLock::new(|| {
70 let mut prompt = String::from(
71 "E2B sandboxes are isolated networked Linux environments. Create or select a sandbox before sandbox-scoped operations, prefer `/home/user` as workspace root, and pause or delete sandboxes when done.",
72 );
73 prompt.push_str(everruns_core::tool_output_sanitizer::EXEC_OUTPUT_HINT);
74 prompt
75});
76
77pub struct E2BCapability;
78
79impl Capability for E2BCapability {
80 fn id(&self) -> &str {
81 "e2b"
82 }
83
84 fn name(&self) -> &str {
85 "E2B"
86 }
87
88 fn description(&self) -> &str {
89 "Run code in cloud sandboxes powered by E2B. Create isolated Linux environments, execute commands, and manage sandbox files."
90 }
91
92 fn localizations(&self) -> Vec<CapabilityLocalization> {
93 vec![CapabilityLocalization::text(
94 "uk",
95 "E2B",
96 "Запускайте код у хмарних пісочницях на основі E2B. Створюйте ізольовані \
97 середовища Linux, виконуйте команди та керуйте файлами пісочниці.",
98 )]
99 }
100
101 fn status(&self) -> CapabilityStatus {
102 CapabilityStatus::Available
103 }
104
105 fn risk_level(&self) -> RiskLevel {
106 RiskLevel::High
107 }
108
109 fn icon(&self) -> Option<&str> {
110 Some("cloud")
111 }
112
113 fn category(&self) -> Option<&str> {
114 Some("Sandboxes")
115 }
116
117 fn system_prompt_addition(&self) -> Option<&str> {
118 Some(&SYSTEM_PROMPT)
119 }
120
121 fn tools(&self) -> Vec<Box<dyn Tool>> {
122 vec![
123 Box::new(E2BCreateSandboxTool),
124 Box::new(E2BExecTool),
125 Box::new(E2BReadFileTool),
126 Box::new(E2BWriteFileTool),
127 Box::new(E2BListSandboxesTool),
128 Box::new(E2BManageSandboxTool),
129 ]
130 }
131
132 fn dependencies(&self) -> Vec<&'static str> {
133 vec!["session_storage"]
134 }
135
136 fn features(&self) -> Vec<&'static str> {
137 vec![LEASED_RESOURCES_FEATURE]
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144
145 #[test]
146 fn capability_metadata() {
147 let cap = E2BCapability;
148 assert_eq!(cap.id(), "e2b");
149 assert_eq!(cap.name(), "E2B");
150 assert_eq!(cap.icon(), Some("cloud"));
151 assert_eq!(cap.category(), Some("Sandboxes"));
152 assert_eq!(cap.dependencies(), vec!["session_storage"]);
153 }
154
155 #[test]
156 fn capability_tools() {
157 let cap = E2BCapability;
158 let names: Vec<_> = cap
159 .tools()
160 .into_iter()
161 .map(|tool| tool.name().to_string())
162 .collect();
163 assert!(names.contains(&"e2b_create_sandbox".to_string()));
164 assert!(names.contains(&"e2b_exec".to_string()));
165 assert!(names.contains(&"e2b_read_file".to_string()));
166 assert!(names.contains(&"e2b_write_file".to_string()));
167 assert!(names.contains(&"e2b_list_sandboxes".to_string()));
168 assert!(names.contains(&"e2b_manage_sandbox".to_string()));
169 }
170
171 #[tokio::test]
172 async fn system_prompt_within_budget() {
173 let cap = E2BCapability;
174 let ctx = everruns_core::capabilities::SystemPromptContext::without_file_store(
175 everruns_core::SessionId::new(),
176 );
177 let prompt = cap.system_prompt_contribution(&ctx).await.unwrap();
178 assert!(prompt.len() <= 1300, "prompt is {} bytes", prompt.len());
182 }
183}