importjsonfromtypingimport(Any,Dict,List,Union,)fromlangchain_core._apiimportdeprecatedfrompydanticimportPrivateAttrfromlangchain_anthropic.chat_modelsimportChatAnthropicSYSTEM_PROMPT_FORMAT="""In this environment you have access to a set of tools you can use to answer the user's question.You may call them like this:<function_calls><invoke><tool_name>$TOOL_NAME</tool_name><parameters><$PARAMETER_NAME>$PARAMETER_VALUE</$PARAMETER_NAME>...</parameters></invoke></function_calls>Here are the tools available:<tools>{formatted_tools}</tools>"""# noqa: E501TOOL_FORMAT="""<tool_description><tool_name>{tool_name}</tool_name><description>{tool_description}</description><parameters>{formatted_parameters}</parameters></tool_description>"""TOOL_PARAMETER_FORMAT="""<parameter><name>{parameter_name}</name><type>{parameter_type}</type><description>{parameter_description}</description></parameter>"""def_get_type(parameter:Dict[str,Any])->str:if"type"inparameter:returnparameter["type"]if"anyOf"inparameter:returnjson.dumps({"anyOf":parameter["anyOf"]})if"allOf"inparameter:returnjson.dumps({"allOf":parameter["allOf"]})returnjson.dumps(parameter)
[docs]defget_system_message(tools:List[Dict])->str:"""Generate a system message that describes the available tools."""tools_data:List[Dict]=[{"tool_name":tool["name"],"tool_description":tool["description"],"formatted_parameters":"\n".join([TOOL_PARAMETER_FORMAT.format(parameter_name=name,parameter_type=_get_type(parameter),parameter_description=parameter.get("description"),)forname,parameterintool["parameters"]["properties"].items()]),}fortoolintools]tools_formatted="\n".join([TOOL_FORMAT.format(tool_name=tool["tool_name"],tool_description=tool["tool_description"],formatted_parameters=tool["formatted_parameters"],)fortoolintools_data])returnSYSTEM_PROMPT_FORMAT.format(formatted_tools=tools_formatted)
def_xml_to_dict(t:Any)->Union[str,Dict[str,Any]]:# Base case: If the element has no children, return its text or an empty string.iflen(t)==0:returnt.textor""# Recursive case: The element has children. Convert them into a dictionary.d:Dict[str,Any]={}forchildint:ifchild.tagnotind:d[child.tag]=_xml_to_dict(child)else:# Handle multiple children with the same tagifnotisinstance(d[child.tag],list):d[child.tag]=[d[child.tag]]# Convert existing entry into a listd[child.tag].append(_xml_to_dict(child))returnddef_xml_to_function_call(invoke:Any,tools:List[Dict])->Dict[str,Any]:name=invoke.find("tool_name").textarguments=_xml_to_dict(invoke.find("parameters"))# make list elements in arguments actually listsfiltered_tools=[toolfortoolintoolsiftool["name"]==name]iflen(filtered_tools)>0andnotisinstance(arguments,str):tool=filtered_tools[0]forkey,valueinarguments.items():ifkeyintool["parameters"]["properties"]:if"type"intool["parameters"]["properties"][key]:iftool["parameters"]["properties"][key]["type"]=="array"andnotisinstance(value,list):arguments[key]=[value]if(tool["parameters"]["properties"][key]["type"]!="object"andisinstance(value,dict)andlen(value.keys())==1):arguments[key]=list(value.values())[0]return{"function":{"name":name,"arguments":json.dumps(arguments),},"type":"function",}def_xml_to_tool_calls(elem:Any,tools:List[Dict])->List[Dict[str,Any]]:""" Convert an XML element and its children into a dictionary of dictionaries. """invokes=elem.findall("invoke")return[_xml_to_function_call(invoke,tools)forinvokeininvokes]
[docs]@deprecated("0.1.5",removal="1.0.0",alternative="ChatAnthropic",message=("Tool-calling is now officially supported by the Anthropic API so this ""workaround is no longer needed."),)classChatAnthropicTools(ChatAnthropic):"""Chat model for interacting with Anthropic functions."""_xmllib:Any=PrivateAttr(default=None)