Commit f474495
fix(agent-runtime): persist partial transcript when a run fails mid-turn (#449)
## Problem
When the executor's `execRun()` async generator throws part-way through
a turn for a **non-abort** reason — most commonly the upstream model
stream being terminated (`API Error: terminated`) — the run's user
prompt and any already-generated assistant output were **never written
to the thread store**.
Root cause: `messages.jsonl` is only written by
`store.appendMessages()`, which is only reached on the **success** path
of each execution method. In the `catch` blocks, the *abort* branch
already had a fallback persist (`persistMessagesOnAbort`, guarded by
`task.committed`), but the **non-abort error** branch only called
`updateRun(rb.fail)` and pushed an `error` event — it never persisted
anything.
Result: the failed turn vanishes from `messages.jsonl` entirely. The
client sees the error, but the persisted history skips straight from the
previous turn to the next one, leaving storage inconsistent with what
actually happened and unusable for resume / audit.
## Fix
All three execution paths — `syncRun`, `asyncRun`, and
`executeStreamBackground` — now persist the partial transcript in their
non-abort error branch, **before** marking the run failed. This mirrors
the existing abort fallback and reuses the same `task.committed` guard,
so we never write a thread for a session the executor never persisted to
disk (which would break subsequent resume).
`persistMessagesOnAbort` is renamed to `persistPartialMessages` since it
now serves both the abort and the mid-turn-failure paths; its doc
comment is generalized accordingly. Behavior of the method body is
unchanged (append input messages + `filterForStorage(streamMessages)`,
swallow store errors).
Because token-level deltas are `stream_event` messages (filtered out by
`filterForStorage`), a mid-stream `tool_use` that never completed is
*not* present in `streamMessages`, so this cannot persist an
unterminated/half tool_use block.
## Tests
Added one regression test per execution path (`syncRun` / `asyncRun` /
`streamRun`): yield one assistant message (flipping `committed=true`),
then throw, and assert the run is `Failed` **and** the thread retains
both the user and the assistant message.
All existing tests pass (158 passing). Note: 2 pre-existing failures in
`cancelRun` (`AgentTimeoutError is not a constructor`) are present on
`master` as well and are unrelated to this change (local ts-node
type-resolution of `@eggjs/tegg-types`).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Conversation history is more robust during non-success runs: committed
assistant responses are preserved and persisted on failures, aborts, or
mid-turn errors, and duplicate messages are avoided.
* **Tests**
* Added runtime tests verifying partial transcripts are persisted and
not duplicated when execution fails after committing output in sync,
async, and streaming runs.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>1 parent 5d90357 commit f474495
2 files changed
Lines changed: 159 additions & 32 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
189 | 199 | | |
190 | 200 | | |
191 | 201 | | |
192 | 202 | | |
193 | 203 | | |
194 | | - | |
195 | | - | |
196 | | - | |
| 204 | + | |
197 | 205 | | |
198 | 206 | | |
199 | 207 | | |
| |||
208 | 216 | | |
209 | 217 | | |
210 | 218 | | |
211 | | - | |
212 | | - | |
213 | | - | |
| 219 | + | |
214 | 220 | | |
215 | 221 | | |
216 | 222 | | |
| |||
223 | 229 | | |
224 | 230 | | |
225 | 231 | | |
| 232 | + | |
226 | 233 | | |
227 | 234 | | |
228 | 235 | | |
229 | 236 | | |
230 | 237 | | |
231 | 238 | | |
232 | | - | |
233 | | - | |
234 | | - | |
| 239 | + | |
235 | 240 | | |
236 | 241 | | |
237 | 242 | | |
238 | 243 | | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
239 | 249 | | |
240 | 250 | | |
241 | 251 | | |
| |||
276 | 286 | | |
277 | 287 | | |
278 | 288 | | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
279 | 296 | | |
280 | 297 | | |
281 | 298 | | |
282 | 299 | | |
283 | 300 | | |
284 | | - | |
285 | | - | |
286 | | - | |
| 301 | + | |
287 | 302 | | |
288 | 303 | | |
289 | 304 | | |
| |||
296 | 311 | | |
297 | 312 | | |
298 | 313 | | |
| 314 | + | |
299 | 315 | | |
300 | 316 | | |
301 | 317 | | |
| |||
306 | 322 | | |
307 | 323 | | |
308 | 324 | | |
| 325 | + | |
309 | 326 | | |
310 | 327 | | |
311 | 328 | | |
312 | 329 | | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
313 | 335 | | |
314 | 336 | | |
315 | 337 | | |
| |||
319 | 341 | | |
320 | 342 | | |
321 | 343 | | |
322 | | - | |
323 | | - | |
324 | | - | |
| 344 | + | |
325 | 345 | | |
326 | 346 | | |
327 | 347 | | |
| |||
437 | 457 | | |
438 | 458 | | |
439 | 459 | | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
| 464 | + | |
| 465 | + | |
| 466 | + | |
440 | 467 | | |
441 | 468 | | |
442 | 469 | | |
443 | 470 | | |
444 | 471 | | |
445 | | - | |
446 | | - | |
447 | | - | |
| 472 | + | |
448 | 473 | | |
449 | 474 | | |
450 | 475 | | |
| |||
464 | 489 | | |
465 | 490 | | |
466 | 491 | | |
467 | | - | |
468 | | - | |
469 | | - | |
| 492 | + | |
470 | 493 | | |
471 | 494 | | |
472 | 495 | | |
| |||
477 | 500 | | |
478 | 501 | | |
479 | 502 | | |
| 503 | + | |
480 | 504 | | |
481 | 505 | | |
482 | 506 | | |
483 | 507 | | |
484 | 508 | | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
485 | 514 | | |
486 | 515 | | |
487 | 516 | | |
| |||
492 | 521 | | |
493 | 522 | | |
494 | 523 | | |
495 | | - | |
496 | | - | |
497 | | - | |
| 524 | + | |
498 | 525 | | |
499 | 526 | | |
500 | 527 | | |
| |||
578 | 605 | | |
579 | 606 | | |
580 | 607 | | |
581 | | - | |
582 | | - | |
583 | | - | |
584 | | - | |
585 | | - | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
586 | 615 | | |
587 | 616 | | |
588 | 617 | | |
589 | 618 | | |
590 | 619 | | |
591 | 620 | | |
592 | | - | |
593 | | - | |
| 621 | + | |
| 622 | + | |
594 | 623 | | |
595 | | - | |
| 624 | + | |
596 | 625 | | |
597 | 626 | | |
598 | 627 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
317 | 317 | | |
318 | 318 | | |
319 | 319 | | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
320 | 377 | | |
321 | 378 | | |
322 | 379 | | |
| |||
369 | 426 | | |
370 | 427 | | |
371 | 428 | | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
| 440 | + | |
| 441 | + | |
| 442 | + | |
| 443 | + | |
| 444 | + | |
| 445 | + | |
| 446 | + | |
372 | 447 | | |
373 | 448 | | |
374 | 449 | | |
| |||
526 | 601 | | |
527 | 602 | | |
528 | 603 | | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
| 619 | + | |
| 620 | + | |
| 621 | + | |
| 622 | + | |
| 623 | + | |
| 624 | + | |
| 625 | + | |
| 626 | + | |
529 | 627 | | |
530 | 628 | | |
531 | 629 | | |
| |||
0 commit comments