代理与工作流 API

管理代理、工作流、触发器、调度、目标和定时任务的端点。

Agent 端点

GET /api/agents

列出所有运行中的 Agent。

响应 200 OK

[
  {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "hello-world",
    "state": "Running",
    "created_at": "2025-01-15T10:30:00Z",
    "model_provider": "groq",
    "model_name": "llama-3.3-70b-versatile"
  }
]

POST /api/agents

从 TOML 清单创建新 Agent。

请求体(JSON):

{
  "manifest_toml": "name = \"my-agent\"\nversion = \"0.1.0\"\ndescription = \"Test agent\"\nauthor = \"me\"\nmodule = \"builtin:chat\"\n\n[model]\nprovider = \"groq\"\nmodel = \"llama-3.3-70b-versatile\"\n\n[capabilities]\ntools = [\"file_read\", \"web_fetch\"]\nmemory_read = [\"*\"]\nmemory_write = [\"self.*\"]\n"
}

响应 201 Created

{
  "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "my-agent"
}

POST /api/agents/bulk

批量创建多个 Agent。

DELETE /api/agents/bulk

通过 ID 列表批量删除多个 Agent。

POST /api/agents/bulk/start

同时启动多个已停止的 Agent。

POST /api/agents/bulk/stop

同时停止多个运行中的 Agent。

GET /api/agents/{id}

获取单个 Agent 的详细信息。

响应 200 OK

{
  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "name": "hello-world",
  "state": "Running",
  "created_at": "2025-01-15T10:30:00Z",
  "session_id": "s1b2c3d4-...",
  "model": {
    "provider": "groq",
    "model": "llama-3.3-70b-versatile"
  },
  "capabilities": {
    "tools": ["file_read", "file_list", "web_fetch"],
    "network": []
  },
  "description": "A friendly greeting agent",
  "tags": []
}

DELETE /api/agents/{id}

终止 Agent 并将其从注册表中移除。

响应 200 OK

{
  "status": "killed",
  "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}

PATCH /api/agents/{id}

部分更新 Agent 的字段。

PUT /api/agents/{id}/update

在运行时更新 Agent 的配置。

请求体

{
  "description": "Updated description",
  "system_prompt": "You are a specialized assistant.",
  "tags": ["updated", "v2"]
}

响应 200 OK

{
  "status": "updated",
  "agent_id": "a1b2c3d4-..."
}

PUT /api/agents/{id}/mode

设置 Agent 的运行模式。Stable 模式会固定当前模型并冻结技能注册表。Normal 模式恢复默认行为。

请求体

{
  "mode": "Stable"
}

响应 200 OK

{
  "status": "updated",
  "mode": "Stable",
  "agent_id": "a1b2c3d4-..."
}

PATCH /api/agents/{id}/identity

更新 Agent 的身份字段(名称、头像、人设)。

PATCH /api/agents/{id}/config

部分更新 Agent 的配置对象。

POST /api/agents/{id}/clone

将现有 Agent 克隆为新的 Agent,使用全新会话。

POST /api/agents/{id}/message

向 Agent 发送消息并接收完整响应。

请求体

{
  "message": "What files are in the current directory?",
  "session_id": "optional-session-uuid"
}

可选 session_id:按请求覆盖此消息落到哪个 session。省略时用 agent 当前 session。给了就路由到那个特定 session(必须是该 agent 已存在的 session),让一个 agent 从单个客户端同时服务多条平行 chat,不需要先 POST /sessions/{id}/switch。fan-out 后端和多 tab dashboard 用得上。

响应 200 OK

{
  "response": "Here are the files in the current directory:\n- Cargo.toml\n- README.md\n...",
  "input_tokens": 142,
  "output_tokens": 87,
  "iterations": 1
}

POST /api/agents/{id}/message/stream

发送消息并以 Server-Sent Events 流的方式接收响应(参见 SSE 流式传输)。

GET /api/agents/{id}/attach

作为额外只读订阅者附加到当前 session 的 SSE 流——多客户端联合观察时有用,CLI、Tauri 桌面、浏览器多 tab 想跟同一回合 live。

POST /message/stream 本身保持 single-consumer(只发起方拿到);本端点由按 session 的 SessionStreamHub 把每个 StreamEvent 同时复制给原调用方和任意数量的额外订阅者。订阅者不推进回合,只观察。

行为:

  • 连接保持到当前回合结束。回合结束时服务端干净关闭。
  • 你 attach 时没有正在跑的回合,连接等下一个。
  • 单个 agent 可有多个并发 attacher,不会拖慢生产者(broadcast channel;按事件的扇出常数代价)。
  • 事件格式跟 /message/stream 完全一样,已有解析器无需改动。
# 第二个客户端联合观察当前回合
curl -N 'http://127.0.0.1:4545/api/agents/$AGENT/attach' \
  -H 'Authorization: Bearer $LIBREFANG_API_KEY'

GET /api/agents/{id}/session

获取 Agent 当前的对话历史。

响应 200 OK

{
  "session_id": "s1b2c3d4-...",
  "agent_id": "a1b2c3d4-...",
  "message_count": 4,
  "context_window_tokens": 1250,
  "messages": [
    {
      "role": "User",
      "content": "Hello"
    },
    {
      "role": "Assistant",
      "content": "Hello! How can I help you?"
    }
  ]
}

GET /api/agents/{id}/sessions

列出 Agent 的所有会话。

POST /api/agents/{id}/sessions

为 Agent 创建新会话。

POST /api/agents/{id}/sessions/{session_id}/switch

切换 Agent 使用的会话。

GET /api/agents/{id}/sessions/by-label/{label}

通过用户指定的标签查找会话。

DELETE /api/agents/{id}/history

清除 Agent 的所有对话历史,但不创建新会话。

POST /api/agents/{id}/session/reset

重置 Agent 的会话,清除所有对话历史。

响应 200 OK

{
  "status": "reset",
  "agent_id": "a1b2c3d4-...",
  "new_session_id": "s5e6f7g8-..."
}

POST /api/agents/{id}/session/compact

触发基于 LLM 的会话压缩。Agent 的对话将由 LLM 进行摘要,仅保留最近的消息和生成的摘要。

响应 200 OK

{
  "status": "compacted",
  "message": "Session compacted: 80 messages summarized, 20 kept"
}

POST /api/agents/{id}/stop

取消 Agent 当前的 LLM 运行。中止任何正在进行的生成。

响应 200 OK

{
  "status": "stopped",
  "message": "Agent run cancelled"
}

PUT /api/agents/{id}/model

在运行时切换 Agent 的 LLM 模型。

请求体

{
  "model": "claude-sonnet-4-20250514"
}

响应 200 OK

{
  "status": "updated",
  "model": "claude-sonnet-4-20250514"
}

GET /api/agents/{id}/tools

获取 Agent 当前的工具列表。

PUT /api/agents/{id}/tools

在运行时替换 Agent 的工具列表。

GET /api/agents/{id}/skills

获取 Agent 当前的技能列表。

PUT /api/agents/{id}/skills

在运行时替换 Agent 的技能列表。

GET /api/agents/{id}/mcp_servers

获取附加到指定 Agent 的 MCP 服务器。

PUT /api/agents/{id}/mcp_servers

设置附加到指定 Agent 的 MCP 服务器。

GET /api/agents/{id}/traces

获取 Agent 的执行追踪(工具调用、LLM 迭代、耗时等)。

GET /api/agents/{id}/metrics

获取 Agent 的运行时指标(Token 数量、延迟、错误率)。

GET /api/agents/{id}/logs

获取 Agent 进程输出的最近日志行。

GET /api/agents/{id}/deliveries

获取 Agent 从通道接收到的入站消息投递记录。

GET /api/agents/{id}/files

列出 Agent 私有文件工作区中的文件。

GET /api/agents/{id}/files/{filename}

从 Agent 的工作区下载指定文件。

PUT /api/agents/{id}/files/{filename}

上传或覆盖 Agent 工作区中的文件。

DELETE /api/agents/{id}/files/{filename}

从 Agent 的工作区中删除文件。

POST /api/agents/{id}/upload

上传文件到 Agent 的工作区(multipart 表单数据)。

GET /api/uploads/{file_id}

通过上传 ID 获取之前上传的文件。

支持的附件类型

POST /api/agents/{id}/message(或 streaming 变体)的 body 引用附件时,后端在调用 LLM 前会把每个 file_id 解析为 content block。识别三类:

类别检测产出 block
图片Content-Type: image/*pngjpegwebpgif内联 base64 图片 block
PDFContent-Type: application/pdf文本 block,前缀 [Attached PDF: <filename>] 跟提取的纯文本
文本 / 代码任何 text/* MIME,列出的 application/* JSON/XML/YAML/TOML/JS/TS/SQL/GraphQL 类型,浏览器没填 MIME 时识别已知扩展名文本 block,前缀 [Attached file: <filename>] 跟 UTF-8 内容

识别的文本/代码扩展名包括 .txt.md.markdown.rst.csv.tsv.log.json.yaml.yml.toml.xml.ini.conf.cfg.env.html.css.js.ts.tsx.jsx.vue.svelte.py.rs.go.java.kt.swift.scala.c.cpp.h.rb.php.lua.r.sh.bash.sql.graphql.proto.ipynbDockerfileMakefile 等等。

上限:

  • PDF 文本提取和文本文件读取都截断在 200,000 字符。
  • 扫描件 / 纯图片 PDF 会带一段简短说明指出无法提取文本,模型仍能看到附件存在。
  • 三类都不匹配的文件被跳过并记 warn 日志;LLM 调用照常带上其余附件继续。

本地小模型注意: 用户消息含多段文本(比如附件头 + 用户提示)时,runtime 在 session-repair 层把同 role 相邻的文本 block 合并。这个归一化在任何 driver 调用之前发生,所以经 Ollama / vLLM / LM Studio 的 chat-tuned 小模型只看到单段 user 文本加图片,依然会注意到附件。

GET /api/agents/{id}/ws

用于实时双向聊天的 WebSocket 连接(参见 WebSocket 协议)。

GET /api/agents/{id}/memory/export

将 Agent 的所有记忆条目导出为 JSON。

POST /api/agents/{id}/memory/import

从 JSON 导入 Agent 的记忆条目。

Owner Notice

agent 可以发结构化的私密旁路消息给运营者,跟用户可见的回复并行。notify_owner 内置 tool 在回合中收集一条或多条 notice;runtime 聚合到 ReplyEnvelope.owner_notice: Option<String> 字段。

通知出现在三处:

  • POST /message 响应 body:顶层 owner_notice 字符串,跟 response 同级。
  • POST /message/stream / GET /attach SSE:在最终 Done 之前的 StreamEvent::OwnerNotice { text } 事件。
  • WhatsApp gateway:设了 OWNER_JIDS 环境变量(逗号分隔的 JID)后,每条 notice 扇出到这组 owner。其他 channel adapter 可以同样接入。

适合 "这个用户问了我没法在公开消息里答的事——升级给运维" 流程,或者任何不该让用户在 chat 里看到的审计轨迹。

GET /api/agents/{id}/sessions/{session_id}/trajectory

导出某个 session 的脱敏 trajectory(审计轨迹)。响应打包了该 session 的消息加最小元数据(agent 名、模型、system prompt 指纹、librefang 版本),所有消息都过隐私脱敏器再序列化。用于支持、审计、合规流程,需要分享 session 但又不能泄密时用这个。

Query 参数:

  • format=json(默认):单 JSON 对象,content-type application/json
  • format=jsonl:NDJSON — 第一行是元数据头,后续每行一条消息;content-type application/x-ndjson。方便 streaming 进 log pipeline 或 jq filter。

响应状态:

  • 200 — trajectory 包。
  • 400 — agent 或 session id 不是合法 UUID。
  • 404 — agent 或 session 不存在。
curl 'http://127.0.0.1:4545/api/agents/$AGENT/sessions/$SESSION/trajectory?format=jsonl' \
  -H 'Authorization: Bearer $LIBREFANG_API_KEY' > session.jsonl

工作流端点

GET /api/workflows

列出所有已注册的工作流。

响应 200 OK

[
  {
    "id": "w1b2c3d4-...",
    "name": "code-review-pipeline",
    "description": "Automated code review workflow",
    "steps": 3,
    "created_at": "2025-01-15T10:30:00Z"
  }
]

POST /api/workflows

创建新的工作流定义。

请求体(JSON):

{
  "name": "code-review-pipeline",
  "description": "Review code changes with multiple agents",
  "steps": [
    {
      "name": "analyze",
      "agent_name": "coder",
      "prompt": "Analyze this code for potential issues: {&lbrace;input&rbrace;}",
      "mode": "sequential",
      "timeout_secs": 120,
      "error_mode": "fail",
      "output_var": "analysis"
    }
  ]
}

步骤配置选项:

字段类型说明
namestring步骤名称
agent_idstringAgent UUID(与 agent_name 二选一)
agent_namestringAgent 名称(与 agent_id 二选一)
promptstring提示词模板,支持 {&lbrace;input&rbrace;}{&lbrace;output_var&rbrace;} 占位符
modestring"sequential""fan_out""collect""conditional""loop"
timeout_secsinteger每步超时时间(默认:120)
error_modestring"fail""skip""retry"
max_retriesinteger用于 "retry" 错误模式(默认:3)
output_varstring存储输出的变量名,供后续步骤使用
conditionstring用于 "conditional" 模式
max_iterationsinteger用于 "loop" 模式(默认:5)
untilstring用于 "loop" 模式:停止条件

响应 201 Created

{
  "workflow_id": "w1b2c3d4-..."
}

GET /api/workflows/{id}

获取指定的工作流定义。

PUT /api/workflows/{id}

更新已有的工作流定义。

DELETE /api/workflows/{id}

删除工作流定义。

POST /api/workflows/{id}/run

执行工作流。

请求体

{
  "input": "Review this pull request: ..."
}

响应 200 OK

{
  "run_id": "r1b2c3d4-...",
  "output": "Code review summary:\n- No critical issues found\n...",
  "status": "completed"
}

GET /api/workflows/{id}/runs

列出工作流的执行历史。

响应 200 OK

[
  {
    "id": "r1b2c3d4-...",
    "workflow_name": "code-review-pipeline",
    "state": "Completed",
    "steps_completed": 3,
    "started_at": "2025-01-15T10:30:00Z",
    "completed_at": "2025-01-15T10:32:15Z"
  }
]

触发器端点

触发响应路由

触发器触发的响应路由到该 agent 的主通道 —— agent 在 [channels] 下注册的那个通道。之前的行为在调用路径上没有调用方通道时(cron 样的触发、调度器事件)会静默丢弃响应。现在响应总会落到可见的地方:agent 自己拥有的面向用户的表面。

task_posted 触发器的 assignee_match:self 过滤

task_posted 触发器可以选择只在任务被指派给 agent 自己时触发(按 agent id 匹配):

{
  "pattern": {
    "task_posted": {
      "assignee_match": "self"
    }
  }
}

assignee_match 接受:

  • "self" — 仅当 task.assignee_id == agent.id 触发。"我应该处理分配给我的任务" 类 agent 用这个。
  • "any"(默认) — 旧行为;任何 task_posted 事件都触发,不看 assignee。

GET /api/triggers

列出所有触发器。可按 Agent 过滤。

查询参数:

  • agent_id(可选):按 Agent UUID 过滤

响应 200 OK

[
  {
    "id": "t1b2c3d4-...",
    "agent_id": "a1b2c3d4-...",
    "pattern": {"lifecycle": {}},
    "prompt_template": "Event: {&lbrace;event&rbrace;}",
    "enabled": true,
    "fire_count": 5,
    "max_fires": 0,
    "created_at": "2025-01-15T10:30:00Z",
    "cooldown_secs": 60,
    "session_mode": "persistent",
    "target_agent_id": null
  }
]

GET /api/triggers/{id}

获取单个触发器详情。

响应 200 OK:与列表中的单条记录格式相同。

响应 404 Not Found:触发器不存在时返回。

POST /api/triggers

创建新的事件触发器。

请求体

{
  "agent_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "pattern": {
    "agent_spawned": {
      "name_pattern": "*"
    }
  },
  "prompt_template": "A new agent was spawned: {&lbrace;event&rbrace;}. Review its capabilities.",
  "max_fires": 0,
  "cooldown_secs": 60,
  "session_mode": "persistent",
  "target_agent_id": "b2c3d4e5-..."
}

agent_idpatternprompt_template 外,其余字段均为可选。

字段类型默认值说明
agent_idUUID触发器归属的 Agent。
patternobject激活触发器的事件模式(见下方模式类型)。
prompt_templatestring事件触发时发送给 Agent 的提示,支持 {&lbrace;event&rbrace;} 占位符。
max_firesinteger0最多触发次数,0 表示无限制。
cooldown_secsinteger引擎默认值两次触发之间的最短间隔(秒)。省略则使用引擎默认值。
session_mode"persistent" | "new"Agent 默认值每次触发的会话连续性。省略则继承 Agent 配置。
target_agent_idUUIDnull将触发消息路由到指定 Agent,而非触发器所有者。

支持的模式类型:

模式说明
{"lifecycle": {}}所有生命周期事件
{"agent_spawned": {"name_pattern": "*"}}Agent 创建事件
{"agent_terminated": {}}Agent 终止事件
{"all": {}}所有事件

响应 201 Created

{
  "trigger_id": "t1b2c3d4-...",
  "agent_id": "a1b2c3d4-..."
}

PATCH /api/triggers/{id}

部分更新触发器配置。所有字段均为可选,仅更新提供的字段。

cooldown_secssession_modetarget_agent_id 设为 null 可清除覆盖值并恢复默认。省略字段则保持不变。

请求体

{
  "prompt_template": "Updated: {&lbrace;event&rbrace;}",
  "enabled": true,
  "max_fires": 10,
  "cooldown_secs": 120,
  "session_mode": "new",
  "target_agent_id": "b2c3d4e5-..."
}

响应 200 OK:返回完整的更新后触发器对象(与 GET /api/triggers/&lbrace;id&rbrace; 格式相同)。

响应 404 Not Found:触发器不存在时返回。

DELETE /api/triggers/{id}

删除触发器。

响应 200 OK

{
  "status": "removed",
  "trigger_id": "t1b2c3d4-..."
}

调度端点

基于时间的 Agent 激活,使用 cron 表达式或间隔语法。

GET /api/schedules

列出所有已配置的调度。

POST /api/schedules

创建新的调度。

请求体

{
  "agent_id": "a1b2c3d4-...",
  "cron": "0 9 * * 1-5",
  "prompt": "Good morning! Summarize overnight events.",
  "enabled": true
}

GET /api/schedules/{id}

获取指定调度。

PUT /api/schedules/{id}

更新调度。

DELETE /api/schedules/{id}

删除调度。

POST /api/schedules/{id}/run

立即触发调度执行(本次调用忽略其 cron 表达式)。


目标端点

用于多步骤 Agent 目标的层级化目标追踪系统。

GET /api/goals

列出所有目标。

POST /api/goals

创建新目标。

请求体

{
  "title": "Migrate database to PostgreSQL",
  "description": "Complete migration with zero downtime",
  "agent_id": "a1b2c3d4-...",
  "parent_id": null,
  "due_at": "2025-02-01T00:00:00Z"
}

GET /api/goals/{id}

获取指定目标。

PUT /api/goals/{id}

更新目标(标题、状态、描述、截止日期)。

DELETE /api/goals/{id}

删除目标及其所有子目标。

GET /api/goals/{id}/children

列出指定父目标的子目标。


定时任务端点

使用标准 cron 表达式语法调度周期性任务。

GET /api/cron/jobs

列出所有定时任务。

POST /api/cron/jobs

创建新的定时任务。

请求体

{
  "name": "daily-digest",
  "schedule": "0 8 * * *",
  "agent_id": "a1b2c3d4-...",
  "prompt": "Prepare the daily digest of overnight activity.",
  "enabled": true
}

GET /api/cron/jobs/{id}

获取指定定时任务的详情。

PUT /api/cron/jobs/{id}

更新定时任务(调度表达式、提示词、Agent 等)。

DELETE /api/cron/jobs/{id}

删除定时任务。

PUT /api/cron/jobs/{id}/enable

切换定时任务的启用状态。

请求体

{
  "enabled": false
}

GET /api/cron/jobs/{id}/status

获取定时任务的上次执行结果和下次预定时间。


中断正在运行的 Agent 轮次

源码: librefang-runtime/src/interrupt.rs

SessionInterrupt 是一个 Arc<AtomicBool> 信号,agent 循环在每个工具调用边界处检查它。设置该标志后,循环在当前工具调用完成后干净退出——不会强制终止线程或取消正在进行的网络请求。

级联到 agent_send 子 agent:父 agent 的 /stop 现在会传播到它通过 agent_send tool 派出的每个子 agent。级联沿着 agent_send 调用时建立的父→子边走,所以对面向用户的 agent 单次 /stop 会停掉它启动的整个 fan-out 树 — 用户放弃后不会有孤儿子 agent 循环继续。完全递归:子 agent 自己又调了 agent_send 的话继续向下传。

中断端点

POST /api/agents/{agent_id}/sessions/{session_id}/interrupt

无需请求体。信号被接受时响应 204 No Content

curl -X POST \
  "http://127.0.0.1:4545/api/agents/${AGENT_ID}/sessions/${SESSION_ID}/interrupt"

行为

场景发生的事情
Agent 在工具调用之间循环在下次边界检查时退出,记录截止当前的部分响应。
Agent 正在进行 LLM 调用LLM 调用正常完成,然后循环检查标志并在执行下一个工具前退出。
Agent 正在执行工具工具运行至完成,然后循环退出。不会在工具执行途中中止。
Agent 已经完成中断标志被忽略,不返回错误。
没有活跃轮次仍返回 204;标志被设置,将在下次轮次时生效。

自动清除

中断标志在以下情况下自动清除:

  • 新的传入消息开始新的 agent 轮次
  • 会话被重置

轮次中断结束后无需发送"恢复"或"清除"请求。

使用场景

  • 用户主动停止:用户在界面中点击"停止"按钮,前端调用中断端点,agent 在当前工具调用后停止。
  • 看门狗超时:外部监控检测到长时间运行的轮次,中断它以避免 token 预算耗尽。
  • 优雅关闭:重启守护进程前中断所有活跃会话,使其记录干净的停止状态而非突然断连。