HTTP API
🔵 服务器提供 HTTP 控制平面以及一个流式传输 Server-Sent Events (SSE) 的聊天端点。端点列表在启动时打印到日志中。
8.1 端点
页面与静态资源(公开)
| Endpoint | 描述 |
|---|---|
GET / |
markdown 站点(落地页) |
GET /site/ · GET /site/:page |
同一站点位于子路径下 |
GET /sessions · /budgets · /teams · /users · /cron · /workflows · /dashboard |
管理 UI |
GET /agents/:name |
单个代理页面 |
GET /widget · /widget.js · /dist/* |
小部件及其资源 |
GET /demo · /demo/overlay |
小部件演示 / 覆盖在真实站点上的浮层 |
GET /distrib/* |
发行版归档(linux/windows zip + sha256、android apk) |
GET /proxy?url=… · /proxy/content?url=… |
前端 HTTP 代理 |
GET /login · POST /login · POST /logout |
管理 UI 的 web 登录 |
GET /login/oidc/:provider · GET /login/oidc/:provider/callback |
管理 UI 的 OIDC 登录(Google/Яндекс/Тинькофф) |
GET /v1/login/methods |
已启用的 OIDC 提供方列表 |
GET /v1/login/widget/:provider · GET /v1/login/widget/:provider/callback |
小部件中最终用户的 OIDC 登录(popup) |
POST /v1/login/widget/password |
最终用户通过 auth.users 登录(签发 x-user-token) |
GET /v1/connectors/callback |
OAuth 连接器的回调(Google Drive 等) |
GET /v1/allowed-senders/:template · POST /v1/allowed-senders/:template |
发送方动态 allowlist(列表 · 添加)🔒 |
DELETE /v1/allowed-senders/:template/:identity |
从 allowlist 中删除发送方 🔒 |
公开 API
| Endpoint | 描述 |
|---|---|
GET /health |
healthcheck |
GET /v1/models |
可用模型 |
GET /v1/templates |
代理模板(welcome、tools;tools_declared/loaded/failed 和 hooks_* — 实际加载的内容) |
POST /v1/chat/completions |
与代理聊天(SSE,自有格式) |
POST /v1/continuations |
懒加载分页表格的下一页 |
POST /v1/uploads |
将附件(文件/截图/照片)上传到会话的 scratch 中 |
POST /v1/input-response |
对代理附件请求的响应(request_attachment) |
POST /v1/approval-response |
最终用户对 inline 审批的响应(小部件) |
POST /v1/sessions/:id |
关闭会话(公开 — 小部件发送 sendBeacon) |
POST /v1/inbound/:template |
来自外部系统的单次代理回合(JSON,可选 bearer) |
POST /v1/user-ticket |
签发 HMAC 签名的身份令牌 |
POST /v1/feedback |
对回答的 like/dislike |
POST /v1/workflows/:name/webhook |
工作流 webhook 触发器(由工作流令牌保护) |
/ext/**(自定义) |
http_route / static_route — 全局(config/routes/)或由代理(route_files:)添加的用户自定义 REST 端点与静态资源;路由上的 auth public/bearer/token_env/user(见 §21) |
管理 API 🔒
| Endpoint | 描述 |
|---|---|
GET /v1/agents · POST /v1/agents |
代理列表 · 创建代理 |
GET /v1/agents/:name |
单个代理的快照 |
DELETE /v1/agents/:pid |
杀死代理及其子代理 |
POST /v1/agents/:pid/signal |
steering:pause / resume / interrupt / terminate(body {"signal":"…"})🔒 |
POST /v1/agents/:pid/reset |
解除监督隔离(unpause + 删除 dead-letters)🔒 |
GET /v1/dead-letters?limit=N |
被隔离的代理输入(dead-letter) |
POST /v1/agents/:name/bench/run |
运行模板基准测试 |
GET /v1/agents/:name/bench/runs · /bench/runs/:id |
基准测试历史与详情 |
GET /v1/sessions |
会话列表(?user_id= — 单个用户的会话 + user_stats) |
GET /v1/sessions/:id · DELETE /v1/sessions/:id |
会话详情 · 关闭 |
GET /v1/budgets |
预算组与进程 |
GET /v1/machines · POST /v1/machines |
受管机器清单 · 创建/更新(模块 remote)🔒 |
GET /v1/machines/:slug · PUT /v1/machines/:slug · DELETE /v1/machines/:slug |
机器 · 更新(slug 来自路径)· 删除 🔒 |
GET /v1/kernels · POST /v1/kernels |
远程 Agent OS 内核注册表 · 创建/更新(模块 kernels)🔒 |
GET /v1/kernels/:slug · PUT /v1/kernels/:slug · DELETE /v1/kernels/:slug |
内核 · 更新 · 删除 🔒 |
GET /v1/kernels/:slug/health |
通过 HTTP 对远程内核进行健康探测 🔒 |
GET /v1/cron · DELETE /v1/cron/:name |
cron 任务与历史 · 删除 |
GET /v1/workflows · POST /v1/workflows/:name/run |
工作流 · 运行 |
GET /v1/workflows/runs/:id · /runs/:id/events |
工作流运行 · 其事件 |
GET /v1/dashboard |
系统仪表盘(负载、token、序列) |
GET /v1/feedback/stats |
评分统计 |
GET /v1/users |
渠道 → 用户映射(带别名/操作员备注) |
PATCH /v1/users/:id |
设置/清除规范用户的 {alias, note} |
POST /v1/users/link · POST /v1/users/:id/unlink |
合并/拆分身份 |
GET /v1/memory/:scope |
检查作用域长期记忆 |
GET /v1/hooks/metrics |
钩子指标:按 (hook, point) 的调用/panic/超时/耗时 |
GET /v1/circuit-breakers |
提供方 breaker 状态(status、failures、opened)+ 配置 |
POST /v1/circuit-breakers/:name/reset |
强制闭合已断开的 breaker |
GET /v1/approvals |
待审批队列(操作员 inbox) |
POST /v1/approvals/:request_id |
批准/拒绝 {approved, comment} |
GET/POST /v1/approvals/roles |
审批者的逻辑角色 · 创建/更新 |
DELETE /v1/approvals/roles/:name |
删除角色 |
POST/DELETE /v1/approvals/roles/:name/members… |
添加/删除角色成员 |
GET /v1/system/tree |
平台内省;按片段导航:?view=summary|modules|types|graph、?module=、?type=、?registry=(无参数 — 整棵树) |
GET /v1/system/modules · /registries · /types · /routes · /services |
内省切片 |
POST /v1/platform/modules/:id/enable · /disable |
启用/禁用模块(重启后生效) |
POST /v1/platform/restart |
重启服务器以应用模块集合 |
GET /v1/builder/agents |
代理配置列表(名称、是否有 agent.yaml、文件数、protected) |
GET /v1/builder/agents/:name |
包元数据:agent.yaml + 文件列表 {path,size}(不含内容) |
GET/PUT/PATCH/DELETE /v1/builder/agents/:name/file?path= |
单个文件:读取 · 写入(原始 body)· 替换行 {old,new,replace_all} · 删除 |
PUT /v1/builder/agents/:name |
创建/部分更新包(agent_yaml? 和/或 files?) |
DELETE /v1/builder/agents/:name |
删除代理目录 |
POST /v1/builder/agents/:name/yaml?path= |
对文件 {op,key,value} 进行 YAML 编辑,op = set|append|remove |
POST /v1/builder/validate |
不写入的包校验(包括检查每个文件 tool_files/hook_files 是否存在 kind) |
GET /v1/tools · GET /v1/tools/:name · POST /v1/tools/:name/call · POST /v1/tools/run |
工具注册表:列表 · 模式 · 按名称运行 · 运行 inline-YAML |
POST /v1/agents/:name/tools/:tool/call |
在代理 :name 的环境中执行工具(其 scope/state,若存活则 session),body {args} |
GET /v1/state/:scope/:id |
:id 的 scoped-state :scope(agent|user|session|team)键 |
GET/PUT/DELETE /v1/state/:scope/:id/:key |
读取 · 写入 {value} · 删除单个状态键 |
GET/POST /v1/teams · GET/DELETE /v1/teams/:id |
命令:列表(?user_id= — 用户命令 + 角色)· 创建 · 详情(成员+授权)· 删除(级联 state) |
POST/DELETE /v1/teams/:id/members… · /grants… |
团队成员与授权(管理员) |
POST/DELETE /v1/my/teams/:id/… |
团队 owner 自助管理(仅限自身授权范围内) |
GET /v1/docs |
文档目录(JSON 格式)(语言、章节/页面 {id,title}) |
GET /v1/docs/page?id=&lang= |
文档页面(markdown 格式){id,title,lang,markdown} |
GET /v1/bench/runs · /v1/bench/catalog |
所有模板的运行记录 · 已配置场景的模板 |
🔒 = 当配置了管理员认证时,需要 Authorization: Bearer <токен>
(见 §8.3)。
分页
列表类端点(/v1/sessions、/v1/agents、/v1/templates、
/v1/budgets)接受 ?limit=N&offset=M。limit — 页大小(截断至
1–1000,默认 100),offset — 跳过多少行(默认 0)。
响应包含 total(而 /v1/sessions — 还有 history_total)。/v1/sessions
当历史会话超过当前页时,添加 history_truncated: true。
8.2 Chat completions
POST /v1/chat/completions 以 Server-Sent Events(SSE)方式流式传输。路径和请求
形式与 OpenAI 类似,但响应格式是自定义的 — 它与
OpenAI-SDK 不兼容(没有 choices[].delta,没有 data: [DONE])。
curl http://127.0.0.1:3000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "ngu-agent",
"messages": [{"role": "user", "content": "Как поступить в НГУ?"}]
}'
请求字段:
| 字段 | 必填 | 含义 |
|---|---|---|
model |
是 | 模板名称(ngu-agent、drom-agent、……)或内置的 assistant |
messages |
是 | {role, content} 列表;进入上下文的是 user 和 system 角色 |
session |
否 | 会话令牌 — 一个会话 = 一个隔离的 agent。省略则进入 legacy 模式(模板的共享 agent) |
attachments |
否 | 已通过 POST /v1/uploads 上传到会话 scratch 的 [{name, mime, size}] 文件列表 — 服务器会注入一条包含其描述的消息 |
stream |
否 | 为兼容性而接受,被忽略 — 始终流式传输 |
temperature |
否 | 接受,被忽略 |
max_tokens |
否 | 接受,被忽略 |
请求头 X-User-Id 为 per-user 预算和记忆作用域设置 user_id。
当配置了 auth.web_user_secret_env 时,服务器要求 HMAC 签名的
X-User-Token(来自 POST /v1/user-ticket);见 §8.8。
响应(SSE 事件)
响应体是命名 SSE 事件流;done 是唯一始终存在的事件。
event |
载荷 data |
|---|---|
token |
{"content": "<токен>", "final": bool} |
tool_call |
{"name": "<инструмент>", "body": "<рендер вызова>"} |
tool_progress |
{"name": "<инструмент>", "body": "<прогресс>"} |
tool_result |
{"name": "<инструмент>", "body": "<рендер результата>"} |
result_blocks |
`{"name": "<инструмент>", "blocks": [ {type: "text" |
input_request |
{"request_id": "<id>", "kind": "file"|"screenshot"|"photo", "description": "..."} — agent 请求附件;通过 POST /v1/input-response 回复 |
budget |
{"tokens": n, "prompt": n, "completion": n, "cached": n, "total": n, "cost": "$x.xxxx"} |
done |
{} — 流已结束 |
result_blocks 承载工具的可视化层(图表、表格、文本、
文件);table 块可以包含 continuation: {id} — 使用该 id 的 POST /v1/continuations
会返回下一页的块,而 file 块承载 name、mime 和
data(base64)以供下载。见公共字段。
错误(未知模型、会话错误、预算耗尽、rate-limit)
以 token 事件的形式在 200 内报告,而不是通过 HTTP 错误码。
8.2.1 附件(uploads / input-response)
将用户文件(widget、Android)上传到会话的 scratch 目录 —
POST /v1/uploads(multipart/form-data):
model— 模板名称(必填);session_id— 会话令牌(可选,否则自动生成);file— 一个或多个文件(file部分)。
响应为 {"session_id": "...", "files": [{"name", "mime", "size"}, …]}。
文件写入 <scratch>/<session>/,之后 agent 按名称读取它们
(file_tool temp、shell_tool {{temp_dir}}、vision_tool)。会考虑
模板的 attachments.enabled/max_size;当附件被禁用时 — 400。
Agent 的附件请求(工具 request_attachment)以 SSE 事件
input_request 的形式到达;widget 显示提示,用户附加文件,
文件通过 /v1/uploads 上传,之后 widget 解析该请求:
curl http://127.0.0.1:3000/v1/input-response \
-H 'Content-Type: application/json' \
-d '{"request_id": "<id>", "files": [{"name": "photo.jpg", "mime": "image/jpeg", "size": 12345}]}'
空的 files = 用户拒绝。未知/过期的 request_id
— 404;默认等待 300 秒(工具的 timeout_secs 字段)。
8.2.2 注意力(attention)与 push
当 agent 调用 notify_tool(或触发 push 同步)时,服务器
向该用户所有已连接的客户端发布注意力事件。
GET /v1/attention/stream — 长生命周期的注意力事件 SSE 流
(x-user-id / x-user-token,与聊天相同)。客户端(Android 前台服务、
Web widget)保持连接并自行绘制通知;这是 live 路径。
event: attention
data: {"title":"...","body":"...","level":"alert","require_ack":false,"session_id":"...","template":"...","channels":[]}
level 级别:silent | notify | alert | alarm | call。alarm/call
(或 require_ack: true)表示“重复直到确认” — Android
显示全屏闹钟/来电,widget — 带声音的横幅。
| 方法 | 路径 | 含义 |
|---|---|---|
GET |
/v1/attention/stream |
用户的注意力 SSE 流 |
POST |
/v1/push/register |
{kind, endpoint} — 注册设备的 push-endpoint(UnifiedPush/ntfy)用于 wakeup |
POST |
/v1/push/unregister |
{kind, endpoint} — 删除 endpoint |
如果在发布时刻没有任何 live 订阅者,服务器会向
已注册的 endpoint 发送 wakeup(不经过 Google — 通过 UnifiedPush/ntfy),被杀死的
应用会醒来并显示通知。详情与示例 —
config/agents/notify-demo/README.md。
8.3 Auth
🔒 端点接受 Authorization: Bearer <токен>(用于 API 客户端),
或 cookie agentos_session(用于 web 登录后的浏览器)。
- Bearer 令牌 — 来自
auth.admin_tokens(config/server.yaml中的имя → токен映射) 或auth.admin_token_env(имя=токен列表)。 令牌名称会写入 access 日志以供审计。 - Web 登录 — 来自
auth.users(логин → пароль)。POST /login校验 凭据并设置HttpOnlycookie(12 小时);登录会写入 access 日志。POST /logout清除 cookie。浏览器 UI(/sessions、/budgets) 在 401 时重定向到/login。 - OIDC 登录 —
GET /login/oidc/:provider启动 Authorization Code + PKCE 通过外部提供商的流程(Google/Яндекс/Тинькофф,配置auth.oidc); callback 交换 code,拉取 userinfo 并将身份与授权auth.oidc.grants(subject / email / email_domain)进行匹配。成功——与密码登录相同的 session-cookie。没有授权——登录被拒绝。
如果 auth 已配置,但没有任何 credential 被允许——管理 API 对每个请求 返回 401(fail-closed)。没有令牌和用户时,管理 API 是开放的 (dev 模式)。
# API-клиент (bearer)
curl -H 'Authorization: Bearer <token>' http://127.0.0.1:3000/v1/sessions
# Web-логин (браузерный поток)
curl -c cookies.txt -H 'Content-Type: application/json' \
-d '{"username":"admin","password":"<password>"}' \
http://127.0.0.1:3000/login
curl -b cookies.txt http://127.0.0.1:3000/v1/sessions
8.4 嵌入小组件
<script src="http://127.0.0.1:3000/widget.js"></script>
小组件由 /widget 提供,与 /v1/chat/completions 通信,并通过 POST /v1/sessions/:id(sendBeacon)
关闭会话。小组件的完整解析
(配置、模型选择、演示)——见 §19。
8.5 代理
/proxy 和 /proxy/content 为前端下载 URL。限制:
- 仅
http/https,端口 80/443; - 主机仅来自
proxy.allow_hosts(当列表非空时); - 私有、loopback、link-local 和 reserved 范围(包括
169.254.169.254)始终被阻止,在每次重定向时。
8.6 健康检查
curl http://127.0.0.1:3000/health
8.7 HTTPS / TLS
设置 AGENT_OS_TLS_CERT 和 AGENT_OS_TLS_KEY(PEM 路径)——服务器将启用
HTTPS。否则——在 AGENT_OS_BIND 上使用普通 HTTP(默认 127.0.0.1:3000)。
8.8 传入 webhook 与身份
传入 webhook
POST /v1/inbound/:template —— 外部系统(CRM、ERP、监控、表单
后端……)启动一次 agent 运行并同步读取响应——无 SSE,无
messages 数组。
curl -X POST http://127.0.0.1:3000/v1/inbound/ngu-agent \
-H 'Content-Type: application/json' \
-d '{"message":"какие общежития у НГУ?","session_id":"crm-123"}'
请求:
| 字段 | 必填 | 含义 |
|---|---|---|
message |
是 | 用户消息 |
session_id |
否 | 用于复用上下文的稳定 id;省略 = 新会话 |
user_id |
否 | 最终用户的身份(Origin::Webhook);省略 = 匿名 |
响应:{"answer": "...", "status": "success", "session_id": "...", "cost_usd": 0.0, "prompt_tokens": n, "completion_tokens": n, "data": null}。
Auth —— 在设置了 inbound.token_env 时使用 bearer 令牌(空 = 开放,dev)。
最终用户身份令牌
当 auth.web_user_secret_env 指向带有 HMAC 密钥的 env 时,小组件会获得
签名令牌,并将其作为 X-User-Token 发送,而不是自报的
X-User-Id:
curl -X POST http://127.0.0.1:3000/v1/user-ticket \
-H 'Content-Type: application/json' -d '{"user_id":"cw-browser-id"}'
# → {"user_id":"cw-browser-id","token":"cw-browser-id.<hmac>"}
没有密钥时,服务器直接信任 X-User-Id(dev 模式)。
用户规范身份
GET /v1/users 列出 (origin, external_id) → canonical_id 的对应关系;
操作员可以合并两个渠道 id(例如 web-id 和 Telegram-id),使
它们共享记忆、预算和状态:
curl -X POST http://127.0.0.1:3000/v1/users/link \
-H 'Authorization: Bearer <token>' \
-d '{"survivor":"cw-browser-id","merged":"tg:123"}'
合并会迁移 scoped state store、长期记忆和内存预算桶;
两个渠道后续的会话都会解析为 survivor。
8.9 反馈(feedback)
小组件将回答评分(like / dislike / cleared)发送到 POST /v1/feedback
(公开),而统计数据发送到 GET /v1/feedback/stats(🔒)。
评分闭合质量循环:memory 钩子在点赞/点踩时提升/降低
本次运行中回忆起的 importance 事实(§6.6)。请求体包含
value、user_text、session。