diff --git a/01-tutorials/07-AgentCore-E2E/Optional-lab-agentcore-observability.ipynb b/01-tutorials/07-AgentCore-E2E/Optional-lab-agentcore-observability.ipynb
index 3f25f4601..0a75a415f 100644
--- a/01-tutorials/07-AgentCore-E2E/Optional-lab-agentcore-observability.ipynb
+++ b/01-tutorials/07-AgentCore-E2E/Optional-lab-agentcore-observability.ipynb
@@ -250,7 +250,7 @@
"import argparse\n",
"from boto3.session import Session\n",
"from opentelemetry import baggage, context\n",
- "from scripts.utils import get_ssm_parameter\n",
+ "from lab_helpers.utils import get_ssm_parameter\n",
"\n",
"from strands import Agent\n",
"from strands.models import BedrockModel\n",
diff --git a/01-tutorials/07-AgentCore-E2E/Optional-lab-identity.ipynb b/01-tutorials/07-AgentCore-E2E/Optional-lab-identity.ipynb
index 61b91f64a..4010ee2d9 100644
--- a/01-tutorials/07-AgentCore-E2E/Optional-lab-identity.ipynb
+++ b/01-tutorials/07-AgentCore-E2E/Optional-lab-identity.ipynb
@@ -680,7 +680,7 @@
"try:\n",
" print(\"๐ฅ Fetching Cognito configuration from SSM...\")\n",
" \n",
- " client_id = get_ssm_parameter(\"/app/customersupport/agentcore/machine_client_id\")\n",
+ " client_id = get_ssm_parameter(\"/app/customersupport/agentcore/client_id\")\n",
" print(f\"โ
Retrieved client ID: {client_id}\")\n",
"\n",
" client_secret = get_ssm_parameter(\"/app/customersupport/agentcore/cognito_secret\")\n",
diff --git a/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb b/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb
index 73dec4156..9ed4d32d0 100644
--- a/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb
+++ b/01-tutorials/07-AgentCore-E2E/lab-03-agentcore-gateway.ipynb
@@ -108,18 +108,17 @@
"outputs": [],
"source": [
"# Import libraries\n",
- "from strands import Agent\n",
- "from strands.models import BedrockModel\n",
- "from strands.tools.mcp import MCPClient\n",
"import os\n",
"import sys\n",
"import boto3\n",
"import json\n",
- "from bedrock_agentcore.identity.auth import requires_access_token\n",
+ "\n",
+ "from strands import Agent\n",
+ "from strands.models import BedrockModel\n",
+ "from strands.tools.mcp import MCPClient\n",
"from mcp.client.streamable_http import streamablehttp_client\n",
- "import requests\n",
+ "from lab_helpers.utils import get_or_create_cognito_pool, put_ssm_parameter, get_ssm_parameter, load_api_spec\n",
"\n",
- "from scripts.utils import get_ssm_parameter, put_ssm_parameter, load_api_spec, get_cognito_client_secret\n",
"\n",
"sts_client = boto3.client('sts')\n",
"\n",
@@ -286,12 +285,11 @@
"source": [
"gateway_name = \"customersupport-gw\"\n",
"\n",
+ "cognito_config = get_or_create_cognito_pool(refresh_token=True)\n",
"auth_config = {\n",
" \"customJWTAuthorizer\": {\n",
- " \"allowedClients\": [\n",
- " get_ssm_parameter(\"/app/customersupport/agentcore/machine_client_id\")\n",
- " ],\n",
- " \"discoveryUrl\": get_ssm_parameter(\"/app/customersupport/agentcore/cognito_discovery_url\")\n",
+ " \"allowedClients\": [cognito_config[\"client_id\"]],\n",
+ " \"discoveryUrl\": cognito_config[\"discovery_url\"]\n",
" }\n",
"}\n",
"\n",
@@ -317,7 +315,13 @@
" \"gateway_arn\": create_response[\"gatewayArn\"],\n",
" }\n",
" put_ssm_parameter(\"/app/customersupport/agentcore/gateway_id\", gateway_id)\n",
- "\n",
+ " put_ssm_parameter(\"/app/customersupport/agentcore/gateway_name\", gateway_name)\n",
+ " put_ssm_parameter(\n",
+ " \"/app/customersupport/agentcore/gateway_arn\", create_response[\"gatewayArn\"]\n",
+ " )\n",
+ " put_ssm_parameter(\n",
+ " \"/app/customersupport/agentcore/gateway_url\", create_response[\"gatewayUrl\"]\n",
+ " )\n",
" print(f\"โ
Gateway created successfully with ID: {gateway_id}\")\n",
"\n",
"except Exception as e:\n",
@@ -354,14 +358,6 @@
"metadata": {},
"outputs": [],
"source": [
- "def load_api_spec(file_path: str) -> list:\n",
- " with open(file_path, \"r\") as f:\n",
- " data = json.load(f)\n",
- " \n",
- " if not isinstance(data, list):\n",
- " raise ValueError(\"Expected a list in the JSON file\")\n",
- " return data\n",
- "\n",
"try:\n",
" api_spec_file = \"./prerequisite/lambda/api_spec.json\"\n",
"\n",
@@ -406,40 +402,8 @@
"metadata": {},
"source": [
"## Step 7: Add our new MCP-based tools to our support agent\n",
- "Here we integrate our authentication token from Cognito into an MCPClient from Strands SDK to create an MCP Server object to integrate with our Strands Agent"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": null,
- "id": "6fec14df-e398-4321-9903-21a5f5f76c3a",
- "metadata": {},
- "outputs": [],
- "source": [
- "def get_token(client_id: str, client_secret: str, scope_string: str, url: str) -> dict:\n",
- " try:\n",
- " headers = {\"Content-Type\": \"application/x-www-form-urlencoded\"}\n",
- " data = {\n",
- " \"grant_type\": \"client_credentials\",\n",
- " \"client_id\": client_id,\n",
- " \"client_secret\": client_secret,\n",
- " \"scope\": scope_string,\n",
- "\n",
- " }\n",
- " response = requests.post(url, headers=headers, data=data)\n",
- " response.raise_for_status()\n",
- " return response.json()\n",
- "\n",
- " except requests.exceptions.RequestException as err:\n",
- " return {\"error\": str(err)}"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bff0a6b8-fdd3-4536-8012-6d0ab34f568f",
- "metadata": {},
- "source": [
- "## Step 7.1. Set up a secure MCP client object"
+ "Here we integrate our authentication token from Cognito into an MCPClient from Strands SDK to create an MCP Server object to integrate with our Strands Agent\n",
+ "### Step 7.1. Set up a secure MCP client object"
]
},
{
@@ -449,19 +413,12 @@
"metadata": {},
"outputs": [],
"source": [
- "gateway_access_token = get_token(\n",
- " get_ssm_parameter(\"/app/customersupport/agentcore/machine_client_id\"),\n",
- " get_cognito_client_secret(),\n",
- " get_ssm_parameter(\"/app/customersupport/agentcore/cognito_auth_scope\"),\n",
- " get_ssm_parameter(\"/app/customersupport/agentcore/cognito_token_url\"))\n",
- "\n",
"print(f\"Gateway Endpoint - MCP URL: {gateway['gateway_url']}\")\n",
- "\n",
"# Set up MCP client\n",
"mcp_client = MCPClient(\n",
" lambda: streamablehttp_client(\n",
" gateway['gateway_url'],\n",
- " headers={\"Authorization\": f\"Bearer {gateway_access_token['access_token']}\"},\n",
+ " headers={\"Authorization\": f\"Bearer {cognito_config['bearer_token']}\"},\n",
" )\n",
")"
]
@@ -501,28 +458,29 @@
" temperature=0.3, # Balanced between creativity and consistency\n",
" region_name=REGION\n",
")\n",
- "\n",
- "try:\n",
- " mcp_client.start()\n",
- "except Exception as e:\n",
- " print(f\"Error initializing agent: {str(e)}\")\n",
- "\n",
- "tools = (\n",
- " [\n",
- " get_product_info,\n",
- " get_return_policy,\n",
- " get_technical_support\n",
- " ]\n",
- " + mcp_client.list_tools_sync()\n",
- " )\n",
- "\n",
- "# Create the customer support agent\n",
- "agent = Agent(\n",
- " model=model,\n",
- " tools=tools,\n",
- " hooks=[memory_hooks],\n",
- " system_prompt=SYSTEM_PROMPT\n",
- ")\n",
+ "def create_agent(prompt):\n",
+ " try:\n",
+ " with mcp_client:\n",
+ " tools = (\n",
+ " [\n",
+ " get_product_info,\n",
+ " get_return_policy,\n",
+ " get_technical_support\n",
+ " ]\n",
+ " + mcp_client.list_tools_sync()\n",
+ " )\n",
+ " \n",
+ " # Create the customer support agent\n",
+ " agent = Agent(\n",
+ " model=model,\n",
+ " tools=tools,\n",
+ " hooks=[memory_hooks],\n",
+ " system_prompt=SYSTEM_PROMPT\n",
+ " )\n",
+ " response = agent(prompt)\n",
+ " return response\n",
+ " except Exception as e:\n",
+ " raise e\n",
"\n",
"print(\"โ
Customer support agent created successfully!\")"
]
@@ -557,18 +515,18 @@
"]\n",
"\n",
"# Function to test the agent\n",
- "def test_agent_responses(agent, prompts):\n",
+ "def test_agent_responses(prompts):\n",
" for i, prompt in enumerate(prompts, 1):\n",
" print(f\"\\nTest Case {i}: {prompt}\")\n",
" print(\"-\" * 50)\n",
" try:\n",
- " response = agent(prompt)\n",
+ " response = create_agent(prompt)\n",
" except Exception as e:\n",
" print(f\"Error: {str(e)}\")\n",
" print(\"-\" * 50)\n",
"\n",
"# Run the tests\n",
- "test_agent_responses(agent, test_prompts)\n",
+ "test_agent_responses(test_prompts)\n",
"\n",
"print(\"\\\\nโ
Basic testing completed!\")\n"
]
diff --git a/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb b/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb
index 15fa7ca56..e3580ddcb 100644
--- a/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb
+++ b/01-tutorials/07-AgentCore-E2E/lab-04-agentcore-runtime.ipynb
@@ -65,6 +65,7 @@
"- Docker, Finch or Podman installed and running\n",
"- Amazon Bedrock AgentCore SDK\n",
"- Strands Agents framework\n",
+ "- **Lab 3 Completion:** This lab builds on Lab 3 (AgentCore Gateway). You MUST run [lab-03-agentcore-gateway](lab-03-agentcore-gateway.ipynb) to provision the gateway before running this lab.\n",
"\n",
"**Note**: You MUST enable [CloudWatch Transaction Search](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Enable-TransactionSearch.html) to be able to see AgentCore Observability traces in CloudWatch.\n"
]
@@ -85,9 +86,9 @@
"outputs": [],
"source": [
"# Import required libraries\n",
- "import os\n",
- "import json\n",
- "import boto3\n",
+ "import os, json, boto3, requests\n",
+ "from lab_helpers.utils import get_ssm_parameter, get_cognito_client_secret\n",
+ "from strands.tools.mcp import MCPClient\n",
"from strands import Agent\n",
"from strands.models import BedrockModel\n",
"from lab_helpers.lab2_memory import create_or_get_memory_resource\n",
@@ -106,12 +107,19 @@
"\n",
"Let's first define the necessary AgentCore Runtime components via Python SDK within our previous local agent implementation.\n",
"\n",
- "Observe the `#### AGENTCORE RUNTIME - LINE i ####` comments below to see where is the relevant deployment code added. You'll find 4 such lines that prepare the runtime-ready agent:\n",
+ "Observe the #### AGENTCORE RUNTIME - LINE 1 #### comments below to see where is the relevant deployment code added. You'll find 4 such lines that prepare the runtime-ready agent:\n",
"\n",
"1. Import the Runtime App with `from bedrock_agentcore.runtime import BedrockAgentCoreApp`\n",
"2. Initialize the App with `app = BedrockAgentCoreApp()`\n",
"3. Decorate our invocation function with `@app.entrypoint`\n",
- "4. Let AgentCore Runtime control the execution with `app.run()`\n"
+ "4. Let AgentCore Runtime control the execution with `app.run()`\n",
+ "\n",
+ "##### Key Implementation Details:\n",
+ "\n",
+ "The runtime-ready agent uses an entrypoint function that extracts user prompts from the payload and JWT tokens from request headers via \n",
+ "context.request_headers.get('Authorization', ''). The authorization token is then propagated directly to the AgentCore Gateway by passing it in the \n",
+ "MCP client headers: headers={\"Authorization\": auth_header}. The implementation includes error handling for missing authentication and returns plain \n",
+ "text responses from synchronous agent invocation while preserving all memory and tool functionality from previous labs."
]
},
{
@@ -126,8 +134,12 @@
" BedrockAgentCoreApp,\n",
") #### AGENTCORE RUNTIME - LINE 1 ####\n",
"from strands import Agent\n",
+ "from strands.tools.mcp import MCPClient\n",
+ "from mcp.client.streamable_http import streamablehttp_client\n",
+ "import requests\n",
+ "import boto3\n",
"from strands.models import BedrockModel\n",
- "from scripts.utils import get_ssm_parameter\n",
+ "from lab_helpers.utils import get_ssm_parameter\n",
"from lab_helpers.lab1_strands_agent import (\n",
" get_return_policy,\n",
" get_product_info,\n",
@@ -143,6 +155,12 @@
" SESSION_ID,\n",
")\n",
"\n",
+ "# Initialize boto3 client\n",
+ "sts_client = boto3.client('sts')\n",
+ "\n",
+ "# Get AWS account details\n",
+ "REGION = boto3.session.Session().region_name\n",
+ "\n",
"# Lab1 import: Create the Bedrock model\n",
"model = BedrockModel(model_id=MODEL_ID)\n",
"\n",
@@ -152,27 +170,69 @@
" memory_id, memory_client, ACTOR_ID, SESSION_ID\n",
")\n",
"\n",
- "# Create the agent with all customer support tools\n",
- "agent = Agent(\n",
- " model=model,\n",
- " tools=[get_return_policy, get_product_info, get_technical_support],\n",
- " system_prompt=SYSTEM_PROMPT,\n",
- " hooks=[memory_hooks],\n",
- ")\n",
- "\n",
"# Initialize the AgentCore Runtime App\n",
"app = BedrockAgentCoreApp() #### AGENTCORE RUNTIME - LINE 2 ####\n",
"\n",
- "\n",
"@app.entrypoint #### AGENTCORE RUNTIME - LINE 3 ####\n",
- "def invoke(payload):\n",
+ "async def invoke(payload, context=None):\n",
" \"\"\"AgentCore Runtime entrypoint function\"\"\"\n",
" user_input = payload.get(\"prompt\", \"\")\n",
"\n",
- " # Invoke the agent\n",
- " response = agent(user_input)\n",
- " return response.message[\"content\"][0][\"text\"]\n",
- "\n",
+ " # Access request headers - handle None case\n",
+ " request_headers = context.request_headers or {}\n",
+ "\n",
+ " # Get Client JWT token\n",
+ " auth_header = request_headers.get('Authorization', '')\n",
+ "\n",
+ " print(f\"Authorization header: {auth_header}\")\n",
+ " # Get Gateway ID\n",
+ " existing_gateway_id = get_ssm_parameter(\"/app/customersupport/agentcore/gateway_id\")\n",
+ " \n",
+ " # Initialize Bedrock AgentCore Control client\n",
+ " gateway_client = boto3.client(\n",
+ " \"bedrock-agentcore-control\",\n",
+ " region_name=REGION,\n",
+ " )\n",
+ " # Get existing gateway details\n",
+ " gateway_response = gateway_client.get_gateway(gatewayIdentifier=existing_gateway_id)\n",
+ "\n",
+ " # Get gateway url\n",
+ " gateway_url = gateway_response['gatewayUrl']\n",
+ "\n",
+ " # Create MCP client and agent within context manager if JWT token available\n",
+ " if gateway_url and auth_header:\n",
+ " try:\n",
+ " mcp_client = MCPClient(lambda: streamablehttp_client(\n",
+ " url=gateway_url,\n",
+ " headers={\"Authorization\": auth_header} \n",
+ " ))\n",
+ " \n",
+ " with mcp_client:\n",
+ " #tools = mcp_client.list_tools_sync()\n",
+ " tools = (\n",
+ " [\n",
+ " get_product_info,\n",
+ " get_return_policy,\n",
+ " get_technical_support\n",
+ " ]\n",
+ " + mcp_client.list_tools_sync()\n",
+ " )\n",
+ " \n",
+ " # Create the agent with all customer support tools\n",
+ " agent = Agent(\n",
+ " model=model,\n",
+ " tools=tools,\n",
+ " system_prompt=SYSTEM_PROMPT,\n",
+ " hooks=[memory_hooks],\n",
+ " )\n",
+ " # Invoke the agent\n",
+ " response = agent(user_input)\n",
+ " return response.message[\"content\"][0][\"text\"]\n",
+ " except Exception as e:\n",
+ " print(f\"MCP client error: {str(e)}\")\n",
+ " return f\"Error: {str(e)}\"\n",
+ " else:\n",
+ " return \"Error: Missing gateway URL or authorization header\"\n",
"\n",
"if __name__ == \"__main__\":\n",
" app.run() #### AGENTCORE RUNTIME - LINE 4 ####"
@@ -219,17 +279,27 @@
{
"cell_type": "code",
"execution_count": null,
- "id": "4581baa2-9edc-425d-becf-09968565081a",
+ "id": "c68f95c9-e97c-4ebd-8009-b2eab09ba614",
"metadata": {},
"outputs": [],
"source": [
- "from lab_helpers.utils import setup_cognito_user_pool, reauthenticate_user\n",
+ "from lab_helpers.utils import get_or_create_cognito_pool, get_ssm_parameter\n",
+ "access_token = get_or_create_cognito_pool(refresh_token=True)\n",
+ "print(f\"Access token: {access_token['bearer_token']}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d1d09fb7",
+ "metadata": {},
+ "source": [
+ "#### AgentCore Runtime Configuration Summary:\n",
"\n",
- "print(\"Setting up Amazon Cognito user pool...\")\n",
- "cognito_config = (\n",
- " setup_cognito_user_pool()\n",
- ") # You'll get your bearer token from this output cell.\n",
- "print(\"Cognito setup completed โ\")"
+ "Below code configures the AgentCore Runtime deployment using the starter toolkit. It creates an execution role for the runtime, then configures the \n",
+ "deployment with the agent entrypoint file (lab_helpers/lab4_runtime.py), enables automatic ECR repository creation, and sets up JWT-based authentication using \n",
+ "Cognito. The configuration specifies allowed client IDs and discovery URLs retrieved from SSM parameters, establishing secure access control for the \n",
+ "production agent deployment. This step automatically generates the Dockerfile and .bedrock_agentcore.yaml configuration files needed for \n",
+ "containerized deployment."
]
},
{
@@ -260,10 +330,10 @@
" agent_name=\"customer_support_agent\",\n",
" authorizer_configuration={\n",
" \"customJWTAuthorizer\": {\n",
- " \"allowedClients\": [cognito_config.get(\"client_id\")],\n",
- " \"discoveryUrl\": cognito_config.get(\"discovery_url\"),\n",
+ " \"allowedClients\": [get_ssm_parameter(\"/app/customersupport/agentcore/client_id\")],\n",
+ " \"discoveryUrl\": get_ssm_parameter(\"/app/customersupport/agentcore/cognito_discovery_url\"),\n",
" }\n",
- " },\n",
+ " }\n",
")\n",
"\n",
"print(\"Configuration completed:\", response)"
@@ -349,7 +419,50 @@
"\n",
"#### Using the AgentCore Starter Toolkit\n",
"\n",
- "We can validate that the agent works using the AgentCore Starter Toolkit for invocation. The starter toolkit can automatically create a session id for us to query our agent. Alternatively, you can also pass the session id as a parameter during invocation. For demonstration purpose, we will create our own session id."
+ "We can validate that the agent works using the AgentCore Starter Toolkit for invocation. The starter toolkit can automatically create a session id for us to query our agent. Alternatively, you can also pass the session id as a parameter during invocation. For demonstration purpose, we will create our own session id.\n",
+ "\n",
+ "#### Runtime Header Configuration\n",
+ "\n",
+ "Below code configures custom header allowlists for the deployed AgentCore Runtime. It extracts the runtime ID from the agent ARN, retrieves the \n",
+ "current runtime configuration to preserve existing settings, then updates the runtime with a request header allowlist that includes the Authorization\n",
+ "header (required for OAuth token propagation) and custom headers. This ensures JWT tokens and other necessary headers are properly forwarded from \n",
+ "client requests to the agent runtime code."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "cc1fa718",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Initialize the AgentCore Control client\n",
+ "client = boto3.client('bedrock-agentcore-control')\n",
+ "\n",
+ "# Extract runtime ID from the ARN (format: arn:aws:bedrock-agentcore:region:account:runtime/runtime-id)\n",
+ "runtime_id = launch_result.agent_arn.split(':')[-1].split('/')[-1]\n",
+ "\n",
+ "print(f\"Runtime ID: {runtime_id}\")\n",
+ "\n",
+ "# Get current runtime configuration to preserve existing settings\n",
+ "current_config = client.get_agent_runtime(agentRuntimeId=runtime_id)\n",
+ "\n",
+ "# Update runtime with custom header configuration while preserving existing settings\n",
+ "client.update_agent_runtime(\n",
+ " agentRuntimeId=runtime_id,\n",
+ " # Preserve existing configuration\n",
+ " agentRuntimeArtifact=current_config['agentRuntimeArtifact'],\n",
+ " roleArn=current_config['roleArn'],\n",
+ " networkConfiguration=current_config['networkConfiguration'],\n",
+ " authorizerConfiguration=current_config.get('authorizerConfiguration'),\n",
+ " # Add custom header allowlist for Authorization and custom headers\n",
+ " requestHeaderConfiguration={\n",
+ " 'requestHeaderAllowlist': [\n",
+ " 'Authorization', # Required for OAuth propogation\n",
+ " 'X-Amzn-Bedrock-AgentCore-Runtime-Custom-H1' # Custom header\n",
+ " ]\n",
+ " }\n",
+ ")"
]
},
{
@@ -365,19 +478,16 @@
"session_id = uuid.uuid4()\n",
"\n",
"# Test different customer support scenarios\n",
- "user_query = \"My Iphone is not connecting with the Bluetooth. What should I do?\"\n",
- "\n",
- "bearer_token = reauthenticate_user(\n",
- " cognito_config.get(\"client_id\"), \n",
- " cognito_config.get(\"client_secret\")\n",
- ")\n",
+ "user_query = \"List all of your tools\"\n",
"\n",
"response = agentcore_runtime.invoke(\n",
" {\"prompt\": user_query}, \n",
- " bearer_token=bearer_token,\n",
+ " #bearer_token=f\"Bearer {access_token['bearer_token']}\",\n",
+ " bearer_token=access_token['bearer_token'],\n",
" session_id=str(session_id)\n",
")\n",
- "response"
+ "\n",
+ "print(response['response'])"
]
},
{
@@ -397,13 +507,13 @@
"metadata": {},
"outputs": [],
"source": [
- "user_query = \"I've turned my Bluetooth on and off but it still does not work\"\n",
+ "user_query = \"Tell me detailed information about the technical documentation on installing a new CPU\"\n",
"response = agentcore_runtime.invoke(\n",
" {\"prompt\": user_query}, \n",
- " bearer_token=bearer_token,\n",
+ " bearer_token=access_token['bearer_token'],\n",
" session_id=str(session_id)\n",
")\n",
- "response"
+ "print(response['response'])"
]
},
{
@@ -425,13 +535,13 @@
"# Creating a new session ID for demonstrating new customer\n",
"session_id2 = uuid.uuid4()\n",
"\n",
- "user_query = \"Still not working. What is going on?\"\n",
+ "user_query = \"I have a Gaming Console Pro device , I want to check my warranty status, warranty serial number is MNO33333333.\"\n",
"response = agentcore_runtime.invoke(\n",
" {\"prompt\": user_query}, \n",
- " bearer_token=bearer_token,\n",
+ " bearer_token=access_token['bearer_token'],\n",
" session_id=str(session_id2)\n",
")\n",
- "response"
+ "print(response['response'])"
]
},
{
diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab2_memory.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab2_memory.py
index d0a09b8a7..872e9c62e 100644
--- a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab2_memory.py
+++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab2_memory.py
@@ -23,7 +23,7 @@
REGION = boto_session.region_name
logger = logging.getLogger(__name__)
-from scripts.utils import get_ssm_parameter, put_ssm_parameter
+from lab_helpers.utils import get_ssm_parameter, put_ssm_parameter
ACTOR_ID = "customer_001"
SESSION_ID = str(uuid.uuid4())
@@ -194,4 +194,4 @@ def get_memory_hooks():
session_id=SESSION_ID,
)
- return memory_hooks
\ No newline at end of file
+ return memory_hooks
diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py
index 07a1002c3..27eaa8031 100644
--- a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py
+++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab4_runtime.py
@@ -1,53 +1,115 @@
+import logging
+
+import boto3
+import requests
from bedrock_agentcore.runtime import (
BedrockAgentCoreApp,
-) #### AGENTCORE RUNTIME - LINE 1 ####
-from strands import Agent
-from strands.models import BedrockModel
-from scripts.utils import get_ssm_parameter
+) # ### AGENTCORE RUNTIME - LINE 1 ####
from lab_helpers.lab1_strands_agent import (
- get_return_policy,
+ MODEL_ID,
+ SYSTEM_PROMPT,
get_product_info,
+ get_return_policy,
get_technical_support,
- SYSTEM_PROMPT,
- MODEL_ID,
)
-
from lab_helpers.lab2_memory import (
- CustomerSupportMemoryHooks,
- memory_client,
ACTOR_ID,
SESSION_ID,
+ CustomerSupportMemoryHooks,
+ memory_client,
)
+from lab_helpers.utils import get_or_create_cognito_pool, get_ssm_parameter
+from mcp.client.streamable_http import streamablehttp_client
+from strands import Agent
+from strands.models import BedrockModel
+from strands.tools.mcp import MCPClient
-# Lab1 import: Create the Bedrock model
-model = BedrockModel(model_id=MODEL_ID)
-
-# Lab2 import : Initialize memory via hooks
-memory_id = get_ssm_parameter("/app/customersupport/agentcore/memory_id")
-memory_hooks = CustomerSupportMemoryHooks(
- memory_id, memory_client, ACTOR_ID, SESSION_ID
+# Add a handler to see the logs
+logging.basicConfig(
+ format="%(levelname)s | %(name)s | %(message)s", handlers=[logging.StreamHandler()]
)
+logger = logging.getLogger("agentcore-app")
+logger.setLevel(logging.DEBUG)
-# Create the agent with all customer support tools
-agent = Agent(
- model=model,
- tools=[get_return_policy, get_product_info, get_technical_support],
- system_prompt=SYSTEM_PROMPT,
- hooks=[memory_hooks],
-)
+class CustomerSupportAgent:
+ def __init__(self):
+ # Lab1 import: Create the Bedrock model
+ self.model = BedrockModel(model_id=MODEL_ID)
+ self.cognito_config = get_or_create_cognito_pool()
+ self.session_id = None
+ self.memory_hook = None
+
+ # Create the agent with all customer support tools (local + MCP)
+ async def create_client(self, gateway_url):
+ # Set up MCP client
+ if self.cognito_config:
+ try:
+ # Lab3 import: Set up MCP client for gateway integration
+ self.gateway_client = MCPClient(
+ lambda: streamablehttp_client(
+ gateway_url,
+ headers={
+ "Authorization": f"Bearer {self.cognito_config['access_token']}"
+ },
+ )
+ )
+ except Exception as e:
+ logger.error(f"Could not initialize MCP client: {e}")
+ else:
+ logger.error("Failed to initialize the agent without a Bearer token")
+
+ def invoke(self, user_input: str):
+ """AgentCore Runtime entrypoint function"""
+ try:
+ with self.gateway_client:
+ agent = Agent(
+ model=self.model,
+ tools=[get_return_policy, get_product_info, get_technical_support]
+ + self.gateway_client.list_tools_sync(),
+ system_prompt=SYSTEM_PROMPT,
+ hooks=[self.memory_hook],
+ )
+ response = agent(user_input)
+ return response
+ except Exception as e:
+ return f"Error while invoking Agent {e}"
+
+ async def stream(self, user_query: str):
+ try:
+ async for event in self.agent.stream_async(user_query):
+ if "data" in event:
+ # Only stream text chunks to the client
+ yield event["data"]
+ except Exception as e:
+ yield f"We are unable to process your request at the moment. Error: {e}"
+
+
+# Lab2 import : Initialize memory via hooks
+memory_id = get_ssm_parameter("/app/customersupport/agentcore/memory_id")
+# Lab 3: Get gateway URL from SSM
+gateway_url = get_ssm_parameter("/app/customersupport/agentcore/gateway_url")
+# Initialize the customer support agent
+customer_support = CustomerSupportAgent()
# Initialize the AgentCore Runtime App
app = BedrockAgentCoreApp() #### AGENTCORE RUNTIME - LINE 2 ####
@app.entrypoint #### AGENTCORE RUNTIME - LINE 3 ####
-def invoke(payload):
+async def invoke(payload, context=None):
"""AgentCore Runtime entrypoint function"""
- user_input = payload.get("prompt", "")
-
+ # if not customer_support.agent:
+ logger.info("initializing agent")
+ memory_hook = CustomerSupportMemoryHooks(
+ memory_id, memory_client, ACTOR_ID, context.session_id or SESSION_ID
+ )
+ customer_support.memory_hook = memory_hook
+ # Initialize MCP client
+ await customer_support.create_client(gateway_url)
# Invoke the agent
- response = agent(user_input)
- return response.message["content"][0]["text"]
+ user_input = payload.get("prompt", "")
+ response = customer_support.invoke(user_input)
+ return response
if __name__ == "__main__":
diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab5_frontend/chat_utils.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab5_frontend/chat_utils.py
index 80e0e9962..128a147bf 100644
--- a/01-tutorials/07-AgentCore-E2E/lab_helpers/lab5_frontend/chat_utils.py
+++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/lab5_frontend/chat_utils.py
@@ -1,9 +1,10 @@
+import json
+import os
import re
+from typing import Any, Dict
+
import boto3
-import json
import yaml
-import os
-from typing import Dict, Any
def get_ssm_parameter(name: str, with_decryption: bool = True) -> str:
@@ -61,8 +62,8 @@ def get_aws_account_id() -> str:
def get_cognito_client_secret() -> str:
client = boto3.client("cognito-idp")
response = client.describe_user_pool_client(
- UserPoolId=get_ssm_parameter("/app/customersupport/agentcore/userpool_id"),
- ClientId=get_ssm_parameter("/app/customersupport/agentcore/machine_client_id"),
+ UserPoolId=get_ssm_parameter("/app/customersupport/agentcore/pool_id"),
+ ClientId=get_ssm_parameter("/app/customersupport/agentcore/client_id"),
)
return response["UserPoolClient"]["ClientSecret"]
@@ -136,10 +137,10 @@ def create_safe_markdown_text(text, message_placeholder):
"""Create safe markdown text with proper encoding and newline handling"""
# First encode/decode for safety
safe_text = text.encode("utf-16", "surrogatepass").decode("utf-16")
-
+
# Convert newlines to HTML breaks for proper rendering
# This handles both actual newlines and any remaining escaped ones
- safe_text = safe_text.replace('\n', '
')
- safe_text = safe_text.replace('\\n', '
')
-
- message_placeholder.markdown(safe_text, unsafe_allow_html=True)
\ No newline at end of file
+ safe_text = safe_text.replace("\n", "
")
+ safe_text = safe_text.replace("\\n", "
")
+
+ message_placeholder.markdown(safe_text, unsafe_allow_html=True)
diff --git a/01-tutorials/07-AgentCore-E2E/lab_helpers/utils.py b/01-tutorials/07-AgentCore-E2E/lab_helpers/utils.py
index 8bbe9e805..023dc1e12 100644
--- a/01-tutorials/07-AgentCore-E2E/lab_helpers/utils.py
+++ b/01-tutorials/07-AgentCore-E2E/lab_helpers/utils.py
@@ -76,8 +76,8 @@ def get_aws_account_id() -> str:
def get_cognito_client_secret() -> str:
client = boto3.client("cognito-idp")
response = client.describe_user_pool_client(
- UserPoolId=get_ssm_parameter("/app/customersupport/agentcore/userpool_id"),
- ClientId=get_ssm_parameter("/app/customersupport/agentcore/machine_client_id"),
+ UserPoolId=get_ssm_parameter("/app/customersupport/agentcore/pool_id"),
+ ClientId=get_ssm_parameter("/app/customersupport/agentcore/client_id"),
)
return response["UserPoolClient"]["ClientSecret"]
@@ -187,11 +187,23 @@ def delete_customer_support_secret():
return False
-def setup_cognito_user_pool():
+def get_or_create_cognito_pool(refresh_token=False):
boto_session = Session()
region = boto_session.region_name
# Initialize Cognito client
cognito_client = boto3.client("cognito-idp", region_name=region)
+ try:
+ # check for existing cognito pool
+ cognito_config_str = get_customer_support_secret()
+ cognito_config = json.loads(cognito_config_str)
+ if refresh_token:
+ cognito_config["bearer_token"] = reauthenticate_user(
+ cognito_config["client_id"], cognito_config["client_secret"]
+ )
+ return cognito_config
+ except:
+ print("No existing cognito config found. Creating a new one..")
+
try:
# Create User Pool
user_pool_response = cognito_client.create_user_pool(
@@ -229,10 +241,8 @@ def setup_cognito_user_pool():
Permanent=True,
)
- app_client_id = client_id
- key = client_secret
- message = bytes(username + app_client_id, "utf-8")
- key = bytes(key, "utf-8")
+ message = bytes(username + client_id, "utf-8")
+ key = bytes(client_secret, "utf-8")
secret_hash = base64.b64encode(
hmac.new(key, message, digestmod=hashlib.sha256).digest()
).decode()
@@ -242,20 +252,18 @@ def setup_cognito_user_pool():
ClientId=client_id,
AuthFlow="USER_PASSWORD_AUTH",
AuthParameters={
- "USERNAME": "testuser",
+ "USERNAME": username,
"PASSWORD": "MyPassword123!",
"SECRET_HASH": secret_hash,
},
)
bearer_token = auth_response["AuthenticationResult"]["AccessToken"]
+ discovery_url = f"https://cognito-idp.{region}.amazonaws.com/{pool_id}/.well-known/openid-configuration"
# Output the required values
print(f"Pool id: {pool_id}")
- print(
- f"Discovery URL: https://cognito-idp.{region}.amazonaws.com/{pool_id}/.well-known/openid-configuration"
- )
+ print(f"Discovery URL: {discovery_url}")
print(f"Client ID: {client_id}")
print(f"Bearer Token: {bearer_token}")
-
# Return values if needed for further processing
cognito_config = {
"pool_id": pool_id,
@@ -263,8 +271,14 @@ def setup_cognito_user_pool():
"client_secret": client_secret,
"secret_hash": secret_hash,
"bearer_token": bearer_token,
- "discovery_url": f"https://cognito-idp.{region}.amazonaws.com/{pool_id}/.well-known/openid-configuration",
+ "discovery_url": discovery_url,
}
+ put_ssm_parameter("/app/customersupport/agentcore/client_id", client_id)
+ put_ssm_parameter("/app/customersupport/agentcore/pool_id", pool_id)
+ put_ssm_parameter(
+ "/app/customersupport/agentcore/cognito_discovery_url", discovery_url
+ )
+ put_ssm_parameter("/app/customersupport/agentcore/client_secret", client_secret)
save_customer_support_secret(json.dumps(cognito_config))
@@ -482,6 +496,17 @@ def create_agentcore_runtime_execution_role():
"Action": ["ssm:GetParameter"],
"Resource": [f"arn:aws:ssm:{region}:{account_id}:parameter/*"],
},
+ {
+ "Sid": "GatewayAccess",
+ "Effect": "Allow",
+ "Action": [
+ "bedrock-agentcore:GetGateway",
+ "bedrock-agentcore:InvokeGateway",
+ ],
+ "Resource": [
+ f"arn:aws:bedrock-agentcore:{region}:{account_id}:gateway/*"
+ ],
+ },
],
}
@@ -579,64 +604,64 @@ def delete_agentcore_runtime_execution_role():
except Exception as e:
print(f"โ Error during cleanup: {str(e)}")
+
def agentcore_memory_cleanup():
-
- control_client = boto3.client('bedrock-agentcore-control',region_name=REGION)
-
+
+ control_client = boto3.client("bedrock-agentcore-control", region_name=REGION)
+
"""List all memories and their associated strategies"""
next_token = None
-
+
while True:
# Build request parameters
params = {}
if next_token:
- params['nextToken'] = next_token
-
+ params["nextToken"] = next_token
+
# List memories
try:
response = control_client.list_memories(**params)
-
+
# Process each memory
- for memory in response.get('memories', []):
- memory_id = memory.get('id')
+ for memory in response.get("memories", []):
+ memory_id = memory.get("id")
print(f"\nMemory ID: {memory_id}")
print(f"Status: {memory.get('status')}")
- response = control_client.delete_memory(
- memoryId=memory_id
- )
+ response = control_client.delete_memory(memoryId=memory_id)
response = control_client.list_memories(**params)
print(f"โ
Successfully deleted memory: {memory_id}")
-
- response = control_client.list_memories(**params)
+
+ response = control_client.list_memories(**params)
# Process each memory status
- for memory in response.get('memories', []):
- memory_id = memory.get('id')
+ for memory in response.get("memories", []):
+ memory_id = memory.get("id")
print(f"\nMemory ID: {memory_id}")
print(f"Status: {memory.get('status')}")
-
+
except Exception as e:
print(f"โ ๏ธ Error getting memory details: {e}")
-
+
# Check for more results
- next_token = response.get('nextToken')
+ next_token = response.get("nextToken")
if not next_token:
break
-
+
+
def gateway_target_cleanup():
-
+
gateway_client = boto3.client(
"bedrock-agentcore-control",
region_name=REGION,
)
- response = gateway_client.list_gateways()
- gateway_id = (response['items'][0]['gatewayId'])
+ response = gateway_client.list_gateways()
+ gateway_id = response["items"][0]["gatewayId"]
print(f"๐๏ธ Deleting all targets for gateway: {gateway_id}")
-
+
# List and delete all targets
list_response = gateway_client.list_gateway_targets(
gatewayIdentifier=gateway_id, maxResults=100
)
-
+
for item in list_response["items"]:
target_id = item["targetId"]
print(f" Deleting target: {target_id}")
@@ -644,49 +669,51 @@ def gateway_target_cleanup():
gatewayIdentifier=gateway_id, targetId=target_id
)
print(f" โ
Target {target_id} deleted")
-
+
# Delete the gateway
print(f"๐๏ธ Deleting gateway: {gateway_id}")
gateway_client.delete_gateway(gatewayIdentifier=gateway_id)
print(f"โ
Gateway {gateway_id} deleted successfully")
+
def runtime_resource_cleanup():
try:
# Initialize AWS clients
- agentcore_control_client = boto3.client("bedrock-agentcore-control", region_name=REGION)
+ agentcore_control_client = boto3.client(
+ "bedrock-agentcore-control", region_name=REGION
+ )
ecr_client = boto3.client("ecr", region_name=REGION)
-
+
# Delete the AgentCore Runtime
# print(" ๐๏ธ Deleting AgentCore Runtime...")
runtimes = agentcore_control_client.list_agent_runtimes()
- for runtime in runtimes['agentRuntimes']:
+ for runtime in runtimes["agentRuntimes"]:
response = agentcore_control_client.delete_agent_runtime(
- agentRuntimeId=runtime['agentRuntimeId']
+ agentRuntimeId=runtime["agentRuntimeId"]
)
print(f" โ
Agent runtime deleted: {response['status']}")
-
+
# Delete the ECR repository
print(" ๐๏ธ Deleting ECR repository...")
repositories = ecr_client.describe_repositories()
- for repo in repositories['repositories']:
- if 'bedrock-agentcore-customer_support_agent' in repo['repositoryName']:
+ for repo in repositories["repositories"]:
+ if "bedrock-agentcore-customer_support_agent" in repo["repositoryName"]:
ecr_client.delete_repository(
- repositoryName=repo['repositoryName'],
- force=True
+ repositoryName=repo["repositoryName"], force=True
)
print(f" โ
ECR repository deleted: {repo['repositoryName']}")
-
-
+
except Exception as e:
print(f" โ ๏ธ Error during runtime cleanup: {e}")
+
def delete_observability_resources():
# Configuration
log_group_name = "agents/customer-support-assistant-logs"
log_stream_name = "default"
-
+
logs_client = boto3.client("logs", region_name=REGION)
-
+
# Delete log stream first (must be done before deleting log group)
try:
print(f" ๐๏ธ Deleting log stream '{log_stream_name}'...")
@@ -699,7 +726,7 @@ def delete_observability_resources():
print(f" โน๏ธ Log stream '{log_stream_name}' doesn't exist")
else:
print(f" โ ๏ธ Error deleting log stream: {e}")
-
+
# Delete log group
try:
print(f" ๐๏ธ Deleting log group '{log_group_name}'...")
@@ -711,6 +738,7 @@ def delete_observability_resources():
else:
print(f" โ ๏ธ Error deleting log group: {e}")
+
def local_file_cleanup():
# List of files to clean up
files_to_delete = [
@@ -720,7 +748,7 @@ def local_file_cleanup():
"customer_support_agent.py",
"agent_runtime.py",
]
-
+
deleted_files = []
missing_files = []
@@ -734,8 +762,10 @@ def local_file_cleanup():
print(f" โ ๏ธ Error deleting {file}: {e}")
else:
missing_files.append(file)
-
+
if deleted_files:
print(f"\n๐ Successfully deleted {len(deleted_files)} files")
if missing_files:
- print(f"โน๏ธ {len(missing_files)} files were already missing: {', '.join(missing_files)}")
\ No newline at end of file
+ print(
+ f"โน๏ธ {len(missing_files)} files were already missing: {', '.join(missing_files)}"
+ )
diff --git a/01-tutorials/07-AgentCore-E2E/prerequisite/cognito.yaml b/01-tutorials/07-AgentCore-E2E/prerequisite/cognito.yaml
index ab203a8d3..efa26d536 100644
--- a/01-tutorials/07-AgentCore-E2E/prerequisite/cognito.yaml
+++ b/01-tutorials/07-AgentCore-E2E/prerequisite/cognito.yaml
@@ -211,7 +211,7 @@ Resources:
CognitoMachineClientIdParameter:
Type: AWS::SSM::Parameter
Properties:
- Name: /app/customersupport/agentcore/machine_client_id
+ Name: /app/customersupport/agentcore/client_id
Type: String
Value: !Ref MachineUserPoolClient
Description: Machine Cognito client ID
@@ -226,12 +226,12 @@ Resources:
Value: !Ref WebUserPoolClient
Description: Cognito client ID for web app
Tags:
- Application: CustomerSuppor
+ Application: CustomerSupport
UserPoolIdParameter:
Type: AWS::SSM::Parameter
Properties:
- Name: /app/customersupport/agentcore/userpool_id
+ Name: /app/customersupport/agentcore/pool_id
Type: String
Value: !Ref UserPool
Description: Cognito client ID
diff --git a/01-tutorials/07-AgentCore-E2E/requirements.txt b/01-tutorials/07-AgentCore-E2E/requirements.txt
index 686d62ac0..38f69fd41 100644
--- a/01-tutorials/07-AgentCore-E2E/requirements.txt
+++ b/01-tutorials/07-AgentCore-E2E/requirements.txt
@@ -1,9 +1,9 @@
strands-agents
strands-agents-tools
-boto3>=1.40.8
-botocore>=1.40.8
-bedrock-agentcore<=0.1.5
-bedrock-agentcore-starter-toolkit==0.1.14
+boto3==1.40.47
+botocore==1.40.47
+bedrock-agentcore==0.1.7
+bedrock-agentcore-starter-toolkit==0.1.20
aws-opentelemetry-distro
ddgs
aws-opentelemetry-distro~=0.10.1
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_agent_runtime.py b/01-tutorials/07-AgentCore-E2E/scripts/agentcore_agent_runtime.py
deleted file mode 100644
index 80d0e6411..000000000
--- a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_agent_runtime.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python3
-
-import sys
-import boto3
-import click
-from utils import get_aws_region
-
-
-@click.command()
-@click.argument('agent_name', type=str)
-@click.option('--dry-run', is_flag=True, help='Show what would be deleted without actually deleting')
-def delete_agent_runtime(agent_name: str, dry_run: bool):
- """Delete an agent runtime by name from AWS Bedrock AgentCore.
-
- AGENT_NAME: Name of the agent runtime to delete
- """
-
- try:
- agentcore_control_client = boto3.client(
- "bedrock-agentcore-control", region_name=get_aws_region()
- )
- except Exception as e:
- click.echo(f"Error creating AWS client: {e}", err=True)
- sys.exit(1)
-
- agent_id = None
- found = False
- next_token = None
-
- click.echo(f"Searching for agent runtime: {agent_name}")
-
- try:
- while True:
- kwargs = {"maxResults": 20}
- if next_token:
- kwargs["nextToken"] = next_token
-
- agent_runtimes = agentcore_control_client.list_agent_runtimes(**kwargs)
-
- for agent_runtime in agent_runtimes.get("agentRuntimes", []):
- if agent_runtime["agentRuntimeName"] == agent_name:
- agent_id = agent_runtime["agentRuntimeId"]
- found = True
- break
-
- if found:
- break
-
- next_token = agent_runtimes.get("nextToken")
- if not next_token:
- break
-
- except Exception as e:
- click.echo(f"Error listing agent runtimes: {e}", err=True)
- sys.exit(1)
-
- if found:
- click.echo(f"Found agent runtime '{agent_name}' with ID: {agent_id}")
-
- if dry_run:
- click.echo(f"[DRY RUN] Would delete agent runtime: {agent_name}")
- return
-
- try:
- agentcore_control_client.delete_agent_runtime(agentRuntimeId=agent_id)
- click.echo(f"Successfully deleted agent runtime: {agent_name}")
- except Exception as e:
- click.echo(f"Error deleting agent runtime: {e}", err=True)
- sys.exit(1)
- else:
- click.echo(f"Agent runtime '{agent_name}' not found", err=True)
- sys.exit(1)
-
-
-if __name__ == "__main__":
- delete_agent_runtime()
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_gateway.py b/01-tutorials/07-AgentCore-E2E/scripts/agentcore_gateway.py
deleted file mode 100644
index e3e6e062b..000000000
--- a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_gateway.py
+++ /dev/null
@@ -1,246 +0,0 @@
-#!/usr/bin/python
-from typing import List
-import os
-import sys
-import boto3
-import click
-
-from utils import (
- get_aws_region,
- get_ssm_parameter,
- put_ssm_parameter,
- delete_ssm_parameter,
- load_api_spec,
- get_cognito_client_secret,
-)
-
-
-REGION = get_aws_region()
-
-gateway_client = boto3.client(
- "bedrock-agentcore-control",
- region_name=REGION,
-)
-
-
-def create_gateway(gateway_name: str, api_spec: List) -> dict:
- """Create an AgentCore gateway with the specified configuration."""
- try:
- # Use Cognito for Inbound OAuth to our Gateway
- lambda_target_config = {
- "mcp": {
- "lambda": {
- "lambdaArn": get_ssm_parameter(
- "/app/customersupport/agentcore/lambda_arn"
- ),
- "toolSchema": {"inlinePayload": api_spec},
- }
- }
- }
-
- auth_config = {
- "customJWTAuthorizer": {
- "allowedClients": [
- get_ssm_parameter(
- "/app/customersupport/agentcore/machine_client_id"
- )
- ],
- "discoveryUrl": get_ssm_parameter(
- "/app/customersupport/agentcore/cognito_discovery_url"
- ),
- }
- }
-
- execution_role_arn = get_ssm_parameter(
- "/app/customersupport/agentcore/gateway_iam_role"
- )
-
- click.echo(f"Creating gateway in region {REGION} with name: {gateway_name}")
- click.echo(f"Execution role ARN: {execution_role_arn}")
-
- create_response = gateway_client.create_gateway(
- name=gateway_name,
- roleArn=execution_role_arn,
- protocolType="MCP",
- authorizerType="CUSTOM_JWT",
- authorizerConfiguration=auth_config,
- description="Customer Support AgentCore Gateway",
- )
-
- click.echo(f"โ
Gateway created: {create_response['gatewayId']}")
-
- # Create gateway target
- credential_config = [{"credentialProviderType": "GATEWAY_IAM_ROLE"}]
- gateway_id = create_response["gatewayId"]
-
- create_target_response = gateway_client.create_gateway_target(
- gatewayIdentifier=gateway_id,
- name="LambdaUsingSDK",
- description="Lambda Target using SDK",
- targetConfiguration=lambda_target_config,
- credentialProviderConfigurations=credential_config,
- )
-
- click.echo(f"โ
Gateway target created: {create_target_response['targetId']}")
-
- gateway = {
- "id": gateway_id,
- "name": gateway_name,
- "gateway_url": create_response["gatewayUrl"],
- "gateway_arn": create_response["gatewayArn"],
- }
-
- # Save gateway details to SSM parameters
- put_ssm_parameter("/app/customersupport/agentcore/gateway_id", gateway_id)
- put_ssm_parameter("/app/customersupport/agentcore/gateway_name", gateway_name)
- put_ssm_parameter(
- "/app/customersupport/agentcore/gateway_arn", create_response["gatewayArn"]
- )
- put_ssm_parameter(
- "/app/customersupport/agentcore/gateway_url", create_response["gatewayUrl"]
- )
- put_ssm_parameter(
- "/app/customersupport/agentcore/cognito_secret",
- get_cognito_client_secret(),
- with_encryption=True,
- )
-
- click.echo("โ
Gateway configuration saved to SSM parameters")
-
- return gateway
-
- except Exception as e:
- click.echo(f"โ Error creating gateway: {str(e)}", err=True)
- sys.exit(1)
-
-
-def delete_gateway(gateway_id: str) -> bool:
- """Delete a gateway and all its targets."""
- try:
- click.echo(f"๐๏ธ Deleting all targets for gateway: {gateway_id}")
-
- # List and delete all targets
- list_response = gateway_client.list_gateway_targets(
- gatewayIdentifier=gateway_id, maxResults=100
- )
-
- for item in list_response["items"]:
- target_id = item["targetId"]
- click.echo(f" Deleting target: {target_id}")
- gateway_client.delete_gateway_target(
- gatewayIdentifier=gateway_id, targetId=target_id
- )
- click.echo(f" โ
Target {target_id} deleted")
-
- # Delete the gateway
- click.echo(f"๐๏ธ Deleting gateway: {gateway_id}")
- gateway_client.delete_gateway(gatewayIdentifier=gateway_id)
- click.echo(f"โ
Gateway {gateway_id} deleted successfully")
-
- return True
-
- except Exception as e:
- click.echo(f"โ Error deleting gateway: {str(e)}", err=True)
- return False
-
-
-def get_gateway_id_from_config() -> str:
- """Get gateway ID from SSM parameter."""
- try:
- return get_ssm_parameter("/app/customersupport/agentcore/gateway_id")
- except Exception as e:
- click.echo(f"โ Error reading gateway ID from SSM: {str(e)}", err=True)
- return None
-
-
-@click.group()
-@click.pass_context
-def cli(ctx):
- """AgentCore Gateway Management CLI.
-
- Create and delete AgentCore gateways for the customer support application.
- """
- ctx.ensure_object(dict)
-
-
-@cli.command()
-@click.option("--name", required=True, help="Name for the gateway")
-@click.option(
- "--api-spec-file",
- default="prerequisite/lambda/api_spec.json",
- help="Path to the API specification file (default: prerequisite/lambda/api_spec.json)",
-)
-def create(name, api_spec_file):
- """Create a new AgentCore gateway."""
- click.echo(f"๐ Creating AgentCore gateway: {name}")
- click.echo(f"๐ Region: {REGION}")
-
- # Validate API spec file exists
- if not os.path.exists(api_spec_file):
- click.echo(f"โ API specification file not found: {api_spec_file}", err=True)
- sys.exit(1)
-
- try:
- api_spec = load_api_spec(api_spec_file)
- gateway = create_gateway(gateway_name=name, api_spec=api_spec)
- click.echo(f"๐ Gateway created successfully with ID: {gateway['id']}")
-
- except Exception as e:
- click.echo(f"โ Failed to create gateway: {str(e)}", err=True)
- sys.exit(1)
-
-
-@cli.command()
-@click.option(
- "--gateway-id",
- help="Gateway ID to delete (if not provided, will read from gateway.config)",
-)
-@click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
-def delete(gateway_id, confirm):
- """Delete an AgentCore gateway and all its targets."""
-
- # If no gateway ID provided, try to read from config
- if not gateway_id:
- gateway_id = get_gateway_id_from_config()
- if not gateway_id:
- click.echo(
- "โ No gateway ID provided and couldn't read from SSM parameters",
- err=True,
- )
- sys.exit(1)
- click.echo(f"๐ Using gateway ID from SSM: {gateway_id}")
-
- # Confirmation prompt
- if not confirm:
- if not click.confirm(
- f"โ ๏ธ Are you sure you want to delete gateway {gateway_id}? This action cannot be undone."
- ):
- click.echo("โ Operation cancelled")
- sys.exit(0)
-
- click.echo(f"๐๏ธ Deleting gateway: {gateway_id}")
-
- if delete_gateway(gateway_id):
- click.echo("โ
Gateway deleted successfully")
-
- # Clean up SSM parameters
- delete_ssm_parameter("/app/customersupport/agentcore/gateway_id")
- delete_ssm_parameter("/app/customersupport/agentcore/gateway_name")
- delete_ssm_parameter("/app/customersupport/agentcore/gateway_arn")
- delete_ssm_parameter("/app/customersupport/agentcore/gateway_url")
- delete_ssm_parameter("/app/customersupport/agentcore/cognito_secret")
- click.echo("๐งน Removed gateway SSM parameters")
-
- # Clean up config file if it exists (backward compatibility)
- if os.path.exists("gateway.config"):
- os.remove("gateway.config")
- click.echo("๐งน Removed gateway.config file")
-
- click.echo("๐ Gateway and configuration deleted successfully")
- else:
- click.echo("โ Failed to delete gateway", err=True)
- sys.exit(1)
-
-
-if __name__ == "__main__":
- cli()
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_memory.py b/01-tutorials/07-AgentCore-E2E/scripts/agentcore_memory.py
deleted file mode 100644
index ce3f71689..000000000
--- a/01-tutorials/07-AgentCore-E2E/scripts/agentcore_memory.py
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/python
-import click
-import boto3
-import sys
-from botocore.exceptions import ClientError
-from bedrock_agentcore.memory import MemoryClient
-from bedrock_agentcore.memory.constants import StrategyType
-from utils import get_aws_region
-
-# AWS clients
-REGION = get_aws_region()
-ssm = boto3.client("ssm", region_name=REGION)
-memory_client = MemoryClient()
-
-
-def store_memory_id_in_ssm(param_name: str, memory_id: str):
- ssm.put_parameter(Name=param_name, Value=memory_id, Type="String", Overwrite=True)
- click.echo(f"๐ Stored memory_id in SSM: {param_name}")
-
-
-def get_memory_id_from_ssm(param_name: str):
- try:
- response = ssm.get_parameter(Name=param_name)
- return response["Parameter"]["Value"]
- except ClientError as e:
- raise click.ClickException(f"โ Could not retrieve memory_id from SSM: {e}")
-
-
-def delete_ssm_param(param_name: str):
- try:
- ssm.delete_parameter(Name=param_name)
- click.echo(f"๐งน Deleted SSM parameter: {param_name}")
- except ClientError as e:
- click.echo(f"โ ๏ธ Failed to delete SSM parameter: {e}")
-
-
-@click.group()
-@click.pass_context
-def cli(ctx):
- """AgentCore Memory Management CLI.
-
- Create and delete AgentCore memory resources for the customer support application.
- """
- ctx.ensure_object(dict)
-
-
-@cli.command()
-@click.option(
- "--name", default="CustomerSupportMemory", help="Name of the memory resource"
-)
-@click.option(
- "--ssm-param",
- default="/app/customersupport/agentcore/memory_id",
- help="SSM parameter to store memory_id",
-)
-@click.option(
- "--event-expiry-days",
- default=30,
- type=int,
- help="Number of days before events expire (default: 30)",
-)
-def create(name, ssm_param, event_expiry_days):
- """Create a new AgentCore memory resource."""
- click.echo(f"๐ Creating AgentCore memory: {name}")
- click.echo(f"๐ Region: {REGION}")
- click.echo(f"โฑ๏ธ Event expiry: {event_expiry_days} days")
-
- strategies = [
- {
- StrategyType.SEMANTIC.value: {
- "name": "fact_extractor",
- "description": "Extracts and stores factual information",
- "namespaces": ["support/user/{actorId}/facts"],
- },
- },
- {
- StrategyType.SUMMARY.value: {
- "name": "conversation_summary",
- "description": "Captures summaries of conversations",
- "namespaces": ["support/user/{actorId}/{sessionId}"],
- },
- },
- {
- StrategyType.USER_PREFERENCE.value: {
- "name": "user_preferences",
- "description": "Captures user preferences and settings",
- "namespaces": ["support/user/{actorId}/preferences"],
- },
- },
- ]
-
- try:
- click.echo("๐ Creating memory resource...")
- memory = memory_client.create_memory_and_wait(
- name=name,
- strategies=strategies,
- description="Memory for customer support agent",
- event_expiry_days=event_expiry_days,
- )
- memory_id = memory["id"]
- click.echo(f"โ
Memory created successfully: {memory_id}")
-
- except Exception as e:
- if "already exists" in str(e):
- click.echo("๐ Memory already exists, finding existing resource...")
- memories = memory_client.list_memories()
- memory_id = next(
- (m["id"] for m in memories if name in m.get("name", "")), None
- )
- if memory_id:
- click.echo(f"โ
Using existing memory: {memory_id}")
- else:
- click.echo("โ Could not find existing memory resource", err=True)
- sys.exit(1)
- else:
- click.echo(f"โ Error creating memory: {str(e)}", err=True)
- sys.exit(1)
-
- try:
- store_memory_id_in_ssm(ssm_param, memory_id)
- click.echo("๐ Memory setup completed successfully!")
- click.echo(f" Memory ID: {memory_id}")
- click.echo(f" SSM Parameter: {ssm_param}")
-
- except Exception as e:
- click.echo(f"โ ๏ธ Memory created but failed to store in SSM: {str(e)}", err=True)
-
-
-@cli.command()
-@click.option(
- "--memory-id",
- help="Memory ID to delete (if not provided, will read from SSM parameter)",
-)
-@click.option(
- "--ssm-param",
- default="/app/customersupport/agentcore/memory_id",
- help="SSM parameter to retrieve memory_id from",
-)
-@click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
-def delete(memory_id, ssm_param, confirm):
- """Delete an AgentCore memory resource."""
-
- # If no memory ID provided, try to read from SSM
- if not memory_id:
- try:
- memory_id = get_memory_id_from_ssm(ssm_param)
- click.echo(f"๐ Using memory ID from SSM: {memory_id}")
- except Exception:
- click.echo(
- "โ No memory ID provided and couldn't read from SSM parameter",
- err=True,
- )
- sys.exit(1)
-
- # Confirmation prompt
- if not confirm:
- if not click.confirm(
- f"โ ๏ธ Are you sure you want to delete memory {memory_id}? This action cannot be undone."
- ):
- click.echo("โ Operation cancelled")
- sys.exit(0)
-
- click.echo(f"๐๏ธ Deleting memory: {memory_id}")
-
- try:
- memory_client.delete_memory(memory_id=memory_id)
- click.echo(f"โ
Memory deleted successfully: {memory_id}")
- except Exception as e:
- click.echo(f"โ Error deleting memory: {str(e)}", err=True)
- sys.exit(1)
-
- # Always delete SSM parameter
- delete_ssm_param(ssm_param)
- click.echo("๐ Memory and SSM parameter deleted successfully")
-
-
-if __name__ == "__main__":
- cli()
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/cognito_credentials_provider.py b/01-tutorials/07-AgentCore-E2E/scripts/cognito_credentials_provider.py
deleted file mode 100644
index 9807161d6..000000000
--- a/01-tutorials/07-AgentCore-E2E/scripts/cognito_credentials_provider.py
+++ /dev/null
@@ -1,254 +0,0 @@
-#!/usr/bin/python
-import boto3
-import click
-import sys
-from botocore.exceptions import ClientError
-from utils import get_ssm_parameter, get_aws_region
-
-REGION = get_aws_region()
-
-identity_client = boto3.client(
- "bedrock-agentcore-control",
- region_name=REGION,
-)
-ssm = boto3.client("ssm", region_name=REGION)
-
-
-def store_provider_name_in_ssm(provider_name: str):
- """Store credential provider name in SSM parameter."""
- param_name = "/app/customersupport/agentcore/cognito_provider"
- try:
- ssm.put_parameter(
- Name=param_name, Value=provider_name, Type="String", Overwrite=True
- )
- click.echo(f"๐ Stored provider name in SSM: {param_name}")
- except ClientError as e:
- click.echo(f"โ ๏ธ Failed to store provider name in SSM: {e}")
-
-
-def get_provider_name_from_ssm() -> str:
- """Get credential provider name from SSM parameter."""
- param_name = "/app/customersupport/agentcore/cognito_provider"
- try:
- response = ssm.get_parameter(Name=param_name)
- return response["Parameter"]["Value"]
- except ClientError:
- return None
-
-
-def delete_ssm_param():
- """Delete SSM parameter for provider."""
- param_name = "/app/customersupport/agentcore/cognito_provider"
- try:
- ssm.delete_parameter(Name=param_name)
- click.echo(f"๐งน Deleted SSM parameter: {param_name}")
- except ClientError as e:
- click.echo(f"โ ๏ธ Failed to delete SSM parameter: {e}")
-
-
-def create_cognito_provider(provider_name: str) -> dict:
- """Create a Cognito OAuth2 credential provider."""
- try:
- click.echo("๐ฅ Fetching Cognito configuration from SSM...")
- client_id = get_ssm_parameter(
- "/app/customersupport/agentcore/machine_client_id"
- )
- click.echo(f"โ
Retrieved client ID: {client_id}")
-
- client_secret = get_ssm_parameter(
- "/app/customersupport/agentcore/cognito_secret"
- )
- click.echo(f"โ
Retrieved client secret: {client_secret[:4]}***")
-
- issuer = get_ssm_parameter(
- "/app/customersupport/agentcore/cognito_discovery_url"
- )
- auth_url = get_ssm_parameter("/app/customersupport/agentcore/cognito_auth_url")
- token_url = get_ssm_parameter(
- "/app/customersupport/agentcore/cognito_token_url"
- )
-
- click.echo(f"โ
Issuer: {issuer}")
- click.echo(f"โ
Authorization Endpoint: {auth_url}")
- click.echo(f"โ
Token Endpoint: {token_url}")
-
- click.echo("โ๏ธ Creating OAuth2 credential provider...")
- cognito_provider = identity_client.create_oauth2_credential_provider(
- name=provider_name,
- credentialProviderVendor="CustomOauth2",
- oauth2ProviderConfigInput={
- "customOauth2ProviderConfig": {
- "clientId": client_id,
- "clientSecret": client_secret,
- "oauthDiscovery": {
- "authorizationServerMetadata": {
- "issuer": issuer,
- "authorizationEndpoint": auth_url,
- "tokenEndpoint": token_url,
- "responseTypes": ["code", "token"],
- }
- },
- }
- },
- )
-
- click.echo("โ
OAuth2 credential provider created successfully")
- provider_arn = cognito_provider["credentialProviderArn"]
- click.echo(f" Provider ARN: {provider_arn}")
- click.echo(f" Provider Name: {cognito_provider['name']}")
-
- # Store provider name in SSM
- store_provider_name_in_ssm(provider_name)
-
- return cognito_provider
-
- except Exception as e:
- click.echo(f"โ Error creating Cognito credential provider: {str(e)}", err=True)
- sys.exit(1)
-
-
-def delete_cognito_provider(provider_name: str) -> bool:
- """Delete a Cognito OAuth2 credential provider."""
- try:
- click.echo(f"๐๏ธ Deleting OAuth2 credential provider: {provider_name}")
-
- identity_client.delete_oauth2_credential_provider(name=provider_name)
-
- click.echo("โ
OAuth2 credential provider deleted successfully")
- return True
-
- except Exception as e:
- click.echo(f"โ Error deleting credential provider: {str(e)}", err=True)
- return False
-
-
-def list_credential_providers() -> list:
- """List all OAuth2 credential providers."""
- try:
- response = identity_client.list_oauth2_credential_providers(maxResults=20)
- providers = response.get("credentialProviders", [])
- return providers
-
- except Exception as e:
- click.echo(f"โ Error listing credential providers: {str(e)}", err=True)
- return []
-
-
-def find_provider_by_name(provider_name: str) -> bool:
- """Check if provider exists by name."""
- providers = list_credential_providers()
- for provider in providers:
- if provider.get("name") == provider_name:
- return True
- return False
-
-
-@click.group()
-@click.pass_context
-def cli(ctx):
- """AgentCore Cognito Credential Provider Management CLI.
-
- Create and delete OAuth2 credential providers for Cognito authentication.
- """
- ctx.ensure_object(dict)
-
-
-@cli.command()
-@click.option(
- "--name", required=True, help="Name for the credential provider (required)"
-)
-def create(name):
- """Create a new Cognito OAuth2 credential provider."""
- click.echo(f"๐ Creating Cognito credential provider: {name}")
- click.echo(f"๐ Region: {REGION}")
-
- # Check if provider already exists in SSM
- existing_name = get_provider_name_from_ssm()
- if existing_name:
- click.echo(f"โ ๏ธ A provider already exists in SSM: {existing_name}")
- if not click.confirm("Do you want to replace it?"):
- click.echo("โ Operation cancelled")
- sys.exit(0)
-
- try:
- provider = create_cognito_provider(provider_name=name)
- click.echo("๐ Cognito credential provider created successfully!")
- click.echo(f" Provider ARN: {provider['credentialProviderArn']}")
- click.echo(f" Provider Name: {provider['name']}")
-
- except Exception as e:
- click.echo(f"โ Failed to create credential provider: {str(e)}", err=True)
- sys.exit(1)
-
-
-@cli.command()
-@click.option(
- "--name",
- help="Name of the credential provider to delete (if not provided, will read from SSM parameter)",
-)
-@click.option("--confirm", is_flag=True, help="Skip confirmation prompt")
-def delete(name, confirm):
- """Delete a Cognito OAuth2 credential provider."""
-
- # If no name provided, try to get from SSM
- if not name:
- name = get_provider_name_from_ssm()
- if not name:
- click.echo(
- "โ No provider name provided and couldn't read from SSM parameter",
- err=True,
- )
- click.echo(" Hint: Use 'list' command to see available providers")
- sys.exit(1)
- click.echo(f"๐ Using provider name from SSM: {name}")
-
- click.echo(f"๐ Looking for credential provider: {name}")
-
- # Check if provider exists
- if not find_provider_by_name(name):
- click.echo(f"โ No credential provider found with name: {name}", err=True)
- click.echo(" Hint: Use 'list' command to see available providers")
- sys.exit(1)
-
- click.echo(f"๐ Found provider: {name}")
-
- # Confirmation prompt
- if not confirm:
- if not click.confirm(
- f"โ ๏ธ Are you sure you want to delete credential provider '{name}'? This action cannot be undone."
- ):
- click.echo("โ Operation cancelled")
- sys.exit(0)
-
- if delete_cognito_provider(name):
- click.echo(f"โ
Credential provider '{name}' deleted successfully")
-
- # Always delete SSM parameter
- delete_ssm_param()
- click.echo("๐ Credential provider and SSM parameter deleted successfully")
- else:
- click.echo("โ Failed to delete credential provider", err=True)
- sys.exit(1)
-
-
-@cli.command("list")
-def list_providers():
- """List all OAuth2 credential providers."""
- providers = list_credential_providers()
-
- if not providers:
- click.echo("โน๏ธ No credential providers found")
- return
-
- click.echo(f"๐ Found {len(providers)} credential provider(s):")
- for provider in providers:
- click.echo(f" โข Name: {provider.get('name', 'N/A')}")
- click.echo(f" ARN: {provider['credentialProviderArn']}")
- click.echo(f" Vendor: {provider.get('credentialProviderVendor', 'N/A')}")
- if "createdTime" in provider:
- click.echo(f" Created: {provider['createdTime']}")
- click.echo()
-
-
-if __name__ == "__main__":
- cli()
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/prereq.sh b/01-tutorials/07-AgentCore-E2E/scripts/prereq.sh
index e2fbc4057..ccf795223 100755
--- a/01-tutorials/07-AgentCore-E2E/scripts/prereq.sh
+++ b/01-tutorials/07-AgentCore-E2E/scripts/prereq.sh
@@ -9,8 +9,17 @@ INFRA_STACK_NAME=${2:-CustomerSupportStackInfra}
COGNITO_STACK_NAME=${3:-CustomerSupportStackCognito}
INFRA_TEMPLATE_FILE="prerequisite/infrastructure.yaml"
COGNITO_TEMPLATE_FILE="prerequisite/cognito.yaml"
-REGION=$(aws configure get region 2>/dev/null || echo "us-west-2")
+# First try to get region from environment variable
+if [ -z "${AWS_REGION}" ]; then
+ # If AWS_REGION is not set, try to get it from AWS CLI config
+ REGION=$(aws configure get region 2>/dev/null || echo "us-west-2")
+ # Export it as an environment variable
+ export AWS_REGION="${REGION}"
+fi
+echo "Region is set to: ${AWS_REGION}"
+export REGION="${AWS_REGION}"
+
# Get AWS Account ID with proper error handling
echo "๐ Getting AWS Account ID..."
@@ -21,7 +30,6 @@ if [ $? -ne 0 ] || [ -z "$ACCOUNT_ID" ] || [ "$ACCOUNT_ID" = "None" ]; then
exit 1
fi
-
FULL_BUCKET_NAME="${BUCKET_NAME}-${ACCOUNT_ID}-${REGION}"
ZIP_FILE="lambda.zip"
LAYER_ZIP_FILE="ddgs-layer.zip"
diff --git a/01-tutorials/07-AgentCore-E2E/scripts/utils.py b/01-tutorials/07-AgentCore-E2E/scripts/utils.py
deleted file mode 100644
index 79448772f..000000000
--- a/01-tutorials/07-AgentCore-E2E/scripts/utils.py
+++ /dev/null
@@ -1,120 +0,0 @@
-import boto3
-import json
-import yaml
-import os
-from typing import Dict, Any
-
-
-def get_ssm_parameter(name: str, with_decryption: bool = True) -> str:
- ssm = boto3.client("ssm")
-
- response = ssm.get_parameter(Name=name, WithDecryption=with_decryption)
-
- return response["Parameter"]["Value"]
-
-
-def put_ssm_parameter(
- name: str, value: str, parameter_type: str = "String", with_encryption: bool = False
-) -> None:
- ssm = boto3.client("ssm")
-
- put_params = {
- "Name": name,
- "Value": value,
- "Type": parameter_type,
- "Overwrite": True,
- }
-
- if with_encryption:
- put_params["Type"] = "SecureString"
-
- ssm.put_parameter(**put_params)
-
-
-def delete_ssm_parameter(name: str) -> None:
- ssm = boto3.client("ssm")
- try:
- ssm.delete_parameter(Name=name)
- except ssm.exceptions.ParameterNotFound:
- pass
-
-
-def load_api_spec(file_path: str) -> list:
- with open(file_path, "r") as f:
- data = json.load(f)
- if not isinstance(data, list):
- raise ValueError("Expected a list in the JSON file")
- return data
-
-
-def get_aws_region() -> str:
- session = boto3.session.Session()
- return session.region_name
-
-
-def get_aws_account_id() -> str:
- sts = boto3.client("sts")
- return sts.get_caller_identity()["Account"]
-
-
-def get_cognito_client_secret() -> str:
- client = boto3.client("cognito-idp")
- response = client.describe_user_pool_client(
- UserPoolId=get_ssm_parameter("/app/customersupport/agentcore/userpool_id"),
- ClientId=get_ssm_parameter("/app/customersupport/agentcore/machine_client_id"),
- )
- return response["UserPoolClient"]["ClientSecret"]
-
-
-def read_config(file_path: str) -> Dict[str, Any]:
- """
- Read configuration from a file path. Supports JSON, YAML, and YML formats.
-
- Args:
- file_path (str): Path to the configuration file
-
- Returns:
- Dict[str, Any]: Configuration data as a dictionary
-
- Raises:
- FileNotFoundError: If the file doesn't exist
- ValueError: If the file format is not supported or invalid
- yaml.YAMLError: If YAML parsing fails
- json.JSONDecodeError: If JSON parsing fails
- """
- if not os.path.exists(file_path):
- raise FileNotFoundError(f"Configuration file not found: {file_path}")
-
- # Get file extension to determine format
- _, ext = os.path.splitext(file_path.lower())
-
- try:
- with open(file_path, "r", encoding="utf-8") as file:
- if ext == ".json":
- return json.load(file)
- elif ext in [".yaml", ".yml"]:
- return yaml.safe_load(file)
- else:
- # Try to auto-detect format by attempting JSON first, then YAML
- content = file.read()
- file.seek(0)
-
- # Try JSON first
- try:
- return json.loads(content)
- except json.JSONDecodeError:
- # Try YAML
- try:
- return yaml.safe_load(content)
- except yaml.YAMLError:
- raise ValueError(
- f"Unsupported configuration file format: {ext}. "
- f"Supported formats: .json, .yaml, .yml"
- )
-
- except json.JSONDecodeError as e:
- raise ValueError(f"Invalid JSON in configuration file {file_path}: {e}")
- except yaml.YAMLError as e:
- raise ValueError(f"Invalid YAML in configuration file {file_path}: {e}")
- except Exception as e:
- raise ValueError(f"Error reading configuration file {file_path}: {e}")