跳转至

配置体系

设计目标

插件有大量可调参数:并发上限、权限名单、MCP 服务器、看板条数、润色开关。这些参数散落在各功能模块里,如果每个模块各自读配置,用户要改一处行为就得翻多个文件。配置体系要解决的就是这个问题:把全部可调项收拢到一个地方,统一声明、统一校验、统一暴露。

设计目标有三条:

  • 开箱即用。所有配置项都有默认值,Runner 启动时自动生成 config.toml,用户不编辑任何文件也能跑起来。
  • 强类型校验。配置错误在加载时暴露,而不是等运行时才炸。字段类型由 Pydantic 保证,插件内部拿到的是校验后的强类型对象。
  • WebUI 可编辑。MaiBot WebUI 根据配置模型自动生成表单,用户改配置不用手写 TOML。

设计方案

Pydantic 数据模型

配置模型全部定义在 config.py,共 13 个 Pydantic 类,分三层:

  • 11 个配置节类,对应 config.toml 的 11 个节:PluginSection(config.py:32)、PermissionConfig(:56)、TaskConfig(:109)、PlannerBoardConfig(:153)、PolishConfig(:184)、SplitterConfig(:201)、SendConfig(:238)、MCPConfig(:324)、SearchConfig(:393)、SubAgentConfig(:410)、ShellConfig(:456)。
  • 1 个嵌套模型 MCPServerConfig(config.py:256),描述单个 MCP 服务器,作为 MCPConfig.servers 列表的元素。
  • 1 个根模型 MaibotAgentConfig(config.py:493),聚合上述 11 节,是插件对外声明的完整配置。

每个类继承 maibot_sdk.PluginConfigBase。字段用 Field(default=..., description=...) 声明默认值和中文描述,json_schema_extra 提供 WebUI 表单的中文 label / hint(无 label 时 WebUI 回退显示英文字段名),__ui_label__ 提供 WebUI 表单的分组名。Literal[...] 类型(如 transport)会让 WebUI 渲染成下拉框。

config.toml 生成与校验

plugin.py:68MaibotAgentConfig 声明为插件的 config_model。Runner 启动时读取该模型,做三件事:

  1. config.toml 不存在,用模型默认值补齐生成;
  2. 校验已有文件的字段类型和结构;
  3. 把字段的 description__ui_label__ 暴露给 WebUI 生成表单。

插件内部通过 self.config 访问校验后的 MaibotAgentConfig 实例,字段类型由 Pydantic 保证。

热更新

配置变更无需重启插件。SDK 在调用 on_config_update(plugin.py:94)前已刷新 plugin.config,插件侧由 apply_config_update(lifecycle.py:161-217)把新值传播到运行时组件:

  1. 重建 PermissionResolver,权限变更立即生效;
  2. scheduler.update_config 更新并发上限与超时参数;
  3. task_manager.update_config 刷新配置引用;
  4. reload_mcp_if_changed 按需重启 MCP 客户端;
  5. 重建 PlannerBoard,清空 hash 去重状态。

任一步失败只记日志,不向 SDK 抛出,避免影响插件整体运行。

使用与配置

13 节配置项详解

以下按 13 个配置节列出全部字段。配置键与 config.py 字段一一对应。

[plugin] — 插件

字段 类型 默认值 说明
enabled bool true 是否启用插件
config_version str "0.1.0" 配置文件版本号

[permission] — 权限

字段 类型 默认值 说明
admins list[str] [] 管理员列表(按人),格式 platform:user_id
admin_groups list[str] [] 管理群列表(按群),格式 platform:group:group_id
users list[str] [] 用户列表(按人),格式 platform:user_id
user_groups list[str] [] 用户群列表(按群),格式 platform:group:group_id
admin_in_group_chats bool false 按人配置的 admin 在群聊中是否生效(私聊无条件生效)

权限判定顺序:admin(人/群)> user(人/群)> guest(未匹配)。详见 权限模型

[task] — 任务

字段 类型 默认值 说明
max_concurrent_tasks int 4 并发任务上限,超出部分按优先级排队
max_runtime_min int 0 agent 任务总时长兜底(分钟),0 = 不限
default_timeout_min int 10 ask_user 无回复挂起等待时间(分钟),已声明但当前未执行
persist_history bool true 是否持久化完整任务历史(当前实现始终持久化,未读取该开关)

scheduled 状态任务创建不受并发限制,但触发运行时仍计入并发计数。详见 调度器

[planner_board] — Planner 看板

字段 类型 默认值 说明
enabled bool true 是否向 Planner 注入插件简介与待办看板
max_waiting int 5 待用户回复任务条数上限(等待最久的优先展示)

看板只推送「需要 Planner 主动介入」的待办(waiting_input),不再注入运行中/定时/已完成等状态快照;每会话首次请求还会注入一次插件能力简介。详见 Planner 看板

[polish] — 润色

字段 类型 默认值 说明
use_jargon bool true 润色时机械匹配黑话(复刻 MaiBot jargon_context_matcher

其他润色参数(消息条数、黑话条数上限等)直接跟随 MaiBot 全局配置,不提供插件级覆盖。

[splitter] — 回复分割

字段 类型 默认值 说明
enable bool true 是否把长回复拆成多条消息发送(复刻 MaiBot response_splitter 思路的确定性版本)
max_length int 1000 单条消息目标最大长度(字符),无标点的超长句会被硬切(ge=50
max_messages int 5 一次回复最多拆成几条消息,超过时尾部合并进最后一条(ge=1

分割在润色之后进行(ReplySender_split),两级策略确定性切分,保留原文不丢内容:含换行时按行分割为主(行是打包的基本单元,段边界只在行边界,仅当单行超过 max_length 时才在行内按句号切分),无换行(单段长文)时整段按句号分割;所有发送路径(instant 任务、agent 完成回复、send_message 工具、失败通知、命令回复)统一跟随本配置生效,不再提供按消息覆盖参数。详见 回复润色

[send] — 发送

字段 类型 默认值 说明
max_retries int 3 消息发送最大重试次数(指数退避 1s→2s),超过后放弃发送并抛异常(ge=1

[mcp] — MCP

字段 类型 默认值 说明
enabled bool true 是否启用 MCP 工具
fetch_enabled bool true 是否启用内置 fetch MCP 服务器
fetch_user_agent str 浏览器 UA(Chrome/126 Windows) 内置 fetch 出站请求的 User-Agent;默认浏览器 UA 规避反爬验证码,留空退回 mcp-server-fetch 自带 UA
fetch_block_internal bool true 是否拦截内置 fetch 抓取内网/云元数据地址(SSRF 缓解,默认开启):拦截回环、私有网段、链路本地(含 169.254.169.254)、CGNAT 等地址,域名先解析再逐 IP 判定;内网文档抓取场景需设为 false
exa_enabled bool true 是否启用内置 exa.ai MCP 服务器
servers list[MCPServerConfig] [](自定义追加;内置 exa/fetch 预设见 08-mcp.md) MCP 服务器列表

插件内置 exa(远程 web 搜索,http)与 fetch(本地网页抓取,stdio)两个预设 MCP 服务器, 由 fetch_enabled / exa_enabled 开关控制,开箱即用;servers 默认空列表,仅用于自定义 追加,与预设同名的条目会替代预设连接。详见 MCP 工具集成servers 列表中的 每个元素为 MCPServerConfig(config.py 的 MCPServerConfig),字段如下:

字段 类型 默认值 说明
name str "" MCP 服务器名称(标识用)
transport Literal["stdio", "http", "sse"] "stdio" 传输协议
command str "" 启动命令(transport="stdio" 时使用)
args list[str] [] 命令行参数列表
env dict[str, str] {} 环境变量键值对
url str "" 服务器 URL(transport="http" / "sse" 时使用)
headers dict[str, str] {} HTTP 请求头

MCP 工具进入 Agent 工具集的 Discoverable 层,按权限过滤。不支持运行时动态增删服务器。详见 MCP 工具集成

字段 类型 默认值 说明
max_results int 20 search_users 返回条数上限

[subagent] — 子 Agent

字段 类型 默认值 说明
enabled bool true 是否启用子 Agent 工具(ask_subagent / ask_subagents),false 时两个工具都不注册
max_rounds int 10 子 Agent 最大执行轮数(ge=1
max_result_chars int 8000 子 Agent 答案最大字符数,超长截断
max_parallel_subagents int 3 ask_subagents 单次批量派发的子 Agent 数量上限(ge=1

子 Agent 由主 Agent 通过工具调用触发,结果回传主 Agent 上下文继续判断;配置经 config_getter 热更新,无需重注册。详见 子 Agent

[plugin_api] — 跨插件 API 工具

字段 类型 默认值 说明
allowlist list[str] [] 允许包装为 Agent 工具(call_*)的插件 API 名;留空(默认)不暴露任何跨插件 API 工具

Agent 侧跨插件 API 工具采用显式允许名单:仅名单内的插件 API 会被包装为 call_{api} 工具,且最低角色固定为 ADMIN(不可配置降低);本插件自身 6 个 任务端点(create / list / get / cancel / inject / history)永远排除在包装 之外——Agent 操作任务请用原生 owner 隔离工具(list_my_tasks / create_subtask / inject_task / cancel_task)。详见 跨插件 API权限模型

[shell] — 命令执行

字段 类型 默认值 说明
enabled bool true 是否注册 run_command 命令执行工具;falseTaskManager.setup() 不注册
timeout_seconds int 60 命令默认超时(秒,ge=1);超时后强制终止整个进程树
max_output_chars int 8000 stdout/stderr 单侧最大返回字符数(ge=100),超长截断

run_command 仅对 admin 可见(min_role + role_provider 双重门控),子 Agent 允许集排除该工具;配置经 config_getter 热更新,timeout_seconds / max_output_chars 修改后无需重注册立即生效。详见 命令执行

已知限制

  • default_timeout_min 已配置但未执行(config.py:133)。TaskConfig.default_timeout_min 声明了 ask_user 无回复挂起等待时间的意图,但调度器未读取该值:waiting_input 状态的任务不因超时而自动取消或推进,而是永久挂起直到用户回复或手动取消。
  • 跨插件 API 信任模型(无身份时按 ADMIN)。SDK 的 api.call 通道不携带调用方身份,6 个跨插件端点对无身份参数的调用按 ADMIN 执行,owner 校验被有意旁路——跨插件调用面向受信任插件。Agent 侧 call_* 工具已收紧:显式允许名单(默认空)+ 最低角色 ADMIN + 自身端点排除,见 [plugin_api] 配置节与 10-cross-plugin-api