Skip to content

Commit 85ab040

Browse files
committed
chore(openspec): add openspec for ai coding
Co-developed-by: Aone Copilot <noreply@alibaba-inc.com> Signed-off-by: Sodawyx <sodawyx@126.com>
1 parent 0e397c1 commit 85ab040

File tree

16 files changed

+444
-0
lines changed

16 files changed

+444
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-03-05
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
## Context
2+
3+
AgentRun SDK 的 `createSandbox` 调用链包含三层:
4+
1. **高层 API**`Sandbox.create` / `create_async`(含多个 `@overload` 签名)— 位于 `sandbox.py``__sandbox_async_template.py`
5+
2. **客户端层**`SandboxClient.create_sandbox` / `create_sandbox_async` — 位于 `client.py``__client_async_template.py`
6+
3. **Data API 层**`SandboxDataAPI.create_sandbox` / `create_sandbox_async` — 位于 `api/sandbox_data.py``api/__sandbox_data_async_template.py`
7+
8+
目前 `SandboxInput` 模型(`model.py`)已声明 `sandbox_id: Optional[str] = None` 字段,但该字段仅为模型定义,实际并未在上述调用链中被读取或传递。Data API 层构建请求体时只包含 `templateName``sandboxIdleTimeoutSeconds` 等字段,缺少 `sandboxId`
9+
10+
## Goals / Non-Goals
11+
12+
**Goals:**
13+
-`createSandbox` 完整调用链中支持可选的 `sandbox_id` 参数
14+
- 当用户传入 `sandbox_id` 时,将其作为 `sandboxId` 字段加入 Data API 请求体
15+
- 不传 `sandbox_id` 时行为与现有完全一致(向后兼容)
16+
- 同步更新所有 async 模板文件,确保 `make codegen` 生成的代码一致
17+
18+
**Non-Goals:**
19+
- 不对 `sandbox_id` 做格式校验(由服务端负责)
20+
- 不修改 `SandboxInput` 模型的结构(已有该字段)
21+
- 不修改 `connect` / `get` / `delete` / `stop` 等非创建相关的方法
22+
23+
## Decisions
24+
25+
### 1. 参数透传方式:逐层显式传参
26+
27+
在调用链的每一层都显式添加 `sandbox_id: Optional[str] = None` 参数,而非通过 `**kwargs` 或统一配置对象传递。
28+
29+
**理由**
30+
- 与现有 `nas_config``oss_mount_config``polar_fs_config` 等参数风格一致
31+
- 类型提示更明确,IDE 自动补全友好
32+
- 相比使用 `SandboxInput` 对象作为参数,显式参数对现有 API 签名的侵入最小
33+
34+
### 2. Data API 层条件性加入 `sandboxId`
35+
36+
`SandboxDataAPI.create_sandbox` 构建请求体时,仅当 `sandbox_id is not None` 时才加入 `sandboxId` 字段,与 `nasConfig``ossMountConfig` 等可选字段的处理方式保持一致。
37+
38+
**理由**:避免发送空值,减少服务端解析歧义。
39+
40+
### 3. overload 签名同步更新
41+
42+
`Sandbox.create` / `create_async` 有 4 组 `@overload` 签名(分别对应 CODE_INTERPRETER、BROWSER、AIO、CUSTOM 四种类型),每组都需要增加 `sandbox_id` 参数。
43+
44+
**理由**:保证任意 `template_type` 调用时都能使用 `sandbox_id`,且类型提示准确。
45+
46+
## Risks / Trade-offs
47+
48+
- **[风险] 模板文件遗漏** → 需确保 `__sandbox_data_async_template.py``__client_async_template.py``__sandbox_async_template.py` 三个模板文件都同步修改,并运行 `make codegen` 重新生成
49+
- **[风险] 参数在 overload 中位置不一致**`sandbox_id` 统一放在 `sandbox_idle_timeout_seconds` 之后、`nas_config` 之前,所有 overload 签名保持一致
50+
- **[权衡] 不做客户端格式校验** → 简化实现,但不合法的 sandboxId 只有在服务端才会报错
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## Why
2+
3+
用户在创建 Sandbox 时可能希望指定自定义的 `sandboxId`,以便实现幂等创建或与外部系统关联。当前 `SandboxInput` 模型中已定义 `sandbox_id` 字段,但在 `create_sandbox` 的整个调用链(`Sandbox.create` -> `SandboxClient.create_sandbox` -> `SandboxDataAPI.create_sandbox`)中并未实际传递该参数到 Data API 请求体中。
4+
5+
## What Changes
6+
7+
-`SandboxDataAPI.create_sandbox` / `create_sandbox_async` 方法中增加可选参数 `sandbox_id`,并在请求体中透传 `sandboxId` 字段
8+
-`SandboxClient.create_sandbox` / `create_sandbox_async` 方法签名中增加可选参数 `sandbox_id` 并向下透传
9+
-`Sandbox.create` / `create_async` 高层 API 及其所有 `@overload` 签名中增加可选参数 `sandbox_id` 并向下透传
10+
- 同步更新对应的 `__*_async_template.py` 模板文件(`__sandbox_data_async_template.py``__client_async_template.py``__sandbox_async_template.py`),保持模板与生成代码一致
11+
- 补充单元测试,验证 `sandbox_id` 参数的传递和序列化
12+
13+
## Capabilities
14+
15+
### New Capabilities
16+
17+
- `create-sandbox-id`: 支持在创建 Sandbox 时传入可选的 `sandboxId` 参数,允许用户自定义沙箱标识
18+
19+
### Modified Capabilities
20+
21+
22+
## Impact
23+
24+
- **API 层**`SandboxDataAPI.create_sandbox` / `create_sandbox_async` 请求体新增可选字段 `sandboxId`
25+
- **客户端层**`SandboxClient.create_sandbox` / `create_sandbox_async` 函数签名新增参数
26+
- **高层 API**`Sandbox.create` / `create_async` 及所有 overload 签名新增参数
27+
- **模板文件**:三个 `__*_async_template.py` 文件需同步修改
28+
- **向后兼容**:该参数为可选,不传则行为与现有一致,无 **BREAKING** 变更
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
## ADDED Requirements
2+
3+
### Requirement: 创建 Sandbox 时支持可选 sandboxId 参数
4+
5+
`Sandbox.create` / `create_async` 及其底层调用链 SHALL 接受一个可选的 `sandbox_id` 参数(类型 `Optional[str]`,默认 `None`)。当用户传入非 `None` 值时,该值 MUST 作为 `sandboxId` 字段包含在发往 Data API 的 POST 请求体中。当未传入时,请求体中 MUST NOT 包含 `sandboxId` 字段。
6+
7+
#### Scenario: 传入 sandbox_id 创建 Sandbox
8+
- **WHEN** 用户调用 `Sandbox.create(template_type=..., template_name=..., sandbox_id="my-custom-id")`
9+
- **THEN** Data API 层发出的 POST 请求体中包含 `"sandboxId": "my-custom-id"` 字段
10+
11+
#### Scenario: 不传 sandbox_id 创建 Sandbox
12+
- **WHEN** 用户调用 `Sandbox.create(template_type=..., template_name=...)` 且不传 `sandbox_id`
13+
- **THEN** Data API 层发出的 POST 请求体中不包含 `sandboxId` 字段,行为与现有一致
14+
15+
#### Scenario: 显式传入 sandbox_id=None
16+
- **WHEN** 用户调用 `Sandbox.create(template_type=..., template_name=..., sandbox_id=None)`
17+
- **THEN** Data API 层发出的 POST 请求体中不包含 `sandboxId` 字段
18+
19+
### Requirement: sandbox_id 参数在所有 overload 签名中可用
20+
21+
所有 `Sandbox.create` / `create_async``@overload` 签名(CODE_INTERPRETER、BROWSER、AIO、CUSTOM)MUST 包含 `sandbox_id: Optional[str] = None` 参数,保证任意模板类型均可使用该参数。
22+
23+
#### Scenario: 各类型 overload 均支持 sandbox_id
24+
- **WHEN** 用户调用任意 `template_type`(CODE_INTERPRETER / BROWSER / AIO / CUSTOM)的 `Sandbox.create`,并传入 `sandbox_id`
25+
- **THEN** 参数正常透传,不抛出 TypeError
26+
27+
### Requirement: SandboxClient 层透传 sandbox_id
28+
29+
`SandboxClient.create_sandbox` / `create_sandbox_async` MUST 接受 `sandbox_id: Optional[str] = None` 参数,并将其传递给 `SandboxDataAPI.create_sandbox` / `create_sandbox_async`
30+
31+
#### Scenario: SandboxClient 传递 sandbox_id 到 DataAPI
32+
- **WHEN** `SandboxClient.create_sandbox(template_name=..., sandbox_id="abc")` 被调用
33+
- **THEN** `SandboxDataAPI.create_sandbox` 接收到 `sandbox_id="abc"`
34+
35+
### Requirement: 异步模板文件与生成代码保持一致
36+
37+
`__sandbox_data_async_template.py``__client_async_template.py``__sandbox_async_template.py` 三个模板文件 MUST 与对应的生成文件(`sandbox_data.py``client.py``sandbox.py`)在 `sandbox_id` 参数定义上保持一致。运行 `make codegen` 后生成代码 MUST NOT 产生差异。
38+
39+
#### Scenario: codegen 后无差异
40+
- **WHEN** 修改完模板文件后运行 `make codegen`
41+
- **THEN** 生成的 `sandbox_data.py``client.py``sandbox.py` 与手动修改后的版本内容一致
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
## 1. Data API 层修改
2+
3+
- [x] 1.1 修改 `agentrun/sandbox/api/__sandbox_data_async_template.py` 中的 `create_sandbox_async` 方法,增加 `sandbox_id: Optional[str] = None` 参数,并在请求体中条件性加入 `sandboxId`
4+
- [x] 1.2 针对 `__sandbox_data_async_template.py` 运行 codegen,生成 `agentrun/sandbox/api/sandbox_data.py`(验证同步方法 `create_sandbox` 也已包含 `sandbox_id` 参数)
5+
6+
## 2. Client 层修改
7+
8+
- [x] 2.1 修改 `agentrun/sandbox/__client_async_template.py` 中的 `create_sandbox_async` 方法,增加 `sandbox_id: Optional[str] = None` 参数并向下透传给 `SandboxDataAPI`
9+
- [x] 2.2 针对 `__client_async_template.py` 运行 codegen,生成 `agentrun/sandbox/client.py`(验证同步方法 `create_sandbox` 也已包含 `sandbox_id` 参数)
10+
11+
## 3. 高层 API 修改
12+
13+
- [x] 3.1 修改 `agentrun/sandbox/__sandbox_async_template.py` 中的 `create_async` 实现和所有 `@overload` 签名,增加 `sandbox_id: Optional[str] = None` 参数并透传给 `SandboxClient.create_sandbox_async`
14+
- [x] 3.2 针对 `__sandbox_async_template.py` 运行 codegen,生成 `agentrun/sandbox/sandbox.py`(验证同步方法 `create` 及其 overload 也已包含 `sandbox_id` 参数)
15+
16+
## 4. 验证
17+
18+
- [x] 4.1 补充/更新单元测试,验证 `sandbox_id` 参数在各层的传递和请求体序列化
19+
- [x] 4.2 运行 `uv run mypy --config-file mypy.ini .` 进行类型检查,确保无新增错误
20+
- [x] 4.3 运行相关模块的单元测试,确保所有测试通过
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-03-05
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
## Context
2+
3+
Sandbox 模块的调用链为:
4+
5+
```
6+
Sandbox 静态方法 (sandbox.py)
7+
→ SandboxClient 方法 (client.py)
8+
→ SandboxDataAPI 方法 (sandbox_data.py)
9+
→ DataAPI 基类 HTTP 方法 (data_api.py)
10+
→ _prepare_request → auth() → httpx 发送请求
11+
```
12+
13+
用户通过 `Config(headers=..., token=...)` 传入认证信息时,期望这些信息能贯穿整条调用链到达最终的 HTTP 请求。
14+
15+
当前状态:`config` 在第 2 层(`SandboxClient``SandboxDataAPI`)和第 3 层(`SandboxDataAPI``DataAPI.get/post/delete`)被丢弃,导致认证信息缺失。
16+
17+
`create_sandbox` / `create_sandbox_async` 在第 2 层正确传递了 `config`,但第 3 层同样缺失。`get/stop/delete` 系列方法在两层都缺失。
18+
19+
## Goals / Non-Goals
20+
21+
**Goals:**
22+
- 确保用户通过 `Config` 传入的所有信息(headers、token 等)能完整透传到底层 HTTP 请求
23+
- 修复 `SandboxClient` 中 6 个方法的 `config` 透传
24+
- 修复 `SandboxDataAPI` 中所有方法的 `config` 透传到 `DataAPI` 基类
25+
- 同步更新模板文件 `__sandbox_data_async_template.py`,确保 `make codegen` 后生成正确代码
26+
27+
**Non-Goals:**
28+
- 不修改 `Sandbox.__get_client()` 的无参构造行为(per-request config 透传已足够)
29+
- 不修改 `DataAPI` 基类的接口设计
30+
- 不修改其他模块(browser、code_interpreter、aio 等)的类似问题(如果存在,作为后续工作)
31+
32+
## Decisions
33+
34+
### 决策 1:在调用点透传 config,而非修改 `__get_client()` 构造
35+
36+
**选择**:在 `SandboxClient` 的每个方法中将 `config` 传给 `SandboxDataAPI`,在 `SandboxDataAPI` 的每个方法中将 `config` 传给 `DataAPI` 基类方法。
37+
38+
**理由**
39+
- `__get_client()` 是一个无状态的工厂方法,如果改为接收 config,需要修改 `Sandbox` 基类上所有调用 `__get_client()` 的地方,改动范围大
40+
- per-request config 透传是已有的设计模式(`create_sandbox` 已部分实现),保持一致性
41+
- `DataAPI` 基类的 `Config.with_configs(self.config, config)` 已支持运行时合并 config
42+
43+
**替代方案**:修改 `__get_client(cls, config)` 让它将 config 注入 `SandboxClient` 构造函数。但这会造成更大改动且每次调用都创建新的 client 实例,不如现有模式高效。
44+
45+
### 决策 2:先修改模板文件,再通过 `make codegen` 生成
46+
47+
**选择**:修改 `__sandbox_data_async_template.py`,再运行 `make codegen` 生成 `sandbox_data.py`
48+
49+
**理由**`sandbox_data.py` 头部注释明确标注为自动生成文件,直接修改会在下次 codegen 时被覆盖。
50+
51+
## Risks / Trade-offs
52+
53+
- **[低风险] 其他模块可能存在相同问题** → 本次仅修复 Sandbox 模块;后续可排查 browser/code_interpreter/aio 等模块,作为独立 change 处理
54+
- **[低风险] `make codegen` 可能覆盖手动修改** → 通过先改模板再 codegen 避免此问题
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
## Why
2+
3+
用户通过 `Sandbox.connect(sandbox_id=..., config=Config(headers={...}))` 传入自定义 Config(含 headers、token 等认证信息)时,这些信息在调用链中被丢弃,导致底层 HTTP 请求缺少必要的认证头,报 `missing API key in header X-API-Key` 错误。此 bug 导致在不设置环境变量 AKSK 的场景下,无法通过 Config 注入认证信息来使用 Sandbox 的 get/stop/delete 等操作。
4+
5+
## What Changes
6+
7+
- 修复 `SandboxClient``get_sandbox``get_sandbox_async``stop_sandbox``stop_sandbox_async``delete_sandbox``delete_sandbox_async` 六个方法,将 `config` 参数透传给 `SandboxDataAPI` 对应方法
8+
- 修复 `SandboxDataAPI` 中所有方法(`get_sandbox``stop_sandbox``delete_sandbox``create_sandbox` 及其 async 版本),将 `config` 参数透传给 `DataAPI` 基类的 HTTP 方法(`get`/`post`/`delete`
9+
- 同步修复 `__sandbox_data_async_template.py` 模板文件,并通过 `make codegen` 重新生成 `sandbox_data.py`
10+
11+
## Capabilities
12+
13+
### New Capabilities
14+
15+
- `sandbox-config-passthrough`: 修复 Sandbox 模块中 Config 对象(headers、token 等)在多层调用链中的完整透传
16+
17+
### Modified Capabilities
18+
19+
## Impact
20+
21+
- **受影响代码**
22+
- `agentrun/sandbox/client.py``SandboxClient` 的 6 个方法
23+
- `agentrun/sandbox/api/__sandbox_data_async_template.py` — 模板文件中所有方法
24+
- `agentrun/sandbox/api/sandbox_data.py` — 自动生成文件(通过 `make codegen` 重新生成)
25+
- **受影响 API**`Sandbox.connect``Sandbox.stop_by_id``Sandbox.delete_by_id` 及其 async 版本
26+
- **向后兼容**:完全向后兼容,不改变任何公开 API 签名,仅修复内部透传缺失
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
## ADDED Requirements
2+
3+
### Requirement: SandboxClient 方法 SHALL 将 config 透传给 SandboxDataAPI
4+
5+
`SandboxClient` 中的 `get_sandbox``get_sandbox_async``stop_sandbox``stop_sandbox_async``delete_sandbox``delete_sandbox_async` 方法 SHALL 将其接收的 `config` 参数传递给对应的 `SandboxDataAPI` 方法调用。
6+
7+
#### Scenario: get_sandbox 透传 config
8+
- **WHEN** 调用 `SandboxClient.get_sandbox(sandbox_id, config=Config(headers={"X-API-Key": "test"}))`
9+
- **THEN** 底层 `SandboxDataAPI.get_sandbox(sandbox_id, config=config)` SHALL 接收到该 config 对象
10+
11+
#### Scenario: stop_sandbox 透传 config
12+
- **WHEN** 调用 `SandboxClient.stop_sandbox(sandbox_id, config=Config(headers={"X-API-Key": "test"}))`
13+
- **THEN** 底层 `SandboxDataAPI.stop_sandbox(sandbox_id, config=config)` SHALL 接收到该 config 对象
14+
15+
#### Scenario: delete_sandbox 透传 config
16+
- **WHEN** 调用 `SandboxClient.delete_sandbox(sandbox_id, config=Config(headers={"X-API-Key": "test"}))`
17+
- **THEN** 底层 `SandboxDataAPI.delete_sandbox(sandbox_id, config=config)` SHALL 接收到该 config 对象
18+
19+
#### Scenario: 异步版本同样透传 config
20+
- **WHEN** 调用 `SandboxClient``get_sandbox_async``stop_sandbox_async``delete_sandbox_async` 并传入 config 时
21+
- **THEN** 底层对应的 `SandboxDataAPI` 异步方法 SHALL 接收到该 config 对象
22+
23+
### Requirement: SandboxDataAPI 方法 SHALL 将 config 透传给 DataAPI 基类 HTTP 方法
24+
25+
`SandboxDataAPI` 中的所有方法(`create_sandbox``get_sandbox``stop_sandbox``delete_sandbox` 及其 async 版本)在调用 `DataAPI` 基类的 `get`/`post`/`delete` 方法时,SHALL 将 `config` 参数传递下去。
26+
27+
#### Scenario: get_sandbox 透传 config 到 DataAPI.get
28+
- **WHEN** `SandboxDataAPI.get_sandbox(sandbox_id, config=some_config)` 被调用时
29+
- **THEN** 底层 `self.get("/", config=config)` SHALL 接收到该 config,使得 `DataAPI._prepare_request` 能通过 `Config.with_configs(self.config, config)` 合并 headers
30+
31+
#### Scenario: create_sandbox 透传 config 到 DataAPI.post
32+
- **WHEN** `SandboxDataAPI.create_sandbox(template_name, config=some_config)` 被调用时
33+
- **THEN** 底层 `self.post("/", data=data, config=config)` SHALL 接收到该 config
34+
35+
#### Scenario: stop_sandbox 透传 config 到 DataAPI.post
36+
- **WHEN** `SandboxDataAPI.stop_sandbox(sandbox_id, config=some_config)` 被调用时
37+
- **THEN** 底层 `self.post("/stop", config=config)` SHALL 接收到该 config
38+
39+
#### Scenario: delete_sandbox 透传 config 到 DataAPI.delete
40+
- **WHEN** `SandboxDataAPI.delete_sandbox(sandbox_id, config=some_config)` 被调用时
41+
- **THEN** 底层 `self.delete("/", config=config)` SHALL 接收到该 config
42+
43+
### Requirement: 自定义 headers SHALL 出现在最终 HTTP 请求中
44+
45+
当用户通过 `Config(headers={"X-API-Key": "xxx"})` 传入自定义 headers 时,这些 headers SHALL 出现在最终发出的 HTTP 请求头中。
46+
47+
#### Scenario: 通过 Sandbox.connect 传入 headers
48+
- **WHEN** 调用 `Sandbox.connect(sandbox_id="...", config=Config(headers={"Authorization": "Bearer token123"}))`
49+
- **THEN** 底层发出的 GET 请求 SHALL 包含 `Authorization: Bearer token123` 请求头
50+
51+
#### Scenario: 通过 Config(token=...) 传入 token
52+
- **WHEN** 调用 `Sandbox.connect(sandbox_id="...", config=Config(token="my-token"))`
53+
- **THEN** 底层发出的请求 SHALL 包含 `Agentrun-Access-Token: my-token` 请求头
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## 1. 修复模板文件 SandboxDataAPI config 透传
2+
3+
- [x] 1.1 修改 `agentrun/sandbox/api/__sandbox_data_async_template.py`,在 `get_sandbox` / `get_sandbox_async``self.get("/")` / `self.get_async("/")` 调用中添加 `config=config`
4+
- [x] 1.2 修改模板中 `stop_sandbox` / `stop_sandbox_async``self.post("/stop")` / `self.post_async("/stop")` 调用中添加 `config=config`
5+
- [x] 1.3 修改模板中 `delete_sandbox` / `delete_sandbox_async``self.delete("/")` / `self.delete_async("/")` 调用中添加 `config=config`
6+
- [x] 1.4 修改模板中 `create_sandbox` / `create_sandbox_async``self.post("/", data=data)` / `self.post_async("/", data=data)` 调用中添加 `config=config`
7+
- [x] 1.5 运行 `uv run python3 codegen/codegen.py --sync-only --template agentrun/sandbox/api/__sandbox_data_async_template.py` 仅重新生成 `agentrun/sandbox/api/sandbox_data.py`,然后运行 `make fmt-file FMT_FILE=agentrun/sandbox/api/__sandbox_data_async_template.py` 格式化模板文件,确认生成结果正确
8+
9+
## 2. 修复 SandboxClient config 透传
10+
11+
- [x] 2.1 修改 `agentrun/sandbox/client.py``get_sandbox` 方法,将 `self.__sandbox_data_api.get_sandbox(sandbox_id)` 改为 `self.__sandbox_data_api.get_sandbox(sandbox_id, config=config)`(已在之前修复)
12+
- [x] 2.2 修改 `get_sandbox_async`,将 `self.__sandbox_data_api.get_sandbox_async(sandbox_id)` 改为 `self.__sandbox_data_api.get_sandbox_async(sandbox_id, config=config)`
13+
- [x] 2.3 修改 `stop_sandbox`,将 `self.__sandbox_data_api.stop_sandbox(sandbox_id)` 改为 `self.__sandbox_data_api.stop_sandbox(sandbox_id, config=config)`
14+
- [x] 2.4 修改 `stop_sandbox_async`,将 `self.__sandbox_data_api.stop_sandbox_async(sandbox_id)` 改为 `self.__sandbox_data_api.stop_sandbox_async(sandbox_id, config=config)`
15+
- [x] 2.5 修改 `delete_sandbox`,将 `self.__sandbox_data_api.delete_sandbox(sandbox_id)` 改为 `self.__sandbox_data_api.delete_sandbox(sandbox_id, config=config)`
16+
- [x] 2.6 修改 `delete_sandbox_async`,将 `self.__sandbox_data_api.delete_sandbox_async(sandbox_id)` 改为 `self.__sandbox_data_api.delete_sandbox_async(sandbox_id, config=config)`
17+
18+
## 3. 验证
19+
20+
- [x] 3.1 运行 `uv run mypy --config-file mypy.ini .` 确保类型检查通过
21+
- [x] 3.2 运行相关单元测试确保无回归
22+
- [x] 3.3 修改 `examples/sandbox_test.py`,通过 `Config(headers=...)` 传入自定义 headers,开启 debug 日志,运行 `uv run python examples/sandbox_test.py` 观察日志中是否包含自定义 headers(使用 `examples/.env` 中的环境变量)

0 commit comments

Comments
 (0)