AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: | AWS Operations Agent with Lambda Web Adapter - Direct boto3 invocation for Claude streaming with DynamoDB persistence Parameters: Environment: Type: String Default: dev AllowedValues: - dev - staging - prod Description: Environment name for resource tagging BedrockRegion: Type: String Default: us-east-1 Description: AWS region for Bedrock service ConversationTableName: Type: String Default: aws-operations-agent-conversations Description: Name of the DynamoDB table for conversation storage ConversationTTLMinutes: Type: Number Default: 15 MinValue: 1 MaxValue: 1440 Description: TTL in minutes for conversation expiration (1-1440 minutes, default 15) ConversationTTLMinutes: Type: Number Default: 15 MinValue: 1 MaxValue: 1440 Description: TTL in minutes for conversation expiration (1-1440 minutes, default 15) Globals: Function: Timeout: 300 MemorySize: 2056 Resources: # DynamoDB Table for Conversation Persistence ConversationTable: Type: AWS::DynamoDB::Table Properties: TableName: !Sub "${ConversationTableName}-${Environment}" BillingMode: PAY_PER_REQUEST AttributeDefinitions: - AttributeName: conversation_id AttributeType: S KeySchema: - AttributeName: conversation_id KeyType: HASH TimeToLiveSpecification: AttributeName: ttl Enabled: true PointInTimeRecoverySpecification: PointInTimeRecoveryEnabled: true StreamSpecification: StreamViewType: NEW_AND_OLD_IMAGES Tags: - Key: Solution Value: lambda-adaptor-bedrock-agentcore - Key: Component Value: conversation-storage - Key: Environment Value: !Ref Environment - Key: ManagedBy Value: SAM # Bedrock AgentCore Gateway Execution Role - Role that Bedrock AgentCore Gateway assumes to invoke Lambda functions BedrockAgentCoreGatewayExecutionRole: Type: AWS::IAM::Role Properties: RoleName: !Sub BedrockAgentCoreGatewayExecutionRole-${Environment} AssumeRolePolicyDocument: Version: '2012-10-17' Statement: # Production Bedrock AgentCore Gateway - Bedrock AgentCore service principal - Effect: Allow Principal: Service: bedrock-agentcore.amazonaws.com Action: sts:AssumeRole Policies: - PolicyName: BedrockAgentCoreGatewayExecutionPolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: InvokeLambdaFunctions Effect: Allow Action: - lambda:InvokeFunction Resource: '*' - Sid: BedrockAgentCorePermissions Effect: Allow Action: - bedrock-agentcore:* - iam:PassRole Resource: '*' - Sid: S3Permissions Effect: Allow Action: - s3:GetObject - s3:PutObject - s3:DeleteObject - s3:ListBucket - s3:GetBucketLocation Resource: '*' - Sid: CloudWatchLogsPermissions Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - logs:DescribeLogGroups - logs:DescribeLogStreams Resource: '*' Tags: - Key: Solution Value: lambda-adaptor-bedrock-agentcore - Key: Component Value: bedrock-agentcore-gateway-execution - Key: Environment Value: !Ref Environment - Key: ManagedBy Value: SAM # Custom Lambda Execution Role AWSOperationsAgentFunctionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole - arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess Policies: - PolicyName: BedrockInvokePolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: BedrockInvokePolicy Effect: Allow Action: - bedrock:InvokeModel - bedrock:InvokeModelWithResponseStream - bedrock:Converse - bedrock:ConverseStream Resource: '*' - PolicyName: DynamoDBConversationPolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: DynamoDBConversationAccess Effect: Allow Action: - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem - dynamodb:Query - dynamodb:Scan Resource: !GetAtt ConversationTable.Arn - PolicyName: CloudWatchLogsPolicy PolicyDocument: Version: '2012-10-17' Statement: - Sid: CloudWatchLogsPolicy Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/aws-operations-agent-${Environment}:* Tags: - Key: Solution Value: lambda-adaptor-bedrock-agentcore - Key: Component Value: aws-operations-agent - Key: Environment Value: !Ref Environment - Key: ManagedBy Value: SAM # AWS Operations Agent Lambda Function AWSOperationsAgentFunction: Type: AWS::Serverless::Function Properties: FunctionName: !Sub aws-operations-agent-${Environment} Description: AWS Operations Agent with Claude streaming via direct boto3 invocation with DynamoDB persistence PackageType: Image MemorySize: 1536 Timeout: 300 Role: !GetAtt AWSOperationsAgentFunctionRole.Arn Environment: Variables: AWS_LWA_INVOKE_MODE: RESPONSE_STREAM BEDROCK_MODEL_ID: us.anthropic.claude-3-7-sonnet-20250219-v1:0 BEDROCK_REGION: !Ref BedrockRegion DYNAMODB_TABLE_NAME: !Ref ConversationTable PROJECT_NAME: lambda-adaptor-bedrock-agentcore ENVIRONMENT: !Ref Environment CONVERSATION_TTL_MINUTES: !Ref ConversationTTLMinutes CONVERSATION_TTL_MINUTES: 15 # Function URL Configuration for direct HTTP access FunctionUrlConfig: AuthType: AWS_IAM InvokeMode: RESPONSE_STREAM # CRITICAL: This was missing! Cors: AllowCredentials: true AllowHeaders: - '*' AllowMethods: - '*' AllowOrigins: - '*' MaxAge: 86400 # Tracing Tracing: Active # Tags Tags: Solution: lambda-adaptor-bedrock-agentcore Component: aws-operations-agent Environment: !Ref Environment ManagedBy: SAM InvocationType: boto3-direct Metadata: Dockerfile: Dockerfile DockerContext: . DockerTag: !Sub aws-operations-agent-${Environment} # CloudWatch Log Group AWSOperationsAgentLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/aws-operations-agent-${Environment} RetentionInDays: 14 Outputs: # DynamoDB Table Information ConversationTableName: Description: Name of the DynamoDB table for conversation storage Value: !Ref ConversationTable Export: Name: !Sub ${AWS::StackName}-ConversationTableName ConversationTableArn: Description: ARN of the DynamoDB table for conversation storage Value: !GetAtt ConversationTable.Arn Export: Name: !Sub ${AWS::StackName}-ConversationTableArn # Bedrock AgentCore Gateway Role Information BedrockAgentCoreGatewayExecutionRoleArn: Description: Bedrock AgentCore Gateway Execution Role ARN - Use this role when creating Bedrock AgentCore Gateway targets Value: !GetAtt BedrockAgentCoreGatewayExecutionRole.Arn Export: Name: !Sub ${AWS::StackName}-BedrockAgentCoreGatewayExecutionRoleArn BedrockAgentCoreGatewayExecutionRoleName: Description: Bedrock AgentCore Gateway Execution Role Name Value: !Ref BedrockAgentCoreGatewayExecutionRole Export: Name: !Sub ${AWS::StackName}-BedrockAgentCoreGatewayExecutionRoleName # Function Information AWSOperationsAgentFunctionArn: Description: AWS Operations Agent Function ARN for direct boto3 invocation Value: !GetAtt AWSOperationsAgentFunction.Arn Export: Name: !Sub ${AWS::StackName}-AWSOperationsAgentArn AWSOperationsAgentFunctionName: Description: AWS Operations Agent Function Name for direct boto3 invocation Value: !Ref AWSOperationsAgentFunction Export: Name: !Sub ${AWS::StackName}-AWSOperationsAgentName AWSOperationsAgentFunctionUrl: Description: AWS Operations Agent Function URL for direct HTTP access Value: !GetAtt AWSOperationsAgentFunctionUrl.FunctionUrl Export: Name: !Sub ${AWS::StackName}-AWSOperationsAgentUrl # Testing Information Boto3TestCommand: Description: Python boto3 command for testing Value: !Sub | import boto3 lambda_client = boto3.client('lambda', region_name='${AWS::Region}') response = lambda_client.invoke_with_response_stream( FunctionName='${AWSOperationsAgentFunction}', Payload='{"message": "Hello Claude!"}' ) # Stack Information StackName: Description: CloudFormation Stack Name Value: !Ref AWS::StackName Environment: Description: Deployment Environment Value: !Ref Environment BedrockRegion: Description: Bedrock Region Value: !Ref BedrockRegion ConversationTTLMinutes: Description: Conversation TTL in minutes Value: !Ref ConversationTTLMinutes Export: Name: !Sub ${AWS::StackName}-ConversationTTLMinutes