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

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.