fix(session): persist assistant after repair compacts message list#44838
fix(session): persist assistant after repair compacts message list#44838JerryLiu369 wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds regression coverage and cursor-handling fixes to ensure SessionDB flushing remains correct when message lists are compacted (repair/compression) after an early persist, especially for cached-agent turns.
Changes:
- Clamp/reset
_last_flushed_db_idxto prevent missing assistant/tool flushes after message-sequence compaction. - Reset stale flush cursor at the start of a fresh cached-agent turn (interrupt depth 0).
- Add focused regression tests for both the repair-compaction scenario and cached-agent turn initialization.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/run_agent/test_early_persist_repair_flush.py | New regression tests covering early persist + repair compaction and stale flush cursor clamping. |
| tests/gateway/test_agent_cache.py | New tests validating flush cursor reset/preservation based on interrupt_depth. |
| run_agent.py | Adjusts SessionDB flush logic when _last_flushed_db_idx is beyond current messages length. |
| gateway/run.py | Resets _last_flushed_db_idx on fresh cached-agent turns to avoid skipping persistence. |
| agent/agent_runtime_helpers.py | Clamps _last_flushed_db_idx when repair_message_sequence compacts messages. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| flush_from = max(start_idx, self._last_flushed_db_idx) | ||
| # repair_message_sequence / compression may shrink `messages` | ||
| # after early persist advanced the cursor past the new length. | ||
| if self._last_flushed_db_idx > len(messages): | ||
| flush_from = start_idx |
There was a problem hiding this comment.
Good catch — agreed. Replaced the `flush_from = start_idx` fallback with clamping `_last_flushed_db_idx` to `len(messages)` before computing `flush_from`, so we avoid re-appending when `start_idx == 0`. Compression tests still pass.
| if hasattr(agent, "_last_flushed_db_idx"): | ||
| agent._last_flushed_db_idx = min( | ||
| agent._last_flushed_db_idx, len(messages) | ||
| ) |
There was a problem hiding this comment.
Makes sense — clamp now runs only when the cursor is an `int` (74457d1 + follow-up commit).
Early turn-start user persist advances _last_flushed_db_idx before repair_message_sequence merges consecutive users and compacts the list. Turn-end flush then skipped the first assistant row, leaving orphan users that grew via \n\n merge on the next gateway turn. Clamp the flush cursor after repair and when idx overshoots list length; also reset _last_flushed_db_idx on cached-agent fresh turns (NousResearch#44327). Co-authored-by: Cursor <cursoragent@cursor.com>
164104e to
74457d1
Compare
|
Rebased onto latest Scope: same-turn gap after early user persist → Not claiming to supersede #24211 or #24196 — those go further on transcript rewrite / flush overshoot in related cases. This is meant as a minimal, test-backed patch for the assistant-drop path seen in production logs. Totally fine to combine, defer, or redirect if a broader approach is preferred. |
Address Copilot review: resetting flush_from to start_idx when conversation_history is None could duplicate DB rows. Clamp _last_flushed_db_idx to len(messages) instead; guard isinstance in repair_message_sequence clamp. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Code Review: Clean ✅ Reviewed the full diff across What was checked:
Architectural note: The |
|
Closing — #45260 (salvage of #44870) has already been merged with a broader fix for the same root cause. Thanks for the review @liuhao1024. |
Summary
Fixes #44837 — gateway sessions where the model sees multiple user messages merged with
\n\nwhile platform inbound is single-message.Rebased onto latest
main. Only the delta beyond merged #44327 / #44518:_last_flushed_db_idxafterrepair_message_sequencecompacts the in-memory list._flush_messages_to_session_dbwhen the cursor overshootslen(messages).#44518 fixes stale cursor across cached-agent turns; this PR addresses the same-turn early-persist → repair → turn-end flush gap.
Root cause
turn_contextearly-persists inbound user → flush cursor advances.repair_message_sequence→ list shrinks.state.db.\n\nblob grows.Related open PRs (same area, not duplicates)
replace_messages()when repair merges into an already-persisted user rowThis PR is intentionally minimal; happy to adjust if maintainers prefer a different merge order or layering.
Test plan
tests/run_agent/test_early_persist_repair_flush.pytests/run_agent/test_860_dedup.py— no dedup regressionpytest tests/run_agent/test_early_persist_repair_flush.py \ tests/run_agent/test_860_dedup.py -q -o addopts=