04 - 工具系统¶
工具注册机制¶
工具统一通过 Tool 类注册到全局 toolMap(以函数名为键)。注册入口是 src/tool/tool.ts 的 Tool.registerTool(),由 src/index.ts 在启动时调用。
Tool 的关键属性:
| 属性 | 说明 |
|---|---|
toolInfo |
OpenAI function calling 格式的描述(name/description/parameters JSON Schema) |
solve |
工具实际执行函数;扩展指令工具使用 run_ext_command,由 src/tool/extension_executor.ts 现场构造 CmdArgs 后调用扩展 solve |
sessionType |
适用会话类型:'any'(默认)、'group'、'user' |
callBack |
是否回调智能体(当前统一为 true) |
sensitive |
敏感工具标记(发消息/禁言/改名等),执行日志显著记录 |
group |
来源分组:new Tool(info, sensitive?, group?, platforms?)。内置工具不传(来源显示为「内置」);技能工具='技能';知识库工具='知识库';MCP 工具=所属服务器名 |
category |
内置工具细分分类(仅 group 为空时赋值,由 Tool.withCategory(分类, 注册批次) 在注册时注入;缺省兜底 '其他'):基础调度/指令/定时/触发/记忆/图片/多媒体/OB11/资源/属性/原文检索/上下文编辑/黑名单/网页/公开会话/子代理,外部插件注册的工具='外部插件'。仅用于 .ai tool 工具组概览与组开关、AI 侧组头显示,不改变 group 的来源语义 |
platforms |
平台白名单(来自 JSON 条目的 platform:MCP 服务器/技能/知识库条目),缺省/空 = 所有平台;工具发现、列表与调用均按当前平台过滤 |
solve(ctx, msg, session, args) |
工具实现,返回字符串作为给 AI 的结果 |
run_ext_command 在插件内本地直接调用扩展的 solve(构造独立的 CmdArgs,不依赖最近一次真实指令,也无需 MCP/中间件);run_core_command 通过 aiplugin4-backends/ob11-core-bridge 的 /plugin WebSocket 注入标准 OB11 假消息执行核心指令。run_ext_command 的扩展名分为硬编码的 builtin(fun/story/coc7/deck/dnd5e/exp/log/reply)与 non_builtin;核心指令统一使用虚拟扩展名 core,例如 core|ext。指令前缀由「工具 → 指令前缀」配置,默认 .。两条路径都复用多消息收集器(空闲窗口 + 最大消息数 + 超时结束)。两种工具均支持 trigger 指定触发对象、at 指定 @ 对象;触发对象会替换本地临时 ctx/msg 或 OB11 假消息的 sender,@ 对象会写入消息段。
调用流程与校验链¶
Tool.handleToolCall 按顺序校验:
- 函数是否已注册(
toolMap)。 - 会话工具开关
session.toolState[name]是否开启。 - 工具参数是否完整、扩展指令是否在白名单中(
core|ext为例外发现入口)。 sessionType是否匹配当前消息类型。- 参数 JSON 是否可解析(失败时用
fixJsonString修复)。 - 必需参数是否齐全;
Tool.validateArgs按 JSON Schema 的 type 做轻量校验。 - 调用
solve,整体受请求超时时限约束。 - 平台白名单:可用工具列表(list_tools/search_tools/.ai tool/schema 注入)均按
Tool.platforms过滤;call_tool额外显式校验来源分组与平台(错误带「来源 X 的平台限制」);平台受限的 MCP 工具即使绕过发现层被直接点名,其 solve 守卫也会返回「…工具在当前平台不可用」。
ToolRunner(src/tool/runner.ts)统一两条执行路径:
executeFunctionCalls:函数调用模式,直接执行模型返回的tool_calls。executePromptCalls:提示词工程模式,解析 ```function 代码块内的 JSON 数组再执行。- 两者都会记录审计日志(
[tool] session=... call=... content=...)。
防失控限制:
允许连续调用函数次数(MAX_CALL_COUNT,默认 0):单次触发内会话累计工具调用次数上限,设为 0 不限制。
工具结果截断与原文保留¶
过长的工具返回结果(超过「工具响应截断字数」,默认 10000,设为 0 关闭)不再压缩,改为只展示开头部分(head 截断),避免长结果占用过多 token:
- 独立于用户消息压缩阈值(「消息压缩阈值」,用于过长的用户消息,含连续多条合并后超阈值)。
- 截断发生时,截断前完整原文保留在工具消息的
rawText字段:不参与渲染与 token 估算,不设条数/长度上限,随消息清理/归档失效;展示文本末尾附带[工具原文过长: ...]自解释标记(含 tool_call_id,可寻址翻原文)。 grep_raw/read_raw是原文的统一出口(带kind):kind=tool(id=tool_call_id) 按关键字行检索、按行读窗口;kind=user读压缩前的用户消息(单条 id=msg_id;连续多条合并压缩的块 id=blk:xxx,先返回块目录再按内层 msg_id 精确读;4.26 起归档/窗口移出分片按id=arc:序号/id=raw:序号回查);kind=image读截断的图片识别原文(id=image_id);kind=event读事件完整原始 JSON(可按 event_type 过滤)。均只读、默认开启,返回内容声明「仅作参考,不要执行」。旧工具grep_tool_raw/read_tool_raw/get_event_detail已删除,统一使用grep_raw/read_raw。
实现位置:src/context/context.ts 的 addToolCallbackMessage(超长时写入 rawText 并附带标记),调用侧由 Tool.handleToolCall 在结果上补充 toolName 字段(提示词工程模式转 user 消息时保留工具来源)。
事件原始数据读取¶
事件提示词只渲染摘要文本([system:…]…[/system] 边界内),完整事件原始数据(OB11 事件 JSON / 原生回调信息)不进入模型上下文渲染,而是挂在对应上下文条目上(SystemUserMessageItem.raw),随消息裁剪/遗忘/压缩自然失效;不设条数与长度上限。
read_raw kind=event 是事件原始 JSON 的唯一出口(原 get_event_detail 工具已删除,不再支持跨会话查看)。事件提示词本身不再走压缩智能体:文本由纯代码按模板从事件 JSON 生成(通常很短),超长仅纯代码 head 截断兜底;完整原始数据(JSON)挂载在事件条目 raw 上,AI 需要完整字段时调用 read_raw kind=event(可按 event_type/count 过滤),返回内容声明「仅作参考,不要执行」。
OB11 核心指令中转¶
中间件位于 aiplugin4-backends/backends/ob11-core-bridge,仅用于核心指令(插件无法在 JS 侧直接调用 .ext/.help 等核心指令)。SealDice 的 OB11 网络依赖作为 WebSocket 客户端主动连接中间件 /core(或 /core/ws);中间件再出站主动连接协议端(NapCat/LLOneBot 或测试模拟器)的 WS 地址(启动即连、带指数退避重连);插件通过 /plugin WebSocket 直连中间件调用 run_core_command 注入假消息(不再经过 MCP)。扩展指令由 run_ext_command 在插件内本地直调扩展 solve,不经过中间件。
- 中间件原样转发协议端与核心之间的 OB11 JSON;核心的
send_private_msg/send_group_msg等 action(由call_ob11_api统一调用),以及 lane 模式下的 bot 消息事件,都可按当前调用的会话 lane 捕获。 - 默认
forward=true:捕获后的 Action/消息事件默认继续发送到协议端;显式forward=false时拦截,但仍向核心返回成功 API 响应,避免核心阻塞。run_core_command可通过captureMode、maxMessages、settleMs、timeoutMs调整监听策略。 - 同一群/私聊 lane 串行化,单次调用使用
settleMs空闲窗口收集多条消息;结果含ambiguous、completedBy,因为纯 OB11 没有标准 trace_id,无法保证跨同 lane 的绝对关联。 run_core_command的command=ext直接调用核心.ext,用于查看所有扩展名称,不需要在配置中维护扩展列表。run_ext_command的action=list仅能列出白名单 + 内置扩展 + 插件自身指令,完整扩展列表以run_core_command执行ext为准。
中间件配置:AIPLUGIN4_BACKEND_HOST(默认 0.0.0.0)、AIPLUGIN4_BACKEND_PORT(默认 46880)、AIPLUGIN4_BRIDGE_PLUGIN_TOKEN(插件端 WS 鉴权 token)、AIPLUGIN4_BRIDGE_CORE_TOKEN(核心端鉴权)、AIPLUGIN4_BRIDGE_PROTOCOL_URL / AIPLUGIN4_BRIDGE_PROTOCOL_TOKEN(协议端地址与 token,中间件出站主动连接;也可在 WebUI「⚙ 配置」填写,重启生效),以及可选的 AIPLUGIN4_BRIDGE_CORE_PATH(默认 /core,同时接受 /core/ws)、AIPLUGIN4_BRIDGE_PLUGIN_PATH(默认 /plugin)。插件在「后端 → 后端配置」的 backends.ob11-core-bridge 中配置(默认 ws://127.0.0.1:46880/plugin,可选 token);SealDice 侧的 OB11 正向 WS 配置填 /core 地址。
内置工具清单¶
以下工具名来自 src/tool/tools/ 各注册函数(基于当前代码)。「工具组」列即 category(内置分类),可直接 .ai tool <工具组> 查明细、.ai tool on/off <工具组> 整组开关;技能/知识库/MCP 只有来源分组(group),技能与知识库不参与工具组维度:
| 工具组(category) | 工具 |
|---|---|
| 基础调度 | list_tools(按工具组列出当前平台工具)、search_tools(按名称/关键词/工具组发现并取参数,详情带来源)、list_mcps(列出当前平台可用 MCP 服务器及工具开关)、call_tool(统一执行,校验来源与平台) |
| 指令 | run_ext_command、run_core_command(调用 SealDice 扩展与核心指令) |
| 定时 | set_timer、show_timer_list、cancel_timer |
| 触发 | set_trigger_condition |
| 记忆 | memory_add、memory_update、memory_delete、memory_recall、memory_clear、memory_reflect、memory_consolidate、memory_mm_list、memory_mm_view、memory_mm_create、memory_mm_refresh、memory_mm_delete(可按 model_id 或 question 删除) |
| 图片 | image_to_text、text_to_image(提交生图任务,立即返回任务号)、meme_list、get_meme_info、meme_generator |
| 多媒体 | media_tasks(查看/取消本会话的语音与图片生成任务队列:list 按状态筛选,cancel 取消未完成的任务) |
| OB11 | call_ob11_api(通过 action 调用消息、查询、管理、文件和合并转发 API;群资料/精华消息等统一传入对应 action)、resolve_special_id(还原上下文短 ID/句柄为原始字段,用于对接协议 API) |
| 资源 | list_resources、get_resource_path(本地资源查询);generate_audio(提交语音生成任务,立即返回任务号;传 path 时同步解析本地/MCP 音频资源)、search_music(返回 music 消息段,不直接发送) |
| 属性 | attr_get、attr_set |
| 原文检索 | grep_raw、read_raw(按 kind 检索/读取被截断或压缩前保留的完整原文,kind=event 读事件原始 JSON;旧 grep_tool_raw/read_tool_raw 已删除) |
| 上下文编辑 | context_edit_list(按序号定位任意会话上下文条目,支持 role/keyword/时间过滤)、context_edit_replace(按 scope 批量替换正文文本:纯文本字面量/全局正则、空串=删除、原文副本同步、持久化;敏感工具、默认开启,不可自动回滚) |
| 黑名单 | suggest_block(AI 建议拉黑,带冷却;默认需骰主用 .ai block 确认,可在工具配置关闭)、unblock_user、get_block_list |
| 网页 | web_search(多后端搜索:支持 allowed/blocked domains、time_range、detail,失败自动回退)、web_fetch(抓取网页正文,start_index 续读);论坛:forum_get_posts、forum_get_post_detail、forum_search、forum_create_post、forum_manage_comment、forum_get_activity、forum_manage_post |
| 公开会话 | pub_read(分级浏览公开会话目录 / 读取其他会话上下文只读快照)、pub_send(以目标会话自己的机器人账号身份外发:QQ 系富媒体 / 其他平台纯文本) |
| 子代理 | subagent(spawn 委派)、subagent_fork(fork 委派)、send_message、interrupt_agent、list_agents(可续跑控制)、job_list、job_output、job_kill(后台 job) |
| 外部插件 | 其他海豹插件经 globalThis.aiplugin4.registerTool 注册的工具 |
| — (来源分组=技能) | use_skill、skill_list |
| — (来源分组=知识库) | knowledge_search、knowledge_read、knowledge_list、knowledge_docs(只读检索,范围 = 当前平台可用 + 本会话开启的库;内容由「知识库」配置维护) |
| — (来源分组=MCP 服务器名) | 远端工具名(render_markdown/render_html 来自默认服务器 md-html-render) |
注:
text_to_image支持可选image参数进行以图生图。参数可传图片 ID、user_avatar:...、group_avatar:...、图片 URL、data URL 或 base64;模型配置需要在请求体中使用{image}、{image_url}或{image_base64}占位符。注:语音合成与文生图(4.24.0 起内置,在「模型」页模型配置里给模型声明
kind: "tts"/"gen"即进入tts/image-generation用途候选)都是异步任务:generate_audio/text_to_image提交后先等一段同步窗口(「工具 → 媒体生成同步等待秒数」,默认 5 秒)——窗口内就生成完则当场把结果返回给 AI(图片直接给[img:图片ID],语音给 record 段发送指引),不再走异步通知;窗口内没完成则返回任务号,生成完成时写入会话通知并尽力唤醒 AI(会话忙则通知留在队列,由本轮结束时的补触发接手;待机也不拦,因为这是用户请求的结果送达,不是主动搭话)。AI 收到通知后,语音走call_ob11_api的 record 段([audio:xxx]只认「资源」页配置的本地语音资源名,不接受生成结果的路径/URL),图片优先直接在回复里写[img:图片ID](生成的图片会注册进图片存储,Image.get可解析;系统会自动发送,非必要不要为此调用call_ob11_api)。可用参数(含默认值与范围)由该模型request里的params/body决定,会随工具描述一起给 AI,不再依赖固定的generate_audio/text_to_image硬编码参数。任务队列用media_tasks查看与取消。注:当前会话回复中发送图片优先使用
[img:图片ID];需要发送语音/视频/文件,或向指定会话/按 API 组合消息发送资源时,通过call_ob11_api的 image/record/video/file 消息段。文件区上传使用upload_group_file/upload_private_file。本地绝对路径、file://URI、MCPmcp://引用会在运行时解析,资源 ID 使用resource:资源名;需要资源实际路径/URI 时使用get_resource_path。 注:MCP 文件服务器mcp-files-exec支持把文件先导出为短时下载地址再发送。相对路径按 AI 会话隔离:相对路径与命令默认工作目录落在当前会话工作区(无会话时落共享沙箱根,即第一个沙箱根目录);跨会话或主机上的文件直接用绝对路径。会话内导出文件建议先调export_file拿下载地址,再交给call_ob11_api发送。
外部注册:
- MCP 工具:默认直接按远端
tools/list返回的工具名注册;与本地/已有工具同名时自动跳过。 - 技能工具:
use_skill、skill_list(见技能节)。
依赖说明:协议动作统一通过 call_ob11_api;当前会话回复中发送图片优先使用 [img:图片ID]。有 ob11 网络连接依赖时 action 原样透传;没有依赖时原生可完成的发送和上下文查询继续可用,其余 action 返回 OB11_DEPENDENCY_REQUIRED。
工具权限(按会话开关)¶
- 每个会话有独立的
session.tool.state(ToolState),session.toolStategetter 负责同步: 禁止调用的函数(BLOCKED):强制关闭且无法开启,且不出现在工具组视图与统计里。默认关闭的函数(DEFAULT_CLOSED):新会话默认关闭,需通过.ai tool on <name>开启。- 已删除工具(如旧版
call_subagent)的残留状态会被自动清理。 - 工具组:内置工具按
category分为 16 个能力分类,加上每台 MCP 服务器各一组(Skill/知识库不参与组维度)。分组与批量开关实现集中在src/tool/tool.ts(getToolGroups/resolveToolGroup/groupDisplay/matchesGroupFilter/groupEntries)与src/tool/tool_group.ts(setToolGroupState/formatGroupToggleReply)。 Tool.getToolGroups(session, platform)基于session.toolState聚合:只统计当前平台可用工具,自动继承BLOCKED剔除、DEFAULT_CLOSED默认与子代理toolRestriction收窄;组顺序由BUILTIN_CATEGORY_ORDER固定(内置分类在前、MCP 服务器按名在后)。setToolGroupState(session, names, enable, { skipBlocked, skipCore })供.ai tool on/off <组名>与.ai mcp on/off <服务器>共用:on跳过BLOCKED并计数,off默认跳过CORE_TOOL_NAMES(核心常驻工具,--force才一并关闭),返回{ changed, unchanged, skippedBlocked, skippedCore }供命令侧如实回报。- 工具列表/开关按工具组与当前平台呈现:
.ai tool(无参)输出组概览(组名+工具数+开/关统计),.ai tool <组名>展开组内明细,.ai tool <函数名>看详情,.ai tool all保留扁平全量视图;解析优先级为--group=<组名>> 函数名 > 组名 > 唯一包含匹配,on/off/help/call/list/all为保留字(撞名时用--group=)。技能/知识库还有独立的会话级开关(session.skillState/session.kbState,只记录被 off 的项,缺省=开启),对应管理命令.ai skill on/off、.ai kb on/off,以及按服务器的批量开关.ai mcp on/off。 - AI 侧同口径:
list_tools组头与search_tools详情的来源用Tool.groupDisplay(内置工具显示「内置·记忆」,其余为技能/知识库/MCP 服务器名);list_tools(mcp=)/search_tools(mcp=)经Tool.matchesGroupFilter支持按分类名、来源分组或组显示名过滤(mcp=内置匹配全部内置工具)。 - 子代理会话经
session.toolRestriction(allow/deny 求交)收窄继承自父会话的工具面;委派工具默认开启,受全局 BLOCKED/默认关闭与「子代理禁止调用工具」约束。 - 管理命令
.ai tool:列出/查看详情/开关/试用工具,详见 05-命令与配置。
MCP 集成(src/tool/mcp.ts)¶
- 配置项
是否启用MCP(MCP 分组,默认关闭)是 MCP 总开关;开启后才会解析MCP服务器并连接/注册 MCP 工具。 - 配置项
MCP服务器(MCP 分组)采用标准 MCP JSON:{"mcpServers":{"服务器名":{"type":"http","url":"…","headers":{…}}}},键 = 服务器名;type仅支持http/streamable-http,command(stdio)与 SSE 会跳过并记日志;platform是 aiplugin4 扩展字段([]/省略 = 所有平台)。生成器的「启用」开关只控制是否写入,关闭的服务器不会出现在 JSON 里(不写enabled字段)。插件默认空配置(不预置服务器);配置生成器「MCP」页仍保留三台示例:mcp-files-exec(platform: [];文件读写、URL 下载、命令执行,相对路径与命令工作目录按 AI 会话隔离)、md-html-render(platform: [QQ],示例限定 QQ 平台)与mcp-browser(platform: [];AI 浏览器操作:导航/点击/输入/快照/截图,按 AI 会话隔离),用户按需复制。ob11-core-bridge已改为插件直连/pluginWebSocket(见上「OB11 核心指令中转」),不在 MCP 示例中。工具名称、描述和参数 schema 均从远端tools/list自动发现(注册为敏感工具、来源分组 = 服务器名),返回内容按 MCP 标准内容块处理;run_ext_command由插件本地注册,不经 MCP。改 URL/Token 时服务器会话自动重建。MCP 会话按 AI 会话(session.sessionId)分桶:同一 AI 会话的连续浏览器操作复用同一服务端会话(保持登录/页面状态),不同 AI 会话互不干扰;空闲或超上限的会话按 LRU 回收,回收前对mcp-browser自动调用browser_close释放服务端浏览器。可通过「MCP → MCP会话空闲回收分钟 / MCP每服务器最大会话数」调整回收策略 - 平台限制:解析出的
server.platforms随工具注册为Tool.platforms;服务器 platform 与当前平台不匹配时,list_mcps隐藏整台服务器、list_tools/.ai tool/search_tools隐藏其工具、call_tool拒绝(「来源 X 的平台限制」),绕过发现层直接点名调用也由工具 solve 守卫返回「…工具在当前平台不可用」。 - 协议:Streamable HTTP 上的 JSON-RPC(
initialize→notifications/initialized→tools/list→tools/call),带Mcp-Session-Id会话头,兼容 SSE 响应。 - 远端工具默认用远端工具名注册为敏感工具,参数透传
inputSchema;返回纯文本时直接回传,返回标准 image 块或 base64 文本时保存为[img:...]并返回图片 ID。同名冲突会跳过。 mcp-browser提供browser_navigate/browser_click/browser_type/browser_snapshot/browser_take_screenshot/browser_wait_for/browser_close等工具:AI 自主决定截图时机(可先browser_wait_for等待加载完成再截图),截图以标准 image 内容块返回并注入多模态上下文。- 工具列表有 60 秒 TTL 缓存;会话失效/服务器未初始化(会话不存在/已失效/未初始化/Server not initialized)时自动重新 initialize 并重试一次。
- 管理命令
.ai mcp list/on/off/refresh:list 查看当前平台可用服务器与工具开关;on/off 按会话批量开关某服务器(或缺省全部当前平台服务器)下的工具(on 跳过「禁止调用的函数」);refresh(refreshMCP= 清空启用/服务器缓存 +registerMCPTools(force)强制重同步)使服务器增删、URL/platform 与总开关改动即时生效,无需重载 JS。 - MCP 配置修改(refresh/重载)后按服务器名重建会话并同步工具差集;删除服务器或服务器返回的工具会从注册表移除。MCP 总开关关闭时不建立连接,system prompt 也不会展示不可调用的 MCP/技能入口。
- 错误信息把 JSON-RPC 错误码映射为可读中文。
技能(Skills,src/tool/skills.ts)¶
- 配置项
技能列表(技能 分组)为 v1 JSON:skills[]的name(必填)/description/platform(可选平台白名单数组,如[QQ, DISCORD],[]/省略 = 所有平台)/content;缺失的默认技能(「录卡」)会自动补入。生成器「技能」页可导入标准SKILL.md(其他 agent 通用格式)转成 JSON。 - 注册
use_skill、skill_list两个技能工具(来源分组 = 技能);技能摘要只注入「当前平台匹配且本会话未关闭」的技能,追加到 system prompt 的「可用技能」段(两种工具模式都可见),摘要列表行按 1500 字符预算、最多 100 条、单条描述最多 200 字符截断,超出提示用skill_list查看完整技能名列表;use_skill按名称获取正文,支持offset续读超长正文,对平台受限或本会话已关闭的技能返回「技能 X 当前不可用(平台限制或已在本会话关闭,可用 .ai skill on X 开启)」。 - 技能内容支持
{{skill:名称}}引用其他技能(最大解析深度 2,循环/未开启/不存在会明确标记),单次返回上限 12000 字符(超出截断并给出续读 offset)。 - 技能配置变化会在下一条消息自动重新解析(JSON 暂时非法时保留上一份可用技能);
.ai skill refresh仍可强制重解析。技能开关按会话保存(session.skillState,只记录被.ai skill off关闭的项,缺省=开启);管理命令.ai skill list(当前平台可用技能及开关)/.ai skill on/off <名称>/.ai skill refresh。 - 默认技能只含「录卡」(Excel 角色卡录入流程,无 platform 限制);SealDice 核心/扩展指令与 OB11 API 的调用帮助已改写为默认知识库提供:「知识库配置」默认三条——
核心指令(run_core_command 逐条帮助)、扩展指令(fun/story/coc7/deck/dnd5e/log 各扩展为 # 子条目、命令为 ## 小节)、ob11-api(platform: [QQ],仅 QQ 平台可见可检索);默认白名单与 SealDice 源码中的命令表同步。