增加调试前端页面
This commit is contained in:
1 parent
3080b17d02
commit
ee9d2d7cf1
22 files changed
+1442
-59
No files matched your search
@@ -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)
|
||||
Reference in new issue
Block a user