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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions