Extension Attributes¶
@extension_attr 把扩展的元数据声明在入口函数上,框架据此做版本门控、数据目录分版与 CLI 注册。
from xun import ExtensionContext, extension_attr
@extension_attr(
api_min_version="1.4.0", # 需要的最低 xun 版本
api_max_version="1.9.9", # 需要的最高 xun 版本(含)
data_version="2", # 数据布局版本
cli=(build_parser(), run), # 交给 `xune <名字>` 的解析器与处理函数
)
def setup_extension(ctx: ExtensionContext) -> None: ...
四个参数全可省略;装饰器返回原函数,元数据挂在函数属性 __xun_extension_attr 上。
版本门¶
| 参数 | 语义 |
|---|---|
api_min_version |
当前版本低于它 → 跳过 |
api_max_version |
当前版本高于它 → 跳过 |
比较只看数字核心:1.2rc3 与 1.2 等价,1.4 与 1.4.0 等价(短的补零),
后缀(dev、rc、post)不参与比较。区间两端都是闭区间。
被门挡下时状态是 skipped 而不是 failed,reason 形如
requires xun >= 1.4.0, running 1.3.0,在 /extensions 里能看到。
源码运行时不做版本检查
xun_version() 读的是包元数据(importlib.metadata.version("xun-agent")),
源码直接跑(未安装发行版)时返回 None,此时版本检查直接通过。
所以本地开发时不会因为版本声明被跳过,装了包之后才会真正生效。
data_version¶
data_version 不是「数据内容的版本」,而是目录布局的版本:声明后数据目录多一层 data_v_<版本>。
| 声明 | 实际目录 |
|---|---|
| 未声明 | $XUN_HOME/extension_data/<扩展名>/ |
data_version="2" |
$XUN_HOME/extension_data/<扩展名>/data_v_2/ |
- 取值必须是单个安全路径段:
\w[\w.+-]*,不能以点开头、不能带路径分隔符,否则构造ExtensionAttr时即报错。 - 提高版本等于「从零开始」:旧目录不会被删除或迁移,需要自己搬。
extension_data_dir(name, data_version)是同一个规则的公开版本, 外部工具(比如xune的 CLI)可以据此在不进入扩展上下文的情况下定位数据目录。
cli¶
cli=(parser, handler):parser 是 argparse.ArgumentParser,handler 接收解析后的
Namespace,返回 int 即作为进程退出码。由 xune <名字> 运行,详见
扩展 CLI 入口 xune。
ExtensionContext¶
setup_extension(ctx) 只拿到这一个对象,它每次 initialize() 都是新的:
| 成员 | 说明 |
|---|---|
ctx.agent |
尚未初始化的 Agent,扩展的全部作用点都在这里 |
ctx.name |
扩展名,也是 extension_settings 与数据目录用的键 |
ctx.settings |
agent.config.extension_settings[ctx.name],未配置时为 {};值已经过环境变量替换 |
ctx.data_dir(_create=True) |
私有数据目录(按 data_version 分层),默认顺带创建;_create=False 只做路径解析不落盘(测试用) |
{
"extension_settings": {
"my-extension": {
"endpoint": "${XUN_MY_ENDPOINT}",
"verbose": true
}
}
}
def setup_extension(ctx: ExtensionContext) -> None:
endpoint = ctx.settings.get("endpoint", "")
cache = ctx.data_dir() / "cache.json"
状态一览¶
/extensions(以及 Web 上的 ShowExtensionsEvent)按扩展列出:
| 字段 | 来源 |
|---|---|
| 名称 | 文件名或目录名 |
| 描述 | 入口函数的 docstring |
| 路径 | 源文件路径 |
| 状态 | uninitialized / loaded / skipped / failed |
| 原因 | skipped 与 failed 时的说明 |
程序内取同样的数据:ExtensionLoader.infos();只要成功导入的:imported()。
三个内置扩展的声明¶
| 扩展 | 声明 |
|---|---|
mcp |
api_min_version="1.3.0" |
skills |
api_min_version="1.4.0" |
stat |
api_min_version="1.4.0", data_version=DATA_VERSION, cli=(build_parser(), cli.run) |
抄一个最接近的改成自己的,通常比从零写更快。