generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 60
feat: add AgentCore Memory Session Manager with Strands Agents #65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
4d4fcee
feat: add Strands AgentCore Memory integration
afarntrog 4c6a24d
readme updates
afarntrog 87e6c7c
use native message parsing from SessionMessage and updating naming of…
afarntrog 305488e
move integration under strands folder to allow for other providers in…
afarntrog 934940b
move integration under strands folder to allow for other providers in…
afarntrog 9255521
update formatting so that `uv run pre-commit run --all-file` passes
afarntrog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Memory integrations for Bedrock AgentCore.""" |
257 changes: 257 additions & 0 deletions
257
src/bedrock_agentcore/memory/integrations/strands/README.md
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,257 @@ | ||
| # Strands AgentCore Memory Examples | ||
|
|
||
| This directory contains comprehensive examples demonstrating how to use the Strands AgentCoreMemorySessionManager with Amazon Bedrock AgentCore Memory for persistent conversation storage and intelligent retrieval (Supports STM and LTM). | ||
|
|
||
| ## Quick Setup | ||
|
|
||
| ```bash | ||
| pip install 'bedrock-agentcore[strands-agents]' | ||
| ``` | ||
|
|
||
| or to develop locally: | ||
| ```bash | ||
| git clone https://github.com/aws/bedrock-agentcore-sdk-python.git | ||
| cd bedrock-agentcore-sdk-python | ||
| uv sync | ||
| source .venv/bin/activate | ||
| ``` | ||
|
|
||
| ## Examples Overview | ||
|
|
||
| ### 1. Short-Term Memory (STM) | ||
| Basic memory functionality for conversation persistence within a session. | ||
|
|
||
| ### 2. Long-Term Memory (LTM) | ||
| Advanced memory with multiple strategies for user preferences, facts, and session summaries. | ||
|
|
||
| --- | ||
|
|
||
| ## Short-Term Memory Example | ||
|
|
||
| ### Basic Setup | ||
|
|
||
| ```python | ||
| import uuid | ||
| import boto3 | ||
| from datetime import date | ||
| from strands import Agent | ||
| from bedrock_agentcore.memory import MemoryClient | ||
| from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig, RetrievalConfig | ||
| from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager | ||
| ``` | ||
|
|
||
| ### Create a Basic Memory | ||
|
|
||
| ```python | ||
| client = MemoryClient(region_name="us-east-1") | ||
| basic_memory = client.create_memory( | ||
| name="BasicTestMemory", | ||
| description="Basic memory for testing short-term functionality" | ||
| ) | ||
| print(basic_memory.get('id')) | ||
| ``` | ||
|
|
||
| ### Configure and Use Agent | ||
|
|
||
| ```python | ||
| MEM_ID = basic_memory.get('id') | ||
| ACTOR_ID = "actor_id_test_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
| SESSION_ID = "testing_session_id_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
|
|
||
|
|
||
| # Configure memory | ||
| agentcore_memory_config = AgentCoreMemoryConfig( | ||
| memory_id=MEM_ID, | ||
| session_id=SESSION_ID, | ||
| actor_id=ACTOR_ID | ||
| ) | ||
|
|
||
| # Create session manager | ||
| session_manager = AgentCoreMemorySessionManager( | ||
| agentcore_memory_config=agentcore_memory_config, | ||
| region_name="us-east-1" | ||
| ) | ||
|
|
||
| # Create agent | ||
| agent = Agent( | ||
| system_prompt="You are a helpful assistant. Use all you know about the user to provide helpful responses.", | ||
| session_manager=session_manager, | ||
| ) | ||
| ``` | ||
|
|
||
| ### Example Conversation | ||
|
|
||
| ```python | ||
| agent("I like sushi with tuna") | ||
| # Agent remembers this preference | ||
|
|
||
| agent("I like pizza") | ||
| # Agent acknowledges both preferences | ||
|
|
||
| agent("What should I buy for lunch today?") | ||
| # Agent suggests options based on remembered preferences | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Long-Term Memory Example | ||
|
|
||
| ### Create LTM Memory with Strategies | ||
|
|
||
| ```python | ||
| from bedrock_agentcore.memory.integrations.strands.config import AgentCoreMemoryConfig, RetrievalConfig | ||
| from bedrock_agentcore.memory.integrations.strands.session_manager import AgentCoreMemorySessionManager | ||
| from datetime import datetime | ||
|
|
||
| # Create comprehensive memory with all built-in strategies | ||
| client = MemoryClient(region_name="us-east-1") | ||
| comprehensive_memory = client.create_memory_and_wait( | ||
| name="ComprehensiveAgentMemory", | ||
| description="Full-featured memory with all built-in strategies", | ||
| strategies=[ | ||
| { | ||
| "summaryMemoryStrategy": { | ||
| "name": "SessionSummarizer", | ||
| "namespaces": ["/summaries/{actorId}/{sessionId}"] | ||
| } | ||
| }, | ||
| { | ||
| "userPreferenceMemoryStrategy": { | ||
| "name": "PreferenceLearner", | ||
| "namespaces": ["/preferences/{actorId}"] | ||
| } | ||
| }, | ||
| { | ||
| "semanticMemoryStrategy": { | ||
| "name": "FactExtractor", | ||
| "namespaces": ["/facts/{actorId}"] | ||
| } | ||
| } | ||
| ] | ||
| ) | ||
| MEM_ID = comprehensive_memory.get('id') | ||
| ACTOR_ID = "actor_id_test_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
| SESSION_ID = "testing_session_id_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
|
|
||
| ``` | ||
|
|
||
| ### Single Namespace Retrieval | ||
|
|
||
| ```python | ||
| config = AgentCoreMemoryConfig( | ||
| memory_id=MEM_ID, | ||
| session_id=SESSION_ID, | ||
| actor_id=ACTOR_ID, | ||
| retrieval_config={ | ||
| "/preferences/{actorId}": RetrievalConfig( | ||
| top_k=5, | ||
| relevance_score=0.7 | ||
| ) | ||
| } | ||
| ) | ||
| session_manager = AgentCoreMemorySessionManager(config, region_name='us-east-1') | ||
| ltm_agent = Agent(session_manager=session_manager) | ||
| ``` | ||
|
|
||
| ### Multiple Namespace Retrieval | ||
|
|
||
| ```python | ||
| config = AgentCoreMemoryConfig( | ||
| memory_id=MEM_ID, | ||
| session_id=SESSION_ID, | ||
| actor_id=ACTOR_ID, | ||
| retrieval_config={ | ||
| "/preferences/{actorId}": RetrievalConfig( | ||
| top_k=5, | ||
| relevance_score=0.7 | ||
| ), | ||
| "/facts/{actorId}": RetrievalConfig( | ||
| top_k=10, | ||
| relevance_score=0.3 | ||
| ), | ||
| "/summaries/{actorId}/{sessionId}": RetrievalConfig( | ||
| top_k=5, | ||
| relevance_score=0.5 | ||
| ) | ||
| } | ||
| ) | ||
| session_manager = AgentCoreMemorySessionManager(config, region_name='us-east-1') | ||
| agent_with_multiple_namespaces = Agent(session_manager=session_manager) | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Large Payload example processing an Image using the [strands_tools](https://github.com/strands-agents/tools) library | ||
|
|
||
| ### Agent with Image Processing | ||
|
|
||
| ```python | ||
| from strands import Agent, tool | ||
| from strands_tools import generate_image, image_reader | ||
|
|
||
| ACTOR_ID = "actor_id_test_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
| SESSION_ID = "testing_session_id_%s" % datetime.now().strftime("%Y%m%d%H%M%S") | ||
|
|
||
| config = AgentCoreMemoryConfig( | ||
| memory_id=MEM_ID, | ||
| session_id=SESSION_ID, | ||
| actor_id=ACTOR_ID, | ||
| ) | ||
| session_manager = AgentCoreMemorySessionManager(config, region_name='us-east-1') | ||
| agent_with_tools = Agent( | ||
| tools=[image_reader], | ||
| system_prompt="You will be provided with a filesystem path to an image. Describe the image in detail.", | ||
| session_manager=session_manager, | ||
| agent_id='my_test_agent_id' | ||
| ) | ||
| # Use with image | ||
| result = agent_with_tools("/path/to/image.png") | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## Key Configuration Options | ||
|
|
||
| ### AgentCoreMemoryConfig Parameters | ||
|
|
||
| - `memory_id`: ID of the Bedrock AgentCore Memory resource | ||
| - `session_id`: Unique identifier for the conversation session | ||
| - `actor_id`: Unique identifier for the user/actor | ||
| - `retrieval_config`: Dictionary mapping namespaces to RetrievalConfig objects | ||
|
|
||
| ### RetrievalConfig Parameters | ||
|
|
||
| - `top_k`: Number of top results to retrieve (default: 5) | ||
| - `relevance_score`: Minimum relevance threshold (0.0-1.0) | ||
|
|
||
| ### Memory Strategies | ||
| https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory-strategies.html | ||
|
|
||
| 1. **summaryMemoryStrategy**: Summarizes conversation sessions | ||
| 2. **userPreferenceMemoryStrategy**: Learns and stores user preferences | ||
| 3. **semanticMemoryStrategy**: Extracts and stores factual information | ||
|
|
||
| ### Namespace Patterns | ||
|
|
||
| - `/preferences/{actorId}`: User-specific preferences | ||
| - `/facts/{actorId}`: User-specific facts | ||
| - `/summaries/{actorId}/{sessionId}`: Session-specific summaries | ||
|
|
||
|
|
||
| --- | ||
|
|
||
| ## Important Notes | ||
|
|
||
| ### Session Management | ||
| - Only **one** agent per session is currently supported | ||
| - Creating multiple agents with the same session will show a warning | ||
|
|
||
| ### Memory Types | ||
| - **STM (Short-Term Memory)**: Basic conversation persistence within a session | ||
| - **LTM (Long-Term Memory)**: Advanced memory with multiple strategies for learning user preferences, facts, and summaries | ||
|
|
||
| ### Best Practices | ||
| - Use unique `session_id` for each conversation | ||
| - Use consistent `actor_id` for the same user across sessions | ||
| - Configure appropriate `relevance_score` thresholds for your use case | ||
| - Test with different `top_k` values to optimize retrieval performance |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| """Strands integration for Bedrock AgentCore Memory.""" |
85 changes: 85 additions & 0 deletions
85
src/bedrock_agentcore/memory/integrations/strands/bedrock_converter.py
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| """Bedrock AgentCore Memory conversion utilities.""" | ||
|
|
||
| import json | ||
| import logging | ||
| from typing import Any, Tuple | ||
|
|
||
| from strands.types.session import SessionMessage | ||
|
|
||
| logger = logging.getLogger(__name__) | ||
|
|
||
| CONVERSATIONAL_MAX_SIZE = 9000 | ||
|
|
||
|
|
||
| class AgentCoreMemoryConverter: | ||
| """Handles conversion between Strands and Bedrock AgentCore Memory formats.""" | ||
|
|
||
| @staticmethod | ||
| def message_to_payload(session_message: SessionMessage) -> list[Tuple[str, str]]: | ||
| """Convert a SessionMessage to Bedrock AgentCore Memory message format. | ||
|
|
||
| Args: | ||
| session_message (SessionMessage): The session message to convert. | ||
|
|
||
| Returns: | ||
| list[Tuple[str, str]]: list of (text, role) tuples for Bedrock AgentCore Memory. | ||
| """ | ||
| session_dict = session_message.to_dict() | ||
| return [(json.dumps(session_dict), session_message.message["role"])] | ||
|
|
||
| @staticmethod | ||
| def events_to_messages(events: list[dict[str, Any]]) -> list[SessionMessage]: | ||
| """Convert Bedrock AgentCore Memory events to SessionMessages. | ||
|
|
||
| Args: | ||
| events (list[dict[str, Any]]): list of events from Bedrock AgentCore Memory. | ||
| Each individual event looks as follows: | ||
| ``` | ||
| { | ||
| "memoryId": "unique_mem_id", | ||
| "actorId": "actor_id", | ||
| "sessionId": "session_id", | ||
| "eventId": "0000001756147154000#ffa53e54", | ||
| "eventTimestamp": datetime.datetime(2025, 8, 25, 15, 12, 34, tzinfo=tzlocal()), | ||
| "payload": [ | ||
| { | ||
| "conversational": { | ||
| "content": {"text": "What is the weather?"}, | ||
| "role": "USER", | ||
| } | ||
| } | ||
| ], | ||
| "branch": {"name": "main"}, | ||
| } | ||
| ``` | ||
|
|
||
| Returns: | ||
| list[SessionMessage]: list of SessionMessage objects. | ||
| """ | ||
| messages = [] | ||
| for event in events: | ||
| for payload_item in event.get("payload", []): | ||
| if "conversational" in payload_item: | ||
| conv = payload_item["conversational"] | ||
| messages.append(SessionMessage.from_dict(json.loads(conv["content"]["text"]))) | ||
| elif "blob" in payload_item: | ||
| try: | ||
| blob_data = json.loads(payload_item["blob"]) | ||
| if isinstance(blob_data, (tuple, list)) and len(blob_data) == 2: | ||
| try: | ||
| messages.append(SessionMessage.from_dict(json.loads(blob_data[0]))) | ||
| except (json.JSONDecodeError, ValueError): | ||
| logger.error("This is not a SessionMessage but just a blob message. Ignoring") | ||
| except (json.JSONDecodeError, ValueError): | ||
| logger.error("Failed to parse blob content: %s", payload_item) | ||
| return list(reversed(messages)) | ||
|
|
||
| @staticmethod | ||
| def total_length(message: tuple[str, str]) -> int: | ||
| """Calculate total length of a message tuple.""" | ||
| return sum(len(text) for text in message) | ||
|
|
||
| @staticmethod | ||
| def exceeds_conversational_limit(message: tuple[str, str]) -> bool: | ||
| """Check if message exceeds conversational size limit.""" | ||
| return AgentCoreMemoryConverter.total_length(message) >= CONVERSATIONAL_MAX_SIZE |
37 changes: 37 additions & 0 deletions
37
src/bedrock_agentcore/memory/integrations/strands/config.py
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| """Configuration for AgentCore Memory Session Manager.""" | ||
|
|
||
| from typing import Dict, Optional | ||
|
|
||
| from pydantic import BaseModel, Field | ||
|
|
||
|
|
||
| class RetrievalConfig(BaseModel): | ||
| """Configuration for memory retrieval operations. | ||
|
|
||
| Attributes: | ||
| top_k: Number of top-scoring records to return from semantic search (default: 10) | ||
| relevance_score: Relevance score to filter responses from semantic search (default: 0.2) | ||
| strategy_id: Optional parameter to filter memory strategies (default: None) | ||
| initialization_query: Optional custom query for initialization retrieval (default: None) | ||
| """ | ||
|
|
||
| top_k: int = Field(default=10, gt=0, le=1000) | ||
| relevance_score: float = Field(default=0.2, ge=0.0, le=1.0) | ||
| strategy_id: Optional[str] = None | ||
| initialization_query: Optional[str] = None | ||
|
|
||
|
|
||
| class AgentCoreMemoryConfig(BaseModel): | ||
| """Configuration for AgentCore Memory Session Manager. | ||
|
|
||
| Attributes: | ||
| memory_id: Required Bedrock AgentCore Memory ID | ||
| session_id: Required unique ID for the session | ||
| actor_id: Required unique ID for the agent instance/user | ||
| retrieval_config: Optional dictionary mapping namespaces to retrieval configurations | ||
| """ | ||
|
|
||
| memory_id: str = Field(min_length=1) | ||
| session_id: str = Field(min_length=1) | ||
| actor_id: str = Field(min_length=1) | ||
| retrieval_config: Optional[Dict[str, RetrievalConfig]] = None |
Empty file.
Oops, something went wrong.
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.