工具体系
模型每回合拿到的工具从哪来、怎样按模型能力与 Agent 配置层层过滤、结果怎样分层截断,以及不在工具清单里的 mcode-tools。
模型在每个回合拿到的是一份临时拼出来的工具清单。原料有四类:从 pi coding-agent 借来的 read、write、edit、bash,MiniMax 在 packages/agent-tools 里自己写的其余本地工具,MCP 服务暴露的工具,以及扩展在装配时追加的工具。拼好之后还要按模型能力、Agent 配置和子 Agent 角色逐层过滤,才交给 pi 的 Agent 循环。
本篇只讲“清单怎么来、怎么剪、结果怎么收”。每个工具的具体行为见文件与 Shell 工具,调用前的放行判断见权限模式与规则。
怎么用
工具注册表不对用户开放,能影响清单的是几处配置:
| 入口 | 作用 | 出处 |
|---|---|---|
config.yaml 的 agents.default 段 | 给默认 Agent 定能力上限:tools 从 12 个内置工具 ID 里挑,builtinTools 挑内置 Matrix 媒体工具,features 开关 mavis、delegation、webSearch | packages/config/src/agent-capabilities.ts:1、:83 |
自定义 Agent 的 tools、disallowedTools、mcpServers | 按名单保留或屏蔽工具与 MCP 服务,省略即继承上限 | packages/local-runtime-v2/src/service/agent/contracts.ts:181 |
mcpToolSearch 段、MAVIS_MCP_TOOL_SEARCH_* 环境变量 | MCP 工具是否改为按需检索 | packages/local-runtime-v2/src/service/turn-system/agent-host/assembly/local-turn-tool-catalog.ts:480 |
toolResultCompaction.maxInlineKiB | 单条工具结果留在上下文里的上限,默认 64KiB | packages/config/src/tool-result-compaction-config.ts:20 |
beta.mcodeTools | 是否把 mcode-tools 放上 bash 的 PATH | packages/config/src/config.ts:494 |
MAVIS_LOCAL_RUNTIME_DISABLE_TOOLS=1 | 一个工具都不给 | packages/local-runtime-v2/src/service/turn-system/production-composition.ts:386 |
自定义 Agent 的写法见 Agent 服务。
源码分布
| 位置 | 内容 | 在本地 CLI 里的角色 |
|---|---|---|
third_party/pi-mono/packages/coding-agent/src/core/tools | read、bash、edit、write、grep、find、ls 七个工具 | 只借用前四个的实现 |
packages/agent-core/src/tools | ToolDefinition、ToolImpl、RuntimeTool 等契约 | 工具协议 |
packages/agent-tools/src/desktop | Local* 工具类与 buildLocalToolRegistry | 模型实际调用的本地工具 |
packages/agent-tools/src/shared | 读取守卫、replace_all、ripgrep 排除规则等 | 供 desktop 包装使用;注释说云端包装也用,但那部分不在公开仓库 |
packages/agent-tools/src/mcp-disclosure | tool_search、mcp_invoke 与检索索引 | MCP 渐进暴露 |
packages/agent-tools/src/cloud | 只有 matrix-tools:图像、视频、语音工具的定义与客户端 | 内置 Matrix MCP 子进程的实现,公开构建未启用 |
packages/agent-tools/src/plugin-hooks | 兼容 Claude Code、Codex 格式的工具结果与转录 | 给插件 Hook 用,见插件系统 |
pi 的七个工具名定义在 third_party/pi-mono/packages/coding-agent/src/core/tools/index.ts:84。MiniMax 只从 pi 引入 createReadTool、createWriteTool、createEditTool、createBashTool 四个工厂(packages/agent-tools/src/desktop/local-pi-tools.ts:11),pi 的 grep、find、ls 在 packages/ 里没有调用处,搜索由自己的 ripgrep 实现承担。
契约:RuntimeTool
packages/agent-core/src/tools 主要定义契约。ToolDefinition 是模型看到的那一面:name、description、typebox 写的 schema,外加可选的 prepareArguments、executionMode(packages/agent-core/src/tools/types.ts:66);ToolImpl.execute(ctx, input, signal, onUpdate) 是执行的那一面;两者配成 RuntimeTool,再挂一个来源标记 source,取值 builtin、builtin-matrix、configured(types.ts:32、:142)。把实现类变成 RuntimeTool 有两种写法:装饰器 @bindTool(def) 加 toRuntimeTool(instance)(packages/agent-core/src/tools/bind.ts:31、:46),或一次声明的 defineRuntimeTool(packages/agent-core/src/tools/define.ts:24)。本地文件与 Shell 工具用的是前一种。同目录还有一组通用工具定义(packages/agent-core/src/tools/builtin-defs.ts:1),公开仓库里没有使用方。
契约到 pi 的转换在 packages/agent-core/src/pi-turn-runner/tools.ts:26 的 newTools:逐个把 RuntimeTool 包成 pi 的 AgentTool,同名直接抛错;执行时把本回合的上下文与 toolCallId 放进闭包传给 impl.execute。没声明执行模式的一律按 sequential 处理(tools.ts:140),而且模式作用于整批:pi 的循环只要发现同一条助手消息里有一个串行工具,整批调用都改成串行(third_party/pi-mono/packages/agent/src/agent-loop.ts:385)。本地的 read、grep、glob 声明为 parallel,write、edit、bash 是 sequential(packages/agent-tools/src/desktop/builtin-defs.ts:19、:57、:93、:110)。
newTools 还带一段后备逻辑:清单里缺 read、write、edit、bash 时,自动补上 pi 的原生实现(tools.ts:44)。v2 准备回合时显式关掉了它(packages/local-runtime-v2/src/service/turn-system/agent-host/assembly/local-turn-execution-preparation.ts:90),所以本地运行时里这四个名字背后一定是 MiniMax 的包装版;包装版在 pi 之上加了什么,下一篇细说。
原料:注册表与几路来源
本地工具的起点是 buildLocalToolRegistry。前七个工具无条件创建(packages/agent-tools/src/desktop/index.ts:118):
export function buildLocalToolRegistry(deps: LocalToolRegistryDeps): Map<string, LocalRuntimeTool> {
const tools: LocalRuntimeTool[] = [
toRuntimeTool(new LocalReadTool(deps.workspaceRoot)),
toRuntimeTool(new LocalWriteTool(deps.workspaceRoot)),
toRuntimeTool(new LocalEditTool(deps.workspaceRoot)),
toRuntimeTool(
new LocalBashTool(
deps.workspaceRoot,
deps.bashAdapter,
deps.bashEnvPolicy,
deps.hostTrashRuntime,
deps.sandboxOperationsFactory,
),
),
toRuntimeTool(new LocalGrepTool(deps.workspaceRoot)),
toRuntimeTool(new LocalGlobTool(deps.workspaceRoot)),
toRuntimeTool(new LocalTodoWriteTool(deps.todoEventSink)),
];其余工具看宿主给没给对应的适配器:skill、memory、code_review、mavis、ask_user 与 request_feature_enable、web_fetch、web_search、task、task_append、task_query、task_output、task_stop、website_deploy。最后按名字建 Map,重名抛错(desktop/index.ts:188)。
把注册表、MCP 和线程目标工具凑成一回合原料的,是 packages/local-runtime/src/api/local-native-tools.ts:258 的 buildLocalTurnToolSources:
- 工具被整体禁用时四路来源全部置空(
local-native-tools.ts:261); task与task_append算同一个委派入口,要求宿主允许且能力上限打开delegation(:276);- MCP 工具由
mcpService.listToolEntriesForTurn列出(:334),每个条目都按服务来源打上builtin-matrix、builtin或configured,认不出的一律算configured(packages/local-runtime-v2/src/service/mcp/tools/runtime-tools.ts:47); - 线程目标(
/goal)的工具单独一路(local-native-tools.ts:362),见 Plan 模式与目标。
命令行宿主另有几处差别:web_search 对 electron、tui、cli 三种宿主启用原生实现(packages/local-runtime/src/api/host-turn-tools.ts:82);记忆与定时任务在 cli、tui 下关掉(packages/local-runtime-v2/src/application/agent/profile-source.ts:52);浏览器工具由应用层在原生工具之后追加(packages/local-runtime-v2/src/application/agent/runtime-agent-product.ts:73,见浏览器工具)。内置 Matrix MCP 在公开仓库里没有启用,运行时组装固定传 builtinMatrix: false(packages/local-runtime-v2/src/compat/v1/runtime.ts:580),所以命令行版的媒体生成与理解主要靠本篇末尾的 mcode-tools。
整条装配线如下:
最后一步之前,@mavis/agent-runtime 的扩展还能再注册工具:装配时清单在前、扩展追加在后(packages/agent-runtime/src/registry.ts:347)。Plan 模式的 EnterPlanMode、ExitPlanMode 就是扩展按回合注册的(packages/agent-extension/src/plan-mode.ts:124)。扩展机制见 Agent 模块。
过滤:一回合的清单怎样定下来
过滤集中在 packages/local-runtime-v2/src/service/turn-system/agent-host/assembly/local-turn-tool-catalog.ts。注释写得直白:各业务域只提供原始工具,模型门槛、MCP 暴露方式和提示都在这里按冻结的回合事实决定(local-turn-tool-catalog.ts:183)。每个工具先过 isReadyTurnToolAllowed(local-turn-tool-catalog.ts:276):
if (input.excludedNames.has(input.tool.def.name)) return false;
if (!isDesktopToolAvailable(input.tool, input.cuRuntimeAvailable)) return false;
if (!input.selector.allowsTool(input.tool.def.name, input.options.selectorAlias)) return false;
if (!isMcpServerAllowed(input.selector, input.options)) return false;
if (
(DELEGATION_TOOL_NAMES.has(input.tool.def.name) ||
(input.source !== 'builtin' && TASK_CONTROL_TOOL_NAMES.has(input.tool.def.name))) &&
!isAuthoritativeMainProfile(input.profile)
) {
return false;
}
if (!input.profile) return true;
return isProfileToolAllowed(input.profile, input.tool, input.source);
}依次是:
- 模型能力:模型本身能看图、看视频时,去掉多余的
images_understand、videos_understand(packages/agent-tools/src/shared/model-tool-capabilities.ts:3)。 - 电脑操控:
desktop_开头的工具只在电脑操控(代码里叫 CU)运行时可用时保留(local-turn-tool-catalog.ts:291)。 - Agent 选择器:名字经
trim、NFKC 归一和小写后比较,disallowedTools命中即剔除,tools有值时只留名单内的(:328)。 - 委派权:
task、task_append以及非内置来源的同名任务控制工具,只给“权威主 Agent”——界面是interactive或cli、可信内置、规范角色为mavis(:320)。 - 档案上限:作为子任务运行的 Agent 拿不到
task、task_append、todowrite、ask_user(:454);features三个开关分别管mavis、委派入口和web_search(:473)。
内置子 Agent 还有一层按角色的上限(packages/agent-tools/src/desktop/canonical-tool-policy.ts:33)。角色只有 explore、worker、verifier 三个(packages/shared/src/subagent-roles.ts:1):
| 角色 | 去掉的工具 |
|---|---|
worker | 只去掉 task、task_append |
verifier | write、edit、website_deploy、todowrite、task、task_append、memory、ask_user、request_feature_enable 与全部 desktop_*(canonical-tool-policy.ts:11) |
explore | 同 verifier,再加 task_query、task_output、task_stop |
MCP 条目上,explore 与 verifier 只留 Matrix 的 web_search(canonical-tool-policy.ts:58);线程目标工具不给子任务,也不给内置子 Agent(local-turn-tool-catalog.ts:432)。子 Agent 的来龙去脉见子 Agent 与后台任务。
过滤完的 MCP 条目交给 planMcpDisclosure 决定暴露方式(packages/agent-tools/src/mcp-disclosure/plan.ts:31):只有 configured 来源的工具可能被延后,内置来源总是内联;要延后还得同时满足开关打开、模型在白名单里、候选数不少于 minDeferCount(默认 1,local-turn-tool-catalog.ts:496)、按“JSON 长度除以 4”估出的 token 数超过上下文窗口的 thresholdPct(默认 0.15,:490)。一旦延后,清单里改放 tool_search 与 mcp_invoke 两个工具,并在用户提示前加一段检索说明。注意白名单默认为空(local-turn-tool-catalog.ts:536),不配置就不会延后。细节见 MCP。
结果截断:三道闸
工具结果进历史之前要过三道闸,越往后越宽:
| 层 | 上限 | 超出后 | 出处 |
|---|---|---|---|
| pi 工具自身 | 2000 行或 50KB | read 截取开头并提示用 offset 续读;bash 保留尾部,全文写进临时文件 | third_party/pi-mono/packages/coding-agent/src/core/tools/truncate.ts:11 |
| desktop 包装 | read 24KiB、bash 24KiB、grep 内容模式 16KiB | read 保留开头并返回 next_offset;bash 头部占 45%,其余留给尾部 | packages/agent-tools/src/desktop/output-limit.ts:3、:103 |
toolOutputBudgetExtension | 默认 64KiB | 文本整体存档,换成一张回执 | packages/agent-extension/src/tool-output-budget.ts:48 |
第三道闸是挂在 after_tool_call 上的扩展。它先确认本回合有 read 工具,没有就原样放行,因为回执得靠 read 才能兑现(tool-output-budget.ts:62);超限时只存文本,图片等媒体块留在结果里;存档写在会话 reports 目录的 tool-outputs/ 下(packages/local-runtime-v2/src/service/turn-system/persistence/tool-output-artifact.repository.ts:8),写失败则退回一段 2KiB 的首尾预览(production-composition.ts:525)。回执要求模型先从存档里取回事实再作答(tool-output-budget.ts:280):
Recover the needed facts from this artifact now, before answering, inferring, or searching another source.
Search this artifact first with bounded rg/grep when available, then read the relevant ranges with read(path, offset, limit).
If artifact search is unavailable, use bounded read directly.
Do not read or print the entire artifact in a single call.
When complete content is required, continue with bounded reads until all of it has been read.这三道闸只管单条结果。历史里的工具结果累计过多时,自动压缩还会归档旧结果,见上下文管理与压缩。
mcode-tools:不在清单里的工具
THIRD_PARTY_NOTICES.md 最后一条提到的 mcode-tools,是一个单文件 CLI:包名 @minimax/mcode-tools,版本 0.0.4,入口 cli.mjs。它不在仓库源码里,而是构建时从 npm 上已发布的 @minimax-ai/[email protected] 压缩包里抽出来的。scripts/lib/mcode-tools-artifact.mjs:7 钉死了下载地址、压缩包的 SHA-512 与 CLI 的 SHA-256;抽取时只认 embedded/mcode-tools/ 下的 cli.mjs、manifest.json 和包里的 THIRD_PARTY_NOTICES.md 三个条目,并核对清单里的版本、构建环境和包名(mcode-tools-artifact.mjs:15),产物放进 embedded/mcode-tools/,原包的第三方声明另存为 MCODE_TOOLS_NOTICES.md(:67)。构建脚本随后把启动器拷进 internal-bin/(scripts/build.mjs:132)。
它不注册成 RuntimeTool,模型是通过 bash 调它的:
- 放上 PATH:TUI 启动时若
beta.mcodeTools为真(packages/tui/src/runtime/lifecycle.ts:321),prepareTuiMcodeToolsIntegration校验资源、在临时目录起一个本地租约代理,再设置几项__MAVIS_MCODE_TOOLS_*环境变量、把internal-bin插到进程 PATH 最前(packages/tui/src/runtime/mcode-tools-integration.ts:80)。bash 子进程继承 PATH,mcode-tools就解析到启动器。 - 启动器转交:启动器用当前运行时的 Node 可执行文件运行同目录上一级的
mcode-tools.js(packages/tui/src/cli/mcode-tools-launchers/mcode-tools:9),后者由packages/tui/src/cli/mcode-tools-entry.ts打包而来,先把环境改成MCODE_AUTH_PROVIDER=shared-broker等取值(packages/tui/src/cli/mcode-tools-environment.ts:124),再加载内嵌的cli.mjs。 - 教模型用:内置技能
mcode-tools-master只在这个 beta 打开时出现(packages/local-runtime/assets/skills/mcode-tools-master/SKILL.md:11),教模型先mcode-tools connector tools --keyword找工具,再connector tool看参数、connector call调用,生成类命令要把 bash 的timeout设成 600。对MiniMax-M2.7系列模型,系统提醒里还会加一段<mcode-tools-master-reminder>,把图像、视频、音频任务都引向这个技能(packages/agent-modules/system-reminder/src/mcode-tools-master-reminder.ts:1)。
beta.mcodeTools 的默认值:打包的 dev、test、staging、prod 构建在 macOS、Linux、Windows 上都默认打开,配置里写 false 可以关掉(config.ts:642)。子进程怎样拿到短期令牌、Connector 背后是哪些云端服务,见账号、OAuth 与云端工具。
下一篇:文件与 Shell 工具——读、写、编辑、搜索与 bash 在 pi 之上各加了哪些守卫。