scalebox-sdk 0.1.25__py3-none-any.whl → 1.0.2__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 (78) hide show
  1. scalebox/__init__.py +2 -2
  2. scalebox/api/__init__.py +3 -1
  3. scalebox/api/client/api/sandboxes/get_sandboxes.py +1 -1
  4. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  5. scalebox/api/client/models/connect_sandbox.py +59 -0
  6. scalebox/api/client/models/error.py +2 -2
  7. scalebox/api/client/models/listed_sandbox.py +24 -3
  8. scalebox/api/client/models/new_sandbox.py +10 -0
  9. scalebox/api/client/models/sandbox.py +13 -0
  10. scalebox/api/client/models/sandbox_detail.py +24 -0
  11. scalebox/cli.py +125 -125
  12. scalebox/client/aclient.py +57 -57
  13. scalebox/client/client.py +102 -102
  14. scalebox/code_interpreter/__init__.py +12 -12
  15. scalebox/code_interpreter/charts.py +230 -230
  16. scalebox/code_interpreter/code_interpreter_async.py +3 -1
  17. scalebox/code_interpreter/code_interpreter_sync.py +3 -1
  18. scalebox/code_interpreter/constants.py +3 -3
  19. scalebox/code_interpreter/exceptions.py +13 -13
  20. scalebox/code_interpreter/models.py +485 -485
  21. scalebox/connection_config.py +36 -1
  22. scalebox/csx_connect/__init__.py +1 -1
  23. scalebox/csx_connect/client.py +485 -485
  24. scalebox/csx_desktop/main.py +651 -651
  25. scalebox/exceptions.py +83 -83
  26. scalebox/generated/api.py +61 -61
  27. scalebox/generated/api_pb2.py +203 -203
  28. scalebox/generated/api_pb2.pyi +956 -956
  29. scalebox/generated/api_pb2_connect.py +1407 -1407
  30. scalebox/generated/rpc.py +50 -50
  31. scalebox/sandbox/main.py +146 -139
  32. scalebox/sandbox/sandbox_api.py +105 -91
  33. scalebox/sandbox/signature.py +40 -40
  34. scalebox/sandbox/utils.py +34 -34
  35. scalebox/sandbox_async/main.py +226 -44
  36. scalebox/sandbox_async/sandbox_api.py +124 -3
  37. scalebox/sandbox_sync/main.py +205 -130
  38. scalebox/sandbox_sync/sandbox_api.py +119 -3
  39. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
  40. scalebox/test/README.md +329 -329
  41. scalebox/test/bedrock_openai_adapter.py +73 -0
  42. scalebox/test/code_interpreter_test.py +34 -34
  43. scalebox/test/code_interpreter_test_sync.py +34 -34
  44. scalebox/test/run_stress_code_interpreter_sync.py +178 -0
  45. scalebox/test/simple_upload_example.py +131 -0
  46. scalebox/test/stabitiy_test.py +323 -0
  47. scalebox/test/test_browser_use.py +27 -0
  48. scalebox/test/test_browser_use_scalebox.py +62 -0
  49. scalebox/test/test_code_interpreter_execcode.py +289 -211
  50. scalebox/test/test_code_interpreter_sync_comprehensive.py +116 -69
  51. scalebox/test/test_connect_pause_async.py +300 -0
  52. scalebox/test/test_connect_pause_sync.py +300 -0
  53. scalebox/test/test_csx_desktop_examples.py +3 -3
  54. scalebox/test/test_desktop_sandbox_sf.py +112 -0
  55. scalebox/test/test_download_url.py +41 -0
  56. scalebox/test/test_existing_sandbox.py +1037 -0
  57. scalebox/test/test_sandbox_async_comprehensive.py +5 -3
  58. scalebox/test/test_sandbox_object_storage_example.py +151 -0
  59. scalebox/test/test_sandbox_object_storage_example_async.py +159 -0
  60. scalebox/test/test_sandbox_sync_comprehensive.py +1 -1
  61. scalebox/test/test_sf.py +141 -0
  62. scalebox/test/test_watch_dir_async.py +58 -0
  63. scalebox/test/testacreate.py +1 -1
  64. scalebox/test/testagetinfo.py +1 -3
  65. scalebox/test/testcomputeuse.py +243 -243
  66. scalebox/test/testsandbox_api.py +5 -5
  67. scalebox/test/testsandbox_async.py +17 -47
  68. scalebox/test/testsandbox_sync.py +19 -15
  69. scalebox/test/upload_100mb_example.py +377 -0
  70. scalebox/utils/httpcoreclient.py +297 -297
  71. scalebox/utils/httpxclient.py +403 -403
  72. scalebox/version.py +2 -2
  73. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/METADATA +1 -1
  74. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/RECORD +78 -60
  75. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/WHEEL +1 -1
  76. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/entry_points.txt +0 -0
  77. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/licenses/LICENSE +0 -0
  78. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.2.dist-info}/top_level.txt +0 -0
@@ -78,7 +78,7 @@ class AsyncSandboxValidator:
78
78
  template="base",
79
79
  debug=False,
80
80
  timeout=300,
81
- api_key="sk-Wk4IgtUYOqnttxGaxZmELEV4p2FXh15Evt0FIcSa",
81
+ api_key="sk-Wk4Ig",
82
82
  metadata={"test": "async_validation"},
83
83
  envs={"TEST_ENV": "async_test"},
84
84
  )
@@ -274,7 +274,9 @@ class AsyncSandboxValidator:
274
274
  await self.sandbox.files.write("/tmp/old_name.txt", "content to rename")
275
275
 
276
276
  # 重命名
277
- result = await self.sandbox.files.rename("/tmp/old_name.txt", "/tmp/new_name.txt")
277
+ result = await self.sandbox.files.rename(
278
+ "/tmp/old_name.txt", "/tmp/new_name.txt"
279
+ )
278
280
  print(result)
279
281
  assert isinstance(result, EntryInfo)
280
282
  assert result.name == "new_name.txt"
@@ -290,7 +292,7 @@ class AsyncSandboxValidator:
290
292
  # 删除文件
291
293
  await self.sandbox.files.remove("/tmp/new_name.txt")
292
294
  assert await self.sandbox.files.exists("/tmp/new_name.txt") == False
293
-
295
+
294
296
  # 删除目录
295
297
  await self.sandbox.files.remove("/tmp/test_dir")
296
298
  assert await self.sandbox.files.exists("/tmp/test_dir") == False
@@ -0,0 +1,151 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ 示例:如何在创建同步 Sandbox 时携带 object_storage 参数。
4
+
5
+ 运行前准备:
6
+ 1. 设置环境变量 SCALEBOX_OBJECT_STORAGE_CONFIG 为 JSON 字符串或 JSON 文件路径,
7
+ 该内容会被原样传递给后端。例如:
8
+ {
9
+ "provider": "s3",
10
+ "bucket": "my-sbx-bucket",
11
+ "region": "us-east-1",
12
+ "access_key_id": "AKIA...",
13
+ "secret_access_key": "******",
14
+ "endpoint": "https://s3.amazonaws.com"
15
+ }
16
+ 2. (可选)设置 SCALEBOX_OBJECT_STORAGE_TEMPLATE / SCALEBOX_OBJECT_STORAGE_TIMEOUT
17
+ 调整模板和沙箱超时时间。
18
+
19
+ 注意:目前只有同步版本支持 object_storage,本示例不会自动运行,
20
+ 需要在提供有效配置后手动执行:
21
+
22
+ PYTHONPATH=/home/ubuntu/git_home/scalebox:$PYTHONPATH \\
23
+ SCALEBOX_OBJECT_STORAGE_CONFIG=/path/to/config.json \\
24
+ python test/test_sandbox_object_storage_example.py
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+ import json
30
+ import logging
31
+ import os
32
+ import sys
33
+ from pathlib import Path
34
+ from typing import Any, Dict, Optional
35
+
36
+ from scalebox.exceptions import SandboxException
37
+ from scalebox.sandbox_sync.main import Sandbox
38
+ from scalebox.sandbox.sandbox_api import SandboxQuery
39
+
40
+ logger = logging.getLogger(__name__)
41
+ logging.basicConfig(
42
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
43
+ )
44
+
45
+ # CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
46
+ # TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
47
+ # TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
48
+ #
49
+ #
50
+ # def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
51
+ # raw_value = os.environ.get(CONFIG_ENV)
52
+ # if not raw_value:
53
+ # logger.warning(
54
+ # "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
55
+ # CONFIG_ENV,
56
+ # )
57
+ # return None
58
+ #
59
+ # config_text: Optional[str] = None
60
+ # potential_path = Path(raw_value)
61
+ # if potential_path.is_file():
62
+ # config_text = potential_path.read_text(encoding="utf-8")
63
+ # else:
64
+ # config_text = raw_value
65
+ #
66
+ # try:
67
+ # payload = json.loads(config_text)
68
+ # except json.JSONDecodeError as exc:
69
+ # logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
70
+ # raise SystemExit(1) from exc
71
+ #
72
+ # if not isinstance(payload, dict):
73
+ # logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
74
+ # raise SystemExit(1)
75
+ #
76
+ # return payload
77
+
78
+
79
+ # def _mask_value(value: str) -> str:
80
+ # if len(value) <= 4:
81
+ # return "*" * len(value)
82
+ # return f"{value[:2]}***{value[-2:]}"
83
+
84
+
85
+ # def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
86
+ # masked = {}
87
+ # for key, value in config.items():
88
+ # if isinstance(value, str):
89
+ # masked[key] = _mask_value(value)
90
+ # else:
91
+ # masked[key] = value
92
+ # return masked
93
+
94
+
95
+ def create_sandbox_with_object_storage():
96
+ # payload = _load_object_storage_payload()
97
+ # if payload is None:
98
+ # return
99
+ #
100
+ # template = os.environ.get(TEMPLATE_ENV, "base")
101
+ # timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
102
+
103
+ sandbox: Optional[Sandbox] = None
104
+ try:
105
+ sandbox = Sandbox.create(
106
+ template="base",
107
+ timeout=3600,
108
+ metadata={"example": "object_storage"},
109
+ object_storage={
110
+ "uri": "s3://bgd-test/test/",
111
+ "mount_point": "/mnt/oss",
112
+ # "access_key": "",
113
+ # "secret_key": "",
114
+ "region": "us-east-2",
115
+ "endpoint": "https://s3.us-east-2.amazonaws.com",
116
+ },
117
+ )
118
+ print(sandbox.sandbox_id)
119
+ print(sandbox.sandbox_domain)
120
+ if sandbox.object_storage:
121
+ print(sandbox.object_storage)
122
+
123
+ info = sandbox.get_info()
124
+ print(info)
125
+ print(f"get_info.object_storage: {info.object_storage}")
126
+
127
+ listed = Sandbox.list(
128
+ query=SandboxQuery(metadata={"example": "object_storage"})
129
+ )
130
+ print(f"List 根据 metadata 命中的沙箱数量: {len(listed)}")
131
+ for listed_box in listed:
132
+ detailed = Sandbox.get_info(sandbox_id=listed_box.sandbox_id)
133
+ print(detailed)
134
+ print(
135
+ f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
136
+ )
137
+
138
+ # 在沙箱中运行简单命令,确认可正常访问
139
+ result = sandbox.commands.run("echo 'object storage sandbox is ready'")
140
+ print(f"命令输出: {result.stdout.strip()}")
141
+ except SandboxException as exc:
142
+ logger.error("创建或使用沙箱失败:%s", exc)
143
+ raise
144
+ finally:
145
+ if sandbox is not None:
146
+ # sandbox.kill()
147
+ logger.info("沙箱已销毁")
148
+
149
+
150
+ if __name__ == "__main__":
151
+ create_sandbox_with_object_storage()
@@ -0,0 +1,159 @@
1
+ #!/usr/bin/env python3
2
+ # pyright: reportMissingImports=false
3
+ """
4
+ 示例:如何在创建异步 Sandbox 时携带 object_storage 参数。
5
+
6
+ 运行前准备:
7
+ 1. 设置环境变量 SCALEBOX_OBJECT_STORAGE_CONFIG 为 JSON 字符串或 JSON 文件路径,
8
+ 该内容会被原样传递给后端。例如:
9
+ {
10
+ "provider": "s3",
11
+ "bucket": "my-sbx-bucket",
12
+ "region": "us-east-1",
13
+ "access_key_id": "AKIA...",
14
+ "secret_access_key": "******",
15
+ "endpoint": "https://s3.amazonaws.com"
16
+ }
17
+ 2. (可选)设置 SCALEBOX_OBJECT_STORAGE_TEMPLATE / SCALEBOX_OBJECT_STORAGE_TIMEOUT
18
+ 调整模板和沙箱超时时间。
19
+
20
+ 注意:object_storage 功能仍主要在同步版本可用,异步示例取决于后端实际支持状况。
21
+ 需要在提供有效配置后手动执行:
22
+
23
+ PYTHONPATH=/home/ubuntu/git_home/scalebox:$PYTHONPATH \\
24
+ SCALEBOX_OBJECT_STORAGE_CONFIG=/path/to/config.json \\
25
+ python test/test_sandbox_object_storage_example_async.py
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import asyncio
31
+ import json
32
+ import logging
33
+ import os
34
+ import sys
35
+ from pathlib import Path
36
+ from typing import Any, Dict, Optional
37
+
38
+ WORKSPACE_ROOT = Path(__file__).resolve().parents[1]
39
+ if str(WORKSPACE_ROOT) not in sys.path:
40
+ sys.path.insert(0, str(WORKSPACE_ROOT))
41
+
42
+ from scalebox.exceptions import SandboxException
43
+ from scalebox.sandbox_async.main import AsyncSandbox
44
+ from scalebox.sandbox.sandbox_api import SandboxQuery
45
+
46
+ logger = logging.getLogger(__name__)
47
+ logging.basicConfig(
48
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
49
+ )
50
+
51
+ # CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
52
+ # TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
53
+ # TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
54
+ #
55
+ #
56
+ # def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
57
+ # raw_value = os.environ.get(CONFIG_ENV)
58
+ # if not raw_value:
59
+ # logger.warning(
60
+ # "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
61
+ # CONFIG_ENV,
62
+ # )
63
+ # return None
64
+ #
65
+ # config_text: Optional[str] = None
66
+ # potential_path = Path(raw_value)
67
+ # if potential_path.is_file():
68
+ # config_text = potential_path.read_text(encoding="utf-8")
69
+ # else:
70
+ # config_text = raw_value
71
+ #
72
+ # try:
73
+ # payload = json.loads(config_text)
74
+ # except json.JSONDecodeError as exc:
75
+ # logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
76
+ # raise SystemExit(1) from exc
77
+ #
78
+ # if not isinstance(payload, dict):
79
+ # logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
80
+ # raise SystemExit(1)
81
+ #
82
+ # return payload
83
+ #
84
+ #
85
+ # def _mask_value(value: str) -> str:
86
+ # if len(value) <= 4:
87
+ # return "*" * len(value)
88
+ # return f"{value[:2]}***{value[-2:]}"
89
+ #
90
+ #
91
+ # def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
92
+ # masked = {}
93
+ # for key, value in config.items():
94
+ # if isinstance(value, str):
95
+ # masked[key] = _mask_value(value)
96
+ # else:
97
+ # masked[key] = value
98
+ # return masked
99
+
100
+
101
+ async def create_sandbox_with_object_storage_async():
102
+ # payload = _load_object_storage_payload()
103
+ # if payload is None:
104
+ # return
105
+ #
106
+ # template = os.environ.get(TEMPLATE_ENV, "base")
107
+ # timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
108
+
109
+ sandbox: Optional[AsyncSandbox] = None
110
+ try:
111
+ sandbox = await AsyncSandbox.create(
112
+ template="base",
113
+ timeout=3600,
114
+ metadata={"example": "object_storage_async"},
115
+ object_storage={
116
+ "uri": "s3://bgd-test/test/",
117
+ "mount_point": "/mnt/oss",
118
+ "access_key": "",
119
+ "secret_key": "",
120
+ "region": "us-east-2",
121
+ "endpoint": "https://s3.us-east-2.amazonaws.com",
122
+ },
123
+ )
124
+ print(sandbox.sandbox_id)
125
+ print(sandbox.sandbox_domain)
126
+ if sandbox.object_storage:
127
+ print(sandbox.object_storage)
128
+
129
+ info = await sandbox.get_info()
130
+ print(info)
131
+ print(f"get_info.object_storage: {info.object_storage}")
132
+
133
+ listed = await AsyncSandbox.list(
134
+ query=SandboxQuery(metadata={"example": "object_storage_async"})
135
+ )
136
+ print(f"Async list 根据 metadata 命中的沙箱数量: {len(listed)}")
137
+ for listed_box in listed:
138
+ detailed = await AsyncSandbox.get_info(sandbox_id=listed_box.sandbox_id)
139
+ print(detailed)
140
+ print(
141
+ f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
142
+ )
143
+
144
+ # 在沙箱中运行简单命令,确认可正常访问
145
+ result = await sandbox.commands.run(
146
+ "echo 'async object storage sandbox is ready'"
147
+ )
148
+ print(f"命令输出: {result.stdout.strip()}")
149
+ except SandboxException as exc:
150
+ logger.error("创建或使用异步沙箱失败:%s", exc)
151
+ raise
152
+ finally:
153
+ if sandbox is not None:
154
+ # await sandbox.kill()
155
+ logger.info("异步沙箱已销毁")
156
+
157
+
158
+ if __name__ == "__main__":
159
+ asyncio.run(create_sandbox_with_object_storage_async())
@@ -292,7 +292,7 @@ class SandboxValidator:
292
292
  # 删除文件
293
293
  self.sandbox.files.remove("/tmp/new_name.txt")
294
294
  assert self.sandbox.files.exists("/tmp/new_name.txt") == False
295
-
295
+
296
296
  # 删除目录
297
297
  self.sandbox.files.remove("/tmp/test_dir")
298
298
  assert self.sandbox.files.exists("/tmp/test_dir") == False
@@ -0,0 +1,141 @@
1
+ from browser_use import Agent, BrowserProfile
2
+ from playwright.async_api import async_playwright
3
+ from dotenv import load_dotenv
4
+ import os, asyncio
5
+ from browser_use.llm import ChatOpenAI
6
+ import subprocess, pathlib
7
+
8
+ load_dotenv()
9
+ os.environ["PLAYWRIGHT_CHROMIUM_EXTRA_ARGS"] = (
10
+ "--no-sandbox --disable-dev-shm-usage --disable-gpu --disable-software-rasterizer"
11
+ )
12
+
13
+ # 1. 正常实例化 ChatOpenAI
14
+ _chat = ChatOpenAI(
15
+ model="Qwen/Qwen2.5-72B-Instruct",
16
+ api_key="sk-nbxsvrydquzfkfrrnnuutnfchpghzeuxilgawvsjqzjhumkh",
17
+ base_url="https://api.siliconflow.cn/v1",
18
+ temperature=0.1,
19
+ )
20
+
21
+
22
+ llm = ChatOpenAI(
23
+ model="deepseek-ai/DeepSeek-R1",
24
+ api_key="sk-nbxsvrydquzfkfrrnnuutnfchpghzeuxilgawvsjqzjhumkh",
25
+ base_url="https://api.siliconflow.cn/v1",
26
+ temperature=0.7,
27
+ )
28
+
29
+
30
+ # 2. 包一层模型,补 .provider + 转发所有必要方法
31
+ class SiliconFlowModel:
32
+ provider = "siliconflow"
33
+
34
+ def __init__(self, chat: ChatOpenAI):
35
+ self.chat = chat
36
+ # 把 browser-use 可能用到的字段全部代理
37
+ self.model_name = chat.model_name # ← 新增
38
+ self.model = chat.model_name # ← 新增(防它再换字段)
39
+ self.ainvoke = chat.ainvoke
40
+ self.invoke = chat.invoke
41
+ self.bind = chat.bind
42
+
43
+ # === 同步 ===
44
+ def invoke(self, *args, **kwargs):
45
+ return self.chat.invoke(*args, **kwargs)
46
+
47
+ # === 异步 ===
48
+ async def ainvoke(self, *args, **kwargs):
49
+ return await self.chat.ainvoke(*args, **kwargs)
50
+
51
+ # 如有其他缺失方法,继续代理即可
52
+ def bind(self, *args, **kwargs):
53
+ return self.chat.bind(*args, **kwargs)
54
+
55
+
56
+ # llm = SiliconFlowModel(_chat)
57
+
58
+
59
+ # 3. 创建 Agent
60
+ async def main():
61
+ # chrome_path = subprocess.check_output(
62
+ # ["which", "google-chrome-stable"], text=True
63
+ # ).strip()
64
+ # browser_profile = BrowserProfile(
65
+ # headless=True, # 先跑通再改 False
66
+ # # executable_path="/usr/bin/google-chrome-stable",
67
+ # extra_args=[
68
+ # "--no-sandbox",
69
+ # "--disable-dev-shm-usage",
70
+ # "--disable-gpu",
71
+ # "--disable-software-rasterizer",
72
+ # "--remote-debugging-port=9222",
73
+ # "--remote-debugging-address=0.0.0.0", # 允许所有地址连接
74
+ # "--user-data-dir=/tmp/chrome-manual-test" # 指定用户数据目录
75
+ # ],
76
+ # )
77
+ # "--disable-dev-shm-usage",
78
+ # "--disable-gpu",
79
+ # "--disable-software-rasterizer",
80
+ async with async_playwright() as pw:
81
+ browser = await pw.chromium.launch(
82
+ proxy={
83
+ "server": "http://net-proxy:80",
84
+ "username": "sbx-jz9kgqolumvmfc7ds",
85
+ "password": "npt-Vd4CpGtjBOQEI8wdBv3wSOd8P4Bup1NgfsM",
86
+ },
87
+ headless=False,
88
+ args=[
89
+ # '--no-sandbox',
90
+ # '--disable-dev-shm-usage',
91
+ # '--disable-gpu',
92
+ # '--disable-extensions',
93
+ # '--disable-background-timer-throttling',
94
+ # '--disable-renderer-backgrounding',
95
+ # '--disable-features=TranslateUI',
96
+ "--disable-blink-features=AutomationControlled", # 禁用自动化控制标志
97
+ "--start-maximized", # 最大化窗口
98
+ ],
99
+ )
100
+ # task = """
101
+ # 1. 打开淘宝官网 (taobao.com)
102
+ # 2. 搜索"格力空调"
103
+ # 3. 记录下第一款商品的价格和标题
104
+ # 4. 打开京东官网 (jd.com)
105
+ # 5. 同样搜索"格力空调"
106
+ # 6. 记录下第一款商品的价格和标题
107
+ # 7. 对比在两个平台上看到的第一个商品的价格
108
+ # """
109
+ task = """
110
+ 1. 打开google搜索
111
+ 2、输入今日新闻
112
+ 3、输出第一条内容
113
+ """
114
+ # task = """
115
+ # 1、打开新浪网(http://sina.cn/)
116
+ # 2. 搜索"科技"
117
+ # 3. 记录前10条记录
118
+ # """
119
+ agent = Agent(
120
+ task=task,
121
+ llm=llm,
122
+ # browser_profile=browser_profile,
123
+ browser=browser,
124
+ use_vision=False,
125
+ )
126
+ result = await agent.run()
127
+ print("---------- 最终结果 ----------")
128
+ print(result)
129
+ await browser.close()
130
+
131
+
132
+ # if __name__ == "__main__":
133
+ # asyncio.run(main())
134
+ loop = asyncio.get_event_loop()
135
+ if loop.is_closed():
136
+ loop = asyncio.new_event_loop()
137
+ asyncio.set_event_loop(loop)
138
+ try:
139
+ loop.run_until_complete(main())
140
+ finally:
141
+ loop.close()
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Minimal async test for sandbox_async.filesystem.watch_dir.
4
+ Creates an AsyncSandbox, watches a temp directory, writes a file to trigger
5
+ an event, asserts events were received, and cleans up.
6
+ """
7
+
8
+ import asyncio
9
+ import time
10
+ import logging
11
+ from typing import List
12
+
13
+ from scalebox.sandbox_async.main import AsyncSandbox
14
+ from scalebox.sandbox.filesystem.watch_handle import FilesystemEvent
15
+
16
+
17
+ logging.basicConfig(
18
+ level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
19
+ )
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ async def main():
24
+ async with await AsyncSandbox.create(
25
+ template="base", timeout=300, metadata={"test": "watch_dir_async"}
26
+ ) as sandbox:
27
+ watch_path = "/tmp/watch_async_test"
28
+ await sandbox.files.make_dir(watch_path)
29
+
30
+ events: List[FilesystemEvent] = []
31
+
32
+ async def on_event(ev: FilesystemEvent):
33
+ print(ev)
34
+ events.append(ev)
35
+
36
+ # Start watching directory
37
+ handle = await sandbox.files.watch_dir(
38
+ path=watch_path,
39
+ on_event=on_event,
40
+ timeout=10,
41
+ recursive=False,
42
+ )
43
+
44
+ # Trigger a filesystem event
45
+ await sandbox.files.write(f"{watch_path}/new_file.txt", "content")
46
+
47
+ # Wait a bit for event propagation
48
+ await asyncio.sleep(2)
49
+
50
+ # Stop watching
51
+ await handle.stop()
52
+
53
+ logger.info(f"Received {len(events)} filesystem events")
54
+ assert len(events) >= 1
55
+
56
+
57
+ if __name__ == "__main__":
58
+ asyncio.run(main())
@@ -7,7 +7,7 @@ from scalebox.sandbox_async import AsyncSandbox
7
7
  async def main():
8
8
  sandbox = await AsyncSandbox.create(
9
9
  template="base", # 或自定义模板名
10
- api_key="sk-Wk4IgtUYOqnttxGaxZmELEV4p2FXh15Evt0FIcSa",
10
+ api_key="sk-Wk4IgtUYOqnttx",
11
11
  timeout=3600,
12
12
  )
13
13
  print("✅ 沙箱已启动,sandbox_domain:", sandbox.sandbox_domain)
@@ -5,9 +5,7 @@ from sandbox_async import AsyncSandbox
5
5
 
6
6
 
7
7
  async def main():
8
- sandbox = await AsyncSandbox.get_info(
9
- sandbox_id="", api_key="sk-Wk4IgtUYOqnttxGaxZmELEV4p2FXh15Evt0FIcSa"
10
- )
8
+ sandbox = await AsyncSandbox.get_info(sandbox_id="", api_key="sk-Wk4Ig")
11
9
  print("✅ 沙箱已启动,sandbox_domain:", sandbox.sandbox_domain)
12
10
  print("✅ 沙箱已启动,ID:", sandbox.sandbox_id)
13
11
  print("✅ 沙箱已启动,connection_config:", sandbox.name)