Skip to content

Bug: Template.sandbox_ttlin_seconds 因 alias 不匹配导致永远为 None #53

@XeonYang

Description

@XeonYang

问题描述

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=Falsemodel_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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions