fuzhengwei / fuzhengwei/WaLiAPI
流式生成内容持久化(stream_segments 溢出表)+ Responses 断线续传回放
- Dominant language
- Rust
- Stars
- 128
- Forks
- 39
- Avg merge
- 15h 25m
- Merged PRs (30d)
- 44
Description
### 现状
流式守卫(首帧/空闲超时、取消也落账)已完整,但**生成内容没有以可寻址方式持久化**:连接断开后已生成部分随内存消亡——用户刷新页面进度全丢、管理员无从查证生成了什么。Responses 协议虽有天然可续传语义(response.id),网关未利用。另:现状仅部分路径累计 `response_choices`(且 64KB 截断),Responses 流完全无内容记录。
### 方案
**第一档(全协议)**:
- `stream_segments` 溢出表(log_id+seq 主键):**detailed 日志策略**下流式落账时把累计内容同步落段,basic 不落(尊重 v0.3.0 用户存储选择);大文本不入主表。
- 落段挂接 `create_log_with_policy` 单一漏斗(全部协议路径共用),best-effort:段失败仅告警,不使主日志落账失败。
- 保留期三条清理路径 + 批量清理循环同步清段。
- 管理端日志详情页展示「流式生成内容(含中断前已生成部分)」并支持复制。
**第二档(仅 Responses)**:
- driver 轨 Responses 流(detailed 策略下)**逐帧渐进持久化**:下游每帧 SSE 字节顺序落段(seq 递增),`response.id` 从 response.created 帧提取为续传锚点(复用上游 id,透传不改写线上格式);日志行 id 预生成,段表与落账行同 id。
- 回放端点 `GET /v1/responses/{id}/events?offset=N`:API Key 鉴权;按锚点回放 offset 之后全部已存帧(字节级原样);原流无终止帧时合成 `response.completed`(status=incomplete, reason=client_disconnected)干净收尾;TTL 默认 24h(`stream.resume_ttl_secs`,0=不限),过期返回 410 明确错误。
- **协议边界(诚实声明)**:客户端断开时上游即终止(与既有取消语义一致、零改动),回放的是断开前已生成内容;Chat/Anthropic 协议上游无 resume 语义,不做。
### 覆盖面如实声明
第一档覆盖**现状有内容累计的路径**(driver 轨 chat SSE、messages 原生/codec);Responses 流由第二档逐帧路径独占覆盖;legacy proxy 流当前不累计内容,本 PR 不新增累计器。
### 测试
段策略门控四象限 + 三条删除路径段随主行清理;chat SSE 累计内容经漏斗落段端到端(真实 driver 路径);完成流全帧落段 + 锚点反查 + 段表/落账行同 id + offset 语义;中断流帧保留 + 499 照常;锚点提取纯函数;回放端点 401/回放+合成收尾/offset/404/410 过期。
### 开放点(征求意见)
1. response_id 复用上游值 + 24h TTL 约定是否符合预期?
2. **「分离续跑 + 活桥接」**(断开后上游继续生成、重连桥接增量)需要把流泵循环重构为任务+通道模式,回归风险高(与「取消也落账」的 Drop finalizer 语义纠缠)——本 PR 不含,是否值得做?
3. 逐帧持久化的写放大:每帧一条 INSERT(SQLite 单写者 + token 节奏,可接受);如担心可改批量缓冲。
4. 回放端点形态是否符合网关 API 风格?
---
对应分支:`feat/capability-c03-stream-persist`(迁移 032;两档一个 PR)。
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with migration 032 and the create_log_with_policy funnel, then trace the existing driver-rail chat SSE, messages, and Responses stream paths. Review the stated four-quadrant persistence, cleanup, replay, offset, authentication, and interruption tests. Done means detailed-policy segments are persisted and cleaned up correctly, Responses frames can be replayed with the specified offset and expiry behavior, and basic policy remains unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust, sqlite
- Domain
- api, backend-api-design, databases
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100