宿主的 WebUI 与 HTTP 接口由 ASP.NET Core Minimal API 提供,默认监听 0.0.0.0:<WebUiPort>(配置项 WebUiPort,默认 1025),本机访问即 http://127.0.0.1:1025。
绑定 0.0.0.0 是为了局域网内可用;不要把端口直接暴露到公网。
| 方式 |
用法 |
| Cookie |
登录后下发 session_token(HttpOnly / SameSite=Lax / Path=/;勾选"记住我"时有效期 30 天,否则为会话级) |
| Bearer |
请求头 Authorization: Bearer <session_token>(脚本/命令行调用方便) |
会话 token 是进程级单一值:重启宿主后旧凭证全部失效。
是否启用认证取决于配置里的 WebUiPassword;首次启动若为空,宿主会自动生成 16 位随机密码并只打印到控制台(不写日志、不进环形缓冲)。
/login /app.css /app.js /css/* /js/*
/api/auth* /api/theme-cfg /background
其余路径必须带凭证:/api/* 未认证返回 401 + {"error":"unauthorized"};非 /api 路径未认证则 302 重定向到 /login。
POST /api/auth/login # 免认证
Content-Type: application/json
{ "password": "控制台打印的密码", "remember": true }
- 成功:
{"ok":true} 并下发 session_token Cookie
- 失败:
{"ok":false,"error":"密码错误"}
- 失败退避:按来源 IP 计数,前 2 次立即返回,之后
2^(n-2) 秒(上限 300 秒);退避期内返回 {"ok":false,"error":"失败次数过多,请 N 秒后再试"}
- 密码用 SHA256 十六进制 + 定长时间比较,避免计时侧信道
POST /api/auth/logout # 清 Cookie
GET /api/auth/status # → {"authRequired":true|false}
认证列:免 = 白名单免认证;✓ = 需要凭证。
| 方法 |
路径 |
认证 |
说明 |
| GET |
/ |
✓ |
主页面(WebUi/index.html,注入资源指纹后返回) |
| GET |
/login |
免 |
登录页 |
| GET |
/app.js |
免 |
按 UiAssets 顺序合并后的 JS 单文件(带 ETag、Cache-Control: no-cache) |
| GET |
/app.css |
免 |
合并后的 CSS 单文件(同上) |
| GET |
/css/*、/js/* |
免 |
磁盘上的原始模块文件(<exe旁>/WebUi/) |
| 方法 |
路径 |
认证 |
说明 |
| GET |
/api/theme-cfg |
免 |
→ {uiOpacity, ctlOpacity, bgOpacity, hasBackground} |
| POST |
/api/theme-cfg |
免 |
请求体 {uiOpacity?, ctlOpacity?, bgOpacity?}(0–100,自动 clamp)→ {ok, …三个当前值} |
| GET |
/background |
免 |
背景图(按扩展名给 image/png、image/webp,其它按 image/jpeg);未设置返回 404 |
| POST |
/background |
✓ |
上传背景图(multipart/form-data,字段 file)→ {ok:true};仅支持 jpg/png/webp(gif 按原扩展存近似)、≤15MB |
| DELETE |
/background |
✓ |
删除背景图 → {ok:true};未设置时 {ok:false,error:"未设置背景"} |
| 方法 |
路径 |
认证 |
说明 |
| GET |
/api/status |
✓ |
→ {connected, selfId, wsUrl, transport, startedAt, uptimeSec};transport 为 onebot / official |
| GET |
/api/logs?after=N |
✓ |
增量拉日志 → {next, lines:[{id,t}]},把 next 作为下次的 after |
| POST |
/api/logs/clear |
✓ |
清空环形缓冲 → 200 空响应(非 JSON) |
| GET |
/api/deps |
✓ |
→ {napcatConfigured, llbotConfigured, napcatRunning, llbotRunning, connected} |
| 方法 |
路径 |
认证 |
说明 |
| POST |
/api/start-connect |
✓ |
请求体 {start:"napcat"|"llbot"|"none"}:按需拉起进程并尝试连接 → {ok, connected, message}(message 是分号拼接的说明,如"已启动;正在连接…") |
| POST |
/api/connect |
✓ |
手动重连(后台进行,结果轮询 /api/status)→ {ok:true, message:"正在连接…"} |
| 方法 |
路径 |
认证 |
说明 |
| GET |
/api/plugins |
✓ |
插件快照数组:{name, version, desc, loaded, autoLoad, source, model}(source=ai/manual/handmade) |
| POST |
/api/plugins/rescan |
✓ |
重新扫描 plugins/ 目录(识别手工拷进来的插件) |
| POST |
/api/plugins/upload |
✓ |
multipart/form-data,字段 file,仅接受 .zip(插件目录打包;包内可含多个插件)→ {ok, …} |
| POST |
/api/plugins/{name}/{action} |
✓ |
action 仅 load / unload / reload → {ok};插件名非法返回 {ok:false,error:"插件名非法"} |
| GET |
/api/plugins/{name}/settings |
✓ |
→ {loaded, defs:[{Key,Label,Type,Default,Description,Options}], values:{…}} |
| POST |
/api/plugins/{name}/settings |
✓ |
请求体为键值对象(只提交要改的键)→ {ok, error};保存后宿主回调插件的 OnSettingsChangedAsync() |
| 方法 |
路径 |
认证 |
说明 |
| GET |
/api/personas/files |
✓ |
→ {files:[…]}(Agent/personas/*.md,已排序) |
| GET |
/api/personas/file?file=xxx.md |
✓ |
→ {ok, text}(文件不存在时 ok:false、text 为空) |
| POST |
/api/personas/file |
✓ |
请求体 {file, text}:保存/新建(file 自动补 .md,只取文件名防路径穿越)→ {ok, file} |
| DELETE |
/api/personas/file?file=xxx.md |
✓ |
→ {ok:true}(不存在也算成功) |
| 方法 |
路径 |
认证 |
说明 |
| POST |
/api/command |
✓ |
请求体 {text:"!plugin list"};必须带命令前缀;WebUI 视为管理员通道 → {message} |
| POST |
/api/test-model |
✓ |
请求体 {apiKey, baseUrl, model}(三者可省,缺省取 Agent 插件设置)→ 成功 {ok:true, reply, model},失败 {ok:false, error};baseUrl 必须是 http(s):// 开头 |
| GET |
/api/instructions |
✓ |
→ {text}:当前 Agent 指令(人格)正文 |
| POST |
/api/instructions |
✓ |
请求体 {text, reload?};reload=true 时顺带重载 Agent 插件 → {ok, reloaded} |
| 方法 |
路径 |
认证 |
说明 |
| GET |
/api/config |
✓ |
返回配置;密码类字段只回标志位(webUiPasswordSet),不回显 AppSecret 等机密 |
| POST |
/api/config |
✓ |
请求体为要改的字段(transport / officialAppId / officialSandbox / officialRegisterCommands / 连接与命令等);→ {ok, wsChanged, reloaded, transportChanged} |
约定:
- 机密字段留空即保持原值,传
"-" 表示清空(AppSecret 等)
transport 变更下次启动生效(响应里 transportChanged:true,前端会提示"需重启")
wsChanged 为 true 时宿主会立即尝试重连
BASE=http://127.0.0.1:1025
# 1) 登录拿 Cookie(脚本里也可以改用 Bearer)
curl -s -c cj.txt -H 'Content-Type: application/json' \
-d '{"password":"控制台打印的密码","remember":true}' $BASE/api/auth/login
# 2) 增量拉日志(先 after=0,之后用上次返回的 next)
curl -s -b cj.txt "$BASE/api/logs?after=0"
# 3) 装插件(zip 里可以是多个插件目录)
curl -s -b cj.txt -F "file=@FlexBot-BuiltInPlugins-1.0.0.zip" $BASE/api/plugins/upload
# 4) 重载某个插件
curl -s -b cj.txt -X POST $BASE/api/plugins/Agent/reload
# 5) 改插件设置(只提交要改的键)
curl -s -b cj.txt -H 'Content-Type: application/json' \
-d '{"NotifyToolCalls":"false"}' $BASE/api/plugins/Agent/settings
# 6) 执行宿主/插件命令(必须带前缀,WebUI 视为管理员)
curl -s -b cj.txt -H 'Content-Type: application/json' \
-d '{"text":"!plugin list"}' $BASE/api/command
# 7) 读配置 / 改通道(改通道需重启生效)
curl -s -b cj.txt $BASE/api/config
curl -s -b cj.txt -H 'Content-Type: application/json' \
-d '{"transport":"official","officialAppId":"1905767608"}' $BASE/api/config
- 业务结果多为 HTTP 200 +
{"ok":true|false, …};失败时带 error 文字(例如 {"ok":false,"error":"仅支持 .zip(把插件目录打包成压缩包上传)"})。
- 401 仅用于未认证的
/api/*;非 API 路径未认证是 302 → /login。
- 少数 GET 直接返回数组或原始文件流(
/api/plugins、/api/personas/files、/background)。
- 日期时间统一字符串
yyyy-MM-dd HH:mm:ss;uptimeSec 为秒数。
WebUI 的资源不在程序里内嵌,而是每次请求从 <exe旁>/WebUi/ 读盘:
/app.js、/app.css 由 UiAssets 清单里的模块按序合并而成(JS 拼接成单文件,避免模块顺序问题);
- 两个合并资源都带
ETag 与 Cache-Control: no-cache,If-None-Match 命中返回 304;
- 页面(
index.html / login.html)里的 app.css?v= / app.js?v= 会被替换成资源指纹(各文件 size/mtime 的 SHA256 前 8 位);
- 因此改完
WebUi/ 下的文件刷新浏览器即生效(指纹变了会拉新资源),不需要重新构建或重启宿主。
例外:新增/删除 UiAssets 清单里的条目属于 C# 侧改动,需要重新构建宿主。