Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,398 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 02 - Creating Registry as Admin\n",
"\n",
"This notebook walks through the creation of a new AWS Agent Registry using Admin Persona and highlights different API operations associated with Registry. \n",
"\n",
"## What You'll Learn\n",
"\n",
"- Create and configure a **Registry** using admin persona\n",
"- List registries in your account\n",
"- Update registry configuration\n",
"\n",
"## Prerequisites\n",
"\n",
"- boto3 >= 1.42.87\n",
"- Execute [notebook 01](01-create-user-personas-workflow.ipynb) to create IAM roles for admin, publisher and consumer personas\n",
"\n",
"## Admin API References\n",
"\n",
"| # | API | Description |\n",
"|---|-----|-------------|\n",
"| 1 | [CreateRegistry](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/create_registry.html) | Create a new registry with approval configuration |\n",
"| 2 | [GetRegistry](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/get_registry.html) | Fetch registry details and poll for READY status |\n",
"| 3 | [ListRegistries](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/list_registries.html) | List all registries in the account |\n",
"| 4 | [UpdateRegistry](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/update_registry.html) | Update registry description or approval config |\n",
"| 5 | [DeleteRegistry](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/delete_registry.html) | Delete a registry by ID |\n",
"| 6 | [ListRegistryRecords](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/list_registry_records.html) | List all records in a registry (cleanup) |\n",
"| 7 | [DeleteRegistryRecord](https://docs.aws.amazon.com/boto3/latest/reference/services/bedrock-agentcore-control/client/delete_registry_record.html) | Delete a specific record from a registry (cleanup) |\n",
"\n",
"#### Notebook Chain\n",
"\n",
"**02 (this notebook)** → 03 (publish records) → 04 (admin approval) → 05 (semantic search)\n",
"\n",
"#### Use Case: Enterprise Payment Processing\n",
"**Admin Persona:** AnyCompany's administrator creates a centralized registry for payment processing agents and tools. This enables customer service AI agents to discover and use standardized payment, refund, and transaction capabilities — without requiring individual integrations per deployment."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 1. Install boto3 SDK and dependencies"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Install core dependencies (`boto3` and `python-dotenv`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"!pip install boto3 python-dotenv --force-reinstall"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Initialize boto3 Session as Admin"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Assume the `admin_persona` IAM role and create a boto3 session with temporary credentials. All subsequent API calls use this session."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import boto3\n",
"import json\n",
"import time\n",
"import utils\n",
"import os\n",
"\n",
"AWS_REGION = os.environ.get(\"AWS_DEFAULT_REGION\", \"us-west-2\")\n",
"\n",
"# Auto-detect account ID from current credentials\n",
"sts = boto3.client(\"sts\", region_name=AWS_REGION)\n",
"ACCOUNT_ID = sts.get_caller_identity()[\"Account\"]\n",
"CALLER_ARN = sts.get_caller_identity()[\"Arn\"]\n",
"\n",
"ADMIN_ROLE_ARN = f\"arn:aws:iam::{ACCOUNT_ID}:role/admin_persona\"\n",
"\n",
"print(f\"Account: {ADMIN_ROLE_ARN}\")\n",
"\n",
"# Assume the Admin role\n",
"creds = utils.assume_role(\n",
" role_arn=ADMIN_ROLE_ARN,\n",
" session_name=\"admin-session\",\n",
")\n",
"\n",
"admin_session = boto3.Session(\n",
" aws_access_key_id=creds[\"AccessKeyId\"],\n",
" aws_secret_access_key=creds[\"SecretAccessKey\"],\n",
" aws_session_token=creds[\"SessionToken\"],\n",
" region_name=AWS_REGION,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Initialize the Control Plane Client\n",
"\n",
"The control plane (`bedrock-agentcore-control`) handles CRUD operations for registries and records."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Control plane client (admin operations)\n",
"cp_client = admin_session.client(\"bedrock-agentcore-control\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 4. Create a Registry\n",
"\n",
"As an admin, you can create the registry that publishers can submit records to.\n",
"\n",
"Setting `autoApproval: False` is the default — records require explicit admin approval before becoming searchable."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"NEW_REGISTRY_NAME = \"AWSAgentRegistry\" # Change this\n",
"NEW_REGISTRY_DESCRIPTION = \"Registry created during the getting-started workshop\" # Change this\n",
"\n",
"print(f\"This will create registry: {NEW_REGISTRY_NAME}\\n\")\n",
"\n",
"resp = cp_client.create_registry(\n",
" name=NEW_REGISTRY_NAME,\n",
" description=NEW_REGISTRY_DESCRIPTION,\n",
" approvalConfiguration={\"autoApproval\": False},\n",
")\n",
"\n",
"REGISTRY_ARN = resp[\"registryArn\"]\n",
"REGISTRY_ID = REGISTRY_ARN.split(\"/\")[-1]\n",
"\n",
"print(f\"Created registry: {NEW_REGISTRY_NAME} (ID: {REGISTRY_ID})\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.1 Wait for Registry to be Ready\n",
"\n",
"Registry creation is asynchronous. Poll `GetRegistry` until the status transitions from `CREATING` to `READY`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"while True:\n",
" r = cp_client.get_registry(registryId=REGISTRY_ID)\n",
" if r[\"status\"] == \"READY\":\n",
" print(f\"Registry is READY\")\n",
" break\n",
" print(f\"Status: {r['status']} - waiting...\")\n",
" time.sleep(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.2 Inspect Registry Details\n",
"\n",
"Fetch the full registry object to confirm the name, description, approval configuration, and timestamps."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"registry = cp_client.get_registry(registryId=REGISTRY_ID)\n",
"utils.pp(registry)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## 5. List Registries\n",
"\n",
"List all registries in your account. You can filter by status (`CREATING` or `READY`)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# List all registries\n",
"registries = cp_client.list_registries()\n",
"print(f\"Found {len(registries.get('registries', []))} registries:\\n\")\n",
"print(f\"{'#':<4} {'Name':<30} {'Registry ID':<20} {'Status':<18} {'Created At':<28} {'Updated At'}\")\n",
"print(\"-\" * 140)\n",
"for i, reg in enumerate(registries.get('registries', []), 1):\n",
" print(f\"{i:<4} {reg['name']:<30} {reg['registryId']:<20} {reg['status']:<18} {str(reg.get('createdAt','N/A')):<28} {str(reg.get('updatedAt','N/A'))}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"## 6. Update Registry Configuration\n",
"\n",
"The following example highlights changing Registry description."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"updated = cp_client.update_registry(\n",
" registryId=REGISTRY_ID,\n",
" description={\"optionalValue\": \"Registry created and updated\"}\n",
")\n",
"\n",
"print(f\"Registry entry updated with New description: {updated['description']}\")\n",
"print(f\"Updated at: {updated['updatedAt']}\")\n",
"\n",
"registry = cp_client.get_registry(registryId=REGISTRY_ID)\n",
"utils.pp(registry)\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6.1 Verify the Update\n",
"\n",
"Re-fetch the registry to confirm the description change was applied."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"registry = cp_client.get_registry(registryId=REGISTRY_ID)\n",
"utils.pp(registry)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"---\n",
"## 7. Deleting a Registry and Its Records (Run with Caution)\n",
"\n",
"A registry can be deleted when it's in a terminal/settled state.\n",
"\n",
"Do not attempt to delete when it's in a transitional state like `CREATING`, `UPDATING`, or `DELETING` — the service is still processing and the delete call will likely fail or conflict.\n",
"\n",
"| Status | Type | Description |\n",
"|--------|------|-------------|\n",
"| `CREATING` | Transitional | Registry is being provisioned |\n",
"| `READY` | Terminal | Registry is active and usable |\n",
"| `UPDATING` | Transitional | A registry update is in progress |\n",
"| `DELETING` | Transitional | Registry deletion is in progress |\n",
"| `CREATE_FAILED` | Terminal | Registry provisioning failed |\n",
"| `UPDATE_FAILED` | Terminal | A registry update failed |\n",
"| `DELETE_FAILED` | Terminal | A registry deletion failed |"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"⚠️ Uncomment the code below to delete all records in the registry, then the registry itself."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# import botocore.exceptions\n",
"\n",
"# REGISTRY_ID = \"xa9Ms0EuuzddjpSF\" # You can update with specific Registry ID.\n",
"\n",
"# try:\n",
"# # Check registry status first\n",
"# reg = cp_client.get_registry(registryId=REGISTRY_ID)\n",
"# reg_status = reg.get(\"status\", \"\")\n",
"\n",
"# if reg_status == \"CREATE_FAILED\":\n",
"# cp_client.delete_registry(registryId=REGISTRY_ID)\n",
"# print(f\"Deleted registry in {reg_status} state.\")\n",
"# else:\n",
"# # Delete all records in the registry\n",
"# records = cp_client.list_registry_records(registryId=REGISTRY_ID)\n",
"# for rec in records[\"registryRecords\"]:\n",
"# cp_client.delete_registry_record(\n",
"# registryId=REGISTRY_ID,\n",
"# recordId=rec[\"recordId\"]\n",
"# )\n",
"# print(f\"Deleted record: {rec['recordId']}\")\n",
"\n",
"# # Delete the registry\n",
"# cp_client.delete_registry(registryId=REGISTRY_ID)\n",
"# print(f\"Deleted registry: {REGISTRY_ID}\")\n",
"\n",
"# print(\"\\nCleanup complete!\")\n",
"\n",
"# except cp_client.exceptions.ResourceNotFoundException:\n",
"# print(f\"Registry {REGISTRY_ID} not found - already cleaned up.\")\n",
"# except botocore.exceptions.ClientError as e:\n",
"# print(f\"Error during cleanup: {e}\")\n",
"\n",
"# # List all registries\n",
"# registries = cp_client.list_registries()\n",
"# print(f\"Found {len(registries.get('registries', []))} registries:\\n\")\n",
"# print(f\"{'#':<4} {'Name':<30} {'Registry ID':<20} {'Status':<18} {'Created At':<28} {'Updated At'}\")\n",
"# print(\"-\" * 140)\n",
"# for i, reg in enumerate(registries.get('registries', []), 1):\n",
"# print(f\"{i:<4} {reg['name']:<30} {reg['registryId']:<20} {reg['status']:<18} {str(reg.get('createdAt','N/A')):<28} {str(reg.get('updatedAt','N/A'))}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Pre-requisites\n",
"- **Notebook 01** — [Create User Personas](01-create-user-personas-workflow.ipynb): Set up user personas: admin, publisher, consumer\n",
"\n",
"## Next Steps\n",
"- **Notebook 03** — [Publishing Records](03-publishing-records-workflow.ipynb): Publish records as a Publisher\n",
"- **Notebook 04** — [Admin Approval](04-admin-approval-workflow.ipynb): Admin Approval workflow \n",
"- **Notebook 05** — [Semantic Search](05-search-registry-workflow.ipynb): Search approved records using NLQ as a Consumer"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "finalchangeenv",
"language": "python",
"name": "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.13.7"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Loading
Loading