Amit Arora ff5fdffd42
fix(02-use-cases): Add multi-region support for SRE-Agent (#246)
* Add multi-region support for SRE-Agent

- Add AWS region configuration parameter to agent_config.yaml
- Update gateway main.py to validate region matches endpoint URL
- Modify SRE agent to read region from config and pass through function chain
- Update memory client and LLM creation to use configurable region
- Fixes hardcoded us-east-1 region dependencies

Closes #245

* Move architecture file to docs/ and improve setup instructions

- Move sre_agent_architecture.md to docs/ folder for better organization
- Update graph export code to generate architecture file in docs/ folder
- Add automatic docs directory creation if it doesn't exist
- Improve README setup instructions:
  - Fix .env.example copy path to use sre_agent folder
  - Add note that Amazon Bedrock users don't need to modify .env
  - Add START_API_BACKEND variable to conditionally start backend servers
  - Useful for workshop environments where backends are already running

* Improve gateway configuration documentation and setup instructions

- Update config.yaml.example to use REGION placeholder instead of hardcoded us-east-1
- Add gateway configuration step to README setup instructions
- Document .cognito_config file in auth.md automated setup section
- Remove duplicate credential_provider_name from config.yaml.example
- Update configuration.md to include .cognito_config in files overview
- Add clear instructions to copy and edit gateway/config.yaml before creating gateway

* Improve IAM role guidance and region handling

- Add clear guidance about IAM role options in gateway/config.yaml.example
- Explain that testing can use current EC2/notebook role
- Recommend dedicated role for production deployments
- Add aws sts get-caller-identity command to help users find their role
- Update deployment scripts to use AWS_REGION env var as fallback
- Scripts now follow: CLI arg -> AWS_REGION env var -> us-east-1 default

* Remove unnecessary individual Cognito ID files

- Remove creation of .cognito_user_pool_id file
- Remove creation of .cognito_client_id file
- Keep only .cognito_config as the single source of truth
- Simplifies configuration management

* Implement region fallback logic for SRE Agent

- Added region fallback chain: agent_config.yaml -> AWS_REGION env -> us-east-1
- Modified agent_config.yaml to comment out region parameter to enable fallback
- Updated multi_agent_langgraph.py with comprehensive fallback implementation
- Added logging to show which region source is being used
- Ensures flexible region configuration without breaking existing deployments
- Maintains backward compatibility while adding multi-region support
2025-08-13 08:32:37 -04:00

191 lines
6.2 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import json
import logging
import os
import time
from datetime import datetime
from pathlib import Path
import boto3
from dotenv import load_dotenv
# Load environment variables from sre_agent directory
load_dotenv(Path(__file__).parent.parent / "sre_agent" / ".env")
# Configure logging with basicConfig
logging.basicConfig(
level=logging.INFO,
# Define log message format
format="%(asctime)s,p%(process)s,{%(filename)s:%(lineno)d},%(levelname)s,%(message)s",
)
logger = logging.getLogger(__name__)
def _get_user_from_env() -> str:
"""Get user_id from environment variable.
Returns:
user_id from USER_ID environment variable or default
"""
user_id = os.getenv("USER_ID")
if user_id:
logger.info(f"Using user_id from environment: {user_id}")
return user_id
else:
# Fallback to default user_id
default_user_id = "default-sre-user"
logger.warning(
f"USER_ID not set in environment, using default: {default_user_id}"
)
return default_user_id
def _get_session_from_env(mode: str) -> str:
"""Get session_id from environment variable or generate one.
Args:
mode: "interactive" or "prompt" for auto-generation prefix
Returns:
session_id from SESSION_ID environment variable or auto-generated
"""
session_id = os.getenv("SESSION_ID")
if session_id:
logger.info(f"Using session_id from environment: {session_id}")
return session_id
else:
# Auto-generate session_id (minimum 33 characters required)
import uuid
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
unique_id = str(uuid.uuid4()).replace("-", "")[:12] # 12 character UUID segment
auto_session_id = f"{mode}-{timestamp}-{unique_id}"
logger.info(
f"SESSION_ID not set in environment, auto-generated: {auto_session_id}"
)
return auto_session_id
def main():
parser = argparse.ArgumentParser(
description="Invoke SRE Agent Runtime via AgentCore"
)
parser.add_argument("--prompt", required=True, help="Prompt to send to the agent")
parser.add_argument(
"--runtime-arn",
help="Agent Runtime ARN (reads from .sre_agent_uri if not provided)",
)
parser.add_argument(
"--region",
default=os.environ.get("AWS_REGION", "us-east-1"),
help="AWS region (default: AWS_REGION env var or us-east-1)"
)
parser.add_argument(
"--session-id", help="Runtime session ID (generates one if not provided)"
)
args = parser.parse_args()
# Get runtime ARN from file if not provided
runtime_arn = args.runtime_arn
if not runtime_arn:
script_dir = Path(__file__).parent
# First try to read from .agent_arn file (preferred)
arn_file = script_dir / ".agent_arn"
if arn_file.exists():
runtime_arn = arn_file.read_text().strip()
logging.info(f"Using runtime ARN from .agent_arn: {runtime_arn}")
else:
# Fallback to deriving from container URI
uri_file = script_dir / ".sre_agent_uri"
if uri_file.exists():
container_uri = uri_file.read_text().strip()
# Extract account ID and construct runtime ARN
# Container URI format: account-id.dkr.ecr.region.amazonaws.com/repo:tag
account_id = container_uri.split(".")[0]
runtime_arn = f"arn:aws:bedrock-agentcore:{args.region}:{account_id}:runtime/sre-agent"
logging.info(
f"Using runtime ARN derived from container URI: {runtime_arn}"
)
else:
logging.error(
"No runtime ARN provided and neither .agent_arn nor .sre_agent_uri file found"
)
logging.error(
"Please provide --runtime-arn or ensure the agent is deployed"
)
return
# Generate session ID if not provided
session_id = args.session_id
if not session_id:
timestamp = str(int(time.time()))
session_id = f"sre-agent-session-{timestamp}-invoke"
logging.info(f"Generated session ID: {session_id}")
# Validate session ID length (must be 33+ characters)
if len(session_id) < 33:
session_id = session_id + "-" + "x" * (33 - len(session_id))
logging.info(f"Padded session ID to meet minimum length: {session_id}")
# Create AgentCore client with custom timeout
from botocore.config import Config
# Increase read timeout to handle long-running agent operations
config = Config(
read_timeout=300, # 5 minutes read timeout (default is 60 seconds)
retries={"max_attempts": 3, "mode": "adaptive"},
)
agent_core_client = boto3.client(
"bedrock-agentcore", region_name=args.region, config=config
)
# Get user_id and session_id from environment
user_id = _get_user_from_env()
env_session_id = _get_session_from_env("invoke")
# Use env session_id if not provided via args
if not args.session_id:
session_id = env_session_id
# Prepare payload with user_id and session_id
payload = json.dumps(
{"input": {"prompt": args.prompt, "user_id": user_id, "session_id": session_id}}
)
logging.info(f"Invoking agent runtime: {runtime_arn}")
logging.info(f"Session ID: {session_id}")
logging.info(f"Prompt: {args.prompt}")
try:
response = agent_core_client.invoke_agent_runtime(
agentRuntimeArn=runtime_arn,
runtimeSessionId=session_id,
payload=payload,
qualifier="DEFAULT",
)
response_body = response["response"].read()
response_data = json.loads(response_body)
logging.info("Agent Response:")
print(json.dumps(response_data, indent=2))
# Extract and print the message separately
if "output" in response_data and "message" in response_data["output"]:
print("\nMessage:")
print(response_data["output"]["message"])
except Exception as e:
logging.error(f"Failed to invoke agent runtime: {e}")
raise
if __name__ == "__main__":
main()