跳转到正文

配置 ​

用 dataclass 定义设置,随插件发布 config.schema.json 和不含真实秘密的 config.example.json。Host 管理每次安装的实际 config.json;示例文件不会自动成为运行配置。

声明与读取 ​

python
from dataclasses import dataclass, field
from neomega_runtime import Plugin

@dataclass
class Settings:
    greeting: str = field(default="你好", metadata={
        "title": "问候语", "description": "插件启动时写入日志的文本"
    })
    interval_seconds: int = field(default=60, metadata={
        "title": "执行间隔(秒)", "minimum": 1, "maximum": 3600
    })

class MyPlugin(Plugin):
    config_type = Settings

    async def on_validate(self, ctx):
        if not ctx.config.greeting.strip():
            raise ValueError("问候语不能为空")

    async def on_start(self, ctx):
        ctx.log.info("%s", ctx.config.greeting)

if __name__ == "__main__":
    MyPlugin().run()

ctx.config 在 on_validate 前完成加载和类型验证。文件不存在时使用 dataclass 默认值;没有默认值的必填字段仍会报错。验证阶段不会创建或重写配置文件。

支持嵌套 dataclass、字符串、整数、有限浮点数、布尔值、列表、字符串键字典及可选类型。未知字段、重复 JSON 键、非有限数及类型混用会被拒绝,true 不能充当整数。配置文件上限 256 KiB。

导出 schema ​

把下面内容另存为 export_config.py,在插件源码目录显式运行。确保 main.py 的 .run() 位于 if __name__ == "__main__" 保护下,避免导入时启动插件。

python
import json
from pathlib import Path
from neomega_runtime import schema_for_config
from main import Settings

Path("config.schema.json").write_text(
    json.dumps(schema_for_config(Settings), ensure_ascii=False, indent=2),
    encoding="utf-8",
)

config.example.json:

json
{"greeting": "你好", "interval_seconds": 60}

把 main.py、manifest.json、schema 和示例逐一加入 package.files.json。修改 Settings 后重新导出并运行 lint;lint 不会通过执行插件来判断 schema 是否与 dataclass 一致。

schema 支持类型、默认值、数组、对象、anyOf、数值上下限及 title、description、examples 等注释;这不是完整 JSON Schema 引擎。生成过程会计算 default_factory,因此不要在默认工厂里发请求或执行游戏动作。

保存与生效 ​

在拥有目标实例管理权限时,通过工具包管理配置:

sh
python3 runtime-admin.py --url "$TARGET_URL" --token-file "$TARGET_TOKEN_FILE" configure hello

向导先验证和预览,再应用。停止的插件只保存配置,不会被自动启动;运行中的插件通过重载应用。检查响应中的 saved、applied 和 reload_required,不能把“已保存”直接理解为“已生效”。

AI 自动化可按顺序使用:

sh
python3 runtime-admin.py --url "$TARGET_URL" --token-file "$TARGET_TOKEN_FILE" --json config-describe hello
python3 runtime-admin.py --url "$TARGET_URL" --token-file "$TARGET_TOKEN_FILE" --json config-get hello
python3 runtime-admin.py --url "$TARGET_URL" --token-file "$TARGET_TOKEN_FILE" --json config-plan hello --config-file candidate.json
python3 runtime-admin.py --url "$TARGET_URL" --token-file "$TARGET_TOKEN_FILE" --json config-apply hello --config-file candidate.json --expected-revision "$CONFIG_REVISION"

前三步读取描述、当前值并预览候选变更。检查 valid 和 issues 后,使用刚读到的 revision 应用已获准的配置。发生冲突时重新读取并合并,不直接用新 revision 覆盖他人的改动。

revision 表示已保存内容版本,active_revision 表示 Host 观察到的生效版本。直接编辑磁盘文件不会即时更新 ctx.config。普通业务状态使用 ctx.storage,不要让插件在验证回调中改写管理员配置。

密钥引用 ​

配置字段标记 secret: True,普通 JSON 仅保存 secret:cloud_api 这样的引用:

python
@dataclass
class CloudSettings:
    api_key: str = field(metadata={"title": "云端密钥", "secret": True})

# 在已设置 config_type = CloudSettings 的回调内读取:
# key = ctx.secrets.get(ctx.config.api_key)

该片段复用前面的 dataclass 和 field 导入。引用名需匹配 secret:[A-Za-z][A-Za-z0-9_-]{0,63},默认值和示例也必须使用引用。ctx.secrets.get(reference) -> str 按需读取,缺失或无效时抛出 SecretError;不要记录其返回值。

管理员使用 secret-set hello --secret-name cloud_api 隐藏输入,或指定 --secret-file 读取私有文件。secret-status hello 只报告是否已配置。读取时使用最新值;插件若缓存凭据,需要重载才能切换。插件是可信代码,私有文件权限不等于恶意插件沙箱。

配置错误与升级 ​

ConfigError(code, path="config", *, expected=None, hint=None, line=None, column=None) 提供安全字段 code、path、expected、hint、line、column。as_dict() 返回非 None 字段。按定位修正候选文件;自定义业务验证也不要在异常文字中携带密钥。

新增带默认值的字段通常能读取旧配置;重命名、删除或收紧类型需要提供明确迁移步骤。保存前验证失败保留旧配置和旧进程;保存后重载失败可能出现 saved=true, applied=false,此时检查日志与运行状态,不承诺业务数据自动回滚。具体故障处理见错误页。

配置与密钥函数 ​

普通插件设置 Plugin.config_type 即可自动加载;离线校验工具可使用以下纯读取入口:

函数 / 类返回与限制
neomega_runtime.config.load_config(kind: type[T], path: Path) -> T读取文件、应用默认值并创建 dataclass;文件缺失等同 {},不写文件。
neomega_runtime.config_schema.schema_for_config(kind)返回声明对应的 schema 字典;也从 neomega_runtime 导出。
neomega_runtime.config_schema.check_config_schema(schema)检查支持的 schema 子集,成功返回 None,非法声明抛 ConfigError。
neomega_runtime.config_schema.validate_config(schema, value)返回加入默认值后的独立 JSON 值;只验证秘密引用,不读取秘密。
neomega_runtime.secrets.Secrets(data_dir: Path)get(reference: str) -> str 读取该数据目录下的秘密;普通插件用 ctx.secrets。

schema 限制为至多 32 层、anyOf 每处 1–16 分支;递归 dataclass、不支持的关键字或不符合声明的默认值/示例会被拒绝。metadata={"secret": True} 仅用于字符串并导出为 x-secret: true,不是普通文本密码输入。

Secrets.get 要求秘密目录及文件不向组和其他用户开放,文件为普通文件,内容为 1–65536 字节 UTF-8。返回值原样保留换行;需要无换行的令牌应由管理员在保存时保证。读取无效引用、缺失、权限不符或编码错误均抛 SecretError,异常不含秘密值或文件路径。

Neomega · 使用、开发与参考文档