everruns_integrations_deno/
lib.rs1pub mod client;
14pub mod connection;
15pub mod state;
16mod tools;
17
18use everruns_core::LEASED_RESOURCES_FEATURE;
19use everruns_core::capabilities::{
20 Capability, CapabilityLocalization, CapabilityStatus, IntegrationPlugin, RiskLevel,
21};
22use everruns_core::connector::ConnectorPlugin;
23use everruns_core::tools::Tool;
24use std::sync::LazyLock;
25use std::time::Duration;
26
27use connection::DenoConnector;
28use tools::{
29 DenoCreateSandboxTool, DenoExecTool, DenoListSandboxesTool, DenoManageSandboxTool,
30 DenoReadFileTool, DenoWriteFileTool,
31};
32
33inventory::submit! {
34 IntegrationPlugin {
35 experimental_only: false,
36 feature_flag: None,
37 factory: || Box::new(DenoCapability),
38 }
39}
40
41inventory::submit! {
42 ConnectorPlugin {
43 experimental_only: true,
44 factory: || Box::new(DenoConnector),
45 }
46}
47
48const DENO_CONSOLE_API_BASE: &str = "https://console.deno.com";
49const DENO_SANDBOX_BASE_DOMAIN: &str = "sandbox-api.deno.net";
50const DENO_SANDBOX_SECRET_PREFIX: &str = "deno_sandbox:";
51const DENO_SANDBOX_TIMEOUT: &str = "20m";
52const DENO_DEFAULT_MEMORY_MB: u64 = 1_280;
53const DENO_MAX_MEMORY_MB: u64 = 16 * 1_024;
54const DENO_RPC_TIMEOUT: Duration = Duration::from_secs(30);
55const DENO_STREAM_IDLE_TIMEOUT: Duration = Duration::from_secs(2);
56const DENO_WORKSPACE_PATH: &str = "/home/app";
57
58static SYSTEM_PROMPT: LazyLock<String> = LazyLock::new(|| {
59 let mut prompt = String::from(
60 "Deno sandboxes are isolated networked microVMs. Create or select a sandbox before sandbox-scoped operations, use `/home/app` as the default workspace, and delete sandboxes when done to avoid leaks.",
61 );
62 prompt.push_str(everruns_core::tool_output_sanitizer::EXEC_OUTPUT_HINT);
63 prompt
64});
65
66pub struct DenoCapability;
67
68impl Capability for DenoCapability {
69 fn id(&self) -> &str {
70 "deno"
71 }
72
73 fn name(&self) -> &str {
74 "Deno Sandboxes"
75 }
76
77 fn description(&self) -> &str {
78 "Run code in cloud-based Deno sandboxes. Create isolated Linux microVMs, execute commands, and manage files. EXPERIMENTAL: This capability may change."
79 }
80
81 fn localizations(&self) -> Vec<CapabilityLocalization> {
82 vec![CapabilityLocalization::text(
83 "uk",
84 "Пісочниці Deno",
85 "Запускайте код у хмарних пісочницях Deno. Створюйте ізольовані мікровіртуальні \
86 машини Linux, виконуйте команди та керуйте файлами. ЕКСПЕРИМЕНТАЛЬНО: ця \
87 можливість може змінитися.",
88 )]
89 }
90
91 fn status(&self) -> CapabilityStatus {
92 CapabilityStatus::Available
93 }
94
95 fn risk_level(&self) -> RiskLevel {
96 RiskLevel::High
97 }
98
99 fn icon(&self) -> Option<&str> {
100 Some("server")
101 }
102
103 fn category(&self) -> Option<&str> {
104 Some("Sandboxes")
105 }
106
107 fn system_prompt_addition(&self) -> Option<&str> {
108 Some(&SYSTEM_PROMPT)
109 }
110
111 fn tools(&self) -> Vec<Box<dyn Tool>> {
112 vec![
113 Box::new(DenoCreateSandboxTool),
114 Box::new(DenoExecTool),
115 Box::new(DenoReadFileTool),
116 Box::new(DenoWriteFileTool),
117 Box::new(DenoListSandboxesTool),
118 Box::new(DenoManageSandboxTool),
119 ]
120 }
121
122 fn dependencies(&self) -> Vec<&'static str> {
123 vec!["session_storage"]
124 }
125
126 fn features(&self) -> Vec<&'static str> {
127 vec![LEASED_RESOURCES_FEATURE]
128 }
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 use everruns_core::capabilities::CapabilityStatus;
135
136 #[test]
137 fn test_capability_metadata() {
138 let cap = DenoCapability;
139 assert_eq!(cap.id(), "deno");
140 assert_eq!(cap.name(), "Deno Sandboxes");
141 assert_eq!(cap.status(), CapabilityStatus::Available);
142 assert_eq!(cap.icon(), Some("server"));
143 assert_eq!(cap.category(), Some("Sandboxes"));
144 }
145
146 #[test]
147 fn test_capability_has_all_tools() {
148 let cap = DenoCapability;
149 let tools = cap.tools();
150 assert_eq!(tools.len(), 6);
151
152 let names: Vec<&str> = tools.iter().map(|t| t.name()).collect();
153 assert!(names.contains(&"deno_create_sandbox"));
154 assert!(names.contains(&"deno_exec"));
155 assert!(names.contains(&"deno_read_file"));
156 assert!(names.contains(&"deno_write_file"));
157 assert!(names.contains(&"deno_list_sandboxes"));
158 assert!(names.contains(&"deno_manage_sandbox"));
159 }
160
161 #[tokio::test]
162 async fn system_prompt_within_budget() {
163 let cap = DenoCapability;
164 let ctx = everruns_core::capabilities::SystemPromptContext::without_file_store(
165 everruns_core::SessionId::new(),
166 );
167 let prompt = cap.system_prompt_contribution(&ctx).await.unwrap();
168 assert!(prompt.len() <= 1300, "prompt is {} bytes", prompt.len());
172 }
173}