Files
memind/docs/regression-guards/h5-session-stream-replay.md

63 lines
3.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# H5 会话 SSE 断线续播守卫
## 症状
后台 `h5_agent_runs` 已经是 `succeeded`、Goose 也已发送 `Finish`,但 H5 输入区仍显示“正在执行任务…”。常见触发条件是手机切后台、锁屏或网络切换发生在 `ActiveRequests``Finish` 之间。
## 根因
Portal 对 SSE 帧使用本地持久化游标。该游标可能是 Portal 生成的 UUID,并不一定是 Goose 能识别的上游事件 ID。若重连时把 Portal UUID 原样作为 `Last-Event-ID` 发送给 Goose,Goose 无法续播,浏览器就收不到遗漏的 `Finish`
## 必须保留的行为
1. Portal 游标只用于查询 `h5_session_stream_events`,不得原样传给 Goose。
2. 连接 Goose 时,只能使用已持久化的 `upstream_event_id`
3. 当前游标或重放尾部没有可用 `upstream_event_id` 时,必须省略 `Last-Event-ID`,让 Goose 从权威事件流重新回放。
4. 本地重放最后一条已经是 `Finish``Error` 时,不再连接 Goose。
5. 重放不得破坏现有消息 ID 合并、Finish 幂等计费和 MindSpace Finish 同步守卫。
## 视觉工具故障旁路
文本模型可能在会话历史中遇到 `read_image` 返回的图片块,并以
`unknown variant image_url, expected text` 拒绝整次请求。图片检查属于可选增强,
不得因此中断页面编辑、写文件、发布或其它文本主任务。
必须保留:
1. 将该上游错误分类为 `SESSION_VISUAL_CONTEXT_UNSUPPORTED`,不得作为普通瞬时错误盲重试。
2. 用干净会话恢复可见文本上下文,并移除新会话策略中的 `read_image`,明确要求 Agent 跳过视觉检查、继续主任务。
3. 一次执行中允许先恢复污染的工具历史,再单独进行一次视觉降级恢复;两个原因不得共用同一个“一次性恢复”开关。
4. 普通重试前必须取消旧会话的活动请求,避免后续请求被 `Session already has an active request` 锁死。
5. 视觉降级只影响当前恢复会话,不得全局关闭图片能力,也不得删减其它开发工具或数据能力。
## 关键路径
- `session-stream.mjs`
- `session-stream-store.mjs`
- `session-reply-wait.mjs`
- `agent-run-gateway.mjs`
- `capabilities.mjs`
- `tkmind-proxy.mjs`
- `server/portal-session-routes.mjs`Portal Session 路由、流中 public HTML 落盘与 Finish 后同步)
- `src/hooks/useTKMindChat.ts`
## 回归测试
```bash
node --test session-stream.test.mjs session-stream-store.test.mjs chat-agent-run-gate.test.mjs
node --test --test-name-pattern='proxySessionEvents' tkmind-proxy.test.mjs
node --test session-reply-wait.test.mjs capabilities.test.mjs agent-run-gateway.test.mjs tkmind-proxy.test.mjs
npm run verify:h5-session-patches
node --test billing-session-concurrency.test.mjs
```
必须覆盖:
- Portal 游标存在但 `upstream_event_id` 为空时,不向 Goose 发送错误游标,并能收到 `Finish`
- 有映射时,Portal 游标正确转换成 Goose 游标。
- 多轮会话中选择最新可映射的上游游标,不被上一轮 Finish 截断。
- Finish 重放不重复扣费,消息合并与页面同步守卫继续通过。
- `image_url` 不兼容时切换到无 `read_image` 的干净会话,并继续文本主任务。
- 工具历史恢复后仍可执行一次独立的视觉降级恢复。
- 瞬时重试前先取消旧请求,避免活动请求冲突。