From e3e9bf9dd6cf16b9a783638690d4a31914be8139 Mon Sep 17 00:00:00 2001 From: Bill Zhang Date: Wed, 27 Aug 2025 12:09:42 -0700 Subject: [PATCH 1/4] Feat: Guardrail support --- .../10_temporal/010_agent_chat/dev.ipynb | 1042 +++++++++++++---- .../010_agent_chat/project/workflow.py | 104 +- .../lib/adk/providers/_modules/openai.py | 18 + .../lib/core/services/adk/providers/openai.py | 86 +- .../adk/providers/openai_activities.py | 292 ++++- 5 files changed, 1259 insertions(+), 283 deletions(-) diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb index 67a8b58b..83e33dae 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb @@ -32,7 +32,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Task(id='fc5d61ff-b9f5-4898-a5a0-a88433955398', created_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 837621, tzinfo=TzInfo(UTC)), name='e292b96b-task', status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 837621, tzinfo=TzInfo(UTC)))\n" + "Task(id='2cb5e5b7-b8ba-4483-b7d3-635e6524e6d1', created_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 906850, tzinfo=TzInfo(UTC)), name='4f5599a2-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 906850, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -54,7 +54,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 4, "id": "3", "metadata": {}, "outputs": [ @@ -62,7 +62,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Event(id='f3c427de-c8cd-49d5-a062-d7500b9948f7', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1044, task_id='fc5d61ff-b9f5-4898-a5a0-a88433955398', content=TextContent(author='user', content='Hello tell me the latest news about AI and AI startups. Think multiple times per step.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 873787, tzinfo=TzInfo(UTC)))\n" + "Event(id='edc2171e-0a9c-4ace-9ed5-5d85e92130ee', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1836, task_id='2cb5e5b7-b8ba-4483-b7d3-635e6524e6d1', content=TextContent(author='user', content='Find me a recipe on spaghetti', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 940148, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -74,13 +74,14 @@ "# - DataContent: A message with JSON-serializable data content\n", "# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n", "# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n", + "# - ReasoningContent: A message with a reasoning content, which contains a reasoning object from a tool call in its content\n", "\n", "# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n", "\n", "rpc_response = client.agents.send_event(\n", " agent_name=AGENT_NAME,\n", " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello tell me the latest news about AI and AI startups. Think hard and think multiple times per step.\"},\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Find me a recipe on spaghetti\"},\n", " \"task_id\": task.id,\n", " }\n", ")\n", @@ -98,16 +99,14 @@ { "data": { "text/html": [ - "
╭───────────────────────── USER [08/20/2025 22:47:26] ─────────────────────────╮\n",
-       " Hello tell me the latest news about AI and AI startups. Think multiple times \n",
-       " per step.                                                                    \n",
+       "
╭───────────────────────── USER [08/27/2025 19:01:17] ─────────────────────────╮\n",
+       " Find me a recipe on spaghetti                                                \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/20/2025 22:47:26] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m Hello tell me the latest news about AI and AI startups. Think multiple times \u001b[96m│\u001b[0m\n", - "\u001b[96m│\u001b[0m per step. \u001b[96m│\u001b[0m\n", + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 19:01:17] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m Find me a recipe on spaghetti \u001b[96m│\u001b[0m\n", "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -124,34 +123,197 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/20/2025 22:47:34] ─────────────────────────╮\n",
+       "
╭──────────────────────── AGENT [08/27/2025 19:01:18] ─────────────────────────╮\n",
+       " I'm sorry, but I cannot process messages about spaghetti. This guardrail was \n",
+       " put in place for demonstration purposes. Please ask me about something else! \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 19:01:18] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about spaghetti. This guardrail was \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m put in place for demonstration purposes. Please ask me about something else! \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 60 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to the async task messages produced by the agent\n", + "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n", + "\n", + "task_messages = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task, \n", + " only_after_timestamp=event.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=60,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ef4dc388", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='6495fc1f-3775-4d84-9406-c2953a07e36d', created_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 331332, tzinfo=TzInfo(UTC)), name='a6c25875-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 331332, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-task\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task = rpc_response.result\n", + "print(task)" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "1b6f452c", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='aaebf675-11b5-4d7e-b2c9-0574798b6dec', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1840, task_id='6495fc1f-3775-4d84-9406-c2953a07e36d', content=TextContent(author='user', content='Find me the factorial of 31, think about how you will do it.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 361054, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Find me the factorial of 31, think about how you will do it.\"},\n", + " \"task_id\": task.id,\n", + " }\n", + ")\n", + "\n", + "event = rpc_response.result\n", + "print(event)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "350e736b", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 19:02:18] ─────────────────────────╮\n",
+       " Find me the factorial of 31, think about how you will do it.                 \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 19:02:18] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m Find me the factorial of 31, think about how you will do it. \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:25] ─────────────────────────╮\n",
        " 🧠 Reasoning                                                                 \n",
        "                                                                              \n",
-       " Fetching latest AI news                                                      \n",
+       " Considering factorial calculation                                            \n",
        "                                                                              \n",
-       " I’m getting ready to fetch the latest news using the web search tool. I      \n",
-       " think I’ll use the functions available and set it up with the model default. \n",
-       " I’ll choose search input focusing on \"latest AI news August 2025,\"           \n",
-       " especially regarding startups. I’ll consider everything relevant, like       \n",
-       " funding, layoffs, newly launched models, acquisitions, regulations, and      \n",
-       " venture capital. I just need to run the web search now to gather this        \n",
-       " information.                                                                 \n",
+       " The user asked for the factorial of 31, which is a bit tricky. I could use   \n",
+       " the calculator tool, but it only handles two-number arithmetic, while        \n",
+       " calculating a factorial involves multiple multiplications. I think I might   \n",
+       " need to rely on an iterative method or do the math manually. I remember the  \n",
+       " values of smaller factorials like 20! and 21! but should compute carefully   \n",
+       " to ensure accuracy. Let's figure out the best method to obtain the correct   \n",
+       " result.                                                                      \n",
+       "                                                                              \n",
+       " Planning factorial computation                                               \n",
+       "                                                                              \n",
+       " The calculator only accepts two numbers at a time, but I can use iterative   \n",
+       " multiplication to compute the factorial step by step. I should use the       \n",
+       " calculator repeatedly, which is fine as long as I keep it all clear and      \n",
+       " avoid showing my thought process. I can describe my method as multiplying    \n",
+       " integers from 1 to 31, which is a straightforward algorithm. I’ll also refer \n",
+       " to known factorial values, like 10! and 20!, to ensure I get 31! correct.    \n",
+       "                                                                              \n",
+       " Calculating stepwise factorial                                               \n",
+       "                                                                              \n",
+       " I can compute the factorial step by step using functions.calculator, which   \n",
+       " will help ensure accuracy. I need to be careful to avoid revealing my        \n",
+       " thought process too much because the calculator will return just the         \n",
+       " results. I’ll start at 1 and multiply by each integer up to 31, which means  \n",
+       " I’ll make around 30 calls. I can definitely proceed by sequentially calling  \n",
+       " the calculator to get the values I need. Let's get started with this         \n",
+       " approach!                                                                    \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/20/2025 22:47:34] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 19:02:25] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mFetching latest AI news\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mConsidering factorial calculation\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The user asked for the factorial of 31, which is a bit tricky. I could use \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m the calculator tool, but it only handles two-number arithmetic, while \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m calculating a factorial involves multiple multiplications. I think I might \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m need to rely on an iterative method or do the math manually. I remember the \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m values of smaller factorials like 20! and 21! but should compute carefully \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m to ensure accuracy. Let's figure out the best method to obtain the correct \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m result. \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mPlanning factorial computation\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The calculator only accepts two numbers at a time, but I can use iterative \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m multiplication to compute the factorial step by step. I should use the \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m calculator repeatedly, which is fine as long as I keep it all clear and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m avoid showing my thought process. I can describe my method as multiplying \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m integers from 1 to 31, which is a straightforward algorithm. I’ll also refer \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m to known factorial values, like 10! and 20!, to ensure I get 31! correct. \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mCalculating stepwise factorial\u001b[0m \u001b[95m│\u001b[0m\n", "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I’m getting ready to fetch the latest news using the web search tool. I \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m think I’ll use the functions available and set it up with the model default. \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I’ll choose search input focusing on \"latest AI news August 2025,\" \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m especially regarding startups. I’ll consider everything relevant, like \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m funding, layoffs, newly launched models, acquisitions, regulations, and \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m venture capital. I just need to run the web search now to gather this \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m information. \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I can compute the factorial step by step using functions.calculator, which \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m will help ensure accuracy. I need to be careful to avoid revealing my \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m thought process too much because the calculator will return just the \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m results. I’ll start at 1 and multiply by each integer up to 31, which means \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I’ll make around 30 calls. I can definitely proceed by sequentially calling \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m the calculator to get the values I need. Let's get started with this \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m approach! \u001b[95m│\u001b[0m\n", "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -168,36 +330,32 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/20/2025 22:47:36] ─────────────────────────╮\n",
-       " 🔧 Tool Request: web_search                                                  \n",
+       "
╭──────────────────────── AGENT [08/27/2025 19:02:35] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
        "                                                                              \n",
        " Arguments:                                                                   \n",
        "                                                                              \n",
        "                                                                              \n",
        "  {                                                                           \n",
-       "    \"input\": \"latest AI news August 2025 AI startups funding layoffs          \n",
-       "  acquisitions new models regulation venture capital August 2025\",            \n",
-       "    \"model\": \"gpt-4o-mini\",                                                   \n",
-       "    \"type\": \"web_search_preview\",                                             \n",
-       "    \"search_context_size\": \"high\"                                             \n",
+       "    \"a\": 1,                                                                   \n",
+       "    \"b\": 2,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
        "  }                                                                           \n",
        "                                                                              \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/20/2025 22:47:36] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: web_search\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:35] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"input\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"latest AI news August 2025 AI startups funding layoffs \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisitions new models regulation venture capital August 2025\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"model\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"gpt-4o-mini\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"type\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"web_search_preview\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"search_context_size\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"high\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m1\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m2\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" @@ -216,196 +374,644 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/20/2025 22:47:47] ─────────────────────────╮\n",
-       "Tool Response: web_search                                                 \n",
+       "
╭──────────────────────── AGENT [08/27/2025 19:02:35] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
        "                                                                              \n",
-       " Response:                                                                    \n",
+       " The result of 1.0 multiply 2.0 is 2                                          \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:35] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 1.0 multiply 2.0 is 2 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:38] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 2,                                                                   \n",
+       "    \"b\": 3,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:38] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m2\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:38] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
        "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"type\": \"text\",                                                           \n",
-       "    \"text\": \"As of August 20, 2025, the artificial intelligence (AI) sector   \n",
-       "  has experienced significant developments across funding, acquisitions,      \n",
-       "  layoffs, new model releases, and regulatory changes. Here's an overview of  \n",
-       "  the latest AI news:\\n\\n**Funding and Acquisitions:**\\n\\n- **TinyFish's $47  \n",
-       "  Million Series A Funding:** TinyFish, an AI startup specializing in         \n",
-       "  automating complex online tasks for enterprises, secured $47 million in a   \n",
-       "  Series A funding round led by ICONIQ Capital. The investment aims to enhan  \n",
-       "  product development and expand market reach.                                \n",
-       "  ([reuters.com](https://www.reuters.com/technology/ai-agent-startup-tinyfis  \n",
-       "  raises-47-million-iconiq-led-round-2025-08-20/?utm_source=openai))\\n\\n-     \n",
-       "  **Databricks' Valuation Surge:** Databricks, a San Francisco-based analyti  \n",
-       "  company, is poised to surpass a $100 billion valuation in its upcoming      \n",
-       "  funding round. This reflects strong investor enthusiasm for AI ventures,    \n",
-       "  with plans to advance product development and pursue mergers and            \n",
-       "  acquisitions within the AI space.                                           \n",
-       "  ([reuters.com](https://www.reuters.com/business/databricks-eyes-over-100-b  \n",
-       "  lion-valuation-investors-back-ai-growth-plans-2025-08-19/?utm_source=opena  \n",
-       "  )\\n\\n- **OpenAI's Acquisition of io:** OpenAI announced the $6.5 billion    \n",
-       "  acquisition of io, an AI hardware startup founded by former Apple designer  \n",
-       "  Jony Ive. The merger aims to integrate hardware and software development,   \n",
-       "  with Ive assuming creative responsibilities across OpenAI.                  \n",
-       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/OpenAI?utm_source=openai  \n",
-       "  \\n\\n**Layoffs:**\\n\\n- **Recruit Holdings' Workforce Reduction:** Recruit    \n",
-       "  Holdings, the parent company of Indeed and Glassdoor, is laying off         \n",
-       "  approximately 1,300 employees, about 6% of its HR technology unit. This mo  \n",
-       "  is part of a strategic shift toward integrating AI technologies and         \n",
-       "  streamlining operations.                                                    \n",
-       "  ([linkedin.com](https://www.linkedin.com/pulse/ai-news-funding-updates-fro  \n",
-       "  last-24-hours11th-july-2025-anshuman-jha-2d20c?utm_source=openai))\\n\\n-     \n",
-       "  **Meta's Staff Reduction:** Meta announced a 5% reduction in its workforce  \n",
-       "  targeting \\\"low performers\\\" as the company prepares for an \\\"intense       \n",
-       "  year.\\\" This decision reflects ongoing efforts to optimize operations amid  \n",
-       "  evolving market conditions.                                                 \n",
-       "  ([techcrunch.com](https://techcrunch.com/2025/07/31/tech-layoffs-2025-list  \n",
-       "  utm_source=openai))\\n\\n**New AI Models:**\\n\\n- **OpenAI's GPT-5 Release:**  \n",
-       "  OpenAI released GPT-5, the latest iteration of its language model, offerin  \n",
-       "  enhanced capabilities and performance. This release signifies continued     \n",
-       "  advancements in AI language processing.                                     \n",
-       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel  \n",
-       "  gence?utm_source=openai))\\n\\n- **Google's A.I. Mode and Veo 3:** Google     \n",
-       "  introduced A.I. Mode, a feature on its search engine powered by the Gemini  \n",
-       "  model, and Veo 3, a new state-of-the-art video generation model. These      \n",
-       "  developments highlight Google's commitment to integrating advanced AI into  \n",
-       "  its services.                                                               \n",
-       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel  \n",
-       "  gence?utm_source=openai))\\n\\n**Regulatory Developments:**\\n\\n- **U.S.       \n",
-       "  Federal AI Regulation Freeze:** The U.S. federal government has implemente  \n",
-       "  a 10-year freeze on state-level AI regulation, preventing individual state  \n",
-       "  from enacting rules governing AI systems. This move aims to establish a     \n",
-       "  unified federal approach to AI governance.                                  \n",
-       "  ([techradar.com](https://www.techradar.com/pro/the-u-s-is-blocking-state-a  \n",
-       "  regulation-heres-what-that-means-for-every-business?utm_source=openai))\\n\\  \n",
-       "   **European Union's AI Act Implementation:** The EU's Artificial            \n",
-       "  Intelligence Act, which came into force on August 1, 2024, is set to be     \n",
-       "  fully applicable by August 2, 2025. The Act establishes a regulatory        \n",
-       "  framework for AI, categorizing applications based on risk levels and        \n",
-       "  imposing corresponding obligations.                                         \n",
-       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/Artificial_Intelligence_  \n",
-       "  t?utm_source=openai))\\n\\n**Venture Capital Trends:**\\n\\n- **Continued       \n",
-       "  Investment in AI Startups:** Venture capital investment in AI companies     \n",
-       "  remains robust, with global funding exceeding $100 billion in 2024, markin  \n",
-       "  an 80% increase from the previous year. This trend underscores the growing  \n",
-       "  confidence in AI's transformative potential across various sectors.         \n",
-       "  ([natlawreview.com](https://natlawreview.com/article/state-funding-market-  \n",
-       "  -companies-2024-2025-outlook?utm_source=openai))\\n\\nThese developments      \n",
-       "  reflect the dynamic and rapidly evolving landscape of the AI industry,      \n",
-       "  encompassing significant financial investments, strategic corporate         \n",
-       "  decisions, technological advancements, and regulatory shifts.\\n\\n\\n## Rece  \n",
-       "  Developments in AI Industry:\\n- [AI agent startup TinyFish raises $47       \n",
-       "  million in ICONIQ-led                                                       \n",
-       "  round](https://www.reuters.com/technology/ai-agent-startup-tinyfish-raises  \n",
-       "  7-million-iconiq-led-round-2025-08-20/?utm_source=openai)\\n- [Databricks    \n",
-       "  eyes over $100 billion valuation as investors back AI growth                \n",
-       "  plans](https://www.reuters.com/business/databricks-eyes-over-100-billion-v  \n",
-       "  uation-investors-back-ai-growth-plans-2025-08-19/?utm_source=openai)\\n- [T  \n",
-       "  U.S. is blocking state AI regulation. Here's what that means for every      \n",
-       "  business](https://www.techradar.com/pro/the-u-s-is-blocking-state-ai-regul  \n",
-       "  ion-heres-what-that-means-for-every-business?utm_source=openai) \",          \n",
-       "    \"annotations\": null,                                                      \n",
-       "    \"meta\": null                                                              \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
+       " The result of 2.0 multiply 3.0 is 6                                          \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/20/2025 22:47:47] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: web_search\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:38] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[1mResponse:\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 2.0 multiply 3.0 is 6 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:40] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 6,                                                                   \n",
+       "    \"b\": 4,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:40] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m6\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m4\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:40] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 6.0 multiply 4.0 is 24                                         \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:40] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"type\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"text\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"text\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"As of August 20, 2025, the artificial intelligence (AI) sector \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mhas experienced significant developments across funding, acquisitions, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlayoffs, new model releases, and regulatory changes. Here's an overview of\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mthe latest AI news:\\n\\n**Funding and Acquisitions:**\\n\\n- **TinyFish's $47\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mMillion Series A Funding:** TinyFish, an AI startup specializing in \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mautomating complex online tasks for enterprises, secured $47 million in a \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mSeries A funding round led by ICONIQ Capital. The investment aims to enhan\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mproduct development and expand market reach. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([reuters.com](https://www.reuters.com/technology/ai-agent-startup-tinyfis\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mraises-47-million-iconiq-led-round-2025-08-20/?utm_source=openai))\\n\\n- \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m**Databricks' Valuation Surge:** Databricks, a San Francisco-based analyti\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mcompany, is poised to surpass a $100 billion valuation in its upcoming \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfunding round. This reflects strong investor enthusiasm for AI ventures, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mwith plans to advance product development and pursue mergers and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisitions within the AI space. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([reuters.com](https://www.reuters.com/business/databricks-eyes-over-100-b\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlion-valuation-investors-back-ai-growth-plans-2025-08-19/?utm_source=opena\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m)\\n\\n- **OpenAI's Acquisition of io:** OpenAI announced the $6.5 billion \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisition of io, an AI hardware startup founded by former Apple designer\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mJony Ive. The merger aims to integrate hardware and software development, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mwith Ive assuming creative responsibilities across OpenAI. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/OpenAI?utm_source=openai\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\\n\\n**Layoffs:**\\n\\n- **Recruit Holdings' Workforce Reduction:** Recruit \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mHoldings, the parent company of Indeed and Glassdoor, is laying off \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mapproximately 1,300 employees, about 6% of its HR technology unit. This mo\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mis part of a strategic shift toward integrating AI technologies and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mstreamlining operations. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([linkedin.com](https://www.linkedin.com/pulse/ai-news-funding-updates-fro\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlast-24-hours11th-july-2025-anshuman-jha-2d20c?utm_source=openai))\\n\\n- \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m**Meta's Staff Reduction:** Meta announced a 5% reduction in its workforce\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mtargeting \\\"low performers\\\" as the company prepares for an \\\"intense \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34myear.\\\" This decision reflects ongoing efforts to optimize operations amid\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mevolving market conditions. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([techcrunch.com](https://techcrunch.com/2025/07/31/tech-layoffs-2025-list\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mutm_source=openai))\\n\\n**New AI Models:**\\n\\n- **OpenAI's GPT-5 Release:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mOpenAI released GPT-5, the latest iteration of its language model, offerin\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34menhanced capabilities and performance. This release signifies continued \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34madvancements in AI language processing. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mgence?utm_source=openai))\\n\\n- **Google's A.I. Mode and Veo 3:** Google \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mintroduced A.I. Mode, a feature on its search engine powered by the Gemini\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mmodel, and Veo 3, a new state-of-the-art video generation model. These \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mdevelopments highlight Google's commitment to integrating advanced AI into\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mits services. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mgence?utm_source=openai))\\n\\n**Regulatory Developments:**\\n\\n- **U.S. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mFederal AI Regulation Freeze:** The U.S. federal government has implemente\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34ma 10-year freeze on state-level AI regulation, preventing individual state\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfrom enacting rules governing AI systems. This move aims to establish a \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34munified federal approach to AI governance. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([techradar.com](https://www.techradar.com/pro/the-u-s-is-blocking-state-a\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mregulation-heres-what-that-means-for-every-business?utm_source=openai))\\n\\\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m **European Union's AI Act Implementation:** The EU's Artificial \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mIntelligence Act, which came into force on August 1, 2024, is set to be \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfully applicable by August 2, 2025. The Act establishes a regulatory \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mframework for AI, categorizing applications based on risk levels and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mimposing corresponding obligations. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/Artificial_Intelligence_\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mt?utm_source=openai))\\n\\n**Venture Capital Trends:**\\n\\n- **Continued \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mInvestment in AI Startups:** Venture capital investment in AI companies \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mremains robust, with global funding exceeding $100 billion in 2024, markin\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34man 80% increase from the previous year. This trend underscores the growing\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mconfidence in AI's transformative potential across various sectors. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([natlawreview.com](https://natlawreview.com/article/state-funding-market-\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m-companies-2024-2025-outlook?utm_source=openai))\\n\\nThese developments \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mreflect the dynamic and rapidly evolving landscape of the AI industry, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mencompassing significant financial investments, strategic corporate \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mdecisions, technological advancements, and regulatory shifts.\\n\\n\\n## Rece\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mDevelopments in AI Industry:\\n- [AI agent startup TinyFish raises $47 \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mmillion in ICONIQ-led \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mround](https://www.reuters.com/technology/ai-agent-startup-tinyfish-raises\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m7-million-iconiq-led-round-2025-08-20/?utm_source=openai)\\n- [Databricks \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34meyes over $100 billion valuation as investors back AI growth \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mplans](https://www.reuters.com/business/databricks-eyes-over-100-billion-v\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34muation-investors-back-ai-growth-plans-2025-08-19/?utm_source=openai)\\n- [T\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mU.S. is blocking state AI regulation. Here's what that means for every \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mbusiness](https://www.techradar.com/pro/the-u-s-is-blocking-state-ai-regul\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mion-heres-what-that-means-for-every-business?utm_source=openai) \"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"annotations\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;102;217;239;48;2;39;40;34mnull\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"meta\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;102;217;239;48;2;39;40;34mnull\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 6.0 multiply 4.0 is 24 \u001b[92m│\u001b[0m\n", "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:42] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 24,                                                                  \n",
+       "    \"b\": 5,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:42] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m24\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:42] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 24.0 multiply 5.0 is 120                                       \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:42] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 24.0 multiply 5.0 is 120 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:44] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 120,                                                                 \n",
+       "    \"b\": 6,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:44] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m120\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m6\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:44] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 120.0 multiply 6.0 is 720                                      \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:44] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 120.0 multiply 6.0 is 720 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:45] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 720,                                                                 \n",
+       "    \"b\": 7,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:45] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m720\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m7\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:45] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 720.0 multiply 7.0 is 5040                                     \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:45] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 720.0 multiply 7.0 is 5040 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:47] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 5040,                                                                \n",
+       "    \"b\": 8,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:47] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5040\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m8\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:47] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 5040.0 multiply 8.0 is 40320                                   \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:47] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 5040.0 multiply 8.0 is 40320 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:48] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 40320,                                                               \n",
+       "    \"b\": 9,                                                                   \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:48] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m40320\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m9\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:48] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 40320.0 multiply 9.0 is 362880                                 \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:48] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 40320.0 multiply 9.0 is 362880 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:51] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 362880,                                                              \n",
+       "    \"b\": 10,                                                                  \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:51] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m362880\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m10\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:51] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 362880.0 multiply 10.0 is 3628800                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:51] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 362880.0 multiply 10.0 is 3628800 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 19:02:53] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 3628800,                                                             \n",
+       "    \"b\": 11,                                                                  \n",
+       "    \"operation\": \"multiply\"                                                   \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:53] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3628800\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m11\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, { "name": "stdout", "output_type": "stream", diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py index 2ef81323..0dc557ac 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py @@ -20,9 +20,12 @@ from agentex.lib.types.tracing import SGPTracingProcessorConfig from agentex.lib.environment_variables import EnvironmentVariables from agentex.types.text_content import TextContent -from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( +from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # noqa: E501 FunctionTool, + TemporalInputGuardrail, ) +from agents.guardrail import GuardrailFunctionOutput +from agents import Agent environment_variables = EnvironmentVariables.refresh() load_dotenv(dotenv_path=".env") @@ -123,12 +126,55 @@ async def calculator(context: RunContextWrapper, args: str) -> str: return f"Error: An unexpected error occurred: {str(e)}" +# Define the spaghetti guardrail function +async def check_spaghetti_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + input: str | list +) -> GuardrailFunctionOutput: + """ + A simple guardrail that checks if 'spaghetti' is mentioned in the input. + """ + # Convert input to string to check + input_text = "" + if isinstance(input, str): + input_text = input.lower() + elif isinstance(input, list): + # For list of messages, check all user messages + for msg in input: + if isinstance(msg, dict) and msg.get("role") == "user": + content = msg.get("content", "") + if isinstance(content, str): + input_text += " " + content.lower() + + # Check if spaghetti is mentioned + contains_spaghetti = "spaghetti" in input_text + + return GuardrailFunctionOutput( + output_info={ + "contains_spaghetti": contains_spaghetti, + "checked_text": ( + input_text[:200] + "..." + if len(input_text) > 200 else input_text + ) + }, + tripwire_triggered=contains_spaghetti + ) + + +# Create the input guardrail +SPAGHETTI_GUARDRAIL = TemporalInputGuardrail( + guardrail_function=check_spaghetti_guardrail, + name="spaghetti_guardrail" +) + + # Create the calculator tool CALCULATOR_TOOL = FunctionTool( name="calculator", description=( - "Performs basic arithmetic operations (add, subtract, multiply, divide) " - "on two numbers." + "Performs basic arithmetic operations (add, subtract, multiply, " + "divide) on two numbers." ), params_json_schema={ "type": "object", @@ -190,7 +236,9 @@ async def on_task_event_send(self, params: SendEventParams) -> None: name=f"Turn {self._state.turn_number}", input=self._state, ) as span: - # Echo back the user's message so it shows up in the UI. This is not done by default so the agent developer has full control over what is shown to the user. + # Echo back the user's message so it shows up in the UI. + # This is not done by default so the agent developer has full + # control over what is shown to the user. await adk.messages.create( task_id=params.task.id, trace_id=params.task.id, @@ -219,33 +267,37 @@ async def on_task_event_send(self, params: SendEventParams) -> None: # Call an LLM to respond to the user's message # When send_as_agent_task_message=True, returns a TaskMessage - run_result = await adk.providers.openai.run_agent_streamed_auto_send( + result = await adk.providers.openai.run_agent_streamed_auto_send( task_id=params.task.id, trace_id=params.task.id, input_list=self._state.input_list, mcp_server_params=MCP_SERVERS, agent_name="Tool-Enabled Assistant", agent_instructions=( - "You are a helpful assistant that can answer questions " - "using various tools. You have access to sequential " - "thinking and web search capabilities through MCP servers, " - "as well as a calculator tool for performing basic " - "arithmetic operations. Use these tools when appropriate " - "to provide accurate and well-reasoned responses." + "You are a helpful assistant that can answer " + "questions using various tools. You have access to " + "sequential thinking and web search capabilities " + "through MCP servers, as well as a calculator tool " + "for performing basic arithmetic operations. Use " + "these tools when appropriate to provide accurate " + "and well-reasoned responses." ), parent_span_id=span.id if span else None, model="gpt-5-mini", model_settings=ModelSettings( - # Include reasoning items in the response (IDs, summaries) + # Include reasoning items in the response + # (IDs, summaries) # response_include=["reasoning.encrypted_content"], # Ask the model to include a short reasoning summary reasoning=Reasoning(effort="medium", summary="detailed"), ), - # tools=[CALCULATOR_TOOL], + tools=[CALCULATOR_TOOL], + input_guardrails=[SPAGHETTI_GUARDRAIL], ) - if self._state: - # Update the state with the final input list if available - final_list = getattr(run_result, "final_input_list", None) + + # Update state with the final input list from result + if self._state and result: + final_list = getattr(result, "final_input_list", None) if final_list is not None: self._state.input_list = final_list @@ -258,19 +310,27 @@ async def on_task_event_send(self, params: SendEventParams) -> None: async def on_task_create(self, params: CreateTaskParams) -> None: logger.info(f"Received task create params: {params}") - # 1. Initialize the state. You can either do this here or in the __init__ method. - # This function is triggered whenever a client creates a task for this agent. - # It is not re-triggered when a new event is sent to the task. + # 1. Initialize the state. You can either do this here or in the + # __init__ method. This function is triggered whenever a client + # creates a task for this agent. It is not re-triggered when a new + # event is sent to the task. self._state = StateModel( input_list=[], turn_number=0, ) - # 2. Wait for the task to be completed indefinitely. If we don't do this the workflow will close as soon as this function returns. Temporal can run hundreds of millions of workflows in parallel, so you don't need to worry about too many workflows running at once. + # 2. Wait for the task to be completed indefinitely. If we don't do + # this the workflow will close as soon as this function returns. + # Temporal can run hundreds of millions of workflows in parallel, + # so you don't need to worry about too many workflows running at once. - # Thus, if you want this agent to field events indefinitely (or for a long time) you need to wait for a condition to be met. + # Thus, if you want this agent to field events indefinitely (or for + # a long time) you need to wait for a condition to be met. await workflow.wait_condition( lambda: self._complete_task, - timeout=None, # Set a timeout if you want to prevent the task from running indefinitely. Generally this is not needed. Temporal can run hundreds of millions of workflows in parallel and more. Only do this if you have a specific reason to do so. + timeout=None, # Set a timeout if you want to prevent the task + # from running indefinitely. Generally this is not needed. + # Temporal can run hundreds of millions of workflows in parallel + # and more. Only do this if you have a specific reason to do so. ) diff --git a/src/agentex/lib/adk/providers/_modules/openai.py b/src/agentex/lib/adk/providers/_modules/openai.py index 2199cf36..b3840fab 100644 --- a/src/agentex/lib/adk/providers/_modules/openai.py +++ b/src/agentex/lib/adk/providers/_modules/openai.py @@ -4,6 +4,7 @@ from agentex.lib.adk.utils._modules.client import create_async_agentex_client from agents import Agent, RunResult, RunResultStreaming from agents.agent import StopAtTools, ToolsToFinalOutputFunction +from agents.guardrail import InputGuardrail, OutputGuardrail from agents.agent_output import AgentOutputSchemaBase from agents.model_settings import ModelSettings from agents.tool import Tool @@ -263,6 +264,9 @@ async def run_agent_streamed( | StopAtTools | ToolsToFinalOutputFunction ) = "run_llm_again", + mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> RunResultStreaming: """ Run an agent with streaming enabled but no TaskMessage creation. @@ -289,6 +293,9 @@ async def run_agent_streamed( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. + mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on initial user input. + output_guardrails: Optional list of output guardrails to run on final agent output. Returns: RunResultStreaming: The result of the agent run with streaming. @@ -318,6 +325,9 @@ async def run_agent_streamed( tools=tools, output_type=output_type, tool_use_behavior=tool_use_behavior, + mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) async def run_agent_streamed_auto_send( @@ -337,6 +347,8 @@ async def run_agent_streamed_auto_send( model: str | None = None, model_settings: ModelSettings | None = None, tools: list[Tool] | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, output_type: type[Any] | AgentOutputSchemaBase | None = None, tool_use_behavior: ( Literal["run_llm_again", "stop_on_first_tool"] @@ -364,6 +376,8 @@ async def run_agent_streamed_auto_send( model: Optional model to use. model_settings: Optional model settings. tools: Optional list of tools. + input_guardrails: Optional list of input guardrails to run on initial user input. + output_guardrails: Optional list of output guardrails to run on final agent output. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. @@ -388,6 +402,8 @@ async def run_agent_streamed_auto_send( output_type=output_type, tool_use_behavior=tool_use_behavior, mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) return await ActivityHelpers.execute_activity( activity_name=OpenAIActivityName.RUN_AGENT_STREAMED_AUTO_SEND, @@ -414,4 +430,6 @@ async def run_agent_streamed_auto_send( output_type=output_type, tool_use_behavior=tool_use_behavior, mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) diff --git a/src/agentex/lib/core/services/adk/providers/openai.py b/src/agentex/lib/core/services/adk/providers/openai.py index 8206ad6f..72948106 100644 --- a/src/agentex/lib/core/services/adk/providers/openai.py +++ b/src/agentex/lib/core/services/adk/providers/openai.py @@ -5,13 +5,14 @@ from agents import Agent, Runner, RunResult, RunResultStreaming from agents.agent import StopAtTools, ToolsToFinalOutputFunction +from agents.guardrail import InputGuardrail, OutputGuardrail +from agents.exceptions import InputGuardrailTripwireTriggered from agents.mcp import MCPServerStdio from mcp import StdioServerParameters from openai.types.responses import ( ResponseCompletedEvent, ResponseFunctionToolCall, ResponseOutputItemDoneEvent, - ResponseReasoningSummaryPartDoneEvent, ResponseTextDeltaEvent, ResponseReasoningSummaryTextDeltaEvent, ResponseReasoningSummaryTextDoneEvent, @@ -104,6 +105,8 @@ async def run_agent( | ToolsToFinalOutputFunction ) = "run_llm_again", mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> RunResult: """ Run an agent without streaming or TaskMessage creation. @@ -122,8 +125,12 @@ async def run_agent( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. - mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. - + mcp_timeout_seconds: Optional param to set the timeout threshold + for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on + initial user input. + output_guardrails: Optional list of output guardrails to run on + final agent output. Returns: SerializableRunResult: The result of the agent run. """ @@ -174,6 +181,10 @@ async def run_agent( agent_kwargs["model_settings"] = ( model_settings.to_oai_model_settings() ) + if input_guardrails is not None: + agent_kwargs["input_guardrails"] = input_guardrails + if output_guardrails is not None: + agent_kwargs["output_guardrails"] = output_guardrails agent = Agent(**agent_kwargs) @@ -214,6 +225,8 @@ async def run_agent_auto_send( | ToolsToFinalOutputFunction ) = "run_llm_again", mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> RunResult: """ Run an agent with automatic TaskMessage creation. @@ -234,7 +247,8 @@ async def run_agent_auto_send( output_type: Optional output type. tool_use_behavior: Optional tool use behavior. mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. - + input_guardrails: Optional list of input guardrails to run on initial user input. + output_guardrails: Optional list of output guardrails to run on final agent output. Returns: SerializableRunResult: The result of the agent run. """ @@ -290,6 +304,10 @@ async def run_agent_auto_send( agent_kwargs["model_settings"] = ( model_settings.to_oai_model_settings() ) + if input_guardrails is not None: + agent_kwargs["input_guardrails"] = input_guardrails + if output_guardrails is not None: + agent_kwargs["output_guardrails"] = output_guardrails agent = Agent(**agent_kwargs) @@ -402,6 +420,8 @@ async def run_agent_streamed( | ToolsToFinalOutputFunction ) = "run_llm_again", mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> RunResultStreaming: """ Run an agent with streaming enabled but no TaskMessage creation. @@ -420,8 +440,12 @@ async def run_agent_streamed( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. - mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. - + mcp_timeout_seconds: Optional param to set the timeout threshold + for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on + initial user input. + output_guardrails: Optional list of output guardrails to run on + final agent output. Returns: RunResultStreaming: The result of the agent run with streaming. """ @@ -471,6 +495,10 @@ async def run_agent_streamed( agent_kwargs["model_settings"] = ( model_settings.to_oai_model_settings() ) + if input_guardrails is not None: + agent_kwargs["input_guardrails"] = input_guardrails + if output_guardrails is not None: + agent_kwargs["output_guardrails"] = output_guardrails agent = Agent(**agent_kwargs) @@ -511,6 +539,8 @@ async def run_agent_streamed_auto_send( | ToolsToFinalOutputFunction ) = "run_llm_again", mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> RunResultStreaming: """ Run an agent with streaming enabled and automatic TaskMessage creation. @@ -530,7 +560,12 @@ async def run_agent_streamed_auto_send( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. - mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. + mcp_timeout_seconds: Optional param to set the timeout threshold + for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on + initial user input. + output_guardrails: Optional list of output guardrails to run on + final agent output. Returns: RunResultStreaming: The result of the agent run with streaming. @@ -589,6 +624,10 @@ async def run_agent_streamed_auto_send( agent_kwargs["model_settings"] = ( model_settings.to_oai_model_settings() ) + if input_guardrails is not None: + agent_kwargs["input_guardrails"] = input_guardrails + if output_guardrails is not None: + agent_kwargs["output_guardrails"] = output_guardrails agent = Agent(**agent_kwargs) @@ -829,6 +868,39 @@ async def run_agent_streamed_auto_send( await streaming_context.close() unclosed_item_ids.discard(item_id) + except InputGuardrailTripwireTriggered as e: + # Handle guardrail trigger by sending a rejection message + rejection_message = ( + "I'm sorry, but I cannot process messages about spaghetti. " + "This guardrail was put in place for demonstration purposes. " + "Please ask me about something else!" + ) + + # Create and send the rejection message as a TaskMessage + async with ( + self.streaming_service.streaming_task_message_context( + task_id=task_id, + initial_content=TextContent( + author="agent", + content=rejection_message, + ), + ) as streaming_context + ): + # Send the full message + await streaming_context.stream_update( + update=StreamTaskMessageFull( + parent_task_message=streaming_context.task_message, + content=TextContent( + author="agent", + content=rejection_message, + ), + type="full", + ), + ) + + # Re-raise to let the activity handle it + raise + finally: # Cleanup: ensure all streaming contexts for this session are properly finished # Create a copy to avoid modifying set during iteration diff --git a/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py b/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py index a53c6ecf..57ab0f56 100644 --- a/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py +++ b/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py @@ -3,12 +3,14 @@ from collections.abc import Callable from contextlib import AsyncExitStack, asynccontextmanager from enum import Enum -from typing import Any, Literal, Optional, override +from typing import Any, Literal, Optional from pydantic import Field, PrivateAttr import cloudpickle from agents import RunContextWrapper, RunResult, RunResultStreaming +from agents.guardrail import InputGuardrail, OutputGuardrail +from agents.exceptions import InputGuardrailTripwireTriggered from agents.mcp import MCPServerStdio, MCPServerStdioParams from agents.model_settings import ModelSettings as OAIModelSettings from agents.tool import FunctionTool as OAIFunctionTool @@ -16,7 +18,6 @@ from openai.types.responses.response_includable import ResponseIncludable from openai.types.shared.reasoning import Reasoning from temporalio import activity - from agentex.lib.core.services.adk.providers.openai import OpenAIService # Local imports @@ -133,6 +134,150 @@ def to_oai_function_tool(self) -> OAIFunctionTool: return OAIFunctionTool(**data) +class TemporalInputGuardrail(BaseModelWithTraceParams): + """Temporal-compatible wrapper for InputGuardrail with function + serialization.""" + name: str + _guardrail_function: Callable = PrivateAttr() + guardrail_function_serialized: str = Field( + default="", + description=( + "Serialized guardrail function. Set automatically during initialization. " + "Pass `guardrail_function` to the constructor instead." + ), + ) + + def __init__( + self, + *, + guardrail_function: Optional[Callable] = None, + **data, + ): + """Initialize with function serialization support for Temporal.""" + super().__init__(**data) + if not guardrail_function: + if not self.guardrail_function_serialized: + raise ValueError( + "One of `guardrail_function` or " + "`guardrail_function_serialized` should be set" + ) + else: + guardrail_function = self._deserialize_callable( + self.guardrail_function_serialized + ) + else: + self.guardrail_function_serialized = self._serialize_callable( + guardrail_function + ) + + self._guardrail_function = guardrail_function + + @classmethod + def _deserialize_callable(cls, serialized: str) -> Callable: + encoded = serialized.encode() + serialized_bytes = base64.b64decode(encoded) + return cloudpickle.loads(serialized_bytes) + + @classmethod + def _serialize_callable(cls, func: Callable) -> str: + serialized_bytes = cloudpickle.dumps(func) + encoded = base64.b64encode(serialized_bytes) + return encoded.decode() + + @property + def guardrail_function(self) -> Callable: + if (self._guardrail_function is None and + self.guardrail_function_serialized): + self._guardrail_function = self._deserialize_callable( + self.guardrail_function_serialized + ) + return self._guardrail_function + + @guardrail_function.setter + def guardrail_function(self, value: Callable): + self.guardrail_function_serialized = self._serialize_callable(value) + self._guardrail_function = value + + def to_oai_input_guardrail(self) -> InputGuardrail: + """Convert to OpenAI InputGuardrail.""" + return InputGuardrail( + guardrail_function=self.guardrail_function, + name=self.name + ) + + +class TemporalOutputGuardrail(BaseModelWithTraceParams): + """Temporal-compatible wrapper for OutputGuardrail with function + serialization.""" + name: str + _guardrail_function: Callable = PrivateAttr() + guardrail_function_serialized: str = Field( + default="", + description=( + "Serialized guardrail function. Set automatically during initialization. " + "Pass `guardrail_function` to the constructor instead." + ), + ) + + def __init__( + self, + *, + guardrail_function: Optional[Callable] = None, + **data, + ): + """Initialize with function serialization support for Temporal.""" + super().__init__(**data) + if not guardrail_function: + if not self.guardrail_function_serialized: + raise ValueError( + "One of `guardrail_function` or " + "`guardrail_function_serialized` should be set" + ) + else: + guardrail_function = self._deserialize_callable( + self.guardrail_function_serialized + ) + else: + self.guardrail_function_serialized = self._serialize_callable( + guardrail_function + ) + + self._guardrail_function = guardrail_function + + @classmethod + def _deserialize_callable(cls, serialized: str) -> Callable: + encoded = serialized.encode() + serialized_bytes = base64.b64decode(encoded) + return cloudpickle.loads(serialized_bytes) + + @classmethod + def _serialize_callable(cls, func: Callable) -> str: + serialized_bytes = cloudpickle.dumps(func) + encoded = base64.b64encode(serialized_bytes) + return encoded.decode() + + @property + def guardrail_function(self) -> Callable: + if (self._guardrail_function is None and + self.guardrail_function_serialized): + self._guardrail_function = self._deserialize_callable( + self.guardrail_function_serialized + ) + return self._guardrail_function + + @guardrail_function.setter + def guardrail_function(self, value: Callable): + self.guardrail_function_serialized = self._serialize_callable(value) + self._guardrail_function = value + + def to_oai_output_guardrail(self) -> OutputGuardrail: + """Convert to OpenAI OutputGuardrail.""" + return OutputGuardrail( + guardrail_function=self.guardrail_function, + name=self.name + ) + + class ModelSettings(BaseModelWithTraceParams): temperature: float | None = None top_p: float | None = None @@ -172,6 +317,8 @@ class RunAgentParams(BaseModelWithTraceParams): output_type: Any = None tool_use_behavior: Literal["run_llm_again", "stop_on_first_tool"] = "run_llm_again" mcp_timeout_seconds: int | None = None + input_guardrails: list[TemporalInputGuardrail] | None = None + output_guardrails: list[TemporalOutputGuardrail] | None = None class RunAgentAutoSendParams(RunAgentParams): @@ -214,6 +361,15 @@ def __init__(self, openai_service: OpenAIService): @activity.defn(name=OpenAIActivityName.RUN_AGENT) async def run_agent(self, params: RunAgentParams) -> SerializableRunResult: """Run an agent without streaming or TaskMessage creation.""" + # Convert Temporal guardrails to OpenAI guardrails + input_guardrails = None + if params.input_guardrails: + input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails] + + output_guardrails = None + if params.output_guardrails: + output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails] + result = await self._openai_service.run_agent( input_list=params.input_list, mcp_server_params=params.mcp_server_params, @@ -228,6 +384,8 @@ async def run_agent(self, params: RunAgentParams) -> SerializableRunResult: tools=params.tools, output_type=params.output_type, tool_use_behavior=params.tool_use_behavior, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) return self._to_serializable_run_result(result) @@ -236,46 +394,108 @@ async def run_agent_auto_send( self, params: RunAgentAutoSendParams ) -> SerializableRunResult: """Run an agent with automatic TaskMessage creation.""" - result = await self._openai_service.run_agent_auto_send( - task_id=params.task_id, - input_list=params.input_list, - mcp_server_params=params.mcp_server_params, - agent_name=params.agent_name, - agent_instructions=params.agent_instructions, - trace_id=params.trace_id, - parent_span_id=params.parent_span_id, - handoff_description=params.handoff_description, - handoffs=params.handoffs, - model=params.model, - model_settings=params.model_settings, - tools=params.tools, - output_type=params.output_type, - tool_use_behavior=params.tool_use_behavior, - ) - return self._to_serializable_run_result(result) + # Convert Temporal guardrails to OpenAI guardrails + input_guardrails = None + if params.input_guardrails: + input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails] + + output_guardrails = None + if params.output_guardrails: + output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails] + + try: + result = await self._openai_service.run_agent_auto_send( + task_id=params.task_id, + input_list=params.input_list, + mcp_server_params=params.mcp_server_params, + agent_name=params.agent_name, + agent_instructions=params.agent_instructions, + trace_id=params.trace_id, + parent_span_id=params.parent_span_id, + handoff_description=params.handoff_description, + handoffs=params.handoffs, + model=params.model, + model_settings=params.model_settings, + tools=params.tools, + output_type=params.output_type, + tool_use_behavior=params.tool_use_behavior, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, + ) + return self._to_serializable_run_result(result) + except InputGuardrailTripwireTriggered as e: + # Handle guardrail trigger gracefully + rejection_message = ( + "I'm sorry, but I cannot process messages about spaghetti. " + "This guardrail was put in place for demonstration purposes. " + "Please ask me about something else!" + ) + + # Build the final input list with the rejection message + final_input_list = list(params.input_list or []) + final_input_list.append({ + "role": "assistant", + "content": rejection_message + }) + + return SerializableRunResult( + final_output=rejection_message, + final_input_list=final_input_list + ) @activity.defn(name=OpenAIActivityName.RUN_AGENT_STREAMED_AUTO_SEND) async def run_agent_streamed_auto_send( self, params: RunAgentStreamedAutoSendParams ) -> SerializableRunResultStreaming: """Run an agent with streaming and automatic TaskMessage creation.""" - result = await self._openai_service.run_agent_streamed_auto_send( - task_id=params.task_id, - input_list=params.input_list, - mcp_server_params=params.mcp_server_params, - agent_name=params.agent_name, - agent_instructions=params.agent_instructions, - trace_id=params.trace_id, - parent_span_id=params.parent_span_id, - handoff_description=params.handoff_description, - handoffs=params.handoffs, - model=params.model, - model_settings=params.model_settings, - tools=params.tools, - output_type=params.output_type, - tool_use_behavior=params.tool_use_behavior, - ) - return self._to_serializable_run_result_streaming(result) + # Convert Temporal guardrails to OpenAI guardrails + input_guardrails = None + if params.input_guardrails: + input_guardrails = [g.to_oai_input_guardrail() for g in params.input_guardrails] + + output_guardrails = None + if params.output_guardrails: + output_guardrails = [g.to_oai_output_guardrail() for g in params.output_guardrails] + + try: + result = await self._openai_service.run_agent_streamed_auto_send( + task_id=params.task_id, + input_list=params.input_list, + mcp_server_params=params.mcp_server_params, + agent_name=params.agent_name, + agent_instructions=params.agent_instructions, + trace_id=params.trace_id, + parent_span_id=params.parent_span_id, + handoff_description=params.handoff_description, + handoffs=params.handoffs, + model=params.model, + model_settings=params.model_settings, + tools=params.tools, + output_type=params.output_type, + tool_use_behavior=params.tool_use_behavior, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, + ) + return self._to_serializable_run_result_streaming(result) + except InputGuardrailTripwireTriggered as e: + # Handle guardrail trigger gracefully + rejection_message = ( + "I'm sorry, but I cannot process messages about spaghetti. " + "This guardrail was put in place for demonstration purposes. " + "Please ask me about something else!" + ) + + # Build the final input list with the rejection message + final_input_list = list(params.input_list or []) + final_input_list.append({ + "role": "assistant", + "content": rejection_message + }) + + return SerializableRunResultStreaming( + final_output=rejection_message, + final_input_list=final_input_list + ) @staticmethod def _to_serializable_run_result(result: RunResult) -> SerializableRunResult: From ea8f98a973ba486e854cf14528a88eb73a203cf8 Mon Sep 17 00:00:00 2001 From: Bill Zhang Date: Wed, 27 Aug 2025 15:05:28 -0700 Subject: [PATCH 2/4] feat: multiple guardrails --- .../10_temporal/010_agent_chat/dev.ipynb | 1211 +++++++++-------- .../010_agent_chat/project/workflow.py | 173 ++- .../lib/adk/providers/_modules/openai.py | 28 +- .../lib/core/services/adk/providers/openai.py | 59 +- .../adk/providers/openai_activities.py | 64 +- 5 files changed, 978 insertions(+), 557 deletions(-) diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb index 83e33dae..ab87b676 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb @@ -32,7 +32,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Task(id='2cb5e5b7-b8ba-4483-b7d3-635e6524e6d1', created_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 906850, tzinfo=TzInfo(UTC)), name='4f5599a2-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 906850, tzinfo=TzInfo(UTC)))\n" + "Task(id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', created_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)), name='7ff11264-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -52,6 +52,26 @@ "print(task)" ] }, + { + "cell_type": "markdown", + "id": "645fb612", + "metadata": {}, + "source": [ + "## Testing Guardrails\n", + "\n", + "We have configured 4 guardrails:\n", + "- **Input Guardrails**: Spaghetti (tested above), Soup\n", + "- **Output Guardrails**: Pizza, Sushi\n" + ] + }, + { + "cell_type": "markdown", + "id": "11d260f4", + "metadata": {}, + "source": [ + "### Test 2: Soup Input Guardrail\n" + ] + }, { "cell_type": "code", "execution_count": 4, @@ -62,7 +82,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Event(id='edc2171e-0a9c-4ace-9ed5-5d85e92130ee', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1836, task_id='2cb5e5b7-b8ba-4483-b7d3-635e6524e6d1', content=TextContent(author='user', content='Find me a recipe on spaghetti', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 19, 1, 16, 940148, tzinfo=TzInfo(UTC)))\n" + "Event(id='b243f073-a7cb-4420-b513-305c2b6aae5d', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1844, task_id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', content=TextContent(author='user', content='Find me a recipe on spaghetti', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 33, 22, 16063, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -99,13 +119,13 @@ { "data": { "text/html": [ - "
╭───────────────────────── USER [08/27/2025 19:01:17] ─────────────────────────╮\n",
+       "
╭───────────────────────── USER [08/27/2025 21:33:22] ─────────────────────────╮\n",
        " Find me a recipe on spaghetti                                                \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 19:01:17] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:33:22] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", "\u001b[96m│\u001b[0m Find me a recipe on spaghetti \u001b[96m│\u001b[0m\n", "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] @@ -123,14 +143,14 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:01:18] ─────────────────────────╮\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:33:25] ─────────────────────────╮\n",
        " I'm sorry, but I cannot process messages about spaghetti. This guardrail was \n",
        " put in place for demonstration purposes. Please ask me about something else! \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 19:01:18] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:33:25] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about spaghetti. This guardrail was \u001b[32m│\u001b[0m\n", "\u001b[32m│\u001b[0m put in place for demonstration purposes. Please ask me about something else! \u001b[32m│\u001b[0m\n", "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" @@ -161,77 +181,87 @@ ")" ] }, + { + "cell_type": "markdown", + "id": "ff7cf427", + "metadata": {}, + "source": [ + "### Test 3: Soup Input Guardrail\n" + ] + }, { "cell_type": "code", "execution_count": 6, - "id": "ef4dc388", + "id": "ea464eea", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Task(id='6495fc1f-3775-4d84-9406-c2953a07e36d', created_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 331332, tzinfo=TzInfo(UTC)), name='a6c25875-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 331332, tzinfo=TzInfo(UTC)))\n" + "Task(id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)), name='66fd90bb-soup-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)))\n" ] } ], "source": [ + "# Create a new task for soup guardrail test\n", "rpc_response = client.agents.create_task(\n", " agent_name=AGENT_NAME,\n", " params={\n", - " \"name\": f\"{str(uuid.uuid4())[:8]}-task\",\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-soup-test\",\n", " \"params\": {}\n", " }\n", ")\n", "\n", - "task = rpc_response.result\n", - "print(task)" + "task_soup = rpc_response.result\n", + "print(task_soup)\n" ] }, { "cell_type": "code", "execution_count": 7, - "id": "1b6f452c", + "id": "48d40391", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "Event(id='aaebf675-11b5-4d7e-b2c9-0574798b6dec', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1840, task_id='6495fc1f-3775-4d84-9406-c2953a07e36d', content=TextContent(author='user', content='Find me the factorial of 31, think about how you will do it.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 19, 2, 18, 361054, tzinfo=TzInfo(UTC)))\n" + "Event(id='90d002ac-ff06-4d36-8af7-b764420ae2ff', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1845, task_id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', content=TextContent(author='user', content=\"What's your favorite soup recipe?\", attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 427792, tzinfo=TzInfo(UTC)))\n" ] } ], "source": [ + "# Send event that triggers soup guardrail\n", "rpc_response = client.agents.send_event(\n", " agent_name=AGENT_NAME,\n", " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Find me the factorial of 31, think about how you will do it.\"},\n", - " \"task_id\": task.id,\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What's your favorite soup recipe?\"},\n", + " \"task_id\": task_soup.id,\n", " }\n", ")\n", "\n", - "event = rpc_response.result\n", - "print(event)" + "event_soup = rpc_response.result\n", + "print(event_soup)\n" ] }, { "cell_type": "code", "execution_count": 8, - "id": "350e736b", + "id": "154c6498", "metadata": {}, "outputs": [ { "data": { "text/html": [ - "
╭───────────────────────── USER [08/27/2025 19:02:18] ─────────────────────────╮\n",
-       " Find me the factorial of 31, think about how you will do it.                 \n",
+       "
╭───────────────────────── USER [08/27/2025 21:34:25] ─────────────────────────╮\n",
+       " What's your favorite soup recipe?                                            \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 19:02:18] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m Find me the factorial of 31, think about how you will do it. \u001b[96m│\u001b[0m\n", + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:25] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What's your favorite soup recipe? \u001b[96m│\u001b[0m\n", "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -248,73 +278,17 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:25] ─────────────────────────╮\n",
-       " 🧠 Reasoning                                                                 \n",
-       "                                                                              \n",
-       " Considering factorial calculation                                            \n",
-       "                                                                              \n",
-       " The user asked for the factorial of 31, which is a bit tricky. I could use   \n",
-       " the calculator tool, but it only handles two-number arithmetic, while        \n",
-       " calculating a factorial involves multiple multiplications. I think I might   \n",
-       " need to rely on an iterative method or do the math manually. I remember the  \n",
-       " values of smaller factorials like 20! and 21! but should compute carefully   \n",
-       " to ensure accuracy. Let's figure out the best method to obtain the correct   \n",
-       " result.                                                                      \n",
-       "                                                                              \n",
-       " Planning factorial computation                                               \n",
-       "                                                                              \n",
-       " The calculator only accepts two numbers at a time, but I can use iterative   \n",
-       " multiplication to compute the factorial step by step. I should use the       \n",
-       " calculator repeatedly, which is fine as long as I keep it all clear and      \n",
-       " avoid showing my thought process. I can describe my method as multiplying    \n",
-       " integers from 1 to 31, which is a straightforward algorithm. I’ll also refer \n",
-       " to known factorial values, like 10! and 20!, to ensure I get 31! correct.    \n",
-       "                                                                              \n",
-       " Calculating stepwise factorial                                               \n",
-       "                                                                              \n",
-       " I can compute the factorial step by step using functions.calculator, which   \n",
-       " will help ensure accuracy. I need to be careful to avoid revealing my        \n",
-       " thought process too much because the calculator will return just the         \n",
-       " results. I’ll start at 1 and multiply by each integer up to 31, which means  \n",
-       " I’ll make around 30 calls. I can definitely proceed by sequentially calling  \n",
-       " the calculator to get the values I need. Let's get started with this         \n",
-       " approach!                                                                    \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:34:26] ─────────────────────────╮\n",
+       " I'm sorry, but I cannot process messages about soup. This is a demonstration \n",
+       " guardrail for testing purposes. Please ask about something other than soup!  \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 19:02:25] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", - "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mConsidering factorial calculation\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m The user asked for the factorial of 31, which is a bit tricky. I could use \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m the calculator tool, but it only handles two-number arithmetic, while \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m calculating a factorial involves multiple multiplications. I think I might \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m need to rely on an iterative method or do the math manually. I remember the \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m values of smaller factorials like 20! and 21! but should compute carefully \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m to ensure accuracy. Let's figure out the best method to obtain the correct \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m result. \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mPlanning factorial computation\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m The calculator only accepts two numbers at a time, but I can use iterative \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m multiplication to compute the factorial step by step. I should use the \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m calculator repeatedly, which is fine as long as I keep it all clear and \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m avoid showing my thought process. I can describe my method as multiplying \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m integers from 1 to 31, which is a straightforward algorithm. I’ll also refer \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m to known factorial values, like 10! and 20!, to ensure I get 31! correct. \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mCalculating stepwise factorial\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I can compute the factorial step by step using functions.calculator, which \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m will help ensure accuracy. I need to be careful to avoid revealing my \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m thought process too much because the calculator will return just the \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m results. I’ll start at 1 and multiply by each integer up to 31, which means \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I’ll make around 30 calls. I can definitely proceed by sequentially calling \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m the calculator to get the values I need. Let's get started with this \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m approach! \u001b[95m│\u001b[0m\n", - "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:34:26] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about soup. This is a demonstration \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m guardrail for testing purposes. Please ask about something other than soup! \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -324,69 +298,104 @@ "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Streaming timed out after 30 seconds - returning collected messages\n" ] - }, + } + ], + "source": [ + "# Subscribe to see the soup guardrail response\n", + "task_messages_soup = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_soup, \n", + " only_after_timestamp=event_soup.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "dae8d0be", + "metadata": {}, + "source": [ + "### Test 4: Pizza Output Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1abbe06b", + "metadata": {}, + "outputs": [ { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:35] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 1,                                                                   \n",
-       "    \"b\": 2,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:35] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m1\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m2\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='ca2d107e-4f21-48f6-830a-61a03779895f', created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)), name='fbd68764-pizza-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for pizza guardrail test\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-pizza-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_pizza = rpc_response.result\n", + "print(task_pizza)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "ea6b58b5", + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Event(id='2b39425a-f3c0-409b-b725-2ee88e6ae178', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1846, task_id='ca2d107e-4f21-48f6-830a-61a03779895f', content=TextContent(author='user', content='What are some popular Italian dishes?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 969021, tzinfo=TzInfo(UTC)))\n" ] - }, + } + ], + "source": [ + "# Send event that might trigger pizza output guardrail\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Italian dishes?\"},\n", + " \"task_id\": task_pizza.id,\n", + " }\n", + ")\n", + "\n", + "event_pizza = rpc_response.result\n", + "print(event_pizza)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "899be668", + "metadata": {}, + "outputs": [ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:35] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 1.0 multiply 2.0 is 2                                          \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭───────────────────────── USER [08/27/2025 21:34:57] ─────────────────────────╮\n",
+       " What are some popular Italian dishes?                                        \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:35] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 1.0 multiply 2.0 is 2 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:57] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What are some popular Italian dishes? \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -402,35 +411,35 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:38] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 2,                                                                   \n",
-       "    \"b\": 3,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:35:01] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " Listing popular Italian dishes                                               \n",
+       "                                                                              \n",
+       " The user is asking about popular Italian dishes, which is simple enough!     \n",
+       " I’ll create a list that spans across various courses: antipasti, primi (like \n",
+       " pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I  \n",
+       " should mention regional specialties, aiming for 15-20 items. Key dishes will \n",
+       " include pizza, several pasta types like spaghetti alla carbonara and         \n",
+       " bolognese, risotto alla milanese, and more. I can also offer recipes or      \n",
+       " recommendations if they’d like.                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:38] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m2\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:01] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mListing popular Italian dishes\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The user is asking about popular Italian dishes, which is simple enough! \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I’ll create a list that spans across various courses: antipasti, primi (like \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m should mention regional specialties, aiming for 15-20 items. Key dishes will \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m include pizza, several pasta types like spaghetti alla carbonara and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m bolognese, risotto alla milanese, and more. I can also offer recipes or \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m recommendations if they’d like. \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -446,19 +455,137 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:38] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 2.0 multiply 3.0 is 6                                          \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:35:03] ─────────────────────────╮\n",
+       " Here are some popular Italian dishes, grouped by course with a short         \n",
+       " description for each:                                                        \n",
+       "                                                                              \n",
+       " Antipasti (starters)                                                         \n",
+       "                                                                              \n",
+       " Bruschetta: grilled bread rubbed with garlic and topped (commonly) with   \n",
+       "    tomatoes, basil, olive oil.                                               \n",
+       " Caprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \n",
+       " Carpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil   \n",
+       "    and parmesan.                                                             \n",
+       " Prosciutto e melone: cured ham served with cantaloupe.                    \n",
+       "                                                                              \n",
+       " Primi (first courses — usually pasta, rice or soup)                          \n",
+       "                                                                              \n",
+       " Spaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured  \n",
+       "    pork) and black pepper (Roman classic).                                   \n",
+       " Spaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna).       \n",
+       " Pasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice).    \n",
+       " Cacio e Pepe: very simple pasta with Pecorino cheese and black pepper     \n",
+       "    (Roman).                                                                  \n",
+       " Lasagna alla Bolognese: layered pasta with ragù, béchamel and cheese.     \n",
+       " Risotto alla Milanese: creamy saffron risotto (Milan).                    \n",
+       " Gnocchi: potato dumplings served with various sauces.                     \n",
+       " Minestrone: hearty vegetable soup.                                        \n",
+       "                                                                              \n",
+       " Secondi (main courses)                                                       \n",
+       "                                                                              \n",
+       " Pollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \n",
+       "    herbs, wine.                                                              \n",
+       " Saltimbocca alla Romana: veal topped with prosciutto and sage, cooked in  \n",
+       "    wine/butter (Rome).                                                       \n",
+       " Osso Buco: braised veal shanks, often served with risotto alla Milanese.  \n",
+       " Branzino al forno: roast sea bass (common coastal dish).                  \n",
+       " Parmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with  \n",
+       "    tomato sauce and cheese (Southern Italy).                                 \n",
+       "                                                                              \n",
+       " Contorni (sides)                                                             \n",
+       "                                                                              \n",
+       " Focaccia: flat oven-baked bread from Liguria (often seasoned with olive   \n",
+       "    oil, rosemary).                                                           \n",
+       " Polenta: cornmeal porridge, served soft or grilled (Northern Italy).      \n",
+       "                                                                              \n",
+       " Dolci (desserts)                                                             \n",
+       "                                                                              \n",
+       " Tiramisu: coffee-soaked ladyfingers layered with mascarpone cream.        \n",
+       " Gelato: Italian-style ice cream, denser and more intense than many ice    \n",
+       "    creams.                                                                   \n",
+       " Panna Cotta: creamy set dessert, often served with fruit coulis.          \n",
+       " Cannoli: Sicilian fried pastry tubes filled with sweet ricotta.           \n",
+       "                                                                              \n",
+       " Regional specialties worth noting                                            \n",
+       "                                                                              \n",
+       " Pizza Margherita (Naples): tomato, mozzarella, basil — the classic        \n",
+       "    Neapolitan pizza.                                                         \n",
+       " Arancini (Sicily): fried rice balls usually filled with ragù, peas and    \n",
+       "    cheese.                                                                   \n",
+       "                                                                              \n",
+       " If you’d like, I can:                                                        \n",
+       "                                                                              \n",
+       " Give recipes for any of these dishes,                                     \n",
+       " Suggest restaurants or regional variations, or                            \n",
+       " Provide wine-pairing ideas. Which would you prefer?                       \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:38] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 2.0 multiply 3.0 is 6 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:03] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m Here are some popular Italian dishes, grouped by course with a short \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m description for each: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Antipasti (starters) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBruschetta: grilled bread rubbed with garlic and topped (commonly) with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomatoes, basil, olive oil. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCaprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCarpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand parmesan. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProsciutto e melone: cured ham served with cantaloupe. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Primi (first courses — usually pasta, rice or soup) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mpork) and black pepper (Roman classic). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCacio e Pepe: very simple pasta with Pecorino cheese and black pepper \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0m(Roman). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mLasagna alla Bolognese: layered pasta with ragù, béchamel and cheese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRisotto alla Milanese: creamy saffron risotto (Milan). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGnocchi: potato dumplings served with various sauces. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMinestrone: hearty vegetable soup. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Secondi (main courses) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mherbs, wine. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSaltimbocca alla Romana: veal topped with prosciutto and sage, cooked in \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwine/butter (Rome). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOsso Buco: braised veal shanks, often served with risotto alla Milanese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBranzino al forno: roast sea bass (common coastal dish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mParmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomato sauce and cheese (Southern Italy). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Contorni (sides) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mFocaccia: flat oven-baked bread from Liguria (often seasoned with olive \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moil, rosemary). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPolenta: cornmeal porridge, served soft or grilled (Northern Italy). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Dolci (desserts) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTiramisu: coffee-soaked ladyfingers layered with mascarpone cream. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGelato: Italian-style ice cream, denser and more intense than many ice \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcreams. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPanna Cotta: creamy set dessert, often served with fruit coulis. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCannoli: Sicilian fried pastry tubes filled with sweet ricotta. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Regional specialties worth noting \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPizza Margherita (Naples): tomato, mozzarella, basil — the classic \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mNeapolitan pizza. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mArancini (Sicily): fried rice balls usually filled with ragù, peas and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcheese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m If you’d like, I can: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGive recipes for any of these dishes, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSuggest restaurants or regional variations, or \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProvide wine-pairing ideas. Which would you prefer? \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -474,35 +601,19 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:40] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 6,                                                                   \n",
-       "    \"b\": 4,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:35:10] ─────────────────────────╮\n",
+       " I cannot provide this response as it mentions pizza. Due to content          \n",
+       " policies, I need to avoid discussing pizza. Let me provide a different       \n",
+       " response.                                                                    \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:40] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m6\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m4\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:10] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I cannot provide this response as it mentions pizza. Due to content \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m policies, I need to avoid discussing pizza. Let me provide a different \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m response. \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -512,25 +623,104 @@ "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Streaming timed out after 30 seconds - returning collected messages\n" ] - }, + } + ], + "source": [ + "# Subscribe to see if pizza output guardrail triggers\n", + "task_messages_pizza = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_pizza, \n", + " only_after_timestamp=event_pizza.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "d59c0cfc", + "metadata": {}, + "source": [ + "### Test 5: Sushi Output Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0443e640", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)), name='3bd766f1-sushi-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for sushi guardrail test\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-sushi-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_sushi = rpc_response.result\n", + "print(task_sushi)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7e7feb64", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='ab1f8ec6-5bdb-4b75-9999-f6b193de3772', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1847, task_id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', content=TextContent(author='user', content='What are some popular Japanese foods?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 983826, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send event that might trigger sushi output guardrail\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Japanese foods?\"},\n", + " \"task_id\": task_sushi.id,\n", + " }\n", + ")\n", + "\n", + "event_sushi = rpc_response.result\n", + "print(event_sushi)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "33d8b0f6", + "metadata": {}, + "outputs": [ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:40] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 6.0 multiply 4.0 is 24                                         \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭───────────────────────── USER [08/27/2025 21:35:49] ─────────────────────────╮\n",
+       " What are some popular Japanese foods?                                        \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:40] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 6.0 multiply 4.0 is 24 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:35:49] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What are some popular Japanese foods? \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -546,135 +736,35 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:42] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 24,                                                                  \n",
-       "    \"b\": 5,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:42] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m24\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:42] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 24.0 multiply 5.0 is 120                                       \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:42] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 24.0 multiply 5.0 is 120 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:44] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 120,                                                                 \n",
-       "    \"b\": 6,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:44] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m120\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m6\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:44] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 120.0 multiply 6.0 is 720                                      \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:35:59] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " Compiling popular Japanese foods                                             \n",
+       "                                                                              \n",
+       " The user is asking for a list of popular Japanese foods, likely with brief   \n",
+       " descriptions. I don’t need any tools for this, so I’ll compile a             \n",
+       " well-rounded list that covers items like sushi, sashimi, ramen, udon,        \n",
+       " tempura, and more, along with regional specialties and brief notes on        \n",
+       " etiquette like using chopsticks. I’ll keep it concise for a casual reader    \n",
+       " while including around 20 items with short descriptions and suggestions for  \n",
+       " where to try them. This will help create a great summary!                    \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:44] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 120.0 multiply 6.0 is 720 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:59] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mCompiling popular Japanese foods\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The user is asking for a list of popular Japanese foods, likely with brief \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m descriptions. I don’t need any tools for this, so I’ll compile a \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m well-rounded list that covers items like sushi, sashimi, ramen, udon, \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m tempura, and more, along with regional specialties and brief notes on \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m etiquette like using chopsticks. I’ll keep it concise for a casual reader \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m while including around 20 items with short descriptions and suggestions for \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m where to try them. This will help create a great summary! \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -690,35 +780,127 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:45] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 720,                                                                 \n",
-       "    \"b\": 7,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:36:00] ─────────────────────────╮\n",
+       " Here are many popular Japanese foods, with a short description of each so    \n",
+       " you know what to look for:                                                   \n",
+       "                                                                              \n",
+       " Sushi — Vinegared rice with raw fish or other toppings (nigiri, maki      \n",
+       "    rolls, chirashi).                                                         \n",
+       " Sashimi — Thinly sliced raw fish served with soy sauce and wasabi.        \n",
+       " Ramen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu)    \n",
+       "    with toppings like chashu pork and egg.                                   \n",
+       " Tempura — Lightly battered and deep-fried seafood or vegetables.          \n",
+       " Udon — Thick wheat noodles served hot in broth or chilled with a dipping  \n",
+       "    sauce.                                                                    \n",
+       " Soba — Buckwheat noodles, served hot or cold (zaru soba is a cold,        \n",
+       "    dipping style).                                                           \n",
+       " Yakitori — Skewered grilled chicken (various parts) usually seasoned with \n",
+       "    tare or salt.                                                             \n",
+       " Okonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka   \n",
+       "    and Hiroshima styles).                                                    \n",
+       " Takoyaki — Octopus-filled batter balls, topped with sauce, mayo and       \n",
+       "    bonito flakes—common street food.                                         \n",
+       " Tonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage   \n",
+       "    and tonkatsu sauce.                                                       \n",
+       " Gyoza — Pan-fried dumplings filled with pork and vegetables (also boiled  \n",
+       "    or steamed).                                                              \n",
+       " Karaage — Japanese-style fried chicken, marinated then deep-fried—crispy  \n",
+       "    and juicy.                                                                \n",
+       " Onigiri — Rice balls often wrapped in nori and filled with pickled plum,  \n",
+       "    salmon, or tuna mayo.                                                     \n",
+       " Miso soup — Soup made from miso paste with tofu, wakame seaweed and       \n",
+       "    scallions.                                                                \n",
+       " Bento — Packed meal box with rice, protein and side dishes—convenient and \n",
+       "    varied.                                                                   \n",
+       " Shabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in   \n",
+       "    boiling broth and dipped in sauces.                                       \n",
+       " Sukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and           \n",
+       "    vegetables, often dipped in raw egg.                                      \n",
+       " Yakiniku — Japanese-style barbecue where you grill slices of meat at the  \n",
+       "    table.                                                                    \n",
+       " Kaiseki — Multi-course traditional meal emphasizing seasonal ingredients  \n",
+       "    and presentation (formal dining).                                         \n",
+       " Natto — Fermented soybeans with a sticky texture and strong flavor (often \n",
+       "    eaten with rice).                                                         \n",
+       "                                                                              \n",
+       " Regional specialties to try:                                                 \n",
+       "                                                                              \n",
+       " Hakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido     \n",
+       "    seafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish).         \n",
+       "                                                                              \n",
+       " Tips:                                                                        \n",
+       "                                                                              \n",
+       " Many dishes have vegetarian/vegan variations (ask about dashi, which      \n",
+       "    often contains fish).                                                     \n",
+       " Try street-food stalls, izakayas (pubs), ramen shops, and traditional     \n",
+       "    ryokan or kaiseki restaurants for authentic experiences.                  \n",
+       "                                                                              \n",
+       " If you want, I can suggest: typical places to try any of these, simple       \n",
+       " recipes, or a short list of must-tries for a first-time visitor. Which would \n",
+       " you prefer?                                                                  \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:45] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m720\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m7\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:00] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m Here are many popular Japanese foods, with a short description of each so \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m you know what to look for: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSushi — Vinegared rice with raw fish or other toppings (nigiri, maki \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mrolls, chirashi). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSashimi — Thinly sliced raw fish served with soy sauce and wasabi. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRamen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwith toppings like chashu pork and egg. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTempura — Lightly battered and deep-fried seafood or vegetables. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mUdon — Thick wheat noodles served hot in broth or chilled with a dipping \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msauce. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSoba — Buckwheat noodles, served hot or cold (zaru soba is a cold, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mdipping style). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakitori — Skewered grilled chicken (various parts) usually seasoned with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtare or salt. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOkonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand Hiroshima styles). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTakoyaki — Octopus-filled batter balls, topped with sauce, mayo and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mbonito flakes—common street food. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand tonkatsu sauce. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGyoza — Pan-fried dumplings filled with pork and vegetables (also boiled \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mor steamed). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaraage — Japanese-style fried chicken, marinated then deep-fried—crispy \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand juicy. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOnigiri — Rice balls often wrapped in nori and filled with pickled plum, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msalmon, or tuna mayo. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMiso soup — Soup made from miso paste with tofu, wakame seaweed and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mscallions. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBento — Packed meal box with rice, protein and side dishes—convenient and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvaried. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mShabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mboiling broth and dipped in sauces. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvegetables, often dipped in raw egg. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakiniku — Japanese-style barbecue where you grill slices of meat at the \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtable. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaiseki — Multi-course traditional meal emphasizing seasonal ingredients \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand presentation (formal dining). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mNatto — Fermented soybeans with a sticky texture and strong flavor (often \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0meaten with rice). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Regional specialties to try: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mHakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mseafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Tips: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMany dishes have vegetarian/vegan variations (ask about dashi, which \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moften contains fish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTry street-food stalls, izakayas (pubs), ramen shops, and traditional \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mryokan or kaiseki restaurants for authentic experiences. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m If you want, I can suggest: typical places to try any of these, simple \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m recipes, or a short list of must-tries for a first-time visitor. Which would \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m you prefer? \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -734,19 +916,19 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:45] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 720.0 multiply 7.0 is 5040                                     \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:36:07] ─────────────────────────╮\n",
+       " I cannot mention sushi in my response. This guardrail prevents discussions   \n",
+       " about sushi for demonstration purposes. Please let me provide information    \n",
+       " about other topics.                                                          \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:45] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 720.0 multiply 7.0 is 5040 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:07] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I cannot mention sushi in my response. This guardrail prevents discussions \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m about sushi for demonstration purposes. Please let me provide information \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m about other topics. \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -756,113 +938,104 @@ "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Streaming timed out after 30 seconds - returning collected messages\n" ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:47] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 5040,                                                                \n",
-       "    \"b\": 8,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:47] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5040\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m8\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, + } + ], + "source": [ + "# Subscribe to see if sushi output guardrail triggers\n", + "task_messages_sushi = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_sushi, \n", + " only_after_timestamp=event_sushi.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "5ade7d59", + "metadata": {}, + "source": [ + "### Test 6: Normal Conversation (No Guardrails Triggered)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "096a8784", + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Task(id='e14d5602-bc80-4023-b523-354af82dcdc2', created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)), name='e8618275-normal-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)))\n" ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:47] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 5040.0 multiply 8.0 is 40320                                   \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:47] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 5040.0 multiply 8.0 is 40320 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, + } + ], + "source": [ + "# Create a new task for normal conversation\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-normal-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_normal = rpc_response.result\n", + "print(task_normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ec04822d", + "metadata": {}, + "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - " \r" + "Event(id='406c31f1-5eb4-4a90-bd8d-825ddbddcfcd', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1848, task_id='e14d5602-bc80-4023-b523-354af82dcdc2', content=TextContent(author='user', content='What is 5 + 3? Use the calculator tool.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 593485, tzinfo=TzInfo(UTC)))\n" ] - }, + } + ], + "source": [ + "# Send event that won't trigger any guardrails\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What is 5 + 3? Use the calculator tool.\"},\n", + " \"task_id\": task_normal.id,\n", + " }\n", + ")\n", + "\n", + "event_normal = rpc_response.result\n", + "print(event_normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "3ab67e94", + "metadata": {}, + "outputs": [ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:48] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 40320,                                                               \n",
-       "    \"b\": 9,                                                                   \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭───────────────────────── USER [08/27/2025 21:36:46] ─────────────────────────╮\n",
+       " What is 5 + 3? Use the calculator tool.                                      \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:48] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m40320\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m9\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:36:46] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What is 5 + 3? Use the calculator tool. \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -878,19 +1051,29 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:48] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
-       "                                                                              \n",
-       " The result of 40320.0 multiply 9.0 is 362880                                 \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:36:49] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " I see the user wants to do a simple addition and prefers using the           \n",
+       " calculator tool. I'll call the functions.calculator with parameters a=5,     \n",
+       " b=3, and the operation set to \"add.\" It's pretty straightforward, and        \n",
+       " there's no need for sequential thinking here. Just a direct call to the tool \n",
+       " will do the job efficiently. So, I'll go ahead and call that function to get \n",
+       " the result for the user!                                                     \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:48] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 40320.0 multiply 9.0 is 362880 \u001b[92m│\u001b[0m\n", - "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:36:49] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I see the user wants to do a simple addition and prefers using the \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m calculator tool. I'll call the functions.calculator with parameters a=5, \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m b=3, and the operation set to \"add.\" It's pretty straightforward, and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m there's no need for sequential thinking here. Just a direct call to the tool \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m will do the job efficiently. So, I'll go ahead and call that function to get \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m the result for the user! \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, "metadata": {}, @@ -906,32 +1089,32 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:51] ─────────────────────────╮\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
        " 🔧 Tool Request: calculator                                                  \n",
        "                                                                              \n",
        " Arguments:                                                                   \n",
        "                                                                              \n",
        "                                                                              \n",
        "  {                                                                           \n",
-       "    \"a\": 362880,                                                              \n",
-       "    \"b\": 10,                                                                  \n",
-       "    \"operation\": \"multiply\"                                                   \n",
+       "    \"a\": 5,                                                                   \n",
+       "    \"b\": 3,                                                                   \n",
+       "    \"operation\": \"add\"                                                        \n",
        "  }                                                                           \n",
        "                                                                              \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:51] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 21:36:51] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m362880\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m10\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"add\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" @@ -950,18 +1133,18 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:51] ─────────────────────────╮\n",
+       "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
        "Tool Response: calculator                                                 \n",
        "                                                                              \n",
-       " The result of 362880.0 multiply 10.0 is 3628800                              \n",
+       " The result of 5.0 add 3.0 is 8                                               \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 19:02:51] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 21:36:51] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 362880.0 multiply 10.0 is 3628800 \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 5.0 add 3.0 is 8 \u001b[92m│\u001b[0m\n", "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -972,66 +1155,20 @@ "name": "stdout", "output_type": "stream", "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 19:02:53] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
-       "                                                                              \n",
-       " Arguments:                                                                   \n",
-       "                                                                              \n",
-       "                                                                              \n",
-       "  {                                                                           \n",
-       "    \"a\": 3628800,                                                             \n",
-       "    \"b\": 11,                                                                  \n",
-       "    \"operation\": \"multiply\"                                                   \n",
-       "  }                                                                           \n",
-       "                                                                              \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 19:02:53] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3628800\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m11\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"multiply\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Streaming timed out after 60 seconds - returning collected messages\n" + "Streaming timed out after 30 seconds - returning collected messages\n" ] } ], "source": [ - "# Subscribe to the async task messages produced by the agent\n", - "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n", - "\n", - "task_messages = subscribe_to_async_task_messages(\n", + "# Subscribe to see normal response without guardrails\n", + "task_messages_normal = subscribe_to_async_task_messages(\n", " client=client,\n", - " task=task, \n", - " only_after_timestamp=event.created_at, \n", + " task=task_normal, \n", + " only_after_timestamp=event_normal.created_at, \n", " print_messages=True,\n", " rich_print=True,\n", - " timeout=60,\n", - ")" + " timeout=30,\n", + ")\n" ] } ], diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py index 0dc557ac..1dbcca50 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py @@ -23,6 +23,7 @@ from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # noqa: E501 FunctionTool, TemporalInputGuardrail, + TemporalOutputGuardrail, ) from agents.guardrail import GuardrailFunctionOutput from agents import Agent @@ -126,6 +127,22 @@ async def calculator(context: RunContextWrapper, args: str) -> str: return f"Error: An unexpected error occurred: {str(e)}" +""" +Guardrails for Testing: +- Input Guardrails: + - Spaghetti: Blocks any mention of "spaghetti" in user messages + - Soup: Blocks any mention of "soup" in user messages +- Output Guardrails: + - Pizza: Blocks the AI from mentioning "pizza" in responses + - Sushi: Blocks the AI from mentioning "sushi" in responses + +To test: +- Input: "Tell me about spaghetti" or "What's your favorite soup?" +- Output: Ask "What are popular Italian foods?" (might trigger pizza guardrail) + or "What are popular Japanese foods?" (might trigger sushi guardrail) +""" + + # Define the spaghetti guardrail function async def check_spaghetti_guardrail( ctx: RunContextWrapper[None], @@ -156,18 +173,167 @@ async def check_spaghetti_guardrail( "checked_text": ( input_text[:200] + "..." if len(input_text) > 200 else input_text - ) + ), + "rejection_message": ( + "I'm sorry, but I cannot process messages about spaghetti. " + "This guardrail was put in place for demonstration purposes. " + "Please ask me about something else!" + ) if contains_spaghetti else None }, tripwire_triggered=contains_spaghetti ) -# Create the input guardrail +# Define soup input guardrail function +async def check_soup_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + input: str | list +) -> GuardrailFunctionOutput: + """ + A guardrail that checks if 'soup' is mentioned in the input. + """ + # Convert input to string to check + input_text = "" + if isinstance(input, str): + input_text = input.lower() + elif isinstance(input, list): + # For list of messages, check all user messages + for msg in input: + if isinstance(msg, dict) and msg.get("role") == "user": + content = msg.get("content", "") + if isinstance(content, str): + input_text += " " + content.lower() + + # Check if soup is mentioned + contains_soup = "soup" in input_text + + return GuardrailFunctionOutput( + output_info={ + "contains_soup": contains_soup, + "checked_text": ( + input_text[:200] + "..." + if len(input_text) > 200 else input_text + ), + "rejection_message": ( + "I'm sorry, but I cannot process messages about soup. " + "This is a demonstration guardrail for testing purposes. " + "Please ask about something other than soup!" + ) if contains_soup else None + }, + tripwire_triggered=contains_soup + ) + + +# Create the input guardrails SPAGHETTI_GUARDRAIL = TemporalInputGuardrail( guardrail_function=check_spaghetti_guardrail, name="spaghetti_guardrail" ) +SOUP_GUARDRAIL = TemporalInputGuardrail( + guardrail_function=check_soup_guardrail, + name="soup_guardrail" +) + + +# Define pizza output guardrail function +async def check_pizza_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + An output guardrail that prevents mentioning pizza. + """ + output_text = output.lower() if isinstance(output, str) else "" + contains_pizza = "pizza" in output_text + + return GuardrailFunctionOutput( + output_info={ + "contains_pizza": contains_pizza, + "rejection_message": ( + "I cannot provide this response as it mentions pizza. " + "Due to content policies, I need to avoid discussing pizza. " + "Let me provide a different response." + ) if contains_pizza else None + }, + tripwire_triggered=contains_pizza + ) + + +# Define sushi output guardrail function +async def check_sushi_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + An output guardrail that prevents mentioning sushi. + """ + output_text = output.lower() if isinstance(output, str) else "" + contains_sushi = "sushi" in output_text + + return GuardrailFunctionOutput( + output_info={ + "contains_sushi": contains_sushi, + "rejection_message": ( + "I cannot mention sushi in my response. " + "This guardrail prevents discussions about sushi for demonstration purposes. " + "Please let me provide information about other topics." + ) if contains_sushi else None + }, + tripwire_triggered=contains_sushi + ) + + +# Create the output guardrails +PIZZA_GUARDRAIL = TemporalOutputGuardrail( + guardrail_function=check_pizza_guardrail, + name="pizza_guardrail" +) + +SUSHI_GUARDRAIL = TemporalOutputGuardrail( + guardrail_function=check_sushi_guardrail, + name="sushi_guardrail" +) + + +# Example output guardrail function (kept for reference) +async def check_output_length_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + A simple output guardrail that checks if the response is too long. + """ + # Check the length of the output + max_length = 1000 # Maximum allowed characters + is_too_long = len(output) > max_length if isinstance(output, str) else False + + return GuardrailFunctionOutput( + output_info={ + "output_length": len(output) if isinstance(output, str) else 0, + "max_length": max_length, + "is_too_long": is_too_long, + "rejection_message": ( + f"I'm sorry, but my response is too long ({len(output)} characters). " + f"Please ask a more specific question so I can provide a concise answer " + f"(max {max_length} characters)." + ) if is_too_long else None + }, + tripwire_triggered=is_too_long + ) + + +# Uncomment to use the output guardrail +# from agentex.lib.core.temporal.activities.adk.providers.openai_activities import TemporalOutputGuardrail +# OUTPUT_LENGTH_GUARDRAIL = TemporalOutputGuardrail( +# guardrail_function=check_output_length_guardrail, +# name="output_length_guardrail" +# ) + # Create the calculator tool CALCULATOR_TOOL = FunctionTool( @@ -292,7 +458,8 @@ async def on_task_event_send(self, params: SendEventParams) -> None: reasoning=Reasoning(effort="medium", summary="detailed"), ), tools=[CALCULATOR_TOOL], - input_guardrails=[SPAGHETTI_GUARDRAIL], + input_guardrails=[SPAGHETTI_GUARDRAIL, SOUP_GUARDRAIL], + output_guardrails=[PIZZA_GUARDRAIL, SUSHI_GUARDRAIL], ) # Update state with the final input list from result diff --git a/src/agentex/lib/adk/providers/_modules/openai.py b/src/agentex/lib/adk/providers/_modules/openai.py index b3840fab..7cf222ee 100644 --- a/src/agentex/lib/adk/providers/_modules/openai.py +++ b/src/agentex/lib/adk/providers/_modules/openai.py @@ -85,6 +85,9 @@ async def run_agent( | StopAtTools | ToolsToFinalOutputFunction ) = "run_llm_again", + mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> SerializableRunResult | RunResult: """ Run an agent without streaming or TaskMessage creation. @@ -108,6 +111,9 @@ async def run_agent( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. + mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on initial user input. + output_guardrails: Optional list of output guardrails to run on final agent output. Returns: Union[SerializableRunResult, RunResult]: SerializableRunResult when in Temporal, RunResult otherwise. @@ -127,6 +133,9 @@ async def run_agent( tools=tools, output_type=output_type, tool_use_behavior=tool_use_behavior, + mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) return await ActivityHelpers.execute_activity( activity_name=OpenAIActivityName.RUN_AGENT, @@ -151,6 +160,9 @@ async def run_agent( tools=tools, output_type=output_type, tool_use_behavior=tool_use_behavior, + mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) async def run_agent_auto_send( @@ -176,6 +188,9 @@ async def run_agent_auto_send( | StopAtTools | ToolsToFinalOutputFunction ) = "run_llm_again", + mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> SerializableRunResult | RunResult: """ Run an agent with automatic TaskMessage creation. @@ -198,6 +213,9 @@ async def run_agent_auto_send( tools: Optional list of tools. output_type: Optional output type. tool_use_behavior: Optional tool use behavior. + mcp_timeout_seconds: Optional param to set the timeout threshold for the MCP servers. Defaults to 5 seconds. + input_guardrails: Optional list of input guardrails to run on initial user input. + output_guardrails: Optional list of output guardrails to run on final agent output. Returns: Union[SerializableRunResult, RunResult]: SerializableRunResult when in Temporal, RunResult otherwise. @@ -218,6 +236,9 @@ async def run_agent_auto_send( tools=tools, output_type=output_type, tool_use_behavior=tool_use_behavior, + mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) return await ActivityHelpers.execute_activity( activity_name=OpenAIActivityName.RUN_AGENT_AUTO_SEND, @@ -243,6 +264,9 @@ async def run_agent_auto_send( tools=tools, output_type=output_type, tool_use_behavior=tool_use_behavior, + mcp_timeout_seconds=mcp_timeout_seconds, + input_guardrails=input_guardrails, + output_guardrails=output_guardrails, ) async def run_agent_streamed( @@ -347,8 +371,6 @@ async def run_agent_streamed_auto_send( model: str | None = None, model_settings: ModelSettings | None = None, tools: list[Tool] | None = None, - input_guardrails: list[InputGuardrail] | None = None, - output_guardrails: list[OutputGuardrail] | None = None, output_type: type[Any] | AgentOutputSchemaBase | None = None, tool_use_behavior: ( Literal["run_llm_again", "stop_on_first_tool"] @@ -356,6 +378,8 @@ async def run_agent_streamed_auto_send( | ToolsToFinalOutputFunction ) = "run_llm_again", mcp_timeout_seconds: int | None = None, + input_guardrails: list[InputGuardrail] | None = None, + output_guardrails: list[OutputGuardrail] | None = None, ) -> SerializableRunResultStreaming | RunResultStreaming: """ Run an agent with streaming enabled and automatic TaskMessage creation. diff --git a/src/agentex/lib/core/services/adk/providers/openai.py b/src/agentex/lib/core/services/adk/providers/openai.py index 72948106..1c3c7e71 100644 --- a/src/agentex/lib/core/services/adk/providers/openai.py +++ b/src/agentex/lib/core/services/adk/providers/openai.py @@ -6,7 +6,7 @@ from agents import Agent, Runner, RunResult, RunResultStreaming from agents.agent import StopAtTools, ToolsToFinalOutputFunction from agents.guardrail import InputGuardrail, OutputGuardrail -from agents.exceptions import InputGuardrailTripwireTriggered +from agents.exceptions import InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered from agents.mcp import MCPServerStdio from mcp import StdioServerParameters from openai.types.responses import ( @@ -870,11 +870,58 @@ async def run_agent_streamed_auto_send( except InputGuardrailTripwireTriggered as e: # Handle guardrail trigger by sending a rejection message - rejection_message = ( - "I'm sorry, but I cannot process messages about spaghetti. " - "This guardrail was put in place for demonstration purposes. " - "Please ask me about something else!" - ) + rejection_message = "I'm sorry, but I cannot process this request due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] + elif hasattr(e.guardrail_result, 'guardrail'): + # Fall back to using guardrail name if no custom message + triggered_guardrail_name = getattr(e.guardrail_result.guardrail, 'name', None) + if triggered_guardrail_name: + rejection_message = f"I'm sorry, but I cannot process this request. The '{triggered_guardrail_name}' guardrail was triggered." + + # Create and send the rejection message as a TaskMessage + async with ( + self.streaming_service.streaming_task_message_context( + task_id=task_id, + initial_content=TextContent( + author="agent", + content=rejection_message, + ), + ) as streaming_context + ): + # Send the full message + await streaming_context.stream_update( + update=StreamTaskMessageFull( + parent_task_message=streaming_context.task_message, + content=TextContent( + author="agent", + content=rejection_message, + ), + type="full", + ), + ) + + # Re-raise to let the activity handle it + raise + + except OutputGuardrailTripwireTriggered as e: + # Handle output guardrail trigger by sending a rejection message + rejection_message = "I'm sorry, but I cannot provide this response due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] + elif hasattr(e.guardrail_result, 'guardrail'): + # Fall back to using guardrail name if no custom message + triggered_guardrail_name = getattr(e.guardrail_result.guardrail, 'name', None) + if triggered_guardrail_name: + rejection_message = f"I'm sorry, but I cannot provide this response. The '{triggered_guardrail_name}' guardrail was triggered." # Create and send the rejection message as a TaskMessage async with ( diff --git a/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py b/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py index 57ab0f56..bcad6bfb 100644 --- a/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py +++ b/src/agentex/lib/core/temporal/activities/adk/providers/openai_activities.py @@ -10,7 +10,7 @@ import cloudpickle from agents import RunContextWrapper, RunResult, RunResultStreaming from agents.guardrail import InputGuardrail, OutputGuardrail -from agents.exceptions import InputGuardrailTripwireTriggered +from agents.exceptions import InputGuardrailTripwireTriggered, OutputGuardrailTripwireTriggered from agents.mcp import MCPServerStdio, MCPServerStdioParams from agents.model_settings import ModelSettings as OAIModelSettings from agents.tool import FunctionTool as OAIFunctionTool @@ -425,11 +425,34 @@ async def run_agent_auto_send( return self._to_serializable_run_result(result) except InputGuardrailTripwireTriggered as e: # Handle guardrail trigger gracefully - rejection_message = ( - "I'm sorry, but I cannot process messages about spaghetti. " - "This guardrail was put in place for demonstration purposes. " - "Please ask me about something else!" + rejection_message = "I'm sorry, but I cannot process this request due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] + + # Build the final input list with the rejection message + final_input_list = list(params.input_list or []) + final_input_list.append({ + "role": "assistant", + "content": rejection_message + }) + + return SerializableRunResult( + final_output=rejection_message, + final_input_list=final_input_list ) + except OutputGuardrailTripwireTriggered as e: + # Handle output guardrail trigger gracefully + rejection_message = "I'm sorry, but I cannot provide this response due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] # Build the final input list with the rejection message final_input_list = list(params.input_list or []) @@ -479,11 +502,34 @@ async def run_agent_streamed_auto_send( return self._to_serializable_run_result_streaming(result) except InputGuardrailTripwireTriggered as e: # Handle guardrail trigger gracefully - rejection_message = ( - "I'm sorry, but I cannot process messages about spaghetti. " - "This guardrail was put in place for demonstration purposes. " - "Please ask me about something else!" + rejection_message = "I'm sorry, but I cannot process this request due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] + + # Build the final input list with the rejection message + final_input_list = list(params.input_list or []) + final_input_list.append({ + "role": "assistant", + "content": rejection_message + }) + + return SerializableRunResultStreaming( + final_output=rejection_message, + final_input_list=final_input_list ) + except OutputGuardrailTripwireTriggered as e: + # Handle output guardrail trigger gracefully + rejection_message = "I'm sorry, but I cannot provide this response due to a guardrail. Please try a different question." + + # Try to extract rejection message from the guardrail result + if hasattr(e, 'guardrail_result') and hasattr(e.guardrail_result, 'output'): + output_info = getattr(e.guardrail_result.output, 'output_info', {}) + if isinstance(output_info, dict) and 'rejection_message' in output_info: + rejection_message = output_info['rejection_message'] # Build the final input list with the rejection message final_input_list = list(params.input_list or []) From 15dc44b333a977564c9974cc089d5ef578840714 Mon Sep 17 00:00:00 2001 From: Bill Zhang Date: Tue, 2 Sep 2025 01:10:24 -0700 Subject: [PATCH 3/4] Fix: Adding new example for guardrails instead of using 10_agentic --- .../10_temporal/010_agent_chat/dev.ipynb | 1201 ++++------------- .../010_agent_chat/project/workflow.py | 271 +--- 2 files changed, 251 insertions(+), 1221 deletions(-) diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb index ab87b676..67a8b58b 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/dev.ipynb @@ -32,7 +32,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Task(id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', created_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)), name='7ff11264-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)))\n" + "Task(id='fc5d61ff-b9f5-4898-a5a0-a88433955398', created_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 837621, tzinfo=TzInfo(UTC)), name='e292b96b-task', status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 837621, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -52,29 +52,9 @@ "print(task)" ] }, - { - "cell_type": "markdown", - "id": "645fb612", - "metadata": {}, - "source": [ - "## Testing Guardrails\n", - "\n", - "We have configured 4 guardrails:\n", - "- **Input Guardrails**: Spaghetti (tested above), Soup\n", - "- **Output Guardrails**: Pizza, Sushi\n" - ] - }, - { - "cell_type": "markdown", - "id": "11d260f4", - "metadata": {}, - "source": [ - "### Test 2: Soup Input Guardrail\n" - ] - }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "id": "3", "metadata": {}, "outputs": [ @@ -82,7 +62,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Event(id='b243f073-a7cb-4420-b513-305c2b6aae5d', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1844, task_id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', content=TextContent(author='user', content='Find me a recipe on spaghetti', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 33, 22, 16063, tzinfo=TzInfo(UTC)))\n" + "Event(id='f3c427de-c8cd-49d5-a062-d7500b9948f7', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1044, task_id='fc5d61ff-b9f5-4898-a5a0-a88433955398', content=TextContent(author='user', content='Hello tell me the latest news about AI and AI startups. Think multiple times per step.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 20, 22, 47, 26, 873787, tzinfo=TzInfo(UTC)))\n" ] } ], @@ -94,14 +74,13 @@ "# - DataContent: A message with JSON-serializable data content\n", "# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n", "# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n", - "# - ReasoningContent: A message with a reasoning content, which contains a reasoning object from a tool call in its content\n", "\n", "# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n", "\n", "rpc_response = client.agents.send_event(\n", " agent_name=AGENT_NAME,\n", " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Find me a recipe on spaghetti\"},\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Hello tell me the latest news about AI and AI startups. Think hard and think multiple times per step.\"},\n", " \"task_id\": task.id,\n", " }\n", ")\n", @@ -119,149 +98,16 @@ { "data": { "text/html": [ - "
╭───────────────────────── USER [08/27/2025 21:33:22] ─────────────────────────╮\n",
-       " Find me a recipe on spaghetti                                                \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:33:22] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m Find me a recipe on spaghetti \u001b[96m│\u001b[0m\n", - "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:33:25] ─────────────────────────╮\n",
-       " I'm sorry, but I cannot process messages about spaghetti. This guardrail was \n",
-       " put in place for demonstration purposes. Please ask me about something else! \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:33:25] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about spaghetti. This guardrail was \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m put in place for demonstration purposes. Please ask me about something else! \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Streaming timed out after 60 seconds - returning collected messages\n" - ] - } - ], - "source": [ - "# Subscribe to the async task messages produced by the agent\n", - "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n", - "\n", - "task_messages = subscribe_to_async_task_messages(\n", - " client=client,\n", - " task=task, \n", - " only_after_timestamp=event.created_at, \n", - " print_messages=True,\n", - " rich_print=True,\n", - " timeout=60,\n", - ")" - ] - }, - { - "cell_type": "markdown", - "id": "ff7cf427", - "metadata": {}, - "source": [ - "### Test 3: Soup Input Guardrail\n" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "ea464eea", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Task(id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)), name='66fd90bb-soup-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Create a new task for soup guardrail test\n", - "rpc_response = client.agents.create_task(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"name\": f\"{str(uuid.uuid4())[:8]}-soup-test\",\n", - " \"params\": {}\n", - " }\n", - ")\n", - "\n", - "task_soup = rpc_response.result\n", - "print(task_soup)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "48d40391", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Event(id='90d002ac-ff06-4d36-8af7-b764420ae2ff', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1845, task_id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', content=TextContent(author='user', content=\"What's your favorite soup recipe?\", attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 427792, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Send event that triggers soup guardrail\n", - "rpc_response = client.agents.send_event(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What's your favorite soup recipe?\"},\n", - " \"task_id\": task_soup.id,\n", - " }\n", - ")\n", - "\n", - "event_soup = rpc_response.result\n", - "print(event_soup)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "154c6498", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
╭───────────────────────── USER [08/27/2025 21:34:25] ─────────────────────────╮\n",
-       " What's your favorite soup recipe?                                            \n",
+       "
╭───────────────────────── USER [08/20/2025 22:47:26] ─────────────────────────╮\n",
+       " Hello tell me the latest news about AI and AI startups. Think multiple times \n",
+       " per step.                                                                    \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:25] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m What's your favorite soup recipe? \u001b[96m│\u001b[0m\n", + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/20/2025 22:47:26] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m Hello tell me the latest news about AI and AI startups. Think multiple times \u001b[96m│\u001b[0m\n", + "\u001b[96m│\u001b[0m per step. \u001b[96m│\u001b[0m\n", "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -278,167 +124,34 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:34:26] ─────────────────────────╮\n",
-       " I'm sorry, but I cannot process messages about soup. This is a demonstration \n",
-       " guardrail for testing purposes. Please ask about something other than soup!  \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:34:26] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about soup. This is a demonstration \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m guardrail for testing purposes. Please ask about something other than soup! \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Streaming timed out after 30 seconds - returning collected messages\n" - ] - } - ], - "source": [ - "# Subscribe to see the soup guardrail response\n", - "task_messages_soup = subscribe_to_async_task_messages(\n", - " client=client,\n", - " task=task_soup, \n", - " only_after_timestamp=event_soup.created_at, \n", - " print_messages=True,\n", - " rich_print=True,\n", - " timeout=30,\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "id": "dae8d0be", - "metadata": {}, - "source": [ - "### Test 4: Pizza Output Guardrail\n" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "1abbe06b", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Task(id='ca2d107e-4f21-48f6-830a-61a03779895f', created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)), name='fbd68764-pizza-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Create a new task for pizza guardrail test\n", - "rpc_response = client.agents.create_task(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"name\": f\"{str(uuid.uuid4())[:8]}-pizza-test\",\n", - " \"params\": {}\n", - " }\n", - ")\n", - "\n", - "task_pizza = rpc_response.result\n", - "print(task_pizza)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "ea6b58b5", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Event(id='2b39425a-f3c0-409b-b725-2ee88e6ae178', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1846, task_id='ca2d107e-4f21-48f6-830a-61a03779895f', content=TextContent(author='user', content='What are some popular Italian dishes?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 969021, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Send event that might trigger pizza output guardrail\n", - "rpc_response = client.agents.send_event(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Italian dishes?\"},\n", - " \"task_id\": task_pizza.id,\n", - " }\n", - ")\n", - "\n", - "event_pizza = rpc_response.result\n", - "print(event_pizza)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "899be668", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
╭───────────────────────── USER [08/27/2025 21:34:57] ─────────────────────────╮\n",
-       " What are some popular Italian dishes?                                        \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:57] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m What are some popular Italian dishes? \u001b[96m│\u001b[0m\n", - "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:35:01] ─────────────────────────╮\n",
+       "
╭──────────────────────── AGENT [08/20/2025 22:47:34] ─────────────────────────╮\n",
        " 🧠 Reasoning                                                                 \n",
        "                                                                              \n",
-       " Listing popular Italian dishes                                               \n",
+       " Fetching latest AI news                                                      \n",
        "                                                                              \n",
-       " The user is asking about popular Italian dishes, which is simple enough!     \n",
-       " I’ll create a list that spans across various courses: antipasti, primi (like \n",
-       " pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I  \n",
-       " should mention regional specialties, aiming for 15-20 items. Key dishes will \n",
-       " include pizza, several pasta types like spaghetti alla carbonara and         \n",
-       " bolognese, risotto alla milanese, and more. I can also offer recipes or      \n",
-       " recommendations if they’d like.                                              \n",
+       " I’m getting ready to fetch the latest news using the web search tool. I      \n",
+       " think I’ll use the functions available and set it up with the model default. \n",
+       " I’ll choose search input focusing on \"latest AI news August 2025,\"           \n",
+       " especially regarding startups. I’ll consider everything relevant, like       \n",
+       " funding, layoffs, newly launched models, acquisitions, regulations, and      \n",
+       " venture capital. I just need to run the web search now to gather this        \n",
+       " information.                                                                 \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:01] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/20/2025 22:47:34] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mListing popular Italian dishes\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mFetching latest AI news\u001b[0m \u001b[95m│\u001b[0m\n", "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m The user is asking about popular Italian dishes, which is simple enough! \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I’ll create a list that spans across various courses: antipasti, primi (like \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m should mention regional specialties, aiming for 15-20 items. Key dishes will \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m include pizza, several pasta types like spaghetti alla carbonara and \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m bolognese, risotto alla milanese, and more. I can also offer recipes or \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m recommendations if they’d like. \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I’m getting ready to fetch the latest news using the web search tool. I \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m think I’ll use the functions available and set it up with the model default. \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I’ll choose search input focusing on \"latest AI news August 2025,\" \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m especially regarding startups. I’ll consider everything relevant, like \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m funding, layoffs, newly launched models, acquisitions, regulations, and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m venture capital. I just need to run the web search now to gather this \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m information. \u001b[95m│\u001b[0m\n", "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -455,666 +168,36 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:35:03] ─────────────────────────╮\n",
-       " Here are some popular Italian dishes, grouped by course with a short         \n",
-       " description for each:                                                        \n",
-       "                                                                              \n",
-       " Antipasti (starters)                                                         \n",
-       "                                                                              \n",
-       " Bruschetta: grilled bread rubbed with garlic and topped (commonly) with   \n",
-       "    tomatoes, basil, olive oil.                                               \n",
-       " Caprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \n",
-       " Carpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil   \n",
-       "    and parmesan.                                                             \n",
-       " Prosciutto e melone: cured ham served with cantaloupe.                    \n",
-       "                                                                              \n",
-       " Primi (first courses — usually pasta, rice or soup)                          \n",
-       "                                                                              \n",
-       " Spaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured  \n",
-       "    pork) and black pepper (Roman classic).                                   \n",
-       " Spaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna).       \n",
-       " Pasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice).    \n",
-       " Cacio e Pepe: very simple pasta with Pecorino cheese and black pepper     \n",
-       "    (Roman).                                                                  \n",
-       " Lasagna alla Bolognese: layered pasta with ragù, béchamel and cheese.     \n",
-       " Risotto alla Milanese: creamy saffron risotto (Milan).                    \n",
-       " Gnocchi: potato dumplings served with various sauces.                     \n",
-       " Minestrone: hearty vegetable soup.                                        \n",
-       "                                                                              \n",
-       " Secondi (main courses)                                                       \n",
-       "                                                                              \n",
-       " Pollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \n",
-       "    herbs, wine.                                                              \n",
-       " Saltimbocca alla Romana: veal topped with prosciutto and sage, cooked in  \n",
-       "    wine/butter (Rome).                                                       \n",
-       " Osso Buco: braised veal shanks, often served with risotto alla Milanese.  \n",
-       " Branzino al forno: roast sea bass (common coastal dish).                  \n",
-       " Parmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with  \n",
-       "    tomato sauce and cheese (Southern Italy).                                 \n",
-       "                                                                              \n",
-       " Contorni (sides)                                                             \n",
-       "                                                                              \n",
-       " Focaccia: flat oven-baked bread from Liguria (often seasoned with olive   \n",
-       "    oil, rosemary).                                                           \n",
-       " Polenta: cornmeal porridge, served soft or grilled (Northern Italy).      \n",
-       "                                                                              \n",
-       " Dolci (desserts)                                                             \n",
-       "                                                                              \n",
-       " Tiramisu: coffee-soaked ladyfingers layered with mascarpone cream.        \n",
-       " Gelato: Italian-style ice cream, denser and more intense than many ice    \n",
-       "    creams.                                                                   \n",
-       " Panna Cotta: creamy set dessert, often served with fruit coulis.          \n",
-       " Cannoli: Sicilian fried pastry tubes filled with sweet ricotta.           \n",
-       "                                                                              \n",
-       " Regional specialties worth noting                                            \n",
-       "                                                                              \n",
-       " Pizza Margherita (Naples): tomato, mozzarella, basil — the classic        \n",
-       "    Neapolitan pizza.                                                         \n",
-       " Arancini (Sicily): fried rice balls usually filled with ragù, peas and    \n",
-       "    cheese.                                                                   \n",
-       "                                                                              \n",
-       " If you’d like, I can:                                                        \n",
-       "                                                                              \n",
-       " Give recipes for any of these dishes,                                     \n",
-       " Suggest restaurants or regional variations, or                            \n",
-       " Provide wine-pairing ideas. Which would you prefer?                       \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:03] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m Here are some popular Italian dishes, grouped by course with a short \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m description for each: \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Antipasti (starters) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBruschetta: grilled bread rubbed with garlic and topped (commonly) with \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomatoes, basil, olive oil. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCaprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCarpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand parmesan. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProsciutto e melone: cured ham served with cantaloupe. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Primi (first courses — usually pasta, rice or soup) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mpork) and black pepper (Roman classic). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCacio e Pepe: very simple pasta with Pecorino cheese and black pepper \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0m(Roman). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mLasagna alla Bolognese: layered pasta with ragù, béchamel and cheese. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRisotto alla Milanese: creamy saffron risotto (Milan). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGnocchi: potato dumplings served with various sauces. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMinestrone: hearty vegetable soup. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Secondi (main courses) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mherbs, wine. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSaltimbocca alla Romana: veal topped with prosciutto and sage, cooked in \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwine/butter (Rome). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOsso Buco: braised veal shanks, often served with risotto alla Milanese. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBranzino al forno: roast sea bass (common coastal dish). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mParmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomato sauce and cheese (Southern Italy). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Contorni (sides) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mFocaccia: flat oven-baked bread from Liguria (often seasoned with olive \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moil, rosemary). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPolenta: cornmeal porridge, served soft or grilled (Northern Italy). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Dolci (desserts) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTiramisu: coffee-soaked ladyfingers layered with mascarpone cream. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGelato: Italian-style ice cream, denser and more intense than many ice \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcreams. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPanna Cotta: creamy set dessert, often served with fruit coulis. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCannoli: Sicilian fried pastry tubes filled with sweet ricotta. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Regional specialties worth noting \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPizza Margherita (Naples): tomato, mozzarella, basil — the classic \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mNeapolitan pizza. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mArancini (Sicily): fried rice balls usually filled with ragù, peas and \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcheese. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m If you’d like, I can: \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGive recipes for any of these dishes, \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSuggest restaurants or regional variations, or \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProvide wine-pairing ideas. Which would you prefer? \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:35:10] ─────────────────────────╮\n",
-       " I cannot provide this response as it mentions pizza. Due to content          \n",
-       " policies, I need to avoid discussing pizza. Let me provide a different       \n",
-       " response.                                                                    \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:10] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m I cannot provide this response as it mentions pizza. Due to content \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m policies, I need to avoid discussing pizza. Let me provide a different \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m response. \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Streaming timed out after 30 seconds - returning collected messages\n" - ] - } - ], - "source": [ - "# Subscribe to see if pizza output guardrail triggers\n", - "task_messages_pizza = subscribe_to_async_task_messages(\n", - " client=client,\n", - " task=task_pizza, \n", - " only_after_timestamp=event_pizza.created_at, \n", - " print_messages=True,\n", - " rich_print=True,\n", - " timeout=30,\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "id": "d59c0cfc", - "metadata": {}, - "source": [ - "### Test 5: Sushi Output Guardrail\n" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "0443e640", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Task(id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)), name='3bd766f1-sushi-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Create a new task for sushi guardrail test\n", - "rpc_response = client.agents.create_task(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"name\": f\"{str(uuid.uuid4())[:8]}-sushi-test\",\n", - " \"params\": {}\n", - " }\n", - ")\n", - "\n", - "task_sushi = rpc_response.result\n", - "print(task_sushi)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "7e7feb64", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Event(id='ab1f8ec6-5bdb-4b75-9999-f6b193de3772', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1847, task_id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', content=TextContent(author='user', content='What are some popular Japanese foods?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 983826, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Send event that might trigger sushi output guardrail\n", - "rpc_response = client.agents.send_event(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Japanese foods?\"},\n", - " \"task_id\": task_sushi.id,\n", - " }\n", - ")\n", - "\n", - "event_sushi = rpc_response.result\n", - "print(event_sushi)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "33d8b0f6", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
╭───────────────────────── USER [08/27/2025 21:35:49] ─────────────────────────╮\n",
-       " What are some popular Japanese foods?                                        \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:35:49] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m What are some popular Japanese foods? \u001b[96m│\u001b[0m\n", - "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:35:59] ─────────────────────────╮\n",
-       " 🧠 Reasoning                                                                 \n",
-       "                                                                              \n",
-       " Compiling popular Japanese foods                                             \n",
-       "                                                                              \n",
-       " The user is asking for a list of popular Japanese foods, likely with brief   \n",
-       " descriptions. I don’t need any tools for this, so I’ll compile a             \n",
-       " well-rounded list that covers items like sushi, sashimi, ramen, udon,        \n",
-       " tempura, and more, along with regional specialties and brief notes on        \n",
-       " etiquette like using chopsticks. I’ll keep it concise for a casual reader    \n",
-       " while including around 20 items with short descriptions and suggestions for  \n",
-       " where to try them. This will help create a great summary!                    \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:59] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", - "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[1mCompiling popular Japanese foods\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m The user is asking for a list of popular Japanese foods, likely with brief \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m descriptions. I don’t need any tools for this, so I’ll compile a \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m well-rounded list that covers items like sushi, sashimi, ramen, udon, \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m tempura, and more, along with regional specialties and brief notes on \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m etiquette like using chopsticks. I’ll keep it concise for a casual reader \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m while including around 20 items with short descriptions and suggestions for \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m where to try them. This will help create a great summary! \u001b[95m│\u001b[0m\n", - "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:36:00] ─────────────────────────╮\n",
-       " Here are many popular Japanese foods, with a short description of each so    \n",
-       " you know what to look for:                                                   \n",
-       "                                                                              \n",
-       " Sushi — Vinegared rice with raw fish or other toppings (nigiri, maki      \n",
-       "    rolls, chirashi).                                                         \n",
-       " Sashimi — Thinly sliced raw fish served with soy sauce and wasabi.        \n",
-       " Ramen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu)    \n",
-       "    with toppings like chashu pork and egg.                                   \n",
-       " Tempura — Lightly battered and deep-fried seafood or vegetables.          \n",
-       " Udon — Thick wheat noodles served hot in broth or chilled with a dipping  \n",
-       "    sauce.                                                                    \n",
-       " Soba — Buckwheat noodles, served hot or cold (zaru soba is a cold,        \n",
-       "    dipping style).                                                           \n",
-       " Yakitori — Skewered grilled chicken (various parts) usually seasoned with \n",
-       "    tare or salt.                                                             \n",
-       " Okonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka   \n",
-       "    and Hiroshima styles).                                                    \n",
-       " Takoyaki — Octopus-filled batter balls, topped with sauce, mayo and       \n",
-       "    bonito flakes—common street food.                                         \n",
-       " Tonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage   \n",
-       "    and tonkatsu sauce.                                                       \n",
-       " Gyoza — Pan-fried dumplings filled with pork and vegetables (also boiled  \n",
-       "    or steamed).                                                              \n",
-       " Karaage — Japanese-style fried chicken, marinated then deep-fried—crispy  \n",
-       "    and juicy.                                                                \n",
-       " Onigiri — Rice balls often wrapped in nori and filled with pickled plum,  \n",
-       "    salmon, or tuna mayo.                                                     \n",
-       " Miso soup — Soup made from miso paste with tofu, wakame seaweed and       \n",
-       "    scallions.                                                                \n",
-       " Bento — Packed meal box with rice, protein and side dishes—convenient and \n",
-       "    varied.                                                                   \n",
-       " Shabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in   \n",
-       "    boiling broth and dipped in sauces.                                       \n",
-       " Sukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and           \n",
-       "    vegetables, often dipped in raw egg.                                      \n",
-       " Yakiniku — Japanese-style barbecue where you grill slices of meat at the  \n",
-       "    table.                                                                    \n",
-       " Kaiseki — Multi-course traditional meal emphasizing seasonal ingredients  \n",
-       "    and presentation (formal dining).                                         \n",
-       " Natto — Fermented soybeans with a sticky texture and strong flavor (often \n",
-       "    eaten with rice).                                                         \n",
-       "                                                                              \n",
-       " Regional specialties to try:                                                 \n",
-       "                                                                              \n",
-       " Hakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido     \n",
-       "    seafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish).         \n",
-       "                                                                              \n",
-       " Tips:                                                                        \n",
-       "                                                                              \n",
-       " Many dishes have vegetarian/vegan variations (ask about dashi, which      \n",
-       "    often contains fish).                                                     \n",
-       " Try street-food stalls, izakayas (pubs), ramen shops, and traditional     \n",
-       "    ryokan or kaiseki restaurants for authentic experiences.                  \n",
-       "                                                                              \n",
-       " If you want, I can suggest: typical places to try any of these, simple       \n",
-       " recipes, or a short list of must-tries for a first-time visitor. Which would \n",
-       " you prefer?                                                                  \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:00] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m Here are many popular Japanese foods, with a short description of each so \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m you know what to look for: \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSushi — Vinegared rice with raw fish or other toppings (nigiri, maki \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mrolls, chirashi). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSashimi — Thinly sliced raw fish served with soy sauce and wasabi. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRamen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu) \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwith toppings like chashu pork and egg. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTempura — Lightly battered and deep-fried seafood or vegetables. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mUdon — Thick wheat noodles served hot in broth or chilled with a dipping \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msauce. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSoba — Buckwheat noodles, served hot or cold (zaru soba is a cold, \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mdipping style). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakitori — Skewered grilled chicken (various parts) usually seasoned with \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtare or salt. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOkonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand Hiroshima styles). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTakoyaki — Octopus-filled batter balls, topped with sauce, mayo and \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mbonito flakes—common street food. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand tonkatsu sauce. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGyoza — Pan-fried dumplings filled with pork and vegetables (also boiled \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mor steamed). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaraage — Japanese-style fried chicken, marinated then deep-fried—crispy \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand juicy. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOnigiri — Rice balls often wrapped in nori and filled with pickled plum, \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msalmon, or tuna mayo. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMiso soup — Soup made from miso paste with tofu, wakame seaweed and \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mscallions. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBento — Packed meal box with rice, protein and side dishes—convenient and \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvaried. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mShabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mboiling broth and dipped in sauces. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvegetables, often dipped in raw egg. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakiniku — Japanese-style barbecue where you grill slices of meat at the \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtable. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaiseki — Multi-course traditional meal emphasizing seasonal ingredients \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand presentation (formal dining). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mNatto — Fermented soybeans with a sticky texture and strong flavor (often \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0meaten with rice). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Regional specialties to try: \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mHakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mseafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m Tips: \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMany dishes have vegetarian/vegan variations (ask about dashi, which \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moften contains fish). \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTry street-food stalls, izakayas (pubs), ramen shops, and traditional \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mryokan or kaiseki restaurants for authentic experiences. \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m If you want, I can suggest: typical places to try any of these, simple \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m recipes, or a short list of must-tries for a first-time visitor. Which would \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m you prefer? \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:36:07] ─────────────────────────╮\n",
-       " I cannot mention sushi in my response. This guardrail prevents discussions   \n",
-       " about sushi for demonstration purposes. Please let me provide information    \n",
-       " about other topics.                                                          \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:07] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", - "\u001b[32m│\u001b[0m I cannot mention sushi in my response. This guardrail prevents discussions \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m about sushi for demonstration purposes. Please let me provide information \u001b[32m│\u001b[0m\n", - "\u001b[32m│\u001b[0m about other topics. \u001b[32m│\u001b[0m\n", - "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Streaming timed out after 30 seconds - returning collected messages\n" - ] - } - ], - "source": [ - "# Subscribe to see if sushi output guardrail triggers\n", - "task_messages_sushi = subscribe_to_async_task_messages(\n", - " client=client,\n", - " task=task_sushi, \n", - " only_after_timestamp=event_sushi.created_at, \n", - " print_messages=True,\n", - " rich_print=True,\n", - " timeout=30,\n", - ")\n" - ] - }, - { - "cell_type": "markdown", - "id": "5ade7d59", - "metadata": {}, - "source": [ - "### Test 6: Normal Conversation (No Guardrails Triggered)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "096a8784", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Task(id='e14d5602-bc80-4023-b523-354af82dcdc2', created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)), name='e8618275-normal-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Create a new task for normal conversation\n", - "rpc_response = client.agents.create_task(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"name\": f\"{str(uuid.uuid4())[:8]}-normal-test\",\n", - " \"params\": {}\n", - " }\n", - ")\n", - "\n", - "task_normal = rpc_response.result\n", - "print(task_normal)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "id": "ec04822d", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Event(id='406c31f1-5eb4-4a90-bd8d-825ddbddcfcd', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1848, task_id='e14d5602-bc80-4023-b523-354af82dcdc2', content=TextContent(author='user', content='What is 5 + 3? Use the calculator tool.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 593485, tzinfo=TzInfo(UTC)))\n" - ] - } - ], - "source": [ - "# Send event that won't trigger any guardrails\n", - "rpc_response = client.agents.send_event(\n", - " agent_name=AGENT_NAME,\n", - " params={\n", - " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What is 5 + 3? Use the calculator tool.\"},\n", - " \"task_id\": task_normal.id,\n", - " }\n", - ")\n", - "\n", - "event_normal = rpc_response.result\n", - "print(event_normal)\n" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "id": "3ab67e94", - "metadata": {}, - "outputs": [ - { - "data": { - "text/html": [ - "
╭───────────────────────── USER [08/27/2025 21:36:46] ─────────────────────────╮\n",
-       " What is 5 + 3? Use the calculator tool.                                      \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:36:46] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", - "\u001b[96m│\u001b[0m What is 5 + 3? Use the calculator tool. \u001b[96m│\u001b[0m\n", - "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:36:49] ─────────────────────────╮\n",
-       " 🧠 Reasoning                                                                 \n",
-       "                                                                              \n",
-       " I see the user wants to do a simple addition and prefers using the           \n",
-       " calculator tool. I'll call the functions.calculator with parameters a=5,     \n",
-       " b=3, and the operation set to \"add.\" It's pretty straightforward, and        \n",
-       " there's no need for sequential thinking here. Just a direct call to the tool \n",
-       " will do the job efficiently. So, I'll go ahead and call that function to get \n",
-       " the result for the user!                                                     \n",
-       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
-       "
\n" - ], - "text/plain": [ - "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:36:49] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", - "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m I see the user wants to do a simple addition and prefers using the \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m calculator tool. I'll call the functions.calculator with parameters a=5, \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m b=3, and the operation set to \"add.\" It's pretty straightforward, and \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m there's no need for sequential thinking here. Just a direct call to the tool \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m will do the job efficiently. So, I'll go ahead and call that function to get \u001b[95m│\u001b[0m\n", - "\u001b[95m│\u001b[0m the result for the user! \u001b[95m│\u001b[0m\n", - "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - " \r" - ] - }, - { - "data": { - "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
-       " 🔧 Tool Request: calculator                                                  \n",
+       "
╭──────────────────────── AGENT [08/20/2025 22:47:36] ─────────────────────────╮\n",
+       " 🔧 Tool Request: web_search                                                  \n",
        "                                                                              \n",
        " Arguments:                                                                   \n",
        "                                                                              \n",
        "                                                                              \n",
        "  {                                                                           \n",
-       "    \"a\": 5,                                                                   \n",
-       "    \"b\": 3,                                                                   \n",
-       "    \"operation\": \"add\"                                                        \n",
+       "    \"input\": \"latest AI news August 2025 AI startups funding layoffs          \n",
+       "  acquisitions new models regulation venture capital August 2025\",            \n",
+       "    \"model\": \"gpt-4o-mini\",                                                   \n",
+       "    \"type\": \"web_search_preview\",                                             \n",
+       "    \"search_context_size\": \"high\"                                             \n",
        "  }                                                                           \n",
        "                                                                              \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 21:36:51] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", - "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/20/2025 22:47:36] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: web_search\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", - "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"add\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"input\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"latest AI news August 2025 AI startups funding layoffs \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisitions new models regulation venture capital August 2025\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"model\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"gpt-4o-mini\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"type\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"web_search_preview\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"search_context_size\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"high\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" @@ -1133,18 +216,190 @@ { "data": { "text/html": [ - "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
-       "Tool Response: calculator                                                 \n",
+       "
╭──────────────────────── AGENT [08/20/2025 22:47:47] ─────────────────────────╮\n",
+       "Tool Response: web_search                                                 \n",
        "                                                                              \n",
-       " The result of 5.0 add 3.0 is 8                                               \n",
+       " Response:                                                                    \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"type\": \"text\",                                                           \n",
+       "    \"text\": \"As of August 20, 2025, the artificial intelligence (AI) sector   \n",
+       "  has experienced significant developments across funding, acquisitions,      \n",
+       "  layoffs, new model releases, and regulatory changes. Here's an overview of  \n",
+       "  the latest AI news:\\n\\n**Funding and Acquisitions:**\\n\\n- **TinyFish's $47  \n",
+       "  Million Series A Funding:** TinyFish, an AI startup specializing in         \n",
+       "  automating complex online tasks for enterprises, secured $47 million in a   \n",
+       "  Series A funding round led by ICONIQ Capital. The investment aims to enhan  \n",
+       "  product development and expand market reach.                                \n",
+       "  ([reuters.com](https://www.reuters.com/technology/ai-agent-startup-tinyfis  \n",
+       "  raises-47-million-iconiq-led-round-2025-08-20/?utm_source=openai))\\n\\n-     \n",
+       "  **Databricks' Valuation Surge:** Databricks, a San Francisco-based analyti  \n",
+       "  company, is poised to surpass a $100 billion valuation in its upcoming      \n",
+       "  funding round. This reflects strong investor enthusiasm for AI ventures,    \n",
+       "  with plans to advance product development and pursue mergers and            \n",
+       "  acquisitions within the AI space.                                           \n",
+       "  ([reuters.com](https://www.reuters.com/business/databricks-eyes-over-100-b  \n",
+       "  lion-valuation-investors-back-ai-growth-plans-2025-08-19/?utm_source=opena  \n",
+       "  )\\n\\n- **OpenAI's Acquisition of io:** OpenAI announced the $6.5 billion    \n",
+       "  acquisition of io, an AI hardware startup founded by former Apple designer  \n",
+       "  Jony Ive. The merger aims to integrate hardware and software development,   \n",
+       "  with Ive assuming creative responsibilities across OpenAI.                  \n",
+       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/OpenAI?utm_source=openai  \n",
+       "  \\n\\n**Layoffs:**\\n\\n- **Recruit Holdings' Workforce Reduction:** Recruit    \n",
+       "  Holdings, the parent company of Indeed and Glassdoor, is laying off         \n",
+       "  approximately 1,300 employees, about 6% of its HR technology unit. This mo  \n",
+       "  is part of a strategic shift toward integrating AI technologies and         \n",
+       "  streamlining operations.                                                    \n",
+       "  ([linkedin.com](https://www.linkedin.com/pulse/ai-news-funding-updates-fro  \n",
+       "  last-24-hours11th-july-2025-anshuman-jha-2d20c?utm_source=openai))\\n\\n-     \n",
+       "  **Meta's Staff Reduction:** Meta announced a 5% reduction in its workforce  \n",
+       "  targeting \\\"low performers\\\" as the company prepares for an \\\"intense       \n",
+       "  year.\\\" This decision reflects ongoing efforts to optimize operations amid  \n",
+       "  evolving market conditions.                                                 \n",
+       "  ([techcrunch.com](https://techcrunch.com/2025/07/31/tech-layoffs-2025-list  \n",
+       "  utm_source=openai))\\n\\n**New AI Models:**\\n\\n- **OpenAI's GPT-5 Release:**  \n",
+       "  OpenAI released GPT-5, the latest iteration of its language model, offerin  \n",
+       "  enhanced capabilities and performance. This release signifies continued     \n",
+       "  advancements in AI language processing.                                     \n",
+       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel  \n",
+       "  gence?utm_source=openai))\\n\\n- **Google's A.I. Mode and Veo 3:** Google     \n",
+       "  introduced A.I. Mode, a feature on its search engine powered by the Gemini  \n",
+       "  model, and Veo 3, a new state-of-the-art video generation model. These      \n",
+       "  developments highlight Google's commitment to integrating advanced AI into  \n",
+       "  its services.                                                               \n",
+       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel  \n",
+       "  gence?utm_source=openai))\\n\\n**Regulatory Developments:**\\n\\n- **U.S.       \n",
+       "  Federal AI Regulation Freeze:** The U.S. federal government has implemente  \n",
+       "  a 10-year freeze on state-level AI regulation, preventing individual state  \n",
+       "  from enacting rules governing AI systems. This move aims to establish a     \n",
+       "  unified federal approach to AI governance.                                  \n",
+       "  ([techradar.com](https://www.techradar.com/pro/the-u-s-is-blocking-state-a  \n",
+       "  regulation-heres-what-that-means-for-every-business?utm_source=openai))\\n\\  \n",
+       "   **European Union's AI Act Implementation:** The EU's Artificial            \n",
+       "  Intelligence Act, which came into force on August 1, 2024, is set to be     \n",
+       "  fully applicable by August 2, 2025. The Act establishes a regulatory        \n",
+       "  framework for AI, categorizing applications based on risk levels and        \n",
+       "  imposing corresponding obligations.                                         \n",
+       "  ([en.wikipedia.org](https://en.wikipedia.org/wiki/Artificial_Intelligence_  \n",
+       "  t?utm_source=openai))\\n\\n**Venture Capital Trends:**\\n\\n- **Continued       \n",
+       "  Investment in AI Startups:** Venture capital investment in AI companies     \n",
+       "  remains robust, with global funding exceeding $100 billion in 2024, markin  \n",
+       "  an 80% increase from the previous year. This trend underscores the growing  \n",
+       "  confidence in AI's transformative potential across various sectors.         \n",
+       "  ([natlawreview.com](https://natlawreview.com/article/state-funding-market-  \n",
+       "  -companies-2024-2025-outlook?utm_source=openai))\\n\\nThese developments      \n",
+       "  reflect the dynamic and rapidly evolving landscape of the AI industry,      \n",
+       "  encompassing significant financial investments, strategic corporate         \n",
+       "  decisions, technological advancements, and regulatory shifts.\\n\\n\\n## Rece  \n",
+       "  Developments in AI Industry:\\n- [AI agent startup TinyFish raises $47       \n",
+       "  million in ICONIQ-led                                                       \n",
+       "  round](https://www.reuters.com/technology/ai-agent-startup-tinyfish-raises  \n",
+       "  7-million-iconiq-led-round-2025-08-20/?utm_source=openai)\\n- [Databricks    \n",
+       "  eyes over $100 billion valuation as investors back AI growth                \n",
+       "  plans](https://www.reuters.com/business/databricks-eyes-over-100-billion-v  \n",
+       "  uation-investors-back-ai-growth-plans-2025-08-19/?utm_source=openai)\\n- [T  \n",
+       "  U.S. is blocking state AI regulation. Here's what that means for every      \n",
+       "  business](https://www.techradar.com/pro/the-u-s-is-blocking-state-ai-regul  \n",
+       "  ion-heres-what-that-means-for-every-business?utm_source=openai) \",          \n",
+       "    \"annotations\": null,                                                      \n",
+       "    \"meta\": null                                                              \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
        "╰──────────────────────────────────────────────────────────────────────────────╯\n",
        "
\n" ], "text/plain": [ - "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 21:36:51] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", - "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/20/2025 22:47:47] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: web_search\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[1mResponse:\u001b[0m \u001b[92m│\u001b[0m\n", "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", - "\u001b[92m│\u001b[0m The result of 5.0 add 3.0 is 8 \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"type\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"text\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"text\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"As of August 20, 2025, the artificial intelligence (AI) sector \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mhas experienced significant developments across funding, acquisitions, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlayoffs, new model releases, and regulatory changes. Here's an overview of\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mthe latest AI news:\\n\\n**Funding and Acquisitions:**\\n\\n- **TinyFish's $47\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mMillion Series A Funding:** TinyFish, an AI startup specializing in \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mautomating complex online tasks for enterprises, secured $47 million in a \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mSeries A funding round led by ICONIQ Capital. The investment aims to enhan\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mproduct development and expand market reach. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([reuters.com](https://www.reuters.com/technology/ai-agent-startup-tinyfis\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mraises-47-million-iconiq-led-round-2025-08-20/?utm_source=openai))\\n\\n- \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m**Databricks' Valuation Surge:** Databricks, a San Francisco-based analyti\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mcompany, is poised to surpass a $100 billion valuation in its upcoming \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfunding round. This reflects strong investor enthusiasm for AI ventures, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mwith plans to advance product development and pursue mergers and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisitions within the AI space. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([reuters.com](https://www.reuters.com/business/databricks-eyes-over-100-b\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlion-valuation-investors-back-ai-growth-plans-2025-08-19/?utm_source=opena\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m)\\n\\n- **OpenAI's Acquisition of io:** OpenAI announced the $6.5 billion \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34macquisition of io, an AI hardware startup founded by former Apple designer\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mJony Ive. The merger aims to integrate hardware and software development, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mwith Ive assuming creative responsibilities across OpenAI. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/OpenAI?utm_source=openai\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\\n\\n**Layoffs:**\\n\\n- **Recruit Holdings' Workforce Reduction:** Recruit \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mHoldings, the parent company of Indeed and Glassdoor, is laying off \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mapproximately 1,300 employees, about 6% of its HR technology unit. This mo\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mis part of a strategic shift toward integrating AI technologies and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mstreamlining operations. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([linkedin.com](https://www.linkedin.com/pulse/ai-news-funding-updates-fro\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mlast-24-hours11th-july-2025-anshuman-jha-2d20c?utm_source=openai))\\n\\n- \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m**Meta's Staff Reduction:** Meta announced a 5% reduction in its workforce\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mtargeting \\\"low performers\\\" as the company prepares for an \\\"intense \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34myear.\\\" This decision reflects ongoing efforts to optimize operations amid\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mevolving market conditions. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([techcrunch.com](https://techcrunch.com/2025/07/31/tech-layoffs-2025-list\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mutm_source=openai))\\n\\n**New AI Models:**\\n\\n- **OpenAI's GPT-5 Release:**\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mOpenAI released GPT-5, the latest iteration of its language model, offerin\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34menhanced capabilities and performance. This release signifies continued \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34madvancements in AI language processing. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mgence?utm_source=openai))\\n\\n- **Google's A.I. Mode and Veo 3:** Google \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mintroduced A.I. Mode, a feature on its search engine powered by the Gemini\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mmodel, and Veo 3, a new state-of-the-art video generation model. These \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mdevelopments highlight Google's commitment to integrating advanced AI into\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mits services. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/2025_in_artificial_intel\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mgence?utm_source=openai))\\n\\n**Regulatory Developments:**\\n\\n- **U.S. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mFederal AI Regulation Freeze:** The U.S. federal government has implemente\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34ma 10-year freeze on state-level AI regulation, preventing individual state\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfrom enacting rules governing AI systems. This move aims to establish a \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34munified federal approach to AI governance. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([techradar.com](https://www.techradar.com/pro/the-u-s-is-blocking-state-a\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mregulation-heres-what-that-means-for-every-business?utm_source=openai))\\n\\\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m **European Union's AI Act Implementation:** The EU's Artificial \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mIntelligence Act, which came into force on August 1, 2024, is set to be \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mfully applicable by August 2, 2025. The Act establishes a regulatory \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mframework for AI, categorizing applications based on risk levels and \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mimposing corresponding obligations. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([en.wikipedia.org](https://en.wikipedia.org/wiki/Artificial_Intelligence_\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mt?utm_source=openai))\\n\\n**Venture Capital Trends:**\\n\\n- **Continued \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mInvestment in AI Startups:** Venture capital investment in AI companies \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mremains robust, with global funding exceeding $100 billion in 2024, markin\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34man 80% increase from the previous year. This trend underscores the growing\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mconfidence in AI's transformative potential across various sectors. \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m([natlawreview.com](https://natlawreview.com/article/state-funding-market-\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m-companies-2024-2025-outlook?utm_source=openai))\\n\\nThese developments \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mreflect the dynamic and rapidly evolving landscape of the AI industry, \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mencompassing significant financial investments, strategic corporate \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mdecisions, technological advancements, and regulatory shifts.\\n\\n\\n## Rece\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mDevelopments in AI Industry:\\n- [AI agent startup TinyFish raises $47 \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mmillion in ICONIQ-led \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mround](https://www.reuters.com/technology/ai-agent-startup-tinyfish-raises\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m7-million-iconiq-led-round-2025-08-20/?utm_source=openai)\\n- [Databricks \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34meyes over $100 billion valuation as investors back AI growth \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mplans](https://www.reuters.com/business/databricks-eyes-over-100-billion-v\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34muation-investors-back-ai-growth-plans-2025-08-19/?utm_source=openai)\\n- [T\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mU.S. is blocking state AI regulation. Here's what that means for every \u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mbusiness](https://www.techradar.com/pro/the-u-s-is-blocking-state-ai-regul\u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34mion-heres-what-that-means-for-every-business?utm_source=openai) \"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"annotations\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;102;217;239;48;2;39;40;34mnull\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"meta\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;102;217;239;48;2;39;40;34mnull\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[92m│\u001b[0m\n", "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" ] }, @@ -1155,20 +410,22 @@ "name": "stdout", "output_type": "stream", "text": [ - "Streaming timed out after 30 seconds - returning collected messages\n" + "Streaming timed out after 60 seconds - returning collected messages\n" ] } ], "source": [ - "# Subscribe to see normal response without guardrails\n", - "task_messages_normal = subscribe_to_async_task_messages(\n", + "# Subscribe to the async task messages produced by the agent\n", + "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n", + "\n", + "task_messages = subscribe_to_async_task_messages(\n", " client=client,\n", - " task=task_normal, \n", - " only_after_timestamp=event_normal.created_at, \n", + " task=task, \n", + " only_after_timestamp=event.created_at, \n", " print_messages=True,\n", " rich_print=True,\n", - " timeout=30,\n", - ")\n" + " timeout=60,\n", + ")" ] } ], diff --git a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py index 1dbcca50..2ef81323 100644 --- a/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py +++ b/examples/tutorials/10_agentic/10_temporal/010_agent_chat/project/workflow.py @@ -20,13 +20,9 @@ from agentex.lib.types.tracing import SGPTracingProcessorConfig from agentex.lib.environment_variables import EnvironmentVariables from agentex.types.text_content import TextContent -from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # noqa: E501 +from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( FunctionTool, - TemporalInputGuardrail, - TemporalOutputGuardrail, ) -from agents.guardrail import GuardrailFunctionOutput -from agents import Agent environment_variables = EnvironmentVariables.refresh() load_dotenv(dotenv_path=".env") @@ -127,220 +123,12 @@ async def calculator(context: RunContextWrapper, args: str) -> str: return f"Error: An unexpected error occurred: {str(e)}" -""" -Guardrails for Testing: -- Input Guardrails: - - Spaghetti: Blocks any mention of "spaghetti" in user messages - - Soup: Blocks any mention of "soup" in user messages -- Output Guardrails: - - Pizza: Blocks the AI from mentioning "pizza" in responses - - Sushi: Blocks the AI from mentioning "sushi" in responses - -To test: -- Input: "Tell me about spaghetti" or "What's your favorite soup?" -- Output: Ask "What are popular Italian foods?" (might trigger pizza guardrail) - or "What are popular Japanese foods?" (might trigger sushi guardrail) -""" - - -# Define the spaghetti guardrail function -async def check_spaghetti_guardrail( - ctx: RunContextWrapper[None], - agent: Agent, - input: str | list -) -> GuardrailFunctionOutput: - """ - A simple guardrail that checks if 'spaghetti' is mentioned in the input. - """ - # Convert input to string to check - input_text = "" - if isinstance(input, str): - input_text = input.lower() - elif isinstance(input, list): - # For list of messages, check all user messages - for msg in input: - if isinstance(msg, dict) and msg.get("role") == "user": - content = msg.get("content", "") - if isinstance(content, str): - input_text += " " + content.lower() - - # Check if spaghetti is mentioned - contains_spaghetti = "spaghetti" in input_text - - return GuardrailFunctionOutput( - output_info={ - "contains_spaghetti": contains_spaghetti, - "checked_text": ( - input_text[:200] + "..." - if len(input_text) > 200 else input_text - ), - "rejection_message": ( - "I'm sorry, but I cannot process messages about spaghetti. " - "This guardrail was put in place for demonstration purposes. " - "Please ask me about something else!" - ) if contains_spaghetti else None - }, - tripwire_triggered=contains_spaghetti - ) - - -# Define soup input guardrail function -async def check_soup_guardrail( - ctx: RunContextWrapper[None], - agent: Agent, - input: str | list -) -> GuardrailFunctionOutput: - """ - A guardrail that checks if 'soup' is mentioned in the input. - """ - # Convert input to string to check - input_text = "" - if isinstance(input, str): - input_text = input.lower() - elif isinstance(input, list): - # For list of messages, check all user messages - for msg in input: - if isinstance(msg, dict) and msg.get("role") == "user": - content = msg.get("content", "") - if isinstance(content, str): - input_text += " " + content.lower() - - # Check if soup is mentioned - contains_soup = "soup" in input_text - - return GuardrailFunctionOutput( - output_info={ - "contains_soup": contains_soup, - "checked_text": ( - input_text[:200] + "..." - if len(input_text) > 200 else input_text - ), - "rejection_message": ( - "I'm sorry, but I cannot process messages about soup. " - "This is a demonstration guardrail for testing purposes. " - "Please ask about something other than soup!" - ) if contains_soup else None - }, - tripwire_triggered=contains_soup - ) - - -# Create the input guardrails -SPAGHETTI_GUARDRAIL = TemporalInputGuardrail( - guardrail_function=check_spaghetti_guardrail, - name="spaghetti_guardrail" -) - -SOUP_GUARDRAIL = TemporalInputGuardrail( - guardrail_function=check_soup_guardrail, - name="soup_guardrail" -) - - -# Define pizza output guardrail function -async def check_pizza_guardrail( - ctx: RunContextWrapper[None], - agent: Agent, - output: str -) -> GuardrailFunctionOutput: - """ - An output guardrail that prevents mentioning pizza. - """ - output_text = output.lower() if isinstance(output, str) else "" - contains_pizza = "pizza" in output_text - - return GuardrailFunctionOutput( - output_info={ - "contains_pizza": contains_pizza, - "rejection_message": ( - "I cannot provide this response as it mentions pizza. " - "Due to content policies, I need to avoid discussing pizza. " - "Let me provide a different response." - ) if contains_pizza else None - }, - tripwire_triggered=contains_pizza - ) - - -# Define sushi output guardrail function -async def check_sushi_guardrail( - ctx: RunContextWrapper[None], - agent: Agent, - output: str -) -> GuardrailFunctionOutput: - """ - An output guardrail that prevents mentioning sushi. - """ - output_text = output.lower() if isinstance(output, str) else "" - contains_sushi = "sushi" in output_text - - return GuardrailFunctionOutput( - output_info={ - "contains_sushi": contains_sushi, - "rejection_message": ( - "I cannot mention sushi in my response. " - "This guardrail prevents discussions about sushi for demonstration purposes. " - "Please let me provide information about other topics." - ) if contains_sushi else None - }, - tripwire_triggered=contains_sushi - ) - - -# Create the output guardrails -PIZZA_GUARDRAIL = TemporalOutputGuardrail( - guardrail_function=check_pizza_guardrail, - name="pizza_guardrail" -) - -SUSHI_GUARDRAIL = TemporalOutputGuardrail( - guardrail_function=check_sushi_guardrail, - name="sushi_guardrail" -) - - -# Example output guardrail function (kept for reference) -async def check_output_length_guardrail( - ctx: RunContextWrapper[None], - agent: Agent, - output: str -) -> GuardrailFunctionOutput: - """ - A simple output guardrail that checks if the response is too long. - """ - # Check the length of the output - max_length = 1000 # Maximum allowed characters - is_too_long = len(output) > max_length if isinstance(output, str) else False - - return GuardrailFunctionOutput( - output_info={ - "output_length": len(output) if isinstance(output, str) else 0, - "max_length": max_length, - "is_too_long": is_too_long, - "rejection_message": ( - f"I'm sorry, but my response is too long ({len(output)} characters). " - f"Please ask a more specific question so I can provide a concise answer " - f"(max {max_length} characters)." - ) if is_too_long else None - }, - tripwire_triggered=is_too_long - ) - - -# Uncomment to use the output guardrail -# from agentex.lib.core.temporal.activities.adk.providers.openai_activities import TemporalOutputGuardrail -# OUTPUT_LENGTH_GUARDRAIL = TemporalOutputGuardrail( -# guardrail_function=check_output_length_guardrail, -# name="output_length_guardrail" -# ) - - # Create the calculator tool CALCULATOR_TOOL = FunctionTool( name="calculator", description=( - "Performs basic arithmetic operations (add, subtract, multiply, " - "divide) on two numbers." + "Performs basic arithmetic operations (add, subtract, multiply, divide) " + "on two numbers." ), params_json_schema={ "type": "object", @@ -402,9 +190,7 @@ async def on_task_event_send(self, params: SendEventParams) -> None: name=f"Turn {self._state.turn_number}", input=self._state, ) as span: - # Echo back the user's message so it shows up in the UI. - # This is not done by default so the agent developer has full - # control over what is shown to the user. + # Echo back the user's message so it shows up in the UI. This is not done by default so the agent developer has full control over what is shown to the user. await adk.messages.create( task_id=params.task.id, trace_id=params.task.id, @@ -433,38 +219,33 @@ async def on_task_event_send(self, params: SendEventParams) -> None: # Call an LLM to respond to the user's message # When send_as_agent_task_message=True, returns a TaskMessage - result = await adk.providers.openai.run_agent_streamed_auto_send( + run_result = await adk.providers.openai.run_agent_streamed_auto_send( task_id=params.task.id, trace_id=params.task.id, input_list=self._state.input_list, mcp_server_params=MCP_SERVERS, agent_name="Tool-Enabled Assistant", agent_instructions=( - "You are a helpful assistant that can answer " - "questions using various tools. You have access to " - "sequential thinking and web search capabilities " - "through MCP servers, as well as a calculator tool " - "for performing basic arithmetic operations. Use " - "these tools when appropriate to provide accurate " - "and well-reasoned responses." + "You are a helpful assistant that can answer questions " + "using various tools. You have access to sequential " + "thinking and web search capabilities through MCP servers, " + "as well as a calculator tool for performing basic " + "arithmetic operations. Use these tools when appropriate " + "to provide accurate and well-reasoned responses." ), parent_span_id=span.id if span else None, model="gpt-5-mini", model_settings=ModelSettings( - # Include reasoning items in the response - # (IDs, summaries) + # Include reasoning items in the response (IDs, summaries) # response_include=["reasoning.encrypted_content"], # Ask the model to include a short reasoning summary reasoning=Reasoning(effort="medium", summary="detailed"), ), - tools=[CALCULATOR_TOOL], - input_guardrails=[SPAGHETTI_GUARDRAIL, SOUP_GUARDRAIL], - output_guardrails=[PIZZA_GUARDRAIL, SUSHI_GUARDRAIL], + # tools=[CALCULATOR_TOOL], ) - - # Update state with the final input list from result - if self._state and result: - final_list = getattr(result, "final_input_list", None) + if self._state: + # Update the state with the final input list if available + final_list = getattr(run_result, "final_input_list", None) if final_list is not None: self._state.input_list = final_list @@ -477,27 +258,19 @@ async def on_task_event_send(self, params: SendEventParams) -> None: async def on_task_create(self, params: CreateTaskParams) -> None: logger.info(f"Received task create params: {params}") - # 1. Initialize the state. You can either do this here or in the - # __init__ method. This function is triggered whenever a client - # creates a task for this agent. It is not re-triggered when a new - # event is sent to the task. + # 1. Initialize the state. You can either do this here or in the __init__ method. + # This function is triggered whenever a client creates a task for this agent. + # It is not re-triggered when a new event is sent to the task. self._state = StateModel( input_list=[], turn_number=0, ) - # 2. Wait for the task to be completed indefinitely. If we don't do - # this the workflow will close as soon as this function returns. - # Temporal can run hundreds of millions of workflows in parallel, - # so you don't need to worry about too many workflows running at once. + # 2. Wait for the task to be completed indefinitely. If we don't do this the workflow will close as soon as this function returns. Temporal can run hundreds of millions of workflows in parallel, so you don't need to worry about too many workflows running at once. - # Thus, if you want this agent to field events indefinitely (or for - # a long time) you need to wait for a condition to be met. + # Thus, if you want this agent to field events indefinitely (or for a long time) you need to wait for a condition to be met. await workflow.wait_condition( lambda: self._complete_task, - timeout=None, # Set a timeout if you want to prevent the task - # from running indefinitely. Generally this is not needed. - # Temporal can run hundreds of millions of workflows in parallel - # and more. Only do this if you have a specific reason to do so. + timeout=None, # Set a timeout if you want to prevent the task from running indefinitely. Generally this is not needed. Temporal can run hundreds of millions of workflows in parallel and more. Only do this if you have a specific reason to do so. ) From a8bbc9d3c4d1cd861d2ba8e6946dceb92b786286 Mon Sep 17 00:00:00 2001 From: Bill Zhang Date: Tue, 2 Sep 2025 01:10:31 -0700 Subject: [PATCH 4/4] Other files --- .../050_agent_chat_guardrails/.dockerignore | 43 + .../050_agent_chat_guardrails/Dockerfile | 46 + .../050_agent_chat_guardrails/README.md | 42 + .../050_agent_chat_guardrails/dev.ipynb | 1196 +++++++++ .../050_agent_chat_guardrails/manifest.yaml | 138 + .../project/__init__.py | 0 .../050_agent_chat_guardrails/project/acp.py | 31 + .../project/run_worker.py | 37 + .../project/workflow.py | 515 ++++ .../050_agent_chat_guardrails/pyproject.toml | 34 + .../050_agent_chat_guardrails/uv.lock | 2262 +++++++++++++++++ 11 files changed, 4344 insertions(+) create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/.dockerignore create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/Dockerfile create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/README.md create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/dev.ipynb create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/manifest.yaml create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/__init__.py create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/acp.py create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/run_worker.py create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/workflow.py create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/pyproject.toml create mode 100644 examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/uv.lock diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/.dockerignore b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/.dockerignore new file mode 100644 index 00000000..c2d7fca4 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/.dockerignore @@ -0,0 +1,43 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# Environments +.env** +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# IDE +.idea/ +.vscode/ +*.swp +*.swo + +# Git +.git +.gitignore + +# Misc +.DS_Store diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/Dockerfile b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/Dockerfile new file mode 100644 index 00000000..eda1cf62 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/Dockerfile @@ -0,0 +1,46 @@ +# syntax=docker/dockerfile:1.3 +FROM python:3.12-slim +COPY --from=ghcr.io/astral-sh/uv:0.6.4 /uv /uvx /bin/ + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + htop \ + vim \ + curl \ + tar \ + python3-dev \ + postgresql-client \ + build-essential \ + libpq-dev \ + gcc \ + cmake \ + netcat-openbsd \ + && apt-get clean \ + && rm -rf /var/lib/apt/lists/* + +# Install tctl (Temporal CLI) +RUN curl -L https://github.com/temporalio/tctl/releases/download/v1.18.1/tctl_1.18.1_linux_arm64.tar.gz -o /tmp/tctl.tar.gz && \ + tar -xzf /tmp/tctl.tar.gz -C /usr/local/bin && \ + chmod +x /usr/local/bin/tctl && \ + rm /tmp/tctl.tar.gz + +RUN uv pip install --system --upgrade pip setuptools wheel + +ENV UV_HTTP_TIMEOUT=1000 + +# Copy just the requirements file to optimize caching +COPY 010_agent_chat/requirements.txt /app/requirements.txt + +WORKDIR /app/ + +# Install the required Python packages +RUN uv pip install --system -r requirements.txt + +# Copy the project code +COPY 010_agent_chat/project /app/project + +# Run the ACP server using uvicorn +CMD ["uvicorn", "project.acp:acp", "--host", "0.0.0.0", "--port", "8000"] + +# When we deploy the worker, we will replace the CMD with the following +# CMD ["python", "-m", "run_worker"] \ No newline at end of file diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/README.md b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/README.md new file mode 100644 index 00000000..9eb75f98 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/README.md @@ -0,0 +1,42 @@ +# [Agentic] Agent Chat with Guardrails + +This tutorial demonstrates how to implement streaming multiturn tool-enabled chat with input and output guardrails using Temporal workflows in AgentEx agents. + +## Overview + +This example extends the basic agent chat functionality by adding guardrails that can filter both user inputs and AI outputs. This is useful for content moderation, compliance, or preventing certain topics from being discussed. + +## Guardrails + +### Input Guardrails +- **Spaghetti Guardrail**: Blocks any mention of "spaghetti" in user messages +- **Soup Guardrail**: Blocks any mention of "soup" in user messages + +### Output Guardrails +- **Pizza Guardrail**: Prevents the AI from mentioning "pizza" in responses +- **Sushi Guardrail**: Prevents the AI from mentioning "sushi" in responses + +## Testing the Guardrails + +To see the guardrails in action: + +1. **Test Input Guardrails:** + - Try: "Tell me about spaghetti" + - Try: "What's your favorite soup?" + - The guardrails will block these messages before they reach the AI + +2. **Test Output Guardrails:** + - Ask: "What are popular Italian foods?" (may trigger pizza guardrail) + - Ask: "What are popular Japanese foods?" (may trigger sushi guardrail) + - The AI may generate responses containing these words, but the guardrails will block them + +## Implementation Details + +The guardrails are implemented as functions that: +- Check the input/output for specific content +- Return a `GuardrailFunctionOutput` with: + - `tripwire_triggered`: Whether to block the content + - `output_info`: Metadata about the check + - `rejection_message`: Custom message shown when content is blocked + +See `workflow.py` for the complete implementation. \ No newline at end of file diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/dev.ipynb b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/dev.ipynb new file mode 100644 index 00000000..ab87b676 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/dev.ipynb @@ -0,0 +1,1196 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "0", + "metadata": {}, + "outputs": [], + "source": [ + "from agentex import Agentex\n", + "\n", + "client = Agentex(base_url=\"http://localhost:5003\")" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1", + "metadata": {}, + "outputs": [], + "source": [ + "AGENT_NAME = \"at010-agent-chat\"" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', created_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)), name='7ff11264-task', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 33, 21, 976210, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# (REQUIRED) Create a new task. For Agentic agents, you must create a task for messages to be associated with.\n", + "import uuid\n", + "\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-task\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task = rpc_response.result\n", + "print(task)" + ] + }, + { + "cell_type": "markdown", + "id": "645fb612", + "metadata": {}, + "source": [ + "## Testing Guardrails\n", + "\n", + "We have configured 4 guardrails:\n", + "- **Input Guardrails**: Spaghetti (tested above), Soup\n", + "- **Output Guardrails**: Pizza, Sushi\n" + ] + }, + { + "cell_type": "markdown", + "id": "11d260f4", + "metadata": {}, + "source": [ + "### Test 2: Soup Input Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "3", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='b243f073-a7cb-4420-b513-305c2b6aae5d', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1844, task_id='0577cdc8-6c6a-4ef7-bc5c-85d27b9327e7', content=TextContent(author='user', content='Find me a recipe on spaghetti', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 33, 22, 16063, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send an event to the agent\n", + "\n", + "# The response is expected to be a list of TaskMessage objects, which is a union of the following types:\n", + "# - TextContent: A message with just text content \n", + "# - DataContent: A message with JSON-serializable data content\n", + "# - ToolRequestContent: A message with a tool request, which contains a JSON-serializable request to call a tool\n", + "# - ToolResponseContent: A message with a tool response, which contains response object from a tool call in its content\n", + "# - ReasoningContent: A message with a reasoning content, which contains a reasoning object from a tool call in its content\n", + "\n", + "# When processing the message/send response, if you are expecting more than TextContent, such as DataContent, ToolRequestContent, or ToolResponseContent, you can process them as well\n", + "\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"Find me a recipe on spaghetti\"},\n", + " \"task_id\": task.id,\n", + " }\n", + ")\n", + "\n", + "event = rpc_response.result\n", + "print(event)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 21:33:22] ─────────────────────────╮\n",
+       " Find me a recipe on spaghetti                                                \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:33:22] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m Find me a recipe on spaghetti \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:33:25] ─────────────────────────╮\n",
+       " I'm sorry, but I cannot process messages about spaghetti. This guardrail was \n",
+       " put in place for demonstration purposes. Please ask me about something else! \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:33:25] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about spaghetti. This guardrail was \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m put in place for demonstration purposes. Please ask me about something else! \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 60 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to the async task messages produced by the agent\n", + "from agentex.lib.utils.dev_tools import subscribe_to_async_task_messages\n", + "\n", + "task_messages = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task, \n", + " only_after_timestamp=event.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=60,\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "ff7cf427", + "metadata": {}, + "source": [ + "### Test 3: Soup Input Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "ea464eea", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)), name='66fd90bb-soup-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 397654, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for soup guardrail test\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-soup-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_soup = rpc_response.result\n", + "print(task_soup)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "48d40391", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='90d002ac-ff06-4d36-8af7-b764420ae2ff', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1845, task_id='b34a414a-5753-4c6c-a6f5-aa8eabb6a731', content=TextContent(author='user', content=\"What's your favorite soup recipe?\", attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 25, 427792, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send event that triggers soup guardrail\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What's your favorite soup recipe?\"},\n", + " \"task_id\": task_soup.id,\n", + " }\n", + ")\n", + "\n", + "event_soup = rpc_response.result\n", + "print(event_soup)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "154c6498", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 21:34:25] ─────────────────────────╮\n",
+       " What's your favorite soup recipe?                                            \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:25] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What's your favorite soup recipe? \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:34:26] ─────────────────────────╮\n",
+       " I'm sorry, but I cannot process messages about soup. This is a demonstration \n",
+       " guardrail for testing purposes. Please ask about something other than soup!  \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:34:26] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I'm sorry, but I cannot process messages about soup. This is a demonstration \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m guardrail for testing purposes. Please ask about something other than soup! \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 30 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to see the soup guardrail response\n", + "task_messages_soup = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_soup, \n", + " only_after_timestamp=event_soup.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "dae8d0be", + "metadata": {}, + "source": [ + "### Test 4: Pizza Output Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1abbe06b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='ca2d107e-4f21-48f6-830a-61a03779895f', created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)), name='fbd68764-pizza-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 922244, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for pizza guardrail test\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-pizza-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_pizza = rpc_response.result\n", + "print(task_pizza)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "ea6b58b5", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='2b39425a-f3c0-409b-b725-2ee88e6ae178', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1846, task_id='ca2d107e-4f21-48f6-830a-61a03779895f', content=TextContent(author='user', content='What are some popular Italian dishes?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 34, 56, 969021, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send event that might trigger pizza output guardrail\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Italian dishes?\"},\n", + " \"task_id\": task_pizza.id,\n", + " }\n", + ")\n", + "\n", + "event_pizza = rpc_response.result\n", + "print(event_pizza)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "899be668", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 21:34:57] ─────────────────────────╮\n",
+       " What are some popular Italian dishes?                                        \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:34:57] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What are some popular Italian dishes? \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:35:01] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " Listing popular Italian dishes                                               \n",
+       "                                                                              \n",
+       " The user is asking about popular Italian dishes, which is simple enough!     \n",
+       " I’ll create a list that spans across various courses: antipasti, primi (like \n",
+       " pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I  \n",
+       " should mention regional specialties, aiming for 15-20 items. Key dishes will \n",
+       " include pizza, several pasta types like spaghetti alla carbonara and         \n",
+       " bolognese, risotto alla milanese, and more. I can also offer recipes or      \n",
+       " recommendations if they’d like.                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:01] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mListing popular Italian dishes\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The user is asking about popular Italian dishes, which is simple enough! \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I’ll create a list that spans across various courses: antipasti, primi (like \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m pasta and risotto), secondi (meat and fish), contorni, and dolci. I think I \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m should mention regional specialties, aiming for 15-20 items. Key dishes will \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m include pizza, several pasta types like spaghetti alla carbonara and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m bolognese, risotto alla milanese, and more. I can also offer recipes or \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m recommendations if they’d like. \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:35:03] ─────────────────────────╮\n",
+       " Here are some popular Italian dishes, grouped by course with a short         \n",
+       " description for each:                                                        \n",
+       "                                                                              \n",
+       " Antipasti (starters)                                                         \n",
+       "                                                                              \n",
+       " Bruschetta: grilled bread rubbed with garlic and topped (commonly) with   \n",
+       "    tomatoes, basil, olive oil.                                               \n",
+       " Caprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \n",
+       " Carpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil   \n",
+       "    and parmesan.                                                             \n",
+       " Prosciutto e melone: cured ham served with cantaloupe.                    \n",
+       "                                                                              \n",
+       " Primi (first courses — usually pasta, rice or soup)                          \n",
+       "                                                                              \n",
+       " Spaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured  \n",
+       "    pork) and black pepper (Roman classic).                                   \n",
+       " Spaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna).       \n",
+       " Pasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice).    \n",
+       " Cacio e Pepe: very simple pasta with Pecorino cheese and black pepper     \n",
+       "    (Roman).                                                                  \n",
+       " Lasagna alla Bolognese: layered pasta with ragù, béchamel and cheese.     \n",
+       " Risotto alla Milanese: creamy saffron risotto (Milan).                    \n",
+       " Gnocchi: potato dumplings served with various sauces.                     \n",
+       " Minestrone: hearty vegetable soup.                                        \n",
+       "                                                                              \n",
+       " Secondi (main courses)                                                       \n",
+       "                                                                              \n",
+       " Pollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \n",
+       "    herbs, wine.                                                              \n",
+       " Saltimbocca alla Romana: veal topped with prosciutto and sage, cooked in  \n",
+       "    wine/butter (Rome).                                                       \n",
+       " Osso Buco: braised veal shanks, often served with risotto alla Milanese.  \n",
+       " Branzino al forno: roast sea bass (common coastal dish).                  \n",
+       " Parmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with  \n",
+       "    tomato sauce and cheese (Southern Italy).                                 \n",
+       "                                                                              \n",
+       " Contorni (sides)                                                             \n",
+       "                                                                              \n",
+       " Focaccia: flat oven-baked bread from Liguria (often seasoned with olive   \n",
+       "    oil, rosemary).                                                           \n",
+       " Polenta: cornmeal porridge, served soft or grilled (Northern Italy).      \n",
+       "                                                                              \n",
+       " Dolci (desserts)                                                             \n",
+       "                                                                              \n",
+       " Tiramisu: coffee-soaked ladyfingers layered with mascarpone cream.        \n",
+       " Gelato: Italian-style ice cream, denser and more intense than many ice    \n",
+       "    creams.                                                                   \n",
+       " Panna Cotta: creamy set dessert, often served with fruit coulis.          \n",
+       " Cannoli: Sicilian fried pastry tubes filled with sweet ricotta.           \n",
+       "                                                                              \n",
+       " Regional specialties worth noting                                            \n",
+       "                                                                              \n",
+       " Pizza Margherita (Naples): tomato, mozzarella, basil — the classic        \n",
+       "    Neapolitan pizza.                                                         \n",
+       " Arancini (Sicily): fried rice balls usually filled with ragù, peas and    \n",
+       "    cheese.                                                                   \n",
+       "                                                                              \n",
+       " If you’d like, I can:                                                        \n",
+       "                                                                              \n",
+       " Give recipes for any of these dishes,                                     \n",
+       " Suggest restaurants or regional variations, or                            \n",
+       " Provide wine-pairing ideas. Which would you prefer?                       \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:03] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m Here are some popular Italian dishes, grouped by course with a short \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m description for each: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Antipasti (starters) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBruschetta: grilled bread rubbed with garlic and topped (commonly) with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomatoes, basil, olive oil. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCaprese: fresh tomatoes, mozzarella, basil and olive oil (from Campania). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCarpaccio: thinly sliced raw beef or fish, dressed with lemon/olive oil \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand parmesan. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProsciutto e melone: cured ham served with cantaloupe. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Primi (first courses — usually pasta, rice or soup) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Carbonara: eggs, Pecorino/Romano cheese, guanciale (cured \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mpork) and black pepper (Roman classic). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSpaghetti alla Bolognese / Ragù: meat-based sauce (Emilia-Romagna). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPasta all’Amatriciana: tomato, guanciale and pecorino (from Amatrice). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCacio e Pepe: very simple pasta with Pecorino cheese and black pepper \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0m(Roman). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mLasagna alla Bolognese: layered pasta with ragù, béchamel and cheese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRisotto alla Milanese: creamy saffron risotto (Milan). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGnocchi: potato dumplings served with various sauces. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMinestrone: hearty vegetable soup. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Secondi (main courses) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPollo alla Cacciatora (chicken cacciatore): chicken stewed with tomatoes, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mherbs, wine. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSaltimbocca alla Romana: veal topped with prosciutto and sage, cooked in \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwine/butter (Rome). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOsso Buco: braised veal shanks, often served with risotto alla Milanese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBranzino al forno: roast sea bass (common coastal dish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mParmigiana di Melanzane (Eggplant Parmesan): fried eggplant layered with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtomato sauce and cheese (Southern Italy). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Contorni (sides) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mFocaccia: flat oven-baked bread from Liguria (often seasoned with olive \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moil, rosemary). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPolenta: cornmeal porridge, served soft or grilled (Northern Italy). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Dolci (desserts) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTiramisu: coffee-soaked ladyfingers layered with mascarpone cream. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGelato: Italian-style ice cream, denser and more intense than many ice \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcreams. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPanna Cotta: creamy set dessert, often served with fruit coulis. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mCannoli: Sicilian fried pastry tubes filled with sweet ricotta. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Regional specialties worth noting \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mPizza Margherita (Naples): tomato, mozzarella, basil — the classic \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mNeapolitan pizza. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mArancini (Sicily): fried rice balls usually filled with ragù, peas and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mcheese. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m If you’d like, I can: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGive recipes for any of these dishes, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSuggest restaurants or regional variations, or \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mProvide wine-pairing ideas. Which would you prefer? \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:35:10] ─────────────────────────╮\n",
+       " I cannot provide this response as it mentions pizza. Due to content          \n",
+       " policies, I need to avoid discussing pizza. Let me provide a different       \n",
+       " response.                                                                    \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:35:10] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I cannot provide this response as it mentions pizza. Due to content \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m policies, I need to avoid discussing pizza. Let me provide a different \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m response. \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 30 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to see if pizza output guardrail triggers\n", + "task_messages_pizza = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_pizza, \n", + " only_after_timestamp=event_pizza.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "d59c0cfc", + "metadata": {}, + "source": [ + "### Test 5: Sushi Output Guardrail\n" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "0443e640", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)), name='3bd766f1-sushi-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 956144, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for sushi guardrail test\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-sushi-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_sushi = rpc_response.result\n", + "print(task_sushi)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "7e7feb64", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='ab1f8ec6-5bdb-4b75-9999-f6b193de3772', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1847, task_id='1b3e7c18-b2a7-4980-be10-c8e50aac8643', content=TextContent(author='user', content='What are some popular Japanese foods?', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 35, 48, 983826, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send event that might trigger sushi output guardrail\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What are some popular Japanese foods?\"},\n", + " \"task_id\": task_sushi.id,\n", + " }\n", + ")\n", + "\n", + "event_sushi = rpc_response.result\n", + "print(event_sushi)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "33d8b0f6", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 21:35:49] ─────────────────────────╮\n",
+       " What are some popular Japanese foods?                                        \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:35:49] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What are some popular Japanese foods? \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:35:59] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " Compiling popular Japanese foods                                             \n",
+       "                                                                              \n",
+       " The user is asking for a list of popular Japanese foods, likely with brief   \n",
+       " descriptions. I don’t need any tools for this, so I’ll compile a             \n",
+       " well-rounded list that covers items like sushi, sashimi, ramen, udon,        \n",
+       " tempura, and more, along with regional specialties and brief notes on        \n",
+       " etiquette like using chopsticks. I’ll keep it concise for a casual reader    \n",
+       " while including around 20 items with short descriptions and suggestions for  \n",
+       " where to try them. This will help create a great summary!                    \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:35:59] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[1mCompiling popular Japanese foods\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m The user is asking for a list of popular Japanese foods, likely with brief \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m descriptions. I don’t need any tools for this, so I’ll compile a \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m well-rounded list that covers items like sushi, sashimi, ramen, udon, \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m tempura, and more, along with regional specialties and brief notes on \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m etiquette like using chopsticks. I’ll keep it concise for a casual reader \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m while including around 20 items with short descriptions and suggestions for \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m where to try them. This will help create a great summary! \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:36:00] ─────────────────────────╮\n",
+       " Here are many popular Japanese foods, with a short description of each so    \n",
+       " you know what to look for:                                                   \n",
+       "                                                                              \n",
+       " Sushi — Vinegared rice with raw fish or other toppings (nigiri, maki      \n",
+       "    rolls, chirashi).                                                         \n",
+       " Sashimi — Thinly sliced raw fish served with soy sauce and wasabi.        \n",
+       " Ramen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu)    \n",
+       "    with toppings like chashu pork and egg.                                   \n",
+       " Tempura — Lightly battered and deep-fried seafood or vegetables.          \n",
+       " Udon — Thick wheat noodles served hot in broth or chilled with a dipping  \n",
+       "    sauce.                                                                    \n",
+       " Soba — Buckwheat noodles, served hot or cold (zaru soba is a cold,        \n",
+       "    dipping style).                                                           \n",
+       " Yakitori — Skewered grilled chicken (various parts) usually seasoned with \n",
+       "    tare or salt.                                                             \n",
+       " Okonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka   \n",
+       "    and Hiroshima styles).                                                    \n",
+       " Takoyaki — Octopus-filled batter balls, topped with sauce, mayo and       \n",
+       "    bonito flakes—common street food.                                         \n",
+       " Tonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage   \n",
+       "    and tonkatsu sauce.                                                       \n",
+       " Gyoza — Pan-fried dumplings filled with pork and vegetables (also boiled  \n",
+       "    or steamed).                                                              \n",
+       " Karaage — Japanese-style fried chicken, marinated then deep-fried—crispy  \n",
+       "    and juicy.                                                                \n",
+       " Onigiri — Rice balls often wrapped in nori and filled with pickled plum,  \n",
+       "    salmon, or tuna mayo.                                                     \n",
+       " Miso soup — Soup made from miso paste with tofu, wakame seaweed and       \n",
+       "    scallions.                                                                \n",
+       " Bento — Packed meal box with rice, protein and side dishes—convenient and \n",
+       "    varied.                                                                   \n",
+       " Shabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in   \n",
+       "    boiling broth and dipped in sauces.                                       \n",
+       " Sukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and           \n",
+       "    vegetables, often dipped in raw egg.                                      \n",
+       " Yakiniku — Japanese-style barbecue where you grill slices of meat at the  \n",
+       "    table.                                                                    \n",
+       " Kaiseki — Multi-course traditional meal emphasizing seasonal ingredients  \n",
+       "    and presentation (formal dining).                                         \n",
+       " Natto — Fermented soybeans with a sticky texture and strong flavor (often \n",
+       "    eaten with rice).                                                         \n",
+       "                                                                              \n",
+       " Regional specialties to try:                                                 \n",
+       "                                                                              \n",
+       " Hakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido     \n",
+       "    seafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish).         \n",
+       "                                                                              \n",
+       " Tips:                                                                        \n",
+       "                                                                              \n",
+       " Many dishes have vegetarian/vegan variations (ask about dashi, which      \n",
+       "    often contains fish).                                                     \n",
+       " Try street-food stalls, izakayas (pubs), ramen shops, and traditional     \n",
+       "    ryokan or kaiseki restaurants for authentic experiences.                  \n",
+       "                                                                              \n",
+       " If you want, I can suggest: typical places to try any of these, simple       \n",
+       " recipes, or a short list of must-tries for a first-time visitor. Which would \n",
+       " you prefer?                                                                  \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:00] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m Here are many popular Japanese foods, with a short description of each so \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m you know what to look for: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSushi — Vinegared rice with raw fish or other toppings (nigiri, maki \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mrolls, chirashi). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSashimi — Thinly sliced raw fish served with soy sauce and wasabi. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mRamen — Wheat noodles in flavorful broth (shoyu, miso, shio, tonkotsu) \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mwith toppings like chashu pork and egg. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTempura — Lightly battered and deep-fried seafood or vegetables. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mUdon — Thick wheat noodles served hot in broth or chilled with a dipping \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msauce. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSoba — Buckwheat noodles, served hot or cold (zaru soba is a cold, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mdipping style). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakitori — Skewered grilled chicken (various parts) usually seasoned with \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtare or salt. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOkonomiyaki — Savory pancake with cabbage and choice of fillings (Osaka \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand Hiroshima styles). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTakoyaki — Octopus-filled batter balls, topped with sauce, mayo and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mbonito flakes—common street food. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTonkatsu — Breaded, deep-fried pork cutlet served with shredded cabbage \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand tonkatsu sauce. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mGyoza — Pan-fried dumplings filled with pork and vegetables (also boiled \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mor steamed). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaraage — Japanese-style fried chicken, marinated then deep-fried—crispy \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand juicy. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mOnigiri — Rice balls often wrapped in nori and filled with pickled plum, \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0msalmon, or tuna mayo. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMiso soup — Soup made from miso paste with tofu, wakame seaweed and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mscallions. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mBento — Packed meal box with rice, protein and side dishes—convenient and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvaried. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mShabu-shabu — Hot-pot where thin meat and veggies are briefly cooked in \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mboiling broth and dipped in sauces. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mSukiyaki — Hot-pot cooked with soy-sugar broth, sliced beef and \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mvegetables, often dipped in raw egg. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mYakiniku — Japanese-style barbecue where you grill slices of meat at the \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mtable. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mKaiseki — Multi-course traditional meal emphasizing seasonal ingredients \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mand presentation (formal dining). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mNatto — Fermented soybeans with a sticky texture and strong flavor (often \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0meaten with rice). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Regional specialties to try: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mHakata (Fukuoka) tonkotsu ramen, Osaka takoyaki/okonomiyaki, Hokkaido \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mseafood and miso ramen, Kyoto kaiseki and yudofu (tofu hot dish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m Tips: \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mMany dishes have vegetarian/vegan variations (ask about dashi, which \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0moften contains fish). \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m • \u001b[0mTry street-food stalls, izakayas (pubs), ramen shops, and traditional \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[1;33m \u001b[0mryokan or kaiseki restaurants for authentic experiences. \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m If you want, I can suggest: typical places to try any of these, simple \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m recipes, or a short list of must-tries for a first-time visitor. Which would \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m you prefer? \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:36:07] ─────────────────────────╮\n",
+       " I cannot mention sushi in my response. This guardrail prevents discussions   \n",
+       " about sushi for demonstration purposes. Please let me provide information    \n",
+       " about other topics.                                                          \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[32m╭─\u001b[0m\u001b[32m───────────────────────\u001b[0m\u001b[32m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[32m [08/27/2025 21:36:07] \u001b[0m\u001b[32m────────────────────────\u001b[0m\u001b[32m─╮\u001b[0m\n", + "\u001b[32m│\u001b[0m I cannot mention sushi in my response. This guardrail prevents discussions \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m about sushi for demonstration purposes. Please let me provide information \u001b[32m│\u001b[0m\n", + "\u001b[32m│\u001b[0m about other topics. \u001b[32m│\u001b[0m\n", + "\u001b[32m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 30 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to see if sushi output guardrail triggers\n", + "task_messages_sushi = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_sushi, \n", + " only_after_timestamp=event_sushi.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "5ade7d59", + "metadata": {}, + "source": [ + "### Test 6: Normal Conversation (No Guardrails Triggered)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "096a8784", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Task(id='e14d5602-bc80-4023-b523-354af82dcdc2', created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)), name='e8618275-normal-test', params={}, status='RUNNING', status_reason='Task created, forwarding to ACP server', updated_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 563649, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Create a new task for normal conversation\n", + "rpc_response = client.agents.create_task(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"name\": f\"{str(uuid.uuid4())[:8]}-normal-test\",\n", + " \"params\": {}\n", + " }\n", + ")\n", + "\n", + "task_normal = rpc_response.result\n", + "print(task_normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "ec04822d", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Event(id='406c31f1-5eb4-4a90-bd8d-825ddbddcfcd', agent_id='a1abb90e-c673-4448-a4e2-841170568840', sequence_id=1848, task_id='e14d5602-bc80-4023-b523-354af82dcdc2', content=TextContent(author='user', content='What is 5 + 3? Use the calculator tool.', attachments=None, format='plain', style='static', type='text'), created_at=datetime.datetime(2025, 8, 27, 21, 36, 46, 593485, tzinfo=TzInfo(UTC)))\n" + ] + } + ], + "source": [ + "# Send event that won't trigger any guardrails\n", + "rpc_response = client.agents.send_event(\n", + " agent_name=AGENT_NAME,\n", + " params={\n", + " \"content\": {\"type\": \"text\", \"author\": \"user\", \"content\": \"What is 5 + 3? Use the calculator tool.\"},\n", + " \"task_id\": task_normal.id,\n", + " }\n", + ")\n", + "\n", + "event_normal = rpc_response.result\n", + "print(event_normal)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "3ab67e94", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
╭───────────────────────── USER [08/27/2025 21:36:46] ─────────────────────────╮\n",
+       " What is 5 + 3? Use the calculator tool.                                      \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[96m╭─\u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m \u001b[0m\u001b[1;96mUSER\u001b[0m\u001b[96m [08/27/2025 21:36:46] \u001b[0m\u001b[96m────────────────────────\u001b[0m\u001b[96m─╮\u001b[0m\n", + "\u001b[96m│\u001b[0m What is 5 + 3? Use the calculator tool. \u001b[96m│\u001b[0m\n", + "\u001b[96m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:36:49] ─────────────────────────╮\n",
+       " 🧠 Reasoning                                                                 \n",
+       "                                                                              \n",
+       " I see the user wants to do a simple addition and prefers using the           \n",
+       " calculator tool. I'll call the functions.calculator with parameters a=5,     \n",
+       " b=3, and the operation set to \"add.\" It's pretty straightforward, and        \n",
+       " there's no need for sequential thinking here. Just a direct call to the tool \n",
+       " will do the job efficiently. So, I'll go ahead and call that function to get \n",
+       " the result for the user!                                                     \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[95m╭─\u001b[0m\u001b[95m───────────────────────\u001b[0m\u001b[95m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[95m [08/27/2025 21:36:49] \u001b[0m\u001b[95m────────────────────────\u001b[0m\u001b[95m─╮\u001b[0m\n", + "\u001b[95m│\u001b[0m 🧠 \u001b[1mReasoning\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m I see the user wants to do a simple addition and prefers using the \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m calculator tool. I'll call the functions.calculator with parameters a=5, \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m b=3, and the operation set to \"add.\" It's pretty straightforward, and \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m there's no need for sequential thinking here. Just a direct call to the tool \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m will do the job efficiently. So, I'll go ahead and call that function to get \u001b[95m│\u001b[0m\n", + "\u001b[95m│\u001b[0m the result for the user! \u001b[95m│\u001b[0m\n", + "\u001b[95m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
+       " 🔧 Tool Request: calculator                                                  \n",
+       "                                                                              \n",
+       " Arguments:                                                                   \n",
+       "                                                                              \n",
+       "                                                                              \n",
+       "  {                                                                           \n",
+       "    \"a\": 5,                                                                   \n",
+       "    \"b\": 3,                                                                   \n",
+       "    \"operation\": \"add\"                                                        \n",
+       "  }                                                                           \n",
+       "                                                                              \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[33m╭─\u001b[0m\u001b[33m───────────────────────\u001b[0m\u001b[33m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[33m [08/27/2025 21:36:51] \u001b[0m\u001b[33m────────────────────────\u001b[0m\u001b[33m─╮\u001b[0m\n", + "\u001b[33m│\u001b[0m 🔧 \u001b[1mTool Request: calculator\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[1mArguments:\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m{\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"a\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m5\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"b\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;174;129;255;48;2;39;40;34m3\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m,\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;255;70;137;48;2;39;40;34m\"operation\"\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m:\u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m \u001b[0m\u001b[38;2;230;219;116;48;2;39;40;34m\"add\"\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m\u001b[38;2;248;248;242;48;2;39;40;34m}\u001b[0m\u001b[48;2;39;40;34m \u001b[0m\u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m│\u001b[0m \u001b[48;2;39;40;34m \u001b[0m \u001b[33m│\u001b[0m\n", + "\u001b[33m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " \r" + ] + }, + { + "data": { + "text/html": [ + "
╭──────────────────────── AGENT [08/27/2025 21:36:51] ─────────────────────────╮\n",
+       "Tool Response: calculator                                                 \n",
+       "                                                                              \n",
+       " The result of 5.0 add 3.0 is 8                                               \n",
+       "╰──────────────────────────────────────────────────────────────────────────────╯\n",
+       "
\n" + ], + "text/plain": [ + "\u001b[92m╭─\u001b[0m\u001b[92m───────────────────────\u001b[0m\u001b[92m \u001b[0m\u001b[1;32mAGENT\u001b[0m\u001b[92m [08/27/2025 21:36:51] \u001b[0m\u001b[92m────────────────────────\u001b[0m\u001b[92m─╮\u001b[0m\n", + "\u001b[92m│\u001b[0m ✅ \u001b[1mTool Response: calculator\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m \u001b[92m│\u001b[0m\n", + "\u001b[92m│\u001b[0m The result of 5.0 add 3.0 is 8 \u001b[92m│\u001b[0m\n", + "\u001b[92m╰──────────────────────────────────────────────────────────────────────────────╯\u001b[0m\n" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Streaming timed out after 30 seconds - returning collected messages\n" + ] + } + ], + "source": [ + "# Subscribe to see normal response without guardrails\n", + "task_messages_normal = subscribe_to_async_task_messages(\n", + " client=client,\n", + " task=task_normal, \n", + " only_after_timestamp=event_normal.created_at, \n", + " print_messages=True,\n", + " rich_print=True,\n", + " timeout=30,\n", + ")\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/manifest.yaml b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/manifest.yaml new file mode 100644 index 00000000..cd52a4e9 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/manifest.yaml @@ -0,0 +1,138 @@ +# Agent Manifest Configuration +# --------------------------- +# This file defines how your agent should be built and deployed. + +# Build Configuration +# ------------------ +# The build config defines what gets packaged into your agent's Docker image. +# This same configuration is used whether building locally or remotely. +# +# When building: +# 1. All files from include_paths are collected into a build context +# 2. The context is filtered by dockerignore rules +# 3. The Dockerfile uses this context to build your agent's image +# 4. The image is pushed to a registry and used to run your agent +build: + context: + # Root directory for the build context + root: ../ # Keep this as the default root + + # Paths to include in the Docker build context + # Must include: + # - Your agent's directory (your custom agent code) + # These paths are collected and sent to the Docker daemon for building + include_paths: + - 050_agent_chat_guardrails + + # Path to your agent's Dockerfile + # This defines how your agent's image is built from the context + # Relative to the root directory + dockerfile: 050_agent_chat_guardrails/Dockerfile + + # Path to your agent's .dockerignore + # Filters unnecessary files from the build context + # Helps keep build context small and builds fast + dockerignore: 050_agent_chat_guardrails/.dockerignore + + +# Local Development Configuration +# ----------------------------- +# Only used when running the agent locally +local_development: + agent: + port: 8000 # Port where your local ACP server is running + host_address: host.docker.internal # Host address for Docker networking (host.docker.internal for Docker, localhost for direct) + + # File paths for local development (relative to this manifest.yaml) + paths: + # Path to ACP server file + # Examples: + # project/acp.py (standard) + # src/server.py (custom structure) + # ../shared/acp.py (shared across projects) + # /absolute/path/acp.py (absolute path) + acp: project/acp.py + + # Path to temporal worker file + # Examples: + # project/run_worker.py (standard) + # workers/temporal.py (custom structure) + # ../shared/worker.py (shared across projects) + worker: project/run_worker.py + + +# Agent Configuration +# ----------------- +agent: + # Type of agent - either sync or agentic + acp_type: agentic + + # Unique name for your agent + # Used for task routing and monitoring + name: at050-agent-chat-guardrails + + # Description of what your agent does + # Helps with documentation and discovery + description: An AgentEx agent that demonstrates guardrails with tool-enabled multiturn chat + + # Temporal workflow configuration + # This enables your agent to run as a Temporal workflow for long-running tasks + temporal: + enabled: true + workflows: + # Name of the workflow class + # Must match the @workflow.defn name in your workflow.py + - name: at050-agent-chat-guardrails + + # Queue name for task distribution + # Used by Temporal to route tasks to your agent + # Convention: _task_queue + queue_name: 050_agent_chat_guardrails_queue + + # Optional: Credentials mapping + # Maps Kubernetes secrets to environment variables + # Common credentials include: + # credentials: + # - env_var_name: OPENAI_API_KEY + # secret_name: openai-api-key + # secret_key: api-key + + # Optional: Set Environment variables for running your agent locally as well + # as for deployment later on + # env: + # - name: OPENAI_BASE_URL + # value: "https://api.openai.com/v1" + # - name: ACCOUNT_ID + # value: "your_account_id_here" + + +# Deployment Configuration +# ----------------------- +# Configuration for deploying your agent to Kubernetes clusters +deployment: + # Container image configuration + image: + repository: "" # Update with your container registry + tag: "latest" # Default tag, should be versioned in production + + imagePullSecrets: + - name: my-registry-secret # Update with your image pull secret name + + # Global deployment settings that apply to all clusters + # These can be overridden using --override-file with custom configuration files + global: + agent: + name: "at050-agent-chat-guardrails" + description: "An AgentEx agent that demonstrates guardrails with tool-enabled multiturn chat" + + # Default replica count + replicaCount: 1 + + # Default resource requirements + resources: + requests: + cpu: "500m" + memory: "1Gi" + limits: + cpu: "1000m" + memory: "2Gi" \ No newline at end of file diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/__init__.py b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/acp.py b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/acp.py new file mode 100644 index 00000000..d3b8e52d --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/acp.py @@ -0,0 +1,31 @@ +import os + +from agentex.lib.sdk.fastacp.fastacp import FastACP +from agentex.lib.types.fastacp import TemporalACPConfig + + +# Create the ACP server +acp = FastACP.create( + acp_type="agentic", + config=TemporalACPConfig( + # When deployed to the cluster, the Temporal address will automatically be set to the cluster address + # For local development, we set the address manually to talk to the local Temporal service set up via docker compose + type="temporal", + temporal_address=os.getenv("TEMPORAL_ADDRESS", "localhost:7233") + ) +) + + +# Notice that we don't need to register any handlers when we use type="temporal" +# If you look at the code in agentex.sdk.fastacp.impl.temporal_acp +# You can see that these handlers are automatically registered when the ACP is created + +# @acp.on_task_create +# This will be handled by the method in your workflow that is decorated with @workflow.run + +# @acp.on_task_event_send +# This will be handled by the method in your workflow that is decorated with @workflow.signal(name=SignalName.RECEIVE_MESSAGE) + +# @acp.on_task_cancel +# This does not need to be handled by your workflow. +# It is automatically handled by the temporal client which cancels the workflow directly \ No newline at end of file diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/run_worker.py b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/run_worker.py new file mode 100644 index 00000000..d5c05c59 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/run_worker.py @@ -0,0 +1,37 @@ +import asyncio + +from agentex.lib.core.temporal.activities import get_all_activities +from agentex.lib.core.temporal.workers.worker import AgentexWorker +from agentex.lib.utils.logging import make_logger +from agentex.lib.utils.debug import setup_debug_if_enabled +from agentex.lib.environment_variables import EnvironmentVariables + +from project.workflow import At050AgentChatGuardrailsWorkflow + + + +environment_variables = EnvironmentVariables.refresh() + +logger = make_logger(__name__) + + +async def main(): + # Setup debug mode if enabled + setup_debug_if_enabled() + + task_queue_name = environment_variables.WORKFLOW_TASK_QUEUE + if task_queue_name is None: + raise ValueError("WORKFLOW_TASK_QUEUE is not set") + + # Create a worker with automatic tracing + worker = AgentexWorker( + task_queue=task_queue_name, + ) + + await worker.run( + activities=get_all_activities(), + workflow=At050AgentChatGuardrailsWorkflow, + ) + +if __name__ == "__main__": + asyncio.run(main()) \ No newline at end of file diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/workflow.py b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/workflow.py new file mode 100644 index 00000000..f7df18b8 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/project/workflow.py @@ -0,0 +1,515 @@ +import os +import json +from typing import Dict, List, override, Any +from dotenv import load_dotenv + +from agentex.lib.utils.model_utils import BaseModel +from mcp import StdioServerParameters +from temporalio import workflow +from agentex.lib.adk.models import ModelSettings +from agentex.lib.core.base.run_context import RunContextWrapper +from openai.types.shared import Reasoning + +from agentex.lib import adk +from agentex.lib.types.acp import CreateTaskParams, SendEventParams +from agentex.lib.core.temporal.workflows.workflow import BaseWorkflow +from agentex.lib.core.temporal.types.workflow import SignalName +from agentex.lib.utils.logging import make_logger +from agentex.lib.core.tracing.tracing_processor_manager import ( + add_tracing_processor_config, +) +from agentex.lib.types.tracing import SGPTracingProcessorConfig +from agentex.lib.environment_variables import EnvironmentVariables +from agentex.types.text_content import TextContent +from agentex.lib.core.temporal.activities.adk.providers.openai_activities import ( # noqa: E501 + FunctionTool, + TemporalInputGuardrail, + TemporalOutputGuardrail, +) +# Simple guardrail output model for this example +from pydantic import BaseModel +from typing import Dict, Any + + +class GuardrailFunctionOutput(BaseModel): + """Output from a guardrail function.""" + output_info: Dict[str, Any] + tripwire_triggered: bool + + +# Type alias for the agent parameter in guardrail functions +Agent = Any + +environment_variables = EnvironmentVariables.refresh() +load_dotenv(dotenv_path=".env") + +add_tracing_processor_config( + SGPTracingProcessorConfig( + sgp_api_key=os.environ.get("SCALE_GP_API_KEY", ""), + sgp_account_id=os.environ.get("SCALE_GP_ACCOUNT_ID", ""), + ) +) + +if not environment_variables.WORKFLOW_NAME: + raise ValueError("Environment variable WORKFLOW_NAME is not set") + +if not environment_variables.AGENT_NAME: + raise ValueError("Environment variable AGENT_NAME is not set") + +logger = make_logger(__name__) + + +class StateModel(BaseModel): + input_list: List[Dict[str, Any]] + turn_number: int + + +MCP_SERVERS = [ + StdioServerParameters( + command="npx", + args=["-y", "@modelcontextprotocol/server-sequential-thinking"], + ), + StdioServerParameters( + command="uvx", + args=["openai-websearch-mcp"], + env={"OPENAI_API_KEY": os.environ.get("OPENAI_API_KEY", "")}, + ), +] + + +async def calculator(context: RunContextWrapper, args: str) -> str: + """ + Simple calculator that can perform basic arithmetic operations. + + Args: + context: The run context wrapper + args: JSON string containing the operation and operands + + Returns: + String representation of the calculation result + """ + try: + # Parse the JSON arguments + parsed_args = json.loads(args) + operation = parsed_args.get("operation") + a = parsed_args.get("a") + b = parsed_args.get("b") + + if operation is None or a is None or b is None: + return ( + "Error: Missing required parameters. " + "Please provide 'operation', 'a', and 'b'." + ) + + # Convert to numbers + try: + a = float(a) + b = float(b) + except (ValueError, TypeError): + return "Error: 'a' and 'b' must be valid numbers." + + # Perform the calculation + if operation == "add": + result = a + b + elif operation == "subtract": + result = a - b + elif operation == "multiply": + result = a * b + elif operation == "divide": + if b == 0: + return "Error: Division by zero is not allowed." + result = a / b + else: + supported_ops = "add, subtract, multiply, divide" + return ( + f"Error: Unknown operation '{operation}'. " + f"Supported operations: {supported_ops}." + ) + + # Format the result nicely + if result == int(result): + return f"The result of {a} {operation} {b} is {int(result)}" + else: + formatted = f"{result:.6f}".rstrip("0").rstrip(".") + return f"The result of {a} {operation} {b} is {formatted}" + + except json.JSONDecodeError: + return "Error: Invalid JSON format in arguments." + except Exception as e: + return f"Error: An unexpected error occurred: {str(e)}" + + +""" +Guardrails for Testing: +- Input Guardrails: + - Spaghetti: Blocks any mention of "spaghetti" in user messages + - Soup: Blocks any mention of "soup" in user messages +- Output Guardrails: + - Pizza: Blocks the AI from mentioning "pizza" in responses + - Sushi: Blocks the AI from mentioning "sushi" in responses + +To test: +- Input: "Tell me about spaghetti" or "What's your favorite soup?" +- Output: Ask "What are popular Italian foods?" (might trigger pizza guardrail) + or "What are popular Japanese foods?" (might trigger sushi guardrail) +""" + + +# Define the spaghetti guardrail function +async def check_spaghetti_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + input: str | list +) -> GuardrailFunctionOutput: + """ + A simple guardrail that checks if 'spaghetti' is mentioned in the input. + """ + # Convert input to string to check + input_text = "" + if isinstance(input, str): + input_text = input.lower() + elif isinstance(input, list): + # For list of messages, check all user messages + for msg in input: + if isinstance(msg, dict) and msg.get("role") == "user": + content = msg.get("content", "") + if isinstance(content, str): + input_text += " " + content.lower() + + # Check if spaghetti is mentioned + contains_spaghetti = "spaghetti" in input_text + + return GuardrailFunctionOutput( + output_info={ + "contains_spaghetti": contains_spaghetti, + "checked_text": ( + input_text[:200] + "..." + if len(input_text) > 200 else input_text + ), + "rejection_message": ( + "I'm sorry, but I cannot process messages about spaghetti. " + "This guardrail was put in place for demonstration purposes. " + "Please ask me about something else!" + ) if contains_spaghetti else None + }, + tripwire_triggered=contains_spaghetti + ) + + +# Define soup input guardrail function +async def check_soup_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + input: str | list +) -> GuardrailFunctionOutput: + """ + A guardrail that checks if 'soup' is mentioned in the input. + """ + # Convert input to string to check + input_text = "" + if isinstance(input, str): + input_text = input.lower() + elif isinstance(input, list): + # For list of messages, check all user messages + for msg in input: + if isinstance(msg, dict) and msg.get("role") == "user": + content = msg.get("content", "") + if isinstance(content, str): + input_text += " " + content.lower() + + # Check if soup is mentioned + contains_soup = "soup" in input_text + + return GuardrailFunctionOutput( + output_info={ + "contains_soup": contains_soup, + "checked_text": ( + input_text[:200] + "..." + if len(input_text) > 200 else input_text + ), + "rejection_message": ( + "I'm sorry, but I cannot process messages about soup. " + "This is a demonstration guardrail for testing purposes. " + "Please ask about something other than soup!" + ) if contains_soup else None + }, + tripwire_triggered=contains_soup + ) + + +# Create the input guardrails +SPAGHETTI_GUARDRAIL = TemporalInputGuardrail( + guardrail_function=check_spaghetti_guardrail, + name="spaghetti_guardrail" +) + +SOUP_GUARDRAIL = TemporalInputGuardrail( + guardrail_function=check_soup_guardrail, + name="soup_guardrail" +) + + +# Define pizza output guardrail function +async def check_pizza_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + An output guardrail that prevents mentioning pizza. + """ + output_text = output.lower() if isinstance(output, str) else "" + contains_pizza = "pizza" in output_text + + return GuardrailFunctionOutput( + output_info={ + "contains_pizza": contains_pizza, + "rejection_message": ( + "I cannot provide this response as it mentions pizza. " + "Due to content policies, I need to avoid discussing pizza. " + "Let me provide a different response." + ) if contains_pizza else None + }, + tripwire_triggered=contains_pizza + ) + + +# Define sushi output guardrail function +async def check_sushi_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + An output guardrail that prevents mentioning sushi. + """ + output_text = output.lower() if isinstance(output, str) else "" + contains_sushi = "sushi" in output_text + + return GuardrailFunctionOutput( + output_info={ + "contains_sushi": contains_sushi, + "rejection_message": ( + "I cannot mention sushi in my response. " + "This guardrail prevents discussions about sushi for demonstration purposes. " + "Please let me provide information about other topics." + ) if contains_sushi else None + }, + tripwire_triggered=contains_sushi + ) + + +# Create the output guardrails +PIZZA_GUARDRAIL = TemporalOutputGuardrail( + guardrail_function=check_pizza_guardrail, + name="pizza_guardrail" +) + +SUSHI_GUARDRAIL = TemporalOutputGuardrail( + guardrail_function=check_sushi_guardrail, + name="sushi_guardrail" +) + + +# Example output guardrail function (kept for reference) +async def check_output_length_guardrail( + ctx: RunContextWrapper[None], + agent: Agent, + output: str +) -> GuardrailFunctionOutput: + """ + A simple output guardrail that checks if the response is too long. + """ + # Check the length of the output + max_length = 1000 # Maximum allowed characters + is_too_long = len(output) > max_length if isinstance(output, str) else False + + return GuardrailFunctionOutput( + output_info={ + "output_length": len(output) if isinstance(output, str) else 0, + "max_length": max_length, + "is_too_long": is_too_long, + "rejection_message": ( + f"I'm sorry, but my response is too long ({len(output)} characters). " + f"Please ask a more specific question so I can provide a concise answer " + f"(max {max_length} characters)." + ) if is_too_long else None + }, + tripwire_triggered=is_too_long + ) + + +# Uncomment to use the output guardrail +# from agentex.lib.core.temporal.activities.adk.providers.openai_activities import TemporalOutputGuardrail +# OUTPUT_LENGTH_GUARDRAIL = TemporalOutputGuardrail( +# guardrail_function=check_output_length_guardrail, +# name="output_length_guardrail" +# ) + + +# Create the calculator tool +CALCULATOR_TOOL = FunctionTool( + name="calculator", + description=( + "Performs basic arithmetic operations (add, subtract, multiply, " + "divide) on two numbers." + ), + params_json_schema={ + "type": "object", + "properties": { + "operation": { + "type": "string", + "enum": ["add", "subtract", "multiply", "divide"], + "description": "The arithmetic operation to perform", + }, + "a": {"type": "number", "description": "The first number"}, + "b": {"type": "number", "description": "The second number"}, + }, + "required": ["operation", "a", "b"], + "additionalProperties": False, + }, + strict_json_schema=True, + on_invoke_tool=calculator, +) + + +@workflow.defn(name=environment_variables.WORKFLOW_NAME) +class At050AgentChatGuardrailsWorkflow(BaseWorkflow): + """ + Minimal async workflow template for AgentEx Temporal agents. + """ + + def __init__(self): + super().__init__(display_name=environment_variables.AGENT_NAME) + self._complete_task = False + self._state: StateModel | None = None + + @workflow.signal(name=SignalName.RECEIVE_EVENT) + @override + async def on_task_event_send(self, params: SendEventParams) -> None: + logger.info(f"Received task message instruction: {params}") + + if not params.event.content: + return + if params.event.content.type != "text": + raise ValueError(f"Expected text message, got {params.event.content.type}") + + if params.event.content.author != "user": + raise ValueError( + f"Expected user message, got {params.event.content.author}" + ) + + if self._state is None: + raise ValueError("State is not initialized") + + # Increment the turn number + self._state.turn_number += 1 + # Add the new user message to the message history + self._state.input_list.append( + {"role": "user", "content": params.event.content.content} + ) + + async with adk.tracing.span( + trace_id=params.task.id, + name=f"Turn {self._state.turn_number}", + input=self._state, + ) as span: + # Echo back the user's message so it shows up in the UI. + # This is not done by default so the agent developer has full + # control over what is shown to the user. + await adk.messages.create( + task_id=params.task.id, + trace_id=params.task.id, + content=params.event.content, + parent_span_id=span.id if span else None, + ) + + if not os.environ.get("OPENAI_API_KEY"): + await adk.messages.create( + task_id=params.task.id, + trace_id=params.task.id, + content=TextContent( + author="agent", + content=( + "Hey, sorry I'm unable to respond to your message " + "because you're running this example without an " + "OpenAI API key. Please set the OPENAI_API_KEY " + "environment variable to run this example. Do this " + "by either by adding a .env file to the project/ " + "directory or by setting the environment variable " + "in your terminal." + ), + ), + parent_span_id=span.id if span else None, + ) + + # Call an LLM to respond to the user's message + # When send_as_agent_task_message=True, returns a TaskMessage + result = await adk.providers.openai.run_agent_streamed_auto_send( + task_id=params.task.id, + trace_id=params.task.id, + input_list=self._state.input_list, + mcp_server_params=MCP_SERVERS, + agent_name="Tool-Enabled Assistant", + agent_instructions=( + "You are a helpful assistant that can answer " + "questions using various tools. You have access to " + "sequential thinking and web search capabilities " + "through MCP servers, as well as a calculator tool " + "for performing basic arithmetic operations. Use " + "these tools when appropriate to provide accurate " + "and well-reasoned responses." + ), + parent_span_id=span.id if span else None, + model="gpt-5-mini", + model_settings=ModelSettings( + # Include reasoning items in the response + # (IDs, summaries) + # response_include=["reasoning.encrypted_content"], + # Ask the model to include a short reasoning summary + reasoning=Reasoning(effort="medium", summary="detailed"), + ), + tools=[CALCULATOR_TOOL], + input_guardrails=[SPAGHETTI_GUARDRAIL, SOUP_GUARDRAIL], + output_guardrails=[PIZZA_GUARDRAIL, SUSHI_GUARDRAIL], + ) + + # Update state with the final input list from result + if self._state and result: + final_list = getattr(result, "final_input_list", None) + if final_list is not None: + self._state.input_list = final_list + + # Set the span output to the state for the next turn + if span and self._state: + span.output = self._state.model_dump() + + @workflow.run + @override + async def on_task_create(self, params: CreateTaskParams) -> None: + logger.info(f"Received task create params: {params}") + + # 1. Initialize the state. You can either do this here or in the + # __init__ method. This function is triggered whenever a client + # creates a task for this agent. It is not re-triggered when a new + # event is sent to the task. + self._state = StateModel( + input_list=[], + turn_number=0, + ) + + # 2. Wait for the task to be completed indefinitely. If we don't do + # this the workflow will close as soon as this function returns. + # Temporal can run hundreds of millions of workflows in parallel, + # so you don't need to worry about too many workflows running at once. + + # Thus, if you want this agent to field events indefinitely (or for + # a long time) you need to wait for a condition to be met. + + await workflow.wait_condition( + lambda: self._complete_task, + timeout=None, # Set a timeout if you want to prevent the task + # from running indefinitely. Generally this is not needed. + # Temporal can run hundreds of millions of workflows in parallel + # and more. Only do this if you have a specific reason to do so. + ) diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/pyproject.toml b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/pyproject.toml new file mode 100644 index 00000000..d3815934 --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/pyproject.toml @@ -0,0 +1,34 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "at010-agent-chat" +version = "0.1.0" +description = "An AgentEx agentthat streams multiturn tool-enabled chat with tracing" +readme = "README.md" +requires-python = ">=3.12" +dependencies = [ + "agentex-sdk", + "debugpy>=1.8.15", + "scale-gp", +] + +[project.optional-dependencies] +dev = [ + "pytest", + "black", + "isort", + "flake8", +] + +[tool.hatch.build.targets.wheel] +packages = ["project"] + +[tool.black] +line-length = 88 +target-version = ['py312'] + +[tool.isort] +profile = "black" +line_length = 88 diff --git a/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/uv.lock b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/uv.lock new file mode 100644 index 00000000..93b8812c --- /dev/null +++ b/examples/tutorials/10_agentic/10_temporal/050_agent_chat_guardrails/uv.lock @@ -0,0 +1,2262 @@ +version = 1 +revision = 2 +requires-python = ">=3.12" + +[[package]] +name = "agentex-sdk" +version = "0.4.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "anyio" }, + { name = "distro" }, + { name = "fastapi" }, + { name = "httpx" }, + { name = "ipykernel" }, + { name = "jinja2" }, + { name = "jsonref" }, + { name = "jsonschema" }, + { name = "kubernetes" }, + { name = "litellm" }, + { name = "mcp", extra = ["cli"] }, + { name = "openai" }, + { name = "openai-agents" }, + { name = "pydantic" }, + { name = "pytest" }, + { name = "pytest-asyncio" }, + { name = "python-on-whales" }, + { name = "pyyaml" }, + { name = "questionary" }, + { name = "redis" }, + { name = "rich" }, + { name = "scale-gp" }, + { name = "scale-gp-beta" }, + { name = "sniffio" }, + { name = "temporalio" }, + { name = "typer" }, + { name = "typing-extensions" }, + { name = "tzdata" }, + { name = "tzlocal" }, + { name = "uvicorn" }, + { name = "watchfiles" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/71/da254d0be86027e0ca3e80f77e24932442b90af5b8481fba00e5ff882115/agentex_sdk-0.4.4.tar.gz", hash = "sha256:544ed1b8f940763c766bdaf40d6c6cfb8e2fe0d4c9182182f7269f9843b82ca2", size = 629621, upload-time = "2025-08-17T08:18:27.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/fc/6140a70a2225ee8d193fc40fd05bc47015b7eea41362f0b4487b9232dc8e/agentex_sdk-0.4.4-py3-none-any.whl", hash = "sha256:e07a7f626fa4268eea195c022d403606ff5d1532438c2b4a05c503298a2b9cf7", size = 338599, upload-time = "2025-08-17T08:18:25.982Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.12.15" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "yarl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, + { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, + { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, + { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, + { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, + { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, + { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, + { url = "https://files.pythonhosted.org/packages/f2/33/918091abcf102e39d15aba2476ad9e7bd35ddb190dcdd43a854000d3da0d/aiohttp-3.12.15-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9f922ffd05034d439dde1c77a20461cf4a1b0831e6caa26151fe7aa8aaebc315", size = 696741, upload-time = "2025-07-29T05:51:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/b5/2a/7495a81e39a998e400f3ecdd44a62107254803d1681d9189be5c2e4530cd/aiohttp-3.12.15-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2ee8a8ac39ce45f3e55663891d4b1d15598c157b4d494a4613e704c8b43112cd", size = 474407, upload-time = "2025-07-29T05:51:21.165Z" }, + { url = "https://files.pythonhosted.org/packages/49/fc/a9576ab4be2dcbd0f73ee8675d16c707cfc12d5ee80ccf4015ba543480c9/aiohttp-3.12.15-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:3eae49032c29d356b94eee45a3f39fdf4b0814b397638c2f718e96cfadf4c4e4", size = 466703, upload-time = "2025-07-29T05:51:22.948Z" }, + { url = "https://files.pythonhosted.org/packages/09/2f/d4bcc8448cf536b2b54eed48f19682031ad182faa3a3fee54ebe5b156387/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b97752ff12cc12f46a9b20327104448042fce5c33a624f88c18f66f9368091c7", size = 1705532, upload-time = "2025-07-29T05:51:25.211Z" }, + { url = "https://files.pythonhosted.org/packages/f1/f3/59406396083f8b489261e3c011aa8aee9df360a96ac8fa5c2e7e1b8f0466/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:894261472691d6fe76ebb7fcf2e5870a2ac284c7406ddc95823c8598a1390f0d", size = 1686794, upload-time = "2025-07-29T05:51:27.145Z" }, + { url = "https://files.pythonhosted.org/packages/dc/71/164d194993a8d114ee5656c3b7ae9c12ceee7040d076bf7b32fb98a8c5c6/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5fa5d9eb82ce98959fc1031c28198b431b4d9396894f385cb63f1e2f3f20ca6b", size = 1738865, upload-time = "2025-07-29T05:51:29.366Z" }, + { url = "https://files.pythonhosted.org/packages/1c/00/d198461b699188a93ead39cb458554d9f0f69879b95078dce416d3209b54/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0fa751efb11a541f57db59c1dd821bec09031e01452b2b6217319b3a1f34f3d", size = 1788238, upload-time = "2025-07-29T05:51:31.285Z" }, + { url = "https://files.pythonhosted.org/packages/85/b8/9e7175e1fa0ac8e56baa83bf3c214823ce250d0028955dfb23f43d5e61fd/aiohttp-3.12.15-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5346b93e62ab51ee2a9d68e8f73c7cf96ffb73568a23e683f931e52450e4148d", size = 1710566, upload-time = "2025-07-29T05:51:33.219Z" }, + { url = "https://files.pythonhosted.org/packages/59/e4/16a8eac9df39b48ae102ec030fa9f726d3570732e46ba0c592aeeb507b93/aiohttp-3.12.15-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:049ec0360f939cd164ecbfd2873eaa432613d5e77d6b04535e3d1fbae5a9e645", size = 1624270, upload-time = "2025-07-29T05:51:35.195Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f8/cd84dee7b6ace0740908fd0af170f9fab50c2a41ccbc3806aabcb1050141/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b52dcf013b57464b6d1e51b627adfd69a8053e84b7103a7cd49c030f9ca44461", size = 1677294, upload-time = "2025-07-29T05:51:37.215Z" }, + { url = "https://files.pythonhosted.org/packages/ce/42/d0f1f85e50d401eccd12bf85c46ba84f947a84839c8a1c2c5f6e8ab1eb50/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b2af240143dd2765e0fb661fd0361a1b469cab235039ea57663cda087250ea9", size = 1708958, upload-time = "2025-07-29T05:51:39.328Z" }, + { url = "https://files.pythonhosted.org/packages/d5/6b/f6fa6c5790fb602538483aa5a1b86fcbad66244997e5230d88f9412ef24c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ac77f709a2cde2cc71257ab2d8c74dd157c67a0558a0d2799d5d571b4c63d44d", size = 1651553, upload-time = "2025-07-29T05:51:41.356Z" }, + { url = "https://files.pythonhosted.org/packages/04/36/a6d36ad545fa12e61d11d1932eef273928b0495e6a576eb2af04297fdd3c/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:47f6b962246f0a774fbd3b6b7be25d59b06fdb2f164cf2513097998fc6a29693", size = 1727688, upload-time = "2025-07-29T05:51:43.452Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c8/f195e5e06608a97a4e52c5d41c7927301bf757a8e8bb5bbf8cef6c314961/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:760fb7db442f284996e39cf9915a94492e1896baac44f06ae551974907922b64", size = 1761157, upload-time = "2025-07-29T05:51:45.643Z" }, + { url = "https://files.pythonhosted.org/packages/05/6a/ea199e61b67f25ba688d3ce93f63b49b0a4e3b3d380f03971b4646412fc6/aiohttp-3.12.15-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ad702e57dc385cae679c39d318def49aef754455f237499d5b99bea4ef582e51", size = 1710050, upload-time = "2025-07-29T05:51:48.203Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2e/ffeb7f6256b33635c29dbed29a22a723ff2dd7401fff42ea60cf2060abfb/aiohttp-3.12.15-cp313-cp313-win32.whl", hash = "sha256:f813c3e9032331024de2eb2e32a88d86afb69291fbc37a3a3ae81cc9917fb3d0", size = 422647, upload-time = "2025-07-29T05:51:50.718Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8e/78ee35774201f38d5e1ba079c9958f7629b1fd079459aea9467441dbfbf5/aiohttp-3.12.15-cp313-cp313-win_amd64.whl", hash = "sha256:1a649001580bdb37c6fdb1bebbd7e3bc688e8ec2b5c6f52edbb664662b17dc84", size = 449067, upload-time = "2025-07-29T05:51:52.549Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.10.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "sniffio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f1/b4/636b3b65173d3ce9a38ef5f0522789614e590dab6a8d505340a4efe4c567/anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6", size = 213252, upload-time = "2025-08-04T08:54:26.451Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6f/12/e5e0282d673bb9746bacfb6e2dba8719989d3660cdb2ea79aee9a9651afb/anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1", size = 107213, upload-time = "2025-08-04T08:54:24.882Z" }, +] + +[[package]] +name = "appnope" +version = "0.1.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/35/5d/752690df9ef5b76e169e68d6a129fa6d08a7100ca7f754c89495db3c6019/appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee", size = 4170, upload-time = "2024-02-06T09:43:11.258Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/29/5ecc3a15d5a33e31b26c11426c45c501e439cb865d0bff96315d86443b78/appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c", size = 4321, upload-time = "2024-02-06T09:43:09.663Z" }, +] + +[[package]] +name = "asttokens" +version = "3.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4a/e7/82da0a03e7ba5141f05cce0d302e6eed121ae055e0456ca228bf693984bc/asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7", size = 61978, upload-time = "2024-11-30T04:30:14.439Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/8a/c46dcc25341b5bce5472c718902eb3d38600a903b14fa6aeecef3f21a46f/asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2", size = 26918, upload-time = "2024-11-30T04:30:10.946Z" }, +] + +[[package]] +name = "at010-agent-chat" +version = "0.1.0" +source = { editable = "." } +dependencies = [ + { name = "agentex-sdk" }, + { name = "debugpy" }, + { name = "scale-gp" }, +] + +[package.optional-dependencies] +dev = [ + { name = "black" }, + { name = "flake8" }, + { name = "isort" }, + { name = "pytest" }, +] + +[package.metadata] +requires-dist = [ + { name = "agentex-sdk" }, + { name = "black", marker = "extra == 'dev'" }, + { name = "debugpy", specifier = ">=1.8.15" }, + { name = "flake8", marker = "extra == 'dev'" }, + { name = "isort", marker = "extra == 'dev'" }, + { name = "pytest", marker = "extra == 'dev'" }, + { name = "scale-gp" }, +] +provides-extras = ["dev"] + +[[package]] +name = "attrs" +version = "25.3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, +] + +[[package]] +name = "black" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec" }, + { name = "platformdirs" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/94/49/26a7b0f3f35da4b5a65f081943b7bcd22d7002f5f0fb8098ec1ff21cb6ef/black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666", size = 649449, upload-time = "2025-01-29T04:15:40.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/71/3fe4741df7adf015ad8dfa082dd36c94ca86bb21f25608eb247b4afb15b2/black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b", size = 1650988, upload-time = "2025-01-29T05:37:16.707Z" }, + { url = "https://files.pythonhosted.org/packages/13/f3/89aac8a83d73937ccd39bbe8fc6ac8860c11cfa0af5b1c96d081facac844/black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc", size = 1453985, upload-time = "2025-01-29T05:37:18.273Z" }, + { url = "https://files.pythonhosted.org/packages/6f/22/b99efca33f1f3a1d2552c714b1e1b5ae92efac6c43e790ad539a163d1754/black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f", size = 1783816, upload-time = "2025-01-29T04:18:33.823Z" }, + { url = "https://files.pythonhosted.org/packages/18/7e/a27c3ad3822b6f2e0e00d63d58ff6299a99a5b3aee69fa77cd4b0076b261/black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba", size = 1440860, upload-time = "2025-01-29T04:19:12.944Z" }, + { url = "https://files.pythonhosted.org/packages/98/87/0edf98916640efa5d0696e1abb0a8357b52e69e82322628f25bf14d263d1/black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f", size = 1650673, upload-time = "2025-01-29T05:37:20.574Z" }, + { url = "https://files.pythonhosted.org/packages/52/e5/f7bf17207cf87fa6e9b676576749c6b6ed0d70f179a3d812c997870291c3/black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3", size = 1453190, upload-time = "2025-01-29T05:37:22.106Z" }, + { url = "https://files.pythonhosted.org/packages/e3/ee/adda3d46d4a9120772fae6de454c8495603c37c4c3b9c60f25b1ab6401fe/black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171", size = 1782926, upload-time = "2025-01-29T04:18:58.564Z" }, + { url = "https://files.pythonhosted.org/packages/cc/64/94eb5f45dcb997d2082f097a3944cfc7fe87e071907f677e80788a2d7b7a/black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18", size = 1442613, upload-time = "2025-01-29T04:19:27.63Z" }, + { url = "https://files.pythonhosted.org/packages/09/71/54e999902aed72baf26bca0d50781b01838251a462612966e9fc4891eadd/black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717", size = 207646, upload-time = "2025-01-29T04:15:38.082Z" }, +] + +[[package]] +name = "cachetools" +version = "5.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/81/3747dad6b14fa2cf53fcf10548cf5aea6913e96fab41a3c198676f8948a5/cachetools-5.5.2.tar.gz", hash = "sha256:1a661caa9175d26759571b2e19580f9d6393969e5dfca11fdb1f947a23e640d4", size = 28380, upload-time = "2025-02-20T21:01:19.524Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/72/76/20fa66124dbe6be5cafeb312ece67de6b61dd91a0247d1ea13db4ebb33c2/cachetools-5.5.2-py3-none-any.whl", hash = "sha256:d26a22bcc62eb95c3beabd9f1ee5e820d3d2704fe2967cbe350e20c8ffcd3f0a", size = 10080, upload-time = "2025-02-20T21:01:16.647Z" }, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/dc/67/960ebe6bf230a96cda2e0abcf73af550ec4f090005363542f0765df162e0/certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407", size = 162386, upload-time = "2025-08-03T03:07:47.08Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e5/48/1549795ba7742c948d2ad169c1c8cdbae65bc450d6cd753d124b17c8cd32/certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5", size = 161216, upload-time = "2025-08-03T03:07:45.777Z" }, +] + +[[package]] +name = "cffi" +version = "1.17.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, + { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, + { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, + { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, + { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, + { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, + { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, + { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, + { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, + { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, + { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, + { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, + { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, + { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, + { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, + { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, + { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, + { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/2d/5fd176ceb9b2fc619e63405525573493ca23441330fcdaee6bef9460e924/charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14", size = 122371, upload-time = "2025-08-09T07:57:28.46Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/5e/14c94999e418d9b87682734589404a25854d5f5d0408df68bc15b6ff54bb/charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1", size = 205655, upload-time = "2025-08-09T07:56:08.475Z" }, + { url = "https://files.pythonhosted.org/packages/7d/a8/c6ec5d389672521f644505a257f50544c074cf5fc292d5390331cd6fc9c3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884", size = 146223, upload-time = "2025-08-09T07:56:09.708Z" }, + { url = "https://files.pythonhosted.org/packages/fc/eb/a2ffb08547f4e1e5415fb69eb7db25932c52a52bed371429648db4d84fb1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018", size = 159366, upload-time = "2025-08-09T07:56:11.326Z" }, + { url = "https://files.pythonhosted.org/packages/82/10/0fd19f20c624b278dddaf83b8464dcddc2456cb4b02bb902a6da126b87a1/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392", size = 157104, upload-time = "2025-08-09T07:56:13.014Z" }, + { url = "https://files.pythonhosted.org/packages/16/ab/0233c3231af734f5dfcf0844aa9582d5a1466c985bbed6cedab85af9bfe3/charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f", size = 151830, upload-time = "2025-08-09T07:56:14.428Z" }, + { url = "https://files.pythonhosted.org/packages/ae/02/e29e22b4e02839a0e4a06557b1999d0a47db3567e82989b5bb21f3fbbd9f/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154", size = 148854, upload-time = "2025-08-09T07:56:16.051Z" }, + { url = "https://files.pythonhosted.org/packages/05/6b/e2539a0a4be302b481e8cafb5af8792da8093b486885a1ae4d15d452bcec/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491", size = 160670, upload-time = "2025-08-09T07:56:17.314Z" }, + { url = "https://files.pythonhosted.org/packages/31/e7/883ee5676a2ef217a40ce0bffcc3d0dfbf9e64cbcfbdf822c52981c3304b/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93", size = 158501, upload-time = "2025-08-09T07:56:18.641Z" }, + { url = "https://files.pythonhosted.org/packages/c1/35/6525b21aa0db614cf8b5792d232021dca3df7f90a1944db934efa5d20bb1/charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f", size = 153173, upload-time = "2025-08-09T07:56:20.289Z" }, + { url = "https://files.pythonhosted.org/packages/50/ee/f4704bad8201de513fdc8aac1cabc87e38c5818c93857140e06e772b5892/charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37", size = 99822, upload-time = "2025-08-09T07:56:21.551Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/3b3836ca6064d0992c58c7561c6b6eee1b3892e9665d650c803bd5614522/charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc", size = 107543, upload-time = "2025-08-09T07:56:23.115Z" }, + { url = "https://files.pythonhosted.org/packages/65/ca/2135ac97709b400c7654b4b764daf5c5567c2da45a30cdd20f9eefe2d658/charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe", size = 205326, upload-time = "2025-08-09T07:56:24.721Z" }, + { url = "https://files.pythonhosted.org/packages/71/11/98a04c3c97dd34e49c7d247083af03645ca3730809a5509443f3c37f7c99/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8", size = 146008, upload-time = "2025-08-09T07:56:26.004Z" }, + { url = "https://files.pythonhosted.org/packages/60/f5/4659a4cb3c4ec146bec80c32d8bb16033752574c20b1252ee842a95d1a1e/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9", size = 159196, upload-time = "2025-08-09T07:56:27.25Z" }, + { url = "https://files.pythonhosted.org/packages/86/9e/f552f7a00611f168b9a5865a1414179b2c6de8235a4fa40189f6f79a1753/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31", size = 156819, upload-time = "2025-08-09T07:56:28.515Z" }, + { url = "https://files.pythonhosted.org/packages/7e/95/42aa2156235cbc8fa61208aded06ef46111c4d3f0de233107b3f38631803/charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f", size = 151350, upload-time = "2025-08-09T07:56:29.716Z" }, + { url = "https://files.pythonhosted.org/packages/c2/a9/3865b02c56f300a6f94fc631ef54f0a8a29da74fb45a773dfd3dcd380af7/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927", size = 148644, upload-time = "2025-08-09T07:56:30.984Z" }, + { url = "https://files.pythonhosted.org/packages/77/d9/cbcf1a2a5c7d7856f11e7ac2d782aec12bdfea60d104e60e0aa1c97849dc/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9", size = 160468, upload-time = "2025-08-09T07:56:32.252Z" }, + { url = "https://files.pythonhosted.org/packages/f6/42/6f45efee8697b89fda4d50580f292b8f7f9306cb2971d4b53f8914e4d890/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5", size = 158187, upload-time = "2025-08-09T07:56:33.481Z" }, + { url = "https://files.pythonhosted.org/packages/70/99/f1c3bdcfaa9c45b3ce96f70b14f070411366fa19549c1d4832c935d8e2c3/charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc", size = 152699, upload-time = "2025-08-09T07:56:34.739Z" }, + { url = "https://files.pythonhosted.org/packages/a3/ad/b0081f2f99a4b194bcbb1934ef3b12aa4d9702ced80a37026b7607c72e58/charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce", size = 99580, upload-time = "2025-08-09T07:56:35.981Z" }, + { url = "https://files.pythonhosted.org/packages/9a/8f/ae790790c7b64f925e5c953b924aaa42a243fb778fed9e41f147b2a5715a/charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef", size = 107366, upload-time = "2025-08-09T07:56:37.339Z" }, + { url = "https://files.pythonhosted.org/packages/8e/91/b5a06ad970ddc7a0e513112d40113e834638f4ca1120eb727a249fb2715e/charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15", size = 204342, upload-time = "2025-08-09T07:56:38.687Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ec/1edc30a377f0a02689342f214455c3f6c2fbedd896a1d2f856c002fc3062/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db", size = 145995, upload-time = "2025-08-09T07:56:40.048Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/5e67ab85e6d22b04641acb5399c8684f4d37caf7558a53859f0283a650e9/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d", size = 158640, upload-time = "2025-08-09T07:56:41.311Z" }, + { url = "https://files.pythonhosted.org/packages/f1/e5/38421987f6c697ee3722981289d554957c4be652f963d71c5e46a262e135/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096", size = 156636, upload-time = "2025-08-09T07:56:43.195Z" }, + { url = "https://files.pythonhosted.org/packages/a0/e4/5a075de8daa3ec0745a9a3b54467e0c2967daaaf2cec04c845f73493e9a1/charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa", size = 150939, upload-time = "2025-08-09T07:56:44.819Z" }, + { url = "https://files.pythonhosted.org/packages/02/f7/3611b32318b30974131db62b4043f335861d4d9b49adc6d57c1149cc49d4/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049", size = 148580, upload-time = "2025-08-09T07:56:46.684Z" }, + { url = "https://files.pythonhosted.org/packages/7e/61/19b36f4bd67f2793ab6a99b979b4e4f3d8fc754cbdffb805335df4337126/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0", size = 159870, upload-time = "2025-08-09T07:56:47.941Z" }, + { url = "https://files.pythonhosted.org/packages/06/57/84722eefdd338c04cf3030ada66889298eaedf3e7a30a624201e0cbe424a/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92", size = 157797, upload-time = "2025-08-09T07:56:49.756Z" }, + { url = "https://files.pythonhosted.org/packages/72/2a/aff5dd112b2f14bcc3462c312dce5445806bfc8ab3a7328555da95330e4b/charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16", size = 152224, upload-time = "2025-08-09T07:56:51.369Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8c/9839225320046ed279c6e839d51f028342eb77c91c89b8ef2549f951f3ec/charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce", size = 100086, upload-time = "2025-08-09T07:56:52.722Z" }, + { url = "https://files.pythonhosted.org/packages/ee/7a/36fbcf646e41f710ce0a563c1c9a343c6edf9be80786edeb15b6f62e17db/charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c", size = 107400, upload-time = "2025-08-09T07:56:55.172Z" }, + { url = "https://files.pythonhosted.org/packages/8a/1f/f041989e93b001bc4e44bb1669ccdcf54d3f00e628229a85b08d330615c5/charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a", size = 53175, upload-time = "2025-08-09T07:57:26.864Z" }, +] + +[[package]] +name = "click" +version = "8.2.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, +] + +[[package]] +name = "colorama" +version = "0.4.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, +] + +[[package]] +name = "comm" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4c/13/7d740c5849255756bc17888787313b61fd38a0a8304fc4f073dfc46122aa/comm-0.2.3.tar.gz", hash = "sha256:2dc8048c10962d55d7ad693be1e7045d891b7ce8d999c97963a5e3e99c055971", size = 6319, upload-time = "2025-07-25T14:02:04.452Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/60/97/891a0971e1e4a8c5d2b20bbe0e524dc04548d2307fee33cdeba148fd4fc7/comm-0.2.3-py3-none-any.whl", hash = "sha256:c615d91d75f7f04f095b30d1c1711babd43bdc6419c1be9886a85f2f4e489417", size = 7294, upload-time = "2025-07-25T14:02:02.896Z" }, +] + +[[package]] +name = "debugpy" +version = "1.8.16" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/d4/722d0bcc7986172ac2ef3c979ad56a1030e3afd44ced136d45f8142b1f4a/debugpy-1.8.16.tar.gz", hash = "sha256:31e69a1feb1cf6b51efbed3f6c9b0ef03bc46ff050679c4be7ea6d2e23540870", size = 1643809, upload-time = "2025-08-06T18:00:02.647Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/fb/0387c0e108d842c902801bc65ccc53e5b91d8c169702a9bbf4f7efcedf0c/debugpy-1.8.16-cp312-cp312-macosx_14_0_universal2.whl", hash = "sha256:b202e2843e32e80b3b584bcebfe0e65e0392920dc70df11b2bfe1afcb7a085e4", size = 2511822, upload-time = "2025-08-06T18:00:18.526Z" }, + { url = "https://files.pythonhosted.org/packages/37/44/19e02745cae22bf96440141f94e15a69a1afaa3a64ddfc38004668fcdebf/debugpy-1.8.16-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64473c4a306ba11a99fe0bb14622ba4fbd943eb004847d9b69b107bde45aa9ea", size = 4230135, upload-time = "2025-08-06T18:00:19.997Z" }, + { url = "https://files.pythonhosted.org/packages/f3/0b/19b1ba5ee4412f303475a2c7ad5858efb99c90eae5ec627aa6275c439957/debugpy-1.8.16-cp312-cp312-win32.whl", hash = "sha256:833a61ed446426e38b0dd8be3e9d45ae285d424f5bf6cd5b2b559c8f12305508", size = 5281271, upload-time = "2025-08-06T18:00:21.281Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e0/bc62e2dc141de53bd03e2c7cb9d7011de2e65e8bdcdaa26703e4d28656ba/debugpy-1.8.16-cp312-cp312-win_amd64.whl", hash = "sha256:75f204684581e9ef3dc2f67687c3c8c183fde2d6675ab131d94084baf8084121", size = 5323149, upload-time = "2025-08-06T18:00:23.033Z" }, + { url = "https://files.pythonhosted.org/packages/62/66/607ab45cc79e60624df386e233ab64a6d8d39ea02e7f80e19c1d451345bb/debugpy-1.8.16-cp313-cp313-macosx_14_0_universal2.whl", hash = "sha256:85df3adb1de5258dca910ae0bb185e48c98801ec15018a263a92bb06be1c8787", size = 2496157, upload-time = "2025-08-06T18:00:24.361Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a0/c95baae08a75bceabb79868d663a0736655e427ab9c81fb848da29edaeac/debugpy-1.8.16-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bee89e948bc236a5c43c4214ac62d28b29388453f5fd328d739035e205365f0b", size = 4222491, upload-time = "2025-08-06T18:00:25.806Z" }, + { url = "https://files.pythonhosted.org/packages/5b/2f/1c8db6ddd8a257c3cd2c46413b267f1d5fa3df910401c899513ce30392d6/debugpy-1.8.16-cp313-cp313-win32.whl", hash = "sha256:cf358066650439847ec5ff3dae1da98b5461ea5da0173d93d5e10f477c94609a", size = 5281126, upload-time = "2025-08-06T18:00:27.207Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ba/c3e154ab307366d6c5a9c1b68de04914e2ce7fa2f50d578311d8cc5074b2/debugpy-1.8.16-cp313-cp313-win_amd64.whl", hash = "sha256:b5aea1083f6f50023e8509399d7dc6535a351cc9f2e8827d1e093175e4d9fa4c", size = 5323094, upload-time = "2025-08-06T18:00:29.03Z" }, + { url = "https://files.pythonhosted.org/packages/52/57/ecc9ae29fa5b2d90107cd1d9bf8ed19aacb74b2264d986ae9d44fe9bdf87/debugpy-1.8.16-py2.py3-none-any.whl", hash = "sha256:19c9521962475b87da6f673514f7fd610328757ec993bf7ec0d8c96f9a325f9e", size = 5287700, upload-time = "2025-08-06T18:00:42.333Z" }, +] + +[[package]] +name = "decorator" +version = "5.2.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/fa/6d96a0978d19e17b68d634497769987b16c8f4cd0a7a05048bec693caa6b/decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360", size = 56711, upload-time = "2025-02-24T04:41:34.073Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4e/8c/f3147f5c4b73e7550fe5f9352eaa956ae838d5c51eb58e7a25b9f3e2643b/decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a", size = 9190, upload-time = "2025-02-24T04:41:32.565Z" }, +] + +[[package]] +name = "distro" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fc/f8/98eea607f65de6527f8a2e8885fc8015d3e6f5775df186e443e0964a11c3/distro-1.9.0.tar.gz", hash = "sha256:2fa77c6fd8940f116ee1d6b94a2f90b13b5ea8d019b98bc8bafdcabcdd9bdbed", size = 60722, upload-time = "2023-12-24T09:54:32.31Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/b3/231ffd4ab1fc9d679809f356cebee130ac7daa00d6d6f3206dd4fd137e9e/distro-1.9.0-py3-none-any.whl", hash = "sha256:7bffd925d65168f85027d8da9af6bddab658135b840670a223589bc0c8ef02b2", size = 20277, upload-time = "2023-12-24T09:54:30.421Z" }, +] + +[[package]] +name = "executing" +version = "2.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/91/50/a9d80c47ff289c611ff12e63f7c5d13942c65d68125160cefd768c73e6e4/executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755", size = 978693, upload-time = "2025-01-22T15:41:29.403Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/8f/c4d9bafc34ad7ad5d8dc16dd1347ee0e507a52c3adb6bfa8887e1c6a26ba/executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa", size = 26702, upload-time = "2025-01-22T15:41:25.929Z" }, +] + +[[package]] +name = "fastapi" +version = "0.115.14" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ca/53/8c38a874844a8b0fa10dd8adf3836ac154082cf88d3f22b544e9ceea0a15/fastapi-0.115.14.tar.gz", hash = "sha256:b1de15cdc1c499a4da47914db35d0e4ef8f1ce62b624e94e0e5824421df99739", size = 296263, upload-time = "2025-06-26T15:29:08.21Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/53/50/b1222562c6d270fea83e9c9075b8e8600b8479150a18e4516a6138b980d1/fastapi-0.115.14-py3-none-any.whl", hash = "sha256:6c0c8bf9420bd58f565e585036d971872472b4f7d3f6c73b698e10cffdefb3ca", size = 95514, upload-time = "2025-06-26T15:29:06.49Z" }, +] + +[[package]] +name = "filelock" +version = "3.19.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/40/bb/0ab3e58d22305b6f5440629d20683af28959bf793d98d11950e305c1c326/filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58", size = 17687, upload-time = "2025-08-14T16:56:03.016Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/42/14/42b2651a2f46b022ccd948bca9f2d5af0fd8929c4eec235b8d6d844fbe67/filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d", size = 15988, upload-time = "2025-08-14T16:56:01.633Z" }, +] + +[[package]] +name = "flake8" +version = "7.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mccabe" }, + { name = "pycodestyle" }, + { name = "pyflakes" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9f/56/13ab06b4f93ca7cac71078fbe37fcea175d3216f31f85c3168a6bbd0bb9a/flake8-7.3.0-py2.py3-none-any.whl", hash = "sha256:b9696257b9ce8beb888cdbe31cf885c90d31928fe202be0889a7cdafad32f01e", size = 57922, upload-time = "2025-06-20T19:31:34.425Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, + { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, + { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, + { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, + { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, + { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, + { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, + { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, + { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, + { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, + { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, + { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, + { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, + { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, + { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, + { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, + { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, + { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, + { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, + { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, + { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, + { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, + { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, + { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, + { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, + { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, + { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, + { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, + { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, + { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, + { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, + { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, + { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, + { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, + { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, + { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, + { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, + { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, + { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, + { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, + { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, + { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, + { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, + { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, + { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, + { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, +] + +[[package]] +name = "fsspec" +version = "2025.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8b/02/0835e6ab9cfc03916fe3f78c0956cfcdb6ff2669ffa6651065d5ebf7fc98/fsspec-2025.7.0.tar.gz", hash = "sha256:786120687ffa54b8283d942929540d8bc5ccfa820deb555a2b5d0ed2b737bf58", size = 304432, upload-time = "2025-07-15T16:05:21.19Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/e0/014d5d9d7a4564cf1c40b5039bc882db69fd881111e03ab3657ac0b218e2/fsspec-2025.7.0-py3-none-any.whl", hash = "sha256:8b012e39f63c7d5f10474de957f3ab793b47b45ae7d39f2fb735f8bbe25c0e21", size = 199597, upload-time = "2025-07-15T16:05:19.529Z" }, +] + +[[package]] +name = "google-auth" +version = "2.40.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cachetools" }, + { name = "pyasn1-modules" }, + { name = "rsa" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9e/9b/e92ef23b84fa10a64ce4831390b7a4c2e53c0132568d99d4ae61d04c8855/google_auth-2.40.3.tar.gz", hash = "sha256:500c3a29adedeb36ea9cf24b8d10858e152f2412e3ca37829b3fa18e33d63b77", size = 281029, upload-time = "2025-06-04T18:04:57.577Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/63/b19553b658a1692443c62bd07e5868adaa0ad746a0751ba62c59568cd45b/google_auth-2.40.3-py2.py3-none-any.whl", hash = "sha256:1370d4593e86213563547f97a92752fc658456fe4514c809544f330fed45a7ca", size = 216137, upload-time = "2025-06-04T18:04:55.573Z" }, +] + +[[package]] +name = "griffe" +version = "1.12.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/81/ca/29f36e00c74844ae50d139cf5a8b1751887b2f4d5023af65d460268ad7aa/griffe-1.12.1.tar.gz", hash = "sha256:29f5a6114c0aeda7d9c86a570f736883f8a2c5b38b57323d56b3d1c000565567", size = 411863, upload-time = "2025-08-14T21:08:15.38Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/f2/4fab6c3e5bcaf38a44cc8a974d2752eaad4c129e45d6533d926a30edd133/griffe-1.12.1-py3-none-any.whl", hash = "sha256:2d7c12334de00089c31905424a00abcfd931b45b8b516967f224133903d302cc", size = 138940, upload-time = "2025-08-14T21:08:13.382Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "hf-xet" +version = "1.1.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7a/49/91010b59debc7c862a5fd426d343134dd9a68778dbe570234b6495a4e204/hf_xet-1.1.8.tar.gz", hash = "sha256:62a0043e441753bbc446dcb5a3fe40a4d03f5fb9f13589ef1df9ab19252beb53", size = 484065, upload-time = "2025-08-18T22:01:03.584Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9c/91/5814db3a0d4a65fb6a87f0931ae28073b87f06307701fe66e7c41513bfb4/hf_xet-1.1.8-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3d5f82e533fc51c7daad0f9b655d9c7811b5308e5890236828bd1dd3ed8fea74", size = 2752357, upload-time = "2025-08-18T22:00:58.777Z" }, + { url = "https://files.pythonhosted.org/packages/70/72/ce898516e97341a7a9d450609e130e108643389110261eaee6deb1ba8545/hf_xet-1.1.8-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:8e2dba5896bca3ab61d0bef4f01a1647004de59640701b37e37eaa57087bbd9d", size = 2613142, upload-time = "2025-08-18T22:00:57.252Z" }, + { url = "https://files.pythonhosted.org/packages/b7/d6/13af5f916cef795ac2b5e4cc1de31f2e0e375f4475d50799915835f301c2/hf_xet-1.1.8-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bfe5700bc729be3d33d4e9a9b5cc17a951bf8c7ada7ba0c9198a6ab2053b7453", size = 3175859, upload-time = "2025-08-18T22:00:55.978Z" }, + { url = "https://files.pythonhosted.org/packages/4c/ed/34a193c9d1d72b7c3901b3b5153b1be9b2736b832692e1c3f167af537102/hf_xet-1.1.8-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:09e86514c3c4284ed8a57d6b0f3d089f9836a0af0a1ceb3c9dd664f1f3eaefef", size = 3074178, upload-time = "2025-08-18T22:00:54.147Z" }, + { url = "https://files.pythonhosted.org/packages/4a/1b/de6817b4bf65385280252dff5c9cceeedfbcb27ddb93923639323c1034a4/hf_xet-1.1.8-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4a9b99ab721d385b83f4fc8ee4e0366b0b59dce03b5888a86029cc0ca634efbf", size = 3238122, upload-time = "2025-08-18T22:01:00.546Z" }, + { url = "https://files.pythonhosted.org/packages/b7/13/874c85c7ed519ec101deb654f06703d9e5e68d34416730f64c4755ada36a/hf_xet-1.1.8-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:25b9d43333bbef39aeae1616789ec329c21401a7fe30969d538791076227b591", size = 3344325, upload-time = "2025-08-18T22:01:02.013Z" }, + { url = "https://files.pythonhosted.org/packages/9e/d3/0aaf279f4f3dea58e99401b92c31c0f752924ba0e6c7d7bb07b1dbd7f35e/hf_xet-1.1.8-cp37-abi3-win_amd64.whl", hash = "sha256:4171f31d87b13da4af1ed86c98cf763292e4720c088b4957cf9d564f92904ca9", size = 2801689, upload-time = "2025-08-18T22:01:04.81Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.27.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/78/82/08f8c936781f67d9e6b9eeb8a0c8b4e406136ea4c3d1f89a5db71d42e0e6/httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2", size = 144189, upload-time = "2024-08-27T12:54:01.334Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/56/95/9377bcb415797e44274b51d46e3249eba641711cf3348050f76ee7b15ffc/httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0", size = 76395, upload-time = "2024-08-27T12:53:59.653Z" }, +] + +[[package]] +name = "httpx-sse" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/fa/66bd985dd0b7c109a3bcb89272ee0bfb7e2b4d06309ad7b38ff866734b2a/httpx_sse-0.4.1.tar.gz", hash = "sha256:8f44d34414bc7b21bf3602713005c5df4917884f76072479b21f68befa4ea26e", size = 12998, upload-time = "2025-06-24T13:21:05.71Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/25/0a/6269e3473b09aed2dab8aa1a600c70f31f00ae1349bee30658f7e358a159/httpx_sse-0.4.1-py3-none-any.whl", hash = "sha256:cba42174344c3a5b06f255ce65b350880f962d99ead85e776f23c6618a377a37", size = 8054, upload-time = "2025-06-24T13:21:04.772Z" }, +] + +[[package]] +name = "huggingface-hub" +version = "0.34.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "filelock" }, + { name = "fsspec" }, + { name = "hf-xet", marker = "platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/c9/bdbe19339f76d12985bc03572f330a01a93c04dffecaaea3061bdd7fb892/huggingface_hub-0.34.4.tar.gz", hash = "sha256:a4228daa6fb001be3f4f4bdaf9a0db00e1739235702848df00885c9b5742c85c", size = 459768, upload-time = "2025-08-08T09:14:52.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/7b/bb06b061991107cd8783f300adff3e7b7f284e330fd82f507f2a1417b11d/huggingface_hub-0.34.4-py3-none-any.whl", hash = "sha256:9b365d781739c93ff90c359844221beef048403f1bc1f1c123c191257c3c890a", size = 561452, upload-time = "2025-08-08T09:14:50.159Z" }, +] + +[[package]] +name = "idna" +version = "3.10" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, +] + +[[package]] +name = "importlib-metadata" +version = "8.7.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "zipp" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/b0/36bd937216ec521246249be3bf9855081de4c5e06a0c9b4219dbeda50373/importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd", size = 27656, upload-time = "2025-04-27T15:29:00.214Z" }, +] + +[[package]] +name = "iniconfig" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f2/97/ebf4da567aa6827c909642694d71c9fcf53e5b504f2d96afea02718862f3/iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7", size = 4793, upload-time = "2025-03-19T20:09:59.721Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/e1/e6716421ea10d38022b952c159d5161ca1193197fb744506875fbb87ea7b/iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760", size = 6050, upload-time = "2025-03-19T20:10:01.071Z" }, +] + +[[package]] +name = "ipykernel" +version = "6.30.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "appnope", marker = "sys_platform == 'darwin'" }, + { name = "comm" }, + { name = "debugpy" }, + { name = "ipython" }, + { name = "jupyter-client" }, + { name = "jupyter-core" }, + { name = "matplotlib-inline" }, + { name = "nest-asyncio" }, + { name = "packaging" }, + { name = "psutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/76/11082e338e0daadc89c8ff866185de11daf67d181901038f9e139d109761/ipykernel-6.30.1.tar.gz", hash = "sha256:6abb270161896402e76b91394fcdce5d1be5d45f456671e5080572f8505be39b", size = 166260, upload-time = "2025-08-04T15:47:35.018Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fc/c7/b445faca8deb954fe536abebff4ece5b097b923de482b26e78448c89d1dd/ipykernel-6.30.1-py3-none-any.whl", hash = "sha256:aa6b9fb93dca949069d8b85b6c79b2518e32ac583ae9c7d37c51d119e18b3fb4", size = 117484, upload-time = "2025-08-04T15:47:32.622Z" }, +] + +[[package]] +name = "ipython" +version = "9.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "decorator" }, + { name = "ipython-pygments-lexers" }, + { name = "jedi" }, + { name = "matplotlib-inline" }, + { name = "pexpect", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" }, + { name = "prompt-toolkit" }, + { name = "pygments" }, + { name = "stack-data" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/54/80/406f9e3bde1c1fd9bf5a0be9d090f8ae623e401b7670d8f6fdf2ab679891/ipython-9.4.0.tar.gz", hash = "sha256:c033c6d4e7914c3d9768aabe76bbe87ba1dc66a92a05db6bfa1125d81f2ee270", size = 4385338, upload-time = "2025-07-01T11:11:30.606Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/63/f8/0031ee2b906a15a33d6bfc12dd09c3dfa966b3cb5b284ecfb7549e6ac3c4/ipython-9.4.0-py3-none-any.whl", hash = "sha256:25850f025a446d9b359e8d296ba175a36aedd32e83ca9b5060430fe16801f066", size = 611021, upload-time = "2025-07-01T11:11:27.85Z" }, +] + +[[package]] +name = "ipython-pygments-lexers" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/4c/5dd1d8af08107f88c7f741ead7a40854b8ac24ddf9ae850afbcf698aa552/ipython_pygments_lexers-1.1.1.tar.gz", hash = "sha256:09c0138009e56b6854f9535736f4171d855c8c08a563a0dcd8022f78355c7e81", size = 8393, upload-time = "2025-01-17T11:24:34.505Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/33/1f075bf72b0b747cb3288d011319aaf64083cf2efef8354174e3ed4540e2/ipython_pygments_lexers-1.1.1-py3-none-any.whl", hash = "sha256:a9462224a505ade19a605f71f8fa63c2048833ce50abc86768a0d81d876dc81c", size = 8074, upload-time = "2025-01-17T11:24:33.271Z" }, +] + +[[package]] +name = "isort" +version = "6.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b8/21/1e2a441f74a653a144224d7d21afe8f4169e6c7c20bb13aec3a2dc3815e0/isort-6.0.1.tar.gz", hash = "sha256:1cb5df28dfbc742e490c5e41bad6da41b805b0a8be7bc93cd0fb2a8a890ac450", size = 821955, upload-time = "2025-02-26T21:13:16.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/11/114d0a5f4dabbdcedc1125dee0888514c3c3b16d3e9facad87ed96fad97c/isort-6.0.1-py3-none-any.whl", hash = "sha256:2dc5d7f65c9678d94c88dfc29161a320eec67328bc97aad576874cb4be1e9615", size = 94186, upload-time = "2025-02-26T21:13:14.911Z" }, +] + +[[package]] +name = "jedi" +version = "0.19.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "parso" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/72/3a/79a912fbd4d8dd6fbb02bf69afd3bb72cf0c729bb3063c6f4498603db17a/jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0", size = 1231287, upload-time = "2024-11-11T01:41:42.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/5a/9cac0c82afec3d09ccd97c8b6502d48f165f9124db81b4bcb90b4af974ee/jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9", size = 1572278, upload-time = "2024-11-11T01:41:40.175Z" }, +] + +[[package]] +name = "jinja2" +version = "3.1.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markupsafe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, +] + +[[package]] +name = "jiter" +version = "0.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/9d/ae7ddb4b8ab3fb1b51faf4deb36cb48a4fbbd7cb36bad6a5fca4741306f7/jiter-0.10.0.tar.gz", hash = "sha256:07a7142c38aacc85194391108dc91b5b57093c978a9932bd86a36862759d9500", size = 162759, upload-time = "2025-05-18T19:04:59.73Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/b5/348b3313c58f5fbfb2194eb4d07e46a35748ba6e5b3b3046143f3040bafa/jiter-0.10.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:1e274728e4a5345a6dde2d343c8da018b9d4bd4350f5a472fa91f66fda44911b", size = 312262, upload-time = "2025-05-18T19:03:44.637Z" }, + { url = "https://files.pythonhosted.org/packages/9c/4a/6a2397096162b21645162825f058d1709a02965606e537e3304b02742e9b/jiter-0.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7202ae396446c988cb2a5feb33a543ab2165b786ac97f53b59aafb803fef0744", size = 320124, upload-time = "2025-05-18T19:03:46.341Z" }, + { url = "https://files.pythonhosted.org/packages/2a/85/1ce02cade7516b726dd88f59a4ee46914bf79d1676d1228ef2002ed2f1c9/jiter-0.10.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23ba7722d6748b6920ed02a8f1726fb4b33e0fd2f3f621816a8b486c66410ab2", size = 345330, upload-time = "2025-05-18T19:03:47.596Z" }, + { url = "https://files.pythonhosted.org/packages/75/d0/bb6b4f209a77190ce10ea8d7e50bf3725fc16d3372d0a9f11985a2b23eff/jiter-0.10.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:371eab43c0a288537d30e1f0b193bc4eca90439fc08a022dd83e5e07500ed026", size = 369670, upload-time = "2025-05-18T19:03:49.334Z" }, + { url = "https://files.pythonhosted.org/packages/a0/f5/a61787da9b8847a601e6827fbc42ecb12be2c925ced3252c8ffcb56afcaf/jiter-0.10.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c675736059020365cebc845a820214765162728b51ab1e03a1b7b3abb70f74c", size = 489057, upload-time = "2025-05-18T19:03:50.66Z" }, + { url = "https://files.pythonhosted.org/packages/12/e4/6f906272810a7b21406c760a53aadbe52e99ee070fc5c0cb191e316de30b/jiter-0.10.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c5867d40ab716e4684858e4887489685968a47e3ba222e44cde6e4a2154f959", size = 389372, upload-time = "2025-05-18T19:03:51.98Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ba/77013b0b8ba904bf3762f11e0129b8928bff7f978a81838dfcc958ad5728/jiter-0.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:395bb9a26111b60141757d874d27fdea01b17e8fac958b91c20128ba8f4acc8a", size = 352038, upload-time = "2025-05-18T19:03:53.703Z" }, + { url = "https://files.pythonhosted.org/packages/67/27/c62568e3ccb03368dbcc44a1ef3a423cb86778a4389e995125d3d1aaa0a4/jiter-0.10.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6842184aed5cdb07e0c7e20e5bdcfafe33515ee1741a6835353bb45fe5d1bd95", size = 391538, upload-time = "2025-05-18T19:03:55.046Z" }, + { url = "https://files.pythonhosted.org/packages/c0/72/0d6b7e31fc17a8fdce76164884edef0698ba556b8eb0af9546ae1a06b91d/jiter-0.10.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:62755d1bcea9876770d4df713d82606c8c1a3dca88ff39046b85a048566d56ea", size = 523557, upload-time = "2025-05-18T19:03:56.386Z" }, + { url = "https://files.pythonhosted.org/packages/2f/09/bc1661fbbcbeb6244bd2904ff3a06f340aa77a2b94e5a7373fd165960ea3/jiter-0.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:533efbce2cacec78d5ba73a41756beff8431dfa1694b6346ce7af3a12c42202b", size = 514202, upload-time = "2025-05-18T19:03:57.675Z" }, + { url = "https://files.pythonhosted.org/packages/1b/84/5a5d5400e9d4d54b8004c9673bbe4403928a00d28529ff35b19e9d176b19/jiter-0.10.0-cp312-cp312-win32.whl", hash = "sha256:8be921f0cadd245e981b964dfbcd6fd4bc4e254cdc069490416dd7a2632ecc01", size = 211781, upload-time = "2025-05-18T19:03:59.025Z" }, + { url = "https://files.pythonhosted.org/packages/9b/52/7ec47455e26f2d6e5f2ea4951a0652c06e5b995c291f723973ae9e724a65/jiter-0.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:a7c7d785ae9dda68c2678532a5a1581347e9c15362ae9f6e68f3fdbfb64f2e49", size = 206176, upload-time = "2025-05-18T19:04:00.305Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b0/279597e7a270e8d22623fea6c5d4eeac328e7d95c236ed51a2b884c54f70/jiter-0.10.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e0588107ec8e11b6f5ef0e0d656fb2803ac6cf94a96b2b9fc675c0e3ab5e8644", size = 311617, upload-time = "2025-05-18T19:04:02.078Z" }, + { url = "https://files.pythonhosted.org/packages/91/e3/0916334936f356d605f54cc164af4060e3e7094364add445a3bc79335d46/jiter-0.10.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cafc4628b616dc32530c20ee53d71589816cf385dd9449633e910d596b1f5c8a", size = 318947, upload-time = "2025-05-18T19:04:03.347Z" }, + { url = "https://files.pythonhosted.org/packages/6a/8e/fd94e8c02d0e94539b7d669a7ebbd2776e51f329bb2c84d4385e8063a2ad/jiter-0.10.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:520ef6d981172693786a49ff5b09eda72a42e539f14788124a07530f785c3ad6", size = 344618, upload-time = "2025-05-18T19:04:04.709Z" }, + { url = "https://files.pythonhosted.org/packages/6f/b0/f9f0a2ec42c6e9c2e61c327824687f1e2415b767e1089c1d9135f43816bd/jiter-0.10.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:554dedfd05937f8fc45d17ebdf298fe7e0c77458232bcb73d9fbbf4c6455f5b3", size = 368829, upload-time = "2025-05-18T19:04:06.912Z" }, + { url = "https://files.pythonhosted.org/packages/e8/57/5bbcd5331910595ad53b9fd0c610392ac68692176f05ae48d6ce5c852967/jiter-0.10.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5bc299da7789deacf95f64052d97f75c16d4fc8c4c214a22bf8d859a4288a1c2", size = 491034, upload-time = "2025-05-18T19:04:08.222Z" }, + { url = "https://files.pythonhosted.org/packages/9b/be/c393df00e6e6e9e623a73551774449f2f23b6ec6a502a3297aeeece2c65a/jiter-0.10.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5161e201172de298a8a1baad95eb85db4fb90e902353b1f6a41d64ea64644e25", size = 388529, upload-time = "2025-05-18T19:04:09.566Z" }, + { url = "https://files.pythonhosted.org/packages/42/3e/df2235c54d365434c7f150b986a6e35f41ebdc2f95acea3036d99613025d/jiter-0.10.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2e2227db6ba93cb3e2bf67c87e594adde0609f146344e8207e8730364db27041", size = 350671, upload-time = "2025-05-18T19:04:10.98Z" }, + { url = "https://files.pythonhosted.org/packages/c6/77/71b0b24cbcc28f55ab4dbfe029f9a5b73aeadaba677843fc6dc9ed2b1d0a/jiter-0.10.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:15acb267ea5e2c64515574b06a8bf393fbfee6a50eb1673614aa45f4613c0cca", size = 390864, upload-time = "2025-05-18T19:04:12.722Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d3/ef774b6969b9b6178e1d1e7a89a3bd37d241f3d3ec5f8deb37bbd203714a/jiter-0.10.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:901b92f2e2947dc6dfcb52fd624453862e16665ea909a08398dde19c0731b7f4", size = 522989, upload-time = "2025-05-18T19:04:14.261Z" }, + { url = "https://files.pythonhosted.org/packages/0c/41/9becdb1d8dd5d854142f45a9d71949ed7e87a8e312b0bede2de849388cb9/jiter-0.10.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:d0cb9a125d5a3ec971a094a845eadde2db0de85b33c9f13eb94a0c63d463879e", size = 513495, upload-time = "2025-05-18T19:04:15.603Z" }, + { url = "https://files.pythonhosted.org/packages/9c/36/3468e5a18238bdedae7c4d19461265b5e9b8e288d3f86cd89d00cbb48686/jiter-0.10.0-cp313-cp313-win32.whl", hash = "sha256:48a403277ad1ee208fb930bdf91745e4d2d6e47253eedc96e2559d1e6527006d", size = 211289, upload-time = "2025-05-18T19:04:17.541Z" }, + { url = "https://files.pythonhosted.org/packages/7e/07/1c96b623128bcb913706e294adb5f768fb7baf8db5e1338ce7b4ee8c78ef/jiter-0.10.0-cp313-cp313-win_amd64.whl", hash = "sha256:75f9eb72ecb640619c29bf714e78c9c46c9c4eaafd644bf78577ede459f330d4", size = 205074, upload-time = "2025-05-18T19:04:19.21Z" }, + { url = "https://files.pythonhosted.org/packages/54/46/caa2c1342655f57d8f0f2519774c6d67132205909c65e9aa8255e1d7b4f4/jiter-0.10.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:28ed2a4c05a1f32ef0e1d24c2611330219fed727dae01789f4a335617634b1ca", size = 318225, upload-time = "2025-05-18T19:04:20.583Z" }, + { url = "https://files.pythonhosted.org/packages/43/84/c7d44c75767e18946219ba2d703a5a32ab37b0bc21886a97bc6062e4da42/jiter-0.10.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14a4c418b1ec86a195f1ca69da8b23e8926c752b685af665ce30777233dfe070", size = 350235, upload-time = "2025-05-18T19:04:22.363Z" }, + { url = "https://files.pythonhosted.org/packages/01/16/f5a0135ccd968b480daad0e6ab34b0c7c5ba3bc447e5088152696140dcb3/jiter-0.10.0-cp313-cp313t-win_amd64.whl", hash = "sha256:d7bfed2fe1fe0e4dda6ef682cee888ba444b21e7a6553e03252e4feb6cf0adca", size = 207278, upload-time = "2025-05-18T19:04:23.627Z" }, + { url = "https://files.pythonhosted.org/packages/1c/9b/1d646da42c3de6c2188fdaa15bce8ecb22b635904fc68be025e21249ba44/jiter-0.10.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:5e9251a5e83fab8d87799d3e1a46cb4b7f2919b895c6f4483629ed2446f66522", size = 310866, upload-time = "2025-05-18T19:04:24.891Z" }, + { url = "https://files.pythonhosted.org/packages/ad/0e/26538b158e8a7c7987e94e7aeb2999e2e82b1f9d2e1f6e9874ddf71ebda0/jiter-0.10.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:023aa0204126fe5b87ccbcd75c8a0d0261b9abdbbf46d55e7ae9f8e22424eeb8", size = 318772, upload-time = "2025-05-18T19:04:26.161Z" }, + { url = "https://files.pythonhosted.org/packages/7b/fb/d302893151caa1c2636d6574d213e4b34e31fd077af6050a9c5cbb42f6fb/jiter-0.10.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c189c4f1779c05f75fc17c0c1267594ed918996a231593a21a5ca5438445216", size = 344534, upload-time = "2025-05-18T19:04:27.495Z" }, + { url = "https://files.pythonhosted.org/packages/01/d8/5780b64a149d74e347c5128d82176eb1e3241b1391ac07935693466d6219/jiter-0.10.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:15720084d90d1098ca0229352607cd68256c76991f6b374af96f36920eae13c4", size = 369087, upload-time = "2025-05-18T19:04:28.896Z" }, + { url = "https://files.pythonhosted.org/packages/e8/5b/f235a1437445160e777544f3ade57544daf96ba7e96c1a5b24a6f7ac7004/jiter-0.10.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e4f2fb68e5f1cfee30e2b2a09549a00683e0fde4c6a2ab88c94072fc33cb7426", size = 490694, upload-time = "2025-05-18T19:04:30.183Z" }, + { url = "https://files.pythonhosted.org/packages/85/a9/9c3d4617caa2ff89cf61b41e83820c27ebb3f7b5fae8a72901e8cd6ff9be/jiter-0.10.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce541693355fc6da424c08b7edf39a2895f58d6ea17d92cc2b168d20907dee12", size = 388992, upload-time = "2025-05-18T19:04:32.028Z" }, + { url = "https://files.pythonhosted.org/packages/68/b1/344fd14049ba5c94526540af7eb661871f9c54d5f5601ff41a959b9a0bbd/jiter-0.10.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31c50c40272e189d50006ad5c73883caabb73d4e9748a688b216e85a9a9ca3b9", size = 351723, upload-time = "2025-05-18T19:04:33.467Z" }, + { url = "https://files.pythonhosted.org/packages/41/89/4c0e345041186f82a31aee7b9d4219a910df672b9fef26f129f0cda07a29/jiter-0.10.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fa3402a2ff9815960e0372a47b75c76979d74402448509ccd49a275fa983ef8a", size = 392215, upload-time = "2025-05-18T19:04:34.827Z" }, + { url = "https://files.pythonhosted.org/packages/55/58/ee607863e18d3f895feb802154a2177d7e823a7103f000df182e0f718b38/jiter-0.10.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:1956f934dca32d7bb647ea21d06d93ca40868b505c228556d3373cbd255ce853", size = 522762, upload-time = "2025-05-18T19:04:36.19Z" }, + { url = "https://files.pythonhosted.org/packages/15/d0/9123fb41825490d16929e73c212de9a42913d68324a8ce3c8476cae7ac9d/jiter-0.10.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:fcedb049bdfc555e261d6f65a6abe1d5ad68825b7202ccb9692636c70fcced86", size = 513427, upload-time = "2025-05-18T19:04:37.544Z" }, + { url = "https://files.pythonhosted.org/packages/d8/b3/2bd02071c5a2430d0b70403a34411fc519c2f227da7b03da9ba6a956f931/jiter-0.10.0-cp314-cp314-win32.whl", hash = "sha256:ac509f7eccca54b2a29daeb516fb95b6f0bd0d0d8084efaf8ed5dfc7b9f0b357", size = 210127, upload-time = "2025-05-18T19:04:38.837Z" }, + { url = "https://files.pythonhosted.org/packages/03/0c/5fe86614ea050c3ecd728ab4035534387cd41e7c1855ef6c031f1ca93e3f/jiter-0.10.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5ed975b83a2b8639356151cef5c0d597c68376fc4922b45d0eb384ac058cfa00", size = 318527, upload-time = "2025-05-18T19:04:40.612Z" }, + { url = "https://files.pythonhosted.org/packages/b3/4a/4175a563579e884192ba6e81725fc0448b042024419be8d83aa8a80a3f44/jiter-0.10.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3aa96f2abba33dc77f79b4cf791840230375f9534e5fac927ccceb58c5e604a5", size = 354213, upload-time = "2025-05-18T19:04:41.894Z" }, +] + +[[package]] +name = "jsonref" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/aa/0d/c1f3277e90ccdb50d33ed5ba1ec5b3f0a242ed8c1b1a85d3afeb68464dca/jsonref-1.1.0.tar.gz", hash = "sha256:32fe8e1d85af0fdefbebce950af85590b22b60f9e95443176adbde4e1ecea552", size = 8814, upload-time = "2023-01-16T16:10:04.455Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/ec/e1db9922bceb168197a558a2b8c03a7963f1afe93517ddd3cf99f202f996/jsonref-1.1.0-py3-none-any.whl", hash = "sha256:590dc7773df6c21cbf948b5dac07a72a251db28b0238ceecce0a2abfa8ec30a9", size = 9425, upload-time = "2023-01-16T16:10:02.255Z" }, +] + +[[package]] +name = "jsonschema" +version = "4.25.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "jsonschema-specifications" }, + { name = "referencing" }, + { name = "rpds-py" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/74/69/f7185de793a29082a9f3c7728268ffb31cb5095131a9c139a74078e27336/jsonschema-4.25.1.tar.gz", hash = "sha256:e4a9655ce0da0c0b67a085847e00a3a51449e1157f4f75e9fb5aa545e122eb85", size = 357342, upload-time = "2025-08-18T17:03:50.038Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/9c/8c95d856233c1f82500c2450b8c68576b4cf1c871db3afac5c34ff84e6fd/jsonschema-4.25.1-py3-none-any.whl", hash = "sha256:3fba0169e345c7175110351d456342c364814cfcf3b964ba4587f22915230a63", size = 90040, upload-time = "2025-08-18T17:03:48.373Z" }, +] + +[[package]] +name = "jsonschema-specifications" +version = "2025.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "referencing" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bf/ce/46fbd9c8119cfc3581ee5643ea49464d168028cfb5caff5fc0596d0cf914/jsonschema_specifications-2025.4.1.tar.gz", hash = "sha256:630159c9f4dbea161a6a2205c3011cc4f18ff381b189fff48bb39b9bf26ae608", size = 15513, upload-time = "2025-04-23T12:34:07.418Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/0e/b27cdbaccf30b890c40ed1da9fd4a3593a5cf94dae54fb34f8a4b74fcd3f/jsonschema_specifications-2025.4.1-py3-none-any.whl", hash = "sha256:4653bffbd6584f7de83a67e0d620ef16900b390ddc7939d56684d6c81e33f1af", size = 18437, upload-time = "2025-04-23T12:34:05.422Z" }, +] + +[[package]] +name = "jupyter-client" +version = "8.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jupyter-core" }, + { name = "python-dateutil" }, + { name = "pyzmq" }, + { name = "tornado" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/71/22/bf9f12fdaeae18019a468b68952a60fe6dbab5d67cd2a103cac7659b41ca/jupyter_client-8.6.3.tar.gz", hash = "sha256:35b3a0947c4a6e9d589eb97d7d4cd5e90f910ee73101611f01283732bd6d9419", size = 342019, upload-time = "2024-09-17T10:44:17.613Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/85/b0394e0b6fcccd2c1eeefc230978a6f8cb0c5df1e4cd3e7625735a0d7d1e/jupyter_client-8.6.3-py3-none-any.whl", hash = "sha256:e8a19cc986cc45905ac3362915f410f3af85424b4c0905e94fa5f2cb08e8f23f", size = 106105, upload-time = "2024-09-17T10:44:15.218Z" }, +] + +[[package]] +name = "jupyter-core" +version = "5.8.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "platformdirs" }, + { name = "pywin32", marker = "platform_python_implementation != 'PyPy' and sys_platform == 'win32'" }, + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/1b/72906d554acfeb588332eaaa6f61577705e9ec752ddb486f302dafa292d9/jupyter_core-5.8.1.tar.gz", hash = "sha256:0a5f9706f70e64786b75acba995988915ebd4601c8a52e534a40b51c95f59941", size = 88923, upload-time = "2025-05-27T07:38:16.655Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2f/57/6bffd4b20b88da3800c5d691e0337761576ee688eb01299eae865689d2df/jupyter_core-5.8.1-py3-none-any.whl", hash = "sha256:c28d268fc90fb53f1338ded2eb410704c5449a358406e8a948b75706e24863d0", size = 28880, upload-time = "2025-05-27T07:38:15.137Z" }, +] + +[[package]] +name = "kubernetes" +version = "28.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "google-auth" }, + { name = "oauthlib" }, + { name = "python-dateutil" }, + { name = "pyyaml" }, + { name = "requests" }, + { name = "requests-oauthlib" }, + { name = "six" }, + { name = "urllib3" }, + { name = "websocket-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/5e/d27f39f447137a9a3d1f31142c77ce74bcedfda7dafe922d725c7ef2da33/kubernetes-28.1.0.tar.gz", hash = "sha256:1468069a573430fb1cb5ad22876868f57977930f80a6749405da31cd6086a7e9", size = 817854, upload-time = "2023-09-18T17:32:07.314Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/6a/1f69c2d8b1ff03f8d8e10d801f4ac3016ed4c1b00aa9795732c6ec900bba/kubernetes-28.1.0-py2.py3-none-any.whl", hash = "sha256:10f56f8160dcb73647f15fafda268e7f60cf7dbc9f8e46d52fcd46d3beb0c18d", size = 1566315, upload-time = "2023-09-18T17:32:05.283Z" }, +] + +[[package]] +name = "litellm" +version = "1.75.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "click" }, + { name = "httpx" }, + { name = "importlib-metadata" }, + { name = "jinja2" }, + { name = "jsonschema" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "tiktoken" }, + { name = "tokenizers" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d2/d8/08615bc4811d9a6df2b46f8efa7a0d6f7f8e1ca268a4c794540d9987a035/litellm-1.75.9.tar.gz", hash = "sha256:d8baf4b9988df599b55cb675808bbe22cedee2f099ba883684fe3f23af8d13a9", size = 10142656, upload-time = "2025-08-20T17:43:50.554Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5d/b2/f21db9636d9fcd67b2c557c58aafb8a6e9b53864f7a40d645e09c2e3ab98/litellm-1.75.9-py3-none-any.whl", hash = "sha256:a72c3e05bcb0e50ac1804f0df09d0d7bf5cb41e84351e1609a960033b0ef01c1", size = 8920144, upload-time = "2025-08-20T17:43:48.327Z" }, +] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5b/f5/4ec618ed16cc4f8fb3b701563655a69816155e79e24a17b651541804721d/markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3", size = 73070, upload-time = "2025-08-11T12:57:52.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/94/54/e7d793b573f298e1c9013b8c4dade17d481164aa517d1d7148619c2cedbf/markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147", size = 87321, upload-time = "2025-08-11T12:57:51.923Z" }, +] + +[[package]] +name = "markupsafe" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, + { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, + { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, + { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, + { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, + { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, + { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, + { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, + { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, + { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, + { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, + { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, + { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, + { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, + { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, + { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, + { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, + { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, + { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, + { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, + { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, + { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, + { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, + { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, + { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, + { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, + { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "traitlets" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/99/5b/a36a337438a14116b16480db471ad061c36c3694df7c2084a0da7ba538b7/matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", size = 8159, upload-time = "2024-04-15T13:44:44.803Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8f/8e/9ad090d3553c280a8060fbf6e24dc1c0c29704ee7d1c372f0c174aa59285/matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca", size = 9899, upload-time = "2024-04-15T13:44:43.265Z" }, +] + +[[package]] +name = "mccabe" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/ff/0ffefdcac38932a54d2b5eed4e0ba8a408f215002cd178ad1df0f2806ff8/mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325", size = 9658, upload-time = "2022-01-24T01:14:51.113Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/27/1a/1f68f9ba0c207934b35b86a8ca3aad8395a3d6dd7921c0686e23853ff5a9/mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e", size = 7350, upload-time = "2022-01-24T01:14:49.62Z" }, +] + +[[package]] +name = "mcp" +version = "1.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "jsonschema" }, + { name = "pydantic" }, + { name = "pydantic-settings" }, + { name = "python-multipart" }, + { name = "pywin32", marker = "sys_platform == 'win32'" }, + { name = "sse-starlette" }, + { name = "starlette" }, + { name = "uvicorn", marker = "sys_platform != 'emscripten'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d3/a8/564c094de5d6199f727f5d9f5672dbec3b00dfafd0f67bf52d995eaa5951/mcp-1.13.0.tar.gz", hash = "sha256:70452f56f74662a94eb72ac5feb93997b35995e389b3a3a574e078bed2aa9ab3", size = 434709, upload-time = "2025-08-14T15:03:58.58Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/6b/46b8bcefc2ee9e2d2e8d2bd25f1c2512f5a879fac4619d716b194d6e7ccc/mcp-1.13.0-py3-none-any.whl", hash = "sha256:8b1a002ebe6e17e894ec74d1943cc09aa9d23cb931bf58d49ab2e9fa6bb17e4b", size = 160226, upload-time = "2025-08-14T15:03:56.641Z" }, +] + +[package.optional-dependencies] +cli = [ + { name = "python-dotenv" }, + { name = "typer" }, +] + +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "multidict" +version = "6.6.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/69/7f/0652e6ed47ab288e3756ea9c0df8b14950781184d4bd7883f4d87dd41245/multidict-6.6.4.tar.gz", hash = "sha256:d2d4e4787672911b48350df02ed3fa3fffdc2f2e8ca06dd6afdf34189b76a9dd", size = 101843, upload-time = "2025-08-11T12:08:48.217Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/05/f6/512ffd8fd8b37fb2680e5ac35d788f1d71bbaf37789d21a820bdc441e565/multidict-6.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0ffb87be160942d56d7b87b0fdf098e81ed565add09eaa1294268c7f3caac4c8", size = 76516, upload-time = "2025-08-11T12:06:53.393Z" }, + { url = "https://files.pythonhosted.org/packages/99/58/45c3e75deb8855c36bd66cc1658007589662ba584dbf423d01df478dd1c5/multidict-6.6.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d191de6cbab2aff5de6c5723101705fd044b3e4c7cfd587a1929b5028b9714b3", size = 45394, upload-time = "2025-08-11T12:06:54.555Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ca/e8c4472a93a26e4507c0b8e1f0762c0d8a32de1328ef72fd704ef9cc5447/multidict-6.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:38a0956dd92d918ad5feff3db8fcb4a5eb7dba114da917e1a88475619781b57b", size = 43591, upload-time = "2025-08-11T12:06:55.672Z" }, + { url = "https://files.pythonhosted.org/packages/05/51/edf414f4df058574a7265034d04c935aa84a89e79ce90fcf4df211f47b16/multidict-6.6.4-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6865f6d3b7900ae020b495d599fcf3765653bc927951c1abb959017f81ae8287", size = 237215, upload-time = "2025-08-11T12:06:57.213Z" }, + { url = "https://files.pythonhosted.org/packages/c8/45/8b3d6dbad8cf3252553cc41abea09ad527b33ce47a5e199072620b296902/multidict-6.6.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0a2088c126b6f72db6c9212ad827d0ba088c01d951cee25e758c450da732c138", size = 258299, upload-time = "2025-08-11T12:06:58.946Z" }, + { url = "https://files.pythonhosted.org/packages/3c/e8/8ca2e9a9f5a435fc6db40438a55730a4bf4956b554e487fa1b9ae920f825/multidict-6.6.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0f37bed7319b848097085d7d48116f545985db988e2256b2e6f00563a3416ee6", size = 242357, upload-time = "2025-08-11T12:07:00.301Z" }, + { url = "https://files.pythonhosted.org/packages/0f/84/80c77c99df05a75c28490b2af8f7cba2a12621186e0a8b0865d8e745c104/multidict-6.6.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:01368e3c94032ba6ca0b78e7ccb099643466cf24f8dc8eefcfdc0571d56e58f9", size = 268369, upload-time = "2025-08-11T12:07:01.638Z" }, + { url = "https://files.pythonhosted.org/packages/0d/e9/920bfa46c27b05fb3e1ad85121fd49f441492dca2449c5bcfe42e4565d8a/multidict-6.6.4-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8fe323540c255db0bffee79ad7f048c909f2ab0edb87a597e1c17da6a54e493c", size = 269341, upload-time = "2025-08-11T12:07:02.943Z" }, + { url = "https://files.pythonhosted.org/packages/af/65/753a2d8b05daf496f4a9c367fe844e90a1b2cac78e2be2c844200d10cc4c/multidict-6.6.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b8eb3025f17b0a4c3cd08cda49acf312a19ad6e8a4edd9dbd591e6506d999402", size = 256100, upload-time = "2025-08-11T12:07:04.564Z" }, + { url = "https://files.pythonhosted.org/packages/09/54/655be13ae324212bf0bc15d665a4e34844f34c206f78801be42f7a0a8aaa/multidict-6.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bbc14f0365534d35a06970d6a83478b249752e922d662dc24d489af1aa0d1be7", size = 253584, upload-time = "2025-08-11T12:07:05.914Z" }, + { url = "https://files.pythonhosted.org/packages/5c/74/ab2039ecc05264b5cec73eb018ce417af3ebb384ae9c0e9ed42cb33f8151/multidict-6.6.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:75aa52fba2d96bf972e85451b99d8e19cc37ce26fd016f6d4aa60da9ab2b005f", size = 251018, upload-time = "2025-08-11T12:07:08.301Z" }, + { url = "https://files.pythonhosted.org/packages/af/0a/ccbb244ac848e56c6427f2392741c06302bbfba49c0042f1eb3c5b606497/multidict-6.6.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fefd4a815e362d4f011919d97d7b4a1e566f1dde83dc4ad8cfb5b41de1df68d", size = 251477, upload-time = "2025-08-11T12:07:10.248Z" }, + { url = "https://files.pythonhosted.org/packages/0e/b0/0ed49bba775b135937f52fe13922bc64a7eaf0a3ead84a36e8e4e446e096/multidict-6.6.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:db9801fe021f59a5b375ab778973127ca0ac52429a26e2fd86aa9508f4d26eb7", size = 263575, upload-time = "2025-08-11T12:07:11.928Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d9/7fb85a85e14de2e44dfb6a24f03c41e2af8697a6df83daddb0e9b7569f73/multidict-6.6.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a650629970fa21ac1fb06ba25dabfc5b8a2054fcbf6ae97c758aa956b8dba802", size = 259649, upload-time = "2025-08-11T12:07:13.244Z" }, + { url = "https://files.pythonhosted.org/packages/03/9e/b3a459bcf9b6e74fa461a5222a10ff9b544cb1cd52fd482fb1b75ecda2a2/multidict-6.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:452ff5da78d4720d7516a3a2abd804957532dd69296cb77319c193e3ffb87e24", size = 251505, upload-time = "2025-08-11T12:07:14.57Z" }, + { url = "https://files.pythonhosted.org/packages/86/a2/8022f78f041dfe6d71e364001a5cf987c30edfc83c8a5fb7a3f0974cff39/multidict-6.6.4-cp312-cp312-win32.whl", hash = "sha256:8c2fcb12136530ed19572bbba61b407f655e3953ba669b96a35036a11a485793", size = 41888, upload-time = "2025-08-11T12:07:15.904Z" }, + { url = "https://files.pythonhosted.org/packages/c7/eb/d88b1780d43a56db2cba24289fa744a9d216c1a8546a0dc3956563fd53ea/multidict-6.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:047d9425860a8c9544fed1b9584f0c8bcd31bcde9568b047c5e567a1025ecd6e", size = 46072, upload-time = "2025-08-11T12:07:17.045Z" }, + { url = "https://files.pythonhosted.org/packages/9f/16/b929320bf5750e2d9d4931835a4c638a19d2494a5b519caaaa7492ebe105/multidict-6.6.4-cp312-cp312-win_arm64.whl", hash = "sha256:14754eb72feaa1e8ae528468f24250dd997b8e2188c3d2f593f9eba259e4b364", size = 43222, upload-time = "2025-08-11T12:07:18.328Z" }, + { url = "https://files.pythonhosted.org/packages/3a/5d/e1db626f64f60008320aab00fbe4f23fc3300d75892a3381275b3d284580/multidict-6.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f46a6e8597f9bd71b31cc708195d42b634c8527fecbcf93febf1052cacc1f16e", size = 75848, upload-time = "2025-08-11T12:07:19.912Z" }, + { url = "https://files.pythonhosted.org/packages/4c/aa/8b6f548d839b6c13887253af4e29c939af22a18591bfb5d0ee6f1931dae8/multidict-6.6.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:22e38b2bc176c5eb9c0a0e379f9d188ae4cd8b28c0f53b52bce7ab0a9e534657", size = 45060, upload-time = "2025-08-11T12:07:21.163Z" }, + { url = "https://files.pythonhosted.org/packages/eb/c6/f5e97e5d99a729bc2aa58eb3ebfa9f1e56a9b517cc38c60537c81834a73f/multidict-6.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5df8afd26f162da59e218ac0eefaa01b01b2e6cd606cffa46608f699539246da", size = 43269, upload-time = "2025-08-11T12:07:22.392Z" }, + { url = "https://files.pythonhosted.org/packages/dc/31/d54eb0c62516776f36fe67f84a732f97e0b0e12f98d5685bebcc6d396910/multidict-6.6.4-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:49517449b58d043023720aa58e62b2f74ce9b28f740a0b5d33971149553d72aa", size = 237158, upload-time = "2025-08-11T12:07:23.636Z" }, + { url = "https://files.pythonhosted.org/packages/c4/1c/8a10c1c25b23156e63b12165a929d8eb49a6ed769fdbefb06e6f07c1e50d/multidict-6.6.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ae9408439537c5afdca05edd128a63f56a62680f4b3c234301055d7a2000220f", size = 257076, upload-time = "2025-08-11T12:07:25.049Z" }, + { url = "https://files.pythonhosted.org/packages/ad/86/90e20b5771d6805a119e483fd3d1e8393e745a11511aebca41f0da38c3e2/multidict-6.6.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87a32d20759dc52a9e850fe1061b6e41ab28e2998d44168a8a341b99ded1dba0", size = 240694, upload-time = "2025-08-11T12:07:26.458Z" }, + { url = "https://files.pythonhosted.org/packages/e7/49/484d3e6b535bc0555b52a0a26ba86e4d8d03fd5587d4936dc59ba7583221/multidict-6.6.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:52e3c8d43cdfff587ceedce9deb25e6ae77daba560b626e97a56ddcad3756879", size = 266350, upload-time = "2025-08-11T12:07:27.94Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b4/aa4c5c379b11895083d50021e229e90c408d7d875471cb3abf721e4670d6/multidict-6.6.4-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ad8850921d3a8d8ff6fbef790e773cecfc260bbfa0566998980d3fa8f520bc4a", size = 267250, upload-time = "2025-08-11T12:07:29.303Z" }, + { url = "https://files.pythonhosted.org/packages/80/e5/5e22c5bf96a64bdd43518b1834c6d95a4922cc2066b7d8e467dae9b6cee6/multidict-6.6.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:497a2954adc25c08daff36f795077f63ad33e13f19bfff7736e72c785391534f", size = 254900, upload-time = "2025-08-11T12:07:30.764Z" }, + { url = "https://files.pythonhosted.org/packages/17/38/58b27fed927c07035abc02befacab42491e7388ca105e087e6e0215ead64/multidict-6.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:024ce601f92d780ca1617ad4be5ac15b501cc2414970ffa2bb2bbc2bd5a68fa5", size = 252355, upload-time = "2025-08-11T12:07:32.205Z" }, + { url = "https://files.pythonhosted.org/packages/d0/a1/dad75d23a90c29c02b5d6f3d7c10ab36c3197613be5d07ec49c7791e186c/multidict-6.6.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a693fc5ed9bdd1c9e898013e0da4dcc640de7963a371c0bd458e50e046bf6438", size = 250061, upload-time = "2025-08-11T12:07:33.623Z" }, + { url = "https://files.pythonhosted.org/packages/b8/1a/ac2216b61c7f116edab6dc3378cca6c70dc019c9a457ff0d754067c58b20/multidict-6.6.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:190766dac95aab54cae5b152a56520fd99298f32a1266d66d27fdd1b5ac00f4e", size = 249675, upload-time = "2025-08-11T12:07:34.958Z" }, + { url = "https://files.pythonhosted.org/packages/d4/79/1916af833b800d13883e452e8e0977c065c4ee3ab7a26941fbfdebc11895/multidict-6.6.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:34d8f2a5ffdceab9dcd97c7a016deb2308531d5f0fced2bb0c9e1df45b3363d7", size = 261247, upload-time = "2025-08-11T12:07:36.588Z" }, + { url = "https://files.pythonhosted.org/packages/c5/65/d1f84fe08ac44a5fc7391cbc20a7cedc433ea616b266284413fd86062f8c/multidict-6.6.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:59e8d40ab1f5a8597abcef00d04845155a5693b5da00d2c93dbe88f2050f2812", size = 257960, upload-time = "2025-08-11T12:07:39.735Z" }, + { url = "https://files.pythonhosted.org/packages/13/b5/29ec78057d377b195ac2c5248c773703a6b602e132a763e20ec0457e7440/multidict-6.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:467fe64138cfac771f0e949b938c2e1ada2b5af22f39692aa9258715e9ea613a", size = 250078, upload-time = "2025-08-11T12:07:41.525Z" }, + { url = "https://files.pythonhosted.org/packages/c4/0e/7e79d38f70a872cae32e29b0d77024bef7834b0afb406ddae6558d9e2414/multidict-6.6.4-cp313-cp313-win32.whl", hash = "sha256:14616a30fe6d0a48d0a48d1a633ab3b8bec4cf293aac65f32ed116f620adfd69", size = 41708, upload-time = "2025-08-11T12:07:43.405Z" }, + { url = "https://files.pythonhosted.org/packages/9d/34/746696dffff742e97cd6a23da953e55d0ea51fa601fa2ff387b3edcfaa2c/multidict-6.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:40cd05eaeb39e2bc8939451f033e57feaa2ac99e07dbca8afe2be450a4a3b6cf", size = 45912, upload-time = "2025-08-11T12:07:45.082Z" }, + { url = "https://files.pythonhosted.org/packages/c7/87/3bac136181e271e29170d8d71929cdeddeb77f3e8b6a0c08da3a8e9da114/multidict-6.6.4-cp313-cp313-win_arm64.whl", hash = "sha256:f6eb37d511bfae9e13e82cb4d1af36b91150466f24d9b2b8a9785816deb16605", size = 43076, upload-time = "2025-08-11T12:07:46.746Z" }, + { url = "https://files.pythonhosted.org/packages/64/94/0a8e63e36c049b571c9ae41ee301ada29c3fee9643d9c2548d7d558a1d99/multidict-6.6.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6c84378acd4f37d1b507dfa0d459b449e2321b3ba5f2338f9b085cf7a7ba95eb", size = 82812, upload-time = "2025-08-11T12:07:48.402Z" }, + { url = "https://files.pythonhosted.org/packages/25/1a/be8e369dfcd260d2070a67e65dd3990dd635cbd735b98da31e00ea84cd4e/multidict-6.6.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0e0558693063c75f3d952abf645c78f3c5dfdd825a41d8c4d8156fc0b0da6e7e", size = 48313, upload-time = "2025-08-11T12:07:49.679Z" }, + { url = "https://files.pythonhosted.org/packages/26/5a/dd4ade298674b2f9a7b06a32c94ffbc0497354df8285f27317c66433ce3b/multidict-6.6.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3f8e2384cb83ebd23fd07e9eada8ba64afc4c759cd94817433ab8c81ee4b403f", size = 46777, upload-time = "2025-08-11T12:07:51.318Z" }, + { url = "https://files.pythonhosted.org/packages/89/db/98aa28bc7e071bfba611ac2ae803c24e96dd3a452b4118c587d3d872c64c/multidict-6.6.4-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:f996b87b420995a9174b2a7c1a8daf7db4750be6848b03eb5e639674f7963773", size = 229321, upload-time = "2025-08-11T12:07:52.965Z" }, + { url = "https://files.pythonhosted.org/packages/c7/bc/01ddda2a73dd9d167bd85d0e8ef4293836a8f82b786c63fb1a429bc3e678/multidict-6.6.4-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc356250cffd6e78416cf5b40dc6a74f1edf3be8e834cf8862d9ed5265cf9b0e", size = 249954, upload-time = "2025-08-11T12:07:54.423Z" }, + { url = "https://files.pythonhosted.org/packages/06/78/6b7c0f020f9aa0acf66d0ab4eb9f08375bac9a50ff5e3edb1c4ccd59eafc/multidict-6.6.4-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:dadf95aa862714ea468a49ad1e09fe00fcc9ec67d122f6596a8d40caf6cec7d0", size = 228612, upload-time = "2025-08-11T12:07:55.914Z" }, + { url = "https://files.pythonhosted.org/packages/00/44/3faa416f89b2d5d76e9d447296a81521e1c832ad6e40b92f990697b43192/multidict-6.6.4-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dd57515bebffd8ebd714d101d4c434063322e4fe24042e90ced41f18b6d3395", size = 257528, upload-time = "2025-08-11T12:07:57.371Z" }, + { url = "https://files.pythonhosted.org/packages/05/5f/77c03b89af0fcb16f018f668207768191fb9dcfb5e3361a5e706a11db2c9/multidict-6.6.4-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:967af5f238ebc2eb1da4e77af5492219fbd9b4b812347da39a7b5f5c72c0fa45", size = 256329, upload-time = "2025-08-11T12:07:58.844Z" }, + { url = "https://files.pythonhosted.org/packages/cf/e9/ed750a2a9afb4f8dc6f13dc5b67b514832101b95714f1211cd42e0aafc26/multidict-6.6.4-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2a4c6875c37aae9794308ec43e3530e4aa0d36579ce38d89979bbf89582002bb", size = 247928, upload-time = "2025-08-11T12:08:01.037Z" }, + { url = "https://files.pythonhosted.org/packages/1f/b5/e0571bc13cda277db7e6e8a532791d4403dacc9850006cb66d2556e649c0/multidict-6.6.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:7f683a551e92bdb7fac545b9c6f9fa2aebdeefa61d607510b3533286fcab67f5", size = 245228, upload-time = "2025-08-11T12:08:02.96Z" }, + { url = "https://files.pythonhosted.org/packages/f3/a3/69a84b0eccb9824491f06368f5b86e72e4af54c3067c37c39099b6687109/multidict-6.6.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:3ba5aaf600edaf2a868a391779f7a85d93bed147854925f34edd24cc70a3e141", size = 235869, upload-time = "2025-08-11T12:08:04.746Z" }, + { url = "https://files.pythonhosted.org/packages/a9/9d/28802e8f9121a6a0804fa009debf4e753d0a59969ea9f70be5f5fdfcb18f/multidict-6.6.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:580b643b7fd2c295d83cad90d78419081f53fd532d1f1eb67ceb7060f61cff0d", size = 243446, upload-time = "2025-08-11T12:08:06.332Z" }, + { url = "https://files.pythonhosted.org/packages/38/ea/6c98add069b4878c1d66428a5f5149ddb6d32b1f9836a826ac764b9940be/multidict-6.6.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:37b7187197da6af3ee0b044dbc9625afd0c885f2800815b228a0e70f9a7f473d", size = 252299, upload-time = "2025-08-11T12:08:07.931Z" }, + { url = "https://files.pythonhosted.org/packages/3a/09/8fe02d204473e14c0af3affd50af9078839dfca1742f025cca765435d6b4/multidict-6.6.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:e1b93790ed0bc26feb72e2f08299691ceb6da5e9e14a0d13cc74f1869af327a0", size = 246926, upload-time = "2025-08-11T12:08:09.467Z" }, + { url = "https://files.pythonhosted.org/packages/37/3d/7b1e10d774a6df5175ecd3c92bff069e77bed9ec2a927fdd4ff5fe182f67/multidict-6.6.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a506a77ddee1efcca81ecbeae27ade3e09cdf21a8ae854d766c2bb4f14053f92", size = 243383, upload-time = "2025-08-11T12:08:10.981Z" }, + { url = "https://files.pythonhosted.org/packages/50/b0/a6fae46071b645ae98786ab738447de1ef53742eaad949f27e960864bb49/multidict-6.6.4-cp313-cp313t-win32.whl", hash = "sha256:f93b2b2279883d1d0a9e1bd01f312d6fc315c5e4c1f09e112e4736e2f650bc4e", size = 47775, upload-time = "2025-08-11T12:08:12.439Z" }, + { url = "https://files.pythonhosted.org/packages/b2/0a/2436550b1520091af0600dff547913cb2d66fbac27a8c33bc1b1bccd8d98/multidict-6.6.4-cp313-cp313t-win_amd64.whl", hash = "sha256:6d46a180acdf6e87cc41dc15d8f5c2986e1e8739dc25dbb7dac826731ef381a4", size = 53100, upload-time = "2025-08-11T12:08:13.823Z" }, + { url = "https://files.pythonhosted.org/packages/97/ea/43ac51faff934086db9c072a94d327d71b7d8b40cd5dcb47311330929ef0/multidict-6.6.4-cp313-cp313t-win_arm64.whl", hash = "sha256:756989334015e3335d087a27331659820d53ba432befdef6a718398b0a8493ad", size = 45501, upload-time = "2025-08-11T12:08:15.173Z" }, + { url = "https://files.pythonhosted.org/packages/fd/69/b547032297c7e63ba2af494edba695d781af8a0c6e89e4d06cf848b21d80/multidict-6.6.4-py3-none-any.whl", hash = "sha256:27d8f8e125c07cb954e54d75d04905a9bba8a439c1d84aca94949d4d03d8601c", size = 12313, upload-time = "2025-08-11T12:08:46.891Z" }, +] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/6e/371856a3fb9d31ca8dac321cda606860fa4548858c0cc45d9d1d4ca2628b/mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558", size = 6343, upload-time = "2025-04-22T14:54:24.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/79/7b/2c79738432f5c924bef5071f933bcc9efd0473bac3b4aa584a6f7c1c8df8/mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505", size = 4963, upload-time = "2025-04-22T14:54:22.983Z" }, +] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, +] + +[[package]] +name = "nexus-rpc" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ef/66/540687556bd28cf1ec370cc6881456203dfddb9dab047b8979c6865b5984/nexus_rpc-1.1.0.tar.gz", hash = "sha256:d65ad6a2f54f14e53ebe39ee30555eaeb894102437125733fb13034a04a44553", size = 77383, upload-time = "2025-07-07T19:03:58.368Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bf/2f/9e9d0dcaa4c6ffa22b7aa31069a8a264c753ff8027b36af602cce038c92f/nexus_rpc-1.1.0-py3-none-any.whl", hash = "sha256:d1b007af2aba186a27e736f8eaae39c03aed05b488084ff6c3d1785c9ba2ad38", size = 27743, upload-time = "2025-07-07T19:03:57.556Z" }, +] + +[[package]] +name = "oauthlib" +version = "3.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/5f/19930f824ffeb0ad4372da4812c50edbd1434f678c90c2733e1188edfc63/oauthlib-3.3.1.tar.gz", hash = "sha256:0f0f8aa759826a193cf66c12ea1af1637f87b9b4622d46e866952bb022e538c9", size = 185918, upload-time = "2025-06-19T22:48:08.269Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/be/9c/92789c596b8df838baa98fa71844d84283302f7604ed565dafe5a6b5041a/oauthlib-3.3.1-py3-none-any.whl", hash = "sha256:88119c938d2b8fb88561af5f6ee0eec8cc8d552b7bb1f712743136eb7523b7a1", size = 160065, upload-time = "2025-06-19T22:48:06.508Z" }, +] + +[[package]] +name = "openai" +version = "1.100.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "jiter" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "tqdm" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/36/e2e24d419438a5e66aa6445ec663194395226293d214bfe615df562b2253/openai-1.100.2.tar.gz", hash = "sha256:787b4c3c8a65895182c58c424f790c25c790cc9a0330e34f73d55b6ee5a00e32", size = 507954, upload-time = "2025-08-19T15:32:47.854Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/db/8d/9ab1599c7942b3d04784ac5473905dc543aeb30a1acce3591d0b425682db/openai-1.100.2-py3-none-any.whl", hash = "sha256:54d3457b2c8d7303a1bc002a058de46bdd8f37a8117751c7cf4ed4438051f151", size = 787755, upload-time = "2025-08-19T15:32:46.252Z" }, +] + +[[package]] +name = "openai-agents" +version = "0.2.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "griffe" }, + { name = "mcp" }, + { name = "openai" }, + { name = "pydantic" }, + { name = "requests" }, + { name = "types-requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1b/4a/9aa3fc776bc631dbfa04459f0b15bca3d1cd570c09aa388ae2e5a04ddf7d/openai_agents-0.2.7.tar.gz", hash = "sha256:b05105a28f2cd1633bc655264d32c7ba300fd3337deb4ac32f054f998bc34852", size = 1493556, upload-time = "2025-08-14T18:58:53.026Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/c4/55507de1d6162c9ea11903d4d6d2d766da79cbed93fbce52c0784ee3f1f0/openai_agents-0.2.7-py3-none-any.whl", hash = "sha256:de8ea493c9d190b37ad05caa33f291740782a443a8a89085ab0d6b30599b44b6", size = 167153, upload-time = "2025-08-14T18:58:51.655Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "parso" +version = "0.8.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/66/94/68e2e17afaa9169cf6412ab0f28623903be73d1b32e208d9e8e541bb086d/parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d", size = 400609, upload-time = "2024-04-05T09:43:55.897Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/ac/dac4a63f978e4dcb3c6d3a78c4d8e0192a113d288502a1216950c41b1027/parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", size = 103650, upload-time = "2024-04-05T09:43:53.299Z" }, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ca/bc/f35b8446f4531a7cb215605d100cd88b7ac6f44ab3fc94870c120ab3adbf/pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712", size = 51043, upload-time = "2023-12-10T22:30:45Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/ff623b09d963f88bfde16306a54e12ee5ea43e9b597108672ff3a408aad6/pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08", size = 31191, upload-time = "2023-12-10T22:30:43.14Z" }, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "ptyprocess" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/92/cc564bf6381ff43ce1f4d06852fc19a2f11d180f23dc32d9588bee2f149d/pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f", size = 166450, upload-time = "2023-11-25T09:07:26.339Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9e/c3/059298687310d527a58bb01f3b1965787ee3b40dce76752eda8b44e9a2c5/pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", size = 63772, upload-time = "2023-11-25T06:56:14.81Z" }, +] + +[[package]] +name = "platformdirs" +version = "4.3.8" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/8b/3c73abc9c759ecd3f1f7ceff6685840859e8070c4d947c93fae71f6a0bf2/platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc", size = 21362, upload-time = "2025-05-07T22:47:42.121Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/39/979e8e21520d4e47a0bbe349e2713c0aac6f3d853d0e5b34d76206c439aa/platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4", size = 18567, upload-time = "2025-05-07T22:47:40.376Z" }, +] + +[[package]] +name = "pluggy" +version = "1.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" }, +] + +[[package]] +name = "prompt-toolkit" +version = "3.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wcwidth" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bb/6e/9d084c929dfe9e3bfe0c6a47e31f78a25c54627d64a66e884a8bf5474f1c/prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed", size = 428940, upload-time = "2025-04-15T09:18:47.731Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/4f/5249960887b1fbe561d9ff265496d170b55a735b76724f10ef19f9e40716/prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07", size = 387810, upload-time = "2025-04-15T09:18:44.753Z" }, +] + +[[package]] +name = "propcache" +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, + { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, + { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, + { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, + { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, + { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, + { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, + { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, + { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, + { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, + { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, + { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, + { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, + { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, + { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, + { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, + { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, + { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, + { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, + { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, + { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, + { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, + { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, + { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, + { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, + { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, + { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, + { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, + { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, + { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, + { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, + { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, + { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, + { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, + { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, + { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, + { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, + { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, + { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, + { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, +] + +[[package]] +name = "protobuf" +version = "5.29.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/43/29/d09e70352e4e88c9c7a198d5645d7277811448d76c23b00345670f7c8a38/protobuf-5.29.5.tar.gz", hash = "sha256:bc1463bafd4b0929216c35f437a8e28731a2b7fe3d98bb77a600efced5a15c84", size = 425226, upload-time = "2025-05-28T23:51:59.82Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/11/6e40e9fc5bba02988a214c07cf324595789ca7820160bfd1f8be96e48539/protobuf-5.29.5-cp310-abi3-win32.whl", hash = "sha256:3f1c6468a2cfd102ff4703976138844f78ebd1fb45f49011afc5139e9e283079", size = 422963, upload-time = "2025-05-28T23:51:41.204Z" }, + { url = "https://files.pythonhosted.org/packages/81/7f/73cefb093e1a2a7c3ffd839e6f9fcafb7a427d300c7f8aef9c64405d8ac6/protobuf-5.29.5-cp310-abi3-win_amd64.whl", hash = "sha256:3f76e3a3675b4a4d867b52e4a5f5b78a2ef9565549d4037e06cf7b0942b1d3fc", size = 434818, upload-time = "2025-05-28T23:51:44.297Z" }, + { url = "https://files.pythonhosted.org/packages/dd/73/10e1661c21f139f2c6ad9b23040ff36fee624310dc28fba20d33fdae124c/protobuf-5.29.5-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e38c5add5a311f2a6eb0340716ef9b039c1dfa428b28f25a7838ac329204a671", size = 418091, upload-time = "2025-05-28T23:51:45.907Z" }, + { url = "https://files.pythonhosted.org/packages/6c/04/98f6f8cf5b07ab1294c13f34b4e69b3722bb609c5b701d6c169828f9f8aa/protobuf-5.29.5-cp38-abi3-manylinux2014_aarch64.whl", hash = "sha256:fa18533a299d7ab6c55a238bf8629311439995f2e7eca5caaff08663606e9015", size = 319824, upload-time = "2025-05-28T23:51:47.545Z" }, + { url = "https://files.pythonhosted.org/packages/85/e4/07c80521879c2d15f321465ac24c70efe2381378c00bf5e56a0f4fbac8cd/protobuf-5.29.5-cp38-abi3-manylinux2014_x86_64.whl", hash = "sha256:63848923da3325e1bf7e9003d680ce6e14b07e55d0473253a690c3a8b8fd6e61", size = 319942, upload-time = "2025-05-28T23:51:49.11Z" }, + { url = "https://files.pythonhosted.org/packages/7e/cc/7e77861000a0691aeea8f4566e5d3aa716f2b1dece4a24439437e41d3d25/protobuf-5.29.5-py3-none-any.whl", hash = "sha256:6cf42630262c59b2d8de33954443d94b746c952b01434fc58a417fdbd2e84bd5", size = 172823, upload-time = "2025-05-28T23:51:58.157Z" }, +] + +[[package]] +name = "psutil" +version = "7.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2a/80/336820c1ad9286a4ded7e845b2eccfcb27851ab8ac6abece774a6ff4d3de/psutil-7.0.0.tar.gz", hash = "sha256:7be9c3eba38beccb6495ea33afd982a44074b78f28c434a1f51cc07fd315c456", size = 497003, upload-time = "2025-02-13T21:54:07.946Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/e6/2d26234410f8b8abdbf891c9da62bee396583f713fb9f3325a4760875d22/psutil-7.0.0-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:101d71dc322e3cffd7cea0650b09b3d08b8e7c4109dd6809fe452dfd00e58b25", size = 238051, upload-time = "2025-02-13T21:54:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/04/8b/30f930733afe425e3cbfc0e1468a30a18942350c1a8816acfade80c005c4/psutil-7.0.0-cp36-abi3-macosx_11_0_arm64.whl", hash = "sha256:39db632f6bb862eeccf56660871433e111b6ea58f2caea825571951d4b6aa3da", size = 239535, upload-time = "2025-02-13T21:54:16.07Z" }, + { url = "https://files.pythonhosted.org/packages/2a/ed/d362e84620dd22876b55389248e522338ed1bf134a5edd3b8231d7207f6d/psutil-7.0.0-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1fcee592b4c6f146991ca55919ea3d1f8926497a713ed7faaf8225e174581e91", size = 275004, upload-time = "2025-02-13T21:54:18.662Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b9/b0eb3f3cbcb734d930fdf839431606844a825b23eaf9a6ab371edac8162c/psutil-7.0.0-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b1388a4f6875d7e2aff5c4ca1cc16c545ed41dd8bb596cefea80111db353a34", size = 277986, upload-time = "2025-02-13T21:54:21.811Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a2/709e0fe2f093556c17fbafda93ac032257242cabcc7ff3369e2cb76a97aa/psutil-7.0.0-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5f098451abc2828f7dc6b58d44b532b22f2088f4999a937557b603ce72b1993", size = 279544, upload-time = "2025-02-13T21:54:24.68Z" }, + { url = "https://files.pythonhosted.org/packages/50/e6/eecf58810b9d12e6427369784efe814a1eec0f492084ce8eb8f4d89d6d61/psutil-7.0.0-cp37-abi3-win32.whl", hash = "sha256:ba3fcef7523064a6c9da440fc4d6bd07da93ac726b5733c29027d7dc95b39d99", size = 241053, upload-time = "2025-02-13T21:54:34.31Z" }, + { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, +] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/e5/16ff212c1e452235a90aeb09066144d0c5a6a8c0834397e03f5224495c4e/ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220", size = 70762, upload-time = "2020-12-28T15:15:30.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/22/a6/858897256d0deac81a172289110f31629fc4cee19b6f01283303e18c8db3/ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", size = 13993, upload-time = "2020-12-28T15:15:28.35Z" }, +] + +[[package]] +name = "pure-eval" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cd/05/0a34433a064256a578f1783a10da6df098ceaa4a57bbeaa96a6c0352786b/pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42", size = 19752, upload-time = "2024-07-21T12:58:21.801Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8e/37/efad0257dc6e593a18957422533ff0f87ede7c9c6ea010a2177d738fb82f/pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", size = 11842, upload-time = "2024-07-21T12:58:20.04Z" }, +] + +[[package]] +name = "pyasn1" +version = "0.6.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ba/e9/01f1a64245b89f039897cb0130016d79f77d52669aae6ee7b159a6c4c018/pyasn1-0.6.1.tar.gz", hash = "sha256:6f580d2bdd84365380830acf45550f2511469f673cb4a5ae3857a3170128b034", size = 145322, upload-time = "2024-09-10T22:41:42.55Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c8/f1/d6a797abb14f6283c0ddff96bbdd46937f64122b8c925cab503dd37f8214/pyasn1-0.6.1-py3-none-any.whl", hash = "sha256:0d632f46f2ba09143da3a8afe9e33fb6f92fa2320ab7e886e2d0f7672af84629", size = 83135, upload-time = "2024-09-11T16:00:36.122Z" }, +] + +[[package]] +name = "pyasn1-modules" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e9/e6/78ebbb10a8c8e4b61a59249394a4a594c1a7af95593dc933a349c8d00964/pyasn1_modules-0.4.2.tar.gz", hash = "sha256:677091de870a80aae844b1ca6134f54652fa2c8c5a52aa396440ac3106e941e6", size = 307892, upload-time = "2025-03-28T02:41:22.17Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/47/8d/d529b5d697919ba8c11ad626e835d4039be708a35b0d22de83a269a6682c/pyasn1_modules-0.4.2-py3-none-any.whl", hash = "sha256:29253a9207ce32b64c3ac6600edc75368f98473906e8fd1043bd6b5b1de2c14a", size = 181259, upload-time = "2025-03-28T02:41:19.028Z" }, +] + +[[package]] +name = "pycodestyle" +version = "2.14.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/11/e0/abfd2a0d2efe47670df87f3e3a0e2edda42f055053c85361f19c0e2c1ca8/pycodestyle-2.14.0.tar.gz", hash = "sha256:c4b5b517d278089ff9d0abdec919cd97262a3367449ea1c8b49b91529167b783", size = 39472, upload-time = "2025-06-20T18:49:48.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d7/27/a58ddaf8c588a3ef080db9d0b7e0b97215cee3a45df74f3a94dbbf5c893a/pycodestyle-2.14.0-py2.py3-none-any.whl", hash = "sha256:dd6bf7cb4ee77f8e016f9c8e74a35ddd9f67e1d5fd4184d86c3b98e07099f42d", size = 31594, upload-time = "2025-06-20T18:49:47.491Z" }, +] + +[[package]] +name = "pycparser" +version = "2.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, +] + +[[package]] +name = "pydantic" +version = "2.11.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, +] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, + { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, + { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, + { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, + { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, + { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, + { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, + { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, + { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, + { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, + { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, + { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, + { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, + { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, + { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, + { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, + { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, + { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, + { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, + { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, + { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, + { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, + { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, + { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, + { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, + { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, + { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, + { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, +] + +[[package]] +name = "pydantic-settings" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "python-dotenv" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, +] + +[[package]] +name = "pyflakes" +version = "3.4.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/45/dc/fd034dc20b4b264b3d015808458391acbf9df40b1e54750ef175d39180b1/pyflakes-3.4.0.tar.gz", hash = "sha256:b24f96fafb7d2ab0ec5075b7350b3d2d2218eab42003821c06344973d3ea2f58", size = 64669, upload-time = "2025-06-20T18:45:27.834Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/2f/81d580a0fb83baeb066698975cb14a618bdbed7720678566f1b046a95fe8/pyflakes-3.4.0-py2.py3-none-any.whl", hash = "sha256:f742a7dbd0d9cb9ea41e9a24a918996e8170c799fa528688d40dd582c8265f4f", size = 63551, upload-time = "2025-06-20T18:45:26.937Z" }, +] + +[[package]] +name = "pygments" +version = "2.19.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, +] + +[[package]] +name = "pyjwt" +version = "2.10.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, +] + +[[package]] +name = "pytest" +version = "8.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/ba/45911d754e8eba3d5a841a5ce61a65a685ff1798421ac054f85aa8747dfb/pytest-8.4.1.tar.gz", hash = "sha256:7c67fd69174877359ed9371ec3af8a3d2b04741818c51e5e99cc1742251fa93c", size = 1517714, upload-time = "2025-06-18T05:48:06.109Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/29/16/c8a903f4c4dffe7a12843191437d7cd8e32751d5de349d45d3fe69544e87/pytest-8.4.1-py3-none-any.whl", hash = "sha256:539c70ba6fcead8e78eebbf1115e8b589e7565830d7d006a8723f19ac8a0afb7", size = 365474, upload-time = "2025-06-18T05:48:03.955Z" }, +] + +[[package]] +name = "pytest-asyncio" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytest" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4e/51/f8794af39eeb870e87a8c8068642fc07bce0c854d6865d7dd0f2a9d338c2/pytest_asyncio-1.1.0.tar.gz", hash = "sha256:796aa822981e01b68c12e4827b8697108f7205020f24b5793b3c41555dab68ea", size = 46652, upload-time = "2025-07-16T04:29:26.393Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/9d/bf86eddabf8c6c9cb1ea9a869d6873b46f105a5d292d3a6f7071f5b07935/pytest_asyncio-1.1.0-py3-none-any.whl", hash = "sha256:5fe2d69607b0bd75c656d1211f969cadba035030156745ee09e7d71740e58ecf", size = 15157, upload-time = "2025-07-16T04:29:24.929Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "python-dotenv" +version = "1.1.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, +] + +[[package]] +name = "python-on-whales" +version = "0.73.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pydantic" }, + { name = "requests" }, + { name = "tqdm" }, + { name = "typer" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/40/c3/f57dd3e7d20af8a0399bb87471eac4698e0686b04073eef4bc291204a709/python_on_whales-0.73.0.tar.gz", hash = "sha256:c76bf3633550e5c948fb4215918364f45efaddb2e09df5ddd169132f7ffdc249", size = 112019, upload-time = "2024-09-06T10:23:12.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d4/e9/ea125eb8954f64e76485aec5c63ca6a5b977e0127a5f3896993f1692166e/python_on_whales-0.73.0-py3-none-any.whl", hash = "sha256:66f31749c2544a0aacb4e3ba03772c2e9227235ea1aecd58aa7a4cdcf26f559a", size = 118125, upload-time = "2024-09-06T10:23:10.856Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, + { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, + { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, + { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, +] + +[[package]] +name = "pyyaml" +version = "6.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, + { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, + { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, + { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, + { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, + { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, + { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, + { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, + { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, + { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, + { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, + { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, + { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, + { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, + { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, +] + +[[package]] +name = "pyzmq" +version = "27.0.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "implementation_name == 'pypy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/30/5f/557d2032a2f471edbcc227da724c24a1c05887b5cda1e3ae53af98b9e0a5/pyzmq-27.0.1.tar.gz", hash = "sha256:45c549204bc20e7484ffd2555f6cf02e572440ecf2f3bdd60d4404b20fddf64b", size = 281158, upload-time = "2025-08-03T05:05:40.352Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/9b/c0957041067c7724b310f22c398be46399297c12ed834c3bc42200a2756f/pyzmq-27.0.1-cp312-abi3-macosx_10_15_universal2.whl", hash = "sha256:af7ebce2a1e7caf30c0bb64a845f63a69e76a2fadbc1cac47178f7bb6e657bdd", size = 1305432, upload-time = "2025-08-03T05:03:32.177Z" }, + { url = "https://files.pythonhosted.org/packages/8e/55/bd3a312790858f16b7def3897a0c3eb1804e974711bf7b9dcb5f47e7f82c/pyzmq-27.0.1-cp312-abi3-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:8f617f60a8b609a13099b313e7e525e67f84ef4524b6acad396d9ff153f6e4cd", size = 895095, upload-time = "2025-08-03T05:03:33.918Z" }, + { url = "https://files.pythonhosted.org/packages/20/50/fc384631d8282809fb1029a4460d2fe90fa0370a0e866a8318ed75c8d3bb/pyzmq-27.0.1-cp312-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1d59dad4173dc2a111f03e59315c7bd6e73da1a9d20a84a25cf08325b0582b1a", size = 651826, upload-time = "2025-08-03T05:03:35.818Z" }, + { url = "https://files.pythonhosted.org/packages/7e/0a/2356305c423a975000867de56888b79e44ec2192c690ff93c3109fd78081/pyzmq-27.0.1-cp312-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f5b6133c8d313bde8bd0d123c169d22525300ff164c2189f849de495e1344577", size = 839751, upload-time = "2025-08-03T05:03:37.265Z" }, + { url = "https://files.pythonhosted.org/packages/d7/1b/81e95ad256ca7e7ccd47f5294c1c6da6e2b64fbace65b84fe8a41470342e/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:58cca552567423f04d06a075f4b473e78ab5bdb906febe56bf4797633f54aa4e", size = 1641359, upload-time = "2025-08-03T05:03:38.799Z" }, + { url = "https://files.pythonhosted.org/packages/50/63/9f50ec965285f4e92c265c8f18344e46b12803666d8b73b65d254d441435/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_i686.whl", hash = "sha256:4b9d8e26fb600d0d69cc9933e20af08552e97cc868a183d38a5c0d661e40dfbb", size = 2020281, upload-time = "2025-08-03T05:03:40.338Z" }, + { url = "https://files.pythonhosted.org/packages/02/4a/19e3398d0dc66ad2b463e4afa1fc541d697d7bc090305f9dfb948d3dfa29/pyzmq-27.0.1-cp312-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:2329f0c87f0466dce45bba32b63f47018dda5ca40a0085cc5c8558fea7d9fc55", size = 1877112, upload-time = "2025-08-03T05:03:42.012Z" }, + { url = "https://files.pythonhosted.org/packages/bf/42/c562e9151aa90ed1d70aac381ea22a929d6b3a2ce4e1d6e2e135d34fd9c6/pyzmq-27.0.1-cp312-abi3-win32.whl", hash = "sha256:57bb92abdb48467b89c2d21da1ab01a07d0745e536d62afd2e30d5acbd0092eb", size = 558177, upload-time = "2025-08-03T05:03:43.979Z" }, + { url = "https://files.pythonhosted.org/packages/40/96/5c50a7d2d2b05b19994bf7336b97db254299353dd9b49b565bb71b485f03/pyzmq-27.0.1-cp312-abi3-win_amd64.whl", hash = "sha256:ff3f8757570e45da7a5bedaa140489846510014f7a9d5ee9301c61f3f1b8a686", size = 618923, upload-time = "2025-08-03T05:03:45.438Z" }, + { url = "https://files.pythonhosted.org/packages/13/33/1ec89c8f21c89d21a2eaff7def3676e21d8248d2675705e72554fb5a6f3f/pyzmq-27.0.1-cp312-abi3-win_arm64.whl", hash = "sha256:df2c55c958d3766bdb3e9d858b911288acec09a9aab15883f384fc7180df5bed", size = 552358, upload-time = "2025-08-03T05:03:46.887Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a0/f26e276211ec8090a4d11e4ec70eb8a8b15781e591c1d44ce62f372963a0/pyzmq-27.0.1-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:497bd8af534ae55dc4ef67eebd1c149ff2a0b0f1e146db73c8b5a53d83c1a5f5", size = 1122287, upload-time = "2025-08-03T05:03:48.838Z" }, + { url = "https://files.pythonhosted.org/packages/9c/d8/af4b507e4f7eeea478cc8ee873995a6fd55582bfb99140593ed460e1db3c/pyzmq-27.0.1-cp313-cp313-android_24_x86_64.whl", hash = "sha256:a066ea6ad6218b4c233906adf0ae67830f451ed238419c0db609310dd781fbe7", size = 1155756, upload-time = "2025-08-03T05:03:50.907Z" }, + { url = "https://files.pythonhosted.org/packages/ac/55/37fae0013e11f88681da42698e550b08a316d608242551f65095cc99232a/pyzmq-27.0.1-cp313-cp313t-macosx_10_15_universal2.whl", hash = "sha256:72d235d6365ca73d8ce92f7425065d70f5c1e19baa458eb3f0d570e425b73a96", size = 1340826, upload-time = "2025-08-03T05:03:52.568Z" }, + { url = "https://files.pythonhosted.org/packages/f2/e4/3a87854c64b26fcf63a9d1b6f4382bd727d4797c772ceb334a97b7489be9/pyzmq-27.0.1-cp313-cp313t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:313a7b374e3dc64848644ca348a51004b41726f768b02e17e689f1322366a4d9", size = 897283, upload-time = "2025-08-03T05:03:54.167Z" }, + { url = "https://files.pythonhosted.org/packages/17/3e/4296c6b0ad2d07be11ae1395dccf9cae48a0a655cf9be1c3733ad2b591d1/pyzmq-27.0.1-cp313-cp313t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:119ce8590409702394f959c159d048002cbed2f3c0645ec9d6a88087fc70f0f1", size = 660565, upload-time = "2025-08-03T05:03:56.152Z" }, + { url = "https://files.pythonhosted.org/packages/72/41/a33ba3aa48b45b23c4cd4ac49aafde46f3e0f81939f2bfb3b6171a437122/pyzmq-27.0.1-cp313-cp313t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:45c3e00ce16896ace2cd770ab9057a7cf97d4613ea5f2a13f815141d8b6894b9", size = 847680, upload-time = "2025-08-03T05:03:57.696Z" }, + { url = "https://files.pythonhosted.org/packages/3f/8c/bf2350bb25b3b58d2e5b5d2290ffab0e923f0cc6d02288d3fbf4baa6e4d1/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:678e50ec112bdc6df5a83ac259a55a4ba97a8b314c325ab26b3b5b071151bc61", size = 1650151, upload-time = "2025-08-03T05:03:59.387Z" }, + { url = "https://files.pythonhosted.org/packages/f7/1a/a5a07c54890891344a8ddc3d5ab320dd3c4e39febb6e4472546e456d5157/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d0b96c30be9f9387b18b18b6133c75a7b1b0065da64e150fe1feb5ebf31ece1c", size = 2023766, upload-time = "2025-08-03T05:04:01.883Z" }, + { url = "https://files.pythonhosted.org/packages/62/5e/514dcff08f02c6c8a45a6e23621901139cf853be7ac5ccd0b9407c3aa3de/pyzmq-27.0.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88dc92d9eb5ea4968123e74db146d770b0c8d48f0e2bfb1dbc6c50a8edb12d64", size = 1885195, upload-time = "2025-08-03T05:04:03.923Z" }, + { url = "https://files.pythonhosted.org/packages/c8/91/87f74f98a487fbef0b115f6025e4a295129fd56b2b633a03ba7d5816ecc2/pyzmq-27.0.1-cp313-cp313t-win32.whl", hash = "sha256:6dcbcb34f5c9b0cefdfc71ff745459241b7d3cda5b27c7ad69d45afc0821d1e1", size = 574213, upload-time = "2025-08-03T05:04:05.905Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d7/07f7d0d7f4c81e08be7b60e52ff2591c557377c017f96204d33d5fca1b07/pyzmq-27.0.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9fd0fda730461f510cfd9a40fafa5355d65f5e3dbdd8d6dfa342b5b3f5d1949", size = 640202, upload-time = "2025-08-03T05:04:07.439Z" }, + { url = "https://files.pythonhosted.org/packages/ab/83/21d66bcef6fb803647a223cbde95111b099e2176277c0cbc8b099c485510/pyzmq-27.0.1-cp313-cp313t-win_arm64.whl", hash = "sha256:56a3b1853f3954ec1f0e91085f1350cc57d18f11205e4ab6e83e4b7c414120e0", size = 561514, upload-time = "2025-08-03T05:04:09.071Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0b/d5ea75cf46b52cdce85a85200c963cb498932953df443892238be49b1a01/pyzmq-27.0.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:f98f6b7787bd2beb1f0dde03f23a0621a0c978edf673b7d8f5e7bc039cbe1b60", size = 1340836, upload-time = "2025-08-03T05:04:10.774Z" }, + { url = "https://files.pythonhosted.org/packages/be/4c/0dbce882550e17db6846b29e9dc242aea7590e7594e1ca5043e8e58fff2d/pyzmq-27.0.1-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:351bf5d8ca0788ca85327fda45843b6927593ff4c807faee368cc5aaf9f809c2", size = 897236, upload-time = "2025-08-03T05:04:13.221Z" }, + { url = "https://files.pythonhosted.org/packages/1b/22/461e131cf16b8814f3c356fa1ea0912697dbc4c64cddf01f7756ec704c1e/pyzmq-27.0.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5268a5a9177afff53dc6d70dffe63114ba2a6e7b20d9411cc3adeba09eeda403", size = 660374, upload-time = "2025-08-03T05:04:15.032Z" }, + { url = "https://files.pythonhosted.org/packages/3f/0c/bbd65a814395bf4fc3e57c6c13af27601c07e4009bdfb75ebcf500537bbd/pyzmq-27.0.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a4aca06ba295aa78bec9b33ec028d1ca08744c36294338c41432b7171060c808", size = 847497, upload-time = "2025-08-03T05:04:16.967Z" }, + { url = "https://files.pythonhosted.org/packages/1e/df/3d1f4a03b561d824cbd491394f67591957e2f1acf6dc85d96f970312a76a/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:1c363c6dc66352331d5ad64bb838765c6692766334a6a02fdb05e76bd408ae18", size = 1650028, upload-time = "2025-08-03T05:04:19.398Z" }, + { url = "https://files.pythonhosted.org/packages/41/c9/a3987540f59a412bdaae3f362f78e00e6769557a598c63b7e32956aade5a/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:87aebf4acd7249bdff8d3df03aed4f09e67078e6762cfe0aecf8d0748ff94cde", size = 2023808, upload-time = "2025-08-03T05:04:21.145Z" }, + { url = "https://files.pythonhosted.org/packages/b0/a5/c388f4cd80498a8eaef7535f2a8eaca0a35b82b87a0b47fa1856fc135004/pyzmq-27.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:e4f22d67756518d71901edf73b38dc0eb4765cce22c8fe122cc81748d425262b", size = 1884970, upload-time = "2025-08-03T05:04:22.908Z" }, + { url = "https://files.pythonhosted.org/packages/9a/ac/b2a89a1ed90526a1b9a260cdc5cd42f055fd44ee8d2a59902b5ac35ddeb1/pyzmq-27.0.1-cp314-cp314t-win32.whl", hash = "sha256:8c62297bc7aea2147b472ca5ca2b4389377ad82898c87cabab2a94aedd75e337", size = 586905, upload-time = "2025-08-03T05:04:24.492Z" }, + { url = "https://files.pythonhosted.org/packages/68/62/7aa5ea04e836f7a788b2a67405f83011cef59ca76d7bac91d1fc9a0476da/pyzmq-27.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bee5248d5ec9223545f8cc4f368c2d571477ae828c99409125c3911511d98245", size = 660503, upload-time = "2025-08-03T05:04:26.382Z" }, + { url = "https://files.pythonhosted.org/packages/89/32/3836ed85947b06f1d67c07ce16c00b0cf8c053ab0b249d234f9f81ff95ff/pyzmq-27.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:0fc24bf45e4a454e55ef99d7f5c8b8712539200ce98533af25a5bfa954b6b390", size = 575098, upload-time = "2025-08-03T05:04:27.974Z" }, +] + +[[package]] +name = "questionary" +version = "2.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "prompt-toolkit" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/b8/d16eb579277f3de9e56e5ad25280fab52fc5774117fb70362e8c2e016559/questionary-2.1.0.tar.gz", hash = "sha256:6302cdd645b19667d8f6e6634774e9538bfcd1aad9be287e743d96cacaf95587", size = 26775, upload-time = "2024-12-29T11:49:17.802Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ad/3f/11dd4cd4f39e05128bfd20138faea57bec56f9ffba6185d276e3107ba5b2/questionary-2.1.0-py3-none-any.whl", hash = "sha256:44174d237b68bc828e4878c763a9ad6790ee61990e0ae72927694ead57bab8ec", size = 36747, upload-time = "2024-12-29T11:49:16.734Z" }, +] + +[[package]] +name = "redis" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyjwt" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6a/cf/128b1b6d7086200c9f387bd4be9b2572a30b90745ef078bd8b235042dc9f/redis-5.3.1.tar.gz", hash = "sha256:ca49577a531ea64039b5a36db3d6cd1a0c7a60c34124d46924a45b956e8cf14c", size = 4626200, upload-time = "2025-07-25T08:06:27.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7f/26/5c5fa0e83c3621db835cfc1f1d789b37e7fa99ed54423b5f519beb931aa7/redis-5.3.1-py3-none-any.whl", hash = "sha256:dc1909bd24669cc31b5f67a039700b16ec30571096c5f1f0d9d2324bff31af97", size = 272833, upload-time = "2025-07-25T08:06:26.317Z" }, +] + +[[package]] +name = "referencing" +version = "0.36.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "attrs" }, + { name = "rpds-py" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2f/db/98b5c277be99dd18bfd91dd04e1b759cad18d1a338188c936e92f921c7e2/referencing-0.36.2.tar.gz", hash = "sha256:df2e89862cd09deabbdba16944cc3f10feb6b3e6f18e902f7cc25609a34775aa", size = 74744, upload-time = "2025-01-25T08:48:16.138Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/b1/3baf80dc6d2b7bc27a95a67752d0208e410351e3feb4eb78de5f77454d8d/referencing-0.36.2-py3-none-any.whl", hash = "sha256:e8699adbbf8b5c7de96d8ffa0eb5c158b3beafce084968e2ea8bb08c6794dcd0", size = 26775, upload-time = "2025-01-25T08:48:14.241Z" }, +] + +[[package]] +name = "regex" +version = "2025.7.34" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/de/e13fa6dc61d78b30ba47481f99933a3b49a57779d625c392d8036770a60d/regex-2025.7.34.tar.gz", hash = "sha256:9ead9765217afd04a86822dfcd4ed2747dfe426e887da413b15ff0ac2457e21a", size = 400714, upload-time = "2025-07-31T00:21:16.262Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ff/f0/31d62596c75a33f979317658e8d261574785c6cd8672c06741ce2e2e2070/regex-2025.7.34-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:7f7211a746aced993bef487de69307a38c5ddd79257d7be83f7b202cb59ddb50", size = 485492, upload-time = "2025-07-31T00:19:35.57Z" }, + { url = "https://files.pythonhosted.org/packages/d8/16/b818d223f1c9758c3434be89aa1a01aae798e0e0df36c1f143d1963dd1ee/regex-2025.7.34-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fb31080f2bd0681484b275461b202b5ad182f52c9ec606052020fe13eb13a72f", size = 290000, upload-time = "2025-07-31T00:19:37.175Z" }, + { url = "https://files.pythonhosted.org/packages/cd/70/69506d53397b4bd6954061bae75677ad34deb7f6ca3ba199660d6f728ff5/regex-2025.7.34-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0200a5150c4cf61e407038f4b4d5cdad13e86345dac29ff9dab3d75d905cf130", size = 286072, upload-time = "2025-07-31T00:19:38.612Z" }, + { url = "https://files.pythonhosted.org/packages/b0/73/536a216d5f66084fb577bb0543b5cb7de3272eb70a157f0c3a542f1c2551/regex-2025.7.34-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:739a74970e736df0773788377969c9fea3876c2fc13d0563f98e5503e5185f46", size = 797341, upload-time = "2025-07-31T00:19:40.119Z" }, + { url = "https://files.pythonhosted.org/packages/26/af/733f8168449e56e8f404bb807ea7189f59507cbea1b67a7bbcd92f8bf844/regex-2025.7.34-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4fef81b2f7ea6a2029161ed6dea9ae13834c28eb5a95b8771828194a026621e4", size = 862556, upload-time = "2025-07-31T00:19:41.556Z" }, + { url = "https://files.pythonhosted.org/packages/19/dd/59c464d58c06c4f7d87de4ab1f590e430821345a40c5d345d449a636d15f/regex-2025.7.34-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ea74cf81fe61a7e9d77989050d0089a927ab758c29dac4e8e1b6c06fccf3ebf0", size = 910762, upload-time = "2025-07-31T00:19:43Z" }, + { url = "https://files.pythonhosted.org/packages/37/a8/b05ccf33ceca0815a1e253693b2c86544932ebcc0049c16b0fbdf18b688b/regex-2025.7.34-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e4636a7f3b65a5f340ed9ddf53585c42e3ff37101d383ed321bfe5660481744b", size = 801892, upload-time = "2025-07-31T00:19:44.645Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9a/b993cb2e634cc22810afd1652dba0cae156c40d4864285ff486c73cd1996/regex-2025.7.34-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cef962d7834437fe8d3da6f9bfc6f93f20f218266dcefec0560ed7765f5fe01", size = 786551, upload-time = "2025-07-31T00:19:46.127Z" }, + { url = "https://files.pythonhosted.org/packages/2d/79/7849d67910a0de4e26834b5bb816e028e35473f3d7ae563552ea04f58ca2/regex-2025.7.34-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:cbe1698e5b80298dbce8df4d8d1182279fbdaf1044e864cbc9d53c20e4a2be77", size = 856457, upload-time = "2025-07-31T00:19:47.562Z" }, + { url = "https://files.pythonhosted.org/packages/91/c6/de516bc082524b27e45cb4f54e28bd800c01efb26d15646a65b87b13a91e/regex-2025.7.34-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:32b9f9bcf0f605eb094b08e8da72e44badabb63dde6b83bd530580b488d1c6da", size = 848902, upload-time = "2025-07-31T00:19:49.312Z" }, + { url = "https://files.pythonhosted.org/packages/7d/22/519ff8ba15f732db099b126f039586bd372da6cd4efb810d5d66a5daeda1/regex-2025.7.34-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:524c868ba527eab4e8744a9287809579f54ae8c62fbf07d62aacd89f6026b282", size = 788038, upload-time = "2025-07-31T00:19:50.794Z" }, + { url = "https://files.pythonhosted.org/packages/3f/7d/aabb467d8f57d8149895d133c88eb809a1a6a0fe262c1d508eb9dfabb6f9/regex-2025.7.34-cp312-cp312-win32.whl", hash = "sha256:d600e58ee6d036081c89696d2bdd55d507498a7180df2e19945c6642fac59588", size = 264417, upload-time = "2025-07-31T00:19:52.292Z" }, + { url = "https://files.pythonhosted.org/packages/3b/39/bd922b55a4fc5ad5c13753274e5b536f5b06ec8eb9747675668491c7ab7a/regex-2025.7.34-cp312-cp312-win_amd64.whl", hash = "sha256:9a9ab52a466a9b4b91564437b36417b76033e8778e5af8f36be835d8cb370d62", size = 275387, upload-time = "2025-07-31T00:19:53.593Z" }, + { url = "https://files.pythonhosted.org/packages/f7/3c/c61d2fdcecb754a40475a3d1ef9a000911d3e3fc75c096acf44b0dfb786a/regex-2025.7.34-cp312-cp312-win_arm64.whl", hash = "sha256:c83aec91af9c6fbf7c743274fd952272403ad9a9db05fe9bfc9df8d12b45f176", size = 268482, upload-time = "2025-07-31T00:19:55.183Z" }, + { url = "https://files.pythonhosted.org/packages/15/16/b709b2119975035169a25aa8e4940ca177b1a2e25e14f8d996d09130368e/regex-2025.7.34-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c3c9740a77aeef3f5e3aaab92403946a8d34437db930a0280e7e81ddcada61f5", size = 485334, upload-time = "2025-07-31T00:19:56.58Z" }, + { url = "https://files.pythonhosted.org/packages/94/a6/c09136046be0595f0331bc58a0e5f89c2d324cf734e0b0ec53cf4b12a636/regex-2025.7.34-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:69ed3bc611540f2ea70a4080f853741ec698be556b1df404599f8724690edbcd", size = 289942, upload-time = "2025-07-31T00:19:57.943Z" }, + { url = "https://files.pythonhosted.org/packages/36/91/08fc0fd0f40bdfb0e0df4134ee37cfb16e66a1044ac56d36911fd01c69d2/regex-2025.7.34-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:d03c6f9dcd562c56527c42b8530aad93193e0b3254a588be1f2ed378cdfdea1b", size = 285991, upload-time = "2025-07-31T00:19:59.837Z" }, + { url = "https://files.pythonhosted.org/packages/be/2f/99dc8f6f756606f0c214d14c7b6c17270b6bbe26d5c1f05cde9dbb1c551f/regex-2025.7.34-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6164b1d99dee1dfad33f301f174d8139d4368a9fb50bf0a3603b2eaf579963ad", size = 797415, upload-time = "2025-07-31T00:20:01.668Z" }, + { url = "https://files.pythonhosted.org/packages/62/cf/2fcdca1110495458ba4e95c52ce73b361cf1cafd8a53b5c31542cde9a15b/regex-2025.7.34-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1e4f4f62599b8142362f164ce776f19d79bdd21273e86920a7b604a4275b4f59", size = 862487, upload-time = "2025-07-31T00:20:03.142Z" }, + { url = "https://files.pythonhosted.org/packages/90/38/899105dd27fed394e3fae45607c1983e138273ec167e47882fc401f112b9/regex-2025.7.34-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:72a26dcc6a59c057b292f39d41465d8233a10fd69121fa24f8f43ec6294e5415", size = 910717, upload-time = "2025-07-31T00:20:04.727Z" }, + { url = "https://files.pythonhosted.org/packages/ee/f6/4716198dbd0bcc9c45625ac4c81a435d1c4d8ad662e8576dac06bab35b17/regex-2025.7.34-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5273fddf7a3e602695c92716c420c377599ed3c853ea669c1fe26218867002f", size = 801943, upload-time = "2025-07-31T00:20:07.1Z" }, + { url = "https://files.pythonhosted.org/packages/40/5d/cff8896d27e4e3dd11dd72ac78797c7987eb50fe4debc2c0f2f1682eb06d/regex-2025.7.34-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:c1844be23cd40135b3a5a4dd298e1e0c0cb36757364dd6cdc6025770363e06c1", size = 786664, upload-time = "2025-07-31T00:20:08.818Z" }, + { url = "https://files.pythonhosted.org/packages/10/29/758bf83cf7b4c34f07ac3423ea03cee3eb3176941641e4ccc05620f6c0b8/regex-2025.7.34-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:dde35e2afbbe2272f8abee3b9fe6772d9b5a07d82607b5788e8508974059925c", size = 856457, upload-time = "2025-07-31T00:20:10.328Z" }, + { url = "https://files.pythonhosted.org/packages/d7/30/c19d212b619963c5b460bfed0ea69a092c6a43cba52a973d46c27b3e2975/regex-2025.7.34-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f6e8e7af516a7549412ce57613e859c3be27d55341a894aacaa11703a4c31a", size = 849008, upload-time = "2025-07-31T00:20:11.823Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b8/3c35da3b12c87e3cc00010ef6c3a4ae787cff0bc381aa3d251def219969a/regex-2025.7.34-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:469142fb94a869beb25b5f18ea87646d21def10fbacb0bcb749224f3509476f0", size = 788101, upload-time = "2025-07-31T00:20:13.729Z" }, + { url = "https://files.pythonhosted.org/packages/47/80/2f46677c0b3c2b723b2c358d19f9346e714113865da0f5f736ca1a883bde/regex-2025.7.34-cp313-cp313-win32.whl", hash = "sha256:da7507d083ee33ccea1310447410c27ca11fb9ef18c95899ca57ff60a7e4d8f1", size = 264401, upload-time = "2025-07-31T00:20:15.233Z" }, + { url = "https://files.pythonhosted.org/packages/be/fa/917d64dd074682606a003cba33585c28138c77d848ef72fc77cbb1183849/regex-2025.7.34-cp313-cp313-win_amd64.whl", hash = "sha256:9d644de5520441e5f7e2db63aec2748948cc39ed4d7a87fd5db578ea4043d997", size = 275368, upload-time = "2025-07-31T00:20:16.711Z" }, + { url = "https://files.pythonhosted.org/packages/65/cd/f94383666704170a2154a5df7b16be28f0c27a266bffcd843e58bc84120f/regex-2025.7.34-cp313-cp313-win_arm64.whl", hash = "sha256:7bf1c5503a9f2cbd2f52d7e260acb3131b07b6273c470abb78568174fe6bde3f", size = 268482, upload-time = "2025-07-31T00:20:18.189Z" }, + { url = "https://files.pythonhosted.org/packages/ac/23/6376f3a23cf2f3c00514b1cdd8c990afb4dfbac3cb4a68b633c6b7e2e307/regex-2025.7.34-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:8283afe7042d8270cecf27cca558873168e771183d4d593e3c5fe5f12402212a", size = 485385, upload-time = "2025-07-31T00:20:19.692Z" }, + { url = "https://files.pythonhosted.org/packages/73/5b/6d4d3a0b4d312adbfd6d5694c8dddcf1396708976dd87e4d00af439d962b/regex-2025.7.34-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6c053f9647e3421dd2f5dff8172eb7b4eec129df9d1d2f7133a4386319b47435", size = 289788, upload-time = "2025-07-31T00:20:21.941Z" }, + { url = "https://files.pythonhosted.org/packages/92/71/5862ac9913746e5054d01cb9fb8125b3d0802c0706ef547cae1e7f4428fa/regex-2025.7.34-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a16dd56bbcb7d10e62861c3cd000290ddff28ea142ffb5eb3470f183628011ac", size = 286136, upload-time = "2025-07-31T00:20:26.146Z" }, + { url = "https://files.pythonhosted.org/packages/27/df/5b505dc447eb71278eba10d5ec940769ca89c1af70f0468bfbcb98035dc2/regex-2025.7.34-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:69c593ff5a24c0d5c1112b0df9b09eae42b33c014bdca7022d6523b210b69f72", size = 797753, upload-time = "2025-07-31T00:20:27.919Z" }, + { url = "https://files.pythonhosted.org/packages/86/38/3e3dc953d13998fa047e9a2414b556201dbd7147034fbac129392363253b/regex-2025.7.34-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98d0ce170fcde1a03b5df19c5650db22ab58af375aaa6ff07978a85c9f250f0e", size = 863263, upload-time = "2025-07-31T00:20:29.803Z" }, + { url = "https://files.pythonhosted.org/packages/68/e5/3ff66b29dde12f5b874dda2d9dec7245c2051f2528d8c2a797901497f140/regex-2025.7.34-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d72765a4bff8c43711d5b0f5b452991a9947853dfa471972169b3cc0ba1d0751", size = 910103, upload-time = "2025-07-31T00:20:31.313Z" }, + { url = "https://files.pythonhosted.org/packages/9e/fe/14176f2182125977fba3711adea73f472a11f3f9288c1317c59cd16ad5e6/regex-2025.7.34-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4494f8fd95a77eb434039ad8460e64d57baa0434f1395b7da44015bef650d0e4", size = 801709, upload-time = "2025-07-31T00:20:33.323Z" }, + { url = "https://files.pythonhosted.org/packages/5a/0d/80d4e66ed24f1ba876a9e8e31b709f9fd22d5c266bf5f3ab3c1afe683d7d/regex-2025.7.34-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4f42b522259c66e918a0121a12429b2abcf696c6f967fa37bdc7b72e61469f98", size = 786726, upload-time = "2025-07-31T00:20:35.252Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/c3ebb30e04a56c046f5c85179dc173818551037daae2c0c940c7b19152cb/regex-2025.7.34-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:aaef1f056d96a0a5d53ad47d019d5b4c66fe4be2da87016e0d43b7242599ffc7", size = 857306, upload-time = "2025-07-31T00:20:37.12Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b2/a4dc5d8b14f90924f27f0ac4c4c4f5e195b723be98adecc884f6716614b6/regex-2025.7.34-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:656433e5b7dccc9bc0da6312da8eb897b81f5e560321ec413500e5367fcd5d47", size = 848494, upload-time = "2025-07-31T00:20:38.818Z" }, + { url = "https://files.pythonhosted.org/packages/0d/21/9ac6e07a4c5e8646a90b56b61f7e9dac11ae0747c857f91d3d2bc7c241d9/regex-2025.7.34-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e91eb2c62c39705e17b4d42d4b86c4e86c884c0d15d9c5a47d0835f8387add8e", size = 787850, upload-time = "2025-07-31T00:20:40.478Z" }, + { url = "https://files.pythonhosted.org/packages/be/6c/d51204e28e7bc54f9a03bb799b04730d7e54ff2718862b8d4e09e7110a6a/regex-2025.7.34-cp314-cp314-win32.whl", hash = "sha256:f978ddfb6216028c8f1d6b0f7ef779949498b64117fc35a939022f67f810bdcb", size = 269730, upload-time = "2025-07-31T00:20:42.253Z" }, + { url = "https://files.pythonhosted.org/packages/74/52/a7e92d02fa1fdef59d113098cb9f02c5d03289a0e9f9e5d4d6acccd10677/regex-2025.7.34-cp314-cp314-win_amd64.whl", hash = "sha256:4b7dc33b9b48fb37ead12ffc7bdb846ac72f99a80373c4da48f64b373a7abeae", size = 278640, upload-time = "2025-07-31T00:20:44.42Z" }, + { url = "https://files.pythonhosted.org/packages/d1/78/a815529b559b1771080faa90c3ab401730661f99d495ab0071649f139ebd/regex-2025.7.34-cp314-cp314-win_arm64.whl", hash = "sha256:4b8c4d39f451e64809912c82392933d80fe2e4a87eeef8859fcc5380d0173c64", size = 271757, upload-time = "2025-07-31T00:20:46.355Z" }, +] + +[[package]] +name = "requests" +version = "2.32.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/db/4254e3eabe8020b458f1a747140d32277ec7a271daf1d235b70dc0b4e6e3/requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6", size = 64738, upload-time = "2025-08-18T20:46:00.542Z" }, +] + +[[package]] +name = "requests-oauthlib" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "oauthlib" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/f2/05f29bc3913aea15eb670be136045bf5c5bbf4b99ecb839da9b422bb2c85/requests-oauthlib-2.0.0.tar.gz", hash = "sha256:b3dffaebd884d8cd778494369603a9e7b58d29111bf6b41bdc2dcd87203af4e9", size = 55650, upload-time = "2024-03-22T20:32:29.939Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/3b/5d/63d4ae3b9daea098d5d6f5da83984853c1bbacd5dc826764b249fe119d24/requests_oauthlib-2.0.0-py2.py3-none-any.whl", hash = "sha256:7dd8a5c40426b779b0868c404bdef9768deccf22749cde15852df527e6269b36", size = 24179, upload-time = "2024-03-22T20:32:28.055Z" }, +] + +[[package]] +name = "rich" +version = "13.9.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/3a/0316b28d0761c6734d6bc14e770d85506c986c85ffb239e688eeaab2c2bc/rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098", size = 223149, upload-time = "2024-11-01T16:43:57.873Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/19/71/39c7c0d87f8d4e6c020a393182060eaefeeae6c01dab6a84ec346f2567df/rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90", size = 242424, upload-time = "2024-11-01T16:43:55.817Z" }, +] + +[[package]] +name = "rpds-py" +version = "0.27.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1e/d9/991a0dee12d9fc53ed027e26a26a64b151d77252ac477e22666b9688bc16/rpds_py-0.27.0.tar.gz", hash = "sha256:8b23cf252f180cda89220b378d917180f29d313cd6a07b2431c0d3b776aae86f", size = 27420, upload-time = "2025-08-07T08:26:39.624Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/17/e67309ca1ac993fa1888a0d9b2f5ccc1f67196ace32e76c9f8e1dbbbd50c/rpds_py-0.27.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:19c990fdf5acecbf0623e906ae2e09ce1c58947197f9bced6bbd7482662231c4", size = 362611, upload-time = "2025-08-07T08:23:44.773Z" }, + { url = "https://files.pythonhosted.org/packages/93/2e/28c2fb84aa7aa5d75933d1862d0f7de6198ea22dfd9a0cca06e8a4e7509e/rpds_py-0.27.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6c27a7054b5224710fcfb1a626ec3ff4f28bcb89b899148c72873b18210e446b", size = 347680, upload-time = "2025-08-07T08:23:46.014Z" }, + { url = "https://files.pythonhosted.org/packages/44/3e/9834b4c8f4f5fe936b479e623832468aa4bd6beb8d014fecaee9eac6cdb1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:09965b314091829b378b60607022048953e25f0b396c2b70e7c4c81bcecf932e", size = 384600, upload-time = "2025-08-07T08:23:48Z" }, + { url = "https://files.pythonhosted.org/packages/19/78/744123c7b38865a965cd9e6f691fde7ef989a00a256fa8bf15b75240d12f/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:14f028eb47f59e9169bfdf9f7ceafd29dd64902141840633683d0bad5b04ff34", size = 400697, upload-time = "2025-08-07T08:23:49.407Z" }, + { url = "https://files.pythonhosted.org/packages/32/97/3c3d32fe7daee0a1f1a678b6d4dfb8c4dcf88197fa2441f9da7cb54a8466/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6168af0be75bba990a39f9431cdfae5f0ad501f4af32ae62e8856307200517b8", size = 517781, upload-time = "2025-08-07T08:23:50.557Z" }, + { url = "https://files.pythonhosted.org/packages/b2/be/28f0e3e733680aa13ecec1212fc0f585928a206292f14f89c0b8a684cad1/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab47fe727c13c09d0e6f508e3a49e545008e23bf762a245b020391b621f5b726", size = 406449, upload-time = "2025-08-07T08:23:51.732Z" }, + { url = "https://files.pythonhosted.org/packages/95/ae/5d15c83e337c082d0367053baeb40bfba683f42459f6ebff63a2fd7e5518/rpds_py-0.27.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5fa01b3d5e3b7d97efab65bd3d88f164e289ec323a8c033c5c38e53ee25c007e", size = 386150, upload-time = "2025-08-07T08:23:52.822Z" }, + { url = "https://files.pythonhosted.org/packages/bf/65/944e95f95d5931112829e040912b25a77b2e7ed913ea5fe5746aa5c1ce75/rpds_py-0.27.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:6c135708e987f46053e0a1246a206f53717f9fadfba27174a9769ad4befba5c3", size = 406100, upload-time = "2025-08-07T08:23:54.339Z" }, + { url = "https://files.pythonhosted.org/packages/21/a4/1664b83fae02894533cd11dc0b9f91d673797c2185b7be0f7496107ed6c5/rpds_py-0.27.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fc327f4497b7087d06204235199daf208fd01c82d80465dc5efa4ec9df1c5b4e", size = 421345, upload-time = "2025-08-07T08:23:55.832Z" }, + { url = "https://files.pythonhosted.org/packages/7c/26/b7303941c2b0823bfb34c71378249f8beedce57301f400acb04bb345d025/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7e57906e38583a2cba67046a09c2637e23297618dc1f3caddbc493f2be97c93f", size = 561891, upload-time = "2025-08-07T08:23:56.951Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c8/48623d64d4a5a028fa99576c768a6159db49ab907230edddc0b8468b998b/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f4f69d7a4300fbf91efb1fb4916421bd57804c01ab938ab50ac9c4aa2212f03", size = 591756, upload-time = "2025-08-07T08:23:58.146Z" }, + { url = "https://files.pythonhosted.org/packages/b3/51/18f62617e8e61cc66334c9fb44b1ad7baae3438662098efbc55fb3fda453/rpds_py-0.27.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b4c4fbbcff474e1e5f38be1bf04511c03d492d42eec0babda5d03af3b5589374", size = 557088, upload-time = "2025-08-07T08:23:59.6Z" }, + { url = "https://files.pythonhosted.org/packages/bd/4c/e84c3a276e2496a93d245516be6b49e20499aa8ca1c94d59fada0d79addc/rpds_py-0.27.0-cp312-cp312-win32.whl", hash = "sha256:27bac29bbbf39601b2aab474daf99dbc8e7176ca3389237a23944b17f8913d97", size = 221926, upload-time = "2025-08-07T08:24:00.695Z" }, + { url = "https://files.pythonhosted.org/packages/83/89/9d0fbcef64340db0605eb0a0044f258076f3ae0a3b108983b2c614d96212/rpds_py-0.27.0-cp312-cp312-win_amd64.whl", hash = "sha256:8a06aa1197ec0281eb1d7daf6073e199eb832fe591ffa329b88bae28f25f5fe5", size = 233235, upload-time = "2025-08-07T08:24:01.846Z" }, + { url = "https://files.pythonhosted.org/packages/c9/b0/e177aa9f39cbab060f96de4a09df77d494f0279604dc2f509263e21b05f9/rpds_py-0.27.0-cp312-cp312-win_arm64.whl", hash = "sha256:e14aab02258cb776a108107bd15f5b5e4a1bbaa61ef33b36693dfab6f89d54f9", size = 223315, upload-time = "2025-08-07T08:24:03.337Z" }, + { url = "https://files.pythonhosted.org/packages/81/d2/dfdfd42565a923b9e5a29f93501664f5b984a802967d48d49200ad71be36/rpds_py-0.27.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:443d239d02d9ae55b74015234f2cd8eb09e59fbba30bf60baeb3123ad4c6d5ff", size = 362133, upload-time = "2025-08-07T08:24:04.508Z" }, + { url = "https://files.pythonhosted.org/packages/ac/4a/0a2e2460c4b66021d349ce9f6331df1d6c75d7eea90df9785d333a49df04/rpds_py-0.27.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8a7acf04fda1f30f1007f3cc96d29d8cf0a53e626e4e1655fdf4eabc082d367", size = 347128, upload-time = "2025-08-07T08:24:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/35/8d/7d1e4390dfe09d4213b3175a3f5a817514355cb3524593380733204f20b9/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d0f92b78cfc3b74a42239fdd8c1266f4715b573204c234d2f9fc3fc7a24f185", size = 384027, upload-time = "2025-08-07T08:24:06.841Z" }, + { url = "https://files.pythonhosted.org/packages/c1/65/78499d1a62172891c8cd45de737b2a4b84a414b6ad8315ab3ac4945a5b61/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ce4ed8e0c7dbc5b19352b9c2c6131dd23b95fa8698b5cdd076307a33626b72dc", size = 399973, upload-time = "2025-08-07T08:24:08.143Z" }, + { url = "https://files.pythonhosted.org/packages/10/a1/1c67c1d8cc889107b19570bb01f75cf49852068e95e6aee80d22915406fc/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fde355b02934cc6b07200cc3b27ab0c15870a757d1a72fd401aa92e2ea3c6bfe", size = 515295, upload-time = "2025-08-07T08:24:09.711Z" }, + { url = "https://files.pythonhosted.org/packages/df/27/700ec88e748436b6c7c4a2262d66e80f8c21ab585d5e98c45e02f13f21c0/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:13bbc4846ae4c993f07c93feb21a24d8ec637573d567a924b1001e81c8ae80f9", size = 406737, upload-time = "2025-08-07T08:24:11.182Z" }, + { url = "https://files.pythonhosted.org/packages/33/cc/6b0ee8f0ba3f2df2daac1beda17fde5cf10897a7d466f252bd184ef20162/rpds_py-0.27.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be0744661afbc4099fef7f4e604e7f1ea1be1dd7284f357924af12a705cc7d5c", size = 385898, upload-time = "2025-08-07T08:24:12.798Z" }, + { url = "https://files.pythonhosted.org/packages/e8/7e/c927b37d7d33c0a0ebf249cc268dc2fcec52864c1b6309ecb960497f2285/rpds_py-0.27.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:069e0384a54f427bd65d7fda83b68a90606a3835901aaff42185fcd94f5a9295", size = 405785, upload-time = "2025-08-07T08:24:14.906Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d2/8ed50746d909dcf402af3fa58b83d5a590ed43e07251d6b08fad1a535ba6/rpds_py-0.27.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4bc262ace5a1a7dc3e2eac2fa97b8257ae795389f688b5adf22c5db1e2431c43", size = 419760, upload-time = "2025-08-07T08:24:16.129Z" }, + { url = "https://files.pythonhosted.org/packages/d3/60/2b2071aee781cb3bd49f94d5d35686990b925e9b9f3e3d149235a6f5d5c1/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2fe6e18e5c8581f0361b35ae575043c7029d0a92cb3429e6e596c2cdde251432", size = 561201, upload-time = "2025-08-07T08:24:17.645Z" }, + { url = "https://files.pythonhosted.org/packages/98/1f/27b67304272521aaea02be293fecedce13fa351a4e41cdb9290576fc6d81/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d93ebdb82363d2e7bec64eecdc3632b59e84bd270d74fe5be1659f7787052f9b", size = 591021, upload-time = "2025-08-07T08:24:18.999Z" }, + { url = "https://files.pythonhosted.org/packages/db/9b/a2fadf823164dd085b1f894be6443b0762a54a7af6f36e98e8fcda69ee50/rpds_py-0.27.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0954e3a92e1d62e83a54ea7b3fdc9efa5d61acef8488a8a3d31fdafbfb00460d", size = 556368, upload-time = "2025-08-07T08:24:20.54Z" }, + { url = "https://files.pythonhosted.org/packages/24/f3/6d135d46a129cda2e3e6d4c5e91e2cc26ea0428c6cf152763f3f10b6dd05/rpds_py-0.27.0-cp313-cp313-win32.whl", hash = "sha256:2cff9bdd6c7b906cc562a505c04a57d92e82d37200027e8d362518df427f96cd", size = 221236, upload-time = "2025-08-07T08:24:22.144Z" }, + { url = "https://files.pythonhosted.org/packages/c5/44/65d7494f5448ecc755b545d78b188440f81da98b50ea0447ab5ebfdf9bd6/rpds_py-0.27.0-cp313-cp313-win_amd64.whl", hash = "sha256:dc79d192fb76fc0c84f2c58672c17bbbc383fd26c3cdc29daae16ce3d927e8b2", size = 232634, upload-time = "2025-08-07T08:24:23.642Z" }, + { url = "https://files.pythonhosted.org/packages/70/d9/23852410fadab2abb611733933401de42a1964ce6600a3badae35fbd573e/rpds_py-0.27.0-cp313-cp313-win_arm64.whl", hash = "sha256:5b3a5c8089eed498a3af23ce87a80805ff98f6ef8f7bdb70bd1b7dae5105f6ac", size = 222783, upload-time = "2025-08-07T08:24:25.098Z" }, + { url = "https://files.pythonhosted.org/packages/15/75/03447917f78512b34463f4ef11066516067099a0c466545655503bed0c77/rpds_py-0.27.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:90fb790138c1a89a2e58c9282fe1089638401f2f3b8dddd758499041bc6e0774", size = 359154, upload-time = "2025-08-07T08:24:26.249Z" }, + { url = "https://files.pythonhosted.org/packages/6b/fc/4dac4fa756451f2122ddaf136e2c6aeb758dc6fdbe9ccc4bc95c98451d50/rpds_py-0.27.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:010c4843a3b92b54373e3d2291a7447d6c3fc29f591772cc2ea0e9f5c1da434b", size = 343909, upload-time = "2025-08-07T08:24:27.405Z" }, + { url = "https://files.pythonhosted.org/packages/7b/81/723c1ed8e6f57ed9d8c0c07578747a2d3d554aaefc1ab89f4e42cfeefa07/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9ce7a9e967afc0a2af7caa0d15a3e9c1054815f73d6a8cb9225b61921b419bd", size = 379340, upload-time = "2025-08-07T08:24:28.714Z" }, + { url = "https://files.pythonhosted.org/packages/98/16/7e3740413de71818ce1997df82ba5f94bae9fff90c0a578c0e24658e6201/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aa0bf113d15e8abdfee92aa4db86761b709a09954083afcb5bf0f952d6065fdb", size = 391655, upload-time = "2025-08-07T08:24:30.223Z" }, + { url = "https://files.pythonhosted.org/packages/e0/63/2a9f510e124d80660f60ecce07953f3f2d5f0b96192c1365443859b9c87f/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:eb91d252b35004a84670dfeafadb042528b19842a0080d8b53e5ec1128e8f433", size = 513017, upload-time = "2025-08-07T08:24:31.446Z" }, + { url = "https://files.pythonhosted.org/packages/2c/4e/cf6ff311d09776c53ea1b4f2e6700b9d43bb4e99551006817ade4bbd6f78/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:db8a6313dbac934193fc17fe7610f70cd8181c542a91382531bef5ed785e5615", size = 402058, upload-time = "2025-08-07T08:24:32.613Z" }, + { url = "https://files.pythonhosted.org/packages/88/11/5e36096d474cb10f2a2d68b22af60a3bc4164fd8db15078769a568d9d3ac/rpds_py-0.27.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce96ab0bdfcef1b8c371ada2100767ace6804ea35aacce0aef3aeb4f3f499ca8", size = 383474, upload-time = "2025-08-07T08:24:33.767Z" }, + { url = "https://files.pythonhosted.org/packages/db/a2/3dff02805b06058760b5eaa6d8cb8db3eb3e46c9e452453ad5fc5b5ad9fe/rpds_py-0.27.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:7451ede3560086abe1aa27dcdcf55cd15c96b56f543fb12e5826eee6f721f858", size = 400067, upload-time = "2025-08-07T08:24:35.021Z" }, + { url = "https://files.pythonhosted.org/packages/67/87/eed7369b0b265518e21ea836456a4ed4a6744c8c12422ce05bce760bb3cf/rpds_py-0.27.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:32196b5a99821476537b3f7732432d64d93a58d680a52c5e12a190ee0135d8b5", size = 412085, upload-time = "2025-08-07T08:24:36.267Z" }, + { url = "https://files.pythonhosted.org/packages/8b/48/f50b2ab2fbb422fbb389fe296e70b7a6b5ea31b263ada5c61377e710a924/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a029be818059870664157194e46ce0e995082ac49926f1423c1f058534d2aaa9", size = 555928, upload-time = "2025-08-07T08:24:37.573Z" }, + { url = "https://files.pythonhosted.org/packages/98/41/b18eb51045d06887666c3560cd4bbb6819127b43d758f5adb82b5f56f7d1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3841f66c1ffdc6cebce8aed64e36db71466f1dc23c0d9a5592e2a782a3042c79", size = 585527, upload-time = "2025-08-07T08:24:39.391Z" }, + { url = "https://files.pythonhosted.org/packages/be/03/a3dd6470fc76499959b00ae56295b76b4bdf7c6ffc60d62006b1217567e1/rpds_py-0.27.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:42894616da0fc0dcb2ec08a77896c3f56e9cb2f4b66acd76fc8992c3557ceb1c", size = 554211, upload-time = "2025-08-07T08:24:40.6Z" }, + { url = "https://files.pythonhosted.org/packages/bf/d1/ee5fd1be395a07423ac4ca0bcc05280bf95db2b155d03adefeb47d5ebf7e/rpds_py-0.27.0-cp313-cp313t-win32.whl", hash = "sha256:b1fef1f13c842a39a03409e30ca0bf87b39a1e2a305a9924deadb75a43105d23", size = 216624, upload-time = "2025-08-07T08:24:42.204Z" }, + { url = "https://files.pythonhosted.org/packages/1c/94/4814c4c858833bf46706f87349c37ca45e154da7dbbec9ff09f1abeb08cc/rpds_py-0.27.0-cp313-cp313t-win_amd64.whl", hash = "sha256:183f5e221ba3e283cd36fdfbe311d95cd87699a083330b4f792543987167eff1", size = 230007, upload-time = "2025-08-07T08:24:43.329Z" }, + { url = "https://files.pythonhosted.org/packages/0e/a5/8fffe1c7dc7c055aa02df310f9fb71cfc693a4d5ccc5de2d3456ea5fb022/rpds_py-0.27.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:f3cd110e02c5bf17d8fb562f6c9df5c20e73029d587cf8602a2da6c5ef1e32cb", size = 362595, upload-time = "2025-08-07T08:24:44.478Z" }, + { url = "https://files.pythonhosted.org/packages/bc/c7/4e4253fd2d4bb0edbc0b0b10d9f280612ca4f0f990e3c04c599000fe7d71/rpds_py-0.27.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:8d0e09cf4863c74106b5265c2c310f36146e2b445ff7b3018a56799f28f39f6f", size = 347252, upload-time = "2025-08-07T08:24:45.678Z" }, + { url = "https://files.pythonhosted.org/packages/f3/c8/3d1a954d30f0174dd6baf18b57c215da03cf7846a9d6e0143304e784cddc/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f689ab822f9b5eb6dfc69893b4b9366db1d2420f7db1f6a2adf2a9ca15ad64", size = 384886, upload-time = "2025-08-07T08:24:46.86Z" }, + { url = "https://files.pythonhosted.org/packages/e0/52/3c5835f2df389832b28f9276dd5395b5a965cea34226e7c88c8fbec2093c/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e36c80c49853b3ffda7aa1831bf175c13356b210c73128c861f3aa93c3cc4015", size = 399716, upload-time = "2025-08-07T08:24:48.174Z" }, + { url = "https://files.pythonhosted.org/packages/40/73/176e46992461a1749686a2a441e24df51ff86b99c2d34bf39f2a5273b987/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6de6a7f622860af0146cb9ee148682ff4d0cea0b8fd3ad51ce4d40efb2f061d0", size = 517030, upload-time = "2025-08-07T08:24:49.52Z" }, + { url = "https://files.pythonhosted.org/packages/79/2a/7266c75840e8c6e70effeb0d38922a45720904f2cd695e68a0150e5407e2/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4045e2fc4b37ec4b48e8907a5819bdd3380708c139d7cc358f03a3653abedb89", size = 408448, upload-time = "2025-08-07T08:24:50.727Z" }, + { url = "https://files.pythonhosted.org/packages/e6/5f/a7efc572b8e235093dc6cf39f4dbc8a7f08e65fdbcec7ff4daeb3585eef1/rpds_py-0.27.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da162b718b12c4219eeeeb68a5b7552fbc7aadedf2efee440f88b9c0e54b45d", size = 387320, upload-time = "2025-08-07T08:24:52.004Z" }, + { url = "https://files.pythonhosted.org/packages/a2/eb/9ff6bc92efe57cf5a2cb74dee20453ba444b6fdc85275d8c99e0d27239d1/rpds_py-0.27.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:0665be515767dc727ffa5f74bd2ef60b0ff85dad6bb8f50d91eaa6b5fb226f51", size = 407414, upload-time = "2025-08-07T08:24:53.664Z" }, + { url = "https://files.pythonhosted.org/packages/fb/bd/3b9b19b00d5c6e1bd0f418c229ab0f8d3b110ddf7ec5d9d689ef783d0268/rpds_py-0.27.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:203f581accef67300a942e49a37d74c12ceeef4514874c7cede21b012613ca2c", size = 420766, upload-time = "2025-08-07T08:24:55.917Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/521a7b1079ce16258c70805166e3ac6ec4ee2139d023fe07954dc9b2d568/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7873b65686a6471c0037139aa000d23fe94628e0daaa27b6e40607c90e3f5ec4", size = 562409, upload-time = "2025-08-07T08:24:57.17Z" }, + { url = "https://files.pythonhosted.org/packages/8b/bf/65db5bfb14ccc55e39de8419a659d05a2a9cd232f0a699a516bb0991da7b/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:249ab91ceaa6b41abc5f19513cb95b45c6f956f6b89f1fe3d99c81255a849f9e", size = 590793, upload-time = "2025-08-07T08:24:58.388Z" }, + { url = "https://files.pythonhosted.org/packages/db/b8/82d368b378325191ba7aae8f40f009b78057b598d4394d1f2cdabaf67b3f/rpds_py-0.27.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d2f184336bc1d6abfaaa1262ed42739c3789b1e3a65a29916a615307d22ffd2e", size = 558178, upload-time = "2025-08-07T08:24:59.756Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ff/f270bddbfbc3812500f8131b1ebbd97afd014cd554b604a3f73f03133a36/rpds_py-0.27.0-cp314-cp314-win32.whl", hash = "sha256:d3c622c39f04d5751408f5b801ecb527e6e0a471b367f420a877f7a660d583f6", size = 222355, upload-time = "2025-08-07T08:25:01.027Z" }, + { url = "https://files.pythonhosted.org/packages/bf/20/fdab055b1460c02ed356a0e0b0a78c1dd32dc64e82a544f7b31c9ac643dc/rpds_py-0.27.0-cp314-cp314-win_amd64.whl", hash = "sha256:cf824aceaeffff029ccfba0da637d432ca71ab21f13e7f6f5179cd88ebc77a8a", size = 234007, upload-time = "2025-08-07T08:25:02.268Z" }, + { url = "https://files.pythonhosted.org/packages/4d/a8/694c060005421797a3be4943dab8347c76c2b429a9bef68fb2c87c9e70c7/rpds_py-0.27.0-cp314-cp314-win_arm64.whl", hash = "sha256:86aca1616922b40d8ac1b3073a1ead4255a2f13405e5700c01f7c8d29a03972d", size = 223527, upload-time = "2025-08-07T08:25:03.45Z" }, + { url = "https://files.pythonhosted.org/packages/1e/f9/77f4c90f79d2c5ca8ce6ec6a76cb4734ee247de6b3a4f337e289e1f00372/rpds_py-0.27.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:341d8acb6724c0c17bdf714319c393bb27f6d23d39bc74f94221b3e59fc31828", size = 359469, upload-time = "2025-08-07T08:25:04.648Z" }, + { url = "https://files.pythonhosted.org/packages/c0/22/b97878d2f1284286fef4172069e84b0b42b546ea7d053e5fb7adb9ac6494/rpds_py-0.27.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6b96b0b784fe5fd03beffff2b1533dc0d85e92bab8d1b2c24ef3a5dc8fac5669", size = 343960, upload-time = "2025-08-07T08:25:05.863Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b0/dfd55b5bb480eda0578ae94ef256d3061d20b19a0f5e18c482f03e65464f/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0c431bfb91478d7cbe368d0a699978050d3b112d7f1d440a41e90faa325557fd", size = 380201, upload-time = "2025-08-07T08:25:07.513Z" }, + { url = "https://files.pythonhosted.org/packages/28/22/e1fa64e50d58ad2b2053077e3ec81a979147c43428de9e6de68ddf6aff4e/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20e222a44ae9f507d0f2678ee3dd0c45ec1e930f6875d99b8459631c24058aec", size = 392111, upload-time = "2025-08-07T08:25:09.149Z" }, + { url = "https://files.pythonhosted.org/packages/49/f9/43ab7a43e97aedf6cea6af70fdcbe18abbbc41d4ae6cdec1bfc23bbad403/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:184f0d7b342967f6cda94a07d0e1fae177d11d0b8f17d73e06e36ac02889f303", size = 515863, upload-time = "2025-08-07T08:25:10.431Z" }, + { url = "https://files.pythonhosted.org/packages/38/9b/9bd59dcc636cd04d86a2d20ad967770bf348f5eb5922a8f29b547c074243/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a00c91104c173c9043bc46f7b30ee5e6d2f6b1149f11f545580f5d6fdff42c0b", size = 402398, upload-time = "2025-08-07T08:25:11.819Z" }, + { url = "https://files.pythonhosted.org/packages/71/bf/f099328c6c85667aba6b66fa5c35a8882db06dcd462ea214be72813a0dd2/rpds_py-0.27.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7a37dd208f0d658e0487522078b1ed68cd6bce20ef4b5a915d2809b9094b410", size = 384665, upload-time = "2025-08-07T08:25:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/a9/c5/9c1f03121ece6634818490bd3c8be2c82a70928a19de03467fb25a3ae2a8/rpds_py-0.27.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:92f3b3ec3e6008a1fe00b7c0946a170f161ac00645cde35e3c9a68c2475e8156", size = 400405, upload-time = "2025-08-07T08:25:14.417Z" }, + { url = "https://files.pythonhosted.org/packages/b5/b8/e25d54af3e63ac94f0c16d8fe143779fe71ff209445a0c00d0f6984b6b2c/rpds_py-0.27.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a1b3db5fae5cbce2131b7420a3f83553d4d89514c03d67804ced36161fe8b6b2", size = 413179, upload-time = "2025-08-07T08:25:15.664Z" }, + { url = "https://files.pythonhosted.org/packages/f9/d1/406b3316433fe49c3021546293a04bc33f1478e3ec7950215a7fce1a1208/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5355527adaa713ab693cbce7c1e0ec71682f599f61b128cf19d07e5c13c9b1f1", size = 556895, upload-time = "2025-08-07T08:25:17.061Z" }, + { url = "https://files.pythonhosted.org/packages/5f/bc/3697c0c21fcb9a54d46ae3b735eb2365eea0c2be076b8f770f98e07998de/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fcc01c57ce6e70b728af02b2401c5bc853a9e14eb07deda30624374f0aebfe42", size = 585464, upload-time = "2025-08-07T08:25:18.406Z" }, + { url = "https://files.pythonhosted.org/packages/63/09/ee1bb5536f99f42c839b177d552f6114aa3142d82f49cef49261ed28dbe0/rpds_py-0.27.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:3001013dae10f806380ba739d40dee11db1ecb91684febb8406a87c2ded23dae", size = 555090, upload-time = "2025-08-07T08:25:20.461Z" }, + { url = "https://files.pythonhosted.org/packages/7d/2c/363eada9e89f7059199d3724135a86c47082cbf72790d6ba2f336d146ddb/rpds_py-0.27.0-cp314-cp314t-win32.whl", hash = "sha256:0f401c369186a5743694dd9fc08cba66cf70908757552e1f714bfc5219c655b5", size = 218001, upload-time = "2025-08-07T08:25:21.761Z" }, + { url = "https://files.pythonhosted.org/packages/e2/3f/d6c216ed5199c9ef79e2a33955601f454ed1e7420a93b89670133bca5ace/rpds_py-0.27.0-cp314-cp314t-win_amd64.whl", hash = "sha256:8a1dca5507fa1337f75dcd5070218b20bc68cf8844271c923c1b79dfcbc20391", size = 230993, upload-time = "2025-08-07T08:25:23.34Z" }, +] + +[[package]] +name = "rsa" +version = "4.9.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyasn1" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/da/8a/22b7beea3ee0d44b1916c0c1cb0ee3af23b700b6da9f04991899d0c555d4/rsa-4.9.1.tar.gz", hash = "sha256:e7bdbfdb5497da4c07dfd35530e1a902659db6ff241e39d9953cad06ebd0ae75", size = 29034, upload-time = "2025-04-16T09:51:18.218Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/64/8d/0133e4eb4beed9e425d9a98ed6e081a55d195481b7632472be1af08d2f6b/rsa-4.9.1-py3-none-any.whl", hash = "sha256:68635866661c6836b8d39430f97a996acbd61bfa49406748ea243539fe239762", size = 34696, upload-time = "2025-04-16T09:51:17.142Z" }, +] + +[[package]] +name = "scale-gp" +version = "0.1.0a59" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c3/3e/c944564757c0a737937c3c87ef61ccfd5138bbe5201fa93edc704124a297/scale_gp-0.1.0a59.tar.gz", hash = "sha256:b7c1e6edb431824f44b8ed2e49969345465e45a1978c1ab6462a7db6d8718f1a", size = 408472, upload-time = "2025-02-05T18:01:22.365Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/13/7c/de71f2853d062535a762157eb9bc0c180fee160447039f074cbefe495728/scale_gp-0.1.0a59-py3-none-any.whl", hash = "sha256:841846c83e4760e14b76ac2a9b44d40a3e9800ad8505f9d24fef11d981466e35", size = 545196, upload-time = "2025-02-05T18:01:20.111Z" }, +] + +[[package]] +name = "scale-gp-beta" +version = "0.1.0a20" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "distro" }, + { name = "httpx" }, + { name = "pydantic" }, + { name = "sniffio" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/86/2b/a6a373ec8d33fad8b553182aa1ceade94434752c935a4ce16ca84d188c0f/scale_gp_beta-0.1.0a20.tar.gz", hash = "sha256:a2be5c1afcb9171d3c2d6f15b45f4512105c79ab12be8e7ef5a22167ac77fb88", size = 157799, upload-time = "2025-06-12T14:46:17.73Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/12/55f47289a0ae1065e4115bc8018b2f01df0b6560b07bacfc0dcf6c3bdcbe/scale_gp_beta-0.1.0a20-py3-none-any.whl", hash = "sha256:482385ee6c3b912aecf70795948ac45b215a4d19feba60f67d6e10c4312440c6", size = 157906, upload-time = "2025-06-12T14:46:16.344Z" }, +] + +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "sse-starlette" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/42/6f/22ed6e33f8a9e76ca0a412405f31abb844b779d52c5f96660766edcd737c/sse_starlette-3.0.2.tar.gz", hash = "sha256:ccd60b5765ebb3584d0de2d7a6e4f745672581de4f5005ab31c3a25d10b52b3a", size = 20985, upload-time = "2025-07-27T09:07:44.565Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ef/10/c78f463b4ef22eef8491f218f692be838282cd65480f6e423d7730dfd1fb/sse_starlette-3.0.2-py3-none-any.whl", hash = "sha256:16b7cbfddbcd4eaca11f7b586f3b8a080f1afe952c15813455b162edea619e5a", size = 11297, upload-time = "2025-07-27T09:07:43.268Z" }, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "asttokens" }, + { name = "executing" }, + { name = "pure-eval" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/28/e3/55dcc2cfbc3ca9c29519eb6884dd1415ecb53b0e934862d3559ddcb7e20b/stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", size = 44707, upload-time = "2023-09-30T13:58:05.479Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, +] + +[[package]] +name = "starlette" +version = "0.46.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, +] + +[[package]] +name = "temporalio" +version = "1.15.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "nexus-rpc" }, + { name = "protobuf" }, + { name = "types-protobuf" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0b/af/1a3619fc62333d0acbdf90cfc5ada97e68e8c0f79610363b2dbb30871d83/temporalio-1.15.0.tar.gz", hash = "sha256:a4bc6ca01717880112caab75d041713aacc8263dc66e41f5019caef68b344fa0", size = 1684485, upload-time = "2025-07-29T03:44:09.071Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/2d/0153f2bc459e0cb59d41d4dd71da46bf9a98ca98bc37237576c258d6696b/temporalio-1.15.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:74bc5cc0e6bdc161a43015538b0821b8713f5faa716c4209971c274b528e0d47", size = 12703607, upload-time = "2025-07-29T03:43:30.083Z" }, + { url = "https://files.pythonhosted.org/packages/e4/39/1b867ec698c8987aef3b7a7024b5c0c732841112fa88d021303d0fc69bea/temporalio-1.15.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ee8001304dae5723d79797516cfeebe04b966fdbdf348e658fce3b43afdda3cd", size = 12232853, upload-time = "2025-07-29T03:43:38.909Z" }, + { url = "https://files.pythonhosted.org/packages/5e/3e/647d9a7c8b2f638f639717404c0bcbdd7d54fddd7844fdb802e3f40dc55f/temporalio-1.15.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8febd1ac36720817e69c2176aa4aca14a97fe0b83f0d2449c0c730b8f0174d02", size = 12636700, upload-time = "2025-07-29T03:43:49.066Z" }, + { url = "https://files.pythonhosted.org/packages/9a/13/7aa9ec694fec9fba39efdbf61d892bccf7d2b1aa3d9bd359544534c1d309/temporalio-1.15.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:202d81a42cafaed9ccc7ccbea0898838e3b8bf92fee65394f8790f37eafbaa63", size = 12860186, upload-time = "2025-07-29T03:43:57.644Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2b/ba962401324892236148046dbffd805d4443d6df7a7dc33cc7964b566bf9/temporalio-1.15.0-cp39-abi3-win_amd64.whl", hash = "sha256:aae5b18d7c9960238af0f3ebf6b7e5959e05f452106fc0d21a8278d78724f780", size = 12932800, upload-time = "2025-07-29T03:44:06.271Z" }, +] + +[[package]] +name = "tiktoken" +version = "0.11.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex" }, + { name = "requests" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a7/86/ad0155a37c4f310935d5ac0b1ccf9bdb635dcb906e0a9a26b616dd55825a/tiktoken-0.11.0.tar.gz", hash = "sha256:3c518641aee1c52247c2b97e74d8d07d780092af79d5911a6ab5e79359d9b06a", size = 37648, upload-time = "2025-08-08T23:58:08.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/9e/eceddeffc169fc75fe0fd4f38471309f11cb1906f9b8aa39be4f5817df65/tiktoken-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fd9e6b23e860973cf9526544e220b223c60badf5b62e80a33509d6d40e6c8f5d", size = 1055199, upload-time = "2025-08-08T23:57:45.076Z" }, + { url = "https://files.pythonhosted.org/packages/4f/cf/5f02bfefffdc6b54e5094d2897bc80efd43050e5b09b576fd85936ee54bf/tiktoken-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6a76d53cee2da71ee2731c9caa747398762bda19d7f92665e882fef229cb0b5b", size = 996655, upload-time = "2025-08-08T23:57:46.304Z" }, + { url = "https://files.pythonhosted.org/packages/65/8e/c769b45ef379bc360c9978c4f6914c79fd432400a6733a8afc7ed7b0726a/tiktoken-0.11.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ef72aab3ea240646e642413cb363b73869fed4e604dcfd69eec63dc54d603e8", size = 1128867, upload-time = "2025-08-08T23:57:47.438Z" }, + { url = "https://files.pythonhosted.org/packages/d5/2d/4d77f6feb9292bfdd23d5813e442b3bba883f42d0ac78ef5fdc56873f756/tiktoken-0.11.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f929255c705efec7a28bf515e29dc74220b2f07544a8c81b8d69e8efc4578bd", size = 1183308, upload-time = "2025-08-08T23:57:48.566Z" }, + { url = "https://files.pythonhosted.org/packages/7a/65/7ff0a65d3bb0fc5a1fb6cc71b03e0f6e71a68c5eea230d1ff1ba3fd6df49/tiktoken-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:61f1d15822e4404953d499fd1dcc62817a12ae9fb1e4898033ec8fe3915fdf8e", size = 1244301, upload-time = "2025-08-08T23:57:49.642Z" }, + { url = "https://files.pythonhosted.org/packages/f5/6e/5b71578799b72e5bdcef206a214c3ce860d999d579a3b56e74a6c8989ee2/tiktoken-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:45927a71ab6643dfd3ef57d515a5db3d199137adf551f66453be098502838b0f", size = 884282, upload-time = "2025-08-08T23:57:50.759Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cd/a9034bcee638716d9310443818d73c6387a6a96db93cbcb0819b77f5b206/tiktoken-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a5f3f25ffb152ee7fec78e90a5e5ea5b03b4ea240beed03305615847f7a6ace2", size = 1055339, upload-time = "2025-08-08T23:57:51.802Z" }, + { url = "https://files.pythonhosted.org/packages/f1/91/9922b345f611b4e92581f234e64e9661e1c524875c8eadd513c4b2088472/tiktoken-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7dc6e9ad16a2a75b4c4be7208055a1f707c9510541d94d9cc31f7fbdc8db41d8", size = 997080, upload-time = "2025-08-08T23:57:53.442Z" }, + { url = "https://files.pythonhosted.org/packages/d0/9d/49cd047c71336bc4b4af460ac213ec1c457da67712bde59b892e84f1859f/tiktoken-0.11.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a0517634d67a8a48fd4a4ad73930c3022629a85a217d256a6e9b8b47439d1e4", size = 1128501, upload-time = "2025-08-08T23:57:54.808Z" }, + { url = "https://files.pythonhosted.org/packages/52/d5/a0dcdb40dd2ea357e83cb36258967f0ae96f5dd40c722d6e382ceee6bba9/tiktoken-0.11.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7fb4effe60574675118b73c6fbfd3b5868e5d7a1f570d6cc0d18724b09ecf318", size = 1182743, upload-time = "2025-08-08T23:57:56.307Z" }, + { url = "https://files.pythonhosted.org/packages/3b/17/a0fc51aefb66b7b5261ca1314afa83df0106b033f783f9a7bcbe8e741494/tiktoken-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:94f984c9831fd32688aef4348803b0905d4ae9c432303087bae370dc1381a2b8", size = 1244057, upload-time = "2025-08-08T23:57:57.628Z" }, + { url = "https://files.pythonhosted.org/packages/50/79/bcf350609f3a10f09fe4fc207f132085e497fdd3612f3925ab24d86a0ca0/tiktoken-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:2177ffda31dec4023356a441793fed82f7af5291120751dee4d696414f54db0c", size = 883901, upload-time = "2025-08-08T23:57:59.359Z" }, +] + +[[package]] +name = "tokenizers" +version = "0.21.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c2/2f/402986d0823f8d7ca139d969af2917fefaa9b947d1fb32f6168c509f2492/tokenizers-0.21.4.tar.gz", hash = "sha256:fa23f85fbc9a02ec5c6978da172cdcbac23498c3ca9f3645c5c68740ac007880", size = 351253, upload-time = "2025-07-28T15:48:54.325Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/98/c6/fdb6f72bf6454f52eb4a2510be7fb0f614e541a2554d6210e370d85efff4/tokenizers-0.21.4-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:2ccc10a7c3bcefe0f242867dc914fc1226ee44321eb618cfe3019b5df3400133", size = 2863987, upload-time = "2025-07-28T15:48:44.877Z" }, + { url = "https://files.pythonhosted.org/packages/8d/a6/28975479e35ddc751dc1ddc97b9b69bf7fcf074db31548aab37f8116674c/tokenizers-0.21.4-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:5e2f601a8e0cd5be5cc7506b20a79112370b9b3e9cb5f13f68ab11acd6ca7d60", size = 2732457, upload-time = "2025-07-28T15:48:43.265Z" }, + { url = "https://files.pythonhosted.org/packages/aa/8f/24f39d7b5c726b7b0be95dca04f344df278a3fe3a4deb15a975d194cbb32/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b376f5a1aee67b4d29032ee85511bbd1b99007ec735f7f35c8a2eb104eade5", size = 3012624, upload-time = "2025-07-28T13:22:43.895Z" }, + { url = "https://files.pythonhosted.org/packages/58/47/26358925717687a58cb74d7a508de96649544fad5778f0cd9827398dc499/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2107ad649e2cda4488d41dfd031469e9da3fcbfd6183e74e4958fa729ffbf9c6", size = 2939681, upload-time = "2025-07-28T13:22:47.499Z" }, + { url = "https://files.pythonhosted.org/packages/99/6f/cc300fea5db2ab5ddc2c8aea5757a27b89c84469899710c3aeddc1d39801/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c73012da95afafdf235ba80047699df4384fdc481527448a078ffd00e45a7d9", size = 3247445, upload-time = "2025-07-28T15:48:39.711Z" }, + { url = "https://files.pythonhosted.org/packages/be/bf/98cb4b9c3c4afd8be89cfa6423704337dc20b73eb4180397a6e0d456c334/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f23186c40395fc390d27f519679a58023f368a0aad234af145e0f39ad1212732", size = 3428014, upload-time = "2025-07-28T13:22:49.569Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/96c1cc780e6ca7f01a57c13235dd05b7bc1c0f3588512ebe9d1331b5f5ae/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cc88bb34e23a54cc42713d6d98af5f1bf79c07653d24fe984d2d695ba2c922a2", size = 3193197, upload-time = "2025-07-28T13:22:51.471Z" }, + { url = "https://files.pythonhosted.org/packages/f2/90/273b6c7ec78af547694eddeea9e05de771278bd20476525ab930cecaf7d8/tokenizers-0.21.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51b7eabb104f46c1c50b486520555715457ae833d5aee9ff6ae853d1130506ff", size = 3115426, upload-time = "2025-07-28T15:48:41.439Z" }, + { url = "https://files.pythonhosted.org/packages/91/43/c640d5a07e95f1cf9d2c92501f20a25f179ac53a4f71e1489a3dcfcc67ee/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:714b05b2e1af1288bd1bc56ce496c4cebb64a20d158ee802887757791191e6e2", size = 9089127, upload-time = "2025-07-28T15:48:46.472Z" }, + { url = "https://files.pythonhosted.org/packages/44/a1/dd23edd6271d4dca788e5200a807b49ec3e6987815cd9d0a07ad9c96c7c2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:1340ff877ceedfa937544b7d79f5b7becf33a4cfb58f89b3b49927004ef66f78", size = 9055243, upload-time = "2025-07-28T15:48:48.539Z" }, + { url = "https://files.pythonhosted.org/packages/21/2b/b410d6e9021c4b7ddb57248304dc817c4d4970b73b6ee343674914701197/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:3c1f4317576e465ac9ef0d165b247825a2a4078bcd01cba6b54b867bdf9fdd8b", size = 9298237, upload-time = "2025-07-28T15:48:50.443Z" }, + { url = "https://files.pythonhosted.org/packages/b7/0a/42348c995c67e2e6e5c89ffb9cfd68507cbaeb84ff39c49ee6e0a6dd0fd2/tokenizers-0.21.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:c212aa4e45ec0bb5274b16b6f31dd3f1c41944025c2358faaa5782c754e84c24", size = 9461980, upload-time = "2025-07-28T15:48:52.325Z" }, + { url = "https://files.pythonhosted.org/packages/3d/d3/dacccd834404cd71b5c334882f3ba40331ad2120e69ded32cf5fda9a7436/tokenizers-0.21.4-cp39-abi3-win32.whl", hash = "sha256:6c42a930bc5f4c47f4ea775c91de47d27910881902b0f20e4990ebe045a415d0", size = 2329871, upload-time = "2025-07-28T15:48:56.841Z" }, + { url = "https://files.pythonhosted.org/packages/41/f2/fd673d979185f5dcbac4be7d09461cbb99751554ffb6718d0013af8604cb/tokenizers-0.21.4-cp39-abi3-win_amd64.whl", hash = "sha256:475d807a5c3eb72c59ad9b5fcdb254f6e17f53dfcbb9903233b0dfa9c943b597", size = 2507568, upload-time = "2025-07-28T15:48:55.456Z" }, +] + +[[package]] +name = "tornado" +version = "6.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/09/ce/1eb500eae19f4648281bb2186927bb062d2438c2e5093d1360391afd2f90/tornado-6.5.2.tar.gz", hash = "sha256:ab53c8f9a0fa351e2c0741284e06c7a45da86afb544133201c5cc8578eb076a0", size = 510821, upload-time = "2025-08-08T18:27:00.78Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f6/48/6a7529df2c9cc12efd2e8f5dd219516184d703b34c06786809670df5b3bd/tornado-6.5.2-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:2436822940d37cde62771cff8774f4f00b3c8024fe482e16ca8387b8a2724db6", size = 442563, upload-time = "2025-08-08T18:26:42.945Z" }, + { url = "https://files.pythonhosted.org/packages/f2/b5/9b575a0ed3e50b00c40b08cbce82eb618229091d09f6d14bce80fc01cb0b/tornado-6.5.2-cp39-abi3-macosx_10_9_x86_64.whl", hash = "sha256:583a52c7aa94ee046854ba81d9ebb6c81ec0fd30386d96f7640c96dad45a03ef", size = 440729, upload-time = "2025-08-08T18:26:44.473Z" }, + { url = "https://files.pythonhosted.org/packages/1b/4e/619174f52b120efcf23633c817fd3fed867c30bff785e2cd5a53a70e483c/tornado-6.5.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b0fe179f28d597deab2842b86ed4060deec7388f1fd9c1b4a41adf8af058907e", size = 444295, upload-time = "2025-08-08T18:26:46.021Z" }, + { url = "https://files.pythonhosted.org/packages/95/fa/87b41709552bbd393c85dd18e4e3499dcd8983f66e7972926db8d96aa065/tornado-6.5.2-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b186e85d1e3536d69583d2298423744740986018e393d0321df7340e71898882", size = 443644, upload-time = "2025-08-08T18:26:47.625Z" }, + { url = "https://files.pythonhosted.org/packages/f9/41/fb15f06e33d7430ca89420283a8762a4e6b8025b800ea51796ab5e6d9559/tornado-6.5.2-cp39-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e792706668c87709709c18b353da1f7662317b563ff69f00bab83595940c7108", size = 443878, upload-time = "2025-08-08T18:26:50.599Z" }, + { url = "https://files.pythonhosted.org/packages/11/92/fe6d57da897776ad2e01e279170ea8ae726755b045fe5ac73b75357a5a3f/tornado-6.5.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:06ceb1300fd70cb20e43b1ad8aaee0266e69e7ced38fa910ad2e03285009ce7c", size = 444549, upload-time = "2025-08-08T18:26:51.864Z" }, + { url = "https://files.pythonhosted.org/packages/9b/02/c8f4f6c9204526daf3d760f4aa555a7a33ad0e60843eac025ccfd6ff4a93/tornado-6.5.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:74db443e0f5251be86cbf37929f84d8c20c27a355dd452a5cfa2aada0d001ec4", size = 443973, upload-time = "2025-08-08T18:26:53.625Z" }, + { url = "https://files.pythonhosted.org/packages/ae/2d/f5f5707b655ce2317190183868cd0f6822a1121b4baeae509ceb9590d0bd/tornado-6.5.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b5e735ab2889d7ed33b32a459cac490eda71a1ba6857b0118de476ab6c366c04", size = 443954, upload-time = "2025-08-08T18:26:55.072Z" }, + { url = "https://files.pythonhosted.org/packages/e8/59/593bd0f40f7355806bf6573b47b8c22f8e1374c9b6fd03114bd6b7a3dcfd/tornado-6.5.2-cp39-abi3-win32.whl", hash = "sha256:c6f29e94d9b37a95013bb669616352ddb82e3bfe8326fccee50583caebc8a5f0", size = 445023, upload-time = "2025-08-08T18:26:56.677Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2a/f609b420c2f564a748a2d80ebfb2ee02a73ca80223af712fca591386cafb/tornado-6.5.2-cp39-abi3-win_amd64.whl", hash = "sha256:e56a5af51cc30dd2cae649429af65ca2f6571da29504a07995175df14c18f35f", size = 445427, upload-time = "2025-08-08T18:26:57.91Z" }, + { url = "https://files.pythonhosted.org/packages/5e/4f/e1f65e8f8c76d73658b33d33b81eed4322fb5085350e4328d5c956f0c8f9/tornado-6.5.2-cp39-abi3-win_arm64.whl", hash = "sha256:d6c33dc3672e3a1f3618eb63b7ef4683a7688e7b9e6e8f0d9aa5726360a004af", size = 444456, upload-time = "2025-08-08T18:26:59.207Z" }, +] + +[[package]] +name = "tqdm" +version = "4.67.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "colorama", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a8/4b/29b4ef32e036bb34e4ab51796dd745cdba7ed47ad142a9f4a1eb8e0c744d/tqdm-4.67.1.tar.gz", hash = "sha256:f8aef9c52c08c13a65f30ea34f4e5aac3fd1a34959879d7e59e63027286627f2", size = 169737, upload-time = "2024-11-24T20:12:22.481Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/30/dc54f88dd4a2b5dc8a0279bdd7270e735851848b762aeb1c1184ed1f6b14/tqdm-4.67.1-py3-none-any.whl", hash = "sha256:26445eca388f82e72884e0d580d5464cd801a3ea01e63e5601bdff9ba6a48de2", size = 78540, upload-time = "2024-11-24T20:12:19.698Z" }, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/eb/79/72064e6a701c2183016abbbfedaba506d81e30e232a68c9f0d6f6fcd1574/traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", size = 161621, upload-time = "2024-04-19T11:11:49.746Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/c0/8f5d070730d7836adc9c9b6408dec68c6ced86b304a9b26a14df072a6e8c/traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f", size = 85359, upload-time = "2024-04-19T11:11:46.763Z" }, +] + +[[package]] +name = "typer" +version = "0.16.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "rich" }, + { name = "shellingham" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/43/78/d90f616bf5f88f8710ad067c1f8705bf7618059836ca084e5bb2a0855d75/typer-0.16.1.tar.gz", hash = "sha256:d358c65a464a7a90f338e3bb7ff0c74ac081449e53884b12ba658cbd72990614", size = 102836, upload-time = "2025-08-18T19:18:22.898Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2d/76/06dbe78f39b2203d2a47d5facc5df5102d0561e2807396471b5f7c5a30a1/typer-0.16.1-py3-none-any.whl", hash = "sha256:90ee01cb02d9b8395ae21ee3368421faf21fa138cb2a541ed369c08cec5237c9", size = 46397, upload-time = "2025-08-18T19:18:21.663Z" }, +] + +[[package]] +name = "types-protobuf" +version = "6.30.2.20250809" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/9e/8777c578b5b66f6ef99ce9dac4865b51016a52b1d681942fbf75ac35d60f/types_protobuf-6.30.2.20250809.tar.gz", hash = "sha256:b04f2998edf0d81bd8600bbd5db0b2adf547837eef6362ba364925cee21a33b4", size = 62204, upload-time = "2025-08-09T03:14:07.547Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/9a/43daca708592570539888d80d6b708dff0b1795218aaf6b13057cc2e2c18/types_protobuf-6.30.2.20250809-py3-none-any.whl", hash = "sha256:7afc2d3f569d281dd22f339179577243be60bf7d1dfb4bc13d0109859fb1f1be", size = 76389, upload-time = "2025-08-09T03:14:06.531Z" }, +] + +[[package]] +name = "types-requests" +version = "2.31.0.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "types-urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f9/b8/c1e8d39996b4929b918aba10dba5de07a8b3f4c8487bb61bb79882544e69/types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0", size = 15535, upload-time = "2023-09-27T06:19:38.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/a1/6f8dc74d9069e790d604ddae70cb46dcbac668f1bb08136e7b0f2f5cd3bf/types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9", size = 14516, upload-time = "2023-09-27T06:19:36.373Z" }, +] + +[[package]] +name = "types-urllib3" +version = "1.26.25.14" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/73/de/b9d7a68ad39092368fb21dd6194b362b98a1daeea5dcfef5e1adb5031c7e/types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f", size = 11239, upload-time = "2023-07-20T15:19:31.307Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/7b/3fc711b2efea5e85a7a0bbfe269ea944aa767bbba5ec52f9ee45d362ccf3/types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e", size = 15377, upload-time = "2023-07-20T15:19:30.379Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.14.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, +] + +[[package]] +name = "tzdata" +version = "2025.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/95/32/1a225d6164441be760d75c2c42e2780dc0873fe382da3e98a2e1e48361e5/tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9", size = 196380, upload-time = "2025-03-23T13:54:43.652Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5c/23/c7abc0ca0a1526a0774eca151daeb8de62ec457e77262b66b359c3c7679e/tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8", size = 347839, upload-time = "2025-03-23T13:54:41.845Z" }, +] + +[[package]] +name = "tzlocal" +version = "5.3.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/8b/2e/c14812d3d4d9cd1773c6be938f89e5735a1f11a9f184ac3639b93cef35d5/tzlocal-5.3.1.tar.gz", hash = "sha256:cceffc7edecefea1f595541dbd6e990cb1ea3d19bf01b2809f362a03dd7921fd", size = 30761, upload-time = "2025-03-05T21:17:41.549Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c2/14/e2a54fabd4f08cd7af1c07030603c3356b74da07f7cc056e600436edfa17/tzlocal-5.3.1-py3-none-any.whl", hash = "sha256:eb1a66c3ef5847adf7a834f1be0800581b683b5608e74f86ecbcef8ab91bb85d", size = 18026, upload-time = "2025-03-05T21:17:39.857Z" }, +] + +[[package]] +name = "urllib3" +version = "1.26.20" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/e8/6ff5e6bc22095cfc59b6ea711b687e2b7ed4bdb373f7eeec370a97d7392f/urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32", size = 307380, upload-time = "2024-08-29T15:43:11.37Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/33/cf/8435d5a7159e2a9c83a95896ed596f68cf798005fe107cc655b5c5c14704/urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e", size = 144225, upload-time = "2024-08-29T15:43:08.921Z" }, +] + +[[package]] +name = "uvicorn" +version = "0.35.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, +] + +[[package]] +name = "watchfiles" +version = "0.24.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c8/27/2ba23c8cc85796e2d41976439b08d52f691655fdb9401362099502d1f0cf/watchfiles-0.24.0.tar.gz", hash = "sha256:afb72325b74fa7a428c009c1b8be4b4d7c2afedafb2982827ef2156646df2fe1", size = 37870, upload-time = "2024-08-28T16:21:37.42Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/82/92a7bb6dc82d183e304a5f84ae5437b59ee72d48cee805a9adda2488b237/watchfiles-0.24.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:7211b463695d1e995ca3feb38b69227e46dbd03947172585ecb0588f19b0d87a", size = 374137, upload-time = "2024-08-28T16:20:23.055Z" }, + { url = "https://files.pythonhosted.org/packages/87/91/49e9a497ddaf4da5e3802d51ed67ff33024597c28f652b8ab1e7c0f5718b/watchfiles-0.24.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4b8693502d1967b00f2fb82fc1e744df128ba22f530e15b763c8d82baee15370", size = 367733, upload-time = "2024-08-28T16:20:24.543Z" }, + { url = "https://files.pythonhosted.org/packages/0d/d8/90eb950ab4998effea2df4cf3a705dc594f6bc501c5a353073aa990be965/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdab9555053399318b953a1fe1f586e945bc8d635ce9d05e617fd9fe3a4687d6", size = 437322, upload-time = "2024-08-28T16:20:25.572Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a2/300b22e7bc2a222dd91fce121cefa7b49aa0d26a627b2777e7bdfcf1110b/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:34e19e56d68b0dad5cff62273107cf5d9fbaf9d75c46277aa5d803b3ef8a9e9b", size = 433409, upload-time = "2024-08-28T16:20:26.628Z" }, + { url = "https://files.pythonhosted.org/packages/99/44/27d7708a43538ed6c26708bcccdde757da8b7efb93f4871d4cc39cffa1cc/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:41face41f036fee09eba33a5b53a73e9a43d5cb2c53dad8e61fa6c9f91b5a51e", size = 452142, upload-time = "2024-08-28T16:20:28.003Z" }, + { url = "https://files.pythonhosted.org/packages/b0/ec/c4e04f755be003129a2c5f3520d2c47026f00da5ecb9ef1e4f9449637571/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5148c2f1ea043db13ce9b0c28456e18ecc8f14f41325aa624314095b6aa2e9ea", size = 469414, upload-time = "2024-08-28T16:20:29.55Z" }, + { url = "https://files.pythonhosted.org/packages/c5/4e/cdd7de3e7ac6432b0abf282ec4c1a1a2ec62dfe423cf269b86861667752d/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e4bd963a935aaf40b625c2499f3f4f6bbd0c3776f6d3bc7c853d04824ff1c9f", size = 472962, upload-time = "2024-08-28T16:20:31.314Z" }, + { url = "https://files.pythonhosted.org/packages/27/69/e1da9d34da7fc59db358424f5d89a56aaafe09f6961b64e36457a80a7194/watchfiles-0.24.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c79d7719d027b7a42817c5d96461a99b6a49979c143839fc37aa5748c322f234", size = 425705, upload-time = "2024-08-28T16:20:32.427Z" }, + { url = "https://files.pythonhosted.org/packages/e8/c1/24d0f7357be89be4a43e0a656259676ea3d7a074901f47022f32e2957798/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:32aa53a9a63b7f01ed32e316e354e81e9da0e6267435c7243bf8ae0f10b428ef", size = 612851, upload-time = "2024-08-28T16:20:33.527Z" }, + { url = "https://files.pythonhosted.org/packages/c7/af/175ba9b268dec56f821639c9893b506c69fd999fe6a2e2c51de420eb2f01/watchfiles-0.24.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ce72dba6a20e39a0c628258b5c308779b8697f7676c254a845715e2a1039b968", size = 594868, upload-time = "2024-08-28T16:20:34.639Z" }, + { url = "https://files.pythonhosted.org/packages/44/81/1f701323a9f70805bc81c74c990137123344a80ea23ab9504a99492907f8/watchfiles-0.24.0-cp312-none-win32.whl", hash = "sha256:d9018153cf57fc302a2a34cb7564870b859ed9a732d16b41a9b5cb2ebed2d444", size = 264109, upload-time = "2024-08-28T16:20:35.692Z" }, + { url = "https://files.pythonhosted.org/packages/b4/0b/32cde5bc2ebd9f351be326837c61bdeb05ad652b793f25c91cac0b48a60b/watchfiles-0.24.0-cp312-none-win_amd64.whl", hash = "sha256:551ec3ee2a3ac9cbcf48a4ec76e42c2ef938a7e905a35b42a1267fa4b1645896", size = 277055, upload-time = "2024-08-28T16:20:36.849Z" }, + { url = "https://files.pythonhosted.org/packages/4b/81/daade76ce33d21dbec7a15afd7479de8db786e5f7b7d249263b4ea174e08/watchfiles-0.24.0-cp312-none-win_arm64.whl", hash = "sha256:b52a65e4ea43c6d149c5f8ddb0bef8d4a1e779b77591a458a893eb416624a418", size = 266169, upload-time = "2024-08-28T16:20:38.149Z" }, + { url = "https://files.pythonhosted.org/packages/30/dc/6e9f5447ae14f645532468a84323a942996d74d5e817837a5c8ce9d16c69/watchfiles-0.24.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:3d2e3ab79a1771c530233cadfd277fcc762656d50836c77abb2e5e72b88e3a48", size = 373764, upload-time = "2024-08-28T16:20:39.263Z" }, + { url = "https://files.pythonhosted.org/packages/79/c0/c3a9929c372816c7fc87d8149bd722608ea58dc0986d3ef7564c79ad7112/watchfiles-0.24.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:327763da824817b38ad125dcd97595f942d720d32d879f6c4ddf843e3da3fe90", size = 367873, upload-time = "2024-08-28T16:20:40.399Z" }, + { url = "https://files.pythonhosted.org/packages/2e/11/ff9a4445a7cfc1c98caf99042df38964af12eed47d496dd5d0d90417349f/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd82010f8ab451dabe36054a1622870166a67cf3fce894f68895db6f74bbdc94", size = 438381, upload-time = "2024-08-28T16:20:41.371Z" }, + { url = "https://files.pythonhosted.org/packages/48/a3/763ba18c98211d7bb6c0f417b2d7946d346cdc359d585cc28a17b48e964b/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d64ba08db72e5dfd5c33be1e1e687d5e4fcce09219e8aee893a4862034081d4e", size = 432809, upload-time = "2024-08-28T16:20:42.504Z" }, + { url = "https://files.pythonhosted.org/packages/30/4c/616c111b9d40eea2547489abaf4ffc84511e86888a166d3a4522c2ba44b5/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1cf1f6dd7825053f3d98f6d33f6464ebdd9ee95acd74ba2c34e183086900a827", size = 451801, upload-time = "2024-08-28T16:20:43.696Z" }, + { url = "https://files.pythonhosted.org/packages/b6/be/d7da83307863a422abbfeb12903a76e43200c90ebe5d6afd6a59d158edea/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43e3e37c15a8b6fe00c1bce2473cfa8eb3484bbeecf3aefbf259227e487a03df", size = 468886, upload-time = "2024-08-28T16:20:44.847Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d3/3dfe131ee59d5e90b932cf56aba5c996309d94dafe3d02d204364c23461c/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88bcd4d0fe1d8ff43675360a72def210ebad3f3f72cabfeac08d825d2639b4ab", size = 472973, upload-time = "2024-08-28T16:20:45.991Z" }, + { url = "https://files.pythonhosted.org/packages/42/6c/279288cc5653a289290d183b60a6d80e05f439d5bfdfaf2d113738d0f932/watchfiles-0.24.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:999928c6434372fde16c8f27143d3e97201160b48a614071261701615a2a156f", size = 425282, upload-time = "2024-08-28T16:20:47.579Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d7/58afe5e85217e845edf26d8780c2d2d2ae77675eeb8d1b8b8121d799ce52/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:30bbd525c3262fd9f4b1865cb8d88e21161366561cd7c9e1194819e0a33ea86b", size = 612540, upload-time = "2024-08-28T16:20:48.915Z" }, + { url = "https://files.pythonhosted.org/packages/6d/d5/b96eeb9fe3fda137200dd2f31553670cbc731b1e13164fd69b49870b76ec/watchfiles-0.24.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:edf71b01dec9f766fb285b73930f95f730bb0943500ba0566ae234b5c1618c18", size = 593625, upload-time = "2024-08-28T16:20:50.543Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e5/c326fe52ee0054107267608d8cea275e80be4455b6079491dfd9da29f46f/watchfiles-0.24.0-cp313-none-win32.whl", hash = "sha256:f4c96283fca3ee09fb044f02156d9570d156698bc3734252175a38f0e8975f07", size = 263899, upload-time = "2024-08-28T16:20:51.759Z" }, + { url = "https://files.pythonhosted.org/packages/a6/8b/8a7755c5e7221bb35fe4af2dc44db9174f90ebf0344fd5e9b1e8b42d381e/watchfiles-0.24.0-cp313-none-win_amd64.whl", hash = "sha256:a974231b4fdd1bb7f62064a0565a6b107d27d21d9acb50c484d2cdba515b9366", size = 276622, upload-time = "2024-08-28T16:20:52.82Z" }, +] + +[[package]] +name = "wcwidth" +version = "0.2.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6c/63/53559446a878410fc5a5974feb13d31d78d752eb18aeba59c7fef1af7598/wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5", size = 101301, upload-time = "2024-01-06T02:10:57.829Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fd/84/fd2ba7aafacbad3c4201d395674fc6348826569da3c0937e75505ead3528/wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859", size = 34166, upload-time = "2024-01-06T02:10:55.763Z" }, +] + +[[package]] +name = "websocket-client" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e6/30/fba0d96b4b5fbf5948ed3f4681f7da2f9f64512e1d303f94b4cc174c24a5/websocket_client-1.8.0.tar.gz", hash = "sha256:3239df9f44da632f96012472805d40a23281a991027ce11d2f45a6f24ac4c3da", size = 54648, upload-time = "2024-04-23T22:16:16.976Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5a/84/44687a29792a70e111c5c477230a72c4b957d88d16141199bf9acb7537a3/websocket_client-1.8.0-py3-none-any.whl", hash = "sha256:17b44cc997f5c498e809b22cdf2d9c7a9e71c02c8cc2b6c56e7c2d1239bfa526", size = 58826, upload-time = "2024-04-23T22:16:14.422Z" }, +] + +[[package]] +name = "yarl" +version = "1.20.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, + { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, + { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, + { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, + { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, + { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, + { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, + { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, + { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, + { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, + { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, + { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, + { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, + { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, + { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, + { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, + { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, + { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, + { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, + { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, + { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, + { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, + { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, + { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, + { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, + { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, + { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, + { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, + { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, + { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, + { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, + { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, + { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, + { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, + { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, + { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, + { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, + { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, + { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, + { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, + { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, + { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, + { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, + { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, + { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, + { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, + { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, +] + +[[package]] +name = "zipp" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/02/0f2892c661036d50ede074e376733dca2ae7c6eb617489437771209d4180/zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166", size = 25547, upload-time = "2025-06-08T17:06:39.4Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/54/647ade08bf0db230bfea292f893923872fd20be6ac6f53b2b936ba839d75/zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e", size = 10276, upload-time = "2025-06-08T17:06:38.034Z" }, +]