Repository navigation
fix(memory): restore latest agent snapshot from batched events - #700
Merged
Merged
Conversation
added 2 commits
October 12, 2026 21:44
With batch_size > 1, one AGENT event holds several SessionAgent snapshots, oldest first. read_agent read payload[0], so restored agents lost the state saved during their previous invocation. Fixes #698
…ssages Restoring payload[-1] relies on the newest snapshot being last and on messages being persisted no later than the snapshot that indexes them. - Prepend agent states re-buffered after a failed flush, so states buffered during the failed send stay newest. - Flush buffered messages before agent states when the agent state buffer fills, so a crash can't leave a snapshot whose removed_message_count points past the saved history.
Contributor
✅ No Breaking Changes DetectedNo public API breaking changes found in this PR. |
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
Contributor
|
Claude Security Review: no high-confidence findings. (run) |
tejaskash
approved these changes
Oct 13, 2026
tejaskash
left a comment
Contributor
There was a problem hiding this comment.
Approving. The fix is correct when flushes don't overlap, and the three new tests fail on main and pass here.
One non-blocking note: the two ordering guarantees in the description hold only when flushes don't overlap. With flush_interval_seconds set, the timer thread can flush while the AfterInvocationEvent flush runs on the agent thread, and both of these still restore a stale snapshot:
- A timer flush of s1 fails slowly. Meanwhile the agent thread buffers s2 and flushes it successfully. The prepend then puts s1 back into an empty buffer, the next flush writes it as the newest AGENT event, and
read_agentrestores s1. _flush_messagesreads the message buffer first and the agent-state buffer later. If the agent thread buffers m2 and s2 in between, s2 is saved and m2 is not.
I reproduced both on this branch and on main, so they don't block this PR. I'll open a separate PR for them.
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #698
Problem
With
batch_size > 1,AgentCoreMemorySessionManagerbuffersSessionAgentsnapshots and flushes them as one AGENT event whosepayloadis ordered oldest first.read_agentreadpayload[0], the oldest snapshot, so an agent restored by a new session manager lost the changes from its previous invocation (agent.state, conversation manager state, interrupt state).Fix
read_agentreadspayload[-1], the last snapshot written. Sessions already stored by affected versions also restore their latest snapshot.extendput them after states buffered during the failed send, sopayload[-1]would restore a stale snapshot.removed_message_countpointed past the saved messages, and the restored history was empty.Behavior change for stored sessions
Batched sessions written since 1.23.1 never restored interrupt state. After this change, a session whose last invocation ended in an unanswered interrupt restores it, as with
batch_size=1, and the next call must passinterruptResponses; a plain prompt raises Strands'TypeError: must resume from interrupt with list of interruptResponse's.Testing
pytest tests/bedrock_agentcore/memory/integrations/strands/: 399 passed.ruff check/ruff format --checkclean.model_calls=3(wasNone).batch_size2/3/5/10 vs 1:agent.stateacross turns,SlidingWindowConversationManager(window_size=4)over 8 turns (plateaus as withbatch_size=1), interrupt resumed from a new agent,async_mode, mid-invocation flushes, flush failure and retry, sessions written bymainthen restored by this branch, two agents in one session.ListEventsreturnspayloadentries in the orderCreateEventwrote them.Not in this PR (pre-existing)
batch_size > 1, legacy agent-event migration inread_agentbuffers the migrated snapshot but deletes the legacy event immediately; a crash before the flush loses it.read_agentreturnNoneinstead of an older valid snapshot (read_sessiongot guards in fix: handle empty payload gracefully #683,read_agentdidn't)._flush_messages_onlyre-buffers failed messages withextend, so the same ordering issue can reorder messages.