Skip to content

feat: support skill version qualifier in download - #129

Open
yuyushui66 wants to merge 3 commits into
Serverless-Devs:mainfrom
yuyushui66:main
Open

feat: support skill version qualifier in download #129
yuyushui66 wants to merge 3 commits into
Serverless-Devs:mainfrom
yuyushui66:main

Conversation

@yuyushui66

Copy link
Copy Markdown

Summary

  • Tool.download_skill() / download_skill_async() 新增 qualifier 参数,支持下载指定版本的 Skill(如 "v1.0.0""default""LATEST"
  • skill_tools() 支持 "name@qualifier" 字符串语法和 qualifier= kwarg,列表入参时每个 skill 可独立指定版本
  • 完全向后兼容:所有新增参数均为可选,老代码无需修改

Background

后端 (funagent-core) 已实现 Skill 版本管理控制面 API 和数据面版本化下载端点:

GET {data_endpoint}/tools/{name}/download?qualifier={version}

本 PR 让 Python SDK 暴露这一能力,使 Agent Runtime / 业务代码可以在下载 Skill 时锁定版本,避免因 LATEST 漂移导致行为变化。

Changes

公开 API(新增可选参数,向后兼容)

API 改动
Tool.download_skill() 新增 qualifier: Optional[str] = None
Tool.download_skill_async() 新增 qualifier: Optional[str] = None
skill_tools() 新增 qualifier: Optional[str] = None kwarg;name 入参字符串/列表元素支持 "@qualifier" 语法

用法示例

# 1. 直接下载指定版本
tool.download_skill(qualifier="v1.0.0")

# 2. skill_tools 字符串语法
skill_tools("my-skill@v1.0.0")
skill_tools("my-skill@default")

# 3. 批量混合版本
skill_tools(["skill-a@v1.0.0", "skill-b@latest", "skill-c"])

# 4. ToolResource 入参用 kwarg
skill_tools(tool, qualifier="v1.0.0")
# 5. 环境变量驱动(agent_v2.py 等无需改代码)
export AGENTRUN_SKILL_NAMES="code-review@v1.0.0,doc-gen@default,test-runner"

关键设计决策

  • @ 作分隔符:工具名受后端正则 ^[_a-zA-Z][-_a-zA-Z0-9]*$ 约束不含 @,分隔符无歧义;使用 rsplit('@', 1) 解析
  • 指定 qualifier 时强制重下:避免使用本地旧版本目录
  • URL 编码qualifierurllib.parse.quote(..., safe='') 编码,确保 RAM 签名正确
  • 空 qualifier 容错"name@" 视为不指定版本;"@v1.0.0"ValueError

内部重构

  • SkillLoader.__init__ 参数 remote_skill_names: List[str]remote_skills: List[Tuple[str, Optional[str]]],以承载每个 skill 的独立版本号
  • 经全量代码扫描确认无外部调用方使用 remote_skill_names,所以此变更实际零影响
  • 新增模块私有函数 _parse_skill_qualifier() 用于解析 "name@qualifier" 语法

Compatibility

调用形式 改动前 改动后
tool.download_skill() ✅ 完全兼容
skill_tools("name") ✅ 完全兼容
skill_tools(["a", "b"]) ✅ 完全兼容
skill_tools(tool) ✅ 完全兼容
AGENTRUN_SKILL_NAMES="a,b" ✅ 完全兼容
tool.download_skill(qualifier="v1.0.0") ��� ✅ 新支持
skill_tools("name@v1.0.0") ✅ 新支持
AGENTRUN_SKILL_NAMES="a@v1.0.0,b" ✅ 新支持

Test Plan

  • 单元测试 tests/unittests/integration/test_skill_loader.py:新增 12 个测试覆盖 _parse_skill_qualifierSkillLoader qualifier 处理、skill_tools 各种入参形式
  • 单元测试 tests/unittests/tool/test_tool.py:新增 3 个测试覆盖 _get_skill_download_url 的 qualifier URL 生成与 URL 编码
  • 全量测试通过:323 passed
  • mypy 类型检查通过:375 source files, no issues
  • 同步 make codegen 重新生成 agentrun/tool/tool.py

Related

  • 后端实现:funagent-core Skill 版本管理服务(PublishVersion / ListVersions / GetVersionByQualifier)
  • 数据面下载端点:GET /tools/{name}/download?qualifier={version}
  • 跨仓库消费链路:BFF (Java) → AgentRun Core (Go) → Agent SDK (Python,本 PR)
Add `qualifier` parameter to `Tool.download_skill()` and
`download_skill_async()` so callers can request a specific skill
version (e.g. "v1.0.0", "default", "LATEST") from the data plane
download endpoint.

`skill_tools()` accepts the same version semantics via the
"name@qualifier" string syntax (for str/list inputs) or the
`qualifier=` keyword (for ToolResource inputs); each list element
can specify its own version independently. Specifying a qualifier
forces re-download to avoid serving a stale local copy.

`SkillLoader` is refactored internally to carry (name, qualifier)
tuples; the legacy `remote_skill_names` parameter is replaced by
`remote_skills`. Code scans confirm no external caller used the
legacy parameter, so this is backward compatible in practice.

Signed-off-by: daoxun.yds <daoxun.yds@alibaba-inc.com>
yuyushui66 and others added 2 commits July 15, 2026 19:08
- Add _validate_skill_qualifier: client-side fail-fast for skill version
  qualifiers (LATEST case-insensitive or strict SemVer vX.Y.Z), rejecting
  retired values like "default" instead of round-tripping to the backend.
  Uses \Z anchor to match backend Go's $ (rejects trailing newline).
- Add .skill_version marker so version switches (pinned<->LATEST, pinned
  version changes) trigger re-download while matching versions reuse the
  local copy; dotfile is hidden from skill scanning.
- Make skill parsing and download per-entry tolerant: one invalid qualifier
  or failed download is logged and skipped without aborting the whole batch.
- Update docstrings from "default" to "LATEST" wording and add tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: daoxun.yds <daoxun.yds@alibaba-inc.com>
…_skill args

- Normalize qualifier to the canonical "LATEST" in _get_skill_download_url
  before building the URL, so the value sent to the backend agrees with the
  local .skill_version marker (skill_loader._canonical_qualifier) regardless
  of input casing.
- Reorder download_skill / download_skill_async params to (target_dir, config,
  qualifier) and sync the docstring arg order.
- Update tests to assert all LATEST casings produce the canonical URL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: daoxun.yds <daoxun.yds@alibaba-inc.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant