内置工具大全
LibreFang 自带的工具目录远不止标准 agent 模板里看到的 file / shell / web 工具。本页覆盖那些一直只活在源码里的家族 —— 浏览器自动化、子进程生命周期、运行时调度、知识图谱、媒体生成、agent 间消息。
Per-agent capability 授权决定一个 agent 实际能调哪些家族。在 agent.toml [capabilities] 里(或用 librefang agent grant CLI)给 agent 开下面这些工具家族的权限。
元工具(Lazy Loading)
两个元工具让 agent 按需发现并加载工具,而不是每次 prompt 都带全部 schema。
| 工具 | 用途 |
|---|---|
tool_search(query) | 返回名字/描述/标签匹配 query 的工具。无副作用,调用便宜。 |
tool_load(name) | 把某工具的完整 schema 拉进当前 session。后续轮次可以调它。 |
Lazy loading 在 manifest 用 lazy_tools = true 按 agent 开启。关掉则恢复"所有工具一直加载"的旧行为。这就是 Agent 模板 里 Lazy Tool Loading 提到的机制。
Agent 间消息(A2A)
不同 LibreFang 实例上的 agent 可以通过 A2A 协议互发任务。
| 工具 | 参数 | 用途 |
|---|---|---|
a2a_discover | url | 探测远端 A2A 端点,返回 agent card(/.well-known/agent.json)。 |
a2a_send | agent_id、message、可选 task_id | 给远端 A2A agent 发任务并等回复。 |
a2a_send 从调用方视角是同步的 —— 阻塞到远端轮次完成(或任务 TTL 到)。要 fire-and-forget 投递,用 notify_owner 或 webhook target。
同 daemon 内 agent 间工具
跟同一 LibreFang daemon 里别的 agent 通话(无 A2A 协议开销) —— 直接 spawn、list、find、kill、发消息。
| 工具 | 参数 | 用途 |
|---|---|---|
agent_send | agent_id、message、可选 async | 给本 daemon 内别的 agent 发消息。默认非阻塞:立即返回 task_id,对方回复完成后投递到调用方 session。传 async: false 则阻塞并直接拿到回复。走进程内 kernel 路由器;受 agent_call 深度上限约束。 |
agent_spawn | template、可选 name、goal | 从模板 spawn 子 agent。返回新的 agent_id。子 agent 默认禁 agent_spawn 和 agent_kill 防止 fork 炸弹。 |
agent_list | — | 列出可访问 agent(id、name、status)。 |
agent_find | query | 按名字、ID 或 tag 搜 agent。 |
agent_kill | agent_id | 终止运行中的 agent。子 agent 上下文里默认禁。 |
goal_update | goal | 中途更新当前 agent 的目标。新目标写进 agent 的 manifest,后续 prompt 看得到。 |
agent_type_create | name,可选 description、system_prompt、provider、model、tools、skills | 创建一个新的智能体类型(agent type)—— 一份存在 daemon 上的可复用 manifest,之后 agent_spawn、仪表盘和 TUI 都能从它生成 agent。这里只能设置这七个字段,manifest 的其余部分先取默认值,之后再改。名字若已被某个智能体类型或某个运行中的 agent 占用,会被拒绝而不是覆盖。 |
agent_type_create 走的是和 POST /api/templates 完全相同的 AgentTypeSpec 校验与同一个存储实现,所以 agent 自己写出来的类型和运维在仪表盘里写出来的没有任何区别。
工具、仪表盘和 TUI 统一用"智能体类型"这个说法;HTTP 路径仍旧只有 /api/templates 一个,不再为同一个资源加第二个别名。
[kernel] 里的 max_agent_call_depth(默认 5)封顶 agent_send 链能递归多深 —— 让 A→B→A 循环根本到不了生产。
下面的 workflow_run 若发生嵌套(某一步的目标 agent 又跑了一次 workflow)也计入同一份预算,因为每一步都会嵌套一整个 agent turn,效果跟 agent_send 跳一层一样。
Memory 工具(per-agent)
一共有两套记忆存储、两套工具族,名字相近,值得仔细区分。
memory_store / memory_recall / memory_list 是键值存储。memory_recall 只接受精确的 key,不做任何匹配 —— 它不是搜索。
| 工具 | 参数 | 用途 |
|---|---|---|
memory_store | key、value | 以精确 key 持久化一个值,只能用同一个 key 取回。 |
memory_recall | key | 按精确 key 查一个值。key 不是逐字符相同就返回“未找到”。 |
memory_list | 可选 limit、offset | 枚举键值存储里的 key 名(不含值)。 |
memory_semantic_* 是语义存储 —— 也就是自动召回机制每轮之前读取的那套向量存储。有了这些工具,agent 才能主动查询它,而不是只能被动接收注入的内容。
| 工具 | 参数 | 用途 |
|---|---|---|
memory_semantic_search | query、可选 limit、min_confidence | 按语义搜索记忆片段,每条结果都带可用于撤回的 id。min_confidence 会过滤置信度已衰减的片段,让调用方可以选择“宁可什么都不要,也不要噪声”。 |
memory_semantic_add | content | 主动记录一条持久事实。内容会经过记忆抽取器,可能被提炼、被合并进已有记忆,或因冗余而被拒绝 —— 返回结果会如实说明实际写入了什么,包括“什么都没写”。 |
memory_semantic_forget | memory_id | 撤回一条记忆,使其不再被召回。这是修正“陈旧记忆持续与 agent 直接观测到的事实相矛盾”的手段。 |
memory_semantic_stats | — | 按层级与类别的计数,以及 auto-memorize、自动召回、LLM 抽取是否开启。用于区分“存储是空的”和“存储被关掉了”。 |
只有 memory_semantic_search 每轮都会带上 schema;其余三个通过 tool_search / tool_load 获取。
语义工具需要同时满足两个条件:capabilities.tools 允许它们(memory_* 这样的 glob 即可),并且记忆 scope 覆盖 agent 自己的记忆 —— search / stats 看 capabilities.memory_read,add / forget 看 capabilities.memory_write。未声明 scope 时保持开放;若声明的 scope 只覆盖键值存储(memory_read = ["kv:*"]),语义工具会被收回,键值工具不受影响。[proactive_memory] enabled = false 时它们也会被完全收回,因为此时存储根本没有构建。
条目 schema、scope、衰减公式、整合触发器见内存系统。
任务队列工具
共享任务板让 agent 发布工作给别的 agent 认领。适合 fan-out、oncall 交接、长跑异步任务。
| 工具 | 参数 | 用途 |
|---|---|---|
task_post | title、body、可选 assignee、priority | 在共享队列创建新任务。 |
task_claim | 可选 priority_filter | 认领最高优先级 pending 任务。TTL 是 [task_board] claim_ttl_secs(默认 600s)。 |
task_complete | task_id、可选 result | 标记已认领任务为完成。 |
task_list | 可选 status、assignee | 带可选过滤条件列出任务。 |
task_status | task_id | 按 ID 查询单个任务,返回 status、result、title、assigned_to、created_at、completed_at。comms_task_status MCP bridge 工具的 native 版本——通过 task_post 委派工作的 agent 可以直接轮询结果,不必加载 bridge。 |
claim TTL 用来从 worker 崩溃中恢复 —— 认领者没在 TTL 内 task_complete,sweeper 把任务重置回 pending 给别的 worker 接手。
Channel 工具
| 工具 | 参数 | 用途 |
|---|---|---|
channel_send | channel、target、content(文本 / 图 / 文件 / poll) | 给某 channel 用户发消息、图片、文件或 poll —— 不走 agent 循环。适合推告警、异步结果、带外通知。 |
channel_dm | user_id、message | 把消息私下发给当前这轮所在群会话中的某一位成员,而不是发到所有人都能看到的群里。 |
channel_members | 可选 channel、chat_id | 列出群会话中已知的成员 —— 守护进程见过发言的每个人的 user_id、display_name、username。只读。 |
channel_send 是 [deliver_only] webhook 模式内部用的工具;agent 也能直接调。Capability:channel.*。
channel_members 读取 channel bridge 在观察群消息时建立的花名册,因此它列出的是在该会话中发过言的人,而不是平台的完整成员列表。
两个参数都默认取当前消息所在的会话,所以在处理消息时可以完全不带参数调用;私聊没有花名册。
指定当前轮次所在 channel 上的另一个会话会被拒绝,理由与 channel_send 拒绝跨会话投递相同 —— 一个群不能枚举另一个群的成员。
用它把请求归属到提出请求的人,并拿到外部系统通知此人所需的平台 user_id。
在群里只找一个人
在群会话里,channel_send 只能发给群本身 —— 把它改指向某个人会被跨会话派发守卫拒绝,因为一个能任意指定收件人的 agent,也就能被诱导指错人。
channel_dm 是那个收窄过的例外:它只接受 user_id 和 message,别的都不接受。
channel、会话和机器人账号全部来自正在处理的这一轮,而收件人必须已经出现在该会话的名册里 —— 也就是 daemon 见过其发言、并且 channel_members 会列出的人。
因此 agent 无法给一个素未谋面的平台 id 发消息,也无法借一个会话伸进另一个会话。
带外场景(cron、trigger、API 触发的运行)没有会话,也就没有名册可以授权任何人;channel_dm 在那里按设计不可用,该用带显式 recipient 的 channel_send。
"私下"在各平台上的含义并不相同,这个工具也不假装相同。
Slack 允许机器人与工作区内任意成员开启 DM,所以 U… id 总能送达。
Telegram 和 Discord 的机器人无法主动联系从未给它发过消息的人,这种发送会失败 —— 它绝不会悄悄退回到发群里,因为一条本该私密、却无声变成公开的通知,比报错更糟。
notify_owner 不是它的替代品:那产生的是面向运维者的通知,通过运维者自己的界面带外送达,没有任何 channel adapter 会把它转给会话参与者。
Workflow / Event 工具
| 工具 | 参数 | 用途 |
|---|---|---|
workflow_run | workflow_id、可选 inputs | 同步执行存好的 workflow 并返回结果。嵌套深度受与 agent_send(上文)相同的 max_agent_call_depth 预算约束;超深的 run 会被拒绝,而不是任其递归。 |
event_publish | event_type、payload | 把结构化事件发到事件总线。监听该 event_type 的 trigger(agent manifest 里的 [[trigger]] 块)会触发。 |
system_time | — | 取 daemon 当前墙钟时间(RFC3339 UTC)。便宜,不调外部 clock。 |
event_publish 是 agent 与 trigger 系统的桥梁 —— 检测到"/inbox 落了新文件"的 agent 可以发 inbox.new_file,任何配在该事件上的 trigger 就跑起来。
技能进化(扩展)
除了上面文档化的 skill_evolve_patch(带 5 策略模糊匹配器)和 skill_read_file,还有:
| 工具 | 参数 | 用途 |
|---|---|---|
skill_evolve_create | name、manifest、可选 body | 从零创建新 skill。 |
skill_evolve_update | name、body | 整体替换 skill body(不模糊匹配,直接覆盖)。 |
skill_evolve_delete | name | 删除整个 skill。 |
skill_evolve_rollback | name、可选 version | 回退 skill 到之前的版本。不指定 version 就回退一步。 |
skill_evolve_write_file | skill、path、body | 在 references/ / templates/ / scripts/ / assets/ 加支持文件。 |
skill_evolve_remove_file | skill、path | 删支持文件。 |
每次 skill_evolve_* 操作都追加到 skill 的进化历史;GET /api/skills/{name} 返回完整审计轨迹。
浏览器自动化
8 个工具包了一个 Playwright 控制的无头浏览器。所有工具都需要 agent 有 browser.* capability,且 config.toml 里配了 [browser] 段(见核心配置)。
| 工具 | 用途 |
|---|---|
browser_navigate(url) | 在活跃 tab 打开/导航 URL。 |
browser_back() | 在 tab 历史栈里后退一步。 |
browser_click(selector) | 点 CSS / 文本选择器匹配的元素。 |
browser_type(selector, text) | 聚焦元素后逐键 debounced 输入文本。 |
browser_scroll(direction, amount?) | 上/下滚动或滚到某选择器。 |
browser_wait(condition, timeout_ms?) | 等选择器/network-idle/时间。 |
browser_screenshot(full_page?) | 截屏(viewport 或整页)为 ContentBlock::ImageFile。 |
browser_read_page() | 抽取页面完整文本 + 结构化大纲(模型只要文本时比 screenshot 便宜)。 |
browser_run_js(script) | 在页面上下文跑任意 JS,返回 JSON 序列化结果。 |
browser_close() | 关闭活跃 tab,释放 slot。 |
Agent 打开的页面绑在该 agent 的 tab 池里(默认 4)。池满时 browser_navigate 用 ToolError::ResourceExhausted 拒绝,而不是悄悄 evict 别的 tab。
子进程生命周期
5 个工具管长跑子进程(build watch、test loop、log tailer、sidecar daemon)。stdin / stdout / stderr 暴露成 agent 可 poll 的流。
| 工具 | 用途 |
|---|---|
process_start(command, cwd?, env?) | spawn 子进程。返回 process_id。 |
process_write(process_id, data) | 给子进程 stdin 写字节。 |
process_list() | 列出该 agent 的活跃子进程(id、cmd、age、pid)。 |
process_poll(process_id, max_bytes?) | 自上次 poll 起读最多 max_bytes 新输出。非阻塞。 |
process_kill(process_id, signal?) | 发信号(默认 SIGTERM);超过宽限期 runtime 升级到 SIGKILL。 |
子进程默认继承 agent 的 workspace 作为 cwd、agent 的环境变量(去除其他 provider 的 secret),agent 关闭时一并停掉。墙钟预算由 [exec_policy] 段强制。
运行时调度
manifest [[cron]] 是静态的安排方式。这些工具让 agent 从循环里动态创建/列出/暂停/恢复调度。
| 工具 | 用途 |
|---|---|
schedule_create(when, prompt, channel?) | 在某未来时间戳调度一次性轮次。 |
schedule_list() | 列出 agent 已调度的轮次。 |
schedule_delete(schedule_id) | 暂停(禁用)已调度的轮次 —— 保留配置而非删除。 |
schedule_resume(schedule_id) | 恢复被暂停的已调度轮次。 |
cron_create(expression, prompt, channel?) | 5 字段 cron 调度循环轮次。 |
cron_list() | 列出 agent 运行时创建的 cron 任务。 |
cron_cancel(cron_id) | 暂停(禁用)运行时 cron 任务 —— 保留配置而非删除。 |
cron_enable(cron_id) | 重新启用被暂停的运行时 cron 任务。 |
agent 不能硬删除已调度的任务:schedule_delete / cron_cancel 只会暂停它,因此即使是行为异常或过于激进的 agent 也无法静默丢失一个已配置好的调度。
永久删除是仅限人类的操作,通过 dashboard 完成(#6159)。
这些工具创建的运行时任务和 manifest cron 共用持久化存储 —— 跨 daemon 重启依然存在。
cron_id / schedule_id 是不透明的;通过 cron_list() 往返获取。
知识图谱
每个 agent 私有的知识图谱存实体和带类型的关系。适合做结构化召回("哪些项目用哪些库"),用扁平 memory 记录不好表达的那种。
| 工具 | 用途 |
|---|---|
knowledge_add_entity(name, type, attributes?) | 插入或更新实体。 |
knowledge_add_relation(from, to, type, weight?) | 在两个实体之间加有向关系。 |
knowledge_query(start, depth?, relation_filter?) | 从 start 做 BFS,返回可达节点 + 边。 |
图谱按 agent 私有,与 agent 的 session 历史一起持久化在 SQLite。非结构化召回用 proactive-memory 工具。
媒体生成与分析
调用 provider 专属媒体 API 的工具。需要按工具单独授权 capability。
| 工具 | 用途 |
|---|---|
image_generate(prompt, size?, style?) | 文生图(OpenAI / Replicate / Vertex)。 |
image_analyze(image, question) | 对已有图像做 vision Q&A。 |
media_describe(image_or_video) | 给已有媒体素材生成 caption / 描述。 |
media_transcribe(audio_or_video, language?, prompt?, start_sec?, max_secs?, out_path?) | 音频转文本;也接受视频容器,服务端会提取其中的音轨。无法识别的扩展名会被拒绝。start_sec / max_secs 只转写一个时间窗口,并在响应中返回 has_more / next_start_sec 以便继续;out_path 会把转写结果写入工作区文件,只返回路径、字节数、sha256 和一段预览。长录音两者都需要,详见下文。 |
speech_to_text(audio_or_video, language?, prompt?) | 支持的提供商和视频容器与 media_transcribe 相同;遇到无法识别的扩展名时不拒绝,而是退回一个宽松的猜测 MIME 类型。不支持时间窗口和 out_path,因此需要其中任何一项的长录音应改用 media_transcribe。 |
text_to_speech(text, voice?) | TTS 合成。 |
music_generate(prompt, lyrics?) | 音乐生成(Suno / Replicate)。 |
video_generate(prompt, duration_secs?) | 提交视频生成任务,返回 task_id。 |
video_status(task_id) | poll 视频任务。 |
canvas_present(html) | 在 dashboard 渲染交互式 HTML canvas。 |
provider 间成本和延迟差别很大 —— 在 config.toml 里配 [media] providers 控制每个工具走哪个 provider。
转写长录音
整场会议的转写结果无法通过单次工具返回完整送达 agent:超过 [tool_results] spill_threshold_bytes(默认 16 KB)的结果会被内核转存到 artifact store,agent 只拿到一个占位;而单次转写请求受一个不随输入长度变化的挂钟超时约束。
这两个限制远早于任何文件大小限制被触及 —— 十分钟的录音提取出来只有两三兆音频。
所以要按时间窗口转写,并写入文件:
media_transcribe(path="meeting.mp4", max_secs=600, out_path="meeting.txt")
→ { "written_to": "...", "file_bytes": 16831, "has_more": true, "next_start_sec": 600.0, "window_preview": "..." }
media_transcribe(path="meeting.mp4", start_sec=600, max_secs=600, out_path="meeting.txt")
→ ... 只要 has_more 为 true 就继续
start_sec 为 0 的窗口会新建文件,后续窗口以换行分隔追加到同一个文件,因此多次调用会拼装成一份完整转写,而其内容始终不进入 agent 的上下文。
推进时请使用 next_start_sec 而不是自行加 max_secs:seek 会落到关键帧上,且最后一个窗口偏短,所以只有实际产出的长度才是不会漂移的边界。
也不要自行猜测 start_sec。
如果窗口起点超出录音结尾约十秒以上,返回的并不是空结果:ffmpeg 会放弃 seek 并返回录音的开头,而这段内容看起来就像你所请求的那一段。
这个余量是绝对值,不随录音长度按比例放大,因此在长录音上只占很小一部分——对一场四十五分钟的会议请求第五十分钟即可触发。
如果调用超时,就调小 max_secs。
一次请求能容纳多少媒体取决于 provider 的速度,自托管端点可能比托管服务慢一个数量级。
如果调用因超出提取后的音频预算而被拒绝,同样应调小 max_secs。
这里有两个大小限制,衡量的是不同的对象:输入容器在读取之前按 50 MB 的视频上限检查,而从中提取出的音轨在发送给 provider 之前按 20 MB 的音频上限检查。
长录音真正会碰到的是后者,因为离开进程的正是这条提取出的音轨——拒绝信息会同时给出实测大小和上限,因此窗口可以据此缩小,而不必靠猜。
Owner 通知
| 工具 | 用途 |
|---|---|
notify_owner(reason, summary, urgency?) | 给 agent owner 发私信,不进 chat。 |
notify_owner 写到 owner 的 inbox,可选地扇出到配好的旁路通道(Telegram、email)。和正常回复不同 —— 消息不进活跃 chat 历史,不会污染下游摘要。线上结构见 API 参考里的 ReplyEnvelope.owner_notice。
地理定位、Docker、Skills
| 工具 | 用途 |
|---|---|
location_get() | 当前位置(默认 IP 基础;可按 agent 覆盖)。 |
docker_exec(container, command) | 在 agent 已被授权访问的运行中 Docker 容器内跑命令。 |
skill_read_file(skill, file) | 读 skill 的支持文件(references/、templates/、scripts/、assets/)。和 skill_evolve_* 配套。 |
docker_exec 要求 agent 在 [capabilities] docker.* 允许列表里,且容器名在 [exec_policy] docker_allowlist。两者缺一,调用以 ToolError::Forbidden 拒绝。
apply_patch 移动语义
apply_patch 接受 UpdateFile { path, move_to, hunks } 形状。move_to 设了时,patch 先把 path 重命名为 move_to,然后对新路径应用 hunks。这把 rename + edit 折叠成单次工具调用,patch 是原子的 —— 读者不会看到改名后的旧路径文件。
hunks 空、move_to 非空 = 纯重命名。在重构多文件、其中一个文件改路径但内容不变时有用。
skill_evolve_patch 模糊匹配
skill_evolve_patch 就地修改已装的 skill。为了能扛住上游小幅漂移,匹配器按 5 个策略走,首匹配胜:
- Exact — 字节级相同(Levenshtein 0)。
- Line-trimmed — 去每行尾空白和 CRLF 后再比。
- Whitespace-normalised — 把行内连续空白合并;忽略 tab vs space 漂移。
- Indent-flexible — 去每行行首空白;忽略重排成不同缩进的修改。
- Block-anchor — 在目标里找连续 N 行 anchor(默认 3 行),把新内容拼到锚周围。
5 个全失败时,patch 用精确 diff 上下文拒绝,下一轮就能看到漂移在哪。没有自动"尽力"合并 —— 模糊匹配是有界的。
配套工具 skill_evolve_write_file 和 skill_evolve_remove_file 不走 patch 语义,直接管 skill 支持文件(references/、templates/、scripts/、assets/)。
在源码里去哪看
- 工具注册与 schema —
crates/librefang-runtime/src/tool_runner/definitions.rs——builtin_tool_definitions()给出每个内置工具的名字、描述和 LLM 看到的 JSON schema。 - 分发 —
crates/librefang-runtime/src/tool_runner/dispatch.rs—— 把工具名路由到处理函数的那个 match;处理函数本身按域拆在同目录的agent.rs、workflow.rs、memory.rs等文件里。 - Capability 把关 —
crates/librefang-types/src/capability.rs,加上execute_tool里的allowed_tools检查 —— 哪些 agent 能调哪些工具。 - 浏览器池 —
crates/librefang-runtime/src/browser.rs和browser_tools.rs。 - Schedule / cron 运行时工具 —
crates/librefang-runtime/src/tool_runner/schedule.rs和cron.rs。
不确定的时候,工具结构体上的 rustdoc 是权威规约。Dashboard 的 "Tools" inspector 也会按当前 capability 授权渲染实际可用的工具集。