-
Notifications
You must be signed in to change notification settings - Fork 66
feat: Add automatic memory provisioning to Bedrock AgentCore CLI #204
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
Conversation
- Integrate AgentCore Memory Manager for STM and LTM configuration - Add memory type selection prompt during agent configuration - Implement automatic memory resource creation with appropriate strategies - Support both short-term memory (30-day retention) and long-term memory extraction - Pass memory configuration to container runtime via environment variables - Handle idempotent memory operations for existing resources
Signed-off-by: Sundar Raghavan <[email protected]>
Remove blocking wait for LTM strategy provisioning during launch Use batch strategy updates to reduce provisioning time from ~3 minutes to seconds Add memory provisioning status to agentcore status command Fix status panel formatting with proper newline characters Use async memory creation for faster agent deployment
… into feature/cli-memory-provisioning
Remove blocking wait for LTM strategy provisioning during launch Use batch strategy updates to reduce provisioning time from ~3 minutes to seconds Add memory provisioning status to agentcore status command Fix status panel formatting with proper newline characters Use async memory creation for faster agent deployment
class MemoryConfig(BaseModel): | ||
"""Memory configuration for BedrockAgentCore.""" | ||
|
||
enabled: bool = Field(default=False, description="Whether memory is enabled") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we enable memory by default? also does this mean short-term memory (event/conversation history) or long-term memory (extraction of memory records from short-term memory)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see there is also enable_ltm -- I think this is confusing to have both controls. Instead, this argument should be an enum like STM_AND_LTM or STM_ONLY or NO_MEMORY (to have LTM, you must have STM)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
short term memory is enabled by default. User will be given a choice to enable LTM - that will be Yes/No - If yes, both STM and LTM - I can clarify the verbiage in setup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced the enabled + enable_ltm boolean combo with a single enum-style field using Literal types (STM_ONLY, STM_AND_LTM, NO_MEMORY)
|
||
# Create memory config | ||
memory_config = MemoryConfig() | ||
memory_config.enabled = True # Always true for STM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment as below about using enums and having only one input
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replaced the enabled + enable_ltm boolean combo with a single enum-style field using Literal types (STM_ONLY, STM_AND_LTM, NO_MEMORY)
BEDROCK_AGENTCORE_MEMORY_ID={{ memory_id }}{% endif %}{% if memory_name %} \ | ||
BEDROCK_AGENTCORE_MEMORY_NAME={{ memory_name }}{% endif %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we give the user some easier affordance for setting this up? Like can we (or do we) prompt the user to provide these? Or, better yet, could we call ListMemories and let the user choose and then assist them in creating a memory if there isn't a memory in the list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes - this is planned as a fast follow up
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Completed this implementation - Users can choose memory id from the List of memories.
Returns: | ||
Tuple of (enable_memory, enable_ltm) | ||
""" | ||
console.print("\\n🧠 [cyan]Memory Configuration[/cyan]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚠️ ℹ️ No container engine found (Docker/Finch/Podman not installed)
✅ Default deployment uses CodeBuild (no container engine needed)
💡 Run 'agentcore launch' for cloud-based building and deployment
💡 For local builds, install Docker, Finch, or Podman
\n🧠 Memory Configuration
✓ Short-term memory is enabled by default
this \n is extra
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, will fix this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still need this :)
# Use private method to avoid waiting | ||
memory = memory_manager._create_memory( | ||
name=memory_name, | ||
description=f"Memory for agent {agent_name} with {'STM+LTM' if strategies else 'STM only'}", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not sure where to leave this comment, but in agentcore status
➜ agentcore status
✅ MemoryManager initialized for region: us-east-1
╭────────────────────────────────────────────────────────────────────────── Agent Status: my_agent ──────────────────────────────────────────────────────────────────────────╮
│ Ready - Agent deployed and endpoint available │
│ │
│ Agent Details: │
│ Agent Name: my_agent │
│ Agent ARN: arn:aws:bedrock-agentcore:us-east-1:332634280070:runtime/my_agent-SnemZt47u5 │
│ Endpoint: DEFAULT (READY) │
│ Region: us-east-1 | Account: 332634280070 │
│ │
│ Memory: STM+LTM (3 strategies) (bedrock_agentcore_my_agent_memory-J7Aosv7Rh7) │
│ │
│ Deployment Info: │
│ Created: 2025-09-26 17:50:16.300812+00:00 │
│ Last Updated: 2025-09-26 17:50:17.515972+00:00 │
│ │
│ 📋 CloudWatch Logs: │
│ /aws/bedrock-agentcore/runtimes/my_agent-SnemZt47u5-DEFAULT --log-stream-name-prefix "2025/09/26/[runtime-logs]" │
│ /aws/bedrock-agentcore/runtimes/my_agent-SnemZt47u5-DEFAULT --log-stream-names "otel-rt-logs" │
│ │
│ 🔍 GenAI Observability Dashboard: │
│ https://console.aws.amazon.com/cloudwatch/home?region=us-east-1#gen-ai-observability/agent-core │
│ │
│ ⏱️ Note: Observability data may take up to 10 minutes to appear after first launch │
│ │
│ 💡 Tail logs with: │
│ aws logs tail /aws/bedrock-agentcore/runtimes/my_agent-SnemZt47u5-DEFAULT --log-stream-name-prefix "2025/09/26/[runtime-logs]" --follow │
│ aws logs tail /aws/bedrock-agentcore/runtimes/my_agent-SnemZt47u5-DEFAULT --log-stream-name-prefix "2025/09/26/[runtime-logs]" --since 1h │
│ │
│ Ready to invoke: │
│ agentcore invoke '{"prompt": "Hello"}' │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
we need more details about the memory resource
│ Memory: STM+LTM (3 strategies) (bedrock_agentcore_my_agent_memory-J7Aosv7Rh7)
we should render all the fields that are on the memory resource here. Should be pretty straightforward to just get an LLM to do that imo
…TM memory status on first invoke.
Addresses PR review comments: - Replace boolean flags (enabled/enable_ltm) with single Literal enum type (STM_ONLY, STM_AND_LTM, NO_MEMORY) for clearer memory mode configuration - Add ListMemories integration in configure flow allowing users to select existing memory resources or create new ones with guided prompts - Enhance agentcore status output to display comprehensive memory resource details including all fields, strategies, namespaces, and provisioning status
return False, False | ||
|
||
# If memory is enabled, ask about long-term memory | ||
console.print("\\n[dim]Long-term memory extracts:[/dim]") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the \n a typo here too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks, updated this
return self._prompt_new_memory_config() | ||
|
||
memory_manager = MemoryManager(region_name=region) | ||
existing_memories = memory_manager.list_memories(max_results=10) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in a follow up, would be nice to figure out how to list all for pre-selection (like maybe exposed via a search or displayed in 3 columns with the full names truncated)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ack
else: | ||
log.debug("No execution role provided and auto-create disabled") | ||
|
||
# Prompt for memory configuration BEFORE generating Dockerfile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this commented out code be here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks. updated this
# Create memory if configured | ||
if agent_config.memory and not agent_config.memory.memory_id: | ||
log.info("Creating memory resource for agent: %s", agent_name) | ||
try: | ||
from ...operations.memory.constants import StrategyType | ||
from ...operations.memory.manager import MemoryManager | ||
|
||
memory_manager = MemoryManager(region_name=agent_config.aws.region) | ||
memory_name = f"bedrock_agentcore_{agent_name}_memory" | ||
|
||
# Check if memory already exists | ||
existing_memory = None | ||
try: | ||
memories = memory_manager.list_memories() | ||
for m in memories: | ||
if m.id.startswith(memory_name): | ||
existing_memory = memory_manager.get_memory(m.id) | ||
log.info("Found existing memory: %s", m.id) | ||
break | ||
except Exception as e: | ||
log.debug("Error checking for existing memory: %s", e) | ||
|
||
# Determine if we need to create new memory or add strategies to existing | ||
if existing_memory: | ||
# Check if strategies need to be added | ||
existing_strategies = [] | ||
if hasattr(existing_memory, "strategies") and existing_memory.strategies: | ||
existing_strategies = existing_memory.strategies | ||
|
||
log.info("Existing memory has %d strategies", len(existing_strategies)) | ||
|
||
# If LTM is enabled but no strategies exist, add them | ||
if agent_config.memory.has_ltm and len(existing_strategies) == 0: | ||
log.info("Adding LTM strategies to existing memory...") | ||
|
||
# Add all strategies in one batch call | ||
memory_manager.update_memory_strategies_and_wait( | ||
memory_id=existing_memory.id, | ||
add_strategies=[ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reuse same logic across code-build and non code-build functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted all memory creation logic into a single _ensure_memory_for_agent() helper function at the top of launch.py. Both CodeBuild and non-CodeBuild paths now call this one function.
entrypoint_path = Path(entrypoint_parts[0]) | ||
agent_var_name = entrypoint_parts[1] if len(entrypoint_parts) > 1 else agent_name | ||
|
||
runtime.generate_dockerfile( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should generate Dockerfile with launch. This should also be dine with non code build launch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the Dockerfile regeneration in _launch_with_codebuild(). Memory env vars now passed purely at runtime via environmentVariables in the agent deployment call. The _deploy_to_bedrock_agentcore() function already handles this injection
agent_arn=agent_config.bedrock_agentcore.agent_arn, | ||
) | ||
|
||
if agent_config.memory and agent_config.memory.memory_id: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
memory specific method for status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed status.py to use MemoryManager's dedicated methods instead of raw dictionary access:
get_memory_status(memory_id) - returns status string with proper error handling
get_memory() - returns memory metadata
get_memory_strategies(memory_id) - handles field name variations (strategies vs memoryStrategies)
|
||
## Prerequisites | ||
|
||
- **AWS Permissions:** You need specific permissions to use the starter toolkit. See the [Permissions Reference](#permissions-reference) section for the complete IAM policy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Highlight that if developer is using root user/admins permissions then these steps are not required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
if memory['status'] != 'ACTIVE': | ||
agent = Agent( | ||
model=MODEL_ID, | ||
system_prompt="You are a helpful assistant.", | ||
tools=[calculate] | ||
) | ||
result = agent(payload.get("prompt", "")) | ||
return { | ||
"response": f"[Memory initializing] {result.message.get('content', [{}])[0].get('text', '')}", | ||
"session_id": "temp" | ||
} | ||
except Exception: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
completed
Key components in this implementation: | ||
|
||
- **Runtime**: Container orchestration service that hosts your agent | ||
- **Memory Service**: Dual-layer storage with STM (exact conversation storage) and LTM (intelligent fact extraction) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it does more than fact extraction.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated to mention all strategies.
|
||
Key components in this implementation: | ||
|
||
- **Runtime**: Container orchestration service that hosts your agent |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
its not an orchestration service. Use descriptions for each aligned aws docs and add those refs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
updated this.
memory_config = AgentCoreMemoryConfig( | ||
memory_id=MEMORY_ID, | ||
session_id=session_id, | ||
actor_id="user", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not use env var for user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missed to update this in the latest version w/ streaming.. updated this now
# "You work at TechCorp." | ||
``` | ||
|
||
### Test Code Interpreter with Memory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is memory important for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
originally had this testing with different session ids.. removed it
project_config = load_config(config_path) | ||
agent_config = project_config.get_agent_config(agent_name) | ||
|
||
# Check memory status on first invoke if LTM is enabled |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why not reuse the status method with status.py instead? seems duplicate logic across invoke and status.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
invoke.py needs a single lightweight check: "Is memory ready or should I fail gracefully?" Adding a dependency on status.py would add 2+ API calls per invoke (agent runtime, endpoint, strategies) and couple invoke logic to CLI display formatting
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have a method that can serve both?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that will work but needs some design considerations.. right now - invoke.py
needs: “Is memory ready?” (boolean, 1 API call). and status.py
needs: “Full memory diagnostics” (rich object, 4 API calls).. creating a shared method with a flag like get_memory_info(full_diagnostics=True/False)
will returns different types..
code_session_id = code_interpreter.start( | ||
name="calc_session", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use same as runtime session id? That would avoid potential crosswiring across multiple sessions/users within an account.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
right.. now uses runtime session id
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lets follow up on -
- Streaming
- Memory status simplification
- Strands documentation links in sample
- **Runtime**: Managed compute service that runs your containerized agent with automatic scaling. See [AgentCore Runtime docs](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html) | ||
- **Memory Service**: Dual-layer storage with short-term memory (chronological event storage with 30-day retention) and long-term memory (extraction of user preferences, semantic facts, and session summaries). See [AgentCore Memory docs](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html) | ||
- **Code Interpreter**: AWS-managed Python sandbox with pre-installed libraries. See [AgentCore Code Interpreter](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/code-interpreter-tool.html) | ||
- **Strands Framework**: Simplifies agent creation with memory session management |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ref for this and the description is not correct.
Description
This PR integrates AWS Bedrock AgentCore Memory into the CLI toolkit, enabling automatic provisioning of both short-term memory (STM) and long-term memory (LTM) capabilities for agents. Users can now seamlessly enable memory features during agent configuration without manual API calls.
Changes
configure.py
allowing users to choose between STM-only or STM+LTMMemoryManager
fromoperations/memory
to automatically provision memory resources/users/{actorId}/preferences
)/users/{actorId}/facts
)/summaries/{actorId}/{sessionId}
)Usage
Type of Change
Testing
Checklist
Security Checklist
Breaking Changes
List any breaking changes and migration instructions:
N/A
Additional Notes
Add any additional notes or context about the PR here.