aws / aws/bedrock-agentcore-sdk-python

AgentCoreMemorySessionManager: retrieval_config context accumulates O(turns × records) across multi-turn conversations

オープン
#420 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

主要言語
Python
スター
764
フォーク
148
平均マージ
1日 23時間
マージ済み PR(30日)
7

説明

Summary

When using AgentCoreMemorySessionManager with retrieval_config, the <user_context> XML injected by retrieve_customer_context() persists in agent.messages and repeats on every turn, growing O(turns × records).

Observed with 5 turns and 3 preferences: 3,655 chars of repeated context (83% of total message content).

Turn 1: [user+XML, assistant]
Turn 2: [user+XML, assistant, user+XML, assistant]          ← XML appears twice
Turn 3: [user+XML, assistant, user+XML, assistant, user+XML, assistant]  ← 3×

Strands Integration Affected

from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig
from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager

Root Cause

In session_manager.py, retrieve_customer_context() (lines 754–829) is registered as a MessageAddedEvent callback (line 840). On each turn it unconditionally inserts XML context at event.agent.messages[-1]["content"][0] (line 823):

event.agent.messages[-1]["content"].insert(
    0, {"text": f"<{self.config.context_tag}>{context_text}</{self.config.context_tag}>"}
)

Three missing controls cause the accumulation:

  1. No deduplication checkretrieve_customer_context() does not check if context is already present before injecting.
  2. No filtering on message restorelist_messages() (lines 688–707) reloads messages with previously-injected context intact. The existing _filter_restored_tool_context() (lines 709–734) strips toolUse/toolResult blocks but has no equivalent for <user_context> tags.
  3. Mutable in-place modification — The injected context is saved as part of the message content, so it reappears when the message history is reloaded on the next turn.

Impact

  • Token waste: Grows linearly per turn. 10 turns × 5 records × 500 chars/record = ~25KB of duplicate context.
  • Context window pressure: In long-running sessions this can consume a significant portion of the model's context window.
  • Cost: Unnecessary input token charges scale with conversation length.

Reproduction

from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig, RetrievalConfig
from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager
from strands import Agent

config = AgentCoreMemoryConfig(
    memory_id=MEMORY_ID,
    session_id=session_id,
    actor_id=actor_id,
    retrieval_config=RetrievalConfig(
        memory_id=MEMORY_ID,
        namespace="preferences",
    ),
)

with AgentCoreMemorySessionManager(config, region_name=REGION) as sm:
    agent = Agent(model=model, session_manager=sm)
    # After 3+ turns, inspect agent.messages — <user_context> XML appears N times
    # where N = number of completed turns

Suggested Fix Directions

Option A (Deduplication before injection):
Before line 823, check if the last message already contains the context tag and skip injection if present.

Option B (Filter on restore — analogous to existing tool context filtering):
Add a _filter_restored_user_context() method that strips previously-injected <user_context> tags from restored messages, similar to how _filter_restored_tool_context() already handles toolUse/toolResult.

Option C (Both):
Strip on restore (Option B) for correctness + deduplicate on inject (Option A) as a safety net.

Current Workaround

Skip retrieval_config and use the memory tool directly for LTM access:

config = AgentCoreMemoryConfig(
    memory_id=MEMORY_ID, session_id=sid, actor_id=aid,
    # no retrieval_config → no auto-injection
)
memory_tool = AgentCoreMemoryToolProvider(
    memory_id=MEMORY_ID, actor_id=aid, session_id=sid, namespace=ns, region=REGION,
)
with AgentCoreMemorySessionManager(config, region_name=REGION) as sm:
    agent = Agent(model=model, session_manager=sm, tools=memory_tool.tools)

Test Gap

The existing integration test test_session_manager_with_retrieval_config_adds_context (line ~140) only verifies context exists after 2 turns but does not assert that context does not accumulate across turns.

コントリビューションガイド

コントリビューションガイドを開く

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

調査の方向性

session_manager.py の list_messages()、_filter_restored_tool_context()、retrieve_customer_context()、および MessageAddedEvent の登録から始めます。統合テスト test_session_manager_with_retrieval_config_adds_context を読み、複数ターンにわたってカバレッジを拡張し、retrieval context が蓄積して agent.messages に入るのではなく、1 回だけ現れることを検証します。

索引モデルが issue の本文から書いたものです。

評価

技術スタック
aws, python
領域
ai, backend
issue の種類
バグ
難易度
3/5
見積もり時間
1〜2日
活発さ
静か
明瞭さ
おおむね明確
初心者へのやさしさ
68/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。