Skip to content

Instantly share code, notes, and snippets.

@DiegoHernanSalazar
Last active July 8, 2025 00:37
Show Gist options
  • Select an option

  • Save DiegoHernanSalazar/5521f4a49f1c242c7c4945d82e04bd37 to your computer and use it in GitHub Desktop.

Select an option

Save DiegoHernanSalazar/5521f4a49f1c242c7c4945d82e04bd37 to your computer and use it in GitHub Desktop.
DeepLearning.AI - langChain - Tavily: Simple ReAct Agent from Scratch
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"kernelspec": {
"name": "python",
"display_name": "Python (Pyodide)",
"language": "python"
},
"language_info": {
"codemirror_mode": {
"name": "python",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8"
}
},
"nbformat_minor": 5,
"nbformat": 4,
"cells": [
{
"id": "945ba482-5764-495b-aef4-1f16e98a8ba1",
"cell_type": "markdown",
"source": "<img src=\"https://home-wordpress.deeplearning.ai/wp-content/uploads/2024/05/V2_DeepLearning_Langchain_AI-Agents_Banner_2070x1080-1.png\"/>",
"metadata": {}
},
{
"id": "83a2f111-e3ab-4c10-a6fd-254f7c00e126",
"cell_type": "markdown",
"source": "# Lesson 1: Simple ReAct Agent from Scratch",
"metadata": {}
},
{
"id": "6400d5e9-25e5-41fd-b710-7f8d89cc93e4",
"cell_type": "code",
"source": "# based on https://til.simonwillison.net/llms/python-react-pattern",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": 1
},
{
"id": "8331d335-3907-4f55-a79c-f341c06a4668",
"cell_type": "code",
"source": "import openai # Call 'openai' library to interact with REST API\nimport re # Search similar text strings patterns at new strings\nimport httpx # Allows you to make HTTP requests from Python \nimport os # Provides a way to interact with the operating system (os)\n\n# Loads environment variables from a file called '.env'. \n# This function does not return data directly, \n# but loads the variables into the runtime environment. \nfrom dotenv import load_dotenv\n\n# load environment variables from a '.env' file into the \n# current directory or process's environment\n_ = load_dotenv()\n\n# From 'openai' library get 'OpenAI()' function\nfrom openai import OpenAI",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "2a7892a9-d6a9-4b4c-9f2e-eb97757fd3f3",
"cell_type": "code",
"source": "client = OpenAI() # Initialize the Language Model client (obj) \n # 'OpenAI()' function that interacts with \n # OpenAI REST API (OpenAI() Includes the API KEY)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "bf59c288-dfd2-4cfd-8410-dfeb01a04855",
"cell_type": "code",
"source": "# Display the model response content -> 'Text'\nchat_completion.choices[0].message.content",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "51484c09-9eed-4ddc-b408-5566ff83b5e0",
"cell_type": "markdown",
"source": "```\n'Hello! How can I assist you today?'\n```",
"metadata": {}
},
{
"id": "4a68de94-51ce-44df-a397-b7fbc84b854f",
"cell_type": "code",
"source": "# Create the 'Agent' class\nclass Agent:\n \n # We want this agent to be parameterized by a 'system' msg\n # So we'll allow the user to pass that 'system' msg =\"\" in.\n # Initialize our 'Agent' class(obj)\n def __init__(self, system=\"\"):\n \n # So, we'll save 'system' msg=\"\" as an attribute\n # self.system = system = \"\"\n self.system = system\n \n # Init as empty, the list of messages to append \n # ['system', 'user', 'content'] messages at ReAct loop\n self.messages = []\n \n # If 'self.system=system' -> there exist a system msg \n # (NOT empty)\n if self.system:\n \n # Append a new 'system' msg into list of messages []\n # self.messages=[{\"role\": \"system\", \"content\": system}]\n self.messages.append({\"role\": \"system\", \"content\": system})\n \n # The Agent can now be initialized, so it will use the call method\n # Input 'user' msg\n def __call__(self, message):\n \n # Takes 'user' msg that comes in as \"string of text\", and\n # append that 'user' msg into list of messages []\n # self.messages=[{\"role\": \"system\", \"content\": system},\n # -> {\"role\": \"user\", \"content\": message}\n # ]\n self.messages.append({\"role\": \"user\", \"content\": message})\n \n # Run 'execute()' function created below, \n # which returns the assistant/model response/result as \"text\"\n result = self.execute()\n \n # Add model 'response' msg as \"text\", into list of messages []\n # self.messages=[{\"role\": \"system\", \"content\": system},\n # {\"role\": \"user\", \"content\": message},\n # -> {\"role\": \"assistant\", \"content\": result}\n # ]\n self.messages.append({\"role\": \"assistant\", \"content\": result})\n \n # Return this model/assistant response/result\n return result\n \n # Implement 'execute()' method\n def execute(self):\n \n # Generate model/assistant response as \"Text\"\n # calling OpenAI language model, called 'client' model (obj)\n # initialized above.\n completion = client.chat.completions.create(\n model=\"gpt-4o\", # Use model=\"gpt-4o\" \n temperature=0, # Reduce model creativity\n # making it very deterministic\n # to avoid hallucinations\n \n # Add accumulated list of messages \n # self.messages = [\n # {\"role\": \"system\", \"content\": system},\n # {\"role\": \"user\", \"content\": message},\n # {\"role\": \"assistant\", \"content\": result}\n # ]\n messages=self.messages)\n \n # Display model/assistant response content as 'String of Text'\n return completion.choices[0].message.content",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "f442bb26-de03-49fb-aa9e-079f7e23c501",
"cell_type": "code",
"source": "# The '.strip()' method in Python, removes initial and finishing whitespace at a \"text string\".\n# prompt = 'system' msg\n\nprompt = \"\"\"\nYou run in a loop of Thought, Action, PAUSE, Observation.\nAt the end of the loop you output an Answer\nUse Thought to describe your thoughts about the question you have been asked.\nUse Action to run one of the actions available to you - then return PAUSE.\nObservation will be the result of running those actions.\n\nYour available actions are:\n\ncalculate:\ne.g. calculate: 4 * 7 / 3\nRuns a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary\n\naverage_dog_weight:\ne.g. average_dog_weight: Collie\nreturns average weight of a dog when given the breed\n\nExample session:\n\nQuestion: How much does a Bulldog weigh?\nThought: I should look the dogs weight using average_dog_weight\nAction: average_dog_weight: Bulldog\nPAUSE\n\nYou will be called again with this:\n\nObservation: A Bulldog weights 51 lbs\n\nYou then output:\n\nAnswer: A bulldog weights 51 lbs\n\"\"\".strip()",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "f3ae4cf4-5eb3-4f07-aff2-e4928584b0bf",
"cell_type": "code",
"source": "# Takes an input 'String' and compute what is inside,\n# as a pýthon code without \" \" -> eval(\"string\")\n# eval(\"2 ** 8\") -> 256\n# eval(\"1024 + 1024\") -> 2048\n# eval(\"sum([8, 16, 32])\") -> 56\n# x = 100 eval(\"x * 2\") -> 200\ndef calculate(what):\n return eval(what)\n\n# Return the average weight of a specific dog breed\ndef average_dog_weight(name):\n \n # Compare 'strings' so, when name 'string' is included in\n # \"Scottish Terrier\" string\n if name in \"Scottish Terrier\":\n \n # Then return a tuple with \"Scottish Terriers average 20 lbs\"\n # text inside that.\n return(\"Scottish Terriers average 20 lbs\")\n \n # Else if, compare 'strings' so, when name 'string' is\n # included in \"Border Collie\" string\n elif name in \"Border Collie\":\n \n # Then return a tuple with \"a Border Collies average \n # weight is 37 lbs\" text inside that.\n return(\"a Border Collies average weight is 37 lbs\")\n \n # Else if, compare 'strings' so, when name 'string' is\n # included in \"Toy Poodle\" string\n elif name in \"Toy Poodle\":\n \n # Then return a tuple with \"a toy poodles average \n # weight is 7 lbs\" text inside that.\n return(\"a toy poodles average weight is 7 lbs\")\n \n # At every other case, when name 'string' is each other\n else:\n \n # Then return a tuple with \"An average dog weights 50 lbs\"\n # inside that, except the specific case at observation in \n # 'system', when name 'string' is a Bulldog, then return\n # \"A bulldog weights 51 lbs\"\n return(\"An average dog weights 50 lbs\")\n\n# Out of function, create a little dictionary which assigns \n# each created 'function()', to be executed when text/prompt \n# its names -> \"calculate\" or \"average_dog_weight\" \nknown_actions = {\n \"calculate\": calculate,\n \"average_dog_weight\": average_dog_weight\n}",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "fafecbd6-19a3-4974-b652-8c856ca447c5",
"cell_type": "code",
"source": "# 1st/Initial Input prompt = 'system' msg\n# Create 'Agent' class (object) and save as 'abot'\nabot = Agent(prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "71dca79c-8e27-4962-a0b3-22c39d6da175",
"cell_type": "code",
"source": "# Use 'Agent(prompt)' class (object) stored as 'abot(prompt)' \n# and input the 'user' msg prompt / text string\n# abot(user_prompt) = Agent(user_prompt)\nresult = abot(\"How much does a toy poodle weigh?\")\nprint(result)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "fff6c5ba-73ce-477c-baf8-4203bfb7f805",
"cell_type": "markdown",
"source": "```\nThought: I should look up the average weight of a Toy Poodle using the average_dog_weight action.\nAction: average_dog_weight: Toy Poodle\nPAUSE\n```",
"metadata": {}
},
{
"id": "9a151d84-8171-4e40-88e9-7e0464369b41",
"cell_type": "code",
"source": "# Get the returned ‘string’ related to the \"Toy Poodle\" case\nresult = average_dog_weight(\"Toy Poodle\")",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "f080677c-5d7d-4764-927d-aeb86ecc65f6",
"cell_type": "code",
"source": "# Display result\nresult",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "71a9e4e1-fe3a-4e64-8e9a-491fa88f5a02",
"cell_type": "markdown",
"source": "```\n'a toy poodles average weight is 7 lbs'\n```",
"metadata": {}
},
{
"id": "11ed4483-9967-403d-afa7-76b9bba10e25",
"cell_type": "code",
"source": "# Format function 'string' result into the next prompt as 'user' msg prompt\n# \"Observation: {a toy poodles average weight is 7 lbs}\"\nnext_prompt = \"Observation: {}\".format(result)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "ab1cf253-5efc-4082-b206-e736dc2c94ea",
"cell_type": "code",
"source": "# Then pass that into the 'abot(user_prompt)' agent, \n# getting assistant answer\nabot(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "caf06d28-f1d5-4c3d-9795-f5e5bdff9b1a",
"cell_type": "markdown",
"source": "'Answer: A Toy Poodle weighs an average of 7 lbs.'",
"metadata": {}
},
{
"id": "29772d28-7843-4465-812a-ff2b2e1d23da",
"cell_type": "code",
"source": "# Get historic list=[{'role':'system', 'content':'text'}, \n# {'role':'user', 'content':'text'}, \n# {'role':'assistant','content':'text'}] \n# of Agent messages with 'agent_obj.messages' attribute\nabot.messages",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "ea5988ab-ba73-4d2f-a6e4-2275805c0b68",
"cell_type": "markdown",
"source": "```\n[{'role': 'system',\n 'content': 'You run in a loop of Thought, Action, PAUSE, Observation.\\nAt the end of the loop you output an Answer\\nUse Thought to describe your thoughts about the question you have been asked.\\nUse Action to run one of the actions available to you - then return PAUSE.\\nObservation will be the result of running those actions.\\n\\nYour available actions are:\\n\\ncalculate:\\ne.g. calculate: 4 * 7 / 3\\nRuns a calculation and returns the number - uses Python so be sure to use floating point syntax if necessary\\n\\naverage_dog_weight:\\ne.g. average_dog_weight: Collie\\nreturns average weight of a dog when given the breed\\n\\nExample session:\\n\\nQuestion: How much does a Bulldog weigh?\\nThought: I should look the dogs weight using average_dog_weight\\nAction: average_dog_weight: Bulldog\\nPAUSE\\n\\nYou will be called again with this:\\n\\nObservation: A Bulldog weights 51 lbs\\n\\nYou then output:\\n\\nAnswer: A bulldog weights 51 lbs'},\n {'role': 'user', 'content': 'How much does a toy poodle weigh?'},\n {'role': 'assistant',\n 'content': 'Thought: I should look up the average weight of a Toy Poodle using the average_dog_weight action.\\nAction: average_dog_weight: Toy Poodle\\nPAUSE'},\n {'role': 'user',\n 'content': 'Observation: a toy poodles average weight is 7 lbs'},\n {'role': 'assistant',\n 'content': 'Answer: A Toy Poodle weighs an average of 7 lbs.'}]\n```",
"metadata": {}
},
{
"id": "7d34edd9-8e27-498a-bbbc-468c13aa3c92",
"cell_type": "code",
"source": "# Try the Agent again, inputting the 'system' msg again, as 1st prompt,\n# but for a different example. (Reinitialize the Agent), clearing\n# ALL the previous messages, already accumulated.\nabot = Agent(prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "d88c4ad5-f0b8-4018-8b2a-a3d9f389deb2",
"cell_type": "code",
"source": "# Do a new and more complicated question \n# as 'user' msg input of Agent\nquestion = \"\"\"I have 2 dogs, a border collie and a scottish terrier. \\\nWhat is their combined weight\"\"\"\n\n# Then pass that into the 'abot(user_prompt)' agent, \n# to get assistant response.\nabot(question)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "0901d324-bf68-427b-a312-487280b898e6",
"cell_type": "markdown",
"source": "```\n'Thought: I need to find the average weight of both a Border Collie and a Scottish Terrier, then add them together to get the combined weight.\\nAction: average_dog_weight: Border Collie\\nPAUSE'\n```",
"metadata": {}
},
{
"id": "171f2f72-b34f-452b-b170-68882922aa49",
"cell_type": "code",
"source": "# Call the function 'average_dog_weight(\"Border Collie\")'\n# to execute the action ‘string’ related to \"Border Collie\" case\n# as 1st step. Then add this function result -> \n# \"a Border Collies average weight is 37 lbs\" \n# as \"Observation: ...\" and create a New 'user' msg prompt\nnext_prompt = \"Observation: {}\".format(average_dog_weight(\"Border Collie\"))\nprint(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "152a3a1f-34b9-4d32-affc-2eae84b0300d",
"cell_type": "markdown",
"source": "```\nObservation: a Border Collies average weight is 37 lbs\n```",
"metadata": {}
},
{
"id": "cf4564b1-4bf4-42fa-a2a7-77f5a796dbef",
"cell_type": "code",
"source": "# Call the Agent to get its 2nd step response, \n# based on this New 'user' msg prompt, as input -> \n# \"Observation: a Border Collies average weight is 37 lbs\"\nabot(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "34a66323-e395-41f1-9bb1-8845a02c06a6",
"cell_type": "markdown",
"source": "```\n'Action: average_dog_weight: Scottish Terrier\\nPAUSE'\n```",
"metadata": {}
},
{
"id": "34a190c4-3d6c-497d-8428-6b8ce4a84f78",
"cell_type": "code",
"source": "# Call the function 'average_dog_weight(\"Scottish Terrier\")'\n# to execute the action ‘string’ related to \"Scottish Terrier\" case\n# as 2nd step. Then add this function result -> \n# \"Scottish Terriers average 20 lbs\" \n# as \"Observation: ...\" and create a New 'user' msg prompt\nnext_prompt = \"Observation: {}\".format(average_dog_weight(\"Scottish Terrier\"))\n\n# Print out onservation 'string' or New 'user' msg / prompt\nprint(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "8ece7b7d-69a3-473a-b713-b652ddd5ed27",
"cell_type": "markdown",
"source": "```\nObservation: Scottish Terriers average 20 lbs\n```",
"metadata": {}
},
{
"id": "09f43af8-986c-4b8b-acca-fac38b7877a1",
"cell_type": "code",
"source": "# Call the Agent to get a new response, \n# based on this New 'user' msg prompt, as input -> \n# \"Observation: Scottish Terriers average 20 lbs\"\nabot(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "6d41d30a-97ee-4b32-ae74-764d9cac3999",
"cell_type": "markdown",
"source": "```\n'Thought: Now that I have the average weights of both dogs, I can calculate their combined weight by adding the two values together.\\nAction: calculate: 37 + 20\\nPAUSE'\n```",
"metadata": {}
},
{
"id": "9b04b57c-79fc-463b-9171-170053a5b3e2",
"cell_type": "code",
"source": "# Use the 'calculate(\"37 + 20\")' function, to evaluate the code\n# in string \"37+20\" -> eval(\"37+20\") = 37 + 20 = 57\n# Then add this function result -> 57 \n# as \"Observation: 57\" and create a New 'user' msg prompt\nnext_prompt = \"Observation: {}\".format(calculate(\"37 + 20\"))\nprint(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "911b234f-9ac4-4367-8b85-9611cadbbee5",
"cell_type": "markdown",
"source": "```\nObservation: 57\n```",
"metadata": {}
},
{
"id": "44a2d2df-5e41-49cf-85a8-451c43b1ea21",
"cell_type": "code",
"source": "# Call the Agent to get a new response, \n# based on this New 'user' msg prompt, as input -> \n# \"Observation: 57\"\nabot(next_prompt)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "85ef988b-581f-406e-97f7-20983b32a468",
"cell_type": "markdown",
"source": "```\n'Answer: The combined weight of a Border Collie and a Scottish Terrier is 57 lbs.'\n```",
"metadata": {}
},
{
"id": "19c7d7e4-73a8-4ec7-9e49-3532387dff02",
"cell_type": "markdown",
"source": "### Add loop ",
"metadata": {}
},
{
"id": "1dfcb479-c285-442e-a31b-973cb143fb49",
"cell_type": "code",
"source": "# Python regular expression to select action -> ^Action: (\\w+)\n# or final answer : (.*)$ \naction_re = re.compile('^Action: (\\w+): (.*)$')",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "88dfa8a8-675d-43f0-9de8-49608b762258",
"cell_type": "code",
"source": "# question = 'user' msg prompt\n# max_turns=5 -> Main while loop, repeats/runs 5 times.\ndef query(question, max_turns=5):\n \n i = 0 # Init counter to keep track of while iters, until max_turns=5\n bot = Agent(prompt) # Create AI Agent (obj) called 'bot', \n # and initialize it adding default 'system' msg\n \n next_prompt = question # Assign new 'user' msg as prompt/question\n # variable to keep track what we should be passing\n # to the Agent, via prompt <- question.\n \n while i < max_turns: # AI Agent runs question/'user' prompt each iteration\n # i = 0,1,2,3,4 times and finish, while loop.\n \n i += 1 # Counter init as '0' so it's less than max_turns=5 \n # so Update/increment counter i = i (init as 0) + 1\n # (+1) each iter\n \n result = bot(next_prompt) # Add new 'user' msg as prompt/query \n # to AI Agent, and get Assistant result\n # or suggested action\n print(result) # Display Agent response or suggested action\n \n actions = [ # <- Add suggested action into a list [] of actions \n \n action_re.match(a) # Use Regular Expression (REGEX) object\n # to analyze gramatically (parse)\n # the Agent response, by adding each \n # completed sentence or suggested action 'a'\n # that matches (is included in)\n # 'action_re' REGEX object, \n # into list[] of actions\n \n for a in result.split('\\n') # Split Agent response 'String'\n # or suggested action\n # using new line character'\\n' \n # as delimiter, and assign\n # each completed sentence to 'a'\n if action_re.match(a) # When sentence/suggested action 'a' \n # matches or is included inside\n # Regular Expression (REGEX) object\n ] # <- Add suggested action into a list [] of actions\n \n if actions: # When exist a List of actions, based on the Agent response \n # ADD some logic to take those actions and\n # get back an Agent response\n \n # If there is an action inside list [] of ‘actions‘,\n # 1st get the ’action’ or function to be called \n # and the ’action_input’ or 'input string' to that function.\n action, action_input = actions[0].groups()\n \n # When we see an action that is NOT in our list of\n # known 'actions', then we're gonna raise an exception\n if action not in known_actions:\n \n # Raise Exception -> \"Unknown action: {action_func}:{string_input}\"\n raise Exception(\"Unknown action: {}: {}\".format(action, action_input))\n \n # Display actual action being executed -> \n # \" --running {action_func} {string_input}\"\n print(\" -- running {} {}\".format(action, action_input))\n \n # Get the observation 'string' for system, from {known_actions} dictionary -> \n # 'known_actions'[action_func]('string_input') that we should take \n observation = known_actions[action](action_input)\n \n # Display observation 'string' just for debugging \n print(\"Observation:\", observation)\n \n # Pass observation 'string' as our New 'user' msg/prompt -> \n # \"Observation: {string}\" to be sent to LLM the next time\n next_prompt = \"Observation: {}\".format(observation)\n \n else: # If there aren't any actions at list\n return # return anything and end the function there",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "8ecffe49-7d84-4c29-a711-1b96c14a7c1f",
"cell_type": "code",
"source": "# Let's call the Agent on the same complex question that we had above \nquestion = \"\"\"I have 2 dogs, a border collie and a scottish terrier. \\\nWhat is their combined weight\"\"\"\n\n# Call 'query()' function\nquery(question)",
"metadata": {
"trusted": true
},
"outputs": [],
"execution_count": null
},
{
"id": "4d20fef4-f626-4242-8d00-4aeee26a4a27",
"cell_type": "markdown",
"source": "```\nThought: I need to find the average weight of both a Border Collie and a Scottish Terrier, then add them together to get the combined weight.\nAction: average_dog_weight: Border Collie\nPAUSE\n -- running average_dog_weight Border Collie\nObservation: a Border Collies average weight is 37 lbs\nAction: average_dog_weight: Scottish Terrier\nPAUSE\n -- running average_dog_weight Scottish Terrier\nObservation: Scottish Terriers average 20 lbs\nThought: Now that I have the average weights of both dogs, I can calculate their combined weight by adding the two values together.\nAction: calculate: 37 + 20\nPAUSE\n -- running calculate 37 + 20\nObservation: 57\nAnswer: The combined weight of a Border Collie and a Scottish Terrier is 57 lbs.\n```",
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment