Repository navigation
Commit 18a101e
fix(agent): 拆分 history_inconsistent,过期的重试与编辑返回 409 (#1357)
* fix(agent): run 终态携带落库轮次,重试与编辑校验按客户端过期报 409
Web 端对已结束但未落库的 run 点击重试或编辑时收到
`session_runtime.history_inconsistent`(500)。原因是服务端与前端对"最新可见轮次"
的判定依据不同:服务端查 `bot_history_messages`,前端取本地列表尾部第一条已结束的
assistant 消息。run 以 errored 结束却未落库时(无可见输出的失败按"未发送"处理),
运行时快照仍保留该 run,`error_code` 恒非空,前端据此判为 `stream` 阶段而保留投影
出的轮次,并把数据库里不存在的 turn id 发给服务端。
变更分三部分:
1. Session Runtime 的 `CurrentRunView` 新增 `persisted_turn`,由应用层在 round 落库
的当下经 `Manager.RecordPersistedTurn` 写入(`storeRoundWithOptionsResult`、
`agentStepCommitter.persist`、`replacePersistedTurn` 三处挂点),先于 `FinishRun`,
终态视图自然保留。前端以该字段判定失败阶段(替代 `error_code`)、把已结束且无
`persisted_turn` 的 run 标为 `unpersisted`(其帧只用于结束屏幕上已有的轮次,不再
引入新轮次),并通过 `isTurnUnpersisted` 不对这类轮次提供重试与编辑。
2. 重试/编辑目标校验拆出 409 编码:`session_runtime.turn_not_latest`(目标非最新或
会话无可见轮次)、`session_runtime.turn_incomplete`(缺 assistant 锚点)。前端收到
后自动刷新历史。`history_inconsistent` 保留给真实的持久化故障。
3. 其余复用该码的位置按领域拆分:`session_runtime.reset_unavailable`(503,重置协调
器未配置)、`session_runtime.reset_conflict`(409,重置租约获取失败或丢失)、
`history.delete_failed`(500)、`external_runtime.session_resume_failed`(502,Codex /
Claude Code 会话恢复失败,同步替换 `isRuntimeConfigurationError` 列表中的
旧码以保持行为)。新增 `catalog_guard_test.go`:每个 `Code` 常量必须有 catalog 条目,
catalog 与 en/zh/ja 的 `errors.*` 叶子键双向对齐,`testdata/codes.golden` 记录已发布
编码与 HTTP 状态并要求只增不改。补齐缺失的 `queue_capacity_exceeded` 文案。
已知残留:owner 失联后由 reaper 结束的 run 没有 `persisted_turn`,前端按未发送处理;
`runtime_run_failed` 字面量与队列域扁平编码的迁移另开任务。
* fix(web): 已完成的 run 缺少 persisted_turn 时不按未发送处理
`unpersisted` 与 `isTurnUnpersisted` 只对失败结束(errored / aborted / lost)且无
`persisted_turn` 的 run 生效。完成即意味着 round 已写入;来自尚未携带该字段的服务端
的完成帧仍需追加到 transcript(`run-turn-ownership.test.ts`、
`turn-identity-pairing.test.ts` 覆盖的场景)。
* fix(agent): persisted_turn 走增量补丁;替换运行未落库失败时刷新历史
审阅发现的修正:
- `RecordPersistedTurn` 改为发布 `CurrentRunPatch.persisted_turn` 增量而非整份
`current_run_view`。逐步提交的 run(steer / 工具循环)每步都会记录一次,整份视图
会让每个订阅者承担步数 × 内容的传输与拷贝成本。前端 `applyRunPatch` 补上该字段。
- 重试 / 编辑的 run 已产生可见输出但未落库就失败时,屏幕上是失败的新回复而数据库仍是
旧尾部,且新回复不可重试。`send.ts` 在这种情况下刷新历史,让旧尾部回来。
- `agentStepCommitter` 记录的 `request_message_id` 固定为 run 自身的请求消息,不再随
steer 覆写。
- tool approval / ask_user 续跑的请求没有 `TurnID`,`notePersistedTurn` 回退到
`RunHandle.TurnID`。
- 记录失败(租约过期、归属丢失)时以 error 级别带 request / assistant 消息 id 记日志,
便于对账客户端可能的重复发送。
- `send.ts` 超出 max-lines,把两个恢复判定移到 `replacement-recovery.ts`。
* refactor(agent): persisted_turn 收窄为 turn_id,补记录遗漏审计与设计说明
按止血修复的标准收尾:
- `PersistedTurnView` 只保留 `turn_id`。前端只需要知道历史里有这一轮,其余信息从历史读;
字段越窄,事件日志重构落地时越容易删除。相应去掉 `agentStepCommitter` 里为它维护的
请求消息 id。
- 前端把"这一轮是否已写入历史"的判定收拢为 `runHistoryState`(active / written /
unwritten),投影、阶段判定、重试门禁、替换失败恢复四处都调用它,重构时只换一个函数。
- Session Runtime 新增 `SetPersistedTurnAuditor`:run 以失败结束且没有记录 `persisted_turn`
时,应用层查历史是否已有该 turn(新增 `DBService.GetHistoryTurn`)。有则说明某条持久化
路径漏掉了 `notePersistedTurn`(或记录在租约过期后被拒),前端会把已写入的轮次当成未
发送,此时以 error 级别记录 run / turn / 消息 id,让遗漏可见而不是静默产生重复发送。
- `docs/design/turn-history-event-log.md` 记录根因(turn 不是一等数据结构、三处状态靠
应用层对齐)、事件日志的目标形态、设计文档需要回答的问题,以及本过渡方案的删除条件。
* docs: 移除事件日志设计说明
按要求不入库;代码注释中的引用同步删除。
* fix(i18n): 错误文案只说现象与下一步
用户可见的文案不再描述内部状态(记录、合并、保存/恢复)或操作分支,改为一句话:
出了什么,接下来做什么(刷新 / 稍后重试 / 联系管理员 / 新开会话)。涉及
`session_runtime.history_inconsistent`、`turn_not_latest`、`turn_incomplete`、
`reset_unavailable`、`reset_conflict`、`history.delete_failed`、
`external_runtime.session_resume_failed` 的 en / zh / ja 文案与 Go 侧兜底 Detail。
* fix(i18n): 重置不可用文案改为联系开发者
* fix(agent): 运行时状态发布失败与会话中止失败改用各自的错误码
`history_inconsistent` 只表示历史写入失败。运行时事件发布到 Session Runtime 失败
(Redis 不可用、run 归属丢失)改为 `session_runtime.publish_failed`(503);删除直连
运行时会话后中止在途 run 失败改为 `session_runtime.abort_failed`(500)。补三语文案与
golden。
* refactor(agent): 收窄为错误码拆分,移除 persisted_turn 与落库审计
同行(LibreChat、Onyx、Dify、Open WebUI、LobeChat、Cherry Studio 等)都在
受理时就确定一轮的持久性,失败记在 assistant 位上;用事后通知的
persisted_turn 去补「按失败类型决定是否落库」会引入落库与记录之间的窗口。
这部分改为另起方案处理,本 PR 只保留错误码拆分:
- 重试/编辑目标过期返回 409 turn_not_latest / turn_incomplete
- 重置、删除历史、外部会话恢复、运行时发布、会话中止各用独立错误码
- history_inconsistent 只表示历史写入失败
- 错误码 catalog 与三语文案的 golden 守卫测试
移除:run 视图的 persisted_turn、RecordPersistedTurn、持久化审计、
GetHistoryTurn,以及前端据此判断未发送/隐藏重试/刷新历史的逻辑。
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: 晨苒 <16112591+chen-ran@users.noreply.github.com>1 parent 9262b6e commit 18a101e
17 files changed
Lines changed: 526 additions & 49 deletions
File tree
- apps/web/src/i18n/locales
- internal
- agent
- application
- runtime
- claudecode
- codex
- apperror
- testdata
- handlers
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| |||
274 | 275 | | |
275 | 276 | | |
276 | 277 | | |
277 | | - | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
278 | 288 | | |
279 | 289 | | |
280 | 290 | | |
| |||
285 | 295 | | |
286 | 296 | | |
287 | 297 | | |
288 | | - | |
| 298 | + | |
| 299 | + | |
289 | 300 | | |
290 | 301 | | |
291 | 302 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
161 | 161 | | |
162 | 162 | | |
163 | 163 | | |
| 164 | + | |
164 | 165 | | |
165 | 166 | | |
166 | 167 | | |
| |||
271 | 272 | | |
272 | 273 | | |
273 | 274 | | |
274 | | - | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
275 | 285 | | |
276 | 286 | | |
277 | 287 | | |
| |||
282 | 292 | | |
283 | 293 | | |
284 | 294 | | |
285 | | - | |
| 295 | + | |
| 296 | + | |
286 | 297 | | |
287 | 298 | | |
288 | 299 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
164 | 164 | | |
165 | 165 | | |
166 | 166 | | |
| 167 | + | |
167 | 168 | | |
168 | 169 | | |
169 | 170 | | |
| |||
274 | 275 | | |
275 | 276 | | |
276 | 277 | | |
277 | | - | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
278 | 288 | | |
279 | 289 | | |
280 | 290 | | |
| |||
285 | 295 | | |
286 | 296 | | |
287 | 297 | | |
288 | | - | |
| 298 | + | |
| 299 | + | |
289 | 300 | | |
290 | 301 | | |
291 | 302 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
175 | 175 | | |
176 | 176 | | |
177 | 177 | | |
| 178 | + | |
178 | 179 | | |
179 | 180 | | |
180 | | - | |
181 | | - | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
182 | 184 | | |
183 | 185 | | |
184 | 186 | | |
| |||
267 | 269 | | |
268 | 270 | | |
269 | 271 | | |
270 | | - | |
| 272 | + | |
| 273 | + | |
271 | 274 | | |
272 | | - | |
| 275 | + | |
273 | 276 | | |
274 | 277 | | |
275 | 278 | | |
276 | 279 | | |
277 | | - | |
| 280 | + | |
278 | 281 | | |
279 | 282 | | |
280 | 283 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
121 | 121 | | |
122 | 122 | | |
123 | 123 | | |
124 | | - | |
125 | | - | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
126 | 127 | | |
127 | | - | |
128 | | - | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
129 | 131 | | |
130 | 132 | | |
131 | 133 | | |
| |||
147 | 149 | | |
148 | 150 | | |
149 | 151 | | |
150 | | - | |
151 | | - | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
152 | 157 | | |
153 | 158 | | |
154 | 159 | | |
155 | 160 | | |
156 | | - | |
| 161 | + | |
157 | 162 | | |
158 | 163 | | |
159 | 164 | | |
160 | 165 | | |
161 | | - | |
162 | | - | |
| 166 | + | |
| 167 | + | |
163 | 168 | | |
164 | 169 | | |
165 | 170 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1030 | 1030 | | |
1031 | 1031 | | |
1032 | 1032 | | |
1033 | | - | |
| 1033 | + | |
1034 | 1034 | | |
1035 | 1035 | | |
1036 | 1036 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
252 | 252 | | |
253 | 253 | | |
254 | 254 | | |
| 255 | + | |
| 256 | + | |
| 257 | + | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
255 | 265 | | |
256 | 266 | | |
257 | 267 | | |
258 | 268 | | |
259 | 269 | | |
260 | | - | |
| 270 | + | |
261 | 271 | | |
262 | 272 | | |
263 | 273 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
315 | 315 | | |
316 | 316 | | |
317 | 317 | | |
318 | | - | |
319 | | - | |
| 318 | + | |
| 319 | + | |
320 | 320 | | |
321 | 321 | | |
322 | 322 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
327 | | - | |
| 327 | + | |
328 | 328 | | |
329 | 329 | | |
330 | 330 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
350 | 350 | | |
351 | 351 | | |
352 | 352 | | |
353 | | - | |
| 353 | + | |
354 | 354 | | |
355 | 355 | | |
356 | 356 | | |
| |||
0 commit comments