增加调试前端页面

This commit is contained in:
andy committed 2026-09-06 00:25:25 +08:00
1 parent 3080b17d02
commit ee9d2d7cf1
22 files changed
+1442 -59

No files matched your search

+216
View File
@@ -0,0 +1,216 @@
# fire-safety-ymd 测试对话页面 v1 Spec
| 项 | 内容 |
| --- | --- |
| 状态 | Implemented locally;测试服务器公网部署待验收 |
| 日期 | 2026-09-06 |
| 负责人 | fire-safety-ymd 后端 |
| 关联接口 | `POST /api/v1/apps/{app_id}/completion` |
| 关联配置 | `FIRE_SAFETY_CHAT_PAGE_ENABLED` |
## 1. 背景
项目已有 DashScope 风格的兼容对话接口。SuperAgent、数据库和公网 MCP 联调时,使用者需要
一个无需另建前端工程的最小浏览器页面,用来输入问题、观察 SSE 结果并验证同一会话的后续轮次。
这个页面只服务于测试和受控联调,不改变既有第三方请求契约,也不提供真实用户登录或授权。
## 2. 目标
- 由 Go 服务可选地提供 `GET /chat` 和 `GET /chat/` 两个页面入口,并提供同源的 CSS/JavaScript 资源。
- `FIRE_SAFETY_CHAT_PAGE_ENABLED` 默认值为 `false`;关闭时两个入口都返回 HTTP 404。
- 开启时页面使用与第三方完全相同的兼容对话请求:
`POST /api/v1/apps/{FIRE_SAFETY_CHAT_COMPAT_APP_ID}/completion`。
- 页面让用户手动输入 `xtoken`,在当前页面内发起 SSE 请求,不把凭证写入页面源码、Cookie、
URL、localStorage、sessionStorage 或服务端配置。
- 页面保存上一轮成功响应的 `output.session_id` 仅在 JavaScript 内存中,并将它用于同一页面的
后续轮次。
- 页面能区分 SSE 的中间会话事件、最终 `finish_reason=stop`、上游错误和 HTTP 错误。
- Nginx 公网入口固定反代 `/chat`、`/chat/`、`/chat/app.css`、`/chat/app.js` 和兼容 `completion` 路径;是否实际提供页面由 Go
配置开关决定。
## 3. 非目标
- 不实现注册、登录、JWT、SSO、角色、租户或最终用户级动态授权。
- 不把静态测试 `xtoken` 写入 HTML、JavaScript 常量、Nginx、镜像或 Git。
- 不持久化 Token、问题、答案、聊天历史或会话映射;刷新页面后不自动恢复会话。
- 不新增一套页面专用的聊天协议、Provider Session 或数据库访问接口。
- 不实现逐字流式动画、文件上传、图像、地图选点、后台任务或多实例共享会话。
- 不把页面公开等同于公网生产能力;页面和当前 Chat 兼容 API 都只适用于受控联调。
## 4. 路由与开关
| 路由 | 开关关闭 | 开关开启 | 说明 |
| --- | --- | --- | --- |
| `GET /chat` | 404 | 308 到 `/chat/` | 页面规范化入口 |
| `GET /chat/` | 404 | 200 `text/html` | 页面入口 |
| `GET /chat/app.css` | 404 | 200 `text/css` | 页面样式资源 |
| `GET /chat/app.js` | 404 | 200 `text/javascript` | 页面脚本资源 |
| `POST /api/v1/apps/{app_id}/completion` | 按 Chat/Compat 配置 | 按 Chat/Compat 配置 | 页面和第三方共用 |
页面开关为 Go 进程启动时读取的配置。修改 `.env` 后必须重新创建 Compose 容器;仅执行
`docker compose restart` 不会把新的环境值加载进已有容器。Nginx 可以始终保留四个页面/资源的
精确反代 location,但 Go 关闭页面时必须返回 404。
当页面开启时,以下依赖也必须满足:
- `FIRE_SAFETY_CHAT_ENABLED=true`;
- `FIRE_SAFETY_CHAT_COMPAT_APP_ID` 非空且与 Nginx 的精确 completion location 一致;
- `FIRE_SAFETY_CHAT_AUTH_TOKEN` 已配置为 Chat 方向的测试凭证;
- `FIRE_SAFETY_CHAT_ALLOWED_ORIGINS` 包含精确值 `https://agent.nianxx.com`;
- SuperAgent 的服务端配置和 MCP 联调配置按对应 Spec 已完成。
页面请求不向 Go 发送身份、角色、区域、租户、Provider Session 或 metadata。页面中出现的
App ID 是公开路由标识,不是 Secret;Chat Token、MCP Bearer 和 SuperAgent Open API Key
必须分别使用不同值。
## 5. 页面行为
页面至少包含:Token 输入框、问题输入框、发送按钮、清空当前会话按钮、运行状态和结果区域。
Token 输入框默认为空,推荐使用密码输入类型;页面不得从 URL、Cookie 或浏览器存储预填。
用户发送问题时,页面使用浏览器 `fetch`(不能使用无法设置自定义 Header 的 `EventSource`)向
同源兼容路径发送:
```http
POST /api/v1/apps/<public-app-id>/completion
Origin: https://agent.nianxx.com
xtoken: <用户本次手动输入的测试 Token>
Content-Type: application/json
Accept: text/event-stream
```
首轮请求体:
```json
{
"input": { "prompt": "观水镇附近有哪些地点候选?" },
"parameters": {}
}
```
后续请求体把同一页面内最近一次成功返回的本地会话 ID 放入 `input.session_id`:
```json
{
"input": {
"prompt": "选择第 2 个,再查询附近水源。",
"session_id": "conv_<previous-result>"
},
"parameters": {}
}
```
页面必须逐个读取 `event: result` 的 SSE 数据:
1. 首个结果一般只包含 `output.session_id` 和 `finish_reason="null"`;页面保存会话 ID,但不把
该事件显示为最终答案。
2. 只有收到同一会话的 `finish_reason="stop"` 且带 `output.text` 时,页面才显示为成功。
3. `event: error`、非 2xx HTTP 响应、解析失败或没有收到 `stop` 时,页面显示失败,不把部分
文本当成可信答案,也不继续复用一个结果未知的会话。
4. 用户点击清空、刷新页面、关闭页面或新开页面时,页面内存中的 Token 和 `session_id` 都丢弃。
页面不应把工具名、工具参数、Provider Session、内部 Trace 或数据库敏感字段直接作为调试
信息展示。最终回答仍是 SuperAgent 辅助内容,不能替代报警、人员撤离、现场核验或现场指挥。
## 6. Origin、Nginx 与安全边界
- 页面与 API 均从 `https://agent.nianxx.com` 提供,因此浏览器的 `Origin` 必须命中 Go 的精确
`FIRE_SAFETY_CHAT_ALLOWED_ORIGINS` 项;不得用 `*` 代替。
- Nginx 只负责 TLS、精确路径、限流、SSE 传输和反代,不比较、注入、记录或保存 `xtoken`。
- `/chat` 和 `/chat/` 页面 GET 本身不依赖 Token;真正的兼容 completion 请求仍由 Go 校验
`xtoken`。页面公开可访问不代表 API 无鉴权。
- 页面不会把 Token 放入 Referer、查询参数、片段、日志或错误消息。输入框可被浏览器用户读取,
所以 Token 只能是受控测试凭证,不能作为最终用户身份。
- 页面表单显式使用 POST,CSP 使用 `form-action 'none'`;JavaScript 不可用时页面显示警告,
不允许浏览器把 Token 或问题退化提交到 URL。
- 当前页面和兼容 API 的会话是单进程内存映射;Docker 重建、进程重启或多实例切换会使旧
`session_id` 失效。
- 不通过页面对外暴露 `/api/chat`、数据库、迁移命令或其他 Go 路由;Nginx 未列出的路径仍返回 404。
## 7. 验收标准
### 配置与路由
- Given 未设置 `FIRE_SAFETY_CHAT_PAGE_ENABLED`,When 请求 `/chat`,Then 返回 404;When 请求
`/chat/` 或两个资源路径,Then 均返回 404,且不创建 SuperAgent Run。
- Given `FIRE_SAFETY_CHAT_PAGE_ENABLED=true` 且依赖配置完整,When 请求 `/chat`,Then 返回 308
到 `/chat/`;When 请求 `/chat/`、`/chat/app.css` 和 `/chat/app.js`,Then 分别返回 200 HTML、
CSS 和 JavaScript。
- Given 页面开启但 `FIRE_SAFETY_CHAT_ALLOWED_ORIGINS` 不含 `https://agent.nianxx.com`,Then
配置校验失败或浏览器 completion 请求被精确 Origin 拒绝;不得放行通配符。
- Given 页面关闭,When Nginx 仍保留 `/chat`、`/chat/` location,Then Go 返回 404,Nginx 不应
把它们改成 DashScope 或其他 upstream。
### 浏览器与兼容接口
- Given 页面打开且用户手动输入合法测试 Token,When 发送首轮问题,Then 请求体和 Header 与
第三方 completion 请求相同,并收到 `event: result`。
- Given 首轮最终事件为 `finish_reason="stop"`,When 用户发送第二个问题,Then 请求使用同一页面
内存中的 `input.session_id`,服务端复用会话。
- Given 用户刷新页面,When 再次发送问题,Then 页面不提交旧的 `session_id` 或 Token。
- Given 错误或空 Token,When 发送问题,Then 服务返回 401;页面不展示或记录 Token。
- Given SSE 只有初始 `null` 事件、发生断流或最终不是 `stop`,Then 页面不显示为成功。
### 公网部署
- Given 服务器 Compose 已重建且 Nginx 已通过 `nginx -t` 并 reload,When `curl -i` 请求公网页面,
Then 开关关闭时四个页面路径均返回 404;开启时 `/chat` 返回 308,`/chat/` 返回 200 `text/html`,
两个资源路径返回 200。
- Given 页面开启,When 浏览器从 `https://agent.nianxx.com/chat/` 发起 completion,Then 服务端
日志可按现有脱敏规则确认 Chat 请求,且不含 Token、问题、答案或会话内部 ID。
- Given 已知公网 MCP 地点搜索曾记录
`operation=fire_safety_search_place_candidates result=success`,Then 该证据只证明地点搜索
已到达并成功;`tools/list` 之外的完整多工具链仍需单独验收。
## 8. 运行与回滚
页面开关变更只修改服务器未提交的 `.env`,不修改 Nginx 中的 Token:
```text
# 默认关闭
FIRE_SAFETY_CHAT_PAGE_ENABLED=false
# 测试开启时
FIRE_SAFETY_CHAT_PAGE_ENABLED=true
FIRE_SAFETY_CHAT_ALLOWED_ORIGINS=https://agent.nianxx.com
```
重新加载运行环境:
```bash
cd /home/firee-safety-ymd
docker compose config --quiet
docker compose up -d --force-recreate --no-build
docker compose ps
curl --fail http://127.0.0.1:16587/health
```
页面验收:
```bash
curl -i https://agent.nianxx.com/chat/
curl -i https://agent.nianxx.com/chat
curl -i https://agent.nianxx.com/chat/app.css
curl -i https://agent.nianxx.com/chat/app.js
```
关闭页面时预期 `/chat`、`/chat/` 以及两个资源均直接为 HTTP 404;开启页面时
预期 `/chat` 为 HTTP 308、跟随后 `/chat/` 为 HTTP 200 `text/html`,两个资源也为 HTTP 200。
使用 `curl -iL https://agent.nianxx.com/chat` 可直接跟随规范化重定向。浏览器
打开 `https://agent.nianxx.com/chat/`,手动输入受控测试 Token,发送不含敏感信息的问题,
再发送第二轮问题确认会话复用。
回滚优先使用配置回滚:把 `FIRE_SAFETY_CHAT_PAGE_ENABLED` 改回 `false`,执行
`docker compose up -d --force-recreate --no-build`,确认 `/chat`、`/chat/` 和两个资源路径都直接
返回 404,之后按需继续保留
兼容 completion 或将其一并关闭。若是版本回滚,切回维护者指定的已验证 revision 后重建;若是
Nginx 配置回滚,恢复 root-only 备份,先执行 `nginx -t` 再 reload。不得通过恢复全路径 `/`、
关闭 Go 鉴权或把 Token 写进 Nginx 解决问题。
## 9. 相关文档
- [`../architecture/public-chat-entry-v1.md`](../architecture/public-chat-entry-v1.md)
- [`../workflows/user-chat.md`](../workflows/user-chat.md)
- [`../project/operations/docker-test-deployment.md`](../project/operations/docker-test-deployment.md)
- [`../project/operations/nginx-public-entry.md`](../project/operations/nginx-public-entry.md)
- [`fire-safety-ymd-dashscope-compatible-chat-v1.md`](fire-safety-ymd-dashscope-compatible-chat-v1.md)