Source code for bedrock_agents_sdk.models.agent

"""
Agent model for Bedrock Agents SDK.
"""
from typing import List, Dict, Any, Optional, Union, Callable, Type
from pydantic import BaseModel, ConfigDict
import os
from dataclasses import dataclass, field

from bedrock_agents_sdk.models.function import Function
from bedrock_agents_sdk.models.action_group import ActionGroup
from bedrock_agents_sdk.models.files import InputFile
from bedrock_agents_sdk.deployment.sam_template import SAMTemplateGenerator
from bedrock_agents_sdk.plugins.base import AgentPlugin, BedrockAgentsPlugin, ClientPlugin

[docs] @dataclass class Agent: """Agent configuration for Amazon Bedrock Agents""" name: str model: str instructions: str functions: Union[List[Callable], Dict[str, List[Callable]]] = field(default_factory=list) action_groups: List[ActionGroup] = field(default_factory=list) enable_code_interpreter: bool = False files: List[InputFile] = field(default_factory=list) plugins: List[Union[AgentPlugin, BedrockAgentsPlugin, ClientPlugin]] = field(default_factory=list) advanced_config: Optional[Dict[str, Any]] = None model_config = ConfigDict(arbitrary_types_allowed=True) def __init__(self, **data): """Initialize the agent and process functions if provided""" # Set default values for attributes self.functions = [] self.files = [] self.plugins = [] self.action_groups = [] self.enable_code_interpreter = False self.advanced_config = None self._custom_dependencies = {} # Handle dictionary format for functions if 'functions' in data and isinstance(data['functions'], dict): action_groups_dict = data.pop('functions') processed_functions = [] # Create ActionGroup objects from the dictionary for group_name, funcs in action_groups_dict.items(): action_group = ActionGroup( name=group_name, description=f"Functions related to {group_name}", functions=funcs ) self.action_groups.append(action_group) # Also add the functions to the functions list with action_group name for func in funcs: processed_functions.append(self._create_function(func, action_group=group_name)) data['functions'] = processed_functions # Initialize attributes from data for key, value in data.items(): setattr(self, key, value) self._process_functions() # Process action groups to ensure all functions are in the functions list self._process_action_groups() def _process_functions(self): """Process functions provided in the constructor""" processed_functions = [] # Process each function for item in self.functions: if isinstance(item, Function): # Already a Function object, keep as is processed_functions.append(item) elif callable(item): # Single function without action group processed_functions.append(self._create_function(item)) # Replace the original functions list with processed functions self.functions = processed_functions def _process_action_groups(self): """Process action groups to ensure all functions are in the functions list""" for action_group in self.action_groups: for func in action_group.functions: # Check if this function is already in the functions list func_names = [f.name for f in self.functions] if isinstance(func, Function): if func.name not in func_names: self.functions.append(func) elif callable(func): func_obj = self._create_function(func, action_group=action_group.name) if func_obj.name not in func_names: self.functions.append(func_obj) def _create_function(self, function: Callable, description: Optional[str] = None, action_group: Optional[str] = None) -> Function: """Create a Function object from a callable""" func_name = function.__name__ # Use provided description or extract first line of docstring if description: func_desc = description elif function.__doc__: # Extract only the first line of the docstring func_desc = function.__doc__.strip().split('\n')[0] else: func_desc = f"Execute the {func_name} function" return Function( name=func_name, description=func_desc, function=function, action_group=action_group )
[docs] def add_function(self, function: Callable, description: Optional[str] = None, action_group: Optional[str] = None): """Add a function to the agent""" self.functions.append(self._create_function(function, description, action_group)) return self
[docs] def add_action_group(self, action_group: ActionGroup): """ Add an action group to the agent Args: action_group: The action group to add Returns: self: For method chaining """ self.action_groups.append(action_group) # Also add the functions to the functions list for func in action_group.functions: if isinstance(func, Function): # Check if function already exists in functions list if func.name not in [f.name for f in self.functions]: self.functions.append(func) elif callable(func): func_obj = self._create_function(func, action_group=action_group.name) # Check if function already exists in functions list if func_obj.name not in [f.name for f in self.functions]: self.functions.append(func_obj) return self
[docs] def add_file(self, name: str, content: bytes, media_type: str, use_case: str = "CODE_INTERPRETER") -> InputFile: """Add a file to be sent to the agent""" file = InputFile(name=name, content=content, media_type=media_type, use_case=use_case) self.files.append(file) return file
[docs] def add_file_from_path(self, file_path: str, use_case: str = "CODE_INTERPRETER") -> InputFile: """Add a file from a local path""" import mimetypes import os name = os.path.basename(file_path) media_type = mimetypes.guess_type(file_path)[0] or 'application/octet-stream' with open(file_path, 'rb') as f: content = f.read() return self.add_file(name, content, media_type, use_case)
[docs] def add_plugin(self, plugin: Union[AgentPlugin, BedrockAgentsPlugin, ClientPlugin]): """ Add a plugin to the agent Args: plugin: The plugin to add """ self.plugins.append(plugin) return self
[docs] def add_dependency(self, dependency: str, version: Optional[str] = None, action_group: Optional[str] = None): """ Add a custom dependency for deployment This method allows you to specify dependencies that should be included in the requirements.txt file when deploying the agent to AWS Lambda. Args: dependency: The name of the dependency (e.g., "pandas") version: Optional version constraint (e.g., ">=1.0.0") action_group: Optional action group to add the dependency to. If not provided, the dependency will be added to all action groups. Returns: self: For method chaining """ if action_group not in self._custom_dependencies: self._custom_dependencies[action_group] = {} self._custom_dependencies[action_group][dependency] = version return self
[docs] def deploy(self, output_dir: Optional[str] = None, foundation_model: Optional[str] = None, parameters: Optional[Dict[str, Dict[str, str]]] = None, description: Optional[str] = None, auto_build: bool = False, auto_deploy: bool = False) -> str: """ Deploy the agent to AWS using SAM Args: output_dir: The directory to output the SAM template and code to. If None, defaults to "./[agent_name]_deployment" foundation_model: The foundation model to use (defaults to the agent's model) parameters: Additional parameters to add to the template description: Description for the SAM template auto_build: Whether to automatically run 'sam build' auto_deploy: Whether to automatically run 'sam deploy --guided' Returns: str: Path to the generated template file """ import os # Create the SAM template generator generator = SAMTemplateGenerator( agent=self, output_dir=output_dir ) # Add custom dependencies to the generator for action_group, deps in self._custom_dependencies.items(): for dep, version in deps.items(): generator.add_custom_dependency(action_group, dep, version) # Generate the SAM template and supporting files template_path = generator.generate( foundation_model=foundation_model, parameters=parameters, description=description ) # Create a safe name for the stack (lowercase, alphanumeric with hyphens) safe_stack_name = ''.join(c.lower() if c.isalnum() else '-' for c in self.name) safe_stack_name = safe_stack_name.strip('-') # Remove leading/trailing hyphens # Automatically build the SAM project if requested if auto_build or auto_deploy: import subprocess import sys print("\n🔨 Building SAM project...") # Change to the output directory original_dir = os.getcwd() os.chdir(generator.output_dir) try: # Run sam build build_result = subprocess.run( ["sam", "build"], capture_output=True, text=True, check=True ) print(build_result.stdout) print("\n✅ SAM project built successfully") # Automatically deploy the SAM project if requested if auto_deploy: print("\n🚀 Deploying SAM project...") # Run sam deploy with the agent name as the stack name deploy_result = subprocess.run( ["sam", "deploy", "--guided", "--capabilities", "CAPABILITY_NAMED_IAM", "--stack-name", f"{safe_stack_name}-agent"], check=True ) print("\n✅ SAM project deployed successfully") except subprocess.CalledProcessError as e: print(f"\n❌ Error: {e}") print(e.stdout) print(e.stderr) except FileNotFoundError: print("\n❌ Error: AWS SAM CLI not found") print("Please install the AWS SAM CLI:") print(" pip install aws-sam-cli") finally: # Change back to the original directory os.chdir(original_dir) return template_path