Skip to content

内置工具 ​

agent 开箱就能调用的全部工具:每个做什么、风险等级多高、什么条件下才会挂上。

裸的 Options()(allowed_tools=None)会挂上 fs 和 web 两组工具:

python
from noeta.sdk import Options
options = Options(system_prompt="…")          # allowed_tools defaults to None
# the agent sees: Read, Glob, Grep, Edit, Write,
#                 Bash, BashOutput, KillShell, WebFetch, WebSearch

WebSearch 还要设置 NOETA_WEB_SEARCH_API_KEY。其余工具各有开关:

工具什么时候挂上
fs、web 两组总是挂上(受 allowed_tools / disallowed_tools 过滤)
memory_*agent 启用了 memory
browser_*agent 启用了 browser,并且任务绑定了一个在跑的沙箱
open_app宿主设置了 HostConfig.app_gateway
run_skill_scriptplugin_config["skills"]["allow_skill_scripts"] 打开,且某个已启用的技能带了脚本
mcp__<alias>__<tool>这个任务注册并启用了远程 MCP server
ToolSearch、McpCall启用的某个 MCP server 的 spec 设了 deferred=True(它自己的工具就不再发给模型)
控制类工具见控制类工具

文件系统工具 ​

来自内置插件 fs(noeta/builtins/fs/)。

工具风险参数做什么
Readlowfile_path、offset?、limit?读 UTF-8 文件,可按行截一段。一次最多返回 100 KB,超出时结果里会说明,模型用 offset 接着读。内容库里存的是整个文件(不超过 1 MiB 时),超过就只存这次返回的那一段。
Globlowpattern、path?列出匹配 glob 的路径(** 递归,支持 {ts,tsx} 这种多选),排好序并有上限。用 rg --files 遍历:遵守 gitignore,跳过隐藏文件。
Greplowpattern、path?、glob?、type?、output_mode?、-i、-n、-o、-u、-A/-B/-C、context?、head_limit?、offset?、multiline?用 ripgrep 搜内容,经 ExecEnv 执行(环境里必须装有 rg;没装时 fs 插件会发一次 RuntimeWarning)。
Edithighfile_path、old_string、new_string、replace_all?精确替换一段文本(默认要求唯一匹配,replace_all 则全部替换)。文件必须先 Read 过。CRLF 换行的文件按 CRLF 匹配和写回。
Writehighfile_path、content新建文件(自动建父目录),或覆盖本任务里已经 Read 过的文件。content 上限 8 MB。
Bashhighcommand、timeout?(毫秒,最多 600000)、description?、run_in_background?在工作区根目录执行命令。后台模式返回一个作业 id。
BashOutputlowbash_id、filter?查后台作业的状态(running / exited)、退出码和新输出。
KillShellhighshell_id停掉后台作业(先 SIGTERM,宽限期后 SIGKILL)。
  • 默认不真写盘。 HostConfig.write_mode="dry_run"(默认)只记录一份拟改的 diff;"apply" 才真正写入。
  • 写有边界,读没有。 Write / Edit 只能写工作区根目录以内;HostConfig.write_roots 可以按任务放开更多目录。Read / Glob / Grep 只把相对路径锚到工作区,绝对路径指到哪就读哪,所以真正的读取边界是进程自己的文件权限。
  • Write 可以在构造时绑定一个相对工作区的 allowed_path_globs 白名单(空 = 不限);* 只匹配一层路径,** 跨目录,{a,b} 表示多选。Edit 不看它。

Shell 审批 ​

SdkHost.shell_mode(默认 ShellMode.ALLOWLIST)和权限模式一起决定 Bash 能跑什么:

设置行为
shell_mode=OFF不挂 Bash。
default / acceptEdits命令经 bash -c 执行。命中白名单的直接跑,其余要审批。命令里有没加引号的 {、*、?、[,或有以 ~ 开头的词,一律要审批,因为 bash 会展开它们;加了引号的写法(如 find . -name '*.py')不受影响。
bypassPermissions什么命令都跑,不审批。

内置白名单(noeta/builtins/fs/impl/shell_rules.py)只认不含 shell 元字符的命令:

程序接受
git status无参数、--short、-s、--porcelain
git diff、git log只读用法
pytest、uv run pytest跑测试;仅限受信任的工作区
npm test、pnpm test任意后续参数;仅限受信任的工作区
grep、rg、find、ls只读;拒绝 rg --pre/--hostname-bin 和 find -exec/-delete/-fprint*

跑测试的这几条会执行仓库里的代码(conftest.py、package.json 里的脚本),所以只有工作区受信任时才免审批——和 .noeta/shell-allowlist.json 用同一套 grant_trust,或者设 project_shell_allowlist_trust="open"。git 那几条仍然免审批,但执行时会加上 -c core.fsmonitor= 和 --no-ext-diff --no-textconv;剩下的风险是仓库 .git/config 里配置的 filter.<driver>.clean。

扩展白名单有三种办法:

来源格式说明
SdkHost.shell_allowlist[{"program": …, "subcommand": …}]运维配置的规则;后续参数只要过得了元字符检查都放行
<workspace>/.noeta/shell-allowlist.json同样的 JSON 列表属于仓库内容,只有工作区被信任(grant_trust)时才加载;否则每个工作区警告一次 UntrustedProjectShellAllowlistWarning
SdkHost(project_shell_allowlist_trust="open")—无条件加载工作区文件;trust_store= 可指向别的信任记录

WARNING

这只是白名单加审批,不是进程沙箱。Bash 起的是真进程,服务端用户能写的地方它都能写。要隔离请用沙箱。

网页工具 ​

工具风险参数做什么
WebFetchlowurl、prompt抓网页、转成 Markdown,再用一次辅助模型调用按 prompt 回答(Options.webfetch_model,默认用任务的主模型)。HTTP 自动升 HTTPS;只有协议、主机、端口都相同的重定向才跟随,其余交回给模型;页面缓存 15 分钟。只支持 http(s)。按 Content-Type 处理:HTML 转成 Markdown,文本 / JSON / XML 原样返回,图片、PDF 和其他二进制类型报工具错误并写明类型。
WebSearchlowquery、count?网页搜索,返回排好序的 Markdown 结果。只有设置了 NOETA_WEB_SEARCH_API_KEY 才挂上。

WebFetch 什么地址都能访问。HostConfig.webfetch_allowed_hosts 列出不用问人就能访问的域名:

写法匹配
example.com只匹配这个域名
*.example.com任意层级的子域名,不含 example.com 本身
权限模式名单外的域名名单内的域名
default、acceptEdits每次调用都要审批直接访问
bypassPermissions直接访问直接访问

写法不合法会在构造 HostConfig 时报错。匹配看的是 URL 真实的域名(转小写、IDNA 规范化),https://example.com@evil.test/ 算作 evil.test。交回给模型的重定向,下一次调用会重新判断。这只是遇到陌生域名时问一下人,不是出网边界——有 Bash 的 agent 一条 curl 就能出去。真要管出网,请在网络层或沙箱里做。

应用工具 ​

工具风险参数做什么
open_applowdir、proxy_to通过 HostConfig.app_gateway 发布工作区里的 HTML 应用。

记忆工具 ​

agent 启用 memory 时挂上(预设里是 main 和后台整理记忆的 agent)。

工具风险参数做什么
memory_writemediumname、text、description?、type?、keywords?、related?写一条 Markdown 记忆。frontmatter 按字段合并进磁盘上已有的(不传 = 保留,传空 = 删除)。created / updated / source_task 由工具自己写(模型传来的 created 会被忽略);HostConfig.memory_max_bytes 按落盘的整页算,字段也算在内;新名字会提示相似的已有记忆。
memory_readlowname读一条记忆的全文。
memory_searchlowquery在名字和正文里做不分大小写的子串搜索;每条最多 3 行摘录,最多 10 条,超出时带 truncated 标记。
memory_archivemediumname把记忆移到 archive/:不再出现在索引、召回和搜索里,但文件不删。

type 取 user / project / procedural / reference。keywords 是逗号分隔的检索别名(跨语言召回靠它);related 列出召回这条时一并带上的其他记忆名。

浏览器工具 ​

只有 agent 启用了 browser 且任务有在跑的沙箱时才挂上。预设里只有 web 子 agent 满足。全部是 high 风险。

工具参数做什么
browser_navigateurl打开网址,返回页面快照。
browser_clickindex点击上一份快照里编号为 index 的元素。
browser_typeindex、text往编号元素里输入文字。
browser_extract—重新读取当前页面快照。
browser_screenshot—截一张 PNG 存进 ContentStore,返回 ContentRef。不会作为图片喂给模型。

快照 = 页面文字 + 带编号的可交互元素。工具名和参数由 Noeta 固定,不随容器镜像变化。

技能工具 ​

工具风险参数做什么
run_skill_scripthighskill、relpath、args?用白名单里的解释器运行已启用技能自带的脚本。不经过 shell。

控制类工具 ​

这些工具交给模型的是一份 schema,调用后变成引擎的决策,而不是执行 Tool.invoke。启用名写进 Options.plugins;写错会在构建时抛 ValueError,并列出合法名字。

工具什么时候挂上启用名 / 插件
Taskagent 能派子任务(有 agents 时自动推出)delegation
TodoWriteagent 启用了它todo_write
AskUserQuestionagent 启用了它ask_user_question
skill启用了它,且合并后的技能菜单非空skill_invocation(由 skills 挂上)
run_workflowHostConfig.workflow_allowed=True 且 agent 能派子任务react
RecallHistory接了上下文压缩——在 Client / query 下总是接的react
structured_output带独立 schema 派出的子任务 / workflow 助手(Options.output_schema 走 provider 原生的结构化输出);必须单独调用,和别的调用放在同一条回复里时整批被退回,模型会被告知单独发react

RecallHistory 按 offset 翻回被压缩进摘要的原始消息——这些内容不在任何文件里。

MCP 工具 ​

远程 MCP 工具名是 mcp__<alias>__<tool>。超过 64 个字符的名字会被截短并加 8 位 sha256 后缀,前缀保留;同一个服务器里两个工具名清洗后撞上,本来合法的保持原名,其余加后缀;两个服务器之间撞名,会在构建 agent 时抛 McpConfigError。进程内的 SDK server(create_sdk_mcp_server)保留 @tool 的原名。

spec 设了 deferred=True 的服务器,工具仍以这些名字注册,但 schema 不随请求发送;模型改为拿到 ToolSearch(查找这些工具和它们的 schema)和 McpCall(按名字调用其中一个),所有这类服务器共用这一对。一次 McpCall 在权限检查和记录里都按真实工具处理。见 MCP server。

风险等级 ​

等级含义default 下要审批
low不影响 agent 自身状态以外的东西否
medium在限定目录里做持久写入(比如记忆库)是
high写文件、起进程、访问外网是

Options.permission_mode:"default" 对 low 以上的工具都要审批;"acceptEdits" 再额外放行 Edit / Write;"bypassPermissions" 全部放行。Bash 和 WebFetch 另有上面说的逐次检查。

下一步 ​

  • 自定义工具——用 @tool 加自己的工具
  • Options——allowed_tools、disallowed_tools、permission_mode
  • 引擎——一次调用是怎么被批准或拒绝的

基于 Apache License 2.0 发布。