Skip to content

fix(acp): atomic session persistence via replace_messages (salvage #13675)#20279

Merged
teknium1 merged 3 commits into
mainfrom
salvage/pr-13675
May 5, 2026
Merged

fix(acp): atomic session persistence via replace_messages (salvage #13675)#20279
teknium1 merged 3 commits into
mainfrom
salvage/pr-13675

Conversation

@teknium1
Copy link
Copy Markdown
Contributor

@teknium1 teknium1 commented May 5, 2026

Salvages @Junass1's PR #13675 onto current main with a simpler implementation.

What it does

ACP's save_session() rewrote the transcript via clear_messages() + a loop of append_message() calls. If any message hit an exception mid-loop (bad tool_calls shape, encoding error, etc.), the DELETE had already committed and the persisted conversation was lost.

Changes

  • acp_adapter/session.py — replace the clear+loop with a single db.replace_messages(state.session_id, state.history) call. SessionDB.replace_messages() already exists on current main (added for /retry, /undo, /compress) and wraps DELETE + bulk INSERT in a BEGIN IMMEDIATE transaction that rolls back on exception.
  • tests/acp/test_session.py — new regression test asserting a mid-encode failure leaves the previously-persisted transcript intact.
  • scripts/release.py — AUTHOR_MAP entry for Junass1.

Reshape vs. original

The original PR added its own replace_messages to hermes_state.py. Main now already has a more comprehensive replace_messages (handles codex_message_items, reasoning_content, role-gated fields). Re-wiring ACP to use the existing helper gives the contributor's safety guarantee with less code and no duplication.

Authorship preserved on the acp_adapter/session.py commit.

Validation

tests/acp/test_session.py — 40 passed locally.

Closes #13675 via salvage.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/acp Agent Communication Protocol adapter labels May 5, 2026
Junass1 and others added 3 commits May 5, 2026 10:05
ACP's save_session() did a non-atomic clear_messages() + append_message()
loop. If any message hit an exception mid-loop (bad tool_call shape, etc.),
the DELETE had already committed and the persisted conversation was lost.

SessionDB.replace_messages() wraps DELETE + bulk INSERT in a single
BEGIN IMMEDIATE transaction that rolls back on any exception, so a bad
message can no longer clobber previously-persisted history.

Salvages @Awsh1's PR #13675 — uses the existing replace_messages()
helper (which covers more message fields than the PR's own copy)
instead of adding a duplicate.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/acp Agent Communication Protocol adapter P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants