Akarsha Sehwag ce1e2d8367
Add Workshop E2E (#253)
* feat: e2e tutorial lab5

* docs: Add README.md for 05-AgentCore Observability lab

* feat: Add Lab 6 of E2E tutorial

* fix: Fix Agent ECR repository typo

* docs: Update Lab 6 Guidelines

* feat: cleanup guardrails

* docs: fix step name

* added lab4

* Add Lab 3 Identity Notebook and README

* added memory and updated lab 1

* pushing all of the helper files from original use case. Remove as needed

* feat: update lab1 helper file

* chore: restructure utils

* feat: update memory helper

* chore: restructure identity

* chore: append to agent definition from the helper

* Renamed agentcore identity to lab6

* Renamed Gateway notebook to Lab 3 and reviewed with fixes

* Fixed typo in delete_memory

* Lab 1: review and minor fixes

* Lab 1: cleanup

* Lab 2: refactored

* fix: change model to Claude 3.7

* added TODOs

* updated lab1 notebook

* update runtime intro

* refactor utils file

* minor_update to memory

* memory return client

* revert change.

* feat: update runtime lab

* feat: add helper for bedrock guardrails

* fix: fix typos

* docs: minor update

* update lab1 tools

* update memory

* update - runtime

* updated lab3 + lambda

* removed outputs

* changed sh

* removed zip

* added one missing piece

* chore: rm observability old lab

* Updates to Lab6 Identity

* Updates to Lab6 Identity

* updated arch. diagram

* update docs lab1

* rename-lab-5-6

* update arch doc

* lab 03

* fixed lab 3 docs

* Fix Lab 4

* Lab 7 frontend

* Fix lab7

* Fix prereq issues and update gitignore

* adding lab 3 tool removal

* removed checkpoints

* merged

* chore: Update Lab 4 documentation

* fix: Update AgentCore IAM Role to access memory

* Lab 7 fixed invoke to runtime

* minor changes

* removed guardrails + minor edits

* Deleting files and folders.

* Rename, Refactor and deletion

Added sagemaker_helper

* fixing Client

* Removing guardrails code

* remove unused arch

* remove unused files

* updating lab01

* remove policies

* updating lab02

* docs: Update lab 4 markdown

* chore: Update Lab 4

* update cleanup

* cleaning up DS_Store files

* frontend

* updates to lab1 notebook

* updating architectures

* Lab5: fixed response formatting in streamlit app

* updating lab3

* updated lab3

* Lab 5 and Lab 6 and Helper Scripts Updates

Lab 5: Added the architecture diagram
Lab 6: Updated the notebook
Utils: Added helper functions
Sagemaker_helper: Cosmetic Updates

* Updating lab 4

* removing clean up from lab 3

* added lab3 changes

* Streamlit Fixes, Cosmetic Updates, Notebook Updates

* add maira's changes

* update lab2+3

* minor updates

* sync labs

* fix runtime docs

* refactoring end-to-end tutorials

* remove guardrail ss

---------

Co-authored-by: Aleksei Iancheruk <aianch@amazon.fr>
Co-authored-by: EugeneSel <youdjin.sel15@gmail.com>
Co-authored-by: Aidan Ricci <riaidan@amazon.com>
Co-authored-by: Achintya <pinnintiachintya@gmail.com>
Co-authored-by: naresh rajaram <nareshrd@amazon.com>
Co-authored-by: Lorenzo Micheli <lorenzo.micheli@gmail.com>
Co-authored-by: Achintya <apinnint@amazon.com>
Co-authored-by: HT <hardikvt@amazon.com>
Co-authored-by: HT <hardik.thakkar00@gmail.com>
Co-authored-by: Maira Ladeira Tanke <mttanke@amazon.com>
2025-08-14 22:52:33 -04:00

664 lines
28 KiB
YAML

AWSTemplateFormatVersion: "2010-09-09"
Description: "CloudFormation template for Customer Support System with DynamoDB tables, SSM parameters, and synthetic data"
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: Lambda Code Configuration
Parameters:
- LambdaS3Bucket
- LambdaS3Key
Parameters:
LambdaS3Bucket:
Description: The name of S3 bucket which contains lambda code
Type: String
MinLength: 1
LambdaS3Key:
Description: The S3 object key which contains customer support assistant code in zip format
Type: String
MinLength: 1
Resources:
RuntimeAgentCoreRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- bedrock-agentcore.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: BedrockAgentPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: ECRImageAccess
Effect: Allow
Action:
- ecr:BatchGetImage
- ecr:GetDownloadUrlForLayer
Resource:
- !Sub arn:aws:ecr:${AWS::Region}:${AWS::AccountId}:repository/bedrock-agentcore-customersupport*
- Effect: Allow
Action:
- logs:DescribeLogStreams
- logs:CreateLogGroup
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/bedrock-agentcore/runtimes/*
- Effect: Allow
Action:
- logs:DescribeLogGroups
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:*
- Effect: Allow
Action:
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/bedrock-agentcore/runtimes/*:log-stream:*
- Sid: ECRTokenAccess
Effect: Allow
Action:
- ecr:GetAuthorizationToken
Resource: "*"
- Effect: Allow
Action:
- xray:PutTraceSegments
- xray:PutTelemetryRecords
- xray:GetSamplingRules
- xray:GetSamplingTargets
Resource: "*"
- Effect: Allow
Action:
- cloudwatch:PutMetricData
Resource: "*"
Condition:
StringEquals:
cloudwatch:namespace: bedrock-agentcore
- Sid: GetAgentAccessToken
Effect: Allow
Action:
- bedrock-agentcore:GetWorkloadAccessToken
- bedrock-agentcore:GetWorkloadAccessTokenForJWT
- bedrock-agentcore:GetWorkloadAccessTokenForUserId
Resource:
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:workload-identity-directory/default
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:workload-identity-directory/default/workload-identity/customersupport*
- Sid: ProvisionedThroughputModelInvocation
Effect: Allow
Action:
- bedrock:InvokeModel
- bedrock:InvokeModelWithResponseStream
Resource:
- "arn:aws:bedrock:*::foundation-model/*"
- !Sub arn:aws:bedrock:${AWS::Region}:${AWS::AccountId}:*
- Sid: SSMGetparam
Effect: Allow
Action:
- ssm:GetParameter
Resource:
- !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/app/customersupport/*
- Sid: Identity
Effect: Allow
Action:
- bedrock-agentcore:GetResourceOauth2Token
Resource:
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:token-vault/default/oauth2credentialprovider/customersupport*
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:workload-identity-directory/default/workload-identity/customersupport*
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:workload-identity-directory/default
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:token-vault/default
- Sid: SecretManager
Effect: Allow
Action:
- secretsmanager:GetSecretValue
Resource:
- !Sub arn:aws:secretsmanager:${AWS::Region}:${AWS::AccountId}:secret:bedrock-agentcore-identity!default/oauth2/customersupport*
- Sid: AgentCoreMemory
Effect: Allow
Action:
- bedrock-agentcore:ListMemories
- bedrock-agentcore:ListMemoryRecords
- bedrock-agentcore:RetrieveMemoryRecords
- bedrock-agentcore:GetMemory
- bedrock-agentcore:GetMemoryRecord
- bedrock-agentcore:CreateEvent
- bedrock-agentcore:GetEvent
- bedrock-agentcore:ListEvents
Resource:
- !Sub arn:aws:bedrock-agentcore:${AWS::Region}:${AWS::AccountId}:memory/customersupport*
GatewayAgentCoreRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service:
- bedrock-agentcore.amazonaws.com
Action:
- sts:AssumeRole
Policies:
- PolicyName: BedrockAgentPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: InvokeFunction
Effect: Allow
Action:
- lambda:InvokeFunction
Resource:
- !GetAtt CustomerSupportLambda.Arn
# DynamoDB Table for Warranty Information
WarrantyTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: serial_number
AttributeType: S
- AttributeName: customer_id
AttributeType: S
KeySchema:
- AttributeName: serial_number
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: customer-index
KeySchema:
- AttributeName: customer_id
KeyType: HASH
Projection:
ProjectionType: ALL
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Tags:
- Key: Application
Value: CustomerSupport
- Key: CostCenter
Value: CustomerSupport
# DynamoDB Table for Customer Profiles
CustomerProfileTable:
Type: AWS::DynamoDB::Table
Properties:
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: customer_id
AttributeType: S
- AttributeName: email
AttributeType: S
- AttributeName: phone
AttributeType: S
KeySchema:
- AttributeName: customer_id
KeyType: HASH
GlobalSecondaryIndexes:
- IndexName: email-index
KeySchema:
- AttributeName: email
KeyType: HASH
Projection:
ProjectionType: ALL
- IndexName: phone-index
KeySchema:
- AttributeName: phone
KeyType: HASH
Projection:
ProjectionType: ALL
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
Tags:
- Key: Application
Value: CustomerSupport
- Key: CostCenter
Value: CustomerSupport
# Lambda function to populate synthetic data
PopulateDataFunction:
Type: AWS::Lambda::Function
Properties:
Runtime: python3.12
Handler: index.lambda_handler
Role: !GetAtt PopulateDataRole.Arn
Timeout: 120
Code:
ZipFile: |
import boto3
import json
import cfnresponse
from datetime import datetime, timedelta
import random
import uuid
from decimal import Decimal
def lambda_handler(event, context):
try:
if event['RequestType'] == 'Create':
dynamodb = boto3.resource('dynamodb')
warranty_table_name = event['ResourceProperties']['WarrantyTableName']
customer_table_name = event['ResourceProperties']['CustomerTableName']
warranty_table = dynamodb.Table(warranty_table_name)
customer_table = dynamodb.Table(customer_table_name)
# Customer profile data
customer_data = [
{
'customer_id': 'CUST001',
'first_name': 'John',
'last_name': 'Smith',
'email': 'john.smith@email.com',
'phone': '+1-555-0101',
'address': {
'street': '123 Main Street',
'city': 'New York',
'state': 'NY',
'zip_code': '10001',
'country': 'USA'
},
'date_of_birth': '1985-03-15',
'registration_date': '2022-11-20',
'tier': 'Premium',
'communication_preferences': {
'email': True,
'sms': True,
'phone': False
},
'support_cases_count': 2,
'total_purchases': 3,
'lifetime_value': 2850.00,
'notes': 'VIP customer, prefers email communication'
},
{
'customer_id': 'CUST002',
'first_name': 'Sarah',
'last_name': 'Johnson',
'email': 'sarah.johnson@email.com',
'phone': '+1-555-0102',
'address': {
'street': '456 Oak Avenue',
'city': 'Los Angeles',
'state': 'CA',
'zip_code': '90210',
'country': 'USA'
},
'date_of_birth': '1990-07-22',
'registration_date': '2023-03-15',
'tier': 'Standard',
'communication_preferences': {
'email': True,
'sms': False,
'phone': True
},
'support_cases_count': 1,
'total_purchases': 1,
'lifetime_value': 1299.99,
'notes': 'Tech-savvy customer, quick to resolve issues'
},
{
'customer_id': 'CUST003',
'first_name': 'Mike',
'last_name': 'Davis',
'email': 'mike.davis@email.com',
'phone': '+1-555-0103',
'address': {
'street': '789 Pine Street',
'city': 'Chicago',
'state': 'IL',
'zip_code': '60601',
'country': 'USA'
},
'date_of_birth': '1988-12-03',
'registration_date': '2023-08-10',
'tier': 'Gold',
'communication_preferences': {
'email': True,
'sms': True,
'phone': True
},
'support_cases_count': 0,
'total_purchases': 2,
'lifetime_value': 549.98,
'notes': 'Audio enthusiast, interested in premium products'
},
{
'customer_id': 'CUST004',
'first_name': 'Emily',
'last_name': 'Brown',
'email': 'emily.brown@email.com',
'phone': '+1-555-0104',
'address': {
'street': '321 Elm Drive',
'city': 'Houston',
'state': 'TX',
'zip_code': '77001',
'country': 'USA'
},
'date_of_birth': '1992-04-18',
'registration_date': '2022-09-05',
'tier': 'Standard',
'communication_preferences': {
'email': True,
'sms': False,
'phone': False
},
'support_cases_count': 3,
'total_purchases': 1,
'lifetime_value': 399.99,
'notes': 'Fitness enthusiast, uses wearables frequently'
},
{
'customer_id': 'CUST005',
'first_name': 'Robert',
'last_name': 'Wilson',
'email': 'robert.wilson@email.com',
'phone': '+1-555-0105',
'address': {
'street': '654 Maple Lane',
'city': 'Phoenix',
'state': 'AZ',
'zip_code': '85001',
'country': 'USA'
},
'date_of_birth': '1983-09-11',
'registration_date': '2023-10-12',
'tier': 'Premium',
'communication_preferences': {
'email': False,
'sms': True,
'phone': True
},
'support_cases_count': 1,
'total_purchases': 1,
'lifetime_value': 699.99,
'notes': 'Gaming enthusiast, prefers phone support'
}
]
# Warranty data with customer_id references
warranty_data = [
{
'serial_number': 'ABC12345678',
'customer_id': 'CUST001',
'product_name': 'SmartPhone Pro Max 128GB',
'purchase_date': '2023-01-15',
'warranty_end_date': '2025-01-15',
'warranty_type': 'Extended Warranty',
'coverage_details': 'Full coverage including accidental damage, water damage, and manufacturer defects',
'purchase_price': 1299.99,
'store_location': 'New York - 5th Avenue'
},
{
'serial_number': 'DEF98765432',
'customer_id': 'CUST002',
'product_name': 'Laptop Ultra 15.6"',
'purchase_date': '2023-06-20',
'warranty_end_date': '2024-06-20',
'warranty_type': 'Standard Warranty',
'coverage_details': 'Hardware defects and manufacturing issues covered. Software support included',
'purchase_price': 1299.99,
'store_location': 'Los Angeles - Beverly Hills'
},
{
'serial_number': 'GHI11111111',
'customer_id': 'CUST003',
'product_name': 'Wireless Headphones Elite',
'purchase_date': '2024-02-10',
'warranty_end_date': '2026-02-10',
'warranty_type': 'Premium Warranty',
'coverage_details': 'Comprehensive coverage including battery replacement, driver issues, and cosmetic damage',
'purchase_price': 299.99,
'store_location': 'Chicago - Michigan Avenue'
},
{
'serial_number': 'JKL22222222',
'customer_id': 'CUST004',
'product_name': 'Smart Watch Series X',
'purchase_date': '2022-12-05',
'warranty_end_date': '2023-12-05',
'warranty_type': 'Standard Warranty',
'coverage_details': 'Hardware and software defects covered. Water resistance guaranteed',
'purchase_price': 399.99,
'store_location': 'Houston - Galleria'
},
{
'serial_number': 'MNO33333333',
'customer_id': 'CUST005',
'product_name': 'Gaming Console Pro',
'purchase_date': '2023-11-25',
'warranty_end_date': '2024-11-25',
'warranty_type': 'Gaming Warranty',
'coverage_details': 'Controller issues, overheating protection, and hard drive replacement covered',
'purchase_price': 699.99,
'store_location': 'Phoenix - Scottsdale'
},
{
'serial_number': 'PQR44444444',
'customer_id': 'CUST001',
'product_name': 'Tablet Air 10.9"',
'purchase_date': '2024-03-12',
'warranty_end_date': '2025-03-12',
'warranty_type': 'Standard Warranty',
'coverage_details': 'Screen defects, battery issues, and charging port problems covered',
'purchase_price': 599.99,
'store_location': 'New York - 5th Avenue'
},
{
'serial_number': 'STU55555555',
'customer_id': 'CUST001',
'product_name': 'Smart TV 65" OLED',
'purchase_date': '2023-08-30',
'warranty_end_date': '2025-08-30',
'warranty_type': 'Extended Warranty',
'coverage_details': 'Panel replacement, smart features, sound system, and remote control covered',
'purchase_price': 1999.99,
'store_location': 'New York - 5th Avenue'
},
{
'serial_number': 'VWX66666666',
'customer_id': 'CUST003',
'product_name': 'Bluetooth Speaker Pro',
'purchase_date': '2024-01-08',
'warranty_end_date': '2026-01-08',
'warranty_type': 'Audio Warranty',
'coverage_details': 'Driver replacement, battery issues, and waterproofing covered',
'purchase_price': 249.99,
'store_location': 'Chicago - Michigan Avenue'
}
]
# Insert customer data
with customer_table.batch_writer() as batch:
for item in customer_data:
item = json.loads(json.dumps(item), parse_float=Decimal)
batch.put_item(Item=item)
# Insert warranty data
with warranty_table.batch_writer() as batch:
for item in warranty_data:
item = json.loads(json.dumps(item), parse_float=Decimal)
batch.put_item(Item=item)
print(f"Successfully populated {len(customer_data)} customer profiles")
print(f"Successfully populated {len(warranty_data)} warranty records")
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
else:
cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
except Exception as e:
print(f"Error: {str(e)}")
cfnresponse.send(event, context, cfnresponse.FAILED, {})
# IAM Role for Lambda function
PopulateDataRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: DynamoDBWritePolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:BatchWriteItem
Resource:
- !GetAtt WarrantyTable.Arn
- !GetAtt CustomerProfileTable.Arn
- PolicyName: AllowBasicLogs
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: arn:aws:logs:*:*:*
# Custom resource to trigger Lambda function
PopulateData:
Type: AWS::CloudFormation::CustomResource
Properties:
ServiceToken: !GetAtt PopulateDataFunction.Arn
WarrantyTableName: !Ref WarrantyTable
CustomerTableName: !Ref CustomerProfileTable
DependsOn:
- WarrantyTable
- CustomerProfileTable
# Lambda target
CustomerSupportLambdaRole:
Type: AWS::IAM::Role
Properties:
Path: /service-role/
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
- Action: sts:AssumeRole
Effect: Allow
Principal:
Service: lambda.amazonaws.com
Policies:
- PolicyName: CustomerProfileAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AllowReadCustomerTableNameFromSSM
Effect: Allow
Action: ssm:GetParameter
Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter${CustomerProfileTableNameParameter}
- Sid: AllowReadCustomerProfileTable
Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:Query
- dynamodb:DescribeTable
Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${CustomerProfileTable}
- Sid: AllowReadCustomerTableIndexes
Effect: Allow
Action:
- dynamodb:Query
Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${CustomerProfileTable}/index/*
- PolicyName: WarrantyCheckAccessPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Sid: AllowReadWarrantyTableNameFromSSM
Effect: Allow
Action: ssm:GetParameter
Resource: !Sub arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter${WarrantyTableNameParameter}
- Sid: AllowReadWarrantyTable
Effect: Allow
Action:
- dynamodb:GetItem
- dynamodb:DescribeTable
Resource: !Sub arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${WarrantyTable}
CustomerSupportLambda:
Type: AWS::Lambda::Function
Properties:
Description: "Lambda function for Customer Support Assistant"
Handler: lambda_function.lambda_handler
Code:
S3Bucket: !Ref LambdaS3Bucket
S3Key: !Ref LambdaS3Key
Role: !GetAtt CustomerSupportLambdaRole.Arn
Runtime: python3.12
PackageType: Zip
Architectures:
- x86_64
# SSM Parameter to store warranty table name
WarrantyTableNameParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /app/customersupport/dynamodb/warranty_table_name
Type: String
Value: !Ref WarrantyTable
Description: DynamoDB table name for warranty information
Tags:
Application: CustomerSupport
# SSM Parameter to store customer profile table name
CustomerProfileTableNameParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /app/customersupport/dynamodb/customer_profile_table_name
Type: String
Value: !Ref CustomerProfileTable
Description: DynamoDB table name for customer profiles
Tags:
Application: CustomerSupport
GatewayAgentcoreIAMRoleParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /app/customersupport/agentcore/gateway_iam_role
Type: String
Value: !GetAtt GatewayAgentCoreRole.Arn
Description: agentcore IAM role to assume
Tags:
Application: CustomerSupport
RuntimeAgentcoreIAMRoleParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /app/customersupport/agentcore/runtime_iam_role
Type: String
Value: !GetAtt RuntimeAgentCoreRole.Arn
Description: agentcore IAM role to assume
Tags:
Application: CustomerSupport
LambdaArnParameter:
Type: AWS::SSM::Parameter
Properties:
Name: /app/customersupport/agentcore/lambda_arn
Type: String
Value: !GetAtt CustomerSupportLambda.Arn
Description: ARN of the lambda that integrates with agentcore
Tags:
Application: CustomerSupport