mirror of
https://github.com/awslabs/amazon-bedrock-agentcore-samples.git
synced 2025-09-08 20:50:46 +00:00
* feat: Add AWS Operations Agent with AgentCore Runtime - Complete rewrite of AWS Operations Agent using Amazon Bedrock AgentCore - Added comprehensive deployment scripts for DIY and SDK runtime modes - Implemented OAuth2/PKCE authentication with Okta integration - Added MCP (Model Context Protocol) tool support for AWS service operations - Sanitized all sensitive information (account IDs, domains, client IDs) with placeholders - Added support for 17 AWS services: EC2, S3, Lambda, CloudFormation, IAM, RDS, CloudWatch, Cost Explorer, ECS, EKS, SNS, SQS, DynamoDB, Route53, API Gateway, SES, Bedrock, SageMaker - Includes chatbot client, gateway management scripts, and comprehensive testing - Ready for public GitHub with security-cleared configuration files Security: All sensitive values replaced with <YOUR_AWS_ACCOUNT_ID>, <YOUR_OKTA_DOMAIN>, <YOUR_OKTA_CLIENT_ID> placeholders * Update AWS Operations Agent architecture diagram --------- Co-authored-by: name <alias@amazon.com>
166 lines
6.3 KiB
Python
166 lines
6.3 KiB
Python
"""
|
|
AgentCore Configuration Manager
|
|
Unified configuration management for all AgentCore consumers
|
|
"""
|
|
|
|
import os
|
|
import yaml
|
|
import logging
|
|
from typing import Dict, Any, List, Optional
|
|
from pathlib import Path
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class AgentCoreConfigManager:
|
|
"""Unified configuration management for all AgentCore consumers"""
|
|
|
|
def __init__(self, environment: str = "debug"):
|
|
"""
|
|
Initialize configuration manager
|
|
|
|
Args:
|
|
environment: Environment type ("debug" or "performance")
|
|
"""
|
|
self.environment = environment
|
|
self.project_root = self._find_project_root()
|
|
self._validator = None # Will be imported when needed to avoid circular imports
|
|
|
|
def _find_project_root(self) -> Path:
|
|
"""Find the project root directory containing .agentcore.yaml"""
|
|
current = Path(__file__).parent
|
|
while current != current.parent:
|
|
if (current / '.agentcore.yaml').exists():
|
|
return current
|
|
current = current.parent
|
|
|
|
# Fallback to parent of shared directory
|
|
return Path(__file__).parent.parent
|
|
|
|
def _load_yaml(self, relative_path: str) -> Dict[str, Any]:
|
|
"""Load YAML file relative to project root"""
|
|
file_path = self.project_root / relative_path
|
|
|
|
if not file_path.exists():
|
|
logger.warning(f"Configuration file not found: {file_path}")
|
|
return {}
|
|
|
|
try:
|
|
with open(file_path, 'r') as f:
|
|
content = yaml.safe_load(f) or {}
|
|
logger.debug(f"Loaded configuration from {file_path}")
|
|
return content
|
|
except Exception as e:
|
|
logger.error(f"Failed to load configuration from {file_path}: {e}")
|
|
return {}
|
|
|
|
def _save_yaml(self, relative_path: str, data: Dict[str, Any]) -> None:
|
|
"""Save YAML file relative to project root"""
|
|
file_path = self.project_root / relative_path
|
|
|
|
# Create directory if it doesn't exist
|
|
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
try:
|
|
with open(file_path, 'w') as f:
|
|
yaml.dump(data, f, default_flow_style=False, indent=2)
|
|
logger.debug(f"Saved configuration to {file_path}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to save configuration to {file_path}: {e}")
|
|
raise
|
|
|
|
def _deep_merge(self, base: Dict[str, Any], override: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Deep merge two dictionaries, with override taking precedence"""
|
|
result = base.copy()
|
|
|
|
for key, value in override.items():
|
|
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
|
|
result[key] = self._deep_merge(result[key], value)
|
|
else:
|
|
result[key] = value
|
|
|
|
return result
|
|
|
|
# Static Configuration Methods
|
|
def get_static_config(self) -> Dict[str, Any]:
|
|
"""Get static configuration (version controlled)"""
|
|
# Load consolidated static config file
|
|
return self._load_yaml("config/static-config.yaml")
|
|
|
|
def get_base_settings(self) -> Dict[str, Any]:
|
|
"""Get base settings only (backward compatibility)"""
|
|
return self.get_static_config()
|
|
|
|
# Dynamic Configuration Methods
|
|
def get_dynamic_config(self) -> Dict[str, Any]:
|
|
"""Get dynamic configuration (deployment generated)"""
|
|
# Load consolidated dynamic config file
|
|
return self._load_yaml("config/dynamic-config.yaml")
|
|
|
|
def update_dynamic_config(self, updates: Dict[str, Any]) -> None:
|
|
"""Update dynamic configuration file"""
|
|
file_path = "config/dynamic-config.yaml"
|
|
current = self._load_yaml(file_path)
|
|
updated = self._deep_merge(current, updates)
|
|
self._save_yaml(file_path, updated)
|
|
|
|
# Merged Configuration Methods
|
|
def get_merged_config(self) -> Dict[str, Any]:
|
|
"""Get complete configuration (static + dynamic merged)"""
|
|
static = self.get_static_config()
|
|
dynamic = self.get_dynamic_config()
|
|
return self._deep_merge(static, dynamic)
|
|
|
|
# Convenience Methods for Backward Compatibility
|
|
def get_model_settings(self) -> Dict[str, Any]:
|
|
"""Get model settings (backward compatibility)"""
|
|
config = self.get_merged_config()
|
|
aws_config = config.get("aws", {})
|
|
agents_config = config.get("agents", {})
|
|
|
|
return {
|
|
"region_name": aws_config.get("region", "us-east-1"),
|
|
"model_id": agents_config.get("modelid", "us.anthropic.claude-3-7-sonnet-20250219-v1:0"),
|
|
"temperature": 0.7, # Default from current usage
|
|
"max_tokens": 4096 # Default from current usage
|
|
}
|
|
|
|
def get_gateway_url(self) -> str:
|
|
"""Get gateway URL (backward compatibility)"""
|
|
config = self.get_merged_config()
|
|
return config.get("gateway", {}).get("url", "")
|
|
|
|
def get_oauth_settings(self) -> Dict[str, Any]:
|
|
"""Get OAuth settings (backward compatibility)"""
|
|
config = self.get_merged_config()
|
|
return config.get("okta", {})
|
|
|
|
def get_tools_schema(self) -> List[Dict[str, Any]]:
|
|
"""Get Bedrock agent tools schema (for gateway target creation)"""
|
|
config = self.get_static_config()
|
|
return config.get("tools_schema", [])
|
|
|
|
def get_mcp_lambda_config(self) -> Dict[str, Any]:
|
|
"""Get MCP lambda configuration (for deployment and gateway operations)"""
|
|
config = self.get_merged_config()
|
|
return config.get("mcp_lambda", {})
|
|
|
|
def validate(self) -> bool:
|
|
"""Validate current configuration"""
|
|
try:
|
|
# Import validator here to avoid circular imports
|
|
if self._validator is None:
|
|
from .config_validator import ConfigValidator
|
|
self._validator = ConfigValidator()
|
|
|
|
static = self.get_static_config()
|
|
dynamic = self.get_dynamic_config()
|
|
merged = self.get_merged_config()
|
|
|
|
self._validator.validate_static(static)
|
|
self._validator.validate_dynamic(dynamic)
|
|
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Configuration validation failed: {e}")
|
|
return False |