问题描述
agentrun.sandbox.template.Template 的字段 sandbox_ttlin_seconds 在通过 from_inner_object() 从阿里云 API 响应解析时,始终为 None,即使 API 实际返回了有效的 TTL 值。
根因分析
1. API 返回的 JSON key
阿里云 API(alibabacloud_agentrun20250910)的 _template.py 中,to_map() 方法将 TTL 字段序列化为:
result['sandboxTTLInSeconds'] = self.sandbox_ttlin_seconds
即 API 响应中的 key 为 sandboxTTLInSeconds(注意 TTL 是大写)。
2. agentrun SDK 的 alias 生成
agentrun/utils/model.py 中的 BaseModel 使用了自动 alias 生成器:
def to_camel_case(field_name: str) -> str:
if "_" not in field_name:
return field_name
parts = field_name.split("_")
return parts[0] + "".join(word.capitalize() for word in parts[1:])
对于字段 sandbox_ttlin_seconds,生成的 alias 为:
sandbox_ttlin_seconds → sandboxTtlinSeconds
3. 不匹配
| 来源 |
Key |
| API 实际返回 |
sandboxTTLInSeconds |
| Pydantic alias 生成 |
sandboxTtlinSeconds |
由于 BaseModel 配置了 validate_by_alias=False,model_validate(d, by_alias=True) 时用 alias 做 key 匹配。sandboxTTLInSeconds 无法匹配到 sandboxTtlinSeconds,因此该值落入 model_extra(因为配置了 extra="allow"),而 sandbox_ttlin_seconds 字段始终为 None。
4. 为什么 idle_timeout 正常?
sandbox_idle_timeout_in_seconds 的 alias 为 sandboxIdleTimeoutInSeconds,与 API 返回的 key 完全一致,因此可以正常解析。
关键区别在于:TTL 是连续大写缩写词,to_camel_case 无法正确处理这种 case。按当前逻辑,ttlin 被视为一个单词,首字母大写变成 Ttlin,而 API 期望的是 TTLIn。
复现步骤
from agentrun.sandbox.template import Template
# 模拟 API 返回的数据(经 alibabacloud SDK to_map 转换后的格式)
api_data = {
'templateName': 'code-interpreter-01',
'sandboxIdleTimeoutInSeconds': 900,
'sandboxTTLInSeconds': 3600,
}
t = Template.model_validate(api_data, by_alias=True)
print(t.sandbox_idle_timeout_in_seconds) # 900 ✅
print(t.sandbox_ttlin_seconds) # None ❌(应为 3600)
print(t.model_extra) # {'sandboxTTLInSeconds': 3600}
期望行为
template.sandbox_ttlin_seconds 应正确解析为 API 返回的 sandboxTTLInSeconds 值。
建议修复方案
方案 A:为该字段添加显式 alias(推荐)
在 agentrun/sandbox/template.py 中:
from pydantic import Field
sandbox_ttlin_seconds: Optional[int] = Field(None, alias="sandboxTTLInSeconds")
这样 Pydantic 会优先使用显式 alias,覆盖自动生成的错误 alias。
方案 B:修正字段命名
将字段重命名为 sandbox_ttl_in_seconds,使 to_camel_case 能正确生成 sandboxTtlInSeconds...但这仍然无法匹配 sandboxTTLInSeconds(API 返回全大写 TTL)。所以此方案仍需搭配显式 alias。
方案 C:改进 to_camel_case 函数
使其能识别常见缩写词(如 TTL、URL、API 等),但通用性和维护成本较高。
影响范围
agentrun.sandbox.template.Template.sandbox_ttlin_seconds — 永远为 None
- 所有通过
Sandbox.get_template() / Sandbox.list_templates() 获取模版 TTL 的代码
- 下游依赖此值的业务逻辑(如同步模版配置到数据库)
环境信息
- agentrun-sdk 版本:0.0.17(已确认 0.0.21 最新版仍存在此问题)
- alibabacloud-agentrun20250910 版本:随 SDK 安装
- Python 版本:3.12
- Pydantic 版本:2.x
临时 Workaround
在业务代码中从 model_extra 回退读取:
def get_template_ttl_sec(template) -> int | None:
val = getattr(template, "sandbox_ttlin_seconds", None)
if val is not None:
return int(val)
extra = getattr(template, "model_extra", None) or {}
raw = extra.get("sandboxTTLInSeconds")
if raw is not None and raw != "":
return int(raw)
return None
问题描述
agentrun.sandbox.template.Template的字段sandbox_ttlin_seconds在通过from_inner_object()从阿里云 API 响应解析时,始终为None,即使 API 实际返回了有效的 TTL 值。根因分析
1. API 返回的 JSON key
阿里云 API(
alibabacloud_agentrun20250910)的_template.py中,to_map()方法将 TTL 字段序列化为:即 API 响应中的 key 为
sandboxTTLInSeconds(注意 TTL 是大写)。2. agentrun SDK 的 alias 生成
agentrun/utils/model.py中的BaseModel使用了自动 alias 生成器:对于字段
sandbox_ttlin_seconds,生成的 alias 为:3. 不匹配
sandboxTTLInSecondssandboxTtlinSeconds由于
BaseModel配置了validate_by_alias=False,model_validate(d, by_alias=True)时用 alias 做 key 匹配。sandboxTTLInSeconds无法匹配到sandboxTtlinSeconds,因此该值落入model_extra(因为配置了extra="allow"),而sandbox_ttlin_seconds字段始终为None。4. 为什么 idle_timeout 正常?
sandbox_idle_timeout_in_seconds的 alias 为sandboxIdleTimeoutInSeconds,与 API 返回的 key 完全一致,因此可以正常解析。关键区别在于:
TTL是连续大写缩写词,to_camel_case无法正确处理这种 case。按当前逻辑,ttlin被视为一个单词,首字母大写变成Ttlin,而 API 期望的是TTLIn。复现步骤
期望行为
template.sandbox_ttlin_seconds应正确解析为 API 返回的sandboxTTLInSeconds值。建议修复方案
方案 A:为该字段添加显式 alias(推荐)
在
agentrun/sandbox/template.py中:这样 Pydantic 会优先使用显式 alias,覆盖自动生成的错误 alias。
方案 B:修正字段命名
将字段重命名为
sandbox_ttl_in_seconds,使to_camel_case能正确生成sandboxTtlInSeconds...但这仍然无法匹配sandboxTTLInSeconds(API 返回全大写 TTL)。所以此方案仍需搭配显式 alias。方案 C:改进
to_camel_case函数使其能识别常见缩写词(如 TTL、URL、API 等),但通用性和维护成本较高。
影响范围
agentrun.sandbox.template.Template.sandbox_ttlin_seconds— 永远为 NoneSandbox.get_template()/Sandbox.list_templates()获取模版 TTL 的代码环境信息
临时 Workaround
在业务代码中从
model_extra回退读取: