Skip to content

[BUG] Pinned messages outside the first N are not preserved across session restore (message-log session managers) #4088

Closed

Description

@strandly-the-agent

Checks

  • I have updated to the lastest minor and patch version of Strands
  • I have checked the documentation and this is not expected behavior
  • I have searched ./issues and there are no duplicates of my issue

SDK Language

Python

Strands Version

main @ 3f1e99b

Language Runtime Version

Python 3.13

Operating System

Amazon Linux 2023 (aarch64)

Installation Method

git clone

Steps to Reproduce

Pins are not head-only:

  1. pin_context is a model-facing @tool that pins/unpins arbitrary indices (_context_manager/modes/agentic/agentic_context.py:206-275).
  2. Users can set metadata.custom.pinned directly — documented at site/src/content/docs/user-guide/concepts/agents/conversation-management.mdx:356.

Pin any message beyond the leading pin_first head, drive a SummarizingConversationManager compaction on a FileSessionManager/S3SessionManager session, and rebuild the agent on the same session.

Expected Behavior

All pinned messages survive the restore, wherever they sit in the transcript — that is the point of pinning.

Actual Behavior

The pinned marker never reaches the store: messages are appended to the session before compaction pins them in place (RepositorySessionManager.append_message fires on MessageAddedEvent), and update_message is redaction-only — verified directly: no stored message carries the metadata. On restore, partition_pinned-preserved mid-range pins are therefore skipped or resurrected by the offset arithmetic, and action="unpin" on head messages leaves persisted pin state stale in the other direction.

Note this is reasoned from code plus verified head-only probes (the store-side marker absence and the head cases are verified end-to-end; an arbitrary mid-range pin was not probed end-to-end).

Additional Context

Related to #4027/#4066, but not closed by them: #4066's mechanism (persist how much of the head is pinned, reattach it on restore) is positional and can only ever describe a leading head. It also does not survive the restore itself — the reattached head comes back without markers (see the #4066 review) — and no positional scheme can express an arbitrary pinned set.

Possible Solution

Persist the marker per message: it already lives inside SessionMessage.message metadata, so writing messages (or updating them) at compaction time would make restore drift-proof, unpin-aware, and correct for non-head pins. Real cost: N store writes on first compaction (S3: N PUTs) and interplay with update_message's redaction substitution (types/session.py:86-94) — hence a follow-up rather than a #4066 rider.

Related Issues

#4027, #4066, #4087

Activity

  1. added
    bugSomething isn't working
    pythonPull requests that update python code
    area-persistenceSession management or checkpointing
    on Aug 31, 2026
  2. Unshure commented on Sep 4, 2026

    @Unshure
    Member

    This is already being tracked in the following issue: #4027

    Per this comment, we do not plan on fixing this issue, and are instead targeting the deprecation of ConversationManager: #4027 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area-contextSession or context relatedarea-persistenceSession management or checkpointingbugSomething isn't workingpythonPull requests that update python code

    Type

    Fields

    Language

    Python

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions