mirror of
https://github.com/awslabs/amazon-bedrock-agentcore-samples.git
synced 2025-09-08 20:50:46 +00:00
* 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>
797 lines
30 KiB
Plaintext
797 lines
30 KiB
Plaintext
{
|
|
"cells": [
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"# Lab 3: Creating Agents with Amazon AgentCore Identity \n",
|
|
"\n",
|
|
"## Overview\n",
|
|
"\n",
|
|
"In this lab, you will enhance your existing customer support agent by integrating Amazon Bedrock AgentCore Identity functionality. This enables your agent to securely authenticate with external services like Google Calendar using OAuth2 flows, while maintaining proper credential management through AgentCore's identity providers.\n",
|
|
"\n",
|
|
"Calendar integration enables your support agent to schedule events like product demonstrations and technical support appointments directly within customer conversations, streamlining the support workflow and enhancing the overall customer experience.\n",
|
|
"\n",
|
|
"\n",
|
|
"\n",
|
|
"**Based on**: [Official Customer Support Assistant](https://github.com/awslabs/amazon-bedrock-agentcore-samples/tree/main/02-use-cases/customer-support-assistant)\n",
|
|
"\n",
|
|
"\n",
|
|
"### Lab Details\n",
|
|
"\n",
|
|
"| Information | Details |\n",
|
|
"| :----------------- | :------------------------------------------------------------------------------- |\n",
|
|
"| Lab type | Incremental Enhancement |\n",
|
|
"| Agent type | Single |\n",
|
|
"| Agentic Framework | Strands Agents |\n",
|
|
"| LLM model | Anthropic Claude Sonnet 4 |\n",
|
|
"| Lab components | AgentCore Identity, OAuth2 providers, Google Calendar API, Cognito integration |\n",
|
|
"| Lab vertical | Customer Support |\n",
|
|
"| Example complexity | Moderate |\n",
|
|
"| SDK used | Amazon BedrockAgentCore Python SDK, Strands Agents, Google API Client |\n",
|
|
"\n",
|
|
"### Lab Architecture\n",
|
|
"\n",
|
|
"In this lab, you will extend your customer support agent with identity management capabilities. The agent will authenticate users through AgentCore Identity providers and access external services like Google Calendar on behalf of authenticated users.\n",
|
|
"\n",
|
|
"Your agent will integrate:\n",
|
|
"- **AgentCore Identity**: Secure credential management and OAuth2 flows\n",
|
|
"- **Google OAuth2 Provider**: Authentication with Google services\n",
|
|
"- **Calendar Tools**: Create events and retrieve calendar information\n",
|
|
"- **Cognito Provider** (Optional): Custom identity provider integration\n",
|
|
"\n",
|
|
"\n",
|
|
"### Lab Key Features\n",
|
|
"\n",
|
|
"- Secure OAuth2 authentication flows\n",
|
|
"- External service integration with proper credential management\n",
|
|
"- Google Calendar API integration\n",
|
|
"- Custom identity provider configuration"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Prerequisites\n",
|
|
"\n",
|
|
"To execute this tutorial you will need:\n",
|
|
"\n",
|
|
"- Python 3.10+\n",
|
|
"- AWS credentials configured\n",
|
|
"- Amazon Bedrock AgentCore SDK\n",
|
|
"- Strands Agents\n",
|
|
"- **Previously completed Labs 1 & 2** - This lab builds directly on your existing agent\n",
|
|
"- **Google Developer Console access** - For creating OAuth2 credentials\n",
|
|
"- **AgentCore Identity permissions** - IAM role with AgentCore Identity access\n",
|
|
"\n",
|
|
"**Note**: Ensure your basic agent from Labs 1 & 2 is working correctly before proceeding.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 1: Install Dependencies and Import Libraries\n",
|
|
"\n",
|
|
"We'll install the required packages for AgentCore Identity integration, Google API access, and OAuth2 authentication flows. We'll also create some helper functions for later."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Install required packages\n",
|
|
"%pip install strands-agents strands-agents-tools \"boto3>=1.39.15\" python-dotenv utils google-auth google-api-python-client ddgs -q"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Import libraries\n",
|
|
"import boto3\n",
|
|
"import click\n",
|
|
"import sys\n",
|
|
"import json\n",
|
|
"import os\n",
|
|
"from botocore.exceptions import ClientError\n",
|
|
"\n",
|
|
"from bedrock_agentcore.identity.auth import requires_access_token\n",
|
|
"from google.oauth2.credentials import Credentials\n",
|
|
"from googleapiclient.discovery import build\n",
|
|
"from googleapiclient.errors import HttpError\n",
|
|
"from datetime import datetime, timedelta\n",
|
|
"from strands import tool\n",
|
|
"from strands import Agent\n",
|
|
"from strands.models import BedrockModel\n",
|
|
"from strands_tools import calculator\n",
|
|
"import webbrowser\n",
|
|
"import sys\n",
|
|
"import os\n",
|
|
"\n",
|
|
"from lab_helpers.utils import get_ssm_parameter, put_ssm_parameter\n",
|
|
"\n",
|
|
"session = boto3.session.Session()\n",
|
|
"region = session.region_name\n",
|
|
"\n",
|
|
"identity_client = boto3.client(\n",
|
|
" \"bedrock-agentcore-control\",\n",
|
|
" region_name=region,\n",
|
|
")\n",
|
|
"cognito = boto3.client('cognito-idp')\n",
|
|
"ssm = boto3.client(\"ssm\", region_name=region)\n",
|
|
"\n",
|
|
"print(\"✅ Libraries imported successfully!\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# Helper functions to save, retrieve, and delete provider names from SSM\n",
|
|
"\n",
|
|
"def store_provider_name_in_ssm(provider_name: str):\n",
|
|
" \"\"\"Store credential provider name in SSM parameter.\"\"\"\n",
|
|
" param_name = \"/app/customersupport/agentcore/google_provider\"\n",
|
|
" try:\n",
|
|
" ssm.put_parameter(\n",
|
|
" Name=param_name, Value=provider_name, Type=\"String\", Overwrite=True\n",
|
|
" )\n",
|
|
" click.echo(f\"🔐 Stored provider name in SSM: {param_name}\")\n",
|
|
" except ClientError as e:\n",
|
|
" click.echo(f\"⚠️ Failed to store provider name in SSM: {e}\")\n",
|
|
"\n",
|
|
"\n",
|
|
"def get_provider_name_from_ssm() -> str:\n",
|
|
" \"\"\"Get credential provider name from SSM parameter.\"\"\"\n",
|
|
" param_name = \"/app/customersupport/agentcore/google_provider\"\n",
|
|
" try:\n",
|
|
" response = ssm.get_parameter(Name=param_name)\n",
|
|
" return response[\"Parameter\"][\"Value\"]\n",
|
|
" except ClientError:\n",
|
|
" return None\n",
|
|
"\n",
|
|
"\n",
|
|
"def delete_ssm_param():\n",
|
|
" \"\"\"Delete SSM parameter for provider.\"\"\"\n",
|
|
" param_name = \"/app/customersupport/agentcore/google_provider\"\n",
|
|
" try:\n",
|
|
" ssm.delete_parameter(Name=param_name)\n",
|
|
" click.echo(f\"🧹 Deleted SSM parameter: {param_name}\")\n",
|
|
" except ClientError as e:\n",
|
|
" click.echo(f\"⚠️ Failed to delete SSM parameter: {e}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 2: Import Customer Support Tools\n",
|
|
"\n",
|
|
"We'll reuse the customer support tools from Lab 1 to maintain our agent's core functionality.\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from lab_helpers.lab1_strands_agent import (\n",
|
|
" get_return_policy,\n",
|
|
" get_product_info,\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 3: Import Memory Tools\n",
|
|
"\n",
|
|
"We'll reuse the memory tools from Lab 2 to maintain our agent's core functionality.\n",
|
|
"\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"from lab_helpers.lab2_helper import setup_memory\n",
|
|
"\n",
|
|
"memory_hook = setup_memory()"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Step 4: Configure AgentCore Identity Clients\n",
|
|
"\n",
|
|
"In this step, we'll integrate Google Calendar API functionality into our customer support agent. To securely access external services like Google Calendar on behalf of users, we need to implement proper authentication mechanisms.\n",
|
|
"\n",
|
|
"Amazon Bedrock AgentCore Identity provides a streamlined approach to managing OAuth2 authentication flows, eliminating the complexity of manual token management, refresh handling, and credential storage. This service acts as a secure intermediary between your agent and external service providers.\n",
|
|
"\n",
|
|
"To create a Google OAuth client, follow the steps below:\n",
|
|
"\n",
|
|
"#### ✅ 1. Create a Project in Google Developer Console\n",
|
|
"\n",
|
|
"1. Go to the [Google Developer Console](https://console.developers.google.com/).\n",
|
|
"2. In the top navigation bar, click on “Create Project”.\n",
|
|
"3. Enter a Project Name.\n",
|
|
"4. Choose an Organization or leave as “No organization” if not applicable.\n",
|
|
"5. Click Create.\n",
|
|
"\n",
|
|
"Your new project will appear in the project list.\n",
|
|
"\n",
|
|
"#### 📦 2. Enable Google Calendar API\n",
|
|
"\n",
|
|
"1. With your project selected, open the left-hand menu and go to APIs & Services > Library.\n",
|
|
"2. In the search bar, type Google Calendar API.\n",
|
|
"3. Click on Google Calendar API from the results.\n",
|
|
"4. Click Enable.\n",
|
|
"\n",
|
|
"#### 🛡️ 3. Configure OAuth Consent Screen\n",
|
|
"\n",
|
|
"1. In the left-hand menu, go to APIs & Services > OAuth consent screen.\n",
|
|
"\n",
|
|
"2. Click “Get started”.\n",
|
|
"\n",
|
|
"3. Fill in the required fields: App Name, and User Support Email\n",
|
|
"4. Click Next, then: Select the User Type (Internal or External). If selecting External, add the tester email addresses. Provide Developer Contact Information (your email).\n",
|
|
"5. Accept terms and click Finish.\n",
|
|
"6. Click Create to finalize the consent screen.\n",
|
|
"\n",
|
|
"#### 🔧 4. Create OAuth 2.0 Credentials\n",
|
|
"\n",
|
|
"1. Navigate to APIs & Services > Credentials from the left-hand menu.\n",
|
|
"2. Click Create Credentials > OAuth client ID.\n",
|
|
"3. Choose Web application as the application type.\n",
|
|
"4. Enter a name for the credentials.\n",
|
|
"5. Under Authorized redirect URIs, add your following redirect URI:\n",
|
|
" - `https://bedrock-agentcore.us-east-1.amazonaws.com/identities/oauth2/callback`\n",
|
|
"6. Click Create.\n",
|
|
"\n",
|
|
"#### 🔑 5. Obtain Client ID and Client Secret\n",
|
|
"\n",
|
|
"After creation, a dialog will display your Client ID and Client Secret. Download JSON to save the credentials to a file. Save this file to your project in `credentials.json`. (You may have to rename the file to match this) \n",
|
|
"\n",
|
|
"#### 🔍 6. Update the Data Access Scopes\n",
|
|
"\n",
|
|
"1. Go to APIs & Services > Credentials.\n",
|
|
"2. Click on the OAuth 2.0 client ID you created.\n",
|
|
"3. In the left-hand menu, select Data access.\n",
|
|
"4. Click “Add or remove scopes”.\n",
|
|
"5. Under Manually add scopes, enter scope: `https://www.googleapis.com/auth/calendar`\n",
|
|
"6. Click Update, then click Save to confirm the configuration."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"credentials_file = \"credentials.json\"\n",
|
|
"\n",
|
|
"#Verify credentials file looks as expected, and extract credentials\n",
|
|
"\n",
|
|
"if not os.path.isfile(credentials_file):\n",
|
|
" print(f\"❌ Error: '{credentials_file}' file not found\")\n",
|
|
" sys.exit(1)\n",
|
|
"\n",
|
|
"print(f\"📄 Reading credentials from {credentials_file}...\")\n",
|
|
"try:\n",
|
|
" with open(credentials_file, \"r\") as f:\n",
|
|
" data = json.load(f)\n",
|
|
"except json.JSONDecodeError as e:\n",
|
|
" print(f\"❌ Error parsing JSON: {e}\")\n",
|
|
" sys.exit(1)\n",
|
|
"\n",
|
|
"web_config = data.get(\"web\")\n",
|
|
"if not web_config:\n",
|
|
" print(\"❌ Error: 'web' section missing in credentials.json\")\n",
|
|
" sys.exit(1)\n",
|
|
"\n",
|
|
"client_id = web_config.get(\"client_id\")\n",
|
|
"client_secret = web_config.get(\"client_secret\")\n",
|
|
"\n",
|
|
"if not client_id:\n",
|
|
" print(\"❌ Error: 'client_id' not found in credentials.json\")\n",
|
|
" sys.exit(1)\n",
|
|
"\n",
|
|
"if not client_secret:\n",
|
|
" print(\"❌ Error: 'client_secret' not found in credentials.json\")\n",
|
|
" sys.exit(1)\n",
|
|
"\n",
|
|
"print(\"✅ Client ID and Secret loaded from credentials.json\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"google_provider_name = \"customersupport-google-calendar\"\n",
|
|
"\n",
|
|
"try:\n",
|
|
" print(\"🔧 Creating Google OAuth2 credential provider...\")\n",
|
|
" google_provider = identity_client.create_oauth2_credential_provider(\n",
|
|
" name=google_provider_name,\n",
|
|
" credentialProviderVendor=\"GoogleOauth2\",\n",
|
|
" oauth2ProviderConfigInput={\n",
|
|
" \"googleOauth2ProviderConfig\": {\n",
|
|
" \"clientId\": client_id,\n",
|
|
" \"clientSecret\": client_secret,\n",
|
|
" }\n",
|
|
" },\n",
|
|
" )\n",
|
|
"\n",
|
|
" print(\"✅ Google OAuth2 credential provider created successfully\")\n",
|
|
" google_provider_arn = google_provider[\"credentialProviderArn\"]\n",
|
|
" print(f\" Provider ARN: {google_provider_arn}\")\n",
|
|
" print(f\" Provider Name: {google_provider['name']}\")\n",
|
|
"\n",
|
|
" # Store provider name in SSM\n",
|
|
" store_provider_name_in_ssm(google_provider_name)\n",
|
|
"except Exception as e:\n",
|
|
" print(f\"❌ Error creating Google credential provider: {str(e)}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# List all OAuth2 credential providers.\n",
|
|
"try:\n",
|
|
" response = identity_client.list_oauth2_credential_providers(maxResults=20)\n",
|
|
" providers = response.get(\"credentialProviders\", [])\n",
|
|
" print(providers)\n",
|
|
"except Exception as e:\n",
|
|
" print(f\"❌ Error listing credential providers: {str(e)}\", err=True)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Now we'll create tools that use AgentCore Identity to authenticate with Google Calendar and perform calendar operations on behalf of users.\n",
|
|
"\n",
|
|
"First, let's configure the OAuth2 authentication flow:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"async def on_auth_url(url: str):\n",
|
|
" webbrowser.open(url)\n",
|
|
" \n",
|
|
"SCOPES = [\"https://www.googleapis.com/auth/calendar\"]\n",
|
|
"\n",
|
|
"google_access_token = None\n",
|
|
"\n",
|
|
"@requires_access_token(\n",
|
|
" provider_name=google_provider_name,\n",
|
|
" scopes=[\"https://www.googleapis.com/auth/calendar\"], # Google OAuth2 scopes\n",
|
|
" auth_flow=\"USER_FEDERATION\", # On-behalf-of user (3LO) flow\n",
|
|
" on_auth_url=on_auth_url, # prints authorization URL to console\n",
|
|
" force_authentication=True,\n",
|
|
" into=\"access_token\",\n",
|
|
")\n",
|
|
"\n",
|
|
"def get_google_access_token(access_token: str):\n",
|
|
" return access_token"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"source": [
|
|
"Now let's create the calendar management tools:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"@tool(\n",
|
|
" name=\"Create_calendar_event\",\n",
|
|
" description=\"Creates a new event on your Google Calendar\",\n",
|
|
")\n",
|
|
"def create_calendar_event() -> str:\n",
|
|
" google_access_token = ''\n",
|
|
" try:\n",
|
|
" google_access_token = get_google_access_token(access_token=google_access_token)\n",
|
|
" if not google_access_token:\n",
|
|
" raise Exception(\"requires_access_token did not provide tokens\")\n",
|
|
" except Exception as e:\n",
|
|
" return \"Error Authentication with Google: \" + str(e)\n",
|
|
"\n",
|
|
" creds = Credentials(token=google_access_token, scopes=SCOPES)\n",
|
|
"\n",
|
|
" try:\n",
|
|
" service = build(\"calendar\", \"v3\", credentials=creds)\n",
|
|
"\n",
|
|
" # Define event details\n",
|
|
" start_time = datetime.now() + timedelta(hours=1)\n",
|
|
" end_time = start_time + timedelta(hours=1)\n",
|
|
"\n",
|
|
" event = {\n",
|
|
" \"summary\": \"Test Event from API\",\n",
|
|
" \"location\": \"Virtual\",\n",
|
|
" \"description\": \"This event was created using the Google Calendar API.\",\n",
|
|
" \"start\": {\n",
|
|
" \"dateTime\": start_time.isoformat() + \"Z\", # UTC time\n",
|
|
" \"timeZone\": \"UTC\",\n",
|
|
" },\n",
|
|
" \"end\": {\n",
|
|
" \"dateTime\": end_time.isoformat() + \"Z\",\n",
|
|
" \"timeZone\": \"UTC\",\n",
|
|
" },\n",
|
|
" }\n",
|
|
"\n",
|
|
" created_event = (\n",
|
|
" service.events().insert(calendarId=\"primary\", body=event).execute()\n",
|
|
" )\n",
|
|
"\n",
|
|
" return json.dumps(\n",
|
|
" {\n",
|
|
" \"event_created\": True,\n",
|
|
" \"event_id\": created_event.get(\"id\"),\n",
|
|
" \"htmlLink\": created_event.get(\"htmlLink\"),\n",
|
|
" }\n",
|
|
" )\n",
|
|
"\n",
|
|
" except HttpError as error:\n",
|
|
" return json.dumps({\"error\": str(error), \"event_created\": False})\n",
|
|
" except Exception as e:\n",
|
|
" return json.dumps({\"error\": str(e), \"event_created\": False})\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"@tool(\n",
|
|
" name=\"Get_calendar_events_today\",\n",
|
|
" description=\"Retrieves the calendar events for the day from your Google Calendar\",\n",
|
|
")\n",
|
|
"def get_calendar_events_today() -> str:\n",
|
|
" google_access_token = ''\n",
|
|
" try:\n",
|
|
" google_access_token = get_google_access_token(\n",
|
|
" access_token=google_access_token)\n",
|
|
"\n",
|
|
" if not google_access_token:\n",
|
|
" raise Exception(\"requires_access_token did not provide tokens\")\n",
|
|
" except Exception as e:\n",
|
|
" return \"Error Authentication with Google: \" + str(e)\n",
|
|
"\n",
|
|
" # Create credentials from the provided access token\n",
|
|
" creds = Credentials(token=google_access_token, scopes=SCOPES)\n",
|
|
" try:\n",
|
|
" service = build(\"calendar\", \"v3\", credentials=creds)\n",
|
|
" # Call the Calendar API\n",
|
|
" today_start = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)\n",
|
|
" today_end = today_start.replace(hour=23, minute=59, second=59)\n",
|
|
"\n",
|
|
" # Format with CDT timezone (-05:00)\n",
|
|
" timeMin = today_start.strftime(\"%Y-%m-%dT00:00:00-05:00\")\n",
|
|
" timeMax = today_end.strftime(\"%Y-%m-%dT23:59:59-05:00\")\n",
|
|
"\n",
|
|
" events_result = (\n",
|
|
" service.events()\n",
|
|
" .list(\n",
|
|
" calendarId=\"primary\",\n",
|
|
" timeMin=timeMin,\n",
|
|
" timeMax=timeMax,\n",
|
|
" singleEvents=True,\n",
|
|
" orderBy=\"startTime\",\n",
|
|
" )\n",
|
|
" .execute()\n",
|
|
" )\n",
|
|
" events = events_result.get(\"items\", [])\n",
|
|
" if not events:\n",
|
|
" return json.dumps({\"events\": []}) # Return empty events array as JSON\n",
|
|
"\n",
|
|
" return json.dumps({\"events\": events}) # Return events wrapped in an object\n",
|
|
" except HttpError as error:\n",
|
|
" error_message = str(error)\n",
|
|
" return json.dumps({\"error\": error_message, \"events\": []})\n",
|
|
" except Exception as e:\n",
|
|
" error_message = str(e)\n",
|
|
" return json.dumps({\"error\": error_message, \"events\": []})"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"Let's create our customer support agent with the new calendar functionality:"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"model_id = \"us.anthropic.claude-sonnet-4-20250514-v1:0\"\n",
|
|
"model = BedrockModel(\n",
|
|
" model_id=model_id,\n",
|
|
")\n",
|
|
"system_prompt = \"\"\"\n",
|
|
" You are a helpful and professional customer support assistant for an electronics e-commerce company.\n",
|
|
"Your role is to:\n",
|
|
"- Provide accurate information using the tools available to you\n",
|
|
"- Support the customer with technical information and product specifications.\n",
|
|
"- Be friendly, patient, and understanding with customers\n",
|
|
"- Always offer additional help after answering questions\n",
|
|
"- If you can't help with something, direct customers to the appropriate contact\n",
|
|
"\n",
|
|
"You have access to the following tools:\n",
|
|
"1. get_return_policy() - For warranty and return policy questions\n",
|
|
"2. get_product_info() - To get information about a specific product\n",
|
|
"3. web_search() - To access current technical documentation, or for updated information. \n",
|
|
"4. create_calendar_event() - To create a new calendar event\n",
|
|
"5. get_calendar_events_today() - To find events on the calendar today\n",
|
|
"Always use the appropriate tool to get accurate, up-to-date information rather than making assumptions about electronic products or specifications.\n",
|
|
" \"\"\"\n",
|
|
"agent = Agent(\n",
|
|
" model=model,\n",
|
|
" system_prompt=system_prompt,\n",
|
|
" tools=[create_calendar_event, get_calendar_events_today],\n",
|
|
" callback_handler=None,\n",
|
|
")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"It's time to test our agent now! You will see a message that says ```Polling for token for authorization url```, followed by a URL. Click on this URL to sign into your Google account, and give the agent the permissions to access your Google calendar."
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"print(str(agent(\n",
|
|
" \"Can you create a new event on my cal? You can call the create_calendar_event directly.\"\n",
|
|
" )))\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"print(str(agent(\"Whats my agenda for today?\")))"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Congratulations! 🎉\n",
|
|
"\n",
|
|
"You have successfully completed **Creating Agents with Amazon AgentCore Identity Functionality**!\n",
|
|
"\n",
|
|
"### What You Accomplished:\n",
|
|
"\n",
|
|
"✅ **Configured AgentCore Identity**: Set up OAuth2 credential providers for secure authentication \n",
|
|
"✅ **Google Calendar Integration**: Created tools for calendar event management and viewing \n",
|
|
"✅ **Enhanced Customer Support**: Extended your agent with scheduling and calendar capabilities \n",
|
|
"\n",
|
|
"### Key Learnings:\n",
|
|
"- **Identity Management**: Using AgentCore Identity for secure credential management\n",
|
|
"- **OAuth2 Flows**: Implementing user federation and token-based authentication\n",
|
|
"- **External API Integration**: Securely connecting to third-party services like Google Calendar\n",
|
|
"- **Tool Enhancement**: Adding identity-aware capabilities to existing agent tools\n",
|
|
"\n",
|
|
"## Next Steps\n",
|
|
"\n",
|
|
"Ready to enhance your agent? Continue with:\n",
|
|
"\n",
|
|
"- **Lab 4**: Leverage Gateway to securely connect tools and other resources\n",
|
|
"- **Lab 5**: Implement observability and guardrails for production monitoring\n",
|
|
"- **Lab 6**: Deploy to AgentCore Runtime for scalable production hosting\n",
|
|
"\n",
|
|
"## Resources\n",
|
|
"\n",
|
|
"- [AgentCore Identity Documentation](https://docs.aws.amazon.com/bedrock/latest/userguide/agentcore-identity.html)\n",
|
|
"- [Google Calendar API Documentation](https://developers.google.com/calendar/api)\n",
|
|
"- [Strands Agents Documentation](https://github.com/strands-agents/sdk-python)\n",
|
|
"- [Amazon Bedrock Models](https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html)\n",
|
|
"- [Official Customer Support Sample](https://github.com/awslabs/amazon-bedrock-agentcore-samples/tree/main/02-use-cases/customer-support-assistant)\n",
|
|
"\n",
|
|
"---\n",
|
|
"\n",
|
|
"**Excellent work! Your customer support agent now has secure identity management and calendar integration capabilities! 🚀**"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## (Optional): Create an Identity Provider with Cognito\n",
|
|
"\n",
|
|
"For additional identity management capabilities, you can also configure a Cognito-based identity provider. This section demonstrates how to create a custom OAuth2 provider using Amazon Cognito:\n"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"cognito_provider_name = \"customersupport-gateways-cognito\"\n",
|
|
"\n",
|
|
"try:\n",
|
|
" print(\"📥 Fetching Cognito configuration from SSM...\")\n",
|
|
" \n",
|
|
" client_id = get_ssm_parameter(\"/app/customersupport/agentcore/machine_client_id\")\n",
|
|
" print(f\"✅ Retrieved client ID: {client_id}\")\n",
|
|
"\n",
|
|
" client_secret = get_ssm_parameter(\"/app/customersupport/agentcore/cognito_secret\")\n",
|
|
" print(f\"✅ Retrieved client secret: {client_secret[:4]}***\")\n",
|
|
"\n",
|
|
" issuer = get_ssm_parameter(\"/app/customersupport/agentcore/cognito_discovery_url\")\n",
|
|
" auth_url = get_ssm_parameter(\"/app/customersupport/agentcore/cognito_auth_url\")\n",
|
|
" token_url = get_ssm_parameter(\"/app/customersupport/agentcore/cognito_token_url\")\n",
|
|
"\n",
|
|
" print(f\"✅ Issuer: {issuer}\")\n",
|
|
" print(f\"✅ Authorization Endpoint: {auth_url}\")\n",
|
|
" print(f\"✅ Token Endpoint: {token_url}\")\n",
|
|
"\n",
|
|
" print(\"⚙️ Creating OAuth2 credential provider...\")\n",
|
|
" \n",
|
|
" cognito_provider = identity_client.create_oauth2_credential_provider(\n",
|
|
" name=cognito_provider_name,\n",
|
|
" credentialProviderVendor=\"CustomOauth2\",\n",
|
|
" oauth2ProviderConfigInput={\n",
|
|
" \"customOauth2ProviderConfig\": {\n",
|
|
" \"clientId\": client_id,\n",
|
|
" \"clientSecret\": client_secret,\n",
|
|
" \"oauthDiscovery\": {\n",
|
|
" \"authorizationServerMetadata\": {\n",
|
|
" \"issuer\": issuer,\n",
|
|
" \"authorizationEndpoint\": auth_url,\n",
|
|
" \"tokenEndpoint\": token_url,\n",
|
|
" \"responseTypes\": [\"code\", \"token\"],\n",
|
|
" }\n",
|
|
" },\n",
|
|
" }\n",
|
|
" },\n",
|
|
" )\n",
|
|
"\n",
|
|
" provider_arn = cognito_provider[\"credentialProviderArn\"]\n",
|
|
" print(provider_arn)\n",
|
|
"except Exception as e:\n",
|
|
" print(f\"❌ Error creating Cognito credential provider: {str(e)}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"response = identity_client.list_oauth2_credential_providers(maxResults=20)\n",
|
|
"providers = response.get(\"credentialProviders\", [])\n",
|
|
"print(providers)"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "markdown",
|
|
"metadata": {},
|
|
"source": [
|
|
"## Cleanup"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {},
|
|
"outputs": [],
|
|
"source": [
|
|
"# try:\n",
|
|
"# print(f\"🗑️ Deleting Google OAuth2 credential provider: {google_provider_name}\")\n",
|
|
"# identity_client.delete_oauth2_credential_provider(name=google_provider_name)\n",
|
|
"# print(\"✅ Google OAuth2 credential provider deleted successfully\")\n",
|
|
"# except Exception as e:\n",
|
|
"# print(f\"❌ Error deleting credential provider: {str(e)}\")"
|
|
]
|
|
},
|
|
{
|
|
"cell_type": "code",
|
|
"execution_count": null,
|
|
"metadata": {
|
|
"tags": []
|
|
},
|
|
"outputs": [],
|
|
"source": [
|
|
"# try:\n",
|
|
"# print(f\"🗑️ Deleting Cognito OAuth2 credential provider: {cognito_provider_name}\")\n",
|
|
"# identity_client.delete_oauth2_credential_provider(name=cognito_provider_name)\n",
|
|
"# print(\"✅ Cognito credential provider deleted successfully\")\n",
|
|
"# except Exception as e:\n",
|
|
"# print(f\"❌ Error deleting credential provider: {str(e)}\")"
|
|
]
|
|
}
|
|
],
|
|
"metadata": {
|
|
"kernelspec": {
|
|
"display_name": "conda_python3",
|
|
"language": "python",
|
|
"name": "conda_python3"
|
|
},
|
|
"language_info": {
|
|
"codemirror_mode": {
|
|
"name": "ipython",
|
|
"version": 3
|
|
},
|
|
"file_extension": ".py",
|
|
"mimetype": "text/x-python",
|
|
"name": "python",
|
|
"nbconvert_exporter": "python",
|
|
"pygments_lexer": "ipython3",
|
|
"version": "3.10.18"
|
|
}
|
|
},
|
|
"nbformat": 4,
|
|
"nbformat_minor": 4
|
|
}
|