[docs]defget_boto_session(credentials_profile_name:Optional[str]=None,region_name:Optional[str]=None,endpoint_url:Optional[str]=None,)->Any:""" Construct the boto3 session """ifcredentials_profile_name:session=boto3.Session(profile_name=credentials_profile_name)else:# use default credentialssession=boto3.Session()client_params={"config":Config(connect_timeout=120,read_timeout=120,retries={"max_attempts":0})}ifregion_name:client_params["region_name"]=region_nameifendpoint_url:client_params["endpoint_url"]=endpoint_urlreturnclient_params,session
[docs]defparse_agent_response(response:Any)->OutputType:""" Parses the raw response from Bedrock Agent Args: response: The raw response from Bedrock Agent Returns Either a BedrockAgentAction or a BedrockAgentFinish """response_text=""event_stream=response["completion"]session_id=response["sessionId"]foreventinevent_stream:if"returnControl"inevent:response_text=json.dumps(event)breakif"chunk"inevent:response_text=event["chunk"]["bytes"].decode("utf-8")agent_finish=BedrockAgentFinish(return_values={"output":response_text},log=response_text,session_id=session_id,)ifnotresponse_text:returnagent_finishif"returnControl"notinresponse_text:returnagent_finishreturn_control=json.loads(response_text).get("returnControl")ifnotreturn_control:returnagent_finishinvocation_inputs=return_control.get("invocationInputs")ifnotinvocation_inputs:returnagent_finishtry:invocation_input=invocation_inputs[0].get("functionInvocationInput",{})action_group=invocation_input.get("actionGroup","")function=invocation_input.get("function","")parameters=invocation_input.get("parameters",[])parameters_json={}forparameterinparameters:parameters_json[parameter.get("name")]=parameter.get("value","")tool=f"{action_group}::{function}"if_DEFAULT_ACTION_GROUP_NAMEinaction_group:tool=f"{function}"return[BedrockAgentAction(tool=tool,tool_input=parameters_json,log=response_text,session_id=session_id,)]exceptExceptionasex:raiseException("Parse exception encountered {}".format(repr(ex)))
def_create_bedrock_agent(bedrock_client:Any,agent_name:str,agent_resource_role_arn:str,instruction:str,foundation_model:str,client_token:Optional[str]=None,customer_encryption_key_arn:Optional[str]=None,description:Optional[str]=None,guardrail_configuration:Optional[GuardrailConfiguration]=None,idle_session_ttl_in_seconds:Optional[int]=None,)->Union[str,None]:""" Creates the bedrock agent """create_agent_request:dict={"agentName":agent_name,"agentResourceRoleArn":agent_resource_role_arn,"foundationModel":foundation_model,"instruction":instruction,}ifdescription:create_agent_request["description"]=descriptionifclient_token:create_agent_request["clientToken"]=client_tokenifcustomer_encryption_key_arn:create_agent_request["customerEncryptionKeyArn"]=customer_encryption_key_arnifguardrail_configurationisnotNone:create_agent_request["guardrailConfiguration"]={"guardrailIdentifier":guardrail_configuration["guardrail_identifier"],"guardrailVersion":guardrail_configuration["guardrail_version"]or"DRAFT",}ifidle_session_ttl_in_seconds:create_agent_request["idleSessionTTLInSeconds"]=idle_session_ttl_in_secondscreate_agent_response=bedrock_client.create_agent(**create_agent_request)request_id=create_agent_response.get("ResponseMetadata",{}).get("RequestId","")logging.info(f"Create bedrock agent call successful with request id: {request_id}")agent_id=create_agent_response["agent"]["agentId"]create_agent_start_time=time.time()whiletime.time()-create_agent_start_time<10:agent_creation_status=(bedrock_client.get_agent(agentId=agent_id).get("agent",{}).get("agentStatus",{}))ifagent_creation_status=="NOT_PREPARED":returnagent_idelse:time.sleep(2)logging.error(f"Failed to create bedrock agent {agent_id}")raiseException(f"Failed to create bedrock agent {agent_id}")def_get_action_group_and_function_names(tool:BaseTool)->Tuple[str,str]:""" Convert the LangChain 'Tool' into Bedrock Action Group name and Function name """action_group_name=_DEFAULT_ACTION_GROUP_NAMEfunction_name=tool.nametool_name_split=tool.name.split("::")iflen(tool_name_split)>1:action_group_name=tool_name_split[0]function_name=tool_name_split[1]returnaction_group_name,function_namedef_create_bedrock_action_groups(bedrock_client:Any,agent_id:str,tools:List[BaseTool])->None:"""Create the bedrock action groups for the agent"""tools_by_action_group=defaultdict(list)fortoolintools:action_group_name,function_name=_get_action_group_and_function_names(tool)tools_by_action_group[action_group_name].append(tool)foraction_group_name,functionsintools_by_action_group.items():bedrock_client.create_agent_action_group(actionGroupName=action_group_name,actionGroupState="ENABLED",actionGroupExecutor={"customControl":"RETURN_CONTROL"},functionSchema={"functions":[_tool_to_function(function)forfunctioninfunctions]},agentId=agent_id,agentVersion="DRAFT",)def_tool_to_function(tool:BaseTool)->dict:""" Convert LangChain tool to a Bedrock function schema """_,function_name=_get_action_group_and_function_names(tool)function_parameters={}forarg_name,arg_detailsintool.args.items():function_parameters[arg_name]={"description":arg_details.get("description",arg_details.get("title",arg_name)),"type":arg_details.get("type","string"),"required":notbool(arg_details.get("default",None)),}return{"description":tool.description,"name":function_name,"parameters":function_parameters,}def_prepare_agent(bedrock_client:Any,agent_id:str)->None:""" Prepare the agent for invocations """bedrock_client.prepare_agent(agentId=agent_id)prepare_agent_start_time=time.time()whiletime.time()-prepare_agent_start_time<10:agent_status=bedrock_client.get_agent(agentId=agent_id)ifagent_status.get("agent",{}).get("agentStatus","")=="PREPARED":returnelse:time.sleep(2)raiseException(f"Timed out while preparing the agent with id {agent_id}")def_get_bedrock_agent(bedrock_client:Any,agent_name:str)->Any:""" Get the agent by name """next_token=NonewhileTrue:ifnext_token:list_agents_response=bedrock_client.list_agents(maxResults=1000,nextToken=next_token)else:list_agents_response=bedrock_client.list_agents(maxResults=1000)agent_summaries=list_agents_response.get("agentSummaries",[])next_token=list_agents_response.get("nextToken")agent_summary=next((xforxinagent_summariesifx.get("agentName")==agent_name),None)ifagent_summary:returnagent_summaryifnext_tokenisNone:returnNone
[docs]classBedrockAgentFinish(AgentFinish):"""AgentFinish with session id information. Parameters: session_id: Session id """session_id:str@classmethoddefis_lc_serializable(cls)->bool:"""Check if the class is serializable by LangChain. Returns: False """returnFalse
[docs]classBedrockAgentAction(AgentAction):"""AgentAction with session id information. Parameters: session_id: session id """session_id:str@classmethoddefis_lc_serializable(cls)->bool:"""Check if the class is serializable by LangChain. Returns: False """returnFalse
[docs]classBedrockAgentsRunnable(RunnableSerializable[Dict,OutputType]):""" Invoke a Bedrock Agent """agent_id:Optional[str]"""Bedrock Agent Id"""agent_alias_id:Optional[str]=_TEST_AGENT_ALIAS_ID"""Bedrock Agent Alias Id"""client:Any"""Boto3 client"""region_name:Optional[str]=None"""Region"""credentials_profile_name:Optional[str]=None"""Credentials to use to invoke the agent"""endpoint_url:Optional[str]=None"""Endpoint URL"""@root_validator(skip_on_failure=True)defvalidate_agent(cls,values:dict)->dict:ifvalues.get("client")isnotNone:returnvaluestry:client_params,session=get_boto_session(credentials_profile_name=values["credentials_profile_name"],region_name=values["region_name"],endpoint_url=values["endpoint_url"],)values["client"]=session.client("bedrock-agent-runtime",**client_params)returnvaluesexceptImportError:raiseModuleNotFoundError("Could not import boto3 python package. ""Please install it with `pip install boto3`.")exceptUnknownServiceErrorase:raiseModuleNotFoundError("Ensure that you have installed the latest boto3 package ""that contains the API for `bedrock-runtime-agent`.")fromeexceptExceptionase:raiseValueError("Could not load credentials to authenticate with AWS client. ""Please check that credentials in the specified ""profile name are valid.")frome
[docs]@classmethoddefcreate_agent(cls,agent_name:str,agent_resource_role_arn:str,foundation_model:str,instruction:str,tools:List[BaseTool]=[],*,client_token:Optional[str]=None,customer_encryption_key_arn:Optional[str]=None,description:Optional[str]=None,guardrail_configuration:Optional[GuardrailConfiguration]=None,idle_session_ttl_in_seconds:Optional[int]=None,credentials_profile_name:Optional[str]=None,region_name:Optional[str]=None,bedrock_endpoint_url:Optional[str]=None,runtime_endpoint_url:Optional[str]=None,**kwargs:Any,)->BedrockAgentsRunnable:""" Creates a Bedrock Agent Runnable that can be used with an AgentExecutor or with LangGraph. This also sets up the Bedrock agent, actions and action groups infrastructure if they don't exist, ensures the agent is in PREPARED state so that it is ready to be called. Args: agent_name: Name of the agent agent_resource_role_arn: The Amazon Resource Name (ARN) of the IAM role with permissions to invoke API operations on the agent. foundation_model: The foundation model to be used for orchestration by the agent you create instruction: Instructions that tell the agent what it should do and how it should interact with users tools: List of tools. Accepts LangChain's BaseTool format client_token: A unique, case-sensitive identifier to ensure that the API request completes no more than one time. If this token matches a previous request, Amazon Bedrock ignores the request, but does not return an error customer_encryption_key_arn: The Amazon Resource Name (ARN) of the KMS key with which to encrypt the agent description: A description of the agent guardrail_configuration: The unique Guardrail configuration assigned to the agent when it is created. idle_session_ttl_in_seconds: The number of seconds for which Amazon Bedrock keeps information about a user's conversation with the agent. A user interaction remains active for the amount of time specified. If no conversation occurs during this time, the session expires and Amazon Bedrock deletes any data provided before the timeout credentials_profile_name: The profile name to use if different from default region_name: Region for the Bedrock agent bedrock_endpoint_url: Endpoint URL for bedrock agent runtime_endpoint_url: Endpoint URL for bedrock agent runtime **kwargs: Additional arguments Returns: BedrockAgentsRunnable configured to invoke the Bedrock agent """client_params,session=get_boto_session(credentials_profile_name=credentials_profile_name,region_name=region_name,endpoint_url=bedrock_endpoint_url,)bedrock_client=session.client("bedrock-agent",**client_params)bedrock_agent=_get_bedrock_agent(bedrock_client=bedrock_client,agent_name=agent_name)ifbedrock_agent:agent_id=bedrock_agent["agentId"]agent_status=bedrock_agent["agentStatus"]ifagent_status!="PREPARED":_prepare_agent(bedrock_client,agent_id)else:try:agent_id=_create_bedrock_agent(bedrock_client=bedrock_client,agent_name=agent_name,agent_resource_role_arn=agent_resource_role_arn,instruction=instruction,foundation_model=foundation_model,client_token=client_token,customer_encryption_key_arn=customer_encryption_key_arn,description=description,guardrail_configuration=guardrail_configuration,idle_session_ttl_in_seconds=idle_session_ttl_in_seconds,)_create_bedrock_action_groups(bedrock_client,agent_id,tools)_prepare_agent(bedrock_client,agent_id)exceptExceptionasexception:logging.error(f"Error in create agent call: {exception}")raiseexceptionreturncls(agent_id=agent_id,region_name=region_name,credentials_profile_name=credentials_profile_name,endpoint_url=runtime_endpoint_url,**kwargs,)
[docs]definvoke(self,input:Dict,config:Optional[RunnableConfig]=None)->OutputType:""" Invoke the Bedrock agent. Args: input: The LangChain Runnable input dictionary that can include: input: The input text to the agent memory_id: The memory id to use for an agent with memory enabled session_id: The session id to use. If not provided, a new session will be started end_session: Boolean indicating whether to end a session or not intermediate_steps: The intermediate steps that are used to provide RoC invocation details enable_trace: Boolean flag to enable trace when invoke bedrock agent Returns: Union[List[BedrockAgentAction], BedrockAgentFinish] """config=ensure_config(config)callback_manager=CallbackManager.configure(inheritable_callbacks=config.get("callbacks"),inheritable_tags=config.get("tags"),inheritable_metadata=config.get("metadata"),)run_manager=callback_manager.on_chain_start(dumpd(self),input,name=config.get("run_name"))try:agent_input={"agentId":self.agent_id,"agentAliasId":self.agent_alias_id,"enableTrace":input.get("enable_trace",False),"endSession":bool(input.get("end_session",False)),}ifinput.get("memory_id"):agent_input["memoryId"]=input.get("memory_id")ifinput.get("intermediate_steps"):session_id,session_state=self._parse_intermediate_steps(input.get("intermediate_steps")# type: ignore[arg-type])ifsession_idisnotNone:agent_input["sessionId"]=session_idifsession_stateisnotNone:agent_input["sessionState"]=session_stateelse:agent_input["inputText"]=input.get("input","")agent_input["sessionId"]=input.get("session_id",str(uuid.uuid4()))output=self.client.invoke_agent(**agent_input)exceptExceptionase:run_manager.on_chain_error(e)raiseetry:response=parse_agent_response(output)exceptExceptionase:run_manager.on_chain_error(e)raiseeelse:run_manager.on_chain_end(response)returnresponse