1use crate::{De, Ser};
6use serde::{self, Deserialize, Serialize};
7use std::collections::HashMap;
8
9#[derive(Debug, Clone, Ser, De)]
11pub struct ContainerConfig {
12 #[serde(skip_serializing_if = "Option::is_none")]
14 pub name: Option<String>,
15
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub metadata: Option<HashMap<String, serde_json::Value>>,
19
20 #[serde(skip_serializing_if = "Option::is_none")]
22 pub python_version: Option<String>,
23
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub libraries: Option<Vec<String>>,
27
28 #[serde(skip_serializing_if = "Option::is_none")]
30 pub memory_limit_mb: Option<u32>,
31
32 #[serde(skip_serializing_if = "Option::is_none")]
34 pub cpu_limit: Option<f32>,
35
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub expiration_minutes: Option<u32>,
39}
40
41impl Default for ContainerConfig {
42 fn default() -> Self {
43 Self {
44 name: None,
45 metadata: None,
46 python_version: Some("3.11".to_string()),
47 libraries: None,
48 memory_limit_mb: None,
49 cpu_limit: None,
50 expiration_minutes: None,
51 }
52 }
53}
54
55#[derive(Debug, Clone, Ser, De)]
57pub struct Container {
58 pub id: String,
60
61 pub object: String,
63
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub name: Option<String>,
67
68 pub status: ContainerStatus,
70
71 pub created_at: u64,
73
74 pub last_activity_at: u64,
76
77 pub expires_at: u64,
79
80 pub python_version: String,
82
83 #[serde(default)]
85 pub libraries: Vec<String>,
86
87 #[serde(default)]
89 pub metadata: HashMap<String, serde_json::Value>,
90
91 #[serde(skip_serializing_if = "Option::is_none")]
93 pub files: Option<Vec<ContainerFile>>,
94
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub memory_usage_mb: Option<u32>,
98
99 #[serde(skip_serializing_if = "Option::is_none")]
101 pub cpu_usage_percent: Option<f32>,
102}
103
104#[derive(Debug, Clone, Ser, De, PartialEq, Eq)]
106#[serde(rename_all = "lowercase")]
107pub enum ContainerStatus {
108 Creating,
110 Active,
112 Idle,
114 Expired,
116 Deleting,
118 Error,
120}
121
122#[derive(Debug, Clone, Ser, De)]
124pub struct ContainerFile {
125 pub id: String,
127
128 pub object: String,
130
131 pub filename: String,
133
134 pub size: u64,
136
137 #[serde(skip_serializing_if = "Option::is_none")]
139 pub mime_type: Option<String>,
140
141 pub created_at: u64,
143
144 #[serde(skip_serializing_if = "Option::is_none")]
146 pub modified_at: Option<u64>,
147
148 pub path: String,
150
151 #[serde(default = "default_true")]
153 pub readable: bool,
154
155 #[serde(default = "default_true")]
157 pub writable: bool,
158
159 #[serde(default)]
161 pub executable: bool,
162}
163
164fn default_true() -> bool {
165 true
166}
167
168#[derive(Debug, Clone, Ser, De)]
170pub struct ContainerList {
171 pub object: String,
173
174 pub data: Vec<Container>,
176
177 #[serde(skip_serializing_if = "Option::is_none")]
179 pub first_id: Option<String>,
180
181 #[serde(skip_serializing_if = "Option::is_none")]
183 pub last_id: Option<String>,
184
185 pub has_more: bool,
187}
188
189#[derive(Debug, Clone, Ser, De)]
191pub struct ContainerFileList {
192 pub object: String,
194
195 pub data: Vec<ContainerFile>,
197
198 pub total: u32,
200}
201
202#[derive(Debug, Clone, Ser, De)]
204pub struct CodeExecutionRequest {
205 pub code: String,
207
208 #[serde(skip_serializing_if = "Option::is_none")]
210 pub timeout_ms: Option<u32>,
211
212 #[serde(skip_serializing_if = "Option::is_none")]
214 pub include_output: Option<bool>,
215}
216
217#[derive(Debug, Clone, Ser, De)]
219pub struct CodeExecutionResult {
220 pub id: String,
222
223 pub status: ExecutionStatus,
225
226 #[serde(skip_serializing_if = "Option::is_none")]
228 pub stdout: Option<String>,
229
230 #[serde(skip_serializing_if = "Option::is_none")]
232 pub stderr: Option<String>,
233
234 #[serde(skip_serializing_if = "Option::is_none")]
236 pub exit_code: Option<i32>,
237
238 #[serde(skip_serializing_if = "Option::is_none")]
240 pub execution_time_ms: Option<u32>,
241
242 #[serde(default)]
244 pub created_files: Vec<ContainerFile>,
245
246 #[serde(default)]
248 pub modified_files: Vec<ContainerFile>,
249
250 #[serde(skip_serializing_if = "Option::is_none")]
252 pub error: Option<String>,
253
254 #[serde(skip_serializing_if = "Option::is_none")]
256 pub memory_used_mb: Option<u32>,
257
258 #[serde(default)]
260 pub citations: Vec<CodeCitation>,
261}
262
263#[derive(Debug, Clone, Ser, De, PartialEq, Eq)]
265#[serde(rename_all = "lowercase")]
266pub enum ExecutionStatus {
267 Running,
269 Success,
271 Failed,
273 Timeout,
275 Cancelled,
277}
278
279#[derive(Debug, Clone, Ser, De)]
281pub struct CodeCitation {
282 pub citation_type: String,
284
285 pub source: String,
287
288 #[serde(skip_serializing_if = "Option::is_none")]
290 pub lines: Option<Vec<u32>>,
291
292 #[serde(default)]
294 pub metadata: HashMap<String, serde_json::Value>,
295}
296
297#[derive(Debug, Clone, Ser, De)]
299pub struct ListContainersParams {
300 #[serde(skip_serializing_if = "Option::is_none")]
302 pub limit: Option<u32>,
303
304 #[serde(skip_serializing_if = "Option::is_none")]
306 pub after: Option<String>,
307
308 #[serde(skip_serializing_if = "Option::is_none")]
310 pub before: Option<String>,
311
312 #[serde(skip_serializing_if = "Option::is_none")]
314 pub status: Option<ContainerStatus>,
315
316 #[serde(skip_serializing_if = "Option::is_none")]
318 pub order: Option<String>,
319}
320
321#[derive(Debug, Clone, Ser, De)]
323pub struct EnhancedCodeInterpreterConfig {
324 #[serde(skip_serializing_if = "Option::is_none")]
326 pub container_mode: Option<ContainerMode>,
327
328 #[serde(skip_serializing_if = "Option::is_none")]
330 pub container_id: Option<String>,
331
332 #[serde(skip_serializing_if = "Option::is_none")]
334 pub container_config: Option<ContainerConfig>,
335
336 #[serde(skip_serializing_if = "Option::is_none")]
338 pub language: Option<String>,
339
340 #[serde(skip_serializing_if = "Option::is_none")]
342 pub max_execution_time_ms: Option<u32>,
343
344 #[serde(skip_serializing_if = "Option::is_none")]
346 pub libraries: Option<Vec<String>>,
347
348 #[serde(skip_serializing_if = "Option::is_none")]
350 pub file_ids: Option<Vec<String>>,
351
352 #[serde(skip_serializing_if = "Option::is_none")]
354 pub persist_container: Option<bool>,
355
356 #[serde(skip_serializing_if = "Option::is_none")]
358 pub include_citations: Option<bool>,
359}
360
361#[derive(Debug, Clone, Ser, De, PartialEq, Eq)]
363#[serde(rename_all = "lowercase")]
364#[derive(Default)]
365pub enum ContainerMode {
366 #[default]
368 Auto,
369 Explicit,
371}
372
373pub struct ContainerBuilder {
375 config: ContainerConfig,
377}
378
379impl Default for ContainerBuilder {
380 fn default() -> Self {
381 Self::new()
382 }
383}
384
385impl ContainerBuilder {
386 #[must_use]
388 pub fn new() -> Self {
389 Self {
390 config: ContainerConfig::default(),
391 }
392 }
393
394 pub fn name(mut self, name: impl Into<String>) -> Self {
396 self.config.name = Some(name.into());
397 self
398 }
399
400 pub fn python_version(mut self, version: impl Into<String>) -> Self {
402 self.config.python_version = Some(version.into());
403 self
404 }
405
406 #[must_use]
408 pub fn libraries(mut self, libs: Vec<String>) -> Self {
409 self.config.libraries = Some(libs);
410 self
411 }
412
413 pub fn add_library(mut self, lib: impl Into<String>) -> Self {
415 let libs = self.config.libraries.get_or_insert_with(Vec::new);
416 libs.push(lib.into());
417 self
418 }
419
420 #[must_use]
422 pub fn memory_limit_mb(mut self, limit: u32) -> Self {
423 self.config.memory_limit_mb = Some(limit);
424 self
425 }
426
427 #[must_use]
429 pub fn cpu_limit(mut self, limit: f32) -> Self {
430 self.config.cpu_limit = Some(limit);
431 self
432 }
433
434 #[must_use]
436 pub fn expiration_minutes(mut self, minutes: u32) -> Self {
437 self.config.expiration_minutes = Some(minutes);
438 self
439 }
440
441 pub fn metadata(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
443 let metadata = self.config.metadata.get_or_insert_with(HashMap::new);
444 metadata.insert(key.into(), value);
445 self
446 }
447
448 #[must_use]
450 pub fn build(self) -> ContainerConfig {
451 self.config
452 }
453}
454
455#[cfg(test)]
456mod tests {
457 use super::*;
458
459 #[test]
460 fn test_container_builder() {
461 let config = ContainerBuilder::new()
462 .name("test-container")
463 .python_version("3.11")
464 .add_library("numpy")
465 .add_library("pandas")
466 .memory_limit_mb(1024)
467 .cpu_limit(2.0)
468 .build();
469
470 assert_eq!(config.name, Some("test-container".to_string()));
471 assert_eq!(config.python_version, Some("3.11".to_string()));
472 assert_eq!(
473 config.libraries,
474 Some(vec!["numpy".to_string(), "pandas".to_string()])
475 );
476 assert_eq!(config.memory_limit_mb, Some(1024));
477 assert_eq!(config.cpu_limit, Some(2.0));
478 }
479}