agentrun-inner-test 0.0.46__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.
Files changed (135) hide show
  1. agentrun/__init__.py +325 -0
  2. agentrun/agent_runtime/__client_async_template.py +466 -0
  3. agentrun/agent_runtime/__endpoint_async_template.py +345 -0
  4. agentrun/agent_runtime/__init__.py +53 -0
  5. agentrun/agent_runtime/__runtime_async_template.py +477 -0
  6. agentrun/agent_runtime/api/__data_async_template.py +58 -0
  7. agentrun/agent_runtime/api/__init__.py +6 -0
  8. agentrun/agent_runtime/api/control.py +1362 -0
  9. agentrun/agent_runtime/api/data.py +98 -0
  10. agentrun/agent_runtime/client.py +868 -0
  11. agentrun/agent_runtime/endpoint.py +649 -0
  12. agentrun/agent_runtime/model.py +362 -0
  13. agentrun/agent_runtime/runtime.py +904 -0
  14. agentrun/credential/__client_async_template.py +177 -0
  15. agentrun/credential/__credential_async_template.py +216 -0
  16. agentrun/credential/__init__.py +28 -0
  17. agentrun/credential/api/__init__.py +5 -0
  18. agentrun/credential/api/control.py +606 -0
  19. agentrun/credential/client.py +319 -0
  20. agentrun/credential/credential.py +381 -0
  21. agentrun/credential/model.py +248 -0
  22. agentrun/integration/__init__.py +21 -0
  23. agentrun/integration/agentscope/__init__.py +12 -0
  24. agentrun/integration/agentscope/adapter.py +17 -0
  25. agentrun/integration/agentscope/builtin.py +65 -0
  26. agentrun/integration/agentscope/message_adapter.py +185 -0
  27. agentrun/integration/agentscope/model_adapter.py +60 -0
  28. agentrun/integration/agentscope/tool_adapter.py +59 -0
  29. agentrun/integration/builtin/__init__.py +16 -0
  30. agentrun/integration/builtin/model.py +93 -0
  31. agentrun/integration/builtin/sandbox.py +1234 -0
  32. agentrun/integration/builtin/toolset.py +47 -0
  33. agentrun/integration/crewai/__init__.py +12 -0
  34. agentrun/integration/crewai/adapter.py +9 -0
  35. agentrun/integration/crewai/builtin.py +65 -0
  36. agentrun/integration/crewai/model_adapter.py +31 -0
  37. agentrun/integration/crewai/tool_adapter.py +26 -0
  38. agentrun/integration/google_adk/__init__.py +12 -0
  39. agentrun/integration/google_adk/adapter.py +15 -0
  40. agentrun/integration/google_adk/builtin.py +65 -0
  41. agentrun/integration/google_adk/message_adapter.py +144 -0
  42. agentrun/integration/google_adk/model_adapter.py +46 -0
  43. agentrun/integration/google_adk/tool_adapter.py +235 -0
  44. agentrun/integration/langchain/__init__.py +30 -0
  45. agentrun/integration/langchain/adapter.py +15 -0
  46. agentrun/integration/langchain/builtin.py +71 -0
  47. agentrun/integration/langchain/message_adapter.py +141 -0
  48. agentrun/integration/langchain/model_adapter.py +37 -0
  49. agentrun/integration/langchain/tool_adapter.py +50 -0
  50. agentrun/integration/langgraph/__init__.py +35 -0
  51. agentrun/integration/langgraph/adapter.py +20 -0
  52. agentrun/integration/langgraph/agent_converter.py +1073 -0
  53. agentrun/integration/langgraph/builtin.py +65 -0
  54. agentrun/integration/pydantic_ai/__init__.py +12 -0
  55. agentrun/integration/pydantic_ai/adapter.py +13 -0
  56. agentrun/integration/pydantic_ai/builtin.py +65 -0
  57. agentrun/integration/pydantic_ai/model_adapter.py +44 -0
  58. agentrun/integration/pydantic_ai/tool_adapter.py +19 -0
  59. agentrun/integration/utils/__init__.py +112 -0
  60. agentrun/integration/utils/adapter.py +560 -0
  61. agentrun/integration/utils/canonical.py +164 -0
  62. agentrun/integration/utils/converter.py +134 -0
  63. agentrun/integration/utils/model.py +110 -0
  64. agentrun/integration/utils/tool.py +1759 -0
  65. agentrun/model/__client_async_template.py +357 -0
  66. agentrun/model/__init__.py +57 -0
  67. agentrun/model/__model_proxy_async_template.py +270 -0
  68. agentrun/model/__model_service_async_template.py +267 -0
  69. agentrun/model/api/__init__.py +6 -0
  70. agentrun/model/api/control.py +1173 -0
  71. agentrun/model/api/data.py +196 -0
  72. agentrun/model/client.py +674 -0
  73. agentrun/model/model.py +235 -0
  74. agentrun/model/model_proxy.py +439 -0
  75. agentrun/model/model_service.py +438 -0
  76. agentrun/sandbox/__aio_sandbox_async_template.py +523 -0
  77. agentrun/sandbox/__browser_sandbox_async_template.py +110 -0
  78. agentrun/sandbox/__client_async_template.py +491 -0
  79. agentrun/sandbox/__code_interpreter_sandbox_async_template.py +463 -0
  80. agentrun/sandbox/__init__.py +69 -0
  81. agentrun/sandbox/__sandbox_async_template.py +463 -0
  82. agentrun/sandbox/__template_async_template.py +152 -0
  83. agentrun/sandbox/aio_sandbox.py +905 -0
  84. agentrun/sandbox/api/__aio_data_async_template.py +335 -0
  85. agentrun/sandbox/api/__browser_data_async_template.py +140 -0
  86. agentrun/sandbox/api/__code_interpreter_data_async_template.py +206 -0
  87. agentrun/sandbox/api/__init__.py +19 -0
  88. agentrun/sandbox/api/__sandbox_data_async_template.py +107 -0
  89. agentrun/sandbox/api/aio_data.py +551 -0
  90. agentrun/sandbox/api/browser_data.py +172 -0
  91. agentrun/sandbox/api/code_interpreter_data.py +396 -0
  92. agentrun/sandbox/api/control.py +1051 -0
  93. agentrun/sandbox/api/playwright_async.py +492 -0
  94. agentrun/sandbox/api/playwright_sync.py +492 -0
  95. agentrun/sandbox/api/sandbox_data.py +154 -0
  96. agentrun/sandbox/browser_sandbox.py +185 -0
  97. agentrun/sandbox/client.py +925 -0
  98. agentrun/sandbox/code_interpreter_sandbox.py +823 -0
  99. agentrun/sandbox/model.py +397 -0
  100. agentrun/sandbox/sandbox.py +848 -0
  101. agentrun/sandbox/template.py +217 -0
  102. agentrun/server/__init__.py +191 -0
  103. agentrun/server/agui_normalizer.py +180 -0
  104. agentrun/server/agui_protocol.py +797 -0
  105. agentrun/server/invoker.py +309 -0
  106. agentrun/server/model.py +427 -0
  107. agentrun/server/openai_protocol.py +535 -0
  108. agentrun/server/protocol.py +140 -0
  109. agentrun/server/server.py +208 -0
  110. agentrun/toolset/__client_async_template.py +62 -0
  111. agentrun/toolset/__init__.py +51 -0
  112. agentrun/toolset/__toolset_async_template.py +204 -0
  113. agentrun/toolset/api/__init__.py +17 -0
  114. agentrun/toolset/api/control.py +262 -0
  115. agentrun/toolset/api/mcp.py +100 -0
  116. agentrun/toolset/api/openapi.py +1251 -0
  117. agentrun/toolset/client.py +102 -0
  118. agentrun/toolset/model.py +321 -0
  119. agentrun/toolset/toolset.py +270 -0
  120. agentrun/utils/__data_api_async_template.py +720 -0
  121. agentrun/utils/__init__.py +5 -0
  122. agentrun/utils/__resource_async_template.py +158 -0
  123. agentrun/utils/config.py +258 -0
  124. agentrun/utils/control_api.py +78 -0
  125. agentrun/utils/data_api.py +1120 -0
  126. agentrun/utils/exception.py +151 -0
  127. agentrun/utils/helper.py +108 -0
  128. agentrun/utils/log.py +77 -0
  129. agentrun/utils/model.py +168 -0
  130. agentrun/utils/resource.py +291 -0
  131. agentrun_inner_test-0.0.46.dist-info/METADATA +263 -0
  132. agentrun_inner_test-0.0.46.dist-info/RECORD +135 -0
  133. agentrun_inner_test-0.0.46.dist-info/WHEEL +5 -0
  134. agentrun_inner_test-0.0.46.dist-info/licenses/LICENSE +201 -0
  135. agentrun_inner_test-0.0.46.dist-info/top_level.txt +1 -0
@@ -0,0 +1,905 @@
1
+ """
2
+ This file is auto generated by the code generation script.
3
+ Do not modify this file manually.
4
+ Use the `make codegen` command to regenerate.
5
+
6
+ 当前文件为自动生成的控制 API 客户端代码。请勿手动修改此文件。
7
+ 使用 `make codegen` 命令重新生成。
8
+
9
+ source: agentrun/sandbox/__aio_sandbox_async_template.py
10
+
11
+ All-in-One 沙箱高层API模板 / All-in-One Sandbox High-Level API Template
12
+
13
+ 此模板用于生成 All-in-One 沙箱资源的高级API代码,结合了浏览器和代码解释器的功能。
14
+ This template is used to generate high-level API code for All-in-One sandbox resources,
15
+ combining browser and code interpreter capabilities.
16
+ """
17
+
18
+ import asyncio
19
+ import time # noqa: F401
20
+ from typing import Optional
21
+
22
+ from agentrun.sandbox.api.aio_data import AioDataAPI
23
+ from agentrun.sandbox.model import CodeLanguage, TemplateType
24
+ from agentrun.utils.exception import ServerError
25
+ from agentrun.utils.log import logger
26
+
27
+ from .sandbox import Sandbox
28
+
29
+ # ========================================
30
+ # Code Interpreter Helper Classes
31
+ # ========================================
32
+
33
+
34
+ class FileOperations:
35
+ """File upload/download operations."""
36
+
37
+ def __init__(self, sandbox: "AioSandbox"):
38
+ self._sandbox = sandbox
39
+
40
+ async def read_async(self, path: str):
41
+ """Read a file from the sandbox (async).
42
+ Args:
43
+ path: Remote file path in the sandbox
44
+ Returns:
45
+ File content
46
+ """
47
+ return await self._sandbox.data_api.read_file_async(path=path)
48
+
49
+ def read(self, path: str):
50
+ """Read a file from the sandbox (async).
51
+ Args:
52
+ path: Remote file path in the sandbox
53
+ Returns:
54
+ File content
55
+ """
56
+ return self._sandbox.data_api.read_file(path=path)
57
+
58
+ async def write_async(
59
+ self,
60
+ path: str,
61
+ content: str,
62
+ mode: str = "644",
63
+ encoding: str = "utf-8",
64
+ create_dir=True,
65
+ ):
66
+ """Write a file to the sandbox (async).
67
+ Args:
68
+ path: Remote file path in the sandbox
69
+ content: File content
70
+ """
71
+ return await self._sandbox.data_api.write_file_async(
72
+ path=path,
73
+ content=content,
74
+ mode=mode,
75
+ encoding=encoding,
76
+ create_dir=create_dir,
77
+ )
78
+
79
+ def write(
80
+ self,
81
+ path: str,
82
+ content: str,
83
+ mode: str = "644",
84
+ encoding: str = "utf-8",
85
+ create_dir=True,
86
+ ):
87
+ """Write a file to the sandbox (async).
88
+ Args:
89
+ path: Remote file path in the sandbox
90
+ content: File content
91
+ """
92
+ return self._sandbox.data_api.write_file(
93
+ path=path,
94
+ content=content,
95
+ mode=mode,
96
+ encoding=encoding,
97
+ create_dir=create_dir,
98
+ )
99
+
100
+
101
+ class FileSystemOperations:
102
+ """File system operations (list, move, remove, stat, mkdir)."""
103
+
104
+ def __init__(self, sandbox: "AioSandbox"):
105
+ self._sandbox = sandbox
106
+
107
+ async def list_async(
108
+ self, path: Optional[str] = None, depth: Optional[int] = None
109
+ ):
110
+ """List directory contents (async).
111
+
112
+ Args:
113
+ path: Directory path (optional)
114
+ depth: Traversal depth (optional)
115
+
116
+ Returns:
117
+ Directory contents
118
+ """
119
+ return await self._sandbox.data_api.list_directory_async(
120
+ path=path, depth=depth
121
+ )
122
+
123
+ def list(self, path: Optional[str] = None, depth: Optional[int] = None):
124
+ """List directory contents (async).
125
+
126
+ Args:
127
+ path: Directory path (optional)
128
+ depth: Traversal depth (optional)
129
+
130
+ Returns:
131
+ Directory contents
132
+ """
133
+ return self._sandbox.data_api.list_directory(path=path, depth=depth)
134
+
135
+ async def move_async(self, source: str, destination: str):
136
+ """Move a file or directory (async).
137
+
138
+ Args:
139
+ source: Source file or directory path
140
+ destination: Target file or directory path
141
+
142
+ Returns:
143
+ Move operation result
144
+ """
145
+ return await self._sandbox.data_api.move_file_async(
146
+ source=source, destination=destination
147
+ )
148
+
149
+ def move(self, source: str, destination: str):
150
+ """Move a file or directory (async).
151
+
152
+ Args:
153
+ source: Source file or directory path
154
+ destination: Target file or directory path
155
+
156
+ Returns:
157
+ Move operation result
158
+ """
159
+ return self._sandbox.data_api.move_file(
160
+ source=source, destination=destination
161
+ )
162
+
163
+ async def remove_async(self, path: str):
164
+ """Remove a file or directory (async).
165
+
166
+ Args:
167
+ path: File or directory path to remove
168
+
169
+ Returns:
170
+ Remove operation result
171
+ """
172
+ return await self._sandbox.data_api.remove_file_async(path=path)
173
+
174
+ def remove(self, path: str):
175
+ """Remove a file or directory (async).
176
+
177
+ Args:
178
+ path: File or directory path to remove
179
+
180
+ Returns:
181
+ Remove operation result
182
+ """
183
+ return self._sandbox.data_api.remove_file(path=path)
184
+
185
+ async def stat_async(self, path: str):
186
+ """Get file or directory statistics (async).
187
+
188
+ Args:
189
+ path: File or directory path
190
+
191
+ Returns:
192
+ File/directory statistics
193
+ """
194
+ return await self._sandbox.data_api.stat_async(path=path)
195
+
196
+ def stat(self, path: str):
197
+ """Get file or directory statistics (async).
198
+
199
+ Args:
200
+ path: File or directory path
201
+
202
+ Returns:
203
+ File/directory statistics
204
+ """
205
+ return self._sandbox.data_api.stat(path=path)
206
+
207
+ async def mkdir_async(
208
+ self,
209
+ path: str,
210
+ parents: Optional[bool] = True,
211
+ mode: Optional[str] = "0755",
212
+ ):
213
+ """Create a directory (async).
214
+
215
+ Args:
216
+ path: Directory path to create
217
+ parents: Whether to create parent directories (default: True)
218
+ mode: Directory permissions mode (default: "0755")
219
+
220
+ Returns:
221
+ Mkdir operation result
222
+ """
223
+ return await self._sandbox.data_api.mkdir_async(
224
+ path=path, parents=parents, mode=mode
225
+ )
226
+
227
+ def mkdir(
228
+ self,
229
+ path: str,
230
+ parents: Optional[bool] = True,
231
+ mode: Optional[str] = "0755",
232
+ ):
233
+ """Create a directory (async).
234
+
235
+ Args:
236
+ path: Directory path to create
237
+ parents: Whether to create parent directories (default: True)
238
+ mode: Directory permissions mode (default: "0755")
239
+
240
+ Returns:
241
+ Mkdir operation result
242
+ """
243
+ return self._sandbox.data_api.mkdir(
244
+ path=path, parents=parents, mode=mode
245
+ )
246
+
247
+ async def upload_async(
248
+ self,
249
+ local_file_path: str,
250
+ target_file_path: str,
251
+ ):
252
+ """Upload a file to the sandbox (async).
253
+
254
+ Args:
255
+ local_file_path: Local file path to upload
256
+ target_file_path: Target file path in sandbox
257
+
258
+ Returns:
259
+ Upload result
260
+ """
261
+ return await self._sandbox.data_api.upload_file_async(
262
+ local_file_path=local_file_path, target_file_path=target_file_path
263
+ )
264
+
265
+ def upload(
266
+ self,
267
+ local_file_path: str,
268
+ target_file_path: str,
269
+ ):
270
+ """Upload a file to the sandbox (async).
271
+
272
+ Args:
273
+ local_file_path: Local file path to upload
274
+ target_file_path: Target file path in sandbox
275
+
276
+ Returns:
277
+ Upload result
278
+ """
279
+ return self._sandbox.data_api.upload_file(
280
+ local_file_path=local_file_path, target_file_path=target_file_path
281
+ )
282
+
283
+ async def download_async(self, path: str, save_path: str):
284
+ """Download a file from the sandbox (async).
285
+
286
+ Args:
287
+ path: Remote file path in the sandbox
288
+ save_path: Local file path to save the downloaded file
289
+
290
+ Returns:
291
+ Download result with 'saved_path' and 'size'
292
+ """
293
+ return await self._sandbox.data_api.download_file_async(
294
+ path=path, save_path=save_path
295
+ )
296
+
297
+ def download(self, path: str, save_path: str):
298
+ """Download a file from the sandbox (async).
299
+
300
+ Args:
301
+ path: Remote file path in the sandbox
302
+ save_path: Local file path to save the downloaded file
303
+
304
+ Returns:
305
+ Download result with 'saved_path' and 'size'
306
+ """
307
+ return self._sandbox.data_api.download_file(
308
+ path=path, save_path=save_path
309
+ )
310
+
311
+
312
+ class ProcessOperations:
313
+ """Process management operations."""
314
+
315
+ def __init__(self, sandbox: "AioSandbox"):
316
+ self._sandbox = sandbox
317
+
318
+ async def cmd_async(
319
+ self, command: str, cwd: str, timeout: Optional[int] = 30
320
+ ):
321
+ """Execute a command in the sandbox (async).
322
+
323
+ Args:
324
+ command: Command to execute
325
+ cwd: Working directory
326
+ timeout: Execution timeout in seconds (default: 30)
327
+
328
+ Returns:
329
+ Command execution result
330
+ """
331
+ return await self._sandbox.data_api.cmd_async(
332
+ command=command, cwd=cwd, timeout=timeout
333
+ )
334
+
335
+ def cmd(self, command: str, cwd: str, timeout: Optional[int] = 30):
336
+ """Execute a command in the sandbox (async).
337
+
338
+ Args:
339
+ command: Command to execute
340
+ cwd: Working directory
341
+ timeout: Execution timeout in seconds (default: 30)
342
+
343
+ Returns:
344
+ Command execution result
345
+ """
346
+ return self._sandbox.data_api.cmd(
347
+ command=command, cwd=cwd, timeout=timeout
348
+ )
349
+
350
+ async def list_async(self):
351
+ """List all processes (async).
352
+
353
+ Returns:
354
+ List of processes
355
+ """
356
+ return await self._sandbox.data_api.list_processes_async()
357
+
358
+ def list(self):
359
+ """List all processes (async).
360
+
361
+ Returns:
362
+ List of processes
363
+ """
364
+ return self._sandbox.data_api.list_processes()
365
+
366
+ async def get_async(self, pid: str):
367
+ """Get a specific process by PID (async).
368
+
369
+ Args:
370
+ pid: Process ID
371
+
372
+ Returns:
373
+ Process information
374
+ """
375
+ return await self._sandbox.data_api.get_process_async(pid=pid)
376
+
377
+ def get(self, pid: str):
378
+ """Get a specific process by PID (async).
379
+
380
+ Args:
381
+ pid: Process ID
382
+
383
+ Returns:
384
+ Process information
385
+ """
386
+ return self._sandbox.data_api.get_process(pid=pid)
387
+
388
+ async def kill_async(self, pid: str):
389
+ """Kill a specific process by PID (async).
390
+
391
+ Args:
392
+ pid: Process ID
393
+
394
+ Returns:
395
+ Kill operation result
396
+ """
397
+ return await self._sandbox.data_api.kill_process_async(pid=pid)
398
+
399
+ def kill(self, pid: str):
400
+ """Kill a specific process by PID (async).
401
+
402
+ Args:
403
+ pid: Process ID
404
+
405
+ Returns:
406
+ Kill operation result
407
+ """
408
+ return self._sandbox.data_api.kill_process(pid=pid)
409
+
410
+
411
+ class ContextOperations:
412
+ """Context management operations."""
413
+
414
+ def __init__(self, sandbox: "AioSandbox"):
415
+ self._sandbox = sandbox
416
+ self._context_id: Optional[str] = None
417
+ self._language: Optional[str] = None
418
+ self._cwd: Optional[str] = None
419
+
420
+ @property
421
+ def context_id(self) -> Optional[str]:
422
+ """Get the current context ID."""
423
+ return self._context_id
424
+
425
+ async def list_async(self):
426
+ """List all contexts (async)."""
427
+ return await self._sandbox.data_api.list_contexts_async()
428
+
429
+ def list(self):
430
+ """List all contexts (async)."""
431
+ return self._sandbox.data_api.list_contexts()
432
+
433
+ async def create_async(
434
+ self,
435
+ language: Optional[CodeLanguage] = CodeLanguage.PYTHON,
436
+ cwd: str = "/home/user",
437
+ ) -> "ContextOperations":
438
+ """Create a new context and save its ID (async).
439
+
440
+ Args:
441
+ language: Programming language (default: "python")
442
+ cwd: Working directory (default: "/home/user")
443
+
444
+ Returns:
445
+ ContextOperations: Returns self for chaining and context manager support
446
+ """
447
+ result = await self._sandbox.data_api.create_context_async(
448
+ language=language, cwd=cwd
449
+ )
450
+ if all(result.get(key) for key in ("id", "cwd", "language")):
451
+ self._context_id = result["id"]
452
+ self._language = result["language"]
453
+ self._cwd = result["cwd"]
454
+ return self
455
+ raise ServerError(500, "Failed to create context")
456
+
457
+ def create(
458
+ self,
459
+ language: Optional[CodeLanguage] = CodeLanguage.PYTHON,
460
+ cwd: str = "/home/user",
461
+ ) -> "ContextOperations":
462
+ """Create a new context and save its ID (async).
463
+
464
+ Args:
465
+ language: Programming language (default: "python")
466
+ cwd: Working directory (default: "/home/user")
467
+
468
+ Returns:
469
+ ContextOperations: Returns self for chaining and context manager support
470
+ """
471
+ result = self._sandbox.data_api.create_context(
472
+ language=language, cwd=cwd
473
+ )
474
+ if all(result.get(key) for key in ("id", "cwd", "language")):
475
+ self._context_id = result["id"]
476
+ self._language = result["language"]
477
+ self._cwd = result["cwd"]
478
+ return self
479
+ raise ServerError(500, "Failed to create context")
480
+
481
+ async def get_async(
482
+ self, context_id: Optional[str] = None
483
+ ) -> "ContextOperations":
484
+ """Get a specific context by ID (async).
485
+ Args:
486
+ context_id: Context ID
487
+ Returns:
488
+ ContextOperations: Returns self for chaining and context manager support
489
+ """
490
+ if context_id is None:
491
+ context_id = self._context_id
492
+ if context_id is None:
493
+ logger.error(f"context id is not set")
494
+ raise ValueError("context id is not set,")
495
+ result = await self._sandbox.data_api.get_context_async(
496
+ context_id=context_id
497
+ )
498
+ if all(result.get(key) for key in ("id", "cwd", "language")):
499
+ self._context_id = result["id"]
500
+ self._language = result["language"]
501
+ self._cwd = result["cwd"]
502
+ return self
503
+ raise ServerError(500, "Failed to create context")
504
+
505
+ def get(self, context_id: Optional[str] = None) -> "ContextOperations":
506
+ """Get a specific context by ID (async).
507
+ Args:
508
+ context_id: Context ID
509
+ Returns:
510
+ ContextOperations: Returns self for chaining and context manager support
511
+ """
512
+ if context_id is None:
513
+ context_id = self._context_id
514
+ if context_id is None:
515
+ logger.error(f"context id is not set")
516
+ raise ValueError("context id is not set,")
517
+ result = self._sandbox.data_api.get_context(context_id=context_id)
518
+ if all(result.get(key) for key in ("id", "cwd", "language")):
519
+ self._context_id = result["id"]
520
+ self._language = result["language"]
521
+ self._cwd = result["cwd"]
522
+ return self
523
+ raise ServerError(500, "Failed to create context")
524
+
525
+ async def execute_async(
526
+ self,
527
+ code: str,
528
+ language: Optional[CodeLanguage] = None,
529
+ context_id: Optional[str] = None,
530
+ timeout: Optional[int] = 30,
531
+ ):
532
+ """Execute code in a context (async).
533
+
534
+ Args:
535
+ code: Code to execute
536
+ language: Programming language (optional)
537
+ context_id: Context ID (optional, uses saved context_id if not provided)
538
+ timeout: Execution timeout in seconds (default: 30)
539
+
540
+ Returns:
541
+ Execution result
542
+
543
+ Raises:
544
+ ValueError: If no context_id is provided and none is saved
545
+ """
546
+ if context_id is None:
547
+ context_id = self._context_id
548
+ if context_id is None and language is None:
549
+ logger.debug("context id is not set, use default language: python")
550
+ language = CodeLanguage.PYTHON
551
+ return await self._sandbox.data_api.execute_code_async(
552
+ context_id=context_id, language=language, code=code, timeout=timeout
553
+ )
554
+
555
+ def execute(
556
+ self,
557
+ code: str,
558
+ language: Optional[CodeLanguage] = None,
559
+ context_id: Optional[str] = None,
560
+ timeout: Optional[int] = 30,
561
+ ):
562
+ """Execute code in a context (async).
563
+
564
+ Args:
565
+ code: Code to execute
566
+ language: Programming language (optional)
567
+ context_id: Context ID (optional, uses saved context_id if not provided)
568
+ timeout: Execution timeout in seconds (default: 30)
569
+
570
+ Returns:
571
+ Execution result
572
+
573
+ Raises:
574
+ ValueError: If no context_id is provided and none is saved
575
+ """
576
+ if context_id is None:
577
+ context_id = self._context_id
578
+ if context_id is None and language is None:
579
+ logger.debug("context id is not set, use default language: python")
580
+ language = CodeLanguage.PYTHON
581
+ return self._sandbox.data_api.execute_code(
582
+ context_id=context_id, language=language, code=code, timeout=timeout
583
+ )
584
+
585
+ async def delete_async(self, context_id: Optional[str] = None):
586
+ """Delete a context (async).
587
+
588
+ Args:
589
+ context_id: Context ID (optional, uses saved context_id if not provided)
590
+
591
+ Returns:
592
+ Delete result
593
+
594
+ Raises:
595
+ ValueError: If no context_id is provided and none is saved
596
+ """
597
+ if context_id is None:
598
+ context_id = self._context_id
599
+ if context_id is None:
600
+ raise ValueError(
601
+ "context_id is required. Either pass it as parameter or create"
602
+ " a context first."
603
+ )
604
+ result = await self._sandbox.data_api.delete_context_async(
605
+ context_id=context_id
606
+ )
607
+ # Clear the saved context_id after deletion
608
+ self._context_id = None
609
+ return result
610
+
611
+ def delete(self, context_id: Optional[str] = None):
612
+ """Delete a context (async).
613
+
614
+ Args:
615
+ context_id: Context ID (optional, uses saved context_id if not provided)
616
+
617
+ Returns:
618
+ Delete result
619
+
620
+ Raises:
621
+ ValueError: If no context_id is provided and none is saved
622
+ """
623
+ if context_id is None:
624
+ context_id = self._context_id
625
+ if context_id is None:
626
+ raise ValueError(
627
+ "context_id is required. Either pass it as parameter or create"
628
+ " a context first."
629
+ )
630
+ result = self._sandbox.data_api.delete_context(context_id=context_id)
631
+ # Clear the saved context_id after deletion
632
+ self._context_id = None
633
+ return result
634
+
635
+ async def __aenter__(self):
636
+ """Asynchronous context manager entry."""
637
+ if self._context_id is None:
638
+ raise ValueError(
639
+ "No context has been created. Call create() first or use: "
640
+ "async with await sandbox.context.create_async(...) as ctx:"
641
+ )
642
+ return self
643
+
644
+ def __enter__(self):
645
+ """Synchronous context manager entry."""
646
+ if self._context_id is None:
647
+ raise ValueError(
648
+ "No context has been created. Call create() first or use: "
649
+ "with sandbox.context.create(...) as ctx:"
650
+ )
651
+ return self
652
+
653
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
654
+ """Asynchronous context manager exit - deletes the context."""
655
+ if self._context_id is not None:
656
+ try:
657
+ await self._sandbox.data_api.delete_context_async(
658
+ self._context_id
659
+ )
660
+ except Exception as e:
661
+ logger.error(
662
+ f"Warning: Failed to delete context {self._context_id}: {e}"
663
+ )
664
+ return False
665
+
666
+ def __exit__(self, exc_type, exc_val, exc_tb):
667
+ """Synchronous context manager exit - deletes the context."""
668
+ if self._context_id is not None:
669
+ try:
670
+ self._sandbox.data_api.delete_context(self._context_id)
671
+ except Exception as e:
672
+ logger.error(
673
+ f"Warning: Failed to delete context {self._context_id}: {e}"
674
+ )
675
+ return False
676
+
677
+
678
+ class AioSandbox(Sandbox):
679
+ """All-in-One Sandbox combining Browser and Code Interpreter capabilities.
680
+
681
+ This class combines the functionality of BrowserSandbox and CodeInterpreterSandbox,
682
+ providing a unified interface for all-in-one sandbox operations.
683
+ """
684
+
685
+ _template_type = TemplateType.AIO
686
+
687
+ _data_api: Optional["AioDataAPI"] = None
688
+ _file: Optional[FileOperations] = None
689
+ _file_system: Optional[FileSystemOperations] = None
690
+ _context: Optional[ContextOperations] = None
691
+ _process: Optional[ProcessOperations] = None
692
+
693
+ async def __aenter__(self):
694
+ """Asynchronous context manager entry."""
695
+ # Poll health check asynchronously
696
+ max_retries = 60 # Maximum 60 seconds
697
+ retry_count = 0
698
+
699
+ logger.debug("Waiting for All-in-One sandbox to be ready...")
700
+
701
+ while retry_count < max_retries:
702
+ retry_count += 1
703
+
704
+ try:
705
+ health = await self.check_health_async()
706
+
707
+ if health["status"] == "ok":
708
+ logger.debug(
709
+ "✓ All-in-One sandbox is ready! (took"
710
+ f" {retry_count} seconds)"
711
+ )
712
+ return self
713
+
714
+ logger.debug(
715
+ "[%d/%d] Health status: %d %s",
716
+ retry_count,
717
+ max_retries,
718
+ health.get("code", 0),
719
+ health.get("message", "not ready"),
720
+ )
721
+
722
+ except Exception as e:
723
+ logger.error(
724
+ f"[{retry_count}/{max_retries}] Health check failed: {e}"
725
+ )
726
+
727
+ if retry_count < max_retries:
728
+ await asyncio.sleep(1)
729
+
730
+ raise RuntimeError(
731
+ f"Health check timeout after {max_retries} seconds. "
732
+ "All-in-One sandbox did not become ready in time."
733
+ )
734
+
735
+ def __enter__(self):
736
+ """Synchronous context manager entry."""
737
+ # Poll health check asynchronously
738
+ max_retries = 60 # Maximum 60 seconds
739
+ retry_count = 0
740
+
741
+ logger.debug("Waiting for All-in-One sandbox to be ready...")
742
+
743
+ while retry_count < max_retries:
744
+ retry_count += 1
745
+
746
+ try:
747
+ health = self.check_health()
748
+
749
+ if health["status"] == "ok":
750
+ logger.debug(
751
+ "✓ All-in-One sandbox is ready! (took"
752
+ f" {retry_count} seconds)"
753
+ )
754
+ return self
755
+
756
+ logger.debug(
757
+ "[%d/%d] Health status: %d %s",
758
+ retry_count,
759
+ max_retries,
760
+ health.get("code", 0),
761
+ health.get("message", "not ready"),
762
+ )
763
+
764
+ except Exception as e:
765
+ logger.error(
766
+ f"[{retry_count}/{max_retries}] Health check failed,"
767
+ f" retrying: {e}"
768
+ )
769
+
770
+ if retry_count < max_retries:
771
+ time.sleep(1)
772
+
773
+ raise RuntimeError(
774
+ f"Health check timeout after {max_retries} seconds. "
775
+ "All-in-One sandbox did not become ready in time."
776
+ )
777
+
778
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
779
+ """Asynchronous context manager exit."""
780
+ if self.sandbox_id is None:
781
+ raise ValueError("Sandbox ID is not set")
782
+ logger.debug(f"Deleting All-in-One sandbox {self.sandbox_id}...")
783
+ await self.delete_async()
784
+
785
+ def __exit__(self, exc_type, exc_val, exc_tb):
786
+ """Synchronous context manager exit."""
787
+ if self.sandbox_id is None:
788
+ raise ValueError("Sandbox ID is not set")
789
+ logger.debug(f"Deleting All-in-One sandbox {self.sandbox_id}...")
790
+ self.delete()
791
+
792
+ @property
793
+ def data_api(self) -> "AioDataAPI":
794
+ """Get data client."""
795
+ if self._data_api is None:
796
+ if self.sandbox_id is None:
797
+ raise ValueError("Sandbox ID is not set")
798
+
799
+ self._data_api = AioDataAPI(
800
+ sandbox_id=self.sandbox_id, config=self._config
801
+ )
802
+
803
+ return self._data_api
804
+
805
+ async def check_health_async(self):
806
+ """Check sandbox health status (async)."""
807
+ return await self.data_api.check_health_async()
808
+
809
+ def check_health(self):
810
+ """Check sandbox health status (sync)."""
811
+ return self.data_api.check_health()
812
+
813
+ # ========================================
814
+ # Browser API Methods
815
+ # ========================================
816
+
817
+ def get_cdp_url(self, record: Optional[bool] = False):
818
+ """Get CDP WebSocket URL for browser automation."""
819
+ return self.data_api.get_cdp_url(record=record)
820
+
821
+ def get_vnc_url(self, record: Optional[bool] = False):
822
+ """Get VNC WebSocket URL for live view."""
823
+ return self.data_api.get_vnc_url(record=record)
824
+
825
+ def sync_playwright(self, record: Optional[bool] = False):
826
+ """Get synchronous Playwright browser instance."""
827
+ return self.data_api.sync_playwright(record=record)
828
+
829
+ def async_playwright(self, record: Optional[bool] = False):
830
+ """Get asynchronous Playwright browser instance."""
831
+ return self.data_api.async_playwright(record=record)
832
+
833
+ async def list_recordings_async(self):
834
+ """List all recordings (async)."""
835
+ return await self.data_api.list_recordings_async()
836
+
837
+ def list_recordings(self):
838
+ """List all recordings (async)."""
839
+ return self.data_api.list_recordings()
840
+
841
+ async def download_recording_async(self, filename: str, save_path: str):
842
+ """
843
+ Asynchronously download a recording video file and save it to local path.
844
+
845
+ Args:
846
+ filename: The name of the recording file to download
847
+ save_path: Local file path to save the downloaded video file (.mkv)
848
+
849
+ Returns:
850
+ Dictionary with 'saved_path' and 'size' keys
851
+ """
852
+ return await self.data_api.download_recording_async(filename, save_path)
853
+
854
+ def download_recording(self, filename: str, save_path: str):
855
+ """
856
+ Synchronously download a recording video file and save it to local path.
857
+
858
+ Args:
859
+ filename: The name of the recording file to download
860
+ save_path: Local file path to save the downloaded video file (.mkv)
861
+
862
+ Returns:
863
+ Dictionary with 'saved_path' and 'size' keys
864
+ """
865
+ return self.data_api.download_recording(filename, save_path)
866
+
867
+ async def delete_recording_async(self, filename: str):
868
+ """Delete a recording file (async)."""
869
+ return await self.data_api.delete_recording_async(filename)
870
+
871
+ def delete_recording(self, filename: str):
872
+ """Delete a recording file (sync)."""
873
+ return self.data_api.delete_recording(filename)
874
+
875
+ # ========================================
876
+ # Code Interpreter API Properties
877
+ # ========================================
878
+
879
+ @property
880
+ def file(self) -> FileOperations:
881
+ """Access file upload/download operations."""
882
+ if self._file is None:
883
+ self._file = FileOperations(self)
884
+ return self._file
885
+
886
+ @property
887
+ def file_system(self) -> FileSystemOperations:
888
+ """Access file system operations."""
889
+ if self._file_system is None:
890
+ self._file_system = FileSystemOperations(self)
891
+ return self._file_system
892
+
893
+ @property
894
+ def context(self) -> ContextOperations:
895
+ """Access context management operations."""
896
+ if self._context is None:
897
+ self._context = ContextOperations(self)
898
+ return self._context
899
+
900
+ @property
901
+ def process(self) -> ProcessOperations:
902
+ """Access process management operations."""
903
+ if self._process is None:
904
+ self._process = ProcessOperations(self)
905
+ return self._process