scalebox-sdk 0.1.25__py3-none-any.whl → 1.0.1__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 (70) hide show
  1. scalebox/__init__.py +2 -2
  2. scalebox/api/__init__.py +3 -1
  3. scalebox/api/client/api/sandboxes/post_sandboxes_sandbox_id_connect.py +193 -0
  4. scalebox/api/client/models/connect_sandbox.py +59 -0
  5. scalebox/api/client/models/error.py +2 -2
  6. scalebox/api/client/models/listed_sandbox.py +19 -1
  7. scalebox/api/client/models/new_sandbox.py +10 -0
  8. scalebox/api/client/models/sandbox.py +13 -0
  9. scalebox/api/client/models/sandbox_detail.py +24 -0
  10. scalebox/cli.py +125 -125
  11. scalebox/client/aclient.py +57 -57
  12. scalebox/client/client.py +102 -102
  13. scalebox/code_interpreter/__init__.py +12 -12
  14. scalebox/code_interpreter/charts.py +230 -230
  15. scalebox/code_interpreter/constants.py +3 -3
  16. scalebox/code_interpreter/exceptions.py +13 -13
  17. scalebox/code_interpreter/models.py +485 -485
  18. scalebox/connection_config.py +34 -1
  19. scalebox/csx_connect/__init__.py +1 -1
  20. scalebox/csx_connect/client.py +485 -485
  21. scalebox/csx_desktop/main.py +651 -651
  22. scalebox/exceptions.py +83 -83
  23. scalebox/generated/api.py +61 -61
  24. scalebox/generated/api_pb2.py +203 -203
  25. scalebox/generated/api_pb2.pyi +956 -956
  26. scalebox/generated/api_pb2_connect.py +1407 -1407
  27. scalebox/generated/rpc.py +50 -50
  28. scalebox/sandbox/main.py +146 -139
  29. scalebox/sandbox/sandbox_api.py +105 -91
  30. scalebox/sandbox/signature.py +40 -40
  31. scalebox/sandbox/utils.py +34 -34
  32. scalebox/sandbox_async/main.py +226 -44
  33. scalebox/sandbox_async/sandbox_api.py +124 -3
  34. scalebox/sandbox_sync/main.py +205 -130
  35. scalebox/sandbox_sync/sandbox_api.py +119 -3
  36. scalebox/test/CODE_INTERPRETER_TESTS_READY.md +323 -323
  37. scalebox/test/README.md +329 -329
  38. scalebox/test/bedrock_openai_adapter.py +67 -0
  39. scalebox/test/code_interpreter_test.py +34 -34
  40. scalebox/test/code_interpreter_test_sync.py +34 -34
  41. scalebox/test/run_stress_code_interpreter_sync.py +166 -0
  42. scalebox/test/simple_upload_example.py +123 -0
  43. scalebox/test/stabitiy_test.py +310 -0
  44. scalebox/test/test_browser_use.py +25 -0
  45. scalebox/test/test_browser_use_scalebox.py +61 -0
  46. scalebox/test/test_code_interpreter_sync_comprehensive.py +115 -65
  47. scalebox/test/test_connect_pause_async.py +277 -0
  48. scalebox/test/test_connect_pause_sync.py +267 -0
  49. scalebox/test/test_desktop_sandbox_sf.py +117 -0
  50. scalebox/test/test_download_url.py +49 -0
  51. scalebox/test/test_sandbox_async_comprehensive.py +1 -1
  52. scalebox/test/test_sandbox_object_storage_example.py +146 -0
  53. scalebox/test/test_sandbox_object_storage_example_async.py +156 -0
  54. scalebox/test/test_sf.py +137 -0
  55. scalebox/test/test_watch_dir_async.py +56 -0
  56. scalebox/test/testacreate.py +1 -1
  57. scalebox/test/testagetinfo.py +1 -1
  58. scalebox/test/testcomputeuse.py +243 -243
  59. scalebox/test/testsandbox_api.py +1 -3
  60. scalebox/test/testsandbox_sync.py +1 -1
  61. scalebox/test/upload_100mb_example.py +355 -0
  62. scalebox/utils/httpcoreclient.py +297 -297
  63. scalebox/utils/httpxclient.py +403 -403
  64. scalebox/version.py +2 -2
  65. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/METADATA +1 -1
  66. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/RECORD +70 -53
  67. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/WHEEL +1 -1
  68. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/entry_points.txt +0 -0
  69. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/licenses/LICENSE +0 -0
  70. {scalebox_sdk-0.1.25.dist-info → scalebox_sdk-1.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,49 @@
1
+ from scalebox.code_interpreter import Sandbox
2
+ import json
3
+
4
+ # 1. 准备要上传的文件内容
5
+ print("正在准备文件内容...")
6
+ results_data = {
7
+ "experiment_id": "exp_001",
8
+ "status": "completed",
9
+ "metrics": {
10
+ "accuracy": 0.952,
11
+ "precision": 0.94,
12
+ "recall": 0.96
13
+ },
14
+ "timestamp": "2024-01-01T12:00:00Z",
15
+ "details": [
16
+ {"epoch": 1, "loss": 0.45},
17
+ {"epoch": 2, "loss": 0.32},
18
+ {"epoch": 3, "loss": 0.18}
19
+ ]
20
+ }
21
+
22
+ # 转换为 JSON 字符串
23
+ json_content = json.dumps(results_data, indent=2)
24
+
25
+ # 2. 创建沙箱并写入文件
26
+ print("\n正在创建沙箱并写入文件...")
27
+ sandbox = Sandbox.create(timeout=1800)
28
+ remote_path = "/home/user/results.json"
29
+
30
+ # 关键修改:使用 sandbox.write() 写入文件
31
+ sandbox.files.write(remote_path, json_content)
32
+ print(f"✅ 文件已写入沙箱: {remote_path}")
33
+
34
+ # 3. 获取预签名下载 URL
35
+ print("\n正在生成下载链接...")
36
+ download_url = sandbox.download_url(
37
+ path=remote_path,
38
+ use_signature_expiration=180 # 180秒有效期
39
+ )
40
+
41
+ print(f"\n📥 下载 URL: {download_url}")
42
+ print(f"⏰ 链接将在 3 分钟后过期")
43
+
44
+ upload_url = sandbox.upload_url(
45
+ path="/home/user",
46
+ use_signature_expiration=360
47
+ )
48
+ print(f"\n📥 上传 URL: {upload_url}")
49
+ print(f"⏰ 链接将在 6 分钟后过期")
@@ -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
  )
@@ -0,0 +1,146 @@
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(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
42
+
43
+ # CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
44
+ # TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
45
+ # TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
46
+ #
47
+ #
48
+ # def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
49
+ # raw_value = os.environ.get(CONFIG_ENV)
50
+ # if not raw_value:
51
+ # logger.warning(
52
+ # "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
53
+ # CONFIG_ENV,
54
+ # )
55
+ # return None
56
+ #
57
+ # config_text: Optional[str] = None
58
+ # potential_path = Path(raw_value)
59
+ # if potential_path.is_file():
60
+ # config_text = potential_path.read_text(encoding="utf-8")
61
+ # else:
62
+ # config_text = raw_value
63
+ #
64
+ # try:
65
+ # payload = json.loads(config_text)
66
+ # except json.JSONDecodeError as exc:
67
+ # logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
68
+ # raise SystemExit(1) from exc
69
+ #
70
+ # if not isinstance(payload, dict):
71
+ # logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
72
+ # raise SystemExit(1)
73
+ #
74
+ # return payload
75
+
76
+
77
+ # def _mask_value(value: str) -> str:
78
+ # if len(value) <= 4:
79
+ # return "*" * len(value)
80
+ # return f"{value[:2]}***{value[-2:]}"
81
+
82
+
83
+ # def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
84
+ # masked = {}
85
+ # for key, value in config.items():
86
+ # if isinstance(value, str):
87
+ # masked[key] = _mask_value(value)
88
+ # else:
89
+ # masked[key] = value
90
+ # return masked
91
+
92
+
93
+ def create_sandbox_with_object_storage():
94
+ # payload = _load_object_storage_payload()
95
+ # if payload is None:
96
+ # return
97
+ #
98
+ # template = os.environ.get(TEMPLATE_ENV, "base")
99
+ # timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
100
+
101
+ sandbox: Optional[Sandbox] = None
102
+ try:
103
+ sandbox = Sandbox.create(
104
+ template="base",
105
+ timeout=3600,
106
+ metadata={"example": "object_storage"},
107
+ object_storage={"uri": "s3://bgd-test/test/",
108
+ "mount_point": "/mnt/oss",
109
+ # "access_key": "",
110
+ # "secret_key": "",
111
+ "region": "us-east-2",
112
+ "endpoint": "https://s3.us-east-2.amazonaws.com",},
113
+ )
114
+ print(sandbox.sandbox_id)
115
+ print(sandbox.sandbox_domain)
116
+ if sandbox.object_storage:
117
+ print(sandbox.object_storage)
118
+
119
+ info = sandbox.get_info()
120
+ print(info)
121
+ print(f"get_info.object_storage: {info.object_storage}")
122
+
123
+ listed = Sandbox.list(query=SandboxQuery(metadata={"example": "object_storage"}))
124
+ print(f"List 根据 metadata 命中的沙箱数量: {len(listed)}")
125
+ for listed_box in listed:
126
+ detailed = Sandbox.get_info(sandbox_id=listed_box.sandbox_id)
127
+ print(detailed)
128
+ print(
129
+ f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
130
+ )
131
+
132
+ # 在沙箱中运行简单命令,确认可正常访问
133
+ result = sandbox.commands.run("echo 'object storage sandbox is ready'")
134
+ print(f"命令输出: {result.stdout.strip()}")
135
+ except SandboxException as exc:
136
+ logger.error("创建或使用沙箱失败:%s", exc)
137
+ raise
138
+ finally:
139
+ if sandbox is not None:
140
+ # sandbox.kill()
141
+ logger.info("沙箱已销毁")
142
+
143
+
144
+ if __name__ == "__main__":
145
+ create_sandbox_with_object_storage()
146
+
@@ -0,0 +1,156 @@
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(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
48
+
49
+ # CONFIG_ENV = "SCALEBOX_OBJECT_STORAGE_CONFIG"
50
+ # TEMPLATE_ENV = "SCALEBOX_OBJECT_STORAGE_TEMPLATE"
51
+ # TIMEOUT_ENV = "SCALEBOX_OBJECT_STORAGE_TIMEOUT"
52
+ #
53
+ #
54
+ # def _load_object_storage_payload() -> Optional[Dict[str, Any]]:
55
+ # raw_value = os.environ.get(CONFIG_ENV)
56
+ # if not raw_value:
57
+ # logger.warning(
58
+ # "未检测到 %s 环境变量,跳过 object_storage 示例。请设置 JSON 配置后重新运行。",
59
+ # CONFIG_ENV,
60
+ # )
61
+ # return None
62
+ #
63
+ # config_text: Optional[str] = None
64
+ # potential_path = Path(raw_value)
65
+ # if potential_path.is_file():
66
+ # config_text = potential_path.read_text(encoding="utf-8")
67
+ # else:
68
+ # config_text = raw_value
69
+ #
70
+ # try:
71
+ # payload = json.loads(config_text)
72
+ # except json.JSONDecodeError as exc:
73
+ # logger.error("无法解析 object_storage 配置(需合法 JSON):%s", exc)
74
+ # raise SystemExit(1) from exc
75
+ #
76
+ # if not isinstance(payload, dict):
77
+ # logger.error("object_storage 配置必须是 JSON 对象,示例详见文件头部注释。")
78
+ # raise SystemExit(1)
79
+ #
80
+ # return payload
81
+ #
82
+ #
83
+ # def _mask_value(value: str) -> str:
84
+ # if len(value) <= 4:
85
+ # return "*" * len(value)
86
+ # return f"{value[:2]}***{value[-2:]}"
87
+ #
88
+ #
89
+ # def _display_object_storage_keys(config: Dict[str, Any]) -> Dict[str, Any]:
90
+ # masked = {}
91
+ # for key, value in config.items():
92
+ # if isinstance(value, str):
93
+ # masked[key] = _mask_value(value)
94
+ # else:
95
+ # masked[key] = value
96
+ # return masked
97
+
98
+
99
+ async def create_sandbox_with_object_storage_async():
100
+ # payload = _load_object_storage_payload()
101
+ # if payload is None:
102
+ # return
103
+ #
104
+ # template = os.environ.get(TEMPLATE_ENV, "base")
105
+ # timeout = int(os.environ.get(TIMEOUT_ENV, "600"))
106
+
107
+ sandbox: Optional[AsyncSandbox] = None
108
+ try:
109
+ sandbox = await AsyncSandbox.create(
110
+ template="base",
111
+ timeout=3600,
112
+ metadata={"example": "object_storage_async"},
113
+ object_storage={
114
+ "uri": "s3://bgd-test/test/",
115
+ "mount_point": "/mnt/oss",
116
+ "access_key": "",
117
+ "secret_key": "",
118
+ "region": "us-east-2",
119
+ "endpoint": "https://s3.us-east-2.amazonaws.com",
120
+ },
121
+ )
122
+ print(sandbox.sandbox_id)
123
+ print(sandbox.sandbox_domain)
124
+ if sandbox.object_storage:
125
+ print(sandbox.object_storage)
126
+
127
+ info = await sandbox.get_info()
128
+ print(info)
129
+ print(f"get_info.object_storage: {info.object_storage}")
130
+
131
+ listed = await AsyncSandbox.list(
132
+ query=SandboxQuery(metadata={"example": "object_storage_async"})
133
+ )
134
+ print(f"Async list 根据 metadata 命中的沙箱数量: {len(listed)}")
135
+ for listed_box in listed:
136
+ detailed = await AsyncSandbox.get_info(sandbox_id=listed_box.sandbox_id)
137
+ print(detailed)
138
+ print(
139
+ f"list -> sandbox {listed_box.sandbox_id} object_storage: {detailed.object_storage}"
140
+ )
141
+
142
+ # 在沙箱中运行简单命令,确认可正常访问
143
+ result = await sandbox.commands.run("echo 'async object storage sandbox is ready'")
144
+ print(f"命令输出: {result.stdout.strip()}")
145
+ except SandboxException as exc:
146
+ logger.error("创建或使用异步沙箱失败:%s", exc)
147
+ raise
148
+ finally:
149
+ if sandbox is not None:
150
+ # await sandbox.kill()
151
+ logger.info("异步沙箱已销毁")
152
+
153
+
154
+ if __name__ == "__main__":
155
+ asyncio.run(create_sandbox_with_object_storage_async())
156
+
@@ -0,0 +1,137 @@
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
+ # 2. 包一层模型,补 .provider + 转发所有必要方法
29
+ class SiliconFlowModel:
30
+ provider = "siliconflow"
31
+
32
+ def __init__(self, chat: ChatOpenAI):
33
+ self.chat = chat
34
+ # 把 browser-use 可能用到的字段全部代理
35
+ self.model_name = chat.model_name # ← 新增
36
+ self.model = chat.model_name # ← 新增(防它再换字段)
37
+ self.ainvoke = chat.ainvoke
38
+ self.invoke = chat.invoke
39
+ self.bind = chat.bind
40
+
41
+ # === 同步 ===
42
+ def invoke(self, *args, **kwargs):
43
+ return self.chat.invoke(*args, **kwargs)
44
+
45
+ # === 异步 ===
46
+ async def ainvoke(self, *args, **kwargs):
47
+ return await self.chat.ainvoke(*args, **kwargs)
48
+
49
+ # 如有其他缺失方法,继续代理即可
50
+ def bind(self, *args, **kwargs):
51
+ return self.chat.bind(*args, **kwargs)
52
+
53
+ # llm = SiliconFlowModel(_chat)
54
+
55
+ # 3. 创建 Agent
56
+ async def main():
57
+ # chrome_path = subprocess.check_output(
58
+ # ["which", "google-chrome-stable"], text=True
59
+ # ).strip()
60
+ # browser_profile = BrowserProfile(
61
+ # headless=True, # 先跑通再改 False
62
+ # # executable_path="/usr/bin/google-chrome-stable",
63
+ # extra_args=[
64
+ # "--no-sandbox",
65
+ # "--disable-dev-shm-usage",
66
+ # "--disable-gpu",
67
+ # "--disable-software-rasterizer",
68
+ # "--remote-debugging-port=9222",
69
+ # "--remote-debugging-address=0.0.0.0", # 允许所有地址连接
70
+ # "--user-data-dir=/tmp/chrome-manual-test" # 指定用户数据目录
71
+ # ],
72
+ # )
73
+ # "--disable-dev-shm-usage",
74
+ # "--disable-gpu",
75
+ # "--disable-software-rasterizer",
76
+ async with async_playwright() as pw:
77
+ browser = await pw.chromium.launch(
78
+ proxy={
79
+ "server": "http://net-proxy:80",
80
+ "username":"sbx-jz9kgqolumvmfc7ds",
81
+ "password": "npt-Vd4CpGtjBOQEI8wdBv3wSOd8P4Bup1NgfsM"
82
+ },
83
+ headless=False,
84
+ args=[
85
+ # '--no-sandbox',
86
+
87
+ # '--disable-dev-shm-usage',
88
+ # '--disable-gpu',
89
+ # '--disable-extensions',
90
+ # '--disable-background-timer-throttling',
91
+ # '--disable-renderer-backgrounding',
92
+ # '--disable-features=TranslateUI',
93
+ "--disable-blink-features=AutomationControlled", # 禁用自动化控制标志
94
+ "--start-maximized", # 最大化窗口
95
+ ]
96
+ )
97
+ # task = """
98
+ # 1. 打开淘宝官网 (taobao.com)
99
+ # 2. 搜索"格力空调"
100
+ # 3. 记录下第一款商品的价格和标题
101
+ # 4. 打开京东官网 (jd.com)
102
+ # 5. 同样搜索"格力空调"
103
+ # 6. 记录下第一款商品的价格和标题
104
+ # 7. 对比在两个平台上看到的第一个商品的价格
105
+ # """
106
+ task = """
107
+ 1. 打开google搜索
108
+ 2、输入今日新闻
109
+ 3、输出第一条内容
110
+ """
111
+ # task = """
112
+ # 1、打开新浪网(http://sina.cn/)
113
+ # 2. 搜索"科技"
114
+ # 3. 记录前10条记录
115
+ # """
116
+ agent = Agent(
117
+ task=task,
118
+ llm=llm,
119
+ # browser_profile=browser_profile,
120
+ browser=browser,
121
+ use_vision=False
122
+ )
123
+ result = await agent.run()
124
+ print("---------- 最终结果 ----------")
125
+ print(result)
126
+ await browser.close()
127
+
128
+ # if __name__ == "__main__":
129
+ # asyncio.run(main())
130
+ loop = asyncio.get_event_loop()
131
+ if loop.is_closed():
132
+ loop = asyncio.new_event_loop()
133
+ asyncio.set_event_loop(loop)
134
+ try:
135
+ loop.run_until_complete(main())
136
+ finally:
137
+ loop.close()
@@ -0,0 +1,56 @@
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(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
18
+ logger = logging.getLogger(__name__)
19
+
20
+
21
+ async def main():
22
+ async with await AsyncSandbox.create(template="base", timeout=300, metadata={"test": "watch_dir_async"}) as sandbox:
23
+ watch_path = "/tmp/watch_async_test"
24
+ await sandbox.files.make_dir(watch_path)
25
+
26
+ events: List[FilesystemEvent] = []
27
+
28
+ async def on_event(ev: FilesystemEvent):
29
+ print(ev)
30
+ events.append(ev)
31
+
32
+ # Start watching directory
33
+ handle = await sandbox.files.watch_dir(
34
+ path=watch_path,
35
+ on_event=on_event,
36
+ timeout=10,
37
+ recursive=False,
38
+ )
39
+
40
+ # Trigger a filesystem event
41
+ await sandbox.files.write(f"{watch_path}/new_file.txt", "content")
42
+
43
+ # Wait a bit for event propagation
44
+ await asyncio.sleep(2)
45
+
46
+ # Stop watching
47
+ await handle.stop()
48
+
49
+ logger.info(f"Received {len(events)} filesystem events")
50
+ assert len(events) >= 1
51
+
52
+
53
+ if __name__ == "__main__":
54
+ asyncio.run(main())
55
+
56
+
@@ -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)
@@ -6,7 +6,7 @@ from sandbox_async import AsyncSandbox
6
6
 
7
7
  async def main():
8
8
  sandbox = await AsyncSandbox.get_info(
9
- sandbox_id="", api_key="sk-Wk4IgtUYOqnttxGaxZmELEV4p2FXh15Evt0FIcSa"
9
+ sandbox_id="", api_key="sk-Wk4Ig"
10
10
  )
11
11
  print("✅ 沙箱已启动,sandbox_domain:", sandbox.sandbox_domain)
12
12
  print("✅ 沙箱已启动,ID:", sandbox.sandbox_id)