aws / aws/bedrock-agentcore-sdk-python

Bug Report: get_last_k_turns() returns messages in reversed order within each turn

Open
#253 0 comments 0 reactions 0 assignees View on GitHub
memory
Dominant language
Python
Stars
761
Forks
147
Avg merge
1d 23h
Merged PRs (30d)
7

Description

# Bug Report: `get_last_k_turns()` returns messages in reversed order within each turn

**Reporter**: Amazon Employee (not a team member of AgentCore SDK, reporting issue only)

## Description

`get_last_k_turns()` returns turns with messages in reversed order (ASSISTANT before USER) instead of chronological order (USER before ASSISTANT). This contradicts the docstring which states "A turn typically consists of a user message followed by assistant response(s)."

## Environment

- **OS**: macOS
- **Python version**: 3.12
- **SDK version**: 1.2.0, 1.2.1 (tested both - bug persists)
- **AWS Region**: ap-northeast-2

## Steps to Reproduce

```python
from bedrock_agentcore.memory import MemoryClient, MemorySessionManager

memory_client = MemoryClient(region_name="ap-northeast-2")
session_manager = MemorySessionManager(
memory_id="mem-xxxxxxxx",
region_name="ap-northeast-2",
)

# Create events in chronological order
# Event 1: USER "Hello"
# Event 2: ASSISTANT "Hi there!"
# Event 3: USER "What's the weather?"
# Event 4: ASSISTANT [toolUse: get_weather]
# Event 5: USER [toolResult: sunny]
# Event 6: ASSISTANT "It's sunny today"

# Get last k turns
turns = session_manager.get_last_k_turns(
actor_id="user_001",
session_id="session_001",
k=10
)

print(turns)
```

## Expected Behavior

Each turn should have messages in chronological order (USER first, then ASSISTANT):

```python
[
[{'role': 'USER', 'content': ...}, {'role': 'ASSISTANT', 'content': ...}],
[{'role': 'USER', 'content': ...}, {'role': 'ASSISTANT', 'content': ...}],
...
]
```

## Actual Behavior

Each turn has messages in **reversed order** (ASSISTANT first, then USER):

```python
[
[{'role': 'ASSISTANT', 'content': "서울역[1호선]으로 안내를..."}], # Turn with only ASSISTANT
[{'role': 'USER', 'content': ...toolResult...}, {'role': 'ASSISTANT', 'content': ...toolUse...}], # Reversed!
[{'role': 'USER', 'content': "2번"}, {'role': 'ASSISTANT', 'content': "서울역 5곳이에요..."}], # Looks correct but paired with PREVIOUS assistant response
...
]
```

## Root Cause Analysis

Looking at the SDK source code in `client.py`:

```python
def get_last_k_turns(self, ...):
# ...
response = self.gmdp_client.list_events(**params) # Returns events in reverse chronological order (newest first)
events = response.get("events", [])

for event in events: # Iterates in reverse order without sorting
# ...
if role == Role.USER.value and current_turn:
turns.append(current_turn)
current_turn = []
current_turn.append(payload_item["conversational"])
```

The issue is that `list_events` API returns events in **reverse chronological order** (newest first), but the SDK processes them without sorting to chronological order first.

## Suggested Fix

Sort events by `eventTimestamp` before processing:

```python
def get_last_k_turns(self, ...):
# ... fetch events ...

# Sort events chronologically before processing
all_events = sorted(all_events, key=lambda e: e.get('eventTimestamp', ''))

# Then process turns...
```

Or reverse the events list before iteration:

```python
for event in reversed(events): # Process oldest to newest
```

## Impact

This bug affects any application that relies on `get_last_k_turns()` to retrieve conversation history for:
- Passing to LLM as context (messages appear in wrong order)
- Displaying conversation history to users
- Analyzing conversation flow

## Workaround

Currently using `list_events()` and manually sorting/grouping:

```python
events = session_manager.list_events(actor_id, session_id)
events_sorted = sorted(events, key=lambda e: e['eventTimestamp'])
# Manual turn grouping...
```

## Related

- PR #209 improved pagination but did not address the ordering issue
- The docstring says "user message followed by assistant response(s)" but actual behavior is reversed

## Update Log

### 2026-02-05: Tested with SDK 1.2.1

Bug still persists in version 1.2.1. Test results:

```
SDK Version: 1.2.1

============================================================
각 턴의 메시지 순서 확인:
============================================================
Turn 1: ['ASSISTANT'] # ← Only ASSISTANT, no USER
Turn 2: ['USER', 'ASSISTANT'] # ← Looks correct but actually misaligned
Turn 3: ['USER', 'ASSISTANT']
Turn 4: ['USER', 'ASSISTANT']
Turn 5: ['USER', 'ASSISTANT']
```

The issue is that Turn 1 contains only ASSISTANT (orphaned from its USER), and subsequent turns pair the PREVIOUS assistant response with the CURRENT user message - the entire conversation is shifted by one position.

Contributor guide

Open the contributing guide

Research direction

Start in client.py at get_last_k_turns and reproduce the supplied event sequence using list_events or the provided MemorySessionManager example. Verify that returned turns preserve chronological USER-before-ASSISTANT ordering and that responses are paired with the correct user messages.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, python
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
50/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.