hopx-ai 0.1.11__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- hopx_ai/__init__.py +114 -0
- hopx_ai/_agent_client.py +373 -0
- hopx_ai/_async_client.py +230 -0
- hopx_ai/_client.py +230 -0
- hopx_ai/_generated/__init__.py +22 -0
- hopx_ai/_generated/models.py +502 -0
- hopx_ai/_utils.py +9 -0
- hopx_ai/_ws_client.py +141 -0
- hopx_ai/async_sandbox.py +427 -0
- hopx_ai/cache.py +97 -0
- hopx_ai/commands.py +174 -0
- hopx_ai/desktop.py +1227 -0
- hopx_ai/env_vars.py +242 -0
- hopx_ai/errors.py +249 -0
- hopx_ai/files.py +489 -0
- hopx_ai/models.py +274 -0
- hopx_ai/models_updated.py +270 -0
- hopx_ai/sandbox.py +1439 -0
- hopx_ai/template/__init__.py +47 -0
- hopx_ai/template/build_flow.py +540 -0
- hopx_ai/template/builder.py +300 -0
- hopx_ai/template/file_hasher.py +81 -0
- hopx_ai/template/ready_checks.py +106 -0
- hopx_ai/template/tar_creator.py +122 -0
- hopx_ai/template/types.py +199 -0
- hopx_ai/terminal.py +164 -0
- hopx_ai-0.1.11.dist-info/METADATA +462 -0
- hopx_ai-0.1.11.dist-info/RECORD +29 -0
- hopx_ai-0.1.11.dist-info/WHEEL +4 -0
hopx_ai/models.py
ADDED
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data models for Bunnyshell Sandboxes SDK.
|
|
3
|
+
|
|
4
|
+
This module combines hand-crafted models (SandboxInfo, Template) with
|
|
5
|
+
auto-generated models from OpenAPI spec for type safety and maintainability.
|
|
6
|
+
|
|
7
|
+
Auto-generated models are re-exported for convenience with backward-compatible names.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Optional, List, Dict, Any
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
|
|
14
|
+
# Import auto-generated models
|
|
15
|
+
from ._generated.models import (
|
|
16
|
+
# Execution models (auto-generated)
|
|
17
|
+
ExecuteResponse as _ExecuteResponse,
|
|
18
|
+
ExecuteRequest as _ExecuteRequest,
|
|
19
|
+
RichOutput as _RichOutput,
|
|
20
|
+
Language,
|
|
21
|
+
|
|
22
|
+
# File models (auto-generated)
|
|
23
|
+
FileInfo as _FileInfo,
|
|
24
|
+
FileListResponse,
|
|
25
|
+
FileContentResponse,
|
|
26
|
+
FileWriteRequest,
|
|
27
|
+
FileResponse,
|
|
28
|
+
|
|
29
|
+
# Command models (auto-generated)
|
|
30
|
+
CommandResponse as _CommandResponse,
|
|
31
|
+
|
|
32
|
+
# Desktop models (auto-generated)
|
|
33
|
+
VNCInfo as _VNCInfo,
|
|
34
|
+
WindowInfo as _WindowInfo,
|
|
35
|
+
RecordingInfo as _RecordingInfo,
|
|
36
|
+
DisplayInfo as _DisplayInfo,
|
|
37
|
+
ScreenshotResponse,
|
|
38
|
+
|
|
39
|
+
# Error models (auto-generated)
|
|
40
|
+
ErrorResponse,
|
|
41
|
+
Code as ErrorCode, # Generated as "Code", export as "ErrorCode"
|
|
42
|
+
|
|
43
|
+
# Metrics models (auto-generated)
|
|
44
|
+
MetricsSnapshot,
|
|
45
|
+
SystemMetrics,
|
|
46
|
+
HealthResponse,
|
|
47
|
+
InfoResponse as _InfoResponse,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# =============================================================================
|
|
52
|
+
# ENHANCED MODELS (Auto-generated + Convenience Methods for DX)
|
|
53
|
+
# =============================================================================
|
|
54
|
+
|
|
55
|
+
class RichOutput(_RichOutput):
|
|
56
|
+
"""
|
|
57
|
+
Rich output from code execution (plots, DataFrames, etc.).
|
|
58
|
+
|
|
59
|
+
Auto-generated from OpenAPI spec with convenience methods added.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
return f"<RichOutput type={self.type}>"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ExecutionResult(_ExecuteResponse):
|
|
67
|
+
"""
|
|
68
|
+
Result of code execution.
|
|
69
|
+
|
|
70
|
+
Auto-generated from OpenAPI spec (ExecuteResponse) with convenience methods.
|
|
71
|
+
This is an alias for backward compatibility while adding DX improvements.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
# Add rich_outputs field (from /execute/rich endpoint, not in base ExecuteResponse)
|
|
75
|
+
rich_outputs: Optional[List[RichOutput]] = Field(default=None, description="Rich outputs (plots, etc.)")
|
|
76
|
+
|
|
77
|
+
@property
|
|
78
|
+
def rich_count(self) -> int:
|
|
79
|
+
"""Number of rich outputs."""
|
|
80
|
+
return len(self.rich_outputs) if self.rich_outputs else 0
|
|
81
|
+
|
|
82
|
+
def __repr__(self) -> str:
|
|
83
|
+
status = "✅" if self.success else "❌"
|
|
84
|
+
exec_time = self.execution_time if self.execution_time is not None else 0.0
|
|
85
|
+
return f"<ExecutionResult {status} time={exec_time:.3f}s rich={self.rich_count}>"
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
class CommandResult(_CommandResponse):
|
|
89
|
+
"""
|
|
90
|
+
Result of command execution.
|
|
91
|
+
|
|
92
|
+
Auto-generated from OpenAPI spec (CommandResponse) with convenience methods.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
@property
|
|
96
|
+
def success(self) -> bool:
|
|
97
|
+
"""Whether command succeeded (exit code 0)."""
|
|
98
|
+
return self.exit_code == 0
|
|
99
|
+
|
|
100
|
+
def __repr__(self) -> str:
|
|
101
|
+
status = "✅" if self.success else "❌"
|
|
102
|
+
return f"<CommandResult {status} exit={self.exit_code} time={self.execution_time:.3f}s>"
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class FileInfo(_FileInfo):
|
|
106
|
+
"""
|
|
107
|
+
File or directory information.
|
|
108
|
+
|
|
109
|
+
Auto-generated from OpenAPI spec with convenience methods.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
@property
|
|
113
|
+
def is_file(self) -> bool:
|
|
114
|
+
"""Whether this is a file (not directory)."""
|
|
115
|
+
return not self.is_directory
|
|
116
|
+
|
|
117
|
+
@property
|
|
118
|
+
def is_dir(self) -> bool:
|
|
119
|
+
"""Alias for is_directory (backward compat)."""
|
|
120
|
+
return self.is_directory
|
|
121
|
+
|
|
122
|
+
@property
|
|
123
|
+
def size_kb(self) -> float:
|
|
124
|
+
"""Size in kilobytes."""
|
|
125
|
+
return self.size / 1024
|
|
126
|
+
|
|
127
|
+
@property
|
|
128
|
+
def size_mb(self) -> float:
|
|
129
|
+
"""Size in megabytes."""
|
|
130
|
+
return self.size / (1024 * 1024)
|
|
131
|
+
|
|
132
|
+
def __repr__(self) -> str:
|
|
133
|
+
type_icon = "📁" if self.is_directory else "📄"
|
|
134
|
+
return f"<FileInfo {type_icon} {self.name} ({self.size} bytes)>"
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
class VNCInfo(_VNCInfo):
|
|
138
|
+
"""VNC server information with convenience properties."""
|
|
139
|
+
|
|
140
|
+
@property
|
|
141
|
+
def running(self) -> bool:
|
|
142
|
+
"""Whether VNC server is running (always True if we have this info)."""
|
|
143
|
+
return True
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class WindowInfo(_WindowInfo):
|
|
147
|
+
"""Window information with convenience properties."""
|
|
148
|
+
pass
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
class RecordingInfo(_RecordingInfo):
|
|
152
|
+
"""Screen recording information with convenience properties."""
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def is_recording(self) -> bool:
|
|
156
|
+
"""Whether recording is in progress."""
|
|
157
|
+
return self.status == "recording"
|
|
158
|
+
|
|
159
|
+
@property
|
|
160
|
+
def is_ready(self) -> bool:
|
|
161
|
+
"""Whether recording is ready to download."""
|
|
162
|
+
return self.status == "stopped"
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
class DisplayInfo(_DisplayInfo):
|
|
166
|
+
"""Display information with convenience properties."""
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def resolution(self) -> str:
|
|
170
|
+
"""Resolution as string (e.g., '1920x1080')."""
|
|
171
|
+
return f"{self.width}x{self.height}"
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# =============================================================================
|
|
175
|
+
# HAND-CRAFTED MODELS (Not in Agent API - for Sandbox Management)
|
|
176
|
+
# =============================================================================
|
|
177
|
+
|
|
178
|
+
class Resources(BaseModel):
|
|
179
|
+
"""Resource specifications."""
|
|
180
|
+
|
|
181
|
+
vcpu: int = Field(..., description="Number of vCPUs")
|
|
182
|
+
memory_mb: int = Field(..., description="Memory in MB")
|
|
183
|
+
disk_mb: int = Field(..., description="Disk size in MB")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
class SandboxInfo(BaseModel):
|
|
187
|
+
"""Sandbox information."""
|
|
188
|
+
|
|
189
|
+
sandbox_id: str = Field(..., description="Sandbox ID")
|
|
190
|
+
template_id: Optional[str] = Field(None, description="Template ID")
|
|
191
|
+
template_name: Optional[str] = Field(None, description="Template name")
|
|
192
|
+
organization_id: int = Field(..., description="Organization ID")
|
|
193
|
+
node_id: Optional[str] = Field(None, description="Node ID where VM is running")
|
|
194
|
+
region: Optional[str] = Field(None, description="Region")
|
|
195
|
+
status: str = Field(..., description="Sandbox status (running, stopped, paused, creating)")
|
|
196
|
+
public_host: str = Field(..., description="Public URL to access sandbox")
|
|
197
|
+
resources: Optional[Resources] = Field(None, description="Resource allocation")
|
|
198
|
+
started_at: Optional[datetime] = Field(None, description="When sandbox started")
|
|
199
|
+
end_at: Optional[datetime] = Field(None, description="When sandbox will be terminated")
|
|
200
|
+
created_at: Optional[datetime] = Field(None, description="Creation timestamp")
|
|
201
|
+
|
|
202
|
+
def __repr__(self) -> str:
|
|
203
|
+
return f"<SandboxInfo {self.sandbox_id}: {self.status}>"
|
|
204
|
+
|
|
205
|
+
def __str__(self) -> str:
|
|
206
|
+
return f"SandboxInfo(sandbox_id={self.sandbox_id}, status={self.status}, url={self.public_host})"
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
class TemplateResources(BaseModel):
|
|
210
|
+
"""Template resource specifications."""
|
|
211
|
+
|
|
212
|
+
vcpu: Optional[int] = None
|
|
213
|
+
memory_mb: Optional[int] = None
|
|
214
|
+
disk_gb: Optional[int] = None
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class Template(BaseModel):
|
|
218
|
+
"""VM template."""
|
|
219
|
+
|
|
220
|
+
id: str = Field(..., description="Template ID")
|
|
221
|
+
name: str = Field(..., description="Template name (slug)")
|
|
222
|
+
display_name: str = Field(..., description="Display name")
|
|
223
|
+
description: Optional[str] = Field(None, description="Description")
|
|
224
|
+
category: Optional[str] = Field(None, description="Category")
|
|
225
|
+
language: Optional[str] = Field(None, description="Primary language")
|
|
226
|
+
icon: Optional[str] = Field(None, description="Icon URL or emoji")
|
|
227
|
+
default_resources: Optional[TemplateResources] = None
|
|
228
|
+
min_resources: Optional[TemplateResources] = None
|
|
229
|
+
max_resources: Optional[TemplateResources] = None
|
|
230
|
+
features: List[str] = Field(default_factory=list)
|
|
231
|
+
tags: List[str] = Field(default_factory=list)
|
|
232
|
+
popularity_score: Optional[int] = None
|
|
233
|
+
docs_url: Optional[str] = None
|
|
234
|
+
is_active: bool = Field(default=True)
|
|
235
|
+
|
|
236
|
+
def __repr__(self) -> str:
|
|
237
|
+
return f"<Template {self.name}: {self.display_name}>"
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
# =============================================================================
|
|
241
|
+
# EXPORTS
|
|
242
|
+
# =============================================================================
|
|
243
|
+
|
|
244
|
+
__all__ = [
|
|
245
|
+
# Enhanced models (auto-generated + convenience)
|
|
246
|
+
"ExecutionResult",
|
|
247
|
+
"CommandResult",
|
|
248
|
+
"FileInfo",
|
|
249
|
+
"RichOutput",
|
|
250
|
+
"VNCInfo",
|
|
251
|
+
"WindowInfo",
|
|
252
|
+
"RecordingInfo",
|
|
253
|
+
"DisplayInfo",
|
|
254
|
+
|
|
255
|
+
# Hand-crafted models
|
|
256
|
+
"SandboxInfo",
|
|
257
|
+
"Template",
|
|
258
|
+
"Resources",
|
|
259
|
+
"TemplateResources",
|
|
260
|
+
|
|
261
|
+
# Auto-generated models (direct exports)
|
|
262
|
+
"Language",
|
|
263
|
+
"ErrorResponse",
|
|
264
|
+
"ErrorCode",
|
|
265
|
+
"MetricsSnapshot",
|
|
266
|
+
"SystemMetrics",
|
|
267
|
+
"HealthResponse",
|
|
268
|
+
"FileListResponse",
|
|
269
|
+
"FileContentResponse",
|
|
270
|
+
"FileWriteRequest",
|
|
271
|
+
"FileResponse",
|
|
272
|
+
"ScreenshotResponse",
|
|
273
|
+
]
|
|
274
|
+
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Data models for Bunnyshell Sandboxes SDK.
|
|
3
|
+
|
|
4
|
+
This module combines hand-crafted models (SandboxInfo, Template) with
|
|
5
|
+
auto-generated models from OpenAPI spec for type safety and maintainability.
|
|
6
|
+
|
|
7
|
+
Auto-generated models are re-exported for convenience with backward-compatible names.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from typing import Optional, List, Dict, Any
|
|
12
|
+
from pydantic import BaseModel, Field
|
|
13
|
+
|
|
14
|
+
# Import auto-generated models
|
|
15
|
+
from ._generated.models import (
|
|
16
|
+
# Execution models (auto-generated)
|
|
17
|
+
ExecuteResponse as _ExecuteResponse,
|
|
18
|
+
ExecuteRequest as _ExecuteRequest,
|
|
19
|
+
RichOutput as _RichOutput,
|
|
20
|
+
Language,
|
|
21
|
+
|
|
22
|
+
# File models (auto-generated)
|
|
23
|
+
FileInfo as _FileInfo,
|
|
24
|
+
FileListResponse,
|
|
25
|
+
FileContentResponse,
|
|
26
|
+
FileWriteRequest,
|
|
27
|
+
FileResponse,
|
|
28
|
+
|
|
29
|
+
# Command models (auto-generated)
|
|
30
|
+
CommandResponse as _CommandResponse,
|
|
31
|
+
|
|
32
|
+
# Desktop models (auto-generated)
|
|
33
|
+
VNCInfo as _VNCInfo,
|
|
34
|
+
WindowInfo as _WindowInfo,
|
|
35
|
+
RecordingInfo as _RecordingInfo,
|
|
36
|
+
DisplayInfo as _DisplayInfo,
|
|
37
|
+
ScreenshotResponse,
|
|
38
|
+
|
|
39
|
+
# Error models (auto-generated)
|
|
40
|
+
ErrorResponse,
|
|
41
|
+
ErrorCode,
|
|
42
|
+
|
|
43
|
+
# Metrics models (auto-generated)
|
|
44
|
+
MetricsSnapshot,
|
|
45
|
+
SystemMetrics,
|
|
46
|
+
HealthResponse,
|
|
47
|
+
InfoResponse as _InfoResponse,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# =============================================================================
|
|
52
|
+
# ENHANCED MODELS (Auto-generated + Convenience Methods for DX)
|
|
53
|
+
# =============================================================================
|
|
54
|
+
|
|
55
|
+
class RichOutput(_RichOutput):
|
|
56
|
+
"""
|
|
57
|
+
Rich output from code execution (plots, DataFrames, etc.).
|
|
58
|
+
|
|
59
|
+
Auto-generated from OpenAPI spec with convenience methods added.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
def __repr__(self) -> str:
|
|
63
|
+
return f"<RichOutput type={self.type}>"
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class ExecutionResult(_ExecuteResponse):
|
|
67
|
+
"""
|
|
68
|
+
Result of code execution.
|
|
69
|
+
|
|
70
|
+
Auto-generated from OpenAPI spec (ExecuteResponse) with convenience methods.
|
|
71
|
+
This is an alias for backward compatibility while adding DX improvements.
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def rich_count(self) -> int:
|
|
76
|
+
"""Number of rich outputs."""
|
|
77
|
+
return len(self.rich_outputs) if self.rich_outputs else 0
|
|
78
|
+
|
|
79
|
+
def __repr__(self) -> str:
|
|
80
|
+
status = "✅" if self.success else "❌"
|
|
81
|
+
return f"<ExecutionResult {status} time={self.execution_time:.3f}s rich={self.rich_count}>"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class CommandResult(_CommandResponse):
|
|
85
|
+
"""
|
|
86
|
+
Result of command execution.
|
|
87
|
+
|
|
88
|
+
Auto-generated from OpenAPI spec (CommandResponse) with convenience methods.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
@property
|
|
92
|
+
def success(self) -> bool:
|
|
93
|
+
"""Whether command succeeded (exit code 0)."""
|
|
94
|
+
return self.exit_code == 0
|
|
95
|
+
|
|
96
|
+
def __repr__(self) -> str:
|
|
97
|
+
status = "✅" if self.success else "❌"
|
|
98
|
+
return f"<CommandResult {status} exit={self.exit_code} time={self.execution_time:.3f}s>"
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class FileInfo(_FileInfo):
|
|
102
|
+
"""
|
|
103
|
+
File or directory information.
|
|
104
|
+
|
|
105
|
+
Auto-generated from OpenAPI spec with convenience methods.
|
|
106
|
+
"""
|
|
107
|
+
|
|
108
|
+
@property
|
|
109
|
+
def is_file(self) -> bool:
|
|
110
|
+
"""Whether this is a file (not directory)."""
|
|
111
|
+
return not self.is_directory
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def is_dir(self) -> bool:
|
|
115
|
+
"""Alias for is_directory (backward compat)."""
|
|
116
|
+
return self.is_directory
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def size_kb(self) -> float:
|
|
120
|
+
"""Size in kilobytes."""
|
|
121
|
+
return self.size / 1024
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def size_mb(self) -> float:
|
|
125
|
+
"""Size in megabytes."""
|
|
126
|
+
return self.size / (1024 * 1024)
|
|
127
|
+
|
|
128
|
+
def __repr__(self) -> str:
|
|
129
|
+
type_icon = "📁" if self.is_directory else "📄"
|
|
130
|
+
return f"<FileInfo {type_icon} {self.name} ({self.size} bytes)>"
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class VNCInfo(_VNCInfo):
|
|
134
|
+
"""VNC server information with convenience properties."""
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def running(self) -> bool:
|
|
138
|
+
"""Whether VNC server is running (always True if we have this info)."""
|
|
139
|
+
return True
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class WindowInfo(_WindowInfo):
|
|
143
|
+
"""Window information with convenience properties."""
|
|
144
|
+
pass
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
class RecordingInfo(_RecordingInfo):
|
|
148
|
+
"""Screen recording information with convenience properties."""
|
|
149
|
+
|
|
150
|
+
@property
|
|
151
|
+
def is_recording(self) -> bool:
|
|
152
|
+
"""Whether recording is in progress."""
|
|
153
|
+
return self.status == "recording"
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def is_ready(self) -> bool:
|
|
157
|
+
"""Whether recording is ready to download."""
|
|
158
|
+
return self.status == "stopped"
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
class DisplayInfo(_DisplayInfo):
|
|
162
|
+
"""Display information with convenience properties."""
|
|
163
|
+
|
|
164
|
+
@property
|
|
165
|
+
def resolution(self) -> str:
|
|
166
|
+
"""Resolution as string (e.g., '1920x1080')."""
|
|
167
|
+
return f"{self.width}x{self.height}"
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
# =============================================================================
|
|
171
|
+
# HAND-CRAFTED MODELS (Not in Agent API - for Sandbox Management)
|
|
172
|
+
# =============================================================================
|
|
173
|
+
|
|
174
|
+
class Resources(BaseModel):
|
|
175
|
+
"""Resource specifications."""
|
|
176
|
+
|
|
177
|
+
vcpu: int = Field(..., description="Number of vCPUs")
|
|
178
|
+
memory_mb: int = Field(..., description="Memory in MB")
|
|
179
|
+
disk_mb: int = Field(..., description="Disk size in MB")
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
class SandboxInfo(BaseModel):
|
|
183
|
+
"""Sandbox information."""
|
|
184
|
+
|
|
185
|
+
sandbox_id: str = Field(..., description="Sandbox ID")
|
|
186
|
+
template_id: Optional[str] = Field(None, description="Template ID")
|
|
187
|
+
template_name: Optional[str] = Field(None, description="Template name")
|
|
188
|
+
organization_id: int = Field(..., description="Organization ID")
|
|
189
|
+
node_id: Optional[str] = Field(None, description="Node ID where VM is running")
|
|
190
|
+
region: Optional[str] = Field(None, description="Region")
|
|
191
|
+
status: str = Field(..., description="Sandbox status (running, stopped, paused, creating)")
|
|
192
|
+
public_host: str = Field(..., description="Public URL to access sandbox")
|
|
193
|
+
resources: Optional[Resources] = Field(None, description="Resource allocation")
|
|
194
|
+
started_at: Optional[datetime] = Field(None, description="When sandbox started")
|
|
195
|
+
end_at: Optional[datetime] = Field(None, description="When sandbox will be terminated")
|
|
196
|
+
created_at: Optional[datetime] = Field(None, description="Creation timestamp")
|
|
197
|
+
|
|
198
|
+
def __repr__(self) -> str:
|
|
199
|
+
return f"<SandboxInfo {self.sandbox_id}: {self.status}>"
|
|
200
|
+
|
|
201
|
+
def __str__(self) -> str:
|
|
202
|
+
return f"SandboxInfo(sandbox_id={self.sandbox_id}, status={self.status}, url={self.public_host})"
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
class TemplateResources(BaseModel):
|
|
206
|
+
"""Template resource specifications."""
|
|
207
|
+
|
|
208
|
+
vcpu: Optional[int] = None
|
|
209
|
+
memory_mb: Optional[int] = None
|
|
210
|
+
disk_gb: Optional[int] = None
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
class Template(BaseModel):
|
|
214
|
+
"""VM template."""
|
|
215
|
+
|
|
216
|
+
id: str = Field(..., description="Template ID")
|
|
217
|
+
name: str = Field(..., description="Template name (slug)")
|
|
218
|
+
display_name: str = Field(..., description="Display name")
|
|
219
|
+
description: Optional[str] = Field(None, description="Description")
|
|
220
|
+
category: Optional[str] = Field(None, description="Category")
|
|
221
|
+
language: Optional[str] = Field(None, description="Primary language")
|
|
222
|
+
icon: Optional[str] = Field(None, description="Icon URL or emoji")
|
|
223
|
+
default_resources: Optional[TemplateResources] = None
|
|
224
|
+
min_resources: Optional[TemplateResources] = None
|
|
225
|
+
max_resources: Optional[TemplateResources] = None
|
|
226
|
+
features: List[str] = Field(default_factory=list)
|
|
227
|
+
tags: List[str] = Field(default_factory=list)
|
|
228
|
+
popularity_score: Optional[int] = None
|
|
229
|
+
docs_url: Optional[str] = None
|
|
230
|
+
is_active: bool = Field(default=True)
|
|
231
|
+
|
|
232
|
+
def __repr__(self) -> str:
|
|
233
|
+
return f"<Template {self.name}: {self.display_name}>"
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
# =============================================================================
|
|
237
|
+
# EXPORTS
|
|
238
|
+
# =============================================================================
|
|
239
|
+
|
|
240
|
+
__all__ = [
|
|
241
|
+
# Enhanced models (auto-generated + convenience)
|
|
242
|
+
"ExecutionResult",
|
|
243
|
+
"CommandResult",
|
|
244
|
+
"FileInfo",
|
|
245
|
+
"RichOutput",
|
|
246
|
+
"VNCInfo",
|
|
247
|
+
"WindowInfo",
|
|
248
|
+
"RecordingInfo",
|
|
249
|
+
"DisplayInfo",
|
|
250
|
+
|
|
251
|
+
# Hand-crafted models
|
|
252
|
+
"SandboxInfo",
|
|
253
|
+
"Template",
|
|
254
|
+
"Resources",
|
|
255
|
+
"TemplateResources",
|
|
256
|
+
|
|
257
|
+
# Auto-generated models (direct exports)
|
|
258
|
+
"Language",
|
|
259
|
+
"ErrorResponse",
|
|
260
|
+
"ErrorCode",
|
|
261
|
+
"MetricsSnapshot",
|
|
262
|
+
"SystemMetrics",
|
|
263
|
+
"HealthResponse",
|
|
264
|
+
"FileListResponse",
|
|
265
|
+
"FileContentResponse",
|
|
266
|
+
"FileWriteRequest",
|
|
267
|
+
"FileResponse",
|
|
268
|
+
"ScreenshotResponse",
|
|
269
|
+
]
|
|
270
|
+
|