(02-usecases)Amazon Bedrock AgentCore Deployment with CDK (#924)
* Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK * Amazon Bedrock AgentCore Deployment with CDK --------- Co-authored-by: Uriel Ramirez <beralfon@amazon.com>
This commit is contained in:
@@ -35,31 +35,30 @@ The following architecture diagram illustrates a reference solution for a genera
|
||||
> [!IMPORTANT]
|
||||
> This sample application is meant for demo purposes and is not production ready. Please make sure to validate the code with your organizations security best practices.
|
||||
|
||||
### AgentCore Runtime & Memory Infrastructure
|
||||
|
||||
**Amazon Bedrock AgentCore** is a fully managed service that enables you to deploy, run, and scale your custom agent applications with built-in runtime and memory capabilities.
|
||||
|
||||
- **[Amazon Bedrock AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html)**: Provides the managed execution environment with invocation endpoints (`/invocations`) and health monitoring (`/ping`) for your agent instances
|
||||
- **[Amazon Bedrock AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html)**: A fully managed service that gives AI agents the ability to remember, learn, and evolve through interactions by capturing events, transforming them into memories, and retrieving relevant context when needed
|
||||
|
||||
The AgentCore infrastructure handles all storage complexity and provides efficient retrieval without requiring developers to manage underlying infrastructure, ensuring continuity and traceability across agent interactions.
|
||||
|
||||
### CDK Infrastructure Deployment
|
||||
|
||||
The AWS CDK stack deploys and configures the following managed services:
|
||||
|
||||
- **IAM AgentCore Execution Role**: Provides necessary permissions for Amazon Bedrock AgentCore execution
|
||||
- **VPC and Private Subnet**: Network isolation and security for database resources
|
||||
- **Amazon Aurora Serverless PostgreSQL**: Stores the video game sales data with RDS Data API integration
|
||||
**Amazon Bedrock AgentCore Resources:**
|
||||
- **[AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html)**: Provides the managed execution environment with invocation endpoints (`/invocations`) and health monitoring (`/ping`) for your agent instances
|
||||
- **[AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html)**: A fully managed service that gives AI agents the ability to remember, learn, and evolve through interactions by capturing events, transforming them into memories, and retrieving relevant context when needed
|
||||
|
||||
The AgentCore infrastructure handles all storage complexity and provides efficient retrieval without requiring developers to manage underlying infrastructure, ensuring continuity and traceability across agent interactions.
|
||||
|
||||
**Data Source and VPC Infrastructure:**
|
||||
- **VPC with Public and Private Subnets**: Network isolation and security for database resources
|
||||
- **Amazon Aurora Serverless v2 PostgreSQL**: Stores the video game sales data with RDS Data API integration
|
||||
- **Amazon DynamoDB**: Stores raw query results for data analysis audit trails
|
||||
- **Parameter Store Configuration Management**: Securely manages application configuration
|
||||
- **AWS Secrets Manager**: Secure storage for database credentials
|
||||
- **Amazon S3**: Import bucket for loading data into Aurora PostgreSQL
|
||||
- **SSM Parameter Store**: Configuration management for AgentCore runtime parameters
|
||||
|
||||
### Amplify Deployment for the Front-End Application
|
||||
|
||||
- **React Web Application**: Delivers the user interface for the assistant
|
||||
- Uses Amazon Cognito for user authentication and permissions management
|
||||
- The application invokes the Amazon Bedrock AgentCore for interacting with the assistant
|
||||
- For chart generation, the application directly invokes the Claude 3.7 Sonnet model
|
||||
- For chart generation, the application directly invokes the Claude Haiku 4.5 model
|
||||
|
||||
### Strands Agent Features
|
||||
|
||||
@@ -81,18 +80,17 @@ The AWS CDK stack deploys and configures the following managed services:
|
||||
The **user interaction workflow** operates as follows:
|
||||
|
||||
- The web application sends user business questions to the AgentCore Invoke
|
||||
- The Strands Agent (powered by Claude 3.7 Sonnet) processes natural language and determines when to execute database queries
|
||||
- The Strands Agent (powered by Claude Haiku 4.5) processes natural language and determines when to execute database queries
|
||||
- The agent's built-in tools execute SQL queries against the Aurora PostgreSQL database and formulate an answer to the question
|
||||
- AgentCore Memory captures session interactions and retrieves previous conversations for context
|
||||
- After the agent's response is received by the web application, the raw data query results are retrieved from the DynamoDB table to display both the answer and the corresponding records
|
||||
- For chart generation, the application invokes a model (powered by Claude 3.7 Sonnet) to analyze the agent's answer and raw data query results to generate the necessary data to render an appropriate chart visualization
|
||||
- For chart generation, the application invokes a model (powered by Claude Haiku 4.5) to analyze the agent's answer and raw data query results to generate the necessary data to render an appropriate chart visualization
|
||||
|
||||
## Deployment Instructions
|
||||
|
||||
The deployment consists of two main steps:
|
||||
|
||||
1. **Back-End Deployment - [Data Source and Configuration Management Deployment with CDK](./cdk-agentcore-strands-data-analyst-assistant/)**
|
||||
1. **Agent Deployment - [Strands Agent Infrastructure Deployment with AgentCore](./agentcore-strands-data-analyst-assistant/)**
|
||||
1. **Back-End Deployment - [Amazon Bedrock AgentCore and Data Source Deployment with CDK](./cdk-data-analyst-assistant-agentcore-strands/)**
|
||||
2. **Front-End Implementation - [Integrating AgentCore with a Ready-to-Use Data Analyst Assistant Application](./amplify-video-games-sales-assistant-agentcore-strands/)**
|
||||
|
||||
> [!NOTE]
|
||||
|
||||
-180
@@ -1,180 +0,0 @@
|
||||
# Agent Deployment - Strands Agent Infrastructure Deployment with AgentCore
|
||||
|
||||
Deploy the Strands Agent Data Analyst Assistant for Video Game Sales using **[Amazon Bedrock AgentCore](https://aws.amazon.com/bedrock/agentcore/)**'s fully managed service for scalable agent applications with **Runtime** and **Memory** capabilities.
|
||||
|
||||
> [!NOTE]
|
||||
> **Working Directory**: Make sure you are in the `agentcore-strands-data-analyst-assistant/` folder before starting this tutorial. All commands in this guide should be executed from this directory.
|
||||
|
||||
## Overview
|
||||
|
||||
This tutorial guides you through deploying a video game sales data analyst agent using Amazon Bedrock AgentCore's managed infrastructure, includes the following modular services:
|
||||
|
||||
- **[Amazon Bedrock AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/agents-tools-runtime.html)**: Provides the managed execution environment with invocation endpoints (`/invocations`) and health monitoring (`/ping`) for your agent instances
|
||||
- **[Amazon Bedrock AgentCore Memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/memory.html)**: A fully managed service that gives AI agents the ability to remember, learn, and evolve through interactions by capturing events, transforming them into memories, and retrieving relevant context when needed
|
||||
|
||||
Don't forget to review the **[Amazon Bedrock AgentCore documentation](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/what-is-bedrock-agentcore.html)**.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This sample application is meant for demo purposes and is not production ready. Please make sure to validate the code with your organizations security best practices.
|
||||
>
|
||||
> Remember to clean up resources after testing to avoid unnecessary costs by following the clean-up steps provided.
|
||||
|
||||
## Environment Setup and Requirements
|
||||
|
||||
Before you begin, ensure you have:
|
||||
|
||||
* **[Back-End Deployment - Data Source and Configuration Management Deployment with CDK](../cdk-agentcore-strands-data-analyst-assistant)**
|
||||
* **[Docker](https://www.docker.com)**
|
||||
* **Required Packages**:
|
||||
* Install the Amazon Bedrock AgentCore CLI:
|
||||
```bash
|
||||
pip install bedrock-agentcore
|
||||
```
|
||||
* Install all project dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
## Create Short-Term AgentCore Memory
|
||||
|
||||
Before deploying your agent, you need to create a **[short-term memory](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/short-term-memory.html)** store that will help your agent maintain conversation context:
|
||||
|
||||
1. Create a memory store with a 7-day default expiry period:
|
||||
|
||||
```bash
|
||||
python3 resources/memory_manager.py create DataAnalystAssistantMemory ${MEMORY_ID_SSM_PARAMETER}
|
||||
```
|
||||
|
||||
2. List all available memory stores to validate that your memory store was created successfully:
|
||||
|
||||
```bash
|
||||
python3 resources/memory_manager.py list
|
||||
```
|
||||
|
||||
This memory store enables your agent to remember previous interactions within the same session, providing a more coherent and contextual conversation experience.
|
||||
|
||||
|
||||
## Local Testing
|
||||
|
||||
Before deploying to AWS, you can test the Data Analyst Agent locally to verify functionality:
|
||||
|
||||
1. Set the required environment variable and start the local agent server:
|
||||
|
||||
```bash
|
||||
export PROJECT_ID="agentcore-data-analyst-assistant"
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
This launches a local server on port 8080 that simulates the AgentCore runtime environment.
|
||||
|
||||
2. In a different terminal, create a session ID for conversation tracking:
|
||||
|
||||
```bash
|
||||
export SESSION_ID=$(uuidgen)
|
||||
```
|
||||
|
||||
3. Test the agent with example queries using curl:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Hello world!", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "what is the structure of your data available?!", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Which developers tend to get the best reviews?", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Give me a summary of our conversation", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
|
||||
## Deploy the Strands Agent with Amazon Bedrock AgentCore
|
||||
|
||||
Deploy your agent to AWS with these simple steps:
|
||||
|
||||
1. Configure the agent deployment accepting default values when prompted:
|
||||
|
||||
```bash
|
||||
agentcore configure \
|
||||
--entrypoint app.py \
|
||||
--name agentcoredataanalystassistant \
|
||||
-er $AGENT_CORE_ROLE_EXECUTION \
|
||||
--disable-memory \
|
||||
--deployment-type container
|
||||
```
|
||||
|
||||
2. Launch the agent infrastructure:
|
||||
|
||||
```bash
|
||||
agentcore launch --env PROJECT_ID="agentcore-data-analyst-assistant"
|
||||
```
|
||||
|
||||
## Testing the Deployed Agent
|
||||
|
||||
Create a session ID for conversation tracking and test your deployed agent:
|
||||
|
||||
```bash
|
||||
export SESSION_ID=$(uuidgen)
|
||||
```
|
||||
|
||||
Test with these example queries:
|
||||
|
||||
```bash
|
||||
agentcore invoke '{
|
||||
"prompt": "Hello world!",
|
||||
"session_id": "'$SESSION_ID'",
|
||||
"last_k_turns": 20
|
||||
}'
|
||||
```
|
||||
|
||||
```bash
|
||||
agentcore invoke '{
|
||||
"prompt": "what is the structure of your data available?!",
|
||||
"session_id": "'$SESSION_ID'",
|
||||
"last_k_turns": 20
|
||||
}'
|
||||
```
|
||||
|
||||
```bash
|
||||
agentcore invoke '{
|
||||
"prompt": "Which developers tend to get the best reviews?",
|
||||
"session_id": "'$SESSION_ID'",
|
||||
"last_k_turns": 20
|
||||
}'
|
||||
```
|
||||
|
||||
```bash
|
||||
agentcore invoke '{
|
||||
"prompt": "Give me a summary of our conversation",
|
||||
"session_id": "'$SESSION_ID'",
|
||||
"last_k_turns": 20
|
||||
}'
|
||||
```
|
||||
|
||||
**Expected Behavior**: The agent responds as "Gus," a video game sales data analyst assistant who provides information about the video_games_sales_units database (64,016 game titles from 1971-2024), analyzes developer review scores, and maintains conversation context across interactions.
|
||||
|
||||
## Next Step
|
||||
|
||||
You can now proceed to the **[Front-End Implementation - Integrating AgentCore with a Ready-to-Use Data Analyst Assistant Application](../amplify-video-games-sales-assistant-agentcore-strands/))**.
|
||||
|
||||
## Cleaning-up Resources (Optional)
|
||||
|
||||
To avoid unnecessary charges, delete the AgentCore run environment from the AWS Console.
|
||||
|
||||
## Thank You
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License.
|
||||
+40
-33
@@ -15,7 +15,7 @@ The application consists of two main components:
|
||||
- **Amazon Bedrock AgentCore Integration:**:
|
||||
- Uses your AgentCore deployment for data analysis and natural language processing
|
||||
- The application invokes the Amazon Bedrock AgentCore for interacting with the assistant
|
||||
- Directly invokes Claude 3.7 Sonnet model for chart generation and visualization
|
||||
- Directly invokes Claude Haiku 4.5 model for chart generation and visualization
|
||||
|
||||
> [!IMPORTANT]
|
||||
> This sample application is for demonstration purposes only and is not production-ready. Please validate the code against your organization's security best practices.
|
||||
@@ -100,28 +100,48 @@ amplify push
|
||||
> [!NOTE]
|
||||
> This creates a Cognito User Pool and Identity Pool in your AWS account for user authentication. AWS credentials for the Front-End Application are automatically managed through Cognito.
|
||||
|
||||
## Get CDK Output Values
|
||||
|
||||
Get the required values from your CDK project outputs. These values are needed for configuring AuthRole permissions and environment variables:
|
||||
|
||||
``` bash
|
||||
# Set the stack name environment variable
|
||||
export STACK_NAME=CdkDataAnalystAssistantAgentcoreStrandsStack
|
||||
|
||||
# Get the values from CDK outputs
|
||||
export QUESTION_ANSWERS_TABLE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableName'].OutputValue" --output text)
|
||||
export QUESTION_ANSWERS_TABLE_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableArn'].OutputValue" --output text)
|
||||
export AGENT_RUNTIME_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AgentRuntimeArn'].OutputValue" --output text)
|
||||
export AGENT_ENDPOINT_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AgentEndpointName'].OutputValue" --output text)
|
||||
|
||||
cat << EOF
|
||||
# DynamoDB Resources
|
||||
QUESTION_ANSWERS_TABLE_NAME: ${QUESTION_ANSWERS_TABLE_NAME}
|
||||
QUESTION_ANSWERS_TABLE_ARN: ${QUESTION_ANSWERS_TABLE_ARN}
|
||||
|
||||
# AgentCore Resources
|
||||
AGENT_RUNTIME_ARN: ${AGENT_RUNTIME_ARN}
|
||||
AGENT_ENDPOINT_NAME: ${AGENT_ENDPOINT_NAME}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Configure AuthRole Permissions
|
||||
|
||||
After authentication deployment, you need to grant your authenticated users permission to access AWS services.
|
||||
|
||||
1. **Find your AuthRole**: Go to AWS Console → IAM → Roles → Search for amplify-daabedrockagentcore-dev-*-authRole
|
||||
1. **Find your AuthRole**: Go to AWS Console → IAM → Roles → Search for `amplify-daabedrockagentcore-dev-*-authRole`
|
||||
|
||||
2. **Get the DynamoDB Table ARN**: From your CDK project outputs, get the `QuestionAnswersTableName` value:
|
||||
2. **Add an inline policy**: Click on the role → **Add permissions** → **Create inline policy** → Select **JSON** tab
|
||||
|
||||
``` bash
|
||||
# Set the stack name environment variable
|
||||
export STACK_NAME=CdkAgentcoreStrandsDataAnalystAssistantStack
|
||||
3. **Copy the policy below** and replace the following placeholders with your actual values:
|
||||
|
||||
# Get the DynamoDB table name and construct the ARN
|
||||
export QUESTION_ANSWERS_TABLE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableName'].OutputValue" --output text)
|
||||
export QUESTION_ANSWERS_TABLE_ARN="arn:aws:dynamodb:$(aws configure get region):$(aws sts get-caller-identity --query Account --output text):table/$QUESTION_ANSWERS_TABLE_NAME"
|
||||
echo "Table ARN: $QUESTION_ANSWERS_TABLE_ARN"
|
||||
```
|
||||
| Placeholder | Replace With | Example |
|
||||
|-------------|--------------|---------|
|
||||
| `<account_id>` | Your AWS Account ID (12-digit number) | `123456789012` |
|
||||
| `<question_answers_table_arn>` | `QUESTION_ANSWERS_TABLE_ARN` from CDK outputs above | `arn:aws:dynamodb:us-east-1:123456789012:table/QuestionAnswers-xxx` |
|
||||
| `<agent_runtime_arn>` | `AGENT_RUNTIME_ARN` from CDK outputs above | `arn:aws:bedrock-agentcore:us-east-1:123456789012:runtime/data-analyst-xxx` |
|
||||
|
||||
3. **Add this policy** (replace `<account_id>` with your AWS account ID, `<question_answers_table_arn>` with the ARN from step 2, and `<agent_arn>` with your AgentCore runtime ARN):
|
||||
|
||||
> [!NOTE]
|
||||
> The AgentCore runtime ARN has been pre-configured based on your current deployment. If you're using a different AgentCore runtime, update the ARN in the BedrockAgentCorePermissions section accordingly.
|
||||
**Policy to copy (replace placeholders):**
|
||||
|
||||
``` json
|
||||
{
|
||||
@@ -153,14 +173,16 @@ echo "Table ARN: $QUESTION_ANSWERS_TABLE_ARN"
|
||||
"Effect": "Allow",
|
||||
"Action": "bedrock-agentcore:InvokeAgentRuntime",
|
||||
"Resource": [
|
||||
"<agent_arn>",
|
||||
"<agent_arn>/runtime-endpoint/*"
|
||||
"<agent_runtime_arn>",
|
||||
"<agent_runtime_arn>/runtime-endpoint/*"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
4. **Save the policy** with a name like `DataAnalystAssistantPermissions`
|
||||
|
||||
## Configure Environment Variables
|
||||
|
||||
Rename the file **src/sample.env.js** to **src/env.js**:
|
||||
@@ -169,22 +191,7 @@ Rename the file **src/sample.env.js** to **src/env.js**:
|
||||
mv src/sample.env.js src/env.js
|
||||
```
|
||||
|
||||
### Get CDK Output Values
|
||||
|
||||
First, get the required values from your CDK project outputs:
|
||||
|
||||
``` bash
|
||||
# Set the stack name environment variable
|
||||
export STACK_NAME=CdkAgentcoreStrandsDataAnalystAssistantStack
|
||||
|
||||
# Get the DynamoDB table name and AgentCore Role ARN from CDK outputs
|
||||
export QUESTION_ANSWERS_TABLE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableName'].OutputValue" --output text)
|
||||
echo "Table Name: $QUESTION_ANSWERS_TABLE_NAME"
|
||||
```
|
||||
|
||||
### Update Environment Variables
|
||||
|
||||
In your **src/env.js** update the following environment variables:
|
||||
In your **src/env.js** update the following environment variables using the CDK output values from above:
|
||||
|
||||
- **QUESTION_ANSWERS_TABLE_NAME**: Use the value from the command above
|
||||
- **AGENT_RUNTIME_ARN**: Your AgentCore runtime ARN (format: "arn:aws:bedrock-agentcore:region:account:runtime/runtime-name")
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 422 KiB After Width: | Height: | Size: 434 KiB |
-19
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 16 KiB |
-136
@@ -1,136 +0,0 @@
|
||||
# Back-End Deployment - Data Source and Configuration Management Deployment with CDK
|
||||
|
||||
Deploy the back-end infrastructure for a Data Analyst Assistant for Video Game Sales using **[AWS Cloud Development Kit (CDK)](https://aws.amazon.com/cdk/)**.
|
||||
|
||||
> [!NOTE]
|
||||
> **Working Directory**: Make sure you are in the `cdk-agentcore-strands-data-analyst-assistant/` folder before starting this tutorial. All commands in this guide should be executed from this directory.
|
||||
|
||||
## Overview
|
||||
|
||||
This tutorial deploys the foundational AWS services required for the video game sales data analyst agent with the following key components:
|
||||
|
||||
- **IAM AgentCore Execution Role**: Comprehensive permissions for Amazon Bedrock AgentCore execution, including access to Bedrock models, RDS Data API, DynamoDB, and Secrets Manager
|
||||
- **VPC with Public and Private Subnets**: Network isolation and security for database resources with NAT Gateway for outbound connectivity
|
||||
- **Amazon Aurora Serverless v2 PostgreSQL**: Scalable database cluster storing video game sales data with RDS Data API integration and encryption
|
||||
- **Amazon DynamoDB**: Single table for tracking SQL query results with pay-per-request billing
|
||||
- **AWS Secrets Manager**: Secure storage for database credentials
|
||||
- **Amazon S3**: Import bucket for loading data into Aurora PostgreSQL with lifecycle policies
|
||||
- **VPC Gateway Endpoints**: Cost-effective access to S3 and DynamoDB services
|
||||
- **SSM Parameter Store**: Configuration management for AgentCore runtime parameters
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Remember to clean up resources after testing to avoid unnecessary costs by following the clean-up steps provided.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have:
|
||||
|
||||
* AWS Account and appropriate IAM permissions for services deployment
|
||||
* **Development Environment**:
|
||||
* Python 3.10 or later installed
|
||||
* **[AWS CDK Installed](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html)**
|
||||
|
||||
* Run this command to create a service-linked role for RDS:
|
||||
|
||||
```bash
|
||||
aws iam create-service-linked-role --aws-service-name rds.amazonaws.com
|
||||
```
|
||||
|
||||
## AWS Deployment
|
||||
|
||||
Navigate to the CDK project folder and install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Deploy the infrastructure:
|
||||
|
||||
```bash
|
||||
cdk deploy
|
||||
```
|
||||
|
||||
Default Parameters:
|
||||
- **ProjectId**: "agentcore-data-analyst-assistant" - Project identifier used for naming resources
|
||||
- **DatabaseName**: "video_games_sales" - Name of the database
|
||||
|
||||
Deployed Resources:
|
||||
|
||||
- **VPC**: Public/private subnets, NAT Gateway, security groups, VPC endpoints
|
||||
- **Aurora PostgreSQL Serverless v2**: Database cluster with RDS Data API
|
||||
- **DynamoDB**: Table for SQL query results
|
||||
- **S3**: Bucket for data imports with lifecycle policies
|
||||
- **Secrets Manager**: Database credentials storage
|
||||
- **IAM**: AgentCore execution role with Bedrock, RDS, DynamoDB permissions
|
||||
- **SSM Parameter Store**: Configuration parameters
|
||||
- `/<projectId>/SECRET_ARN`: Database secret ARN
|
||||
- `/<projectId>/AURORA_RESOURCE_ARN`: Aurora cluster ARN
|
||||
- `/<projectId>/DATABASE_NAME`: Database name
|
||||
- `/<projectId>/QUESTION_ANSWERS_TABLE`: DynamoDB question answers table name
|
||||
- `/<projectId>/MAX_RESPONSE_SIZE_BYTES`: Maximum response size in bytes (1MB)
|
||||
- `/<projectId>/MEMORY_ID`: AgentCore Memory ID for the Agent
|
||||
|
||||
These parameters are automatically retrieved by the Strands Agent to establish database connections and configure agent behavior.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Enhance AI safety and compliance by implementing **[Amazon Bedrock Guardrails](https://aws.amazon.com/bedrock/guardrails/)** for your AI applications with the seamless integration offered by **[Strands Agents SDK](https://strandsagents.com/latest/user-guide/safety-security/guardrails/)**.
|
||||
|
||||
## Load Sample Data into PostgreSQL Database
|
||||
|
||||
1. Install required Python dependencies:
|
||||
|
||||
``` bash
|
||||
pip install boto3
|
||||
```
|
||||
|
||||
2. Set up the required environment variables:
|
||||
|
||||
``` bash
|
||||
# Set the stack name environment variable
|
||||
export STACK_NAME=CdkAgentcoreStrandsDataAnalystAssistantStack
|
||||
|
||||
# Retrieve the output values and store them in environment variables
|
||||
export SECRET_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='SecretARN'].OutputValue" --output text)
|
||||
export DATA_SOURCE_BUCKET_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='DataSourceBucketName'].OutputValue" --output text)
|
||||
export AURORA_SERVERLESS_DB_CLUSTER_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AuroraServerlessDBClusterARN'].OutputValue" --output text)
|
||||
export AGENT_CORE_ROLE_EXECUTION=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AgentCoreMyRoleARN'].OutputValue" --output text)
|
||||
export MEMORY_ID_SSM_PARAMETER=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='MemoryIdSSMParameter'].OutputValue" --output text)
|
||||
cat << EOF
|
||||
STACK_NAME: ${STACK_NAME}
|
||||
SECRET_ARN: ${SECRET_ARN}
|
||||
DATA_SOURCE_BUCKET_NAME: ${DATA_SOURCE_BUCKET_NAME}
|
||||
AURORA_SERVERLESS_DB_CLUSTER_ARN: ${AURORA_SERVERLESS_DB_CLUSTER_ARN}
|
||||
AGENT_CORE_ROLE_EXECUTION: ${AGENT_CORE_ROLE_EXECUTION}
|
||||
MEMORY_ID_SSM_PARAMETER: ${MEMORY_ID_SSM_PARAMETER}
|
||||
EOF
|
||||
|
||||
```
|
||||
|
||||
3. Load sample data into PostgreSQL:
|
||||
|
||||
``` bash
|
||||
python3 resources/create-sales-database.py
|
||||
```
|
||||
|
||||
The script uses the **[video_games_sales_no_headers.csv](./resources/database/video_games_sales_no_headers.csv)** as the data source.
|
||||
|
||||
> [!NOTE]
|
||||
> The data source provided contains information from [Video Game Sales](https://www.kaggle.com/datasets/asaniczka/video-game-sales-2024) which is made available under the [ODC Attribution License](https://opendatacommons.org/licenses/odbl/1-0/).
|
||||
|
||||
## Next Step
|
||||
|
||||
You can now proceed to the **[Agent Deployment - Strands Agent Infrastructure Deployment with AgentCore](../agentcore-strands-data-analyst-assistant/))**.
|
||||
|
||||
## Cleaning-up Resources (Optional)
|
||||
|
||||
To avoid unnecessary charges, delete the CDK stack:
|
||||
|
||||
``` bash
|
||||
cdk destroy
|
||||
```
|
||||
|
||||
## Thank You
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License.
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
# Data Analyst Assistant - Amazon Bedrock AgentCore and Data Source Deployment with CDK
|
||||
|
||||
Deploy the complete infrastructure for a Data Analyst Assistant for Video Game Sales using **[AWS Cloud Development Kit (CDK)](https://aws.amazon.com/cdk/)** and **[Amazon Bedrock AgentCore](https://docs.aws.amazon.com/bedrock/latest/userguide/agentcore.html)**.
|
||||
|
||||
> [!NOTE]
|
||||
> **Working Directory**: Make sure you are in the `cdk-data-analyst-assistant-agentcore-strands/` folder before starting this tutorial. All commands in this guide should be executed from this directory.
|
||||
|
||||
## Overview
|
||||
|
||||
This CDK stack deploys a complete data analyst assistant powered by Amazon Bedrock AgentCore with the following components:
|
||||
|
||||
### Amazon Bedrock AgentCore Resources
|
||||
|
||||
- **AgentCore Memory**: Short-term memory for maintaining conversation context with 7-day event expiration
|
||||
- **AgentCore Runtime**: Container-based runtime hosting the Strands Agent with ARM64 architecture
|
||||
- **AgentCore Runtime Endpoint**: HTTP endpoint for invoking the data analyst assistant
|
||||
|
||||
### Data Source and VPC Infrastructure
|
||||
|
||||
- **Amazon Aurora Serverless v2 PostgreSQL**: Scalable database cluster (v17.4) with RDS Data API enabled and storage encryption
|
||||
- **Amazon DynamoDB**: Table for tracking SQL query results with pay-per-request billing
|
||||
- **AWS Secrets Manager**: Secure storage for database credentials
|
||||
- **Amazon S3**: Import bucket for loading data into Aurora PostgreSQL with 7-day lifecycle policy
|
||||
- **SSM Parameter Store**: Configuration parameters for AgentCore runtime
|
||||
- **VPC with Public and Private Subnets**: Network isolation with NAT Gateway for outbound connectivity
|
||||
- **Security Groups**: Database access control with self-referencing rule for PostgreSQL (port 5432)
|
||||
- **VPC Gateway Endpoints**: Cost-effective access to S3 and DynamoDB services
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Remember to clean up resources after testing to avoid unnecessary costs by following the clean-up steps provided.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you begin, ensure you have:
|
||||
|
||||
* AWS Account and appropriate IAM permissions for services deployment
|
||||
* **Development Environment**:
|
||||
* Python 3.10 or later installed
|
||||
* Node.js and npm installed
|
||||
* Docker installed and running (required for building the agent container image)
|
||||
* **[AWS CDK Installed](https://docs.aws.amazon.com/cdk/v2/guide/getting-started.html)**
|
||||
|
||||
* Run this command to create a service-linked role for RDS. This role is required for Aurora Serverless v2 to manage resources on your behalf. New AWS accounts that haven't used RDS before may not have this role, which can cause CDK deployment failures:
|
||||
|
||||
```bash
|
||||
aws iam create-service-linked-role --aws-service-name rds.amazonaws.com
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> If the role already exists, you will see the message: `Service role name AWSServiceRoleForRDS has been taken in this account`. This is expected and you can proceed with the deployment.
|
||||
|
||||
## AWS Deployment
|
||||
|
||||
Navigate to the CDK project folder and install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
Deploy the infrastructure:
|
||||
|
||||
```bash
|
||||
cdk deploy
|
||||
```
|
||||
|
||||
Default Parameters:
|
||||
- **ProjectId**: "data-analyst-assistant-agentcore" - Project identifier used for naming resources
|
||||
- **DatabaseName**: "video_games_sales" - Name of the database
|
||||
- **BedrockModelId**: "global.anthropic.claude-haiku-4-5-20251001-v1:0" - Bedrock model ID for the agent
|
||||
|
||||
### Deployed Resources
|
||||
|
||||
**AgentCore Resources:**
|
||||
- AgentCore Memory with 7-day event expiration
|
||||
- AgentCore Runtime (container-based, ARM64)
|
||||
- AgentCore Runtime Endpoint
|
||||
- ECR repository with agent container image
|
||||
|
||||
**Data Infrastructure:**
|
||||
- VPC with public/private subnets, NAT Gateway, security groups, VPC endpoints
|
||||
- Aurora PostgreSQL Serverless v2 (v17.4) with RDS Data API enabled
|
||||
- DynamoDB table for SQL query results
|
||||
- S3 bucket for data imports with lifecycle policies
|
||||
- Secrets Manager for database credentials
|
||||
|
||||
**Configuration:**
|
||||
- SSM Parameter Store parameters:
|
||||
- `/<projectId>/SECRET_ARN`: Database secret ARN
|
||||
- `/<projectId>/AURORA_RESOURCE_ARN`: Aurora cluster ARN
|
||||
- `/<projectId>/DATABASE_NAME`: Database name
|
||||
- `/<projectId>/QUESTION_ANSWERS_TABLE`: DynamoDB table name
|
||||
- `/<projectId>/MAX_RESPONSE_SIZE_BYTES`: Maximum response size (1MB)
|
||||
- `/<projectId>/BEDROCK_MODEL_ID`: Bedrock model ID for the agent
|
||||
|
||||
These parameters are automatically retrieved by the Strands Agent via environment variables (`PROJECT_ID`, `MEMORY_ID`, `BEDROCK_MODEL_ID`) to establish database connections and configure agent behavior.
|
||||
|
||||
### Stack Outputs
|
||||
|
||||
After deployment, the stack exports:
|
||||
- `MemoryId`: AgentCore Memory ID
|
||||
- `AuroraServerlessDBClusterARN`: Aurora cluster ARN
|
||||
- `SecretARN`: Database credentials secret ARN
|
||||
- `DataSourceBucketName`: S3 import bucket name
|
||||
- `QuestionAnswersTableName`: DynamoDB table name
|
||||
- `QuestionAnswersTableArn`: DynamoDB table ARN
|
||||
- `AgentRuntimeArn`: AgentCore runtime ARN
|
||||
- `AgentEndpointName`: AgentCore runtime endpoint name
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Enhance AI safety and compliance by implementing **[Amazon Bedrock Guardrails](https://aws.amazon.com/bedrock/guardrails/)** for your AI applications with the seamless integration offered by **[Strands Agents SDK](https://strandsagents.com/latest/user-guide/safety-security/guardrails/)**.
|
||||
|
||||
## Set Up Environment Variables
|
||||
|
||||
After deployment, set up the required environment variables. These are needed for loading sample data and local testing:
|
||||
|
||||
```bash
|
||||
# Set the stack name environment variable
|
||||
export STACK_NAME=CdkDataAnalystAssistantAgentcoreStrandsStack
|
||||
|
||||
# Retrieve the output values and store them in environment variables
|
||||
|
||||
# Project configuration
|
||||
export PROJECT_ID=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Parameters[?ParameterKey=='ProjectId'].ParameterValue" --output text)
|
||||
export BEDROCK_MODEL_ID=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Parameters[?ParameterKey=='BedrockModelId'].ParameterValue" --output text)
|
||||
|
||||
# AgentCore resources
|
||||
export MEMORY_ID=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='MemoryId'].OutputValue" --output text)
|
||||
export AGENT_RUNTIME_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AgentRuntimeArn'].OutputValue" --output text)
|
||||
export AGENT_ENDPOINT_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AgentEndpointName'].OutputValue" --output text)
|
||||
|
||||
# Database resources
|
||||
export SECRET_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='SecretARN'].OutputValue" --output text)
|
||||
export AURORA_SERVERLESS_DB_CLUSTER_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='AuroraServerlessDBClusterARN'].OutputValue" --output text)
|
||||
|
||||
# DynamoDB resources
|
||||
export QUESTION_ANSWERS_TABLE_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableName'].OutputValue" --output text)
|
||||
export QUESTION_ANSWERS_TABLE_ARN=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='QuestionAnswersTableArn'].OutputValue" --output text)
|
||||
|
||||
# S3 resources
|
||||
export DATA_SOURCE_BUCKET_NAME=$(aws cloudformation describe-stacks --stack-name "$STACK_NAME" --query "Stacks[0].Outputs[?OutputKey=='DataSourceBucketName'].OutputValue" --output text)
|
||||
|
||||
cat << EOF
|
||||
# Stack Configuration
|
||||
STACK_NAME: ${STACK_NAME}
|
||||
PROJECT_ID: ${PROJECT_ID}
|
||||
BEDROCK_MODEL_ID: ${BEDROCK_MODEL_ID}
|
||||
|
||||
# AgentCore Resources
|
||||
MEMORY_ID: ${MEMORY_ID}
|
||||
AGENT_RUNTIME_ARN: ${AGENT_RUNTIME_ARN}
|
||||
AGENT_ENDPOINT_NAME: ${AGENT_ENDPOINT_NAME}
|
||||
|
||||
# Database Resources
|
||||
SECRET_ARN: ${SECRET_ARN}
|
||||
AURORA_SERVERLESS_DB_CLUSTER_ARN: ${AURORA_SERVERLESS_DB_CLUSTER_ARN}
|
||||
|
||||
# DynamoDB Resources
|
||||
QUESTION_ANSWERS_TABLE_NAME: ${QUESTION_ANSWERS_TABLE_NAME}
|
||||
QUESTION_ANSWERS_TABLE_ARN: ${QUESTION_ANSWERS_TABLE_ARN}
|
||||
|
||||
# S3 Resources
|
||||
DATA_SOURCE_BUCKET_NAME: ${DATA_SOURCE_BUCKET_NAME}
|
||||
EOF
|
||||
```
|
||||
|
||||
## Load Sample Data into PostgreSQL Database
|
||||
|
||||
1. Install required Python dependencies:
|
||||
|
||||
```bash
|
||||
pip install boto3
|
||||
```
|
||||
|
||||
2. Load sample data into PostgreSQL:
|
||||
|
||||
```bash
|
||||
python3 resources/create-sales-database.py
|
||||
```
|
||||
|
||||
The script uses the **[video_games_sales_no_headers.csv](./resources/database/video_games_sales_no_headers.csv)** as the data source.
|
||||
|
||||
> [!NOTE]
|
||||
> The data source provided contains information from [Video Game Sales](https://www.kaggle.com/datasets/asaniczka/video-game-sales-2024) which is made available under the [ODC Attribution License](https://opendatacommons.org/licenses/odbl/1-0/).
|
||||
|
||||
## Local Testing
|
||||
|
||||
Before deploying to AWS, you can test the Data Analyst Agent locally to verify functionality:
|
||||
|
||||
1. Navigate to the agent folder and start the local agent server:
|
||||
|
||||
```bash
|
||||
cd data-analyst-assistant-agentcore-strands
|
||||
python3 app.py
|
||||
```
|
||||
|
||||
This launches a local server on port 8080 that simulates the AgentCore runtime environment.
|
||||
|
||||
2. In a different terminal, create a session ID for conversation tracking:
|
||||
|
||||
```bash
|
||||
export SESSION_ID=$(uuidgen)
|
||||
```
|
||||
|
||||
3. Test the agent with example queries using curl:
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Hello world!", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "what is the structure of your data available?!", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Which developers tend to get the best reviews?", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
```bash
|
||||
curl -X POST http://localhost:8080/invocations \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"prompt": "Give me a summary of our conversation", "session_id": "'$SESSION_ID'", "last_k_turns": 20}'
|
||||
```
|
||||
|
||||
## Invoking the Agent
|
||||
|
||||
Once deployed and data is loaded, you can invoke the agent using the AgentCore Runtime Endpoint. The endpoint name is available in the stack outputs as `AgentEndpointName`.
|
||||
|
||||
## Next Step
|
||||
|
||||
You can now proceed to the **[Front-End Implementation - Integrating AgentCore with a Ready-to-Use Data Analyst Assistant Application](../amplify-video-games-sales-assistant-agentcore-strands/))**.
|
||||
|
||||
## Cleaning-up Resources (Optional)
|
||||
|
||||
To avoid unnecessary charges, delete the CDK stack:
|
||||
|
||||
```bash
|
||||
cdk destroy
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License.
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
#!/usr/bin/env node
|
||||
import * as cdk from 'aws-cdk-lib/core';
|
||||
import { CdkAgentcoreStrandsDataAnalystAssistantStack } from '../cdklib/cdk-agentcore-strands-data-analyst-assistant-stack';
|
||||
import { CdkDataAnalystAssistantAgentcoreStrandsStack } from '../cdklib/cdk-data-analyst-assistant-agentcore-strands-stack';
|
||||
|
||||
const app = new cdk.App();
|
||||
new CdkAgentcoreStrandsDataAnalystAssistantStack(app, 'CdkAgentcoreStrandsDataAnalystAssistantStack', {
|
||||
new CdkDataAnalystAssistantAgentcoreStrandsStack(app, 'CdkDataAnalystAssistantAgentcoreStrandsStack', {
|
||||
/* If you don't specify 'env', this stack will be environment-agnostic.
|
||||
* Account/Region-dependent features and context lookups will not work,
|
||||
* but a single synthesized template can be deployed anywhere. */
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"app": "npx ts-node --prefer-ts-exts bin/cdk-agentcore-strands-data-analyst-assistant.ts",
|
||||
"app": "npx ts-node --prefer-ts-exts bin/cdk-data-analyst-assistant-agentcore-strands.ts",
|
||||
"watch": {
|
||||
"include": [
|
||||
"**"
|
||||
+129
-38
@@ -19,8 +19,11 @@ import * as s3 from "aws-cdk-lib/aws-s3";
|
||||
import * as iam from "aws-cdk-lib/aws-iam";
|
||||
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
|
||||
import * as ssm from 'aws-cdk-lib/aws-ssm';
|
||||
import * as ecr_assets from 'aws-cdk-lib/aws-ecr-assets';
|
||||
import * as path from 'path';
|
||||
import { aws_bedrockagentcore as bedrockagentcore } from 'aws-cdk-lib';
|
||||
|
||||
export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
export class CdkDataAnalystAssistantAgentcoreStrandsStack extends cdk.Stack {
|
||||
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
|
||||
super(scope, id, props);
|
||||
|
||||
@@ -32,7 +35,7 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
const projectId = new cdk.CfnParameter(this, "ProjectId", {
|
||||
type: "String",
|
||||
description: "Project identifier used for naming resources",
|
||||
default: "agentcore-data-analyst-assistant",
|
||||
default: "data-analyst-assistant-agentcore",
|
||||
});
|
||||
|
||||
// Name of the Aurora PostgreSQL database
|
||||
@@ -42,6 +45,13 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
default: "video_games_sales",
|
||||
});
|
||||
|
||||
// Bedrock model ID for the agent
|
||||
const bedrockModelId = new cdk.CfnParameter(this, "BedrockModelId", {
|
||||
type: "String",
|
||||
description: "The Bedrock model ID for the agent",
|
||||
default: "global.anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
});
|
||||
|
||||
// ================================
|
||||
// DYNAMODB TABLES
|
||||
// ================================
|
||||
@@ -111,6 +121,13 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
}
|
||||
);
|
||||
|
||||
// Allow inbound PostgreSQL traffic from the same security group
|
||||
sg_db.addIngressRule(
|
||||
sg_db,
|
||||
ec2.Port.tcp(5432),
|
||||
"Allow PostgreSQL access from within the same security group"
|
||||
);
|
||||
|
||||
// Database credentials stored in AWS Secrets Manager
|
||||
const databaseUsername = "postgres";
|
||||
const secret = new rds.DatabaseSecret(this, "AssistantSecret", {
|
||||
@@ -123,6 +140,33 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
assumedBy: new iam.ServicePrincipal("rds.amazonaws.com"),
|
||||
});
|
||||
|
||||
// ================================
|
||||
// S3 STORAGE
|
||||
// ================================
|
||||
|
||||
// S3 bucket containing data for import into Aurora PostgreSQL
|
||||
const importBucket = new s3.Bucket(this, "ImportBucket", {
|
||||
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
||||
autoDeleteObjects: true,
|
||||
lifecycleRules: [
|
||||
{
|
||||
expiration: cdk.Duration.days(7), // Auto-delete objects after 7 days
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
// Grant S3 access to the Aurora role for data imports
|
||||
auroraS3Role.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"],
|
||||
resources: [
|
||||
importBucket.bucketArn,
|
||||
`${importBucket.bucketArn}/*`,
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// Aurora PostgreSQL Serverless v2 cluster containing video games sales data
|
||||
let cluster = new rds.DatabaseCluster(this, "AssistantCluster", {
|
||||
engine: rds.DatabaseClusterEngine.auroraPostgres({
|
||||
@@ -360,19 +404,7 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
}
|
||||
);
|
||||
|
||||
// Grant S3 access to the role
|
||||
auroraS3Role.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
actions: ["s3:GetObject", "s3:ListBucket", "s3:GetBucketLocation"],
|
||||
resources: [
|
||||
`arn:aws:s3:::${projectId.valueAsString}-${this.region}-${this.account}-import`,
|
||||
`arn:aws:s3:::${projectId.valueAsString}-${this.region}-${this.account}-import/*`,
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
// Add additional RDS permissions
|
||||
// Add additional RDS permissions to Aurora S3 role
|
||||
auroraS3Role.addToPolicy(
|
||||
new iam.PolicyStatement({
|
||||
effect: iam.Effect.ALLOW,
|
||||
@@ -389,21 +421,69 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
);
|
||||
|
||||
// ================================
|
||||
// S3 STORAGE
|
||||
// DOCKER IMAGE ASSET
|
||||
// ================================
|
||||
|
||||
// S3 bucket containing data for import into Aurora PostgreSQL
|
||||
const importBucket = new s3.Bucket(this, "ImportBucket", {
|
||||
bucketName: `${projectId.valueAsString}-${this.region}-${this.account}-import`,
|
||||
removalPolicy: cdk.RemovalPolicy.DESTROY,
|
||||
autoDeleteObjects: true,
|
||||
lifecycleRules: [
|
||||
{
|
||||
expiration: cdk.Duration.days(7), // Auto-delete objects after 7 days
|
||||
},
|
||||
],
|
||||
// Build and push Docker image automatically during CDK deployment
|
||||
// DockerImageAsset creates and manages its own ECR repository
|
||||
const dockerImageAsset = new ecr_assets.DockerImageAsset(this, 'RuntimeDockerImage', {
|
||||
directory: path.join(__dirname, '../data-analyst-assistant-agentcore-strands'),
|
||||
platform: ecr_assets.Platform.LINUX_ARM64
|
||||
});
|
||||
|
||||
// ================================
|
||||
// BEDROCK AGENTCORE MEMORY
|
||||
// ================================
|
||||
|
||||
// Short-term memory for AgentCore to maintain conversation context
|
||||
const uniqueSuffix = cdk.Names.uniqueId(this).slice(-8).toLowerCase().replace(/[^a-z0-9]/g, '');
|
||||
const agentMemory = new bedrockagentcore.CfnMemory(this, 'AgentMemory', {
|
||||
name: `DataAnalystAssistantMemory_${uniqueSuffix}`,
|
||||
eventExpiryDuration: 7, // Events expire after 7 days
|
||||
memoryExecutionRoleArn: agentCoreRole.roleArn,
|
||||
description: 'Short-term memory for data analyst assistant conversations',
|
||||
});
|
||||
|
||||
// ================================
|
||||
// BEDROCK AGENTCORE RUNTIME
|
||||
// ================================
|
||||
|
||||
// AgentCore Runtime with container type for the data analyst assistant
|
||||
const agentRuntime = new bedrockagentcore.CfnRuntime(this, 'AgentRuntime', {
|
||||
agentRuntimeName: `DataAnalystRuntime_${uniqueSuffix}`,
|
||||
agentRuntimeArtifact: {
|
||||
containerConfiguration: {
|
||||
containerUri: dockerImageAsset.imageUri,
|
||||
},
|
||||
},
|
||||
networkConfiguration: {
|
||||
networkMode: 'PUBLIC',
|
||||
},
|
||||
roleArn: agentCoreRole.roleArn,
|
||||
description: 'Container runtime for video games sales data analyst assistant',
|
||||
environmentVariables: {
|
||||
PROJECT_ID: projectId.valueAsString,
|
||||
MEMORY_ID: agentMemory.attrMemoryId,
|
||||
BEDROCK_MODEL_ID: bedrockModelId.valueAsString,
|
||||
},
|
||||
});
|
||||
|
||||
agentRuntime.addDependency(agentMemory);
|
||||
|
||||
// ================================
|
||||
// BEDROCK AGENTCORE RUNTIME ENDPOINT
|
||||
// ================================
|
||||
|
||||
// Runtime endpoint for invoking the data analyst assistant
|
||||
const runtimeEndpoint = new bedrockagentcore.CfnRuntimeEndpoint(this, 'RuntimeEndpoint', {
|
||||
agentRuntimeId: agentRuntime.attrAgentRuntimeId,
|
||||
name: `DataAnalystEndpoint_${uniqueSuffix}`,
|
||||
description: 'Endpoint for invoking the video games sales data analyst assistant',
|
||||
});
|
||||
|
||||
// Endpoint depends on runtime being created first
|
||||
runtimeEndpoint.addDependency(agentRuntime);
|
||||
|
||||
// ================================
|
||||
// SSM PARAMETERS
|
||||
// ================================
|
||||
@@ -444,10 +524,10 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
type: 'String'
|
||||
});
|
||||
|
||||
new ssm.CfnParameter(this, 'MemoryIdParam', {
|
||||
name: `/${projectId.valueAsString}/MEMORY_ID`,
|
||||
value: "AssistantAgentMemoryIdToBeCreated",
|
||||
description: 'Memory ID for the agent',
|
||||
new ssm.CfnParameter(this, 'BedrockModelIdParam', {
|
||||
name: `/${projectId.valueAsString}/BEDROCK_MODEL_ID`,
|
||||
value: bedrockModelId.valueAsString,
|
||||
description: 'Bedrock model ID for the agent',
|
||||
type: 'String'
|
||||
});
|
||||
|
||||
@@ -481,18 +561,29 @@ export class CdkAgentcoreStrandsDataAnalystAssistantStack extends cdk.Stack {
|
||||
exportName: `${projectId.valueAsString}-QuestionAnswersTableName`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "AgentCoreMyRoleARN", {
|
||||
value: agentCoreRole.roleArn,
|
||||
description: "The ARN of the AgentCoreMyRole",
|
||||
exportName: `${projectId.valueAsString}-AgentCoreMyRoleARN`,
|
||||
new cdk.CfnOutput(this, "QuestionAnswersTableArn", {
|
||||
value: rawQueryResults.tableArn,
|
||||
description: "The ARN of the DynamoDB table for storing query results",
|
||||
exportName: `${projectId.valueAsString}-QuestionAnswersTableArn`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "MemoryIdSSMParameter", {
|
||||
value: `/${projectId.valueAsString}/MEMORY_ID`,
|
||||
description: "The SSM parameter name for the memory ID",
|
||||
exportName: `${projectId.valueAsString}-MemoryIdSSMParameter`,
|
||||
new cdk.CfnOutput(this, "AgentRuntimeArn", {
|
||||
value: agentRuntime.attrAgentRuntimeArn,
|
||||
description: "The ARN of the AgentCore runtime",
|
||||
exportName: `${projectId.valueAsString}-AgentRuntimeArn`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "AgentEndpointName", {
|
||||
value: runtimeEndpoint.name,
|
||||
description: "The name of the AgentCore runtime endpoint",
|
||||
exportName: `${projectId.valueAsString}-AgentEndpointName`,
|
||||
});
|
||||
|
||||
new cdk.CfnOutput(this, "MemoryId", {
|
||||
value: agentMemory.attrMemoryId,
|
||||
description: "The ID of the AgentCore Memory",
|
||||
exportName: `${projectId.valueAsString}-MemoryId`,
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
FROM ghcr.io/astral-sh/uv:python3.13-bookworm-slim
|
||||
WORKDIR /app
|
||||
|
||||
# All environment variables in one layer
|
||||
ENV UV_SYSTEM_PYTHON=1 \
|
||||
UV_COMPILE_BYTECODE=1 \
|
||||
UV_NO_PROGRESS=1 \
|
||||
PYTHONUNBUFFERED=1 \
|
||||
DOCKER_CONTAINER=1 \
|
||||
AWS_REGION=us-east-1 \
|
||||
AWS_DEFAULT_REGION=us-east-1
|
||||
|
||||
|
||||
|
||||
COPY requirements.txt requirements.txt
|
||||
# Install from requirements file
|
||||
RUN uv pip install -r requirements.txt
|
||||
|
||||
|
||||
|
||||
|
||||
RUN uv pip install aws-opentelemetry-distro>=0.10.1
|
||||
|
||||
|
||||
# Signal that this is running in Docker for host binding logic
|
||||
ENV DOCKER_CONTAINER=1
|
||||
|
||||
# Create non-root user
|
||||
RUN useradd -m -u 1000 bedrock_agentcore
|
||||
USER bedrock_agentcore
|
||||
|
||||
EXPOSE 9000
|
||||
EXPOSE 8000
|
||||
EXPOSE 8080
|
||||
|
||||
# Health check using the /ping endpoint
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8080/ping', timeout=5)" || exit 1
|
||||
|
||||
# Copy entire project (respecting .dockerignore)
|
||||
COPY . .
|
||||
|
||||
# Use the full module path
|
||||
|
||||
CMD ["opentelemetry-instrument", "python", "-m", "app"]
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
# Data Analyst Assistant - Strands Agent
|
||||
|
||||
A video games sales data analyst assistant built with the **[Strands Agents SDK](https://strandsagents.com/)** and powered by **[Amazon Bedrock AgentCore](https://aws.amazon.com/bedrock/agentcore/)**.
|
||||
|
||||
## Overview
|
||||
|
||||
This agent provides an intelligent data analyst assistant specialized in video game sales analysis. It leverages Amazon Bedrock Claude models for natural language processing, Aurora Serverless PostgreSQL for data storage, and AgentCore Memory for conversation context management.
|
||||
|
||||
## Features
|
||||
|
||||
- Natural language to SQL query conversion
|
||||
- Video game sales data analysis and insights
|
||||
- Conversation memory and context awareness via AgentCore Memory
|
||||
- Real-time streaming responses
|
||||
- Comprehensive error handling and logging
|
||||
|
||||
## Agent Tools
|
||||
|
||||
| Tool | Type | Description |
|
||||
|------|------|-------------|
|
||||
| `get_tables_information` | Custom | Retrieves metadata about database tables, including structure, columns, and relationships |
|
||||
| `execute_sql_query` | Custom | Executes SQL queries against the PostgreSQL database based on natural language questions |
|
||||
| `current_time` | Native (Strands) | Provides current date and time information based on user's timezone |
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
data-analyst-assistant-agentcore-strands/
|
||||
├── app.py # Main application entry point
|
||||
├── Dockerfile # Container configuration for AgentCore Runtime
|
||||
├── instructions.txt # Agent system prompt and behavior configuration
|
||||
├── requirements.txt # Python dependencies
|
||||
├── src/
|
||||
│ ├── tools/ # Custom tool implementations
|
||||
│ └── utils/ # Utility functions and helpers
|
||||
└── resources/ # Additional resources
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
The agent uses the following environment variables:
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `PROJECT_ID` | Project identifier for SSM parameter retrieval |
|
||||
| `MEMORY_ID` | AgentCore Memory ID for conversation context |
|
||||
| `BEDROCK_MODEL_ID` | Bedrock model ID (default: `global.anthropic.claude-haiku-4-5-20251001-v1:0`) |
|
||||
|
||||
## Model Provider
|
||||
|
||||
- **Amazon Bedrock** with Claude Haiku 4.5 (default: `global.anthropic.claude-haiku-4-5-20251001-v1:0`)
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the Apache-2.0 License.
|
||||
+13
-65
@@ -20,7 +20,6 @@ from uuid import uuid4
|
||||
|
||||
# Bedrock Agent Core imports
|
||||
from bedrock_agentcore import BedrockAgentCoreApp
|
||||
from bedrock_agentcore.memory import MemoryClient
|
||||
from strands import Agent, tool
|
||||
from strands_tools import current_time
|
||||
from strands.models import BedrockModel
|
||||
@@ -30,7 +29,6 @@ from src.tools import get_tables_information, run_sql_query
|
||||
from src.utils import (
|
||||
save_raw_query_result,
|
||||
load_file_content,
|
||||
load_config,
|
||||
get_agentcore_memory_messages,
|
||||
MemoryHookProvider,
|
||||
)
|
||||
@@ -39,59 +37,13 @@ from src.utils import (
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger("personal-agent")
|
||||
|
||||
# Retrieve AgentCore Memory ID
|
||||
memory_id = os.environ.get("MEMORY_ID")
|
||||
|
||||
# Load configuration from SSM Parameter Store
|
||||
# Get PROJECT_ID from environment variable to construct SSM parameter paths
|
||||
PROJECT_ID = os.environ.get("PROJECT_ID", "agentcore-data-analyst-assistant")
|
||||
|
||||
# Load all configuration from SSM
|
||||
try:
|
||||
config = load_config()
|
||||
print("✅ CONFIGURATION LOADED FROM SSM")
|
||||
print("-" * 50)
|
||||
print(f"🔧 Project ID: {PROJECT_ID}")
|
||||
print(f"📊 Database: {config.get('DATABASE_NAME')}")
|
||||
print("-" * 50)
|
||||
except Exception as e:
|
||||
print("❌ CONFIGURATION LOAD ERROR")
|
||||
print("-" * 50)
|
||||
print(f"🚨 Error: {e}")
|
||||
print(f"🔧 Project ID: {PROJECT_ID}")
|
||||
print("-" * 50)
|
||||
# Set empty config as fallback
|
||||
config = {}
|
||||
|
||||
|
||||
# Initialize AgentCore Memory configuration
|
||||
try:
|
||||
print("\n" + "=" * 70)
|
||||
print("🚀 INITIALIZING VIDEO GAMES SALES ANALYST ASSISTANT")
|
||||
print("=" * 70)
|
||||
print("📋 Loading configuration from AWS Systems Manager...")
|
||||
|
||||
# Retrieve memory ID from config
|
||||
memory_id = config.get("MEMORY_ID")
|
||||
|
||||
# Validate memory ID configuration
|
||||
if not memory_id or memory_id.strip() == "":
|
||||
error_msg = "Memory ID not found in configuration. Please create AgentCore Memory first."
|
||||
print(f"❌ Configuration Error: {error_msg}")
|
||||
logger.error(error_msg)
|
||||
raise ValueError(error_msg)
|
||||
|
||||
print(f"✅ Memory ID retrieved: {memory_id}")
|
||||
|
||||
# Initialize AgentCore Memory Client
|
||||
print("🧠 Connecting to AgentCore Memory service...")
|
||||
client = MemoryClient()
|
||||
print("✅ Memory client connected successfully")
|
||||
print("=" * 70 + "\n")
|
||||
|
||||
except Exception as e:
|
||||
print(f"💥 INITIALIZATION FAILED: {str(e)}")
|
||||
print("=" * 70 + "\n")
|
||||
logger.error(f"Failed to initialize AgentCore Memory: {e}")
|
||||
raise
|
||||
# Retrieve Bedrock Model ID
|
||||
bedrock_model_id_env = os.environ.get(
|
||||
"BEDROCK_MODEL_ID", "global.anthropic.claude-haiku-4-5-20251001-v1:0"
|
||||
)
|
||||
|
||||
|
||||
# Initialize the Bedrock Agent Core app
|
||||
@@ -244,7 +196,8 @@ async def agent_invocation(payload):
|
||||
|
||||
Expected payload structure:
|
||||
{
|
||||
model_id="global.anthropic.claude-haiku-4-5-20251001-v1:0",
|
||||
"prompt": "Your video game sales analysis question",
|
||||
"prompt_uuid": "optional-unique-prompt-identifier",
|
||||
"user_timezone": "US/Pacific",
|
||||
"session_id": "optional-conversation-session-id",
|
||||
"user_id": "optional-user-identifier",
|
||||
@@ -260,9 +213,6 @@ async def agent_invocation(payload):
|
||||
"prompt",
|
||||
"No prompt found in input, please guide customer to create a json payload with prompt key",
|
||||
)
|
||||
bedrock_model_id = payload.get(
|
||||
"bedrock_model_id", "global.anthropic.claude-haiku-4-5-20251001-v1:0"
|
||||
)
|
||||
prompt_uuid = payload.get("prompt_uuid", str(uuid4()))
|
||||
user_timezone = payload.get("user_timezone", "US/Pacific")
|
||||
session_id = payload.get("session_id", str(uuid4()))
|
||||
@@ -275,7 +225,7 @@ async def agent_invocation(payload):
|
||||
print(
|
||||
f"💬 User Query: {user_message[:100]}{'...' if len(user_message) > 100 else ''}"
|
||||
)
|
||||
print(f"🤖 Claude Model: {bedrock_model_id}")
|
||||
print(f"🤖 Claude Model: {bedrock_model_id_env}")
|
||||
print(f"🆔 Prompt UUID: {prompt_uuid}")
|
||||
print(f"🌍 User Timezone: {user_timezone}")
|
||||
print(f"🔗 Conversation ID: {session_id}")
|
||||
@@ -284,14 +234,14 @@ async def agent_invocation(payload):
|
||||
print("-" * 80)
|
||||
|
||||
# Initialize Claude model for video game sales analysis
|
||||
print(f"🧠 Initializing Claude model for analysis: {bedrock_model_id}")
|
||||
bedrock_model = BedrockModel(model_id=bedrock_model_id)
|
||||
print(f"🧠 Initializing Claude model for analysis: {bedrock_model_id_env}")
|
||||
bedrock_model = BedrockModel(model_id=bedrock_model_id_env)
|
||||
print("✅ Claude model ready for video game sales analysis")
|
||||
|
||||
print("-" * 80)
|
||||
print("🧠 Retrieving conversation context from AgentCore Memory...")
|
||||
agentcore_messages = get_agentcore_memory_messages(
|
||||
client, memory_id, user_id, session_id, last_k_turns
|
||||
memory_id, user_id, session_id, last_k_turns
|
||||
)
|
||||
|
||||
print("📋 CONVERSATION CONTEXT LOADED:")
|
||||
@@ -331,9 +281,7 @@ async def agent_invocation(payload):
|
||||
messages=agentcore_messages,
|
||||
model=bedrock_model,
|
||||
system_prompt=system_prompt,
|
||||
hooks=[
|
||||
MemoryHookProvider(client, memory_id, user_id, session_id, last_k_turns)
|
||||
],
|
||||
hooks=[MemoryHookProvider(memory_id, user_id, session_id, last_k_turns)],
|
||||
tools=[
|
||||
get_tables_information,
|
||||
current_time,
|
||||
+1
-1
@@ -3,5 +3,5 @@ strands-agents-tools
|
||||
typing
|
||||
boto3
|
||||
bedrock-agentcore
|
||||
bedrock-agentcore-starter-toolkit>=0.1.34
|
||||
bedrock-agentcore-starter-toolkit
|
||||
botocore
|
||||
+56
-35
@@ -18,29 +18,35 @@ from bedrock_agentcore.memory import MemoryClient
|
||||
from botocore.exceptions import ClientError
|
||||
|
||||
# Configure logging
|
||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||
logging.basicConfig(
|
||||
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
|
||||
)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Default configuration
|
||||
DEFAULT_MEMORY_NAME = "AssistantAgentMemory"
|
||||
DEFAULT_EXPIRY_DAYS = 7
|
||||
|
||||
def create_memory(memory_name: str = DEFAULT_MEMORY_NAME, expiry_days: int = DEFAULT_EXPIRY_DAYS,
|
||||
parameter_store_name: Optional[str] = None) -> Optional[str]:
|
||||
|
||||
def create_memory(
|
||||
memory_name: str = DEFAULT_MEMORY_NAME,
|
||||
expiry_days: int = DEFAULT_EXPIRY_DAYS,
|
||||
parameter_store_name: Optional[str] = None,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Create a new memory resource for the agent and store the memory ID in parameter store
|
||||
|
||||
|
||||
Args:
|
||||
memory_name (str): Name for the memory resource
|
||||
expiry_days (int): Retention period for short-term memory
|
||||
parameter_store_name (str): Name of the parameter store to update with memory ID
|
||||
|
||||
|
||||
Returns:
|
||||
str: Memory ID if successful, None otherwise
|
||||
"""
|
||||
logger.info(f"Creating memory resource: {memory_name}")
|
||||
client = MemoryClient()
|
||||
|
||||
|
||||
try:
|
||||
# Create memory resource for short-term conversation storage
|
||||
memory = client.create_memory_and_wait(
|
||||
@@ -49,23 +55,25 @@ def create_memory(memory_name: str = DEFAULT_MEMORY_NAME, expiry_days: int = DEF
|
||||
description="Short-term memory for data analyst assistant",
|
||||
event_expiry_days=expiry_days, # Retention period for short-term memory (up to 365 days)
|
||||
)
|
||||
memory_id = memory['id']
|
||||
memory_id = memory["id"]
|
||||
logger.info(f"✅ Created memory: {memory_id}")
|
||||
|
||||
|
||||
# Store memory ID in parameter store if parameter_store_name is provided
|
||||
if parameter_store_name:
|
||||
try:
|
||||
ssm_client = boto3.client('ssm')
|
||||
ssm_client = boto3.client("ssm")
|
||||
ssm_client.put_parameter(
|
||||
Name=parameter_store_name,
|
||||
Value=memory_id,
|
||||
Type='String',
|
||||
Overwrite=True
|
||||
Type="String",
|
||||
Overwrite=True,
|
||||
)
|
||||
logger.info(
|
||||
f"✅ Stored memory ID in parameter store: {parameter_store_name}"
|
||||
)
|
||||
logger.info(f"✅ Stored memory ID in parameter store: {parameter_store_name}")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ Failed to store memory ID in parameter store: {e}")
|
||||
|
||||
|
||||
return memory_id
|
||||
except ClientError as e:
|
||||
logger.info(f"❌ ERROR: {e}")
|
||||
@@ -74,32 +82,34 @@ def create_memory(memory_name: str = DEFAULT_MEMORY_NAME, expiry_days: int = DEF
|
||||
# Log any errors during memory creation
|
||||
logger.error(f"❌ ERROR: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return None
|
||||
|
||||
|
||||
def list_memories() -> List[Dict[str, Any]]:
|
||||
"""
|
||||
List all available memory resources
|
||||
|
||||
|
||||
Returns:
|
||||
List[Dict]: List of memory resources
|
||||
"""
|
||||
logger.info("Listing memory resources...")
|
||||
client = MemoryClient()
|
||||
|
||||
|
||||
try:
|
||||
memories = client.list_memories()
|
||||
logger.info(f"Found {len(memories)} memory resources:")
|
||||
|
||||
|
||||
if memories:
|
||||
print("\n📋 Memory Resources:")
|
||||
print("-" * 60)
|
||||
for i, memory in enumerate(memories, 1):
|
||||
memory_id = memory.get('id', 'N/A')
|
||||
memory_name = memory.get('name', 'N/A')
|
||||
status = memory.get('status', 'N/A')
|
||||
created_time = memory.get('createdTime', 'N/A')
|
||||
|
||||
memory_id = memory.get("id", "N/A")
|
||||
memory_name = memory.get("name", "N/A")
|
||||
status = memory.get("status", "N/A")
|
||||
created_time = memory.get("createdTime", "N/A")
|
||||
|
||||
print(f"{i}. Name: {memory_name}")
|
||||
print(f" ID: {memory_id}")
|
||||
print(f" Status: {status}")
|
||||
@@ -107,46 +117,56 @@ def list_memories() -> List[Dict[str, Any]]:
|
||||
print("-" * 60)
|
||||
else:
|
||||
print("No memory resources found.")
|
||||
|
||||
|
||||
return memories
|
||||
except Exception as e:
|
||||
logger.error(f"❌ ERROR listing memories: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return []
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function to handle command line arguments"""
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: python3 memory_manager.py [create|list]")
|
||||
print(" create <memory_name> <parameter_store_name> - Create a new memory resource")
|
||||
print(
|
||||
" create <memory_name> <parameter_store_name> - Create a new memory resource"
|
||||
)
|
||||
print(" list - List all existing memory resources")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
action = sys.argv[1].lower()
|
||||
|
||||
if action == 'create':
|
||||
|
||||
if action == "create":
|
||||
if len(sys.argv) != 4:
|
||||
print("Usage: python3 memory_manager.py create <memory_name> <parameter_store_name>")
|
||||
print(
|
||||
"Usage: python3 memory_manager.py create <memory_name> <parameter_store_name>"
|
||||
)
|
||||
print(" <memory_name> - Name for the memory resource")
|
||||
print(" <parameter_store_name> - Name of the parameter store to update with memory ID")
|
||||
print(
|
||||
" <parameter_store_name> - Name of the parameter store to update with memory ID"
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
memory_name = sys.argv[2]
|
||||
parameter_store_name = sys.argv[3]
|
||||
|
||||
|
||||
print(f"🚀 Creating memory resource: {memory_name}")
|
||||
print(f"📝 Parameter store name: {parameter_store_name}")
|
||||
|
||||
memory_id = create_memory(memory_name=memory_name, parameter_store_name=parameter_store_name)
|
||||
|
||||
memory_id = create_memory(
|
||||
memory_name=memory_name, parameter_store_name=parameter_store_name
|
||||
)
|
||||
if memory_id:
|
||||
print(f"✅ Memory created successfully!")
|
||||
print("✅ Memory created successfully!")
|
||||
print(f"Memory ID: {memory_id}")
|
||||
print(f"Memory ID stored in parameter store: {parameter_store_name}")
|
||||
else:
|
||||
print("❌ Failed to create memory")
|
||||
sys.exit(1)
|
||||
elif action == 'list':
|
||||
elif action == "list":
|
||||
print("📋 Listing memory resources...")
|
||||
memories = list_memories()
|
||||
if not memories:
|
||||
@@ -156,5 +176,6 @@ def main():
|
||||
print("Available actions: create, list")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
+1
-4
@@ -28,7 +28,6 @@ class MemoryHookProvider(HookProvider):
|
||||
initializes and saving messages as they are added to the conversation.
|
||||
|
||||
Attributes:
|
||||
memory_client: Client for interacting with Bedrock Agent Core memory
|
||||
memory_id: ID of the memory resource
|
||||
actor_id: ID of the user/actor
|
||||
session_id: ID of the current conversation session
|
||||
@@ -37,7 +36,6 @@ class MemoryHookProvider(HookProvider):
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
memory_client: MemoryClient,
|
||||
memory_id: str,
|
||||
actor_id: str,
|
||||
session_id: str,
|
||||
@@ -47,13 +45,12 @@ class MemoryHookProvider(HookProvider):
|
||||
Initialize the memory hook provider.
|
||||
|
||||
Args:
|
||||
memory_client: Client for interacting with Bedrock Agent Core memory
|
||||
memory_id: ID of the memory resource
|
||||
actor_id: ID of the user/actor
|
||||
session_id: ID of the current conversation session
|
||||
last_k_turns: Number of conversation turns to retrieve from history (default: 20)
|
||||
"""
|
||||
self.memory_client = memory_client
|
||||
self.memory_client = MemoryClient()
|
||||
self.memory_id = memory_id
|
||||
self.actor_id = actor_id
|
||||
self.session_id = session_id
|
||||
+2
-2
@@ -15,7 +15,6 @@ logger = logging.getLogger("agentcore-memory-utils")
|
||||
|
||||
|
||||
def get_agentcore_memory_messages(
|
||||
memory_client: MemoryClient,
|
||||
memory_id: str,
|
||||
actor_id: str,
|
||||
session_id: str,
|
||||
@@ -28,7 +27,6 @@ def get_agentcore_memory_messages(
|
||||
and formats them in the standard message format with role and content structure.
|
||||
|
||||
Args:
|
||||
memory_client: Client for interacting with Bedrock Agent Core memory
|
||||
memory_id: ID of the memory resource
|
||||
actor_id: ID of the user/actor
|
||||
session_id: ID of the current conversation session
|
||||
@@ -45,6 +43,8 @@ def get_agentcore_memory_messages(
|
||||
Exception: If there's an error retrieving messages from memory
|
||||
"""
|
||||
try:
|
||||
# Initialize memory client
|
||||
memory_client = MemoryClient()
|
||||
# Pretty console output for memory retrieval start
|
||||
print("\n" + "=" * 70)
|
||||
print("🧠 AGENTCORE MEMORY RETRIEVAL")
|
||||
-3
@@ -9,7 +9,6 @@ Parameters:
|
||||
- SECRET_ARN: ARN of the AWS Secrets Manager secret containing database credentials
|
||||
- AURORA_RESOURCE_ARN: ARN of the Aurora Serverless cluster
|
||||
- DATABASE_NAME: Name of the database to connect to
|
||||
- MEMORY_ID: AgentCore Memory ID for conversation context management
|
||||
- QUESTION_ANSWERS_TABLE: DynamoDB table for storing query results
|
||||
- MAX_RESPONSE_SIZE_BYTES: Maximum size of query responses in bytes (default: 25600)
|
||||
"""
|
||||
@@ -79,7 +78,6 @@ def load_config():
|
||||
"DATABASE_NAME",
|
||||
"QUESTION_ANSWERS_TABLE",
|
||||
"MAX_RESPONSE_SIZE_BYTES",
|
||||
"MEMORY_ID",
|
||||
]
|
||||
|
||||
config = {}
|
||||
@@ -105,7 +103,6 @@ def load_config():
|
||||
"SECRET_ARN",
|
||||
"AURORA_RESOURCE_ARN",
|
||||
"DATABASE_NAME",
|
||||
"MEMORY_ID",
|
||||
]:
|
||||
raise ValueError(
|
||||
f"Required SSM parameter /{PROJECT_ID}/{key} not found"
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "cdk-agentcore-strands-data-analyst-assistant",
|
||||
"name": "cdk-data-analyst-assistant-agentcore-strands",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"cdk-agentcore-strands-data-analyst-assistant": "bin/cdk-agentcore-strands-data-analyst-assistant.js"
|
||||
"cdk-data-analyst-assistant-agentcore-strands": "bin/cdk-data-analyst-assistant-agentcore-strands.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
@@ -13,9 +13,9 @@
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.14",
|
||||
"@types/node": "22.7.9",
|
||||
"aws-cdk": "2.1031.1",
|
||||
"jest": "^29.7.0",
|
||||
"ts-jest": "^29.2.5",
|
||||
"aws-cdk": "2.1031.2",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "~5.6.3"
|
||||
},
|
||||
+5
-5
@@ -15,7 +15,6 @@ local_file_path = "resources/database/video_games_sales_no_headers.csv"
|
||||
s3_file_name = "video_games_sales_no_headers.csv"
|
||||
|
||||
try:
|
||||
|
||||
# Upload file to S3
|
||||
s3_client = boto3.client("s3")
|
||||
s3_client.upload_file(
|
||||
@@ -30,7 +29,7 @@ try:
|
||||
client = boto3.client("rds-data")
|
||||
|
||||
# Create table
|
||||
query1 = """ CREATE TABLE video_games_sales_units (
|
||||
query1 = """ CREATE TABLE IF NOT EXISTS video_games_sales_units (
|
||||
title TEXT,
|
||||
console TEXT,
|
||||
genre TEXT,
|
||||
@@ -56,7 +55,7 @@ try:
|
||||
print("Query response: " + str(response))
|
||||
|
||||
# Create AWS S3 extension
|
||||
query2 = "CREATE EXTENSION aws_s3 CASCADE;"
|
||||
query2 = "CREATE EXTENSION IF NOT EXISTS aws_s3 CASCADE;"
|
||||
|
||||
response = client.execute_statement(
|
||||
resourceArn=aurora_serverless_db_cluster_arn,
|
||||
@@ -69,12 +68,13 @@ try:
|
||||
print("Query: " + query2)
|
||||
print("Query response: " + str(response))
|
||||
|
||||
# Import data from S3
|
||||
# Import data from S3 using IAM role credentials
|
||||
# Note: This uses the IAM role associated with the Aurora cluster via s3ImportRole
|
||||
query3 = f"""
|
||||
SELECT aws_s3.table_import_from_s3(
|
||||
'video_games_sales_units',
|
||||
'title,console,genre,publisher,developer,critic_score,total_sales,na_sales,jp_sales,pal_sales,other_sales,release_date',
|
||||
'DELIMITER ''|''',
|
||||
'(FORMAT csv, DELIMITER ''|'', HEADER false)',
|
||||
aws_commons.create_s3_uri('{data_source_bucket_name}', '{s3_file_name}', '{region}')
|
||||
); """
|
||||
|
||||
|
Can't render this file because it is too large.
|
+3
-3
@@ -1,13 +1,13 @@
|
||||
// import * as cdk from 'aws-cdk-lib/core';
|
||||
// import { Template } from 'aws-cdk-lib/assertions';
|
||||
// import * as CdkAgentcoreStrandsDataAnalystAssistant from '../lib/cdk-agentcore-strands-data-analyst-assistant-stack';
|
||||
// import * as CdkDataAnalystAssistantAgentcoreStrands from '../lib/cdk-data-analyst-assistant-agentcore-strands-stack';
|
||||
|
||||
// example test. To run these tests, uncomment this file along with the
|
||||
// example resource in lib/cdk-agentcore-strands-data-analyst-assistant-stack.ts
|
||||
// example resource in lib/cdk-data-analyst-assistant-agentcore-strands-stack.ts
|
||||
test('SQS Queue Created', () => {
|
||||
// const app = new cdk.App();
|
||||
// // WHEN
|
||||
// const stack = new CdkAgentcoreStrandsDataAnalystAssistant.CdkAgentcoreStrandsDataAnalystAssistantStack(app, 'MyTestStack');
|
||||
// const stack = new CdkDataAnalystAssistantAgentcoreStrands.CdkDataAnalystAssistantAgentcoreStrandsStack(app, 'MyTestStack');
|
||||
// // THEN
|
||||
// const template = Template.fromStack(stack);
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 422 KiB After Width: | Height: | Size: 434 KiB |
Reference in New Issue
Block a user