From 90d3237cd32e562557d704f52d8a704571277be6 Mon Sep 17 00:00:00 2001 From: Luis Da Silva Date: Tue, 29 Jul 2025 05:03:53 +0100 Subject: [PATCH 01/40] Update README.md to reflect all samples (#215) Co-authored-by: tconley1428 --- hello/README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hello/README.md b/hello/README.md index f5dde687..c014d08c 100644 --- a/hello/README.md +++ b/hello/README.md @@ -17,14 +17,15 @@ Replace `hello/hello_activity.py` in the command with any other example filename * [hello_activity](hello_activity.py) - Execute an activity from a workflow. +* [hello_activity_async](hello_activity_async.py) - Execute an async activity from a workflow. * [hello_activity_choice](hello_activity_choice.py) - Execute certain activities inside a workflow based on dynamic input. * [hello_activity_method](hello_activity_method.py) - Demonstrate an activity that is an instance method on a class and can access class state. +* [hello_activity_heartbeat](hello_activity_heartbeat.py) - Demonstrate usage of heartbeat timeouts. * [hello_activity_multiprocess](hello_activity_multiprocess.py) - Execute a synchronous activity on a process pool. * [hello_activity_retry](hello_activity_retry.py) - Demonstrate activity retry by failing until a certain number of attempts. -* [hello_activity_threaded](hello_activity_threaded.py) - Execute a synchronous activity on a thread pool. * [hello_async_activity_completion](hello_async_activity_completion.py) - Complete an activity outside of the function that was called. * [hello_cancellation](hello_cancellation.py) - Manually react to cancellation inside workflows and activities. @@ -38,6 +39,7 @@ Replace `hello/hello_activity.py` in the command with any other example filename * [hello_mtls](hello_mtls.py) - Accept URL, namespace, and certificate info as CLI args and use mTLS for connecting to server. * [hello_parallel_activity](hello_parallel_activity.py) - Execute multiple activities at once. +* [hello_patch](hello_patch.py) - Demonstrates how to patch executions. * [hello_query](hello_query.py) - Invoke queries on a workflow. * [hello_search_attributes](hello_search_attributes.py) - Start workflow with search attributes then change while running. @@ -46,4 +48,4 @@ Replace `hello/hello_activity.py` in the command with any other example filename Note: To enable the workflow update, set the `frontend.enableUpdateWorkflowExecution` dynamic config value to true. - temporal server start-dev --dynamic-config-value frontend.enableUpdateWorkflowExecution=true \ No newline at end of file + temporal server start-dev --dynamic-config-value frontend.enableUpdateWorkflowExecution=true From 85e98431b49fcc2c9cc9842973209e1db0203f00 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 08:03:19 -0600 Subject: [PATCH 02/40] Update samples for 1.15 (#220) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * Update dependency to 1.15.0 release --------- Co-authored-by: Tim Conley --- openai_agents/run_agents_as_tools_workflow.py | 6 +- openai_agents/run_customer_service_client.py | 6 +- openai_agents/run_hello_world_workflow.py | 6 +- openai_agents/run_research_workflow.py | 6 +- openai_agents/run_tools_workflow.py | 6 +- openai_agents/run_worker.py | 63 +++--- pyproject.toml | 6 +- uv.lock | 212 ++++++++++++++++-- 8 files changed, 244 insertions(+), 67 deletions(-) diff --git a/openai_agents/run_agents_as_tools_workflow.py b/openai_agents/run_agents_as_tools_workflow.py index 9c37beb0..822ca709 100644 --- a/openai_agents/run_agents_as_tools_workflow.py +++ b/openai_agents/run_agents_as_tools_workflow.py @@ -1,7 +1,7 @@ import asyncio from temporalio.client import Client -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from openai_agents.workflows.agents_as_tools_workflow import AgentsAsToolsWorkflow @@ -10,7 +10,9 @@ async def main(): # Create client connected to server at the given address client = await Client.connect( "localhost:7233", - data_converter=pydantic_data_converter, + plugins=[ + OpenAIAgentsPlugin(), + ], ) # Execute a workflow diff --git a/openai_agents/run_customer_service_client.py b/openai_agents/run_customer_service_client.py index be081c1e..ef8aaf62 100644 --- a/openai_agents/run_customer_service_client.py +++ b/openai_agents/run_customer_service_client.py @@ -7,7 +7,7 @@ WorkflowUpdateFailedError, ) from temporalio.common import QueryRejectCondition -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from temporalio.service import RPCError, RPCStatusCode from openai_agents.workflows.customer_service_workflow import ( @@ -24,7 +24,9 @@ async def main(): # Create client connected to server at the given address client = await Client.connect( "localhost:7233", - data_converter=pydantic_data_converter, + plugins=[ + OpenAIAgentsPlugin(), + ], ) handle = client.get_workflow_handle(args.conversation_id) diff --git a/openai_agents/run_hello_world_workflow.py b/openai_agents/run_hello_world_workflow.py index 566d525a..9ec8833f 100644 --- a/openai_agents/run_hello_world_workflow.py +++ b/openai_agents/run_hello_world_workflow.py @@ -1,7 +1,7 @@ import asyncio from temporalio.client import Client -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from openai_agents.workflows.hello_world_workflow import HelloWorldAgent @@ -10,7 +10,9 @@ async def main(): # Create client connected to server at the given address client = await Client.connect( "localhost:7233", - data_converter=pydantic_data_converter, + plugins=[ + OpenAIAgentsPlugin(), + ], ) # Execute a workflow diff --git a/openai_agents/run_research_workflow.py b/openai_agents/run_research_workflow.py index 136874db..5279648e 100644 --- a/openai_agents/run_research_workflow.py +++ b/openai_agents/run_research_workflow.py @@ -1,7 +1,7 @@ import asyncio from temporalio.client import Client -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from openai_agents.workflows.research_bot_workflow import ResearchWorkflow @@ -10,7 +10,9 @@ async def main(): # Create client connected to server at the given address client = await Client.connect( "localhost:7233", - data_converter=pydantic_data_converter, + plugins=[ + OpenAIAgentsPlugin(), + ], ) # Execute a workflow diff --git a/openai_agents/run_tools_workflow.py b/openai_agents/run_tools_workflow.py index 2635be6f..cfb3d811 100644 --- a/openai_agents/run_tools_workflow.py +++ b/openai_agents/run_tools_workflow.py @@ -1,7 +1,7 @@ import asyncio from temporalio.client import Client -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from openai_agents.workflows.tools_workflow import ToolsWorkflow @@ -10,7 +10,9 @@ async def main(): # Create client connected to server at the given address client = await Client.connect( "localhost:7233", - data_converter=pydantic_data_converter, + plugins=[ + OpenAIAgentsPlugin(), + ], ) # Execute a workflow diff --git a/openai_agents/run_worker.py b/openai_agents/run_worker.py index 9dbaef91..b17fbd0f 100644 --- a/openai_agents/run_worker.py +++ b/openai_agents/run_worker.py @@ -4,13 +4,7 @@ from datetime import timedelta from temporalio.client import Client -from temporalio.contrib.openai_agents import ( - ModelActivity, - ModelActivityParameters, - OpenAIAgentsTracingInterceptor, - set_open_ai_agent_temporal_overrides, -) -from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin from temporalio.worker import Worker from openai_agents.workflows.agents_as_tools_workflow import AgentsAsToolsWorkflow @@ -22,34 +16,33 @@ async def main(): - with set_open_ai_agent_temporal_overrides( - model_params=ModelActivityParameters( - start_to_close_timeout=timedelta(seconds=60), - ), - ): - # Create client connected to server at the given address - client = await Client.connect( - "localhost:7233", - data_converter=pydantic_data_converter, - ) - - worker = Worker( - client, - task_queue="openai-agents-task-queue", - workflows=[ - HelloWorldAgent, - ToolsWorkflow, - ResearchWorkflow, - CustomerServiceWorkflow, - AgentsAsToolsWorkflow, - ], - activities=[ - ModelActivity().invoke_model_activity, - get_weather, - ], - interceptors=[OpenAIAgentsTracingInterceptor()], - ) - await worker.run() + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=120) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-task-queue", + workflows=[ + HelloWorldAgent, + ToolsWorkflow, + ResearchWorkflow, + CustomerServiceWorkflow, + AgentsAsToolsWorkflow, + ], + activities=[ + get_weather, + ], + ) + await worker.run() if __name__ == "__main__": diff --git a/pyproject.toml b/pyproject.toml index 620bbc52..077dc912 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.14.1,<2"] +dependencies = ["temporalio>=1.15.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" @@ -55,8 +55,8 @@ open-telemetry = [ "opentelemetry-exporter-otlp-proto-grpc", ] openai-agents = [ - "openai-agents >= 0.0.19", - "temporalio[openai-agents] >= 1.14.1", + "openai-agents[litellm] >= 0.2.3", + "temporalio[openai-agents] >= 1.15.0", ] pydantic-converter = ["pydantic>=2.10.6,<3"] sentry = ["sentry-sdk>=1.11.0,<2"] diff --git a/uv.lock b/uv.lock index 99aaf356..8fc1c4b4 100644 --- a/uv.lock +++ b/uv.lock @@ -435,6 +435,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, ] +[[package]] +name = "filelock" +version = "3.18.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, +] + [[package]] name = "frozenlist" version = "1.7.0" @@ -529,6 +538,15 @@ wheels = [ { 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 = "gevent" version = "25.4.2" @@ -709,6 +727,21 @@ 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.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, + { url = "https://files.pythonhosted.org/packages/de/5f/2c78e28f309396e71ec8e4e9304a6483dcbc36172b5cea8f291994163425/hf_xet-1.1.5-cp37-abi3-macosx_11_0_arm64.whl", hash = "sha256:9fa6e3ee5d61912c4a113e0708eaaef987047616465ac7aa30f7121a48fc1af8", size = 2556338, upload-time = "2025-06-20T21:48:30.079Z" }, + { url = "https://files.pythonhosted.org/packages/6d/2f/6cad7b5fe86b7652579346cb7f85156c11761df26435651cbba89376cd2c/hf_xet-1.1.5-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc874b5c843e642f45fd85cda1ce599e123308ad2901ead23d3510a47ff506d1", size = 3102894, upload-time = "2025-06-20T21:48:28.114Z" }, + { url = "https://files.pythonhosted.org/packages/d0/54/0fcf2b619720a26fbb6cc941e89f2472a522cd963a776c089b189559447f/hf_xet-1.1.5-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:dbba1660e5d810bd0ea77c511a99e9242d920790d0e63c0e4673ed36c4022d18", size = 3002134, upload-time = "2025-06-20T21:48:25.906Z" }, + { url = "https://files.pythonhosted.org/packages/f3/92/1d351ac6cef7c4ba8c85744d37ffbfac2d53d0a6c04d2cabeba614640a78/hf_xet-1.1.5-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ab34c4c3104133c495785d5d8bba3b1efc99de52c02e759cf711a91fd39d3a14", size = 3171009, upload-time = "2025-06-20T21:48:33.987Z" }, + { url = "https://files.pythonhosted.org/packages/c9/65/4b2ddb0e3e983f2508528eb4501288ae2f84963586fbdfae596836d5e57a/hf_xet-1.1.5-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:83088ecea236d5113de478acb2339f92c95b4fb0462acaa30621fac02f5a534a", size = 3279245, upload-time = "2025-06-20T21:48:36.051Z" }, + { url = "https://files.pythonhosted.org/packages/f0/55/ef77a85ee443ae05a9e9cba1c9f0dd9241eb42da2aeba1dc50f51154c81a/hf_xet-1.1.5-cp37-abi3-win_amd64.whl", hash = "sha256:73e167d9807d166596b4b2f0b585c6d5bd84a26dea32843665a8b58f6edba245", size = 2738931, upload-time = "2025-06-20T21:48:39.482Z" }, +] + [[package]] name = "httpcore" version = "1.0.9" @@ -782,6 +815,25 @@ 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.1" +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/22/cd/841bc8e0550d69f632a15cdd70004e95ba92cd0fbe13087d6669e2bb5f44/huggingface_hub-0.34.1.tar.gz", hash = "sha256:6978ed89ef981de3c78b75bab100a214843be1cc9d24f8e9c0dc4971808ef1b1", size = 456783, upload-time = "2025-07-25T14:54:54.758Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/8c/cf/dd53c0132f50f258b06dd37a4616817b1f1f6a6b38382c06effd04bb6881/huggingface_hub-0.34.1-py3-none-any.whl", hash = "sha256:60d843dcb7bc335145b20e7d2f1dfe93910f6787b2b38a936fb772ce2a83757c", size = 558788, upload-time = "2025-07-25T14:54:52.957Z" }, +] + [[package]] name = "idna" version = "3.10" @@ -821,6 +873,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, ] +[[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" @@ -1054,6 +1118,28 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/f0/63b06b99b730b9954f8709f6f7d9b8d076fa0a973e472efe278089bde42b/langsmith-0.1.147-py3-none-any.whl", hash = "sha256:7166fc23b965ccf839d64945a78e9f1157757add228b086141eb03a60d699a15", size = 311812, upload-time = "2024-11-27T17:32:39.569Z" }, ] +[[package]] +name = "litellm" +version = "1.74.8" +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/c0/16/89c5123c808cbc51e398afc2f1a56da1d75d5e8ef7be417895a3794f0416/litellm-1.74.8.tar.gz", hash = "sha256:6e0a18aecf62459d465ee6d9a2526fcb33719a595b972500519abe95fe4906e0", size = 9639701, upload-time = "2025-07-23T23:38:02.903Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/af/4a/eba1b617acb7fa597d169cdd1b5ce98502bd179138f130721a2367d2deb8/litellm-1.74.8-py3-none-any.whl", hash = "sha256:f9433207d1e12e545495e5960fe02d93e413ecac4a28225c522488e1ab1157a1", size = 8713698, upload-time = "2025-07-23T23:38:00.708Z" }, +] + [[package]] name = "markdown-it-py" version = "3.0.0" @@ -1066,6 +1152,64 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, ] +[[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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, + { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, + { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, + { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, + { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, + { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, + { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, + { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, + { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, + { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, + { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, + { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, + { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, + { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, + { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, + { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, + { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, + { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, + { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, + { 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 = "marshmallow" version = "3.26.1" @@ -1314,7 +1458,7 @@ wheels = [ [[package]] name = "openai" -version = "1.95.0" +version = "1.97.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, @@ -1326,14 +1470,14 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ef/2f/0c6f509a1585545962bfa6e201d7fb658eb2a6f52fb8c26765632d91706c/openai-1.95.0.tar.gz", hash = "sha256:54bc42df9f7142312647dd485d34cca5df20af825fa64a30ca55164be2cf4cc9", size = 488144, upload-time = "2025-07-10T18:35:49.946Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/57/1c471f6b3efb879d26686d31582997615e969f3bb4458111c9705e56332e/openai-1.97.1.tar.gz", hash = "sha256:a744b27ae624e3d4135225da9b1c89c107a2a7e5bc4c93e5b7b5214772ce7a4e", size = 494267, upload-time = "2025-07-22T13:10:12.607Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/19/a5/57d0bb58b938a3e3f352ff26e645da1660436402a6ad1b29780d261cc5a5/openai-1.95.0-py3-none-any.whl", hash = "sha256:a7afc9dca7e7d616371842af8ea6dbfbcb739a85d183f5f664ab1cc311b9ef18", size = 755572, upload-time = "2025-07-10T18:35:47.507Z" }, + { url = "https://files.pythonhosted.org/packages/ee/35/412a0e9c3f0d37c94ed764b8ac7adae2d834dbd20e69f6aca582118e0f55/openai-1.97.1-py3-none-any.whl", hash = "sha256:4e96bbdf672ec3d44968c9ea39d2c375891db1acc1794668d8149d5fa6000606", size = 764380, upload-time = "2025-07-22T13:10:10.689Z" }, ] [[package]] name = "openai-agents" -version = "0.1.0" +version = "0.2.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, @@ -1344,9 +1488,14 @@ dependencies = [ { name = "types-requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/99/f8/a292d8f506997355755d88db619966539ec838ce18f070c5a101e5a430ec/openai_agents-0.1.0.tar.gz", hash = "sha256:a697a4fdd881a7a16db8c0dcafba0f17d9e90b6236a4b79923bd043b6ae86d80", size = 1379588, upload-time = "2025-06-27T20:58:03.186Z" } +sdist = { url = "https://files.pythonhosted.org/packages/e3/17/1f9eefb99fde956e5912a00fbdd03d50ebc734cc45a80b8fe4007d3813c2/openai_agents-0.2.3.tar.gz", hash = "sha256:95d4ad194c5c0cf1a40038cb701eee8ecdaaf7698d87bb13e3c2c5cff80c4b4d", size = 1464947, upload-time = "2025-07-21T19:34:20.595Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/31/5b/326e6b1b661dbef718977a8379f9702a4eec1df772450517870beeb3af35/openai_agents-0.1.0-py3-none-any.whl", hash = "sha256:6a8ef71d3f20aecba0f01bca2e059590d1c23f5adc02d780cb5921ea8a7ca774", size = 130620, upload-time = "2025-06-27T20:58:01.461Z" }, + { url = "https://files.pythonhosted.org/packages/eb/a7/d6bdf69a54c15d237a2be979981f33dab8f5da53f9bc2e734fb2b58592ca/openai_agents-0.2.3-py3-none-any.whl", hash = "sha256:15c5602de7076a5df6d11f07a18ffe0cf4f6811f6135b301acdd1998398a6d5c", size = 161393, upload-time = "2025-07-21T19:34:18.883Z" }, +] + +[package.optional-dependencies] +litellm = [ + { name = "litellm" }, ] [[package]] @@ -2447,7 +2596,7 @@ wheels = [ [[package]] name = "temporalio" -version = "1.14.1" +version = "1.15.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, @@ -2456,13 +2605,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/40/23/ef5ed581d26112e21c4a6d4ddc2c4eaa5700c0d70b53b07566553e9b7d90/temporalio-1.14.1.tar.gz", hash = "sha256:b240cf56f64add65beb75bd18aa854ac35bdc2505097af5af1e235d611190a9d", size = 1607639, upload-time = "2025-07-10T20:56:43.485Z" } +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/bd/66/6dc4f5a647a9901cf19e012c442173574babdc879ccaf4cb166662a23ef0/temporalio-1.14.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ebde00b59af72e512e5837445e4b5b8aa445431d57a71bbeb57a5ba8a93ac8be", size = 12508009, upload-time = "2025-07-10T20:56:30.653Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/654ebcc92c658180576127ac6dc047fab43b7730f39df4439645e91577fb/temporalio-1.14.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:3c21cff8fdc60fbcc9acd91e6c119b0b5f9de7671fe806459f00d68bd4ecae78", size = 12091653, upload-time = "2025-07-10T20:56:33.199Z" }, - { url = "https://files.pythonhosted.org/packages/8a/58/7fc3a7bde275c059e42d0279c54e8e66642b67be8eda21b31347f4277186/temporalio-1.14.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f984b503ae741213fe71128d6193076f3267691561ff3c55dbe798f92e6ee1b", size = 12451995, upload-time = "2025-07-10T20:56:36.055Z" }, - { url = "https://files.pythonhosted.org/packages/98/12/14f6a7a1f4aebb7d846469f5c1cd165cce55b793ded6ce5fc315bd83e28f/temporalio-1.14.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:830cb1a820624a5e64f6c874b5aca6ad9eb841295407dd2011074159a2d28bdb", size = 12688904, upload-time = "2025-07-10T20:56:38.501Z" }, - { url = "https://files.pythonhosted.org/packages/b4/ed/c09f1ca41d5ed9f9a777a0ddd5bc225f8300bab8b42bc6751195566706fb/temporalio-1.14.1-cp39-abi3-win_amd64.whl", hash = "sha256:ad4e6a16b42bb34aebec62fb8bbe8f64643d8268ed6d7db337dfe98a76799bb0", size = 12758696, upload-time = "2025-07-10T20:56:41.266Z" }, + { 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.optional-dependencies] @@ -2533,7 +2682,7 @@ open-telemetry = [ { name = "temporalio", extra = ["opentelemetry"] }, ] openai-agents = [ - { name = "openai-agents" }, + { name = "openai-agents", extra = ["litellm"] }, { name = "temporalio", extra = ["openai-agents"] }, ] pydantic-converter = [ @@ -2548,14 +2697,14 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.14.1,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.15.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] cloud-export-to-parquet = [ { name = "boto3", specifier = ">=1.34.89,<2" }, - { name = "numpy", marker = "python_full_version >= '3.9' and python_full_version < '3.13'", specifier = ">=1.26.0,<2" }, - { name = "pandas", marker = "python_full_version >= '3.9' and python_full_version < '4'", specifier = ">=2.2.2,<3" }, + { name = "numpy", marker = "python_full_version >= '3.10' and python_full_version < '3.13'", specifier = ">=1.26.0,<2" }, + { name = "pandas", marker = "python_full_version >= '3.10' and python_full_version < '4'", specifier = ">=2.2.2,<3" }, { name = "pyarrow", specifier = ">=19.0.1" }, ] dev = [ @@ -2595,8 +2744,8 @@ open-telemetry = [ { name = "temporalio", extras = ["opentelemetry"] }, ] openai-agents = [ - { name = "openai-agents", specifier = ">=0.0.19" }, - { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.14.1" }, + { name = "openai-agents", extras = ["litellm"], specifier = ">=0.2.3" }, + { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.15.0" }, ] pydantic-converter = [{ name = "pydantic", specifier = ">=2.10.6,<3" }] sentry = [{ name = "sentry-sdk", specifier = ">=1.11.0,<2" }] @@ -2650,6 +2799,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/de/a8/8f499c179ec900783ffe133e9aab10044481679bb9aad78436d239eee716/tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95", size = 894669, upload-time = "2025-02-14T06:02:47.341Z" }, ] +[[package]] +name = "tokenizers" +version = "0.21.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "huggingface-hub" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ab/2d/b0fce2b8201635f60e8c95990080f58461cc9ca3d5026de2e900f38a7f21/tokenizers-0.21.2.tar.gz", hash = "sha256:fdc7cffde3e2113ba0e6cc7318c40e3438a4d74bbc62bf04bcc63bdfb082ac77", size = 351545, upload-time = "2025-06-24T10:24:52.449Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1d/cc/2936e2d45ceb130a21d929743f1e9897514691bec123203e10837972296f/tokenizers-0.21.2-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:342b5dfb75009f2255ab8dec0041287260fed5ce00c323eb6bab639066fef8ec", size = 2875206, upload-time = "2025-06-24T10:24:42.755Z" }, + { url = "https://files.pythonhosted.org/packages/6c/e6/33f41f2cc7861faeba8988e7a77601407bf1d9d28fc79c5903f8f77df587/tokenizers-0.21.2-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:126df3205d6f3a93fea80c7a8a266a78c1bd8dd2fe043386bafdd7736a23e45f", size = 2732655, upload-time = "2025-06-24T10:24:41.56Z" }, + { url = "https://files.pythonhosted.org/packages/33/2b/1791eb329c07122a75b01035b1a3aa22ad139f3ce0ece1b059b506d9d9de/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a32cd81be21168bd0d6a0f0962d60177c447a1aa1b1e48fa6ec9fc728ee0b12", size = 3019202, upload-time = "2025-06-24T10:24:31.791Z" }, + { url = "https://files.pythonhosted.org/packages/05/15/fd2d8104faa9f86ac68748e6f7ece0b5eb7983c7efc3a2c197cb98c99030/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8bd8999538c405133c2ab999b83b17c08b7fc1b48c1ada2469964605a709ef91", size = 2934539, upload-time = "2025-06-24T10:24:34.567Z" }, + { url = "https://files.pythonhosted.org/packages/a5/2e/53e8fd053e1f3ffbe579ca5f9546f35ac67cf0039ed357ad7ec57f5f5af0/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5e9944e61239b083a41cf8fc42802f855e1dca0f499196df37a8ce219abac6eb", size = 3248665, upload-time = "2025-06-24T10:24:39.024Z" }, + { url = "https://files.pythonhosted.org/packages/00/15/79713359f4037aa8f4d1f06ffca35312ac83629da062670e8830917e2153/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:514cd43045c5d546f01142ff9c79a96ea69e4b5cda09e3027708cb2e6d5762ab", size = 3451305, upload-time = "2025-06-24T10:24:36.133Z" }, + { url = "https://files.pythonhosted.org/packages/38/5f/959f3a8756fc9396aeb704292777b84f02a5c6f25c3fc3ba7530db5feb2c/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b1b9405822527ec1e0f7d8d2fdb287a5730c3a6518189c968254a8441b21faae", size = 3214757, upload-time = "2025-06-24T10:24:37.784Z" }, + { url = "https://files.pythonhosted.org/packages/c5/74/f41a432a0733f61f3d21b288de6dfa78f7acff309c6f0f323b2833e9189f/tokenizers-0.21.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed9a4d51c395103ad24f8e7eb976811c57fbec2af9f133df471afcd922e5020", size = 3121887, upload-time = "2025-06-24T10:24:40.293Z" }, + { url = "https://files.pythonhosted.org/packages/3c/6a/bc220a11a17e5d07b0dfb3b5c628621d4dcc084bccd27cfaead659963016/tokenizers-0.21.2-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c41862df3d873665ec78b6be36fcc30a26e3d4902e9dd8608ed61d49a48bc19", size = 9091965, upload-time = "2025-06-24T10:24:44.431Z" }, + { url = "https://files.pythonhosted.org/packages/6c/bd/ac386d79c4ef20dc6f39c4706640c24823dca7ebb6f703bfe6b5f0292d88/tokenizers-0.21.2-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:ed21dc7e624e4220e21758b2e62893be7101453525e3d23264081c9ef9a6d00d", size = 9053372, upload-time = "2025-06-24T10:24:46.455Z" }, + { url = "https://files.pythonhosted.org/packages/63/7b/5440bf203b2a5358f074408f7f9c42884849cd9972879e10ee6b7a8c3b3d/tokenizers-0.21.2-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:0e73770507e65a0e0e2a1affd6b03c36e3bc4377bd10c9ccf51a82c77c0fe365", size = 9298632, upload-time = "2025-06-24T10:24:48.446Z" }, + { url = "https://files.pythonhosted.org/packages/a4/d2/faa1acac3f96a7427866e94ed4289949b2524f0c1878512516567d80563c/tokenizers-0.21.2-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:106746e8aa9014a12109e58d540ad5465b4c183768ea96c03cbc24c44d329958", size = 9470074, upload-time = "2025-06-24T10:24:50.378Z" }, + { url = "https://files.pythonhosted.org/packages/d8/a5/896e1ef0707212745ae9f37e84c7d50269411aef2e9ccd0de63623feecdf/tokenizers-0.21.2-cp39-abi3-win32.whl", hash = "sha256:cabda5a6d15d620b6dfe711e1af52205266d05b379ea85a8a301b3593c60e962", size = 2330115, upload-time = "2025-06-24T10:24:55.069Z" }, + { url = "https://files.pythonhosted.org/packages/13/c3/cc2755ee10be859c4338c962a35b9a663788c0c0b50c0bdd8078fb6870cf/tokenizers-0.21.2-cp39-abi3-win_amd64.whl", hash = "sha256:58747bb898acdb1007f37a7bbe614346e98dc28708ffb66a3fd50ce169ac6c98", size = 2509918, upload-time = "2025-06-24T10:24:53.71Z" }, +] + [[package]] name = "tomli" version = "2.2.1" From f738fcdaa28408d75e6a6951e87024c05435949c Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 16:00:40 -0600 Subject: [PATCH 03/40] Reorganize OpenAI samples (#221) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * Reset uv.lock --------- Co-authored-by: Tim Conley --- openai_agents/README.md | 41 ++--------- openai_agents/agent_patterns/README.md | 68 +++++++++++++++++++ .../run_agents_as_tools_workflow.py | 4 +- openai_agents/agent_patterns/run_worker.py | 39 +++++++++++ .../workflows/agents_as_tools_workflow.py | 0 openai_agents/basic/README.md | 25 +++++++ .../activities}/get_weather_activity.py | 0 .../{ => basic}/run_hello_world_workflow.py | 2 +- .../{ => basic}/run_tools_workflow.py | 2 +- openai_agents/{ => basic}/run_worker.py | 14 ++-- .../workflows/hello_world_workflow.py | 0 .../{ => basic}/workflows/tools_workflow.py | 2 +- openai_agents/customer_service/README.md | 21 ++++++ .../customer_service.py | 0 .../run_customer_service_client.py | 2 +- openai_agents/customer_service/run_worker.py | 39 +++++++++++ .../workflows/customer_service_workflow.py | 2 +- openai_agents/research_bot/README.md | 35 ++++++++++ .../agents}/planner_agent.py | 0 .../agents}/research_manager.py | 6 +- .../agents}/search_agent.py | 0 .../agents}/writer_agent.py | 0 .../run_research_workflow.py | 2 +- openai_agents/research_bot/run_worker.py | 37 ++++++++++ .../workflows/research_bot_workflow.py | 2 +- openai_agents/workflows/__init__.py | 0 .../workflows/research_agents/__init__.py | 0 27 files changed, 287 insertions(+), 56 deletions(-) create mode 100644 openai_agents/agent_patterns/README.md rename openai_agents/{ => agent_patterns}/run_agents_as_tools_workflow.py (85%) create mode 100644 openai_agents/agent_patterns/run_worker.py rename openai_agents/{ => agent_patterns}/workflows/agents_as_tools_workflow.py (100%) create mode 100644 openai_agents/basic/README.md rename openai_agents/{workflows => basic/activities}/get_weather_activity.py (100%) rename openai_agents/{ => basic}/run_hello_world_workflow.py (89%) rename openai_agents/{ => basic}/run_tools_workflow.py (89%) rename openai_agents/{ => basic}/run_worker.py (58%) rename openai_agents/{ => basic}/workflows/hello_world_workflow.py (100%) rename openai_agents/{ => basic}/workflows/tools_workflow.py (90%) create mode 100644 openai_agents/customer_service/README.md rename openai_agents/{workflows => customer_service}/customer_service.py (100%) rename openai_agents/{ => customer_service}/run_customer_service_client.py (96%) create mode 100644 openai_agents/customer_service/run_worker.py rename openai_agents/{ => customer_service}/workflows/customer_service_workflow.py (98%) create mode 100644 openai_agents/research_bot/README.md rename openai_agents/{workflows/research_agents => research_bot/agents}/planner_agent.py (100%) rename openai_agents/{workflows/research_agents => research_bot/agents}/research_manager.py (91%) rename openai_agents/{workflows/research_agents => research_bot/agents}/search_agent.py (100%) rename openai_agents/{workflows/research_agents => research_bot/agents}/writer_agent.py (100%) rename openai_agents/{ => research_bot}/run_research_workflow.py (88%) create mode 100644 openai_agents/research_bot/run_worker.py rename openai_agents/{ => research_bot}/workflows/research_bot_workflow.py (68%) delete mode 100644 openai_agents/workflows/__init__.py delete mode 100644 openai_agents/workflows/research_agents/__init__.py diff --git a/openai_agents/README.md b/openai_agents/README.md index 1eceb747..96975ec2 100644 --- a/openai_agents/README.md +++ b/openai_agents/README.md @@ -21,42 +21,13 @@ This approach ensures that AI agent workflows are durable, observable, and can h - Required dependencies installed via `uv sync --group openai-agents` - OpenAI API key set as environment variable: `export OPENAI_API_KEY=your_key_here` -## Running the Examples +## Examples -1. **Start the worker** (supports all samples): - ```bash - uv run openai_agents/run_worker.py - ``` +Each directory contains a complete example with its own README for detailed instructions: -2. **Run individual samples** in separate terminals: +- **[Basic Examples](./basic/README.md)** - Simple agent examples including a hello world agent and a tools-enabled agent that can access external APIs like weather services. +- **[Agent Patterns](./agent_patterns/README.md)** - Advanced patterns for agent composition, including using agents as tools within other agents. +- **[Research Bot](./research_bot/README.md)** - Multi-agent research system with specialized roles: a planner agent, search agent, and writer agent working together to conduct comprehensive research. +- **[Customer Service](./customer_service/README.md)** - Interactive customer service agent with escalation capabilities, demonstrating conversational workflows. -### Basic Agent Examples - -- **Hello World Agent** - Simple agent that responds in haikus: - ```bash - uv run openai_agents/run_hello_world_workflow.py - ``` - -- **Tools Agent** - Agent with access to external tools (weather API): - ```bash - uv run openai_agents/run_tools_workflow.py - ``` - -### Advanced Multi-Agent Examples - -- **Research Workflow** - Multi-agent research system with specialized roles: - ```bash - uv run openai_agents/run_research_workflow.py - ``` - Features a planner agent, search agent, and writer agent working together. - -- **Customer Service Workflow** - Customer service agent with escalation capabilities (interactive): - ```bash - uv run openai_agents/run_customer_service_client.py --conversation-id my-conversation-123 - ``` - -- **Agents as Tools** - Demonstrate using agents as tools within other agents: - ```bash - uv run openai_agents/run_agents_as_tools_workflow.py - ``` diff --git a/openai_agents/agent_patterns/README.md b/openai_agents/agent_patterns/README.md new file mode 100644 index 00000000..26867f10 --- /dev/null +++ b/openai_agents/agent_patterns/README.md @@ -0,0 +1,68 @@ +# Agent Patterns + +Common agentic patterns extended with Temporal's durable execution capabilities. + +*Adapted from [OpenAI Agents SDK agent patterns](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns)* + +## Running the Examples + +First, start the worker (supports all patterns): +```bash +uv run openai_agents/agent_patterns/run_worker.py +``` + +Then run individual examples in separate terminals: + +## Deterministic Flows + +**TODO** + +A common tactic is to break down a task into a series of smaller steps. Each task can be performed by an agent, and the output of one agent is used as input to the next. For example, if your task was to generate a story, you could break it down into the following steps: + +1. Generate an outline +2. Generate the story +3. Generate the ending + +Each of these steps can be performed by an agent. The output of one agent is used as input to the next. + +## Handoffs and Routing + +**TODO** + +In many situations, you have specialized sub-agents that handle specific tasks. You can use handoffs to route the task to the right agent. + +For example, you might have a frontline agent that receives a request, and then hands off to a specialized agent based on the language of the request. + +## Agents as Tools + +The mental model for handoffs is that the new agent "takes over". It sees the previous conversation history, and owns the conversation from that point onwards. However, this is not the only way to use agents. You can also use agents as a tool - the tool agent goes off and runs on its own, and then returns the result to the original agent. + +For example, you could model a translation task as tool calls instead: rather than handing over to the language-specific agent, you could call the agent as a tool, and then use the result in the next step. This enables things like translating multiple languages at once. + +```bash +uv run openai_agents/agent_patterns/run_agents_as_tools_workflow.py +``` + +## LLM-as-a-Judge + +**TODO** + +LLMs can often improve the quality of their output if given feedback. A common pattern is to generate a response using a model, and then use a second model to provide feedback. You can even use a small model for the initial generation and a larger model for the feedback, to optimize cost. + +For example, you could use an LLM to generate an outline for a story, and then use a second LLM to evaluate the outline and provide feedback. You can then use the feedback to improve the outline, and repeat until the LLM is satisfied with the outline. + +## Parallelization + +**TODO** + +Running multiple agents in parallel is a common pattern. This can be useful for both latency (e.g. if you have multiple steps that don't depend on each other) and also for other reasons e.g. generating multiple responses and picking the best one. + +## Guardrails + +**TODO** + +Related to parallelization, you often want to run input guardrails to make sure the inputs to your agents are valid. For example, if you have a customer support agent, you might want to make sure that the user isn't trying to ask for help with a math problem. + +You can definitely do this without any special Agents SDK features by using parallelization, but we support a special guardrail primitive. Guardrails can have a "tripwire" - if the tripwire is triggered, the agent execution will immediately stop and a `GuardrailTripwireTriggered` exception will be raised. + +This is really useful for latency: for example, you might have a very fast model that runs the guardrail and a slow model that runs the actual agent. You wouldn't want to wait for the slow model to finish, so guardrails let you quickly reject invalid inputs. \ No newline at end of file diff --git a/openai_agents/run_agents_as_tools_workflow.py b/openai_agents/agent_patterns/run_agents_as_tools_workflow.py similarity index 85% rename from openai_agents/run_agents_as_tools_workflow.py rename to openai_agents/agent_patterns/run_agents_as_tools_workflow.py index 822ca709..a42d3aac 100644 --- a/openai_agents/run_agents_as_tools_workflow.py +++ b/openai_agents/agent_patterns/run_agents_as_tools_workflow.py @@ -3,7 +3,9 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin -from openai_agents.workflows.agents_as_tools_workflow import AgentsAsToolsWorkflow +from openai_agents.agent_patterns.workflows.agents_as_tools_workflow import ( + AgentsAsToolsWorkflow, +) async def main(): diff --git a/openai_agents/agent_patterns/run_worker.py b/openai_agents/agent_patterns/run_worker.py new file mode 100644 index 00000000..3ca0eda2 --- /dev/null +++ b/openai_agents/agent_patterns/run_worker.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.agent_patterns.workflows.agents_as_tools_workflow import ( + AgentsAsToolsWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=30) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-task-queue", + workflows=[ + AgentsAsToolsWorkflow, + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/workflows/agents_as_tools_workflow.py b/openai_agents/agent_patterns/workflows/agents_as_tools_workflow.py similarity index 100% rename from openai_agents/workflows/agents_as_tools_workflow.py rename to openai_agents/agent_patterns/workflows/agents_as_tools_workflow.py diff --git a/openai_agents/basic/README.md b/openai_agents/basic/README.md new file mode 100644 index 00000000..56d9f528 --- /dev/null +++ b/openai_agents/basic/README.md @@ -0,0 +1,25 @@ +# Basic Agent Examples + +Simple examples to get started with OpenAI Agents SDK integrated with Temporal workflows. + +*Adapted from [OpenAI Agents SDK basic examples](https://github.com/openai/openai-agents-python/tree/main/examples/basic)* + +## Running the Examples + +First, start the worker (supports all basic examples): +```bash +uv run openai_agents/basic/run_worker.py +``` + +Then run individual examples in separate terminals: + +### Hello World Agent +```bash +uv run openai_agents/basic/run_hello_world_workflow.py +``` + +### Tools Agent +Agent with access to external tools (weather API): +```bash +uv run openai_agents/basic/run_tools_workflow.py +``` \ No newline at end of file diff --git a/openai_agents/workflows/get_weather_activity.py b/openai_agents/basic/activities/get_weather_activity.py similarity index 100% rename from openai_agents/workflows/get_weather_activity.py rename to openai_agents/basic/activities/get_weather_activity.py diff --git a/openai_agents/run_hello_world_workflow.py b/openai_agents/basic/run_hello_world_workflow.py similarity index 89% rename from openai_agents/run_hello_world_workflow.py rename to openai_agents/basic/run_hello_world_workflow.py index 9ec8833f..412dbb58 100644 --- a/openai_agents/run_hello_world_workflow.py +++ b/openai_agents/basic/run_hello_world_workflow.py @@ -3,7 +3,7 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin -from openai_agents.workflows.hello_world_workflow import HelloWorldAgent +from openai_agents.basic.workflows.hello_world_workflow import HelloWorldAgent async def main(): diff --git a/openai_agents/run_tools_workflow.py b/openai_agents/basic/run_tools_workflow.py similarity index 89% rename from openai_agents/run_tools_workflow.py rename to openai_agents/basic/run_tools_workflow.py index cfb3d811..eb6adcc1 100644 --- a/openai_agents/run_tools_workflow.py +++ b/openai_agents/basic/run_tools_workflow.py @@ -3,7 +3,7 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin -from openai_agents.workflows.tools_workflow import ToolsWorkflow +from openai_agents.basic.workflows.tools_workflow import ToolsWorkflow async def main(): diff --git a/openai_agents/run_worker.py b/openai_agents/basic/run_worker.py similarity index 58% rename from openai_agents/run_worker.py rename to openai_agents/basic/run_worker.py index b17fbd0f..ec94e907 100644 --- a/openai_agents/run_worker.py +++ b/openai_agents/basic/run_worker.py @@ -7,12 +7,9 @@ from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin from temporalio.worker import Worker -from openai_agents.workflows.agents_as_tools_workflow import AgentsAsToolsWorkflow -from openai_agents.workflows.customer_service_workflow import CustomerServiceWorkflow -from openai_agents.workflows.get_weather_activity import get_weather -from openai_agents.workflows.hello_world_workflow import HelloWorldAgent -from openai_agents.workflows.research_bot_workflow import ResearchWorkflow -from openai_agents.workflows.tools_workflow import ToolsWorkflow +from openai_agents.basic.activities.get_weather_activity import get_weather +from openai_agents.basic.workflows.hello_world_workflow import HelloWorldAgent +from openai_agents.basic.workflows.tools_workflow import ToolsWorkflow async def main(): @@ -22,7 +19,7 @@ async def main(): plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( - start_to_close_timeout=timedelta(seconds=120) + start_to_close_timeout=timedelta(seconds=30) ) ), ], @@ -34,9 +31,6 @@ async def main(): workflows=[ HelloWorldAgent, ToolsWorkflow, - ResearchWorkflow, - CustomerServiceWorkflow, - AgentsAsToolsWorkflow, ], activities=[ get_weather, diff --git a/openai_agents/workflows/hello_world_workflow.py b/openai_agents/basic/workflows/hello_world_workflow.py similarity index 100% rename from openai_agents/workflows/hello_world_workflow.py rename to openai_agents/basic/workflows/hello_world_workflow.py diff --git a/openai_agents/workflows/tools_workflow.py b/openai_agents/basic/workflows/tools_workflow.py similarity index 90% rename from openai_agents/workflows/tools_workflow.py rename to openai_agents/basic/workflows/tools_workflow.py index c9f80e9f..70964dc0 100644 --- a/openai_agents/workflows/tools_workflow.py +++ b/openai_agents/basic/workflows/tools_workflow.py @@ -6,7 +6,7 @@ from temporalio import workflow from temporalio.contrib import openai_agents as temporal_agents -from openai_agents.workflows.get_weather_activity import get_weather +from openai_agents.basic.activities.get_weather_activity import get_weather @workflow.defn diff --git a/openai_agents/customer_service/README.md b/openai_agents/customer_service/README.md new file mode 100644 index 00000000..34b9504d --- /dev/null +++ b/openai_agents/customer_service/README.md @@ -0,0 +1,21 @@ +# Customer Service + +Interactive customer service agent with escalation capabilities, extended with Temporal's durable conversational workflows. + +*Adapted from [OpenAI Agents SDK customer service](https://github.com/openai/openai-agents-python/tree/main/examples/customer_service)* + +This example demonstrates how to build persistent, stateful conversations where each conversation maintains state across multiple interactions and can survive system restarts and failures. + +## Running the Example + +First, start the worker: +```bash +uv run openai_agents/customer_service/run_worker.py +``` + +Then start a customer service conversation: +```bash +uv run openai_agents/customer_service/run_customer_service_client.py --conversation-id my-conversation-123 +``` + +You can start a new conversation with any unique conversation ID, or resume existing conversations by using the same conversation ID. The conversation state is persisted in the Temporal workflow, allowing you to resume conversations even after restarting the client. \ No newline at end of file diff --git a/openai_agents/workflows/customer_service.py b/openai_agents/customer_service/customer_service.py similarity index 100% rename from openai_agents/workflows/customer_service.py rename to openai_agents/customer_service/customer_service.py diff --git a/openai_agents/run_customer_service_client.py b/openai_agents/customer_service/run_customer_service_client.py similarity index 96% rename from openai_agents/run_customer_service_client.py rename to openai_agents/customer_service/run_customer_service_client.py index ef8aaf62..e66419e4 100644 --- a/openai_agents/run_customer_service_client.py +++ b/openai_agents/customer_service/run_customer_service_client.py @@ -10,7 +10,7 @@ from temporalio.contrib.openai_agents import OpenAIAgentsPlugin from temporalio.service import RPCError, RPCStatusCode -from openai_agents.workflows.customer_service_workflow import ( +from openai_agents.customer_service.workflows.customer_service_workflow import ( CustomerServiceWorkflow, ProcessUserMessageInput, ) diff --git a/openai_agents/customer_service/run_worker.py b/openai_agents/customer_service/run_worker.py new file mode 100644 index 00000000..b82f6919 --- /dev/null +++ b/openai_agents/customer_service/run_worker.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.customer_service.workflows.customer_service_workflow import ( + CustomerServiceWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=30) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-task-queue", + workflows=[ + CustomerServiceWorkflow, + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/workflows/customer_service_workflow.py b/openai_agents/customer_service/workflows/customer_service_workflow.py similarity index 98% rename from openai_agents/workflows/customer_service_workflow.py rename to openai_agents/customer_service/workflows/customer_service_workflow.py index 3186c5ab..c816d868 100644 --- a/openai_agents/workflows/customer_service_workflow.py +++ b/openai_agents/customer_service/workflows/customer_service_workflow.py @@ -14,7 +14,7 @@ ) from temporalio import workflow -from openai_agents.workflows.customer_service import ( +from openai_agents.customer_service.customer_service import ( AirlineAgentContext, ProcessUserMessageInput, init_agents, diff --git a/openai_agents/research_bot/README.md b/openai_agents/research_bot/README.md new file mode 100644 index 00000000..f4f4a074 --- /dev/null +++ b/openai_agents/research_bot/README.md @@ -0,0 +1,35 @@ +# Research Bot + +Multi-agent research system with specialized roles, extended with Temporal's durable execution. + +*Adapted from [OpenAI Agents SDK research bot](https://github.com/openai/openai-agents-python/tree/main/examples/research_bot)* + +## Architecture + +The flow is: + +1. User enters their research topic +2. `planner_agent` comes up with a plan to search the web for information. The plan is a list of search queries, with a search term and a reason for each query. +3. For each search item, we run a `search_agent`, which uses the Web Search tool to search for that term and summarize the results. These all run in parallel. +4. Finally, the `writer_agent` receives the search summaries, and creates a written report. + +## Running the Example + +First, start the worker: +```bash +uv run openai_agents/research_bot/run_worker.py +``` + +Then run the research workflow: +```bash +uv run openai_agents/research_bot/run_research_workflow.py +``` + +## Suggested Improvements + +If you're building your own research bot, some ideas to add to this are: + +1. Retrieval: Add support for fetching relevant information from a vector store. You could use the File Search tool for this. +2. Image and file upload: Allow users to attach PDFs or other files, as baseline context for the research. +3. More planning and thinking: Models often produce better results given more time to think. Improve the planning process to come up with a better plan, and add an evaluation step so that the model can choose to improve its results, search for more stuff, etc. +4. Code execution: Allow running code, which is useful for data analysis. \ No newline at end of file diff --git a/openai_agents/workflows/research_agents/planner_agent.py b/openai_agents/research_bot/agents/planner_agent.py similarity index 100% rename from openai_agents/workflows/research_agents/planner_agent.py rename to openai_agents/research_bot/agents/planner_agent.py diff --git a/openai_agents/workflows/research_agents/research_manager.py b/openai_agents/research_bot/agents/research_manager.py similarity index 91% rename from openai_agents/workflows/research_agents/research_manager.py rename to openai_agents/research_bot/agents/research_manager.py index 356da1d7..62a77a07 100644 --- a/openai_agents/workflows/research_agents/research_manager.py +++ b/openai_agents/research_bot/agents/research_manager.py @@ -8,13 +8,13 @@ # TODO: Restore progress updates from agents import RunConfig, Runner, custom_span, trace - from openai_agents.workflows.research_agents.planner_agent import ( + from openai_agents.research_bot.agents.planner_agent import ( WebSearchItem, WebSearchPlan, new_planner_agent, ) - from openai_agents.workflows.research_agents.search_agent import new_search_agent - from openai_agents.workflows.research_agents.writer_agent import ( + from openai_agents.research_bot.agents.search_agent import new_search_agent + from openai_agents.research_bot.agents.writer_agent import ( ReportData, new_writer_agent, ) diff --git a/openai_agents/workflows/research_agents/search_agent.py b/openai_agents/research_bot/agents/search_agent.py similarity index 100% rename from openai_agents/workflows/research_agents/search_agent.py rename to openai_agents/research_bot/agents/search_agent.py diff --git a/openai_agents/workflows/research_agents/writer_agent.py b/openai_agents/research_bot/agents/writer_agent.py similarity index 100% rename from openai_agents/workflows/research_agents/writer_agent.py rename to openai_agents/research_bot/agents/writer_agent.py diff --git a/openai_agents/run_research_workflow.py b/openai_agents/research_bot/run_research_workflow.py similarity index 88% rename from openai_agents/run_research_workflow.py rename to openai_agents/research_bot/run_research_workflow.py index 5279648e..e2739ef5 100644 --- a/openai_agents/run_research_workflow.py +++ b/openai_agents/research_bot/run_research_workflow.py @@ -3,7 +3,7 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin -from openai_agents.workflows.research_bot_workflow import ResearchWorkflow +from openai_agents.research_bot.workflows.research_bot_workflow import ResearchWorkflow async def main(): diff --git a/openai_agents/research_bot/run_worker.py b/openai_agents/research_bot/run_worker.py new file mode 100644 index 00000000..fd6827d6 --- /dev/null +++ b/openai_agents/research_bot/run_worker.py @@ -0,0 +1,37 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.research_bot.workflows.research_bot_workflow import ResearchWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=120) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-task-queue", + workflows=[ + ResearchWorkflow, + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/workflows/research_bot_workflow.py b/openai_agents/research_bot/workflows/research_bot_workflow.py similarity index 68% rename from openai_agents/workflows/research_bot_workflow.py rename to openai_agents/research_bot/workflows/research_bot_workflow.py index c0779c02..c2523c8c 100644 --- a/openai_agents/workflows/research_bot_workflow.py +++ b/openai_agents/research_bot/workflows/research_bot_workflow.py @@ -1,6 +1,6 @@ from temporalio import workflow -from openai_agents.workflows.research_agents.research_manager import ResearchManager +from openai_agents.research_bot.agents.research_manager import ResearchManager @workflow.defn diff --git a/openai_agents/workflows/__init__.py b/openai_agents/workflows/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/openai_agents/workflows/research_agents/__init__.py b/openai_agents/workflows/research_agents/__init__.py deleted file mode 100644 index e69de29b..00000000 From 14e42d6f6986b52c6ae4a7deae8a0b296666b57d Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 16:18:04 -0600 Subject: [PATCH 04/40] OpenAI Agents basic examples (#223) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * porting basic examples from OpenAI Agents Examples * Revert uv.lock change --------- Co-authored-by: Tim Conley --- openai_agents/basic/README.md | 58 +++++++++- .../basic/activities/image_activities.py | 19 ++++ .../basic/activities/math_activities.py | 15 +++ openai_agents/basic/media/image_bison.jpg | Bin 0 -> 235620 bytes .../basic/run_agent_lifecycle_workflow.py | 28 +++++ .../run_dynamic_system_prompt_workflow.py | 41 +++++++ .../basic/run_hello_world_workflow.py | 2 +- openai_agents/basic/run_lifecycle_workflow.py | 31 +++++ .../basic/run_local_image_workflow.py | 32 ++++++ .../basic/run_non_strict_output_workflow.py | 35 ++++++ .../run_previous_response_id_workflow.py | 35 ++++++ .../basic/run_remote_image_workflow.py | 33 ++++++ openai_agents/basic/run_tools_workflow.py | 2 +- openai_agents/basic/run_worker.py | 32 +++++- .../workflows/agent_lifecycle_workflow.py | 97 ++++++++++++++++ .../dynamic_system_prompt_workflow.py | 48 ++++++++ .../basic/workflows/lifecycle_workflow.py | 106 ++++++++++++++++++ .../basic/workflows/local_image_workflow.py | 54 +++++++++ .../workflows/non_strict_output_workflow.py | 86 ++++++++++++++ .../previous_response_id_workflow.py | 48 ++++++++ .../basic/workflows/remote_image_workflow.py | 45 ++++++++ 21 files changed, 842 insertions(+), 5 deletions(-) create mode 100644 openai_agents/basic/activities/image_activities.py create mode 100644 openai_agents/basic/activities/math_activities.py create mode 100644 openai_agents/basic/media/image_bison.jpg create mode 100644 openai_agents/basic/run_agent_lifecycle_workflow.py create mode 100644 openai_agents/basic/run_dynamic_system_prompt_workflow.py create mode 100644 openai_agents/basic/run_lifecycle_workflow.py create mode 100644 openai_agents/basic/run_local_image_workflow.py create mode 100644 openai_agents/basic/run_non_strict_output_workflow.py create mode 100644 openai_agents/basic/run_previous_response_id_workflow.py create mode 100644 openai_agents/basic/run_remote_image_workflow.py create mode 100644 openai_agents/basic/workflows/agent_lifecycle_workflow.py create mode 100644 openai_agents/basic/workflows/dynamic_system_prompt_workflow.py create mode 100644 openai_agents/basic/workflows/lifecycle_workflow.py create mode 100644 openai_agents/basic/workflows/local_image_workflow.py create mode 100644 openai_agents/basic/workflows/non_strict_output_workflow.py create mode 100644 openai_agents/basic/workflows/previous_response_id_workflow.py create mode 100644 openai_agents/basic/workflows/remote_image_workflow.py diff --git a/openai_agents/basic/README.md b/openai_agents/basic/README.md index 56d9f528..e593ee48 100644 --- a/openai_agents/basic/README.md +++ b/openai_agents/basic/README.md @@ -4,6 +4,8 @@ Simple examples to get started with OpenAI Agents SDK integrated with Temporal w *Adapted from [OpenAI Agents SDK basic examples](https://github.com/openai/openai-agents-python/tree/main/examples/basic)* +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + ## Running the Examples First, start the worker (supports all basic examples): @@ -14,12 +16,64 @@ uv run openai_agents/basic/run_worker.py Then run individual examples in separate terminals: ### Hello World Agent +Basic agent that only responds in haikus: ```bash uv run openai_agents/basic/run_hello_world_workflow.py ``` ### Tools Agent -Agent with access to external tools (weather API): +Agent with access to external tools (simulated weather API): ```bash uv run openai_agents/basic/run_tools_workflow.py -``` \ No newline at end of file +``` + +### Agent Lifecycle with Hooks +Demonstrates agent lifecycle events and handoffs between agents: +```bash +uv run openai_agents/basic/run_agent_lifecycle_workflow.py +``` + +### Lifecycle with Usage Tracking +Shows detailed usage tracking with RunHooks (requests, tokens, etc.): +```bash +uv run openai_agents/basic/run_lifecycle_workflow.py +``` + +### Dynamic System Prompts +Agent with dynamic instruction generation based on context (haiku/pirate/robot): +```bash +uv run openai_agents/basic/run_dynamic_system_prompt_workflow.py +``` + +### Non-Strict Output Types +Demonstrates different JSON schema validation approaches: +```bash +uv run openai_agents/basic/run_non_strict_output_workflow.py +``` + +Note: `CustomOutputSchema` is not supported by the Temporal OpenAI Agents SDK integration and is omitted in this example. + +### Image Processing - Local +Process local image files with AI vision: +```bash +uv run openai_agents/basic/run_local_image_workflow.py +``` + +### Image Processing - Remote +Process remote image URLs with AI vision: +```bash +uv run openai_agents/basic/run_remote_image_workflow.py +``` + +### Previous Response ID +Demonstrates conversation continuity using response IDs: +```bash +uv run openai_agents/basic/run_previous_response_id_workflow.py +``` + +## Omitted Examples + +The following examples from the [reference repository](https://github.com/openai/openai-agents-python/tree/main/examples/basic) are not included in this Temporal adaptation: + +- **Session** - Stores state in local SQLite database, not appropriate for distributed workflows +- **Stream Items/Stream Text** - Streaming is not supported in Temporal OpenAI Agents SDK integration \ No newline at end of file diff --git a/openai_agents/basic/activities/image_activities.py b/openai_agents/basic/activities/image_activities.py new file mode 100644 index 00000000..23c770b1 --- /dev/null +++ b/openai_agents/basic/activities/image_activities.py @@ -0,0 +1,19 @@ +import base64 + +from temporalio import activity + + +@activity.defn +async def read_image_as_base64(image_path: str) -> str: + """ + Read an image file and convert it to base64 string. + + Args: + image_path: Path to the image file + + Returns: + Base64 encoded string of the image + """ + with open(image_path, "rb") as image_file: + encoded_string = base64.b64encode(image_file.read()).decode("utf-8") + return encoded_string diff --git a/openai_agents/basic/activities/math_activities.py b/openai_agents/basic/activities/math_activities.py new file mode 100644 index 00000000..1e875b23 --- /dev/null +++ b/openai_agents/basic/activities/math_activities.py @@ -0,0 +1,15 @@ +import random + +from temporalio import activity + + +@activity.defn +async def random_number(max_value: int) -> int: + """Generate a random number up to the provided maximum.""" + return random.randint(0, max_value) + + +@activity.defn +async def multiply_by_two(x: int) -> int: + """Simple multiplication by two.""" + return x * 2 diff --git a/openai_agents/basic/media/image_bison.jpg b/openai_agents/basic/media/image_bison.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b113c91f601eac2369c4b859b18f86a24a228d89 GIT binary patch literal 235620 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 z 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 None: + client = await Client.connect("localhost:7233") + + user_input = input("Enter a max number: ") + max_number = int(user_input) + + result = await client.execute_workflow( + AgentLifecycleWorkflow.run, + max_number, + id="agent-lifecycle-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print(f"Final result: {result}") + print("Done!") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_dynamic_system_prompt_workflow.py b/openai_agents/basic/run_dynamic_system_prompt_workflow.py new file mode 100644 index 00000000..46c53c6d --- /dev/null +++ b/openai_agents/basic/run_dynamic_system_prompt_workflow.py @@ -0,0 +1,41 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.dynamic_system_prompt_workflow import ( + DynamicSystemPromptWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + user_message = "Tell me a joke." + + result = await client.execute_workflow( + DynamicSystemPromptWorkflow.run, + user_message, + id="dynamic-prompt-workflow", + task_queue="openai-agents-basic-task-queue", + ) + print(result) + print() + + # Run with specific style + result = await client.execute_workflow( + DynamicSystemPromptWorkflow.run, + args=[user_message, "pirate"], + id="dynamic-prompt-pirate-workflow", + task_queue="openai-agents-basic-task-queue", + ) + print(result) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_hello_world_workflow.py b/openai_agents/basic/run_hello_world_workflow.py index 412dbb58..0662a4fa 100644 --- a/openai_agents/basic/run_hello_world_workflow.py +++ b/openai_agents/basic/run_hello_world_workflow.py @@ -20,7 +20,7 @@ async def main(): HelloWorldAgent.run, "Tell me about recursion in programming.", id="my-workflow-id", - task_queue="openai-agents-task-queue", + task_queue="openai-agents-basic-task-queue", ) print(f"Result: {result}") diff --git a/openai_agents/basic/run_lifecycle_workflow.py b/openai_agents/basic/run_lifecycle_workflow.py new file mode 100644 index 00000000..00286ece --- /dev/null +++ b/openai_agents/basic/run_lifecycle_workflow.py @@ -0,0 +1,31 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.lifecycle_workflow import LifecycleWorkflow + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + user_input = input("Enter a max number: ") + max_number = int(user_input) + + result = await client.execute_workflow( + LifecycleWorkflow.run, + max_number, + id="lifecycle-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print(f"Final result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_local_image_workflow.py b/openai_agents/basic/run_local_image_workflow.py new file mode 100644 index 00000000..6dfec809 --- /dev/null +++ b/openai_agents/basic/run_local_image_workflow.py @@ -0,0 +1,32 @@ +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.local_image_workflow import LocalImageWorkflow + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Use the media file from the original example + image_path = os.path.join(os.path.dirname(__file__), "media/image_bison.jpg") + + result = await client.execute_workflow( + LocalImageWorkflow.run, + args=[image_path, "What do you see in this image?"], + id="local-image-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print(f"Agent response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_non_strict_output_workflow.py b/openai_agents/basic/run_non_strict_output_workflow.py new file mode 100644 index 00000000..192e1206 --- /dev/null +++ b/openai_agents/basic/run_non_strict_output_workflow.py @@ -0,0 +1,35 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.non_strict_output_workflow import ( + NonStrictOutputWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + input_message = "Tell me 3 short jokes." + + result = await client.execute_workflow( + NonStrictOutputWorkflow.run, + input_message, + id="non-strict-output-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print("=== Non-Strict Output Type Results ===") + for key, value in result.items(): + print(f"{key}: {value}") + print() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_previous_response_id_workflow.py b/openai_agents/basic/run_previous_response_id_workflow.py new file mode 100644 index 00000000..ddae5107 --- /dev/null +++ b/openai_agents/basic/run_previous_response_id_workflow.py @@ -0,0 +1,35 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.previous_response_id_workflow import ( + PreviousResponseIdWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + first_question = "What is the largest country in South America?" + follow_up_question = "What is the capital of that country?" + + result = await client.execute_workflow( + PreviousResponseIdWorkflow.run, + args=[first_question, follow_up_question], + id="previous-response-id-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print("\nFinal results:") + print(f"1. {result[0]}") + print(f"2. {result[1]}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_remote_image_workflow.py b/openai_agents/basic/run_remote_image_workflow.py new file mode 100644 index 00000000..f7c41b9a --- /dev/null +++ b/openai_agents/basic/run_remote_image_workflow.py @@ -0,0 +1,33 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.basic.workflows.remote_image_workflow import RemoteImageWorkflow + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Use the URL from the original example + image_url = ( + "https://upload.wikimedia.org/wikipedia/commons/0/0c/GoldenGateBridge-001.jpg" + ) + + result = await client.execute_workflow( + RemoteImageWorkflow.run, + args=[image_url, "What do you see in this image?"], + id="remote-image-workflow", + task_queue="openai-agents-basic-task-queue", + ) + + print(f"Agent response: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/basic/run_tools_workflow.py b/openai_agents/basic/run_tools_workflow.py index eb6adcc1..9aed2dbf 100644 --- a/openai_agents/basic/run_tools_workflow.py +++ b/openai_agents/basic/run_tools_workflow.py @@ -20,7 +20,7 @@ async def main(): ToolsWorkflow.run, "What is the weather in Tokio?", id="tools-workflow", - task_queue="openai-agents-task-queue", + task_queue="openai-agents-basic-task-queue", ) print(f"Result: {result}") diff --git a/openai_agents/basic/run_worker.py b/openai_agents/basic/run_worker.py index ec94e907..94d6a882 100644 --- a/openai_agents/basic/run_worker.py +++ b/openai_agents/basic/run_worker.py @@ -8,7 +8,27 @@ from temporalio.worker import Worker from openai_agents.basic.activities.get_weather_activity import get_weather +from openai_agents.basic.activities.image_activities import read_image_as_base64 +from openai_agents.basic.activities.math_activities import ( + multiply_by_two, + random_number, +) +from openai_agents.basic.workflows.agent_lifecycle_workflow import ( + AgentLifecycleWorkflow, +) +from openai_agents.basic.workflows.dynamic_system_prompt_workflow import ( + DynamicSystemPromptWorkflow, +) from openai_agents.basic.workflows.hello_world_workflow import HelloWorldAgent +from openai_agents.basic.workflows.lifecycle_workflow import LifecycleWorkflow +from openai_agents.basic.workflows.local_image_workflow import LocalImageWorkflow +from openai_agents.basic.workflows.non_strict_output_workflow import ( + NonStrictOutputWorkflow, +) +from openai_agents.basic.workflows.previous_response_id_workflow import ( + PreviousResponseIdWorkflow, +) +from openai_agents.basic.workflows.remote_image_workflow import RemoteImageWorkflow from openai_agents.basic.workflows.tools_workflow import ToolsWorkflow @@ -27,13 +47,23 @@ async def main(): worker = Worker( client, - task_queue="openai-agents-task-queue", + task_queue="openai-agents-basic-task-queue", workflows=[ HelloWorldAgent, ToolsWorkflow, + AgentLifecycleWorkflow, + DynamicSystemPromptWorkflow, + NonStrictOutputWorkflow, + LocalImageWorkflow, + RemoteImageWorkflow, + LifecycleWorkflow, + PreviousResponseIdWorkflow, ], activities=[ get_weather, + multiply_by_two, + random_number, + read_image_as_base64, ], ) await worker.run() diff --git a/openai_agents/basic/workflows/agent_lifecycle_workflow.py b/openai_agents/basic/workflows/agent_lifecycle_workflow.py new file mode 100644 index 00000000..61cdad90 --- /dev/null +++ b/openai_agents/basic/workflows/agent_lifecycle_workflow.py @@ -0,0 +1,97 @@ +from typing import Any + +from agents import Agent, AgentHooks, RunContextWrapper, Runner, function_tool +from pydantic import BaseModel +from temporalio import workflow + + +class CustomAgentHooks(AgentHooks): + def __init__(self, display_name: str): + self.event_counter = 0 + self.display_name = display_name + + async def on_start(self, context: RunContextWrapper, agent: Agent) -> None: + self.event_counter += 1 + print( + f"### ({self.display_name}) {self.event_counter}: Agent {agent.name} started" + ) + + async def on_end( + self, context: RunContextWrapper, agent: Agent, output: Any + ) -> None: + self.event_counter += 1 + print( + f"### ({self.display_name}) {self.event_counter}: Agent {agent.name} ended with output {output}" + ) + + async def on_handoff( + self, context: RunContextWrapper, agent: Agent, source: Agent + ) -> None: + self.event_counter += 1 + print( + f"### ({self.display_name}) {self.event_counter}: Agent {source.name} handed off to {agent.name}" + ) + + async def on_tool_start( + self, context: RunContextWrapper, agent: Agent, tool + ) -> None: + self.event_counter += 1 + print( + f"### ({self.display_name}) {self.event_counter}: Agent {agent.name} started tool {tool.name}" + ) + + async def on_tool_end( + self, context: RunContextWrapper, agent: Agent, tool, result: str + ) -> None: + self.event_counter += 1 + print( + f"### ({self.display_name}) {self.event_counter}: Agent {agent.name} ended tool {tool.name} with result {result}" + ) + + +@function_tool +def random_number_tool(max: int) -> int: + """ + Generate a random number up to the provided maximum. + """ + return workflow.random().randint(0, max) + + +@function_tool +def multiply_by_two_tool(x: int) -> int: + """Simple multiplication by two.""" + return x * 2 + + +class FinalResult(BaseModel): + number: int + + +@workflow.defn +class AgentLifecycleWorkflow: + @workflow.run + async def run(self, max_number: int) -> FinalResult: + + multiply_agent = Agent( + name="Multiply Agent", + instructions="Multiply the number by 2 and then return the final result.", + tools=[multiply_by_two_tool], + output_type=FinalResult, + hooks=CustomAgentHooks(display_name="Multiply Agent"), + ) + + start_agent = Agent( + name="Start Agent", + instructions="Generate a random number. If it's even, stop. If it's odd, hand off to the multiply agent.", + tools=[random_number_tool], + output_type=FinalResult, + handoffs=[multiply_agent], + hooks=CustomAgentHooks(display_name="Start Agent"), + ) + + result = await Runner.run( + start_agent, + input=f"Generate a random number between 0 and {max_number}.", + ) + + return result.final_output diff --git a/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py b/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py new file mode 100644 index 00000000..00e77fbb --- /dev/null +++ b/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py @@ -0,0 +1,48 @@ +from typing import Literal, Optional + +from agents import Agent, RunContextWrapper, Runner +from temporalio import workflow + + +class CustomContext: + def __init__(self, style: Literal["haiku", "pirate", "robot"]): + self.style = style + + +def custom_instructions( + run_context: RunContextWrapper[CustomContext], agent: Agent[CustomContext] +) -> str: + context = run_context.context + if context.style == "haiku": + return "Only respond in haikus." + elif context.style == "pirate": + return "Respond as a pirate." + else: + return "Respond as a robot and say 'beep boop' a lot." + + +@workflow.defn +class DynamicSystemPromptWorkflow: + @workflow.run + async def run(self, user_message: str, style: Optional[str] = None) -> str: + if style is None: + selected_style: Literal[ + "haiku", "pirate", "robot" + ] = workflow.random().choice(["haiku", "pirate", "robot"]) + else: + # Validate that the provided style is one of the allowed values + if style not in ["haiku", "pirate", "robot"]: + raise ValueError( + f"Invalid style: {style}. Must be one of: haiku, pirate, robot" + ) + selected_style = style # type: ignore + + context = CustomContext(style=selected_style) + + agent = Agent( + name="Chat agent", + instructions=custom_instructions, + ) + + result = await Runner.run(agent, user_message, context=context) + return f"Style: {selected_style}\nResponse: {result.final_output}" diff --git a/openai_agents/basic/workflows/lifecycle_workflow.py b/openai_agents/basic/workflows/lifecycle_workflow.py new file mode 100644 index 00000000..cf72de4a --- /dev/null +++ b/openai_agents/basic/workflows/lifecycle_workflow.py @@ -0,0 +1,106 @@ +from typing import Any + +from agents import ( + Agent, + RunContextWrapper, + RunHooks, + Runner, + Tool, + Usage, + function_tool, +) +from pydantic import BaseModel +from temporalio import workflow + + +class ExampleHooks(RunHooks): + def __init__(self): + self.event_counter = 0 + + def _usage_to_str(self, usage: Usage) -> str: + return f"{usage.requests} requests, {usage.input_tokens} input tokens, {usage.output_tokens} output tokens, {usage.total_tokens} total tokens" + + async def on_agent_start(self, context: RunContextWrapper, agent: Agent) -> None: + self.event_counter += 1 + print( + f"### {self.event_counter}: Agent {agent.name} started. Usage: {self._usage_to_str(context.usage)}" + ) + + async def on_agent_end( + self, context: RunContextWrapper, agent: Agent, output: Any + ) -> None: + self.event_counter += 1 + print( + f"### {self.event_counter}: Agent {agent.name} ended with output {output}. Usage: {self._usage_to_str(context.usage)}" + ) + + async def on_tool_start( + self, context: RunContextWrapper, agent: Agent, tool: Tool + ) -> None: + self.event_counter += 1 + print( + f"### {self.event_counter}: Tool {tool.name} started. Usage: {self._usage_to_str(context.usage)}" + ) + + async def on_tool_end( + self, context: RunContextWrapper, agent: Agent, tool: Tool, result: str + ) -> None: + self.event_counter += 1 + print( + f"### {self.event_counter}: Tool {tool.name} ended with result {result}. Usage: {self._usage_to_str(context.usage)}" + ) + + async def on_handoff( + self, context: RunContextWrapper, from_agent: Agent, to_agent: Agent + ) -> None: + self.event_counter += 1 + print( + f"### {self.event_counter}: Handoff from {from_agent.name} to {to_agent.name}. Usage: {self._usage_to_str(context.usage)}" + ) + + +@function_tool +def random_number(max: int) -> int: + """Generate a random number up to the provided max.""" + return workflow.random().randint(0, max) + + +@function_tool +def multiply_by_two(x: int) -> int: + """Return x times two.""" + return x * 2 + + +class FinalResult(BaseModel): + number: int + + +@workflow.defn +class LifecycleWorkflow: + @workflow.run + async def run(self, max_number: int) -> FinalResult: + hooks = ExampleHooks() + + multiply_agent = Agent( + name="Multiply Agent", + instructions="Multiply the number by 2 and then return the final result.", + tools=[multiply_by_two], + output_type=FinalResult, + ) + + start_agent = Agent( + name="Start Agent", + instructions="Generate a random number. If it's even, stop. If it's odd, hand off to the multiplier agent.", + tools=[random_number], + output_type=FinalResult, + handoffs=[multiply_agent], + ) + + result = await Runner.run( + start_agent, + hooks=hooks, + input=f"Generate a random number between 0 and {max_number}.", + ) + + print("Done!") + return result.final_output diff --git a/openai_agents/basic/workflows/local_image_workflow.py b/openai_agents/basic/workflows/local_image_workflow.py new file mode 100644 index 00000000..b536f517 --- /dev/null +++ b/openai_agents/basic/workflows/local_image_workflow.py @@ -0,0 +1,54 @@ +from agents import Agent, Runner +from temporalio import workflow + +from openai_agents.basic.activities.image_activities import read_image_as_base64 + + +@workflow.defn +class LocalImageWorkflow: + @workflow.run + async def run( + self, image_path: str, question: str = "What do you see in this image?" + ) -> str: + """ + Process a local image file with an AI agent. + + Args: + image_path: Path to the local image file + question: Question to ask about the image + + Returns: + Agent's response about the image + """ + # Convert image to base64 using activity + b64_image = await workflow.execute_activity( + read_image_as_base64, + image_path, + start_to_close_timeout=workflow.timedelta(seconds=30), + ) + + agent = Agent( + name="Assistant", + instructions="You are a helpful assistant.", + ) + + result = await Runner.run( + agent, + [ + { + "role": "user", + "content": [ + { + "type": "input_image", + "detail": "auto", + "image_url": f"data:image/jpeg;base64,{b64_image}", + } + ], + }, + { + "role": "user", + "content": question, + }, + ], + ) + return result.final_output diff --git a/openai_agents/basic/workflows/non_strict_output_workflow.py b/openai_agents/basic/workflows/non_strict_output_workflow.py new file mode 100644 index 00000000..f56716c1 --- /dev/null +++ b/openai_agents/basic/workflows/non_strict_output_workflow.py @@ -0,0 +1,86 @@ +import json +from dataclasses import dataclass +from typing import Any + +from agents import Agent, AgentOutputSchema, AgentOutputSchemaBase, Runner +from temporalio import workflow + + +@dataclass +class OutputType: + jokes: dict[int, str] + """A list of jokes, indexed by joke number.""" + + +class CustomOutputSchema(AgentOutputSchemaBase): + """A demonstration of a custom output schema.""" + + def is_plain_text(self) -> bool: + return False + + def name(self) -> str: + return "CustomOutputSchema" + + def json_schema(self) -> dict[str, Any]: + return { + "type": "object", + "properties": { + "jokes": {"type": "object", "properties": {"joke": {"type": "string"}}} + }, + } + + def is_strict_json_schema(self) -> bool: + return False + + def validate_json(self, json_str: str) -> Any: + json_obj = json.loads(json_str) + # Just for demonstration, we'll return a list. + return list(json_obj["jokes"].values()) + + +@workflow.defn +class NonStrictOutputWorkflow: + @workflow.run + async def run(self, input_text: str) -> dict[str, Any]: + """ + Demonstrates non-strict output types that require special handling. + + Args: + input_text: The input message to the agent + + Returns: + Dictionary with results from different output type approaches + """ + results = {} + + agent = Agent( + name="Assistant", + instructions="You are a helpful assistant.", + output_type=OutputType, + ) + + # First, try with strict output type (this should fail) + try: + result = await Runner.run(agent, input_text) + results["strict_result"] = "Unexpected success" + except Exception as e: + results["strict_error"] = str(e) + + # Now try with non-strict output type + try: + agent.output_type = AgentOutputSchema(OutputType, strict_json_schema=False) + result = await Runner.run(agent, input_text) + results["non_strict_result"] = result.final_output + except Exception as e: + results["non_strict_error"] = str(e) + + # Finally, try with custom output type + # Not presently supported by Temporal + # try: + # agent.output_type = CustomOutputSchema() + # result = await Runner.run(agent, input_text) + # results["custom_result"] = result.final_output + # except Exception as e: + # results["custom_error"] = str(e) + + return results diff --git a/openai_agents/basic/workflows/previous_response_id_workflow.py b/openai_agents/basic/workflows/previous_response_id_workflow.py new file mode 100644 index 00000000..64015159 --- /dev/null +++ b/openai_agents/basic/workflows/previous_response_id_workflow.py @@ -0,0 +1,48 @@ +from typing import Tuple + +from agents import Agent, Runner +from temporalio import workflow + + +@workflow.defn +class PreviousResponseIdWorkflow: + @workflow.run + async def run( + self, first_question: str, follow_up_question: str + ) -> Tuple[str, str]: + """ + Demonstrates usage of the `previous_response_id` parameter to continue a conversation. + The second run passes the previous response ID to the model, which allows it to continue the + conversation without re-sending the previous messages. + + Notes: + 1. This only applies to the OpenAI Responses API. Other models will ignore this parameter. + 2. Responses are only stored for 30 days as of this writing, so in production you should + store the response ID along with an expiration date; if the response is no longer valid, + you'll need to re-send the previous conversation history. + + Args: + first_question: The initial question to ask + follow_up_question: The follow-up question that references the first response + + Returns: + Tuple of (first_response, second_response) + """ + agent = Agent( + name="Assistant", + instructions="You are a helpful assistant. be VERY concise.", + ) + + # First question + result1 = await Runner.run(agent, first_question) + first_response = result1.final_output + + # Follow-up question using previous response ID + result2 = await Runner.run( + agent, + follow_up_question, + previous_response_id=result1.last_response_id, + ) + second_response = result2.final_output + + return first_response, second_response diff --git a/openai_agents/basic/workflows/remote_image_workflow.py b/openai_agents/basic/workflows/remote_image_workflow.py new file mode 100644 index 00000000..ce07bd21 --- /dev/null +++ b/openai_agents/basic/workflows/remote_image_workflow.py @@ -0,0 +1,45 @@ +from agents import Agent, Runner +from temporalio import workflow + + +@workflow.defn +class RemoteImageWorkflow: + @workflow.run + async def run( + self, image_url: str, question: str = "What do you see in this image?" + ) -> str: + """ + Process a remote image URL with an AI agent. + + Args: + image_url: URL of the remote image + question: Question to ask about the image + + Returns: + Agent's response about the image + """ + agent = Agent( + name="Assistant", + instructions="You are a helpful assistant.", + ) + + result = await Runner.run( + agent, + [ + { + "role": "user", + "content": [ + { + "type": "input_image", + "detail": "auto", + "image_url": image_url, + } + ], + }, + { + "role": "user", + "content": question, + }, + ], + ) + return result.final_output From 582235fcc63299f3363d1e7e9e38200e39e42257 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 16:52:43 -0600 Subject: [PATCH 05/40] OpenAI Agents agent pattern examples (#224) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * porting agent patterns from OpenAI agents examples * Revert uv.lock --------- Co-authored-by: Tim Conley --- openai_agents/agent_patterns/README.md | 91 ++++++++++++------- .../run_agents_as_tools_workflow.py | 6 +- .../run_deterministic_workflow.py | 31 +++++++ .../run_forcing_tool_use_workflow.py | 50 ++++++++++ .../run_input_guardrails_workflow.py | 40 ++++++++ .../run_llm_as_a_judge_workflow.py | 31 +++++++ .../run_output_guardrails_workflow.py | 40 ++++++++ .../run_parallelization_workflow.py | 31 +++++++ .../agent_patterns/run_routing_workflow.py | 29 ++++++ openai_agents/agent_patterns/run_worker.py | 28 +++++- .../workflows/deterministic_workflow.py | 90 ++++++++++++++++++ .../workflows/forcing_tool_use_workflow.py | 83 +++++++++++++++++ .../workflows/input_guardrails_workflow.py | 87 ++++++++++++++++++ .../workflows/llm_as_a_judge_workflow.py | 86 ++++++++++++++++++ .../workflows/output_guardrails_workflow.py | 78 ++++++++++++++++ .../workflows/parallelization_workflow.py | 70 ++++++++++++++ .../workflows/routing_workflow.py | 67 ++++++++++++++ openai_agents/basic/run_worker.py | 2 +- 18 files changed, 904 insertions(+), 36 deletions(-) create mode 100644 openai_agents/agent_patterns/run_deterministic_workflow.py create mode 100644 openai_agents/agent_patterns/run_forcing_tool_use_workflow.py create mode 100644 openai_agents/agent_patterns/run_input_guardrails_workflow.py create mode 100644 openai_agents/agent_patterns/run_llm_as_a_judge_workflow.py create mode 100644 openai_agents/agent_patterns/run_output_guardrails_workflow.py create mode 100644 openai_agents/agent_patterns/run_parallelization_workflow.py create mode 100644 openai_agents/agent_patterns/run_routing_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/deterministic_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/input_guardrails_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/llm_as_a_judge_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/output_guardrails_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/parallelization_workflow.py create mode 100644 openai_agents/agent_patterns/workflows/routing_workflow.py diff --git a/openai_agents/agent_patterns/README.md b/openai_agents/agent_patterns/README.md index 26867f10..33784747 100644 --- a/openai_agents/agent_patterns/README.md +++ b/openai_agents/agent_patterns/README.md @@ -4,6 +4,8 @@ Common agentic patterns extended with Temporal's durable execution capabilities. *Adapted from [OpenAI Agents SDK agent patterns](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns)* +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + ## Running the Examples First, start the worker (supports all patterns): @@ -13,56 +15,83 @@ uv run openai_agents/agent_patterns/run_worker.py Then run individual examples in separate terminals: -## Deterministic Flows - -**TODO** - -A common tactic is to break down a task into a series of smaller steps. Each task can be performed by an agent, and the output of one agent is used as input to the next. For example, if your task was to generate a story, you could break it down into the following steps: - -1. Generate an outline -2. Generate the story -3. Generate the ending - -Each of these steps can be performed by an agent. The output of one agent is used as input to the next. - -## Handoffs and Routing - -**TODO** - -In many situations, you have specialized sub-agents that handle specific tasks. You can use handoffs to route the task to the right agent. +### Deterministic Flows +Sequential agent execution with validation gates - demonstrates breaking complex tasks into smaller steps: +```bash +uv run openai_agents/agent_patterns/run_deterministic_workflow.py +``` -For example, you might have a frontline agent that receives a request, and then hands off to a specialized agent based on the language of the request. +### Parallelization +Run multiple agents in parallel and select the best result - useful for improving quality or reducing latency: +```bash +uv run openai_agents/agent_patterns/run_parallelization_workflow.py +``` -## Agents as Tools +### LLM-as-a-Judge +Iterative improvement using feedback loops - generate content, evaluate it, and improve until satisfied: +```bash +uv run openai_agents/agent_patterns/run_llm_as_a_judge_workflow.py +``` -The mental model for handoffs is that the new agent "takes over". It sees the previous conversation history, and owns the conversation from that point onwards. However, this is not the only way to use agents. You can also use agents as a tool - the tool agent goes off and runs on its own, and then returns the result to the original agent. +### Agents as Tools +Use agents as callable tools within other agents - enables composition and specialized task delegation: +```bash +uv run openai_agents/agent_patterns/run_agents_as_tools_workflow.py +``` -For example, you could model a translation task as tool calls instead: rather than handing over to the language-specific agent, you could call the agent as a tool, and then use the result in the next step. This enables things like translating multiple languages at once. +### Agent Routing and Handoffs +Route requests to specialized agents based on content analysis (adapted for non-streaming): +```bash +uv run openai_agents/agent_patterns/run_routing_workflow.py +``` +### Input Guardrails +Pre-execution validation to prevent unwanted requests - demonstrates safety mechanisms: ```bash -uv run openai_agents/agent_patterns/run_agents_as_tools_workflow.py +uv run openai_agents/agent_patterns/run_input_guardrails_workflow.py ``` -## LLM-as-a-Judge +### Output Guardrails +Post-execution validation to detect sensitive content - ensures safe responses: +```bash +uv run openai_agents/agent_patterns/run_output_guardrails_workflow.py +``` -**TODO** +### Forcing Tool Use +Control tool execution strategies - choose between different approaches to tool usage: +```bash +uv run openai_agents/agent_patterns/run_forcing_tool_use_workflow.py +``` -LLMs can often improve the quality of their output if given feedback. A common pattern is to generate a response using a model, and then use a second model to provide feedback. You can even use a small model for the initial generation and a larger model for the feedback, to optimize cost. +## Pattern Details -For example, you could use an LLM to generate an outline for a story, and then use a second LLM to evaluate the outline and provide feedback. You can then use the feedback to improve the outline, and repeat until the LLM is satisfied with the outline. +### Deterministic Flows +A common tactic is to break down a task into a series of smaller steps. Each task can be performed by an agent, and the output of one agent is used as input to the next. For example, if your task was to generate a story, you could break it down into the following steps: -## Parallelization +1. Generate an outline +2. Check outline quality and genre +3. Write the story (only if outline passes validation) -**TODO** +Each of these steps can be performed by an agent. The output of one agent is used as input to the next. +### Parallelization Running multiple agents in parallel is a common pattern. This can be useful for both latency (e.g. if you have multiple steps that don't depend on each other) and also for other reasons e.g. generating multiple responses and picking the best one. -## Guardrails +### LLM-as-a-Judge +LLMs can often improve the quality of their output if given feedback. A common pattern is to generate a response using a model, and then use a second model to provide feedback. You can even use a small model for the initial generation and a larger model for the feedback, to optimize cost. -**TODO** +### Agents as Tools +The mental model for handoffs is that the new agent "takes over". It sees the previous conversation history, and owns the conversation from that point onwards. However, this is not the only way to use agents. You can also use agents as a tool - the tool agent goes off and runs on its own, and then returns the result to the original agent. +### Guardrails Related to parallelization, you often want to run input guardrails to make sure the inputs to your agents are valid. For example, if you have a customer support agent, you might want to make sure that the user isn't trying to ask for help with a math problem. You can definitely do this without any special Agents SDK features by using parallelization, but we support a special guardrail primitive. Guardrails can have a "tripwire" - if the tripwire is triggered, the agent execution will immediately stop and a `GuardrailTripwireTriggered` exception will be raised. -This is really useful for latency: for example, you might have a very fast model that runs the guardrail and a slow model that runs the actual agent. You wouldn't want to wait for the slow model to finish, so guardrails let you quickly reject invalid inputs. \ No newline at end of file +This is really useful for latency: for example, you might have a very fast model that runs the guardrail and a slow model that runs the actual agent. You wouldn't want to wait for the slow model to finish, so guardrails let you quickly reject invalid inputs. + +## Omitted Examples + +The following patterns from the [reference repository](https://github.com/openai/openai-agents-python/tree/main/examples/agent_patterns) are not included in this Temporal adaptation: + +- **Streaming Guardrails**: Requires streaming capabilities which are not yet available in the Temporal integration \ No newline at end of file diff --git a/openai_agents/agent_patterns/run_agents_as_tools_workflow.py b/openai_agents/agent_patterns/run_agents_as_tools_workflow.py index a42d3aac..8b0c1345 100644 --- a/openai_agents/agent_patterns/run_agents_as_tools_workflow.py +++ b/openai_agents/agent_patterns/run_agents_as_tools_workflow.py @@ -20,9 +20,9 @@ async def main(): # Execute a workflow result = await client.execute_workflow( AgentsAsToolsWorkflow.run, - "Translate to English: 'ΒΏCΓ³mo estΓ‘s?'", - id="my-workflow-id", - task_queue="openai-agents-task-queue", + "Please translate 'Good morning, how are you?' to Spanish and French", + id="agents-as-tools-workflow-example", + task_queue="openai-agents-patterns-task-queue", ) print(f"Result: {result}") diff --git a/openai_agents/agent_patterns/run_deterministic_workflow.py b/openai_agents/agent_patterns/run_deterministic_workflow.py new file mode 100644 index 00000000..abb2e4de --- /dev/null +++ b/openai_agents/agent_patterns/run_deterministic_workflow.py @@ -0,0 +1,31 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.deterministic_workflow import ( + DeterministicWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + DeterministicWorkflow.run, + "Write a science fiction story about time travel", + id="deterministic-workflow-example", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_forcing_tool_use_workflow.py b/openai_agents/agent_patterns/run_forcing_tool_use_workflow.py new file mode 100644 index 00000000..5dfa42c5 --- /dev/null +++ b/openai_agents/agent_patterns/run_forcing_tool_use_workflow.py @@ -0,0 +1,50 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.forcing_tool_use_workflow import ( + ForcingToolUseWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute workflows with different tool use behaviors + print("Testing default behavior:") + result1 = await client.execute_workflow( + ForcingToolUseWorkflow.run, + "default", + id="forcing-tool-use-workflow-default", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Default result: {result1}") + + print("\nTesting first_tool behavior:") + result2 = await client.execute_workflow( + ForcingToolUseWorkflow.run, + "first_tool", + id="forcing-tool-use-workflow-first-tool", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"First tool result: {result2}") + + print("\nTesting custom behavior:") + result3 = await client.execute_workflow( + ForcingToolUseWorkflow.run, + "custom", + id="forcing-tool-use-workflow-custom", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Custom result: {result3}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_input_guardrails_workflow.py b/openai_agents/agent_patterns/run_input_guardrails_workflow.py new file mode 100644 index 00000000..82536e26 --- /dev/null +++ b/openai_agents/agent_patterns/run_input_guardrails_workflow.py @@ -0,0 +1,40 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.input_guardrails_workflow import ( + InputGuardrailsWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow with a normal question (should pass) + result1 = await client.execute_workflow( + InputGuardrailsWorkflow.run, + "What's the capital of California?", + id="input-guardrails-workflow-normal", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Normal question result: {result1}") + + # Execute a workflow with a math homework question (should be blocked) + result2 = await client.execute_workflow( + InputGuardrailsWorkflow.run, + "Can you help me solve for x: 2x + 5 = 11?", + id="input-guardrails-workflow-blocked", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Math homework result: {result2}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_llm_as_a_judge_workflow.py b/openai_agents/agent_patterns/run_llm_as_a_judge_workflow.py new file mode 100644 index 00000000..aa6d97a6 --- /dev/null +++ b/openai_agents/agent_patterns/run_llm_as_a_judge_workflow.py @@ -0,0 +1,31 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.llm_as_a_judge_workflow import ( + LLMAsAJudgeWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + LLMAsAJudgeWorkflow.run, + "A thrilling adventure story about pirates searching for treasure", + id="llm-as-a-judge-workflow-example", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_output_guardrails_workflow.py b/openai_agents/agent_patterns/run_output_guardrails_workflow.py new file mode 100644 index 00000000..16d64764 --- /dev/null +++ b/openai_agents/agent_patterns/run_output_guardrails_workflow.py @@ -0,0 +1,40 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.output_guardrails_workflow import ( + OutputGuardrailsWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow with a normal question (should pass) + result1 = await client.execute_workflow( + OutputGuardrailsWorkflow.run, + "What's the capital of California?", + id="output-guardrails-workflow-normal", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Normal question result: {result1}") + + # Execute a workflow with input that might trigger sensitive data output + result2 = await client.execute_workflow( + OutputGuardrailsWorkflow.run, + "My phone number is 650-123-4567. Where do you think I live?", + id="output-guardrails-workflow-sensitive", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Sensitive data result: {result2}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_parallelization_workflow.py b/openai_agents/agent_patterns/run_parallelization_workflow.py new file mode 100644 index 00000000..5b8d9f5d --- /dev/null +++ b/openai_agents/agent_patterns/run_parallelization_workflow.py @@ -0,0 +1,31 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.parallelization_workflow import ( + ParallelizationWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + ParallelizationWorkflow.run, + "Hello, world! How are you today?", + id="parallelization-workflow-example", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_routing_workflow.py b/openai_agents/agent_patterns/run_routing_workflow.py new file mode 100644 index 00000000..51c28233 --- /dev/null +++ b/openai_agents/agent_patterns/run_routing_workflow.py @@ -0,0 +1,29 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.agent_patterns.workflows.routing_workflow import RoutingWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + RoutingWorkflow.run, + "Bonjour! Comment allez-vous aujourd'hui?", + id="routing-workflow-example", + task_queue="openai-agents-patterns-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/agent_patterns/run_worker.py b/openai_agents/agent_patterns/run_worker.py index 3ca0eda2..4edb8ae4 100644 --- a/openai_agents/agent_patterns/run_worker.py +++ b/openai_agents/agent_patterns/run_worker.py @@ -10,6 +10,25 @@ from openai_agents.agent_patterns.workflows.agents_as_tools_workflow import ( AgentsAsToolsWorkflow, ) +from openai_agents.agent_patterns.workflows.deterministic_workflow import ( + DeterministicWorkflow, +) +from openai_agents.agent_patterns.workflows.forcing_tool_use_workflow import ( + ForcingToolUseWorkflow, +) +from openai_agents.agent_patterns.workflows.input_guardrails_workflow import ( + InputGuardrailsWorkflow, +) +from openai_agents.agent_patterns.workflows.llm_as_a_judge_workflow import ( + LLMAsAJudgeWorkflow, +) +from openai_agents.agent_patterns.workflows.output_guardrails_workflow import ( + OutputGuardrailsWorkflow, +) +from openai_agents.agent_patterns.workflows.parallelization_workflow import ( + ParallelizationWorkflow, +) +from openai_agents.agent_patterns.workflows.routing_workflow import RoutingWorkflow async def main(): @@ -27,9 +46,16 @@ async def main(): worker = Worker( client, - task_queue="openai-agents-task-queue", + task_queue="openai-agents-patterns-task-queue", workflows=[ AgentsAsToolsWorkflow, + DeterministicWorkflow, + ParallelizationWorkflow, + LLMAsAJudgeWorkflow, + ForcingToolUseWorkflow, + InputGuardrailsWorkflow, + OutputGuardrailsWorkflow, + RoutingWorkflow, ], ) await worker.run() diff --git a/openai_agents/agent_patterns/workflows/deterministic_workflow.py b/openai_agents/agent_patterns/workflows/deterministic_workflow.py new file mode 100644 index 00000000..339e7a0f --- /dev/null +++ b/openai_agents/agent_patterns/workflows/deterministic_workflow.py @@ -0,0 +1,90 @@ +from agents import Agent, RunConfig, Runner, trace +from pydantic import BaseModel +from temporalio import workflow + +""" +This example demonstrates a deterministic flow, where each step is performed by an agent. +1. The first agent generates a story outline +2. We feed the outline into the second agent +3. The second agent checks if the outline is good quality and if it is a scifi story +4. If the outline is not good quality or not a scifi story, we stop here +5. If the outline is good quality and a scifi story, we feed the outline into the third agent +6. The third agent writes the story + +*Adapted from the OpenAI Agents SDK deterministic pattern example* +""" + + +class OutlineCheckerOutput(BaseModel): + good_quality: bool + is_scifi: bool + + +def story_outline_agent() -> Agent: + return Agent( + name="story_outline_agent", + instructions="Generate a very short story outline based on the user's input.", + ) + + +def outline_checker_agent() -> Agent: + return Agent( + name="outline_checker_agent", + instructions="Read the given story outline, and judge the quality. Also, determine if it is a scifi story.", + output_type=OutlineCheckerOutput, + ) + + +def story_agent() -> Agent: + return Agent( + name="story_agent", + instructions="Write a short story based on the given outline.", + output_type=str, + ) + + +@workflow.defn +class DeterministicWorkflow: + @workflow.run + async def run(self, input_prompt: str) -> str: + config = RunConfig() + + # Ensure the entire workflow is a single trace + with trace("Deterministic story flow"): + # 1. Generate an outline + outline_result = await Runner.run( + story_outline_agent(), + input_prompt, + run_config=config, + ) + workflow.logger.info("Outline generated") + + # 2. Check the outline + outline_checker_result = await Runner.run( + outline_checker_agent(), + outline_result.final_output, + run_config=config, + ) + + # 3. Add a gate to stop if the outline is not good quality or not a scifi story + assert isinstance(outline_checker_result.final_output, OutlineCheckerOutput) + if not outline_checker_result.final_output.good_quality: + workflow.logger.info("Outline is not good quality, so we stop here.") + return "Story generation stopped: Outline quality insufficient." + + if not outline_checker_result.final_output.is_scifi: + workflow.logger.info("Outline is not a scifi story, so we stop here.") + return "Story generation stopped: Outline is not science fiction." + + workflow.logger.info( + "Outline is good quality and a scifi story, so we continue to write the story." + ) + + # 4. Write the story + story_result = await Runner.run( + story_agent(), + outline_result.final_output, + run_config=config, + ) + + return f"Final story: {story_result.final_output}" diff --git a/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py b/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py new file mode 100644 index 00000000..a8eaedd6 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py @@ -0,0 +1,83 @@ +from typing import Any, Literal + +from agents import ( + Agent, + FunctionToolResult, + ModelSettings, + RunConfig, + RunContextWrapper, + Runner, + ToolsToFinalOutputFunction, + ToolsToFinalOutputResult, + function_tool, +) +from pydantic import BaseModel +from temporalio import workflow + +""" +This example shows how to force the agent to use a tool. It uses `ModelSettings(tool_choice="required")` +to force the agent to use any tool. + +You can run it with 3 options: +1. `default`: The default behavior, which is to send the tool output to the LLM. In this case, + `tool_choice` is not set, because otherwise it would result in an infinite loop - the LLM would + call the tool, the tool would run and send the results to the LLM, and that would repeat + (because the model is forced to use a tool every time.) +2. `first_tool_result`: The first tool result is used as the final output. +3. `custom`: A custom tool use behavior function is used. The custom function receives all the tool + results, and chooses to use the first tool result to generate the final output. + +*Adapted from the OpenAI Agents SDK forcing_tool_use pattern example* +""" + + +class Weather(BaseModel): + city: str + temperature_range: str + conditions: str + + +@function_tool +def get_weather(city: str) -> Weather: + workflow.logger.info("[debug] get_weather called") + return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind") + + +async def custom_tool_use_behavior( + context: RunContextWrapper[Any], results: list[FunctionToolResult] +) -> ToolsToFinalOutputResult: + weather: Weather = results[0].output + return ToolsToFinalOutputResult( + is_final_output=True, final_output=f"{weather.city} is {weather.conditions}." + ) + + +@workflow.defn +class ForcingToolUseWorkflow: + @workflow.run + async def run(self, tool_use_behavior: str = "default") -> str: + config = RunConfig() + + if tool_use_behavior == "default": + behavior: Literal[ + "run_llm_again", "stop_on_first_tool" + ] | ToolsToFinalOutputFunction = "run_llm_again" + elif tool_use_behavior == "first_tool": + behavior = "stop_on_first_tool" + elif tool_use_behavior == "custom": + behavior = custom_tool_use_behavior + + agent = Agent( + name="Weather agent", + instructions="You are a helpful agent.", + tools=[get_weather], + tool_use_behavior=behavior, + model_settings=ModelSettings( + tool_choice="required" if tool_use_behavior != "default" else None + ), + ) + + result = await Runner.run( + agent, input="What's the weather in Tokyo?", run_config=config + ) + return str(result.final_output) diff --git a/openai_agents/agent_patterns/workflows/input_guardrails_workflow.py b/openai_agents/agent_patterns/workflows/input_guardrails_workflow.py new file mode 100644 index 00000000..83677840 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/input_guardrails_workflow.py @@ -0,0 +1,87 @@ +from agents import ( + Agent, + GuardrailFunctionOutput, + InputGuardrailTripwireTriggered, + RunConfig, + RunContextWrapper, + Runner, + TResponseInputItem, + input_guardrail, +) +from pydantic import BaseModel +from temporalio import workflow + +""" +This example shows how to use input guardrails. + +Guardrails are checks that run in parallel to the agent's execution. +They can be used to do things like: +- Check if input messages are off-topic +- Check that input messages don't violate any policies +- Take over control of the agent's execution if an unexpected input is detected + +In this example, we'll setup an input guardrail that trips if the user is asking to do math homework. +If the guardrail trips, we'll respond with a refusal message. + +*Adapted from the OpenAI Agents SDK input_guardrails pattern example* +""" + + +class MathHomeworkOutput(BaseModel): + reasoning: str + is_math_homework: bool + + +guardrail_agent = Agent( + name="Guardrail check", + instructions="Check if the user is asking you to do their math homework.", + output_type=MathHomeworkOutput, +) + + +@input_guardrail +async def math_guardrail( + context: RunContextWrapper[None], + agent: Agent, + input: str | list[TResponseInputItem], +) -> GuardrailFunctionOutput: + """This is an input guardrail function, which happens to call an agent to check if the input + is a math homework question. + """ + result = await Runner.run(guardrail_agent, input, context=context.context) + final_output = result.final_output_as(MathHomeworkOutput) + + return GuardrailFunctionOutput( + output_info=final_output, + tripwire_triggered=final_output.is_math_homework, + ) + + +@workflow.defn +class InputGuardrailsWorkflow: + @workflow.run + async def run(self, user_input: str) -> str: + config = RunConfig() + agent = Agent( + name="Customer support agent", + instructions="You are a customer support agent. You help customers with their questions.", + input_guardrails=[math_guardrail], + ) + + input_data: list[TResponseInputItem] = [ + { + "role": "user", + "content": user_input, + } + ] + + try: + result = await Runner.run(agent, input_data, run_config=config) + return str(result.final_output) + except InputGuardrailTripwireTriggered: + # If the guardrail triggered, we instead return a refusal message + message = "Sorry, I can't help you with your math homework." + workflow.logger.info( + "Input guardrail triggered - refusing to help with math homework" + ) + return message diff --git a/openai_agents/agent_patterns/workflows/llm_as_a_judge_workflow.py b/openai_agents/agent_patterns/workflows/llm_as_a_judge_workflow.py new file mode 100644 index 00000000..7ad536f2 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/llm_as_a_judge_workflow.py @@ -0,0 +1,86 @@ +from dataclasses import dataclass +from typing import Literal + +from agents import Agent, ItemHelpers, RunConfig, Runner, TResponseInputItem, trace +from temporalio import workflow + +""" +This example shows the LLM as a judge pattern. The first agent generates an outline for a story. +The second agent judges the outline and provides feedback. We loop until the judge is satisfied +with the outline. + +*Adapted from the OpenAI Agents SDK llm_as_a_judge pattern example* +""" + + +@dataclass +class EvaluationFeedback: + feedback: str + score: Literal["pass", "needs_improvement", "fail"] + + +def story_outline_generator() -> Agent: + return Agent[None]( + name="story_outline_generator", + instructions=( + "You generate a very short story outline based on the user's input." + "If there is any feedback provided, use it to improve the outline." + ), + ) + + +def evaluator() -> Agent: + return Agent[None]( + name="evaluator", + instructions=( + "You evaluate a story outline and decide if it's good enough." + "If it's not good enough, you provide feedback on what needs to be improved." + "Never give it a pass on the first try. After 5 attempts, you can give it a pass if story outline is good enough - do not go for perfection" + ), + output_type=EvaluationFeedback, + ) + + +@workflow.defn +class LLMAsAJudgeWorkflow: + @workflow.run + async def run(self, msg: str) -> str: + config = RunConfig() + input_items: list[TResponseInputItem] = [{"content": msg, "role": "user"}] + latest_outline: str | None = None + + # We'll run the entire workflow in a single trace + with trace("LLM as a judge"): + while True: + story_outline_result = await Runner.run( + story_outline_generator(), + input_items, + run_config=config, + ) + + input_items = story_outline_result.to_input_list() + latest_outline = ItemHelpers.text_message_outputs( + story_outline_result.new_items + ) + workflow.logger.info("Story outline generated") + + evaluator_result = await Runner.run( + evaluator(), + input_items, + run_config=config, + ) + result: EvaluationFeedback = evaluator_result.final_output + + workflow.logger.info(f"Evaluator score: {result.score}") + + if result.score == "pass": + workflow.logger.info("Story outline is good enough, exiting.") + break + + workflow.logger.info("Re-running with feedback") + + input_items.append( + {"content": f"Feedback: {result.feedback}", "role": "user"} + ) + + return f"Final story outline: {latest_outline}" diff --git a/openai_agents/agent_patterns/workflows/output_guardrails_workflow.py b/openai_agents/agent_patterns/workflows/output_guardrails_workflow.py new file mode 100644 index 00000000..58a306c9 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/output_guardrails_workflow.py @@ -0,0 +1,78 @@ +from agents import ( + Agent, + GuardrailFunctionOutput, + OutputGuardrailTripwireTriggered, + RunConfig, + RunContextWrapper, + Runner, + output_guardrail, +) +from pydantic import BaseModel, Field +from temporalio import workflow + +""" +This example shows how to use output guardrails. + +Output guardrails are checks that run on the final output of an agent. +They can be used to do things like: +- Check if the output contains sensitive data +- Check if the output is a valid response to the user's message + +In this example, we'll use a (contrived) example where we check if the agent's response contains +a phone number. + +*Adapted from the OpenAI Agents SDK output_guardrails pattern example* +""" + + +class MessageOutput(BaseModel): + reasoning: str = Field( + description="Thoughts on how to respond to the user's message" + ) + response: str = Field(description="The response to the user's message") + user_name: str | None = Field( + description="The name of the user who sent the message, if known" + ) + + +@output_guardrail +async def sensitive_data_check( + context: RunContextWrapper, agent: Agent, output: MessageOutput +) -> GuardrailFunctionOutput: + phone_number_in_response = "650" in output.response + phone_number_in_reasoning = "650" in output.reasoning + + return GuardrailFunctionOutput( + output_info={ + "phone_number_in_response": phone_number_in_response, + "phone_number_in_reasoning": phone_number_in_reasoning, + }, + tripwire_triggered=phone_number_in_response or phone_number_in_reasoning, + ) + + +def assistant_agent() -> Agent: + return Agent( + name="Assistant", + instructions="You are a helpful assistant.", + output_type=MessageOutput, + output_guardrails=[sensitive_data_check], + ) + + +@workflow.defn +class OutputGuardrailsWorkflow: + @workflow.run + async def run(self, user_input: str) -> str: + config = RunConfig() + agent = assistant_agent() + + try: + result = await Runner.run(agent, user_input, run_config=config) + output = result.final_output_as(MessageOutput) + return f"Response: {output.response}" + except OutputGuardrailTripwireTriggered as e: + workflow.logger.info( + f"Output guardrail triggered. Info: {e.guardrail_result.output.output_info}" + ) + return f"Output guardrail triggered due to sensitive data detection. Info: {e.guardrail_result.output.output_info}" diff --git a/openai_agents/agent_patterns/workflows/parallelization_workflow.py b/openai_agents/agent_patterns/workflows/parallelization_workflow.py new file mode 100644 index 00000000..5a07a030 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/parallelization_workflow.py @@ -0,0 +1,70 @@ +import asyncio + +from agents import Agent, ItemHelpers, RunConfig, Runner, trace +from temporalio import workflow + +""" +This example shows the parallelization pattern. We run the agent three times in parallel, and pick +the best result. + +*Adapted from the OpenAI Agents SDK parallelization pattern example* +""" + + +def spanish_agent() -> Agent: + return Agent( + name="spanish_agent", + instructions="You translate the user's message to Spanish", + ) + + +def translation_picker() -> Agent: + return Agent( + name="translation_picker", + instructions="You pick the best Spanish translation from the given options.", + ) + + +@workflow.defn +class ParallelizationWorkflow: + @workflow.run + async def run(self, msg: str) -> str: + config = RunConfig() + + # Ensure the entire workflow is a single trace + with trace("Parallel translation"): + # Run three translation agents in parallel + res_1, res_2, res_3 = await asyncio.gather( + Runner.run( + spanish_agent(), + msg, + run_config=config, + ), + Runner.run( + spanish_agent(), + msg, + run_config=config, + ), + Runner.run( + spanish_agent(), + msg, + run_config=config, + ), + ) + + outputs = [ + ItemHelpers.text_message_outputs(res_1.new_items), + ItemHelpers.text_message_outputs(res_2.new_items), + ItemHelpers.text_message_outputs(res_3.new_items), + ] + + translations = "\n\n".join(outputs) + workflow.logger.info(f"Generated translations:\n{translations}") + + best_translation = await Runner.run( + translation_picker(), + f"Input: {msg}\n\nTranslations:\n{translations}", + run_config=config, + ) + + return f"Best translation: {best_translation.final_output}" diff --git a/openai_agents/agent_patterns/workflows/routing_workflow.py b/openai_agents/agent_patterns/workflows/routing_workflow.py new file mode 100644 index 00000000..4d821349 --- /dev/null +++ b/openai_agents/agent_patterns/workflows/routing_workflow.py @@ -0,0 +1,67 @@ +from agents import Agent, RunConfig, Runner, TResponseInputItem, trace +from temporalio import workflow + +""" +This example shows the handoffs/routing pattern. The triage agent receives the first message, and +then hands off to the appropriate agent based on the language of the request. + +Note: This is adapted from the original streaming version to work with Temporal's non-streaming approach. + +*Adapted from the OpenAI Agents SDK routing pattern example* +""" + + +def french_agent() -> Agent: + return Agent( + name="french_agent", + instructions="You only speak French", + ) + + +def spanish_agent() -> Agent: + return Agent( + name="spanish_agent", + instructions="You only speak Spanish", + ) + + +def english_agent() -> Agent: + return Agent( + name="english_agent", + instructions="You only speak English", + ) + + +def triage_agent() -> Agent: + return Agent( + name="triage_agent", + instructions="Handoff to the appropriate agent based on the language of the request.", + handoffs=[french_agent(), spanish_agent(), english_agent()], + ) + + +@workflow.defn +class RoutingWorkflow: + @workflow.run + async def run(self, msg: str) -> str: + config = RunConfig() + + with trace("Routing example"): + inputs: list[TResponseInputItem] = [{"content": msg, "role": "user"}] + + # Run the triage agent to determine which language agent to handoff to + result = await Runner.run( + triage_agent(), + input=inputs, + run_config=config, + ) + + # Get the final response after handoff + # Note: current_agent attribute may not be available in all SDK versions + workflow.logger.info("Handoff completed") + + # Convert result to proper input format for next agent + inputs = result.to_input_list() + + # Return the result from the handoff (either the handoff agent's response or triage response) + return f"Response: {result.final_output}" diff --git a/openai_agents/basic/run_worker.py b/openai_agents/basic/run_worker.py index 94d6a882..f9bc0bf5 100644 --- a/openai_agents/basic/run_worker.py +++ b/openai_agents/basic/run_worker.py @@ -47,7 +47,7 @@ async def main(): worker = Worker( client, - task_queue="openai-agents-basic-task-queue", + task_queue="openai-agents-task-queue", workflows=[ HelloWorldAgent, ToolsWorkflow, From f4486afbf0d86fbd42023aa1c6082bdab4b13675 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 17:03:39 -0600 Subject: [PATCH 06/40] OpenAI Agents - Tools, Handoffs, and Hosted MCP (#225) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * Ported Toos, Handoffs, and Hosted MCP * Revert uv.lock --------- Co-authored-by: Tim Conley --- openai_agents/handoffs/README.md | 44 +++ .../handoffs/run_message_filter_workflow.py | 38 +++ openai_agents/handoffs/run_worker.py | 42 +++ .../workflows/message_filter_workflow.py | 112 ++++++++ openai_agents/hosted_mcp/README.md | 39 +++ .../hosted_mcp/run_approval_mcp_workflow.py | 30 ++ .../hosted_mcp/run_simple_mcp_workflow.py | 30 ++ openai_agents/hosted_mcp/run_worker.py | 42 +++ .../workflows/approval_mcp_workflow.py | 48 ++++ .../workflows/simple_mcp_workflow.py | 28 ++ openai_agents/tools/README.md | 61 ++++ .../tools/run_code_interpreter_workflow.py | 32 +++ .../tools/run_file_search_workflow.py | 33 +++ .../tools/run_image_generator_workflow.py | 60 ++++ .../tools/run_web_search_workflow.py | 33 +++ openai_agents/tools/run_worker.py | 50 ++++ openai_agents/tools/setup_knowledge_base.py | 270 ++++++++++++++++++ .../workflows/code_interpreter_workflow.py | 25 ++ .../tools/workflows/file_search_workflow.py | 24 ++ .../workflows/image_generator_workflow.py | 45 +++ .../tools/workflows/web_search_workflow.py | 20 ++ 21 files changed, 1106 insertions(+) create mode 100644 openai_agents/handoffs/README.md create mode 100644 openai_agents/handoffs/run_message_filter_workflow.py create mode 100644 openai_agents/handoffs/run_worker.py create mode 100644 openai_agents/handoffs/workflows/message_filter_workflow.py create mode 100644 openai_agents/hosted_mcp/README.md create mode 100644 openai_agents/hosted_mcp/run_approval_mcp_workflow.py create mode 100644 openai_agents/hosted_mcp/run_simple_mcp_workflow.py create mode 100644 openai_agents/hosted_mcp/run_worker.py create mode 100644 openai_agents/hosted_mcp/workflows/approval_mcp_workflow.py create mode 100644 openai_agents/hosted_mcp/workflows/simple_mcp_workflow.py create mode 100644 openai_agents/tools/README.md create mode 100644 openai_agents/tools/run_code_interpreter_workflow.py create mode 100644 openai_agents/tools/run_file_search_workflow.py create mode 100644 openai_agents/tools/run_image_generator_workflow.py create mode 100644 openai_agents/tools/run_web_search_workflow.py create mode 100644 openai_agents/tools/run_worker.py create mode 100644 openai_agents/tools/setup_knowledge_base.py create mode 100644 openai_agents/tools/workflows/code_interpreter_workflow.py create mode 100644 openai_agents/tools/workflows/file_search_workflow.py create mode 100644 openai_agents/tools/workflows/image_generator_workflow.py create mode 100644 openai_agents/tools/workflows/web_search_workflow.py diff --git a/openai_agents/handoffs/README.md b/openai_agents/handoffs/README.md new file mode 100644 index 00000000..c38b0919 --- /dev/null +++ b/openai_agents/handoffs/README.md @@ -0,0 +1,44 @@ +# Handoffs Examples + +Agent handoff patterns with message filtering in Temporal workflows. + +*Adapted from [OpenAI Agents SDK handoffs examples](https://github.com/openai/openai-agents-python/tree/main/examples/handoffs)* + +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + +## Running the Examples + +First, start the worker: +```bash +uv run openai_agents/handoffs/run_worker.py +``` + +Then run the workflow: + +### Message Filter Workflow +Demonstrates agent handoffs with message history filtering: +```bash +uv run openai_agents/handoffs/run_message_filter_workflow.py +``` + +## Workflow Pattern + +The workflow demonstrates a 4-step conversation with message filtering: + +1. **Introduction**: User greets first agent with name +2. **Tool Usage**: First agent generates random number using function tool +3. **Agent Switch**: Conversation moves to second agent for general questions +4. **Spanish Handoff**: Second agent detects Spanish and hands off to Spanish specialist + +During the Spanish handoff, message filtering occurs: +- All tool-related messages are removed from history +- First two messages are dropped (demonstration of selective context) +- Filtered conversation continues with Spanish agent + +The workflow returns both the final response and complete message history for inspection. + +## Omitted Examples + +The following patterns from the [reference repository](https://github.com/openai/openai-agents-python/tree/main/examples/handoffs) are not included in this Temporal adaptation: + +- **Message Filter Streaming**: Streaming capabilities are not yet available in the Temporal integration \ No newline at end of file diff --git a/openai_agents/handoffs/run_message_filter_workflow.py b/openai_agents/handoffs/run_message_filter_workflow.py new file mode 100644 index 00000000..7ecb9f47 --- /dev/null +++ b/openai_agents/handoffs/run_message_filter_workflow.py @@ -0,0 +1,38 @@ +import asyncio +import json + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.handoffs.workflows.message_filter_workflow import ( + MessageFilterWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + MessageFilterWorkflow.run, + "Sora", + id="message-filter-workflow", + task_queue="openai-agents-handoffs-task-queue", + ) + + print(f"Final output: {result.final_output}") + print("\n===Final messages===\n") + + # Print the final message history to see the effect of the message filter + for message in result.final_messages: + print(json.dumps(message, indent=2)) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/handoffs/run_worker.py b/openai_agents/handoffs/run_worker.py new file mode 100644 index 00000000..8941f4d8 --- /dev/null +++ b/openai_agents/handoffs/run_worker.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.handoffs.workflows.message_filter_workflow import ( + MessageFilterWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-handoffs-task-queue", + workflows=[ + MessageFilterWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/handoffs/workflows/message_filter_workflow.py b/openai_agents/handoffs/workflows/message_filter_workflow.py new file mode 100644 index 00000000..8adc9453 --- /dev/null +++ b/openai_agents/handoffs/workflows/message_filter_workflow.py @@ -0,0 +1,112 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import List + +from agents import Agent, HandoffInputData, Runner, function_tool, handoff +from agents.extensions import handoff_filters +from agents.items import TResponseInputItem +from temporalio import workflow + + +@dataclass +class MessageFilterResult: + final_output: str + final_messages: List[TResponseInputItem] + + +@function_tool +def random_number_tool(max: int) -> int: + """Return a random integer between 0 and the given maximum.""" + return workflow.random().randint(0, max) + + +def spanish_handoff_message_filter( + handoff_message_data: HandoffInputData, +) -> HandoffInputData: + # First, we'll remove any tool-related messages from the message history + handoff_message_data = handoff_filters.remove_all_tools(handoff_message_data) + + # Second, we'll also remove the first two items from the history, just for demonstration + history = ( + tuple(handoff_message_data.input_history[2:]) + if isinstance(handoff_message_data.input_history, tuple) + else handoff_message_data.input_history + ) + + return HandoffInputData( + input_history=history, + pre_handoff_items=tuple(handoff_message_data.pre_handoff_items), + new_items=tuple(handoff_message_data.new_items), + ) + + +@workflow.defn +class MessageFilterWorkflow: + @workflow.run + async def run(self, user_name: str = "Sora") -> MessageFilterResult: + first_agent = Agent( + name="Assistant", + instructions="Be extremely concise.", + tools=[random_number_tool], + ) + + spanish_agent = Agent( + name="Spanish Assistant", + instructions="You only speak Spanish and are extremely concise.", + handoff_description="A Spanish-speaking assistant.", + ) + + second_agent = Agent( + name="Assistant", + instructions=( + "Be a helpful assistant. If the user speaks Spanish, handoff to the Spanish assistant." + ), + handoffs=[ + handoff(spanish_agent, input_filter=spanish_handoff_message_filter) + ], + ) + + # 1. Send a regular message to the first agent + result = await Runner.run(first_agent, input=f"Hi, my name is {user_name}.") + + # 2. Ask it to generate a number + result = await Runner.run( + first_agent, + input=result.to_input_list() + + [ + { + "content": "Can you generate a random number between 0 and 100?", + "role": "user", + } + ], + ) + + # 3. Call the second agent + result = await Runner.run( + second_agent, + input=result.to_input_list() + + [ + { + "content": "I live in New York City. What's the population of the city?", + "role": "user", + } + ], + ) + + # 4. Cause a handoff to occur + result = await Runner.run( + second_agent, + input=result.to_input_list() + + [ + { + "content": "Por favor habla en espaΓ±ol. ΒΏCuΓ‘l es mi nombre y dΓ³nde vivo?", + "role": "user", + } + ], + ) + + # Return the final result and message history + return MessageFilterResult( + final_output=result.final_output, final_messages=result.to_input_list() + ) diff --git a/openai_agents/hosted_mcp/README.md b/openai_agents/hosted_mcp/README.md new file mode 100644 index 00000000..78a37131 --- /dev/null +++ b/openai_agents/hosted_mcp/README.md @@ -0,0 +1,39 @@ +# Hosted MCP Examples + +Integration with hosted MCP (Model Context Protocol) servers using OpenAI agents in Temporal workflows. + +*Adapted from [OpenAI Agents SDK hosted_mcp examples](https://github.com/openai/openai-agents-python/tree/main/examples/hosted_mcp)* + +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + +## Running the Examples + +First, start the worker (supports all MCP workflows): +```bash +uv run openai_agents/hosted_mcp/run_worker.py +``` + +Then run individual examples in separate terminals: + +### Simple MCP Connection +Connect to a hosted MCP server without approval requirements (trusted servers): +```bash +uv run openai_agents/hosted_mcp/run_simple_mcp_workflow.py +``` + +### MCP with Approval Callbacks +Connect to a hosted MCP server with approval workflow for tool execution: +```bash +uv run openai_agents/hosted_mcp/run_approval_mcp_workflow.py +``` + +## MCP Server Configuration + +Both examples default to using the GitMCP server (`https://gitmcp.io/openai/codex`) which provides repository analysis capabilities. The workflows can be easily modified to use different MCP servers by changing the `server_url` parameter. + +### Approval Workflow Notes + +The approval example demonstrates the callback structure for tool approvals in a Temporal context. In this implementation: + +- The approval callback automatically approves requests for demonstration purposes +- In production environments, approvals would typically be handled by communicating with a human user. Because the approval executes in the Temporal workflow, you can use signals or updates to communicate approval status. diff --git a/openai_agents/hosted_mcp/run_approval_mcp_workflow.py b/openai_agents/hosted_mcp/run_approval_mcp_workflow.py new file mode 100644 index 00000000..8821c78a --- /dev/null +++ b/openai_agents/hosted_mcp/run_approval_mcp_workflow.py @@ -0,0 +1,30 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.hosted_mcp.workflows.approval_mcp_workflow import ApprovalMCPWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + ApprovalMCPWorkflow.run, + "Which language is this repo written in?", + id="approval-mcp-workflow", + task_queue="openai-agents-hosted-mcp-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/hosted_mcp/run_simple_mcp_workflow.py b/openai_agents/hosted_mcp/run_simple_mcp_workflow.py new file mode 100644 index 00000000..5e0c064f --- /dev/null +++ b/openai_agents/hosted_mcp/run_simple_mcp_workflow.py @@ -0,0 +1,30 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.hosted_mcp.workflows.simple_mcp_workflow import SimpleMCPWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + SimpleMCPWorkflow.run, + "Which language is this repo written in?", + id="simple-mcp-workflow", + task_queue="openai-agents-hosted-mcp-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/hosted_mcp/run_worker.py b/openai_agents/hosted_mcp/run_worker.py new file mode 100644 index 00000000..fb25f7b6 --- /dev/null +++ b/openai_agents/hosted_mcp/run_worker.py @@ -0,0 +1,42 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.hosted_mcp.workflows.approval_mcp_workflow import ApprovalMCPWorkflow +from openai_agents.hosted_mcp.workflows.simple_mcp_workflow import SimpleMCPWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-hosted-mcp-task-queue", + workflows=[ + SimpleMCPWorkflow, + ApprovalMCPWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/hosted_mcp/workflows/approval_mcp_workflow.py b/openai_agents/hosted_mcp/workflows/approval_mcp_workflow.py new file mode 100644 index 00000000..1b5b7b6f --- /dev/null +++ b/openai_agents/hosted_mcp/workflows/approval_mcp_workflow.py @@ -0,0 +1,48 @@ +from __future__ import annotations + +from agents import ( + Agent, + HostedMCPTool, + MCPToolApprovalFunctionResult, + MCPToolApprovalRequest, + Runner, +) +from temporalio import workflow + + +def approval_callback(request: MCPToolApprovalRequest) -> MCPToolApprovalFunctionResult: + """Simple approval callback that logs the request and approves by default. + + In a real application, user input would be provided through a UI or API. + The approval callback executes within the Temporal workflow, so the application + can use signals or updates to receive user input. + """ + workflow.logger.info(f"MCP tool approval requested for: {request.data.name}") + + result: MCPToolApprovalFunctionResult = {"approve": True} + return result + + +@workflow.defn +class ApprovalMCPWorkflow: + @workflow.run + async def run( + self, question: str, server_url: str = "https://gitmcp.io/openai/codex" + ) -> str: + agent = Agent( + name="Assistant", + tools=[ + HostedMCPTool( + tool_config={ + "type": "mcp", + "server_label": "gitmcp", + "server_url": server_url, + "require_approval": "always", + }, + on_approval_request=approval_callback, + ) + ], + ) + + result = await Runner.run(agent, question) + return result.final_output diff --git a/openai_agents/hosted_mcp/workflows/simple_mcp_workflow.py b/openai_agents/hosted_mcp/workflows/simple_mcp_workflow.py new file mode 100644 index 00000000..2fac64bc --- /dev/null +++ b/openai_agents/hosted_mcp/workflows/simple_mcp_workflow.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from agents import Agent, HostedMCPTool, Runner +from temporalio import workflow + + +@workflow.defn +class SimpleMCPWorkflow: + @workflow.run + async def run( + self, question: str, server_url: str = "https://gitmcp.io/openai/codex" + ) -> str: + agent = Agent( + name="Assistant", + tools=[ + HostedMCPTool( + tool_config={ + "type": "mcp", + "server_label": "gitmcp", + "server_url": server_url, + "require_approval": "never", + } + ) + ], + ) + + result = await Runner.run(agent, question) + return result.final_output diff --git a/openai_agents/tools/README.md b/openai_agents/tools/README.md new file mode 100644 index 00000000..6f65e432 --- /dev/null +++ b/openai_agents/tools/README.md @@ -0,0 +1,61 @@ +# Tools Examples + +Demonstrations of various OpenAI agent tools integrated with Temporal workflows. + +*Adapted from [OpenAI Agents SDK tools examples](https://github.com/openai/openai-agents-python/tree/main/examples/tools)* + +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + +## Setup + +### Knowledge Base Setup (Required for File Search) +Create a vector store with sample documents for file search testing: +```bash +uv run openai_agents/tools/setup_knowledge_base.py +``` + +This script: +- Creates 6 sample documents +- Uploads files to OpenAI with proper cleanup using context managers +- Creates an assistant with vector store for file search capabilities +- Updates workflow files with the new vector store ID automatically + +## Running the Examples + +First, start the worker (supports all tools): +```bash +uv run openai_agents/tools/run_worker.py +``` + +Then run individual examples in separate terminals: + +### Code Interpreter +Execute Python code for mathematical calculations and data analysis: +```bash +uv run openai_agents/tools/run_code_interpreter_workflow.py +``` + +### File Search +Search through uploaded documents using vector similarity: +```bash +uv run openai_agents/tools/run_file_search_workflow.py +``` + +### Image Generation +Generate images: +```bash +uv run openai_agents/tools/run_image_generator_workflow.py +``` + +### Web Search +Search the web for current information with location context: +```bash +uv run openai_agents/tools/run_web_search_workflow.py +``` + + +## Omitted Examples + +The following tools from the [reference repository](https://github.com/openai/openai-agents-python/tree/main/examples/tools) are not included in this Temporal adaptation: + +- **Computer Use**: Complex browser automation not suitable for distributed systems implementation. \ No newline at end of file diff --git a/openai_agents/tools/run_code_interpreter_workflow.py b/openai_agents/tools/run_code_interpreter_workflow.py new file mode 100644 index 00000000..2b819712 --- /dev/null +++ b/openai_agents/tools/run_code_interpreter_workflow.py @@ -0,0 +1,32 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.tools.workflows.code_interpreter_workflow import ( + CodeInterpreterWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + CodeInterpreterWorkflow.run, + "What is the square root of 273 * 312821 plus 1782?", + id="code-interpreter-workflow", + task_queue="openai-agents-tools-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/run_file_search_workflow.py b/openai_agents/tools/run_file_search_workflow.py new file mode 100644 index 00000000..09b8bb57 --- /dev/null +++ b/openai_agents/tools/run_file_search_workflow.py @@ -0,0 +1,33 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.tools.workflows.file_search_workflow import FileSearchWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + FileSearchWorkflow.run, + args=[ + "Be concise, and tell me 1 sentence about Arrakis I might not know.", + "vs_68855c27140c8191849b5f1887d8d335", # Vector store with Arrakis knowledge + ], + id="file-search-workflow", + task_queue="openai-agents-tools-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/run_image_generator_workflow.py b/openai_agents/tools/run_image_generator_workflow.py new file mode 100644 index 00000000..77a60d26 --- /dev/null +++ b/openai_agents/tools/run_image_generator_workflow.py @@ -0,0 +1,60 @@ +import asyncio +import base64 +import os +import subprocess +import sys +import tempfile + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.tools.workflows.image_generator_workflow import ( + ImageGeneratorWorkflow, +) + + +def open_file(path: str) -> None: + if sys.platform.startswith("darwin"): + subprocess.run(["open", path], check=False) # macOS + elif os.name == "nt": # Windows + os.startfile(path) # type: ignore + elif os.name == "posix": + subprocess.run(["xdg-open", path], check=False) # Linux/Unix + else: + print(f"Don't know how to open files on this platform: {sys.platform}") + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + ImageGeneratorWorkflow.run, + "Create an image of a frog eating a pizza, comic book style.", + id="image-generator-workflow", + task_queue="openai-agents-tools-task-queue", + ) + + print(f"Text result: {result.final_output}") + + if result.image_data: + # Save and open the image + with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp: + tmp.write(base64.b64decode(result.image_data)) + temp_path = tmp.name + + print(f"Image saved to: {temp_path}") + # Open the image + open_file(temp_path) + else: + print("No image data found in result") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/run_web_search_workflow.py b/openai_agents/tools/run_web_search_workflow.py new file mode 100644 index 00000000..dd7f992f --- /dev/null +++ b/openai_agents/tools/run_web_search_workflow.py @@ -0,0 +1,33 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.tools.workflows.web_search_workflow import WebSearchWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + WebSearchWorkflow.run, + args=[ + "search the web for 'local sports news' and give me 1 interesting update in a sentence.", + "New York", + ], + id="web-search-workflow", + task_queue="openai-agents-tools-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/run_worker.py b/openai_agents/tools/run_worker.py new file mode 100644 index 00000000..a58df470 --- /dev/null +++ b/openai_agents/tools/run_worker.py @@ -0,0 +1,50 @@ +from __future__ import annotations + +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.tools.workflows.code_interpreter_workflow import ( + CodeInterpreterWorkflow, +) +from openai_agents.tools.workflows.file_search_workflow import FileSearchWorkflow +from openai_agents.tools.workflows.image_generator_workflow import ( + ImageGeneratorWorkflow, +) +from openai_agents.tools.workflows.web_search_workflow import WebSearchWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ) + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-tools-task-queue", + workflows=[ + CodeInterpreterWorkflow, + FileSearchWorkflow, + ImageGeneratorWorkflow, + WebSearchWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/setup_knowledge_base.py b/openai_agents/tools/setup_knowledge_base.py new file mode 100644 index 00000000..fc467805 --- /dev/null +++ b/openai_agents/tools/setup_knowledge_base.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +""" +Setup script to create vector store with sample documents for testing FileSearchWorkflow. +Creates documents about Arrakis/Dune and uploads them to OpenAI for file search testing. +""" + +import asyncio +import os +import tempfile +from contextlib import asynccontextmanager +from pathlib import Path +from typing import Dict, List + +from openai import AsyncOpenAI + +# Sample knowledge base content +KNOWLEDGE_BASE = { + "arrakis_overview": """ +Arrakis: The Desert Planet + +Arrakis, also known as Dune, is the third planet of the Canopus system. This harsh desert world is the sole source of the spice melange, the most valuable substance in the known universe. + +Key characteristics: +- Single biome: Desert covering the entire planet +- No natural precipitation +- Extreme temperature variations between day and night +- Home to the giant sandworms (Shai-Hulud) +- Indigenous population: the Fremen + +The planet's ecology is entirely dependent on the sandworms, which produce the spice as a byproduct of their life cycle. Water is incredibly scarce, leading to the development of stillsuits and other water conservation technologies. +""", + "spice_melange": """ +The Spice Melange + +Melange, commonly known as "the spice," is the most important substance in the Dune universe. This geriatric spice extends life, expands consciousness, and is essential for space navigation. + +Properties of Spice: +- Extends human lifespan significantly +- Enhances mental abilities and prescient vision +- Required for Guild Navigators to fold space +- Highly addictive with fatal withdrawal symptoms +- Turns eyes blue over time (the "Eyes of Ibad") + +Production: +The spice is created through the interaction of sandworms with pre-spice masses in the deep desert. The presence of water is toxic to sandworms, making Arrakis the only known source of spice in the universe. + +Economic Impact: +Control of spice production grants immense political and economic power, making Arrakis the most strategically important planet in the Imperium. +""", + "sandworms": """ +Sandworms of Arrakis + +The sandworms, known to the Fremen as Shai-Hulud ("Old Man of the Desert"), are colossal creatures that dominate Arrakis. These massive beings can grow to lengths of over 400 meters and live for thousands of years. + +Characteristics: +- Enormous size: up to 400+ meters in length +- Extreme sensitivity to water and moisture +- Produce the spice melange as part of their life cycle +- Territorial and attracted to rhythmic vibrations +- Crystalline teeth capable of crushing rock and metal + +Life Cycle: +Sandworms begin as sandtrout, small creatures that sequester water. They eventually metamorphose into the giant sandworms through a complex process involving spice production. + +Cultural Significance: +The Fremen worship sandworms as semi-divine beings and have developed elaborate rituals around them, including the dangerous practice of sandworm riding. +""", + "fremen_culture": """ +The Fremen of Arrakis + +The Fremen are the indigenous people of Arrakis, perfectly adapted to life in the harsh desert environment. Their culture revolves around water conservation, survival, and reverence for the sandworms. + +Cultural Practices: +- Water discipline: Every drop of moisture is preserved +- Stillsuits: Advanced technology to recycle body moisture +- Desert survival skills passed down through generations +- Ritualistic relationship with sandworms +- Sietch communities: Hidden underground settlements + +Religious Beliefs: +The Fremen follow a syncretic religion combining elements of Islam, Buddhism, and Christianity, adapted to their desert environment. They believe in prophecies of a messiah who will transform Arrakis. + +Military Prowess: +Despite their seemingly primitive lifestyle, the Fremen are formidable warriors, using their intimate knowledge of the desert and unconventional tactics to great effect. +""", + "house_atreides": """ +House Atreides and Arrakis + +House Atreides, led by Duke Leto Atreides, was granted control of Arrakis by Emperor Shaddam IV in a political trap designed to destroy the noble house. This transition from House Harkonnen marked the beginning of the events in Dune. + +Key Figures: +- Duke Leto Atreides: Noble leader focused on honor and justice +- Lady Jessica: Bene Gesserit concubine and mother of Paul +- Paul Atreides: Heir to the duchy and potential Kwisatz Haderach +- Duncan Idaho: Loyal swordmaster and warrior +- Gurney Halleck: Weapons master and troubadour + +The Atreides approach to ruling Arrakis differed dramatically from the Harkonnens, seeking to work with the Fremen rather than exploit them. This philosophy, while noble, ultimately led to their downfall when the Emperor and Harkonnens betrayed them. + +Legacy: +Though House Atreides was destroyed in the coup, Paul's survival and alliance with the Fremen would eventually lead to an even greater destiny. +""", + "ecology_arrakis": """ +The Ecology of Arrakis + +Arrakis presents a unique ecosystem entirely based on the water cycle created by sandworms and sandtrout. This closed ecological system has evolved over millennia to support life in extreme desert conditions. + +Water Cycle: +- Sandtrout sequester all available water deep underground +- This creates the desert conditions necessary for spice production +- Adult sandworms are killed by water, maintaining the cycle +- Plants and animals have evolved extreme water conservation + +Flora and Fauna: +- Desert plants with deep root systems and water storage +- Small desert animals adapted to minimal water consumption +- No large surface water bodies exist naturally +- All life forms show evolutionary adaptation to water scarcity + +The ecosystem is incredibly fragile - any significant introduction of water could disrupt the entire balance and potentially eliminate spice production, fundamentally changing the planet and the universe's economy. +""", +} + + +@asynccontextmanager +async def temporary_files(content_dict: Dict[str, str]): + """Context manager to create and cleanup temporary files.""" + temp_files = [] + try: + for name, content in content_dict.items(): + temp_file = tempfile.NamedTemporaryFile( + mode="w", suffix=".txt", prefix=f"{name}_", delete=False + ) + temp_file.write(content) + temp_file.close() + temp_files.append((name, temp_file.name)) + + yield temp_files + finally: + for _, temp_path in temp_files: + try: + os.unlink(temp_path) + except OSError: + pass + + +async def upload_files_to_openai(temp_files: List[tuple[str, str]]) -> List[str]: + """Upload temporary files to OpenAI and return file IDs.""" + client = AsyncOpenAI() + file_ids = [] + + for name, temp_path in temp_files: + try: + with open(temp_path, "rb") as f: + file_obj = await client.files.create(file=f, purpose="assistants") + file_ids.append(file_obj.id) + print(f"Uploaded {name}: {file_obj.id}") + except Exception as e: + print(f"Error uploading {name}: {e}") + + return file_ids + + +async def create_vector_store_with_assistant(file_ids: List[str]) -> str: + """Create an assistant with vector store containing the uploaded files.""" + client = AsyncOpenAI() + + try: + assistant = await client.beta.assistants.create( + name="Arrakis Knowledge Assistant", + instructions="You are an expert on Arrakis and the Dune universe. Use the uploaded files to answer questions about the desert planet, spice, sandworms, Fremen culture, and related topics.", + model="gpt-4o", + tools=[{"type": "file_search"}], + tool_resources={ + "file_search": { + "vector_stores": [ + { + "file_ids": file_ids, + "metadata": {"name": "Arrakis Knowledge Base"}, + } + ] + } + }, + ) + + # Extract vector store ID from assistant + if assistant.tool_resources and assistant.tool_resources.file_search: + vector_store_ids = assistant.tool_resources.file_search.vector_store_ids + if vector_store_ids: + return vector_store_ids[0] + + raise Exception("No vector store ID found in assistant response") + + except Exception as e: + print(f"Error creating assistant: {e}") + raise + + +def update_workflow_files(vector_store_id: str): + """Update workflow files with the new vector store ID.""" + import re + + files_to_update = ["run_file_search_workflow.py"] + + # Pattern to match any vector store ID with the specific comment + pattern = r'(vs_[a-f0-9]+)",\s*#\s*Vector store with Arrakis knowledge' + replacement = f'{vector_store_id}", # Vector store with Arrakis knowledge' + + for filename in files_to_update: + file_path = Path(__file__).parent / filename + if file_path.exists(): + try: + content = file_path.read_text() + if re.search(pattern, content): + updated_content = re.sub(pattern, replacement, content) + file_path.write_text(updated_content) + print(f"Updated {filename} with vector store ID") + else: + print(f"No matching pattern found in {filename}") + except Exception as e: + print(f"Error updating {filename}: {e}") + + +async def main(): + """Main function to set up the knowledge base.""" + # Check for API key + if not os.getenv("OPENAI_API_KEY"): + print("Error: OPENAI_API_KEY environment variable not set") + print("Please set your OpenAI API key:") + print("export OPENAI_API_KEY='your-api-key-here'") + return + + print("Setting up Arrakis knowledge base...") + + try: + # Create temporary files and upload them + async with temporary_files(KNOWLEDGE_BASE) as temp_files: + print(f"Created {len(temp_files)} temporary files") + + file_ids = await upload_files_to_openai(temp_files) + + if not file_ids: + print("Error: No files were successfully uploaded") + return + + print(f"Successfully uploaded {len(file_ids)} files") + + # Create vector store via assistant + vector_store_id = await create_vector_store_with_assistant(file_ids) + + print(f"Created vector store: {vector_store_id}") + + # Update workflow files + update_workflow_files(vector_store_id) + + print() + print("=" * 60) + print("KNOWLEDGE BASE SETUP COMPLETE") + print("=" * 60) + print(f"Vector Store ID: {vector_store_id}") + print(f"Files indexed: {len(file_ids)}") + print("Content: Arrakis/Dune universe knowledge") + print("=" * 60) + + except Exception as e: + print(f"Setup failed: {e}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/tools/workflows/code_interpreter_workflow.py b/openai_agents/tools/workflows/code_interpreter_workflow.py new file mode 100644 index 00000000..6715bc50 --- /dev/null +++ b/openai_agents/tools/workflows/code_interpreter_workflow.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from agents import Agent, CodeInterpreterTool, Runner +from temporalio import workflow + + +@workflow.defn +class CodeInterpreterWorkflow: + @workflow.run + async def run(self, question: str) -> str: + agent = Agent( + name="Code interpreter", + instructions="You love doing math.", + tools=[ + CodeInterpreterTool( + tool_config={ + "type": "code_interpreter", + "container": {"type": "auto"}, + }, + ) + ], + ) + + result = await Runner.run(agent, question) + return result.final_output diff --git a/openai_agents/tools/workflows/file_search_workflow.py b/openai_agents/tools/workflows/file_search_workflow.py new file mode 100644 index 00000000..915dcec4 --- /dev/null +++ b/openai_agents/tools/workflows/file_search_workflow.py @@ -0,0 +1,24 @@ +from __future__ import annotations + +from agents import Agent, FileSearchTool, Runner +from temporalio import workflow + + +@workflow.defn +class FileSearchWorkflow: + @workflow.run + async def run(self, question: str, vector_store_id: str) -> str: + agent = Agent( + name="File searcher", + instructions="You are a helpful agent.", + tools=[ + FileSearchTool( + max_num_results=3, + vector_store_ids=[vector_store_id], + include_search_results=True, + ) + ], + ) + + result = await Runner.run(agent, question) + return result.final_output diff --git a/openai_agents/tools/workflows/image_generator_workflow.py b/openai_agents/tools/workflows/image_generator_workflow.py new file mode 100644 index 00000000..7c58091b --- /dev/null +++ b/openai_agents/tools/workflows/image_generator_workflow.py @@ -0,0 +1,45 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import Optional + +from agents import Agent, ImageGenerationTool, Runner +from temporalio import workflow + + +@dataclass +class ImageGenerationResult: + final_output: str + image_data: Optional[str] = None + + +@workflow.defn +class ImageGeneratorWorkflow: + @workflow.run + async def run(self, prompt: str) -> ImageGenerationResult: + agent = Agent( + name="Image generator", + instructions="You are a helpful agent.", + tools=[ + ImageGenerationTool( + tool_config={"type": "image_generation", "quality": "low"}, + ) + ], + ) + + result = await Runner.run(agent, prompt) + + # Extract image data if available + image_data = None + for item in result.new_items: + if ( + item.type == "tool_call_item" + and item.raw_item.type == "image_generation_call" + and (img_result := item.raw_item.result) + ): + image_data = img_result + break + + return ImageGenerationResult( + final_output=result.final_output, image_data=image_data + ) diff --git a/openai_agents/tools/workflows/web_search_workflow.py b/openai_agents/tools/workflows/web_search_workflow.py new file mode 100644 index 00000000..8b505ac1 --- /dev/null +++ b/openai_agents/tools/workflows/web_search_workflow.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +from agents import Agent, Runner, WebSearchTool +from temporalio import workflow + + +@workflow.defn +class WebSearchWorkflow: + @workflow.run + async def run(self, question: str, user_city: str = "New York") -> str: + agent = Agent( + name="Web searcher", + instructions="You are a helpful agent.", + tools=[ + WebSearchTool(user_location={"type": "approximate", "city": user_city}) + ], + ) + + result = await Runner.run(agent, question) + return result.final_output From dc337295bcf7ccebb71f108974dcebaa3d986360 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 17:19:28 -0600 Subject: [PATCH 07/40] OpenAI Agents financial research and reasoning examples (#226) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * Port financial research example and reasoning_content example * formatting * switch model * pin model snapshot * Revert uv.lock --------- Co-authored-by: Tim Conley --- .../financial_research_agent/README.md | 61 ++++++++ .../agents/financials_agent.py | 23 +++ .../agents/planner_agent.py | 35 +++++ .../agents/risk_agent.py | 22 +++ .../agents/search_agent.py | 20 +++ .../agents/verifier_agent.py | 27 ++++ .../agents/writer_agent.py | 34 +++++ .../financial_research_manager.py | 142 ++++++++++++++++++ .../run_financial_research_workflow.py | 41 +++++ .../financial_research_agent/run_worker.py | 33 ++++ .../workflows/financial_research_workflow.py | 13 ++ openai_agents/reasoning_content/README.md | 37 +++++ .../activities/reasoning_activities.py | 52 +++++++ .../run_reasoning_content_workflow.py | 54 +++++++ openai_agents/reasoning_content/run_worker.py | 37 +++++ .../workflows/reasoning_content_workflow.py | 32 ++++ 16 files changed, 663 insertions(+) create mode 100644 openai_agents/financial_research_agent/README.md create mode 100644 openai_agents/financial_research_agent/agents/financials_agent.py create mode 100644 openai_agents/financial_research_agent/agents/planner_agent.py create mode 100644 openai_agents/financial_research_agent/agents/risk_agent.py create mode 100644 openai_agents/financial_research_agent/agents/search_agent.py create mode 100644 openai_agents/financial_research_agent/agents/verifier_agent.py create mode 100644 openai_agents/financial_research_agent/agents/writer_agent.py create mode 100644 openai_agents/financial_research_agent/financial_research_manager.py create mode 100644 openai_agents/financial_research_agent/run_financial_research_workflow.py create mode 100644 openai_agents/financial_research_agent/run_worker.py create mode 100644 openai_agents/financial_research_agent/workflows/financial_research_workflow.py create mode 100644 openai_agents/reasoning_content/README.md create mode 100644 openai_agents/reasoning_content/activities/reasoning_activities.py create mode 100644 openai_agents/reasoning_content/run_reasoning_content_workflow.py create mode 100644 openai_agents/reasoning_content/run_worker.py create mode 100644 openai_agents/reasoning_content/workflows/reasoning_content_workflow.py diff --git a/openai_agents/financial_research_agent/README.md b/openai_agents/financial_research_agent/README.md new file mode 100644 index 00000000..fed8e5b2 --- /dev/null +++ b/openai_agents/financial_research_agent/README.md @@ -0,0 +1,61 @@ +# Financial Research Agent + +Multi-agent financial research system with specialized roles, extended with Temporal's durable execution. + +*Adapted from [OpenAI Agents SDK financial research agent](https://github.com/openai/openai-agents-python/tree/main/examples/financial_research_agent)* + +## Architecture + +This example shows how you might compose a richer financial research agent using the Agents SDK. The pattern is similar to the `research_bot` example, but with more specialized sub-agents and a verification step. + +The flow is: + +1. **Planning**: A planner agent turns the end user's request into a list of search terms relevant to financial analysis – recent news, earnings calls, corporate filings, industry commentary, etc. +2. **Search**: A search agent uses the built-in `WebSearchTool` to retrieve terse summaries for each search term. (You could also add `FileSearchTool` if you have indexed PDFs or 10-Ks.) +3. **Sub-analysts**: Additional agents (e.g. a fundamentals analyst and a risk analyst) are exposed as tools so the writer can call them inline and incorporate their outputs. +4. **Writing**: A senior writer agent brings together the search snippets and any sub-analyst summaries into a long-form markdown report plus a short executive summary. +5. **Verification**: A final verifier agent audits the report for obvious inconsistencies or missing sourcing. + +## Running the Example + +First, start the worker: +```bash +uv run openai_agents/financial_research_agent/run_worker.py +``` + +Then run the financial research workflow: +```bash +uv run openai_agents/financial_research_agent/run_financial_research_workflow.py +``` + +Enter a query like: +``` +Write up an analysis of Apple Inc.'s most recent quarter. +``` + +You can also just hit enter to run this query, which is provided as the default. + +## Components + +### Agents + +- **Planner Agent**: Creates a search plan with 5-15 relevant search terms +- **Search Agent**: Uses web search to gather financial information +- **Financials Agent**: Analyzes company fundamentals (revenue, profit, margins) +- **Risk Agent**: Identifies potential red flags and risk factors +- **Writer Agent**: Synthesizes information into a comprehensive report +- **Verifier Agent**: Audits the final report for consistency and accuracy + +### Writer Agent Tools + +The writer agent has access to tools that invoke the specialist analysts: +- `fundamentals_analysis`: Get financial performance analysis +- `risk_analysis`: Get risk factor assessment + +## Temporal Integration + +The example demonstrates several Temporal patterns: +- Durable execution of multi-step research workflows +- Parallel execution of web searches using `asyncio.create_task` +- Use of `workflow.as_completed` for handling concurrent tasks +- Proper import handling with `workflow.unsafe.imports_passed_through()` diff --git a/openai_agents/financial_research_agent/agents/financials_agent.py b/openai_agents/financial_research_agent/agents/financials_agent.py new file mode 100644 index 00000000..72a2be95 --- /dev/null +++ b/openai_agents/financial_research_agent/agents/financials_agent.py @@ -0,0 +1,23 @@ +from agents import Agent +from pydantic import BaseModel + +# A sub-agent focused on analyzing a company's fundamentals. +FINANCIALS_PROMPT = ( + "You are a financial analyst focused on company fundamentals such as revenue, " + "profit, margins and growth trajectory. Given a collection of web (and optional file) " + "search results about a company, write a concise analysis of its recent financial " + "performance. Pull out key metrics or quotes. Keep it under 2 paragraphs." +) + + +class AnalysisSummary(BaseModel): + summary: str + """Short text summary for this aspect of the analysis.""" + + +def new_financials_agent() -> Agent: + return Agent( + name="FundamentalsAnalystAgent", + instructions=FINANCIALS_PROMPT, + output_type=AnalysisSummary, + ) diff --git a/openai_agents/financial_research_agent/agents/planner_agent.py b/openai_agents/financial_research_agent/agents/planner_agent.py new file mode 100644 index 00000000..8c7ffcb9 --- /dev/null +++ b/openai_agents/financial_research_agent/agents/planner_agent.py @@ -0,0 +1,35 @@ +from agents import Agent +from pydantic import BaseModel + +# Generate a plan of searches to ground the financial analysis. +# For a given financial question or company, we want to search for +# recent news, official filings, analyst commentary, and other +# relevant background. +PROMPT = ( + "You are a financial research planner. Given a request for financial analysis, " + "produce a set of web searches to gather the context needed. Aim for recent " + "headlines, earnings calls or 10-K snippets, analyst commentary, and industry background. " + "Output between 5 and 15 search terms to query for." +) + + +class FinancialSearchItem(BaseModel): + reason: str + """Your reasoning for why this search is relevant.""" + + query: str + """The search term to feed into a web (or file) search.""" + + +class FinancialSearchPlan(BaseModel): + searches: list[FinancialSearchItem] + """A list of searches to perform.""" + + +def new_planner_agent() -> Agent: + return Agent( + name="FinancialPlannerAgent", + instructions=PROMPT, + model="o3-mini", + output_type=FinancialSearchPlan, + ) diff --git a/openai_agents/financial_research_agent/agents/risk_agent.py b/openai_agents/financial_research_agent/agents/risk_agent.py new file mode 100644 index 00000000..c73e94ef --- /dev/null +++ b/openai_agents/financial_research_agent/agents/risk_agent.py @@ -0,0 +1,22 @@ +from agents import Agent +from pydantic import BaseModel + +# A sub-agent specializing in identifying risk factors or concerns. +RISK_PROMPT = ( + "You are a risk analyst looking for potential red flags in a company's outlook. " + "Given background research, produce a short analysis of risks such as competitive threats, " + "regulatory issues, supply chain problems, or slowing growth. Keep it under 2 paragraphs." +) + + +class AnalysisSummary(BaseModel): + summary: str + """Short text summary for this aspect of the analysis.""" + + +def new_risk_agent() -> Agent: + return Agent( + name="RiskAnalystAgent", + instructions=RISK_PROMPT, + output_type=AnalysisSummary, + ) diff --git a/openai_agents/financial_research_agent/agents/search_agent.py b/openai_agents/financial_research_agent/agents/search_agent.py new file mode 100644 index 00000000..e40e357e --- /dev/null +++ b/openai_agents/financial_research_agent/agents/search_agent.py @@ -0,0 +1,20 @@ +from agents import Agent, WebSearchTool +from agents.model_settings import ModelSettings + +# Given a search term, use web search to pull back a brief summary. +# Summaries should be concise but capture the main financial points. +INSTRUCTIONS = ( + "You are a research assistant specializing in financial topics. " + "Given a search term, use web search to retrieve up-to-date context and " + "produce a short summary of at most 300 words. Focus on key numbers, events, " + "or quotes that will be useful to a financial analyst." +) + + +def new_search_agent() -> Agent: + return Agent( + name="FinancialSearchAgent", + instructions=INSTRUCTIONS, + tools=[WebSearchTool()], + model_settings=ModelSettings(tool_choice="required"), + ) diff --git a/openai_agents/financial_research_agent/agents/verifier_agent.py b/openai_agents/financial_research_agent/agents/verifier_agent.py new file mode 100644 index 00000000..9d3f0a01 --- /dev/null +++ b/openai_agents/financial_research_agent/agents/verifier_agent.py @@ -0,0 +1,27 @@ +from agents import Agent +from pydantic import BaseModel + +# Agent to sanity-check a synthesized report for consistency and recall. +# This can be used to flag potential gaps or obvious mistakes. +VERIFIER_PROMPT = ( + "You are a meticulous auditor. You have been handed a financial analysis report. " + "Your job is to verify the report is internally consistent, clearly sourced, and makes " + "no unsupported claims. Point out any issues or uncertainties." +) + + +class VerificationResult(BaseModel): + verified: bool + """Whether the report seems coherent and plausible.""" + + issues: str + """If not verified, describe the main issues or concerns.""" + + +def new_verifier_agent() -> Agent: + return Agent( + name="VerificationAgent", + instructions=VERIFIER_PROMPT, + model="gpt-4o", + output_type=VerificationResult, + ) diff --git a/openai_agents/financial_research_agent/agents/writer_agent.py b/openai_agents/financial_research_agent/agents/writer_agent.py new file mode 100644 index 00000000..9accc202 --- /dev/null +++ b/openai_agents/financial_research_agent/agents/writer_agent.py @@ -0,0 +1,34 @@ +from agents import Agent +from pydantic import BaseModel + +# Writer agent brings together the raw search results and optionally calls out +# to sub-analyst tools for specialized commentary, then returns a cohesive markdown report. +WRITER_PROMPT = ( + "You are a senior financial analyst. You will be provided with the original query and " + "a set of raw search summaries. Your task is to synthesize these into a long-form markdown " + "report (at least several paragraphs) including a short executive summary and follow-up " + "questions. If needed, you can call the available analysis tools (e.g. fundamentals_analysis, " + "risk_analysis) to get short specialist write-ups to incorporate." +) + + +class FinancialReportData(BaseModel): + short_summary: str + """A short 2-3 sentence executive summary.""" + + markdown_report: str + """The full markdown report.""" + + follow_up_questions: list[str] + """Suggested follow-up questions for further research.""" + + +# Note: We will attach tools to specialist analyst agents at runtime in the manager. +# This shows how an agent can use tools to delegate to specialized subagents. +def new_writer_agent() -> Agent: + return Agent( + name="FinancialWriterAgent", + instructions=WRITER_PROMPT, + model="gpt-4.1-2025-04-14", + output_type=FinancialReportData, + ) diff --git a/openai_agents/financial_research_agent/financial_research_manager.py b/openai_agents/financial_research_agent/financial_research_manager.py new file mode 100644 index 00000000..9a437a45 --- /dev/null +++ b/openai_agents/financial_research_agent/financial_research_manager.py @@ -0,0 +1,142 @@ +from __future__ import annotations + +import asyncio +from collections.abc import Sequence + +from agents import RunConfig, Runner, RunResult, custom_span, trace +from temporalio import workflow + +from openai_agents.financial_research_agent.agents.financials_agent import ( + new_financials_agent, +) +from openai_agents.financial_research_agent.agents.planner_agent import ( + FinancialSearchItem, + FinancialSearchPlan, + new_planner_agent, +) +from openai_agents.financial_research_agent.agents.risk_agent import new_risk_agent +from openai_agents.financial_research_agent.agents.search_agent import new_search_agent +from openai_agents.financial_research_agent.agents.verifier_agent import ( + VerificationResult, + new_verifier_agent, +) +from openai_agents.financial_research_agent.agents.writer_agent import ( + FinancialReportData, + new_writer_agent, +) + + +async def _summary_extractor(run_result: RunResult) -> str: + """Custom output extractor for sub-agents that return an AnalysisSummary.""" + # The financial/risk analyst agents emit an AnalysisSummary with a `summary` field. + # We want the tool call to return just that summary text so the writer can drop it inline. + return str(run_result.final_output.summary) + + +class FinancialResearchManager: + """ + Orchestrates the full flow: planning, searching, sub-analysis, writing, and verification. + """ + + def __init__(self) -> None: + self.run_config = RunConfig() + self.planner_agent = new_planner_agent() + self.search_agent = new_search_agent() + self.financials_agent = new_financials_agent() + self.risk_agent = new_risk_agent() + self.writer_agent = new_writer_agent() + self.verifier_agent = new_verifier_agent() + + async def run(self, query: str) -> str: + with trace("Financial research trace"): + search_plan = await self._plan_searches(query) + search_results = await self._perform_searches(search_plan) + report = await self._write_report(query, search_results) + verification = await self._verify_report(report) + + # Return formatted output + result = f"""=====REPORT===== + +{report.markdown_report} + +=====FOLLOW UP QUESTIONS===== + +{chr(10).join(report.follow_up_questions)} + +=====VERIFICATION===== + +Verified: {verification.verified} +Issues: {verification.issues}""" + + return result + + async def _plan_searches(self, query: str) -> FinancialSearchPlan: + result = await Runner.run( + self.planner_agent, + f"Query: {query}", + run_config=self.run_config, + ) + return result.final_output_as(FinancialSearchPlan) + + async def _perform_searches( + self, search_plan: FinancialSearchPlan + ) -> Sequence[str]: + with custom_span("Search the web"): + tasks = [ + asyncio.create_task(self._search(item)) for item in search_plan.searches + ] + results: list[str] = [] + for task in workflow.as_completed(tasks): + result = await task + if result is not None: + results.append(result) + return results + + async def _search(self, item: FinancialSearchItem) -> str | None: + input_data = f"Search term: {item.query}\nReason: {item.reason}" + try: + result = await Runner.run( + self.search_agent, + input_data, + run_config=self.run_config, + ) + return str(result.final_output) + except Exception: + return None + + async def _write_report( + self, query: str, search_results: Sequence[str] + ) -> FinancialReportData: + # Expose the specialist analysts as tools so the writer can invoke them inline + # and still produce the final FinancialReportData output. + fundamentals_tool = self.financials_agent.as_tool( + tool_name="fundamentals_analysis", + tool_description="Use to get a short write-up of key financial metrics", + custom_output_extractor=_summary_extractor, + ) + risk_tool = self.risk_agent.as_tool( + tool_name="risk_analysis", + tool_description="Use to get a short write-up of potential red flags", + custom_output_extractor=_summary_extractor, + ) + writer_with_tools = self.writer_agent.clone( + tools=[fundamentals_tool, risk_tool] + ) + + input_data = ( + f"Original query: {query}\nSummarized search results: {search_results}" + ) + result = await Runner.run( + writer_with_tools, + input_data, + run_config=self.run_config, + ) + return result.final_output_as(FinancialReportData) + + async def _verify_report(self, report: FinancialReportData) -> VerificationResult: + result = await Runner.run( + self.verifier_agent, + report.markdown_report, + run_config=self.run_config, + ) + return result.final_output_as(VerificationResult) diff --git a/openai_agents/financial_research_agent/run_financial_research_workflow.py b/openai_agents/financial_research_agent/run_financial_research_workflow.py new file mode 100644 index 00000000..80adc86b --- /dev/null +++ b/openai_agents/financial_research_agent/run_financial_research_workflow.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.financial_research_agent.workflows.financial_research_workflow import ( + FinancialResearchWorkflow, +) + + +async def main(): + # Get the query from user input + query = input("Enter a financial research query: ") + if not query.strip(): + query = "Write up an analysis of Apple Inc.'s most recent quarter." + print(f"Using default query: {query}") + + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + print(f"Starting financial research for: {query}") + print("This may take several minutes to complete...\n") + + result = await client.execute_workflow( + FinancialResearchWorkflow.run, + query, + id=f"financial-research-{hash(query)}", + task_queue="financial-research-task-queue", + ) + + print(result) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/financial_research_agent/run_worker.py b/openai_agents/financial_research_agent/run_worker.py new file mode 100644 index 00000000..507bd77c --- /dev/null +++ b/openai_agents/financial_research_agent/run_worker.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.financial_research_agent.workflows.financial_research_workflow import ( + FinancialResearchWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + worker = Worker( + client, + task_queue="financial-research-task-queue", + workflows=[FinancialResearchWorkflow], + ) + + print("Starting financial research worker...") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/financial_research_agent/workflows/financial_research_workflow.py b/openai_agents/financial_research_agent/workflows/financial_research_workflow.py new file mode 100644 index 00000000..487e3fd5 --- /dev/null +++ b/openai_agents/financial_research_agent/workflows/financial_research_workflow.py @@ -0,0 +1,13 @@ +from temporalio import workflow + +from openai_agents.financial_research_agent.financial_research_manager import ( + FinancialResearchManager, +) + + +@workflow.defn +class FinancialResearchWorkflow: + @workflow.run + async def run(self, query: str) -> str: + manager = FinancialResearchManager() + return await manager.run(query) diff --git a/openai_agents/reasoning_content/README.md b/openai_agents/reasoning_content/README.md new file mode 100644 index 00000000..c654d266 --- /dev/null +++ b/openai_agents/reasoning_content/README.md @@ -0,0 +1,37 @@ +# Reasoning Content + +Example demonstrating how to use the reasoning content feature with models that support it, running in the context of Temporal's durable execution. + +*Adapted from [OpenAI Agents SDK reasoning content](https://github.com/openai/openai-agents-python/tree/main/examples/reasoning_content)* + +## Overview + +Some models, like deepseek-reasoner, provide a reasoning_content field in addition to the regular content. This example shows how to access and use this reasoning content within Temporal workflows. The reasoning content contains the model's step-by-step thinking process before providing the final answer. + +## Architecture + +This example uses an activity to handle the OpenAI model calls. The workflow orchestrates the process by calling the `get_reasoning_response` activity, which uses the OpenAI provider to get a response from a reasoning-capable model and extracts both reasoning content and regular content. + +The model calls are run in an activity rather than directly in the workflow because Temporal's the involve I/O. + +## Running the Example + +First, start the worker: +```bash +uv run openai_agents/reasoning_content/run_worker.py +``` + +Then run the reasoning content workflow: +```bash +uv run openai_agents/reasoning_content/run_reasoning_content_workflow.py +``` + +## Requirements + +- Set your `OPENAI_API_KEY` environment variable +- Use a model that supports reasoning content (e.g., `deepseek-reasoner`) +- Optionally set `EXAMPLE_MODEL_NAME` environment variable to specify the model + +## Note on Streaming + +The original OpenAI Agents SDK example includes streaming capabilities, but since Temporal workflows do not support streaming yet, this example contains only the non-streaming approach. \ No newline at end of file diff --git a/openai_agents/reasoning_content/activities/reasoning_activities.py b/openai_agents/reasoning_content/activities/reasoning_activities.py new file mode 100644 index 00000000..b111a742 --- /dev/null +++ b/openai_agents/reasoning_content/activities/reasoning_activities.py @@ -0,0 +1,52 @@ +import os +from typing import Any, cast + +from agents import ModelSettings +from agents.models.interface import ModelTracing +from agents.models.openai_provider import OpenAIProvider +from openai.types.responses import ResponseOutputRefusal, ResponseOutputText +from temporalio import activity + + +@activity.defn +async def get_reasoning_response( + prompt: str, model_name: str | None = None +) -> tuple[str | None, str | None]: + """ + Activity to get response from a reasoning-capable model. + Returns tuple of (reasoning_content, regular_content). + """ + model_name = model_name or os.getenv("EXAMPLE_MODEL_NAME") or "deepseek-reasoner" + + provider = OpenAIProvider() + model = provider.get_model(model_name) + + response = await model.get_response( + system_instructions="You are a helpful assistant that explains your reasoning step by step.", + input=prompt, + model_settings=ModelSettings(), + tools=[], + output_schema=None, + handoffs=[], + tracing=ModelTracing.DISABLED, + previous_response_id=None, + prompt=None, + ) + + # Extract reasoning content and regular content from the response + reasoning_content = None + regular_content = None + + for item in response.output: + if hasattr(item, "type") and item.type == "reasoning": + reasoning_content = item.summary[0].text + elif hasattr(item, "type") and item.type == "message": + if item.content and len(item.content) > 0: + content_item = item.content[0] + if isinstance(content_item, ResponseOutputText): + regular_content = content_item.text + elif isinstance(content_item, ResponseOutputRefusal): + refusal_item = cast(Any, content_item) + regular_content = refusal_item.refusal + + return reasoning_content, regular_content diff --git a/openai_agents/reasoning_content/run_reasoning_content_workflow.py b/openai_agents/reasoning_content/run_reasoning_content_workflow.py new file mode 100644 index 00000000..79e5d7ba --- /dev/null +++ b/openai_agents/reasoning_content/run_reasoning_content_workflow.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python3 + +import asyncio +import os + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.reasoning_content.workflows.reasoning_content_workflow import ( + ReasoningContentWorkflow, + ReasoningResult, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Demo prompts that benefit from reasoning + demo_prompts = [ + "What is the square root of 841? Please explain your reasoning.", + "Explain the concept of recursion in programming", + "Write a haiku about recursion in programming", + ] + + model_name = os.getenv("EXAMPLE_MODEL_NAME") or "deepseek-reasoner" + print(f"Using model: {model_name}") + print("Note: This example requires a model that supports reasoning content.") + print("You may need to use a specific model like deepseek-reasoner or similar.\n") + + for i, prompt in enumerate(demo_prompts, 1): + print(f"=== Example {i}: {prompt} ===") + + result: ReasoningResult = await client.execute_workflow( + ReasoningContentWorkflow.run, + args=[prompt, model_name], + id=f"reasoning-content-{i}", + task_queue="reasoning-content-task-queue", + ) + + print(f"\nPrompt: {result.prompt}") + print("\nReasoning Content:") + print(result.reasoning_content or "No reasoning content provided") + print("\nRegular Content:") + print(result.regular_content or "No regular content provided") + print("-" * 50 + "\n") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/reasoning_content/run_worker.py b/openai_agents/reasoning_content/run_worker.py new file mode 100644 index 00000000..51393b2e --- /dev/null +++ b/openai_agents/reasoning_content/run_worker.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.reasoning_content.activities.reasoning_activities import ( + get_reasoning_response, +) +from openai_agents.reasoning_content.workflows.reasoning_content_workflow import ( + ReasoningContentWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + worker = Worker( + client, + task_queue="reasoning-content-task-queue", + workflows=[ReasoningContentWorkflow], + activities=[get_reasoning_response], + ) + + print("Starting reasoning content worker...") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/reasoning_content/workflows/reasoning_content_workflow.py b/openai_agents/reasoning_content/workflows/reasoning_content_workflow.py new file mode 100644 index 00000000..0a9f0a15 --- /dev/null +++ b/openai_agents/reasoning_content/workflows/reasoning_content_workflow.py @@ -0,0 +1,32 @@ +from dataclasses import dataclass + +from temporalio import workflow + +from openai_agents.reasoning_content.activities.reasoning_activities import ( + get_reasoning_response, +) + + +@dataclass +class ReasoningResult: + reasoning_content: str | None + regular_content: str | None + prompt: str + + +@workflow.defn +class ReasoningContentWorkflow: + @workflow.run + async def run(self, prompt: str, model_name: str | None = None) -> ReasoningResult: + # Call the activity to get the reasoning response + reasoning_content, regular_content = await workflow.execute_activity( + get_reasoning_response, + args=[prompt, model_name], + start_to_close_timeout=workflow.timedelta(minutes=5), + ) + + return ReasoningResult( + reasoning_content=reasoning_content, + regular_content=regular_content, + prompt=prompt, + ) From 8043fb0e6979adee3eb0e466a2b2dea866499bf6 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 17:30:06 -0600 Subject: [PATCH 08/40] OpenAI Agents Third-Party model providers (#227) * update for plugins * formatting * reference main branch * cleanup * switch to plugins on the runners * move around samples * update README files * formatting update * formatting * timeout adjustments * litellm model provider * Format --------- Co-authored-by: Tim Conley --- openai_agents/model_providers/README.md | 38 ++++++++++++++++++ .../run_litellm_auto_workflow.py | 29 ++++++++++++++ .../run_worker_litellm_provider.py | 39 +++++++++++++++++++ .../workflows/litellm_auto_workflow.py | 25 ++++++++++++ 4 files changed, 131 insertions(+) create mode 100644 openai_agents/model_providers/README.md create mode 100644 openai_agents/model_providers/run_litellm_auto_workflow.py create mode 100644 openai_agents/model_providers/run_worker_litellm_provider.py create mode 100644 openai_agents/model_providers/workflows/litellm_auto_workflow.py diff --git a/openai_agents/model_providers/README.md b/openai_agents/model_providers/README.md new file mode 100644 index 00000000..097dc525 --- /dev/null +++ b/openai_agents/model_providers/README.md @@ -0,0 +1,38 @@ +# Model Providers Examples + +Custom LLM provider integration examples for OpenAI Agents SDK with Temporal workflows. + +*Adapted from [OpenAI Agents SDK model providers examples](https://github.com/openai/openai-agents-python/tree/main/examples/model_providers)* + +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + +## Running the Examples + +### Currently Implemented + +#### LiteLLM Auto +Uses built-in LiteLLM support to connect to various model providers. + +Start the LiteLLM provider worker: +```bash +# Set the required environment variable for your chosen provider +export ANTHROPIC_API_KEY="your_anthropic_api_key" # For Anthropic + +uv run openai_agents/model_providers/run_worker_litellm_provider.py +``` + +Then run the example in a separate terminal: +```bash +uv run openai_agents/model_providers/run_litellm_auto_workflow.py +``` + +The example uses Anthropic Claude by default but can be modified to use other LiteLLM-supported providers. + +Find more LiteLLM providers at: https://docs.litellm.ai/docs/providers + +## Not Yet Implemented + +- **Custom Example Agent** - Custom OpenAI client integration +- **Custom Example Global** - Global default client configuration +- **Custom Example Provider** - Custom ModelProvider pattern +- **LiteLLM Provider** - Interactive model/API key input \ No newline at end of file diff --git a/openai_agents/model_providers/run_litellm_auto_workflow.py b/openai_agents/model_providers/run_litellm_auto_workflow.py new file mode 100644 index 00000000..0e4e05f1 --- /dev/null +++ b/openai_agents/model_providers/run_litellm_auto_workflow.py @@ -0,0 +1,29 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.model_providers.workflows.litellm_auto_workflow import ( + LitellmAutoWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + result = await client.execute_workflow( + LitellmAutoWorkflow.run, + "What's the weather in Tokyo?", + id="litellm-auto-workflow-id", + task_queue="openai-agents-model-providers-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/model_providers/run_worker_litellm_provider.py b/openai_agents/model_providers/run_worker_litellm_provider.py new file mode 100644 index 00000000..5eb8b8b2 --- /dev/null +++ b/openai_agents/model_providers/run_worker_litellm_provider.py @@ -0,0 +1,39 @@ +import asyncio +from datetime import timedelta + +from agents.extensions.models.litellm_provider import LitellmProvider +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.model_providers.workflows.litellm_auto_workflow import ( + LitellmAutoWorkflow, +) + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=30) + ), + model_provider=LitellmProvider(), + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-model-providers-task-queue", + workflows=[ + LitellmAutoWorkflow, + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/model_providers/workflows/litellm_auto_workflow.py b/openai_agents/model_providers/workflows/litellm_auto_workflow.py new file mode 100644 index 00000000..4a67ded4 --- /dev/null +++ b/openai_agents/model_providers/workflows/litellm_auto_workflow.py @@ -0,0 +1,25 @@ +from __future__ import annotations + +from agents import Agent, Runner, function_tool, set_tracing_disabled +from temporalio import workflow + + +@workflow.defn +class LitellmAutoWorkflow: + @workflow.run + async def run(self, prompt: str) -> str: + set_tracing_disabled(disabled=True) + + @function_tool + def get_weather(city: str): + return f"The weather in {city} is sunny." + + agent = Agent( + name="Assistant", + instructions="You only respond in haikus.", + model="anthropic/claude-3-5-sonnet-20240620", + tools=[get_weather], + ) + + result = await Runner.run(agent, prompt) + return result.final_output From dfeb7eedeb40e7aa79ff1475bd56a0a853351d67 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 17:41:40 -0600 Subject: [PATCH 09/40] Customer service workflow fixes, including continue-as-new (#222) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Port continue-as-new fix for customer service workflow - Add case-insensitive string matching in FAQ lookup tool - Update init_agents to return tuple with agent map for continue-as-new state management - Implement continue-as-new functionality with proper state serialization - Fix client output to skip duplicate user message on print πŸ€– Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude * cleanup --------- Co-authored-by: Claude Co-authored-by: tconley1428 --- .../customer_service/customer_service.py | 17 ++-- .../run_customer_service_client.py | 2 +- .../workflows/customer_service_workflow.py | 77 ++++++++++++++----- 3 files changed, 71 insertions(+), 25 deletions(-) diff --git a/openai_agents/customer_service/customer_service.py b/openai_agents/customer_service/customer_service.py index 6a08f4ed..88f6e3cd 100644 --- a/openai_agents/customer_service/customer_service.py +++ b/openai_agents/customer_service/customer_service.py @@ -1,5 +1,7 @@ from __future__ import annotations as _annotations +from typing import Dict, Tuple + from agents import Agent, RunContextWrapper, function_tool, handoff from agents.extensions.handoff_prompt import RECOMMENDED_PROMPT_PREFIX from pydantic import BaseModel @@ -23,19 +25,20 @@ class AirlineAgentContext(BaseModel): description_override="Lookup frequently asked questions.", ) async def faq_lookup_tool(question: str) -> str: - if "bag" in question or "baggage" in question: + question_lower = question.lower() + if "bag" in question_lower or "baggage" in question_lower: return ( "You are allowed to bring one bag on the plane. " "It must be under 50 pounds and 22 inches x 14 inches x 9 inches." ) - elif "seats" in question or "plane" in question: + elif "seats" in question_lower or "plane" in question_lower: return ( "There are 120 seats on the plane. " "There are 22 business class seats and 98 economy seats. " "Exit rows are rows 4 and 16. " "Rows 5-8 are Economy Plus, with extra legroom. " ) - elif "wifi" in question: + elif "wifi" in question_lower: return "We have free wifi on the plane, join Airline-Wifi" return "I'm sorry, I don't know the answer to that question." @@ -74,7 +77,9 @@ async def on_seat_booking_handoff( ### AGENTS -def init_agents() -> Agent[AirlineAgentContext]: +def init_agents() -> Tuple[ + Agent[AirlineAgentContext], Dict[str, Agent[AirlineAgentContext]] +]: """ Initialize the agents for the airline customer service workflow. :return: triage agent @@ -121,7 +126,9 @@ def init_agents() -> Agent[AirlineAgentContext]: faq_agent.handoffs.append(triage_agent) seat_booking_agent.handoffs.append(triage_agent) - return triage_agent + return triage_agent, { + agent.name: agent for agent in [faq_agent, seat_booking_agent, triage_agent] + } class ProcessUserMessageInput(BaseModel): diff --git a/openai_agents/customer_service/run_customer_service_client.py b/openai_agents/customer_service/run_customer_service_client.py index e66419e4..044e0775 100644 --- a/openai_agents/customer_service/run_customer_service_client.py +++ b/openai_agents/customer_service/run_customer_service_client.py @@ -67,7 +67,7 @@ async def main(): CustomerServiceWorkflow.process_user_message, message_input ) history.extend(new_history) - print(*new_history, sep="\n") + print(*new_history[1:], sep="\n") except WorkflowUpdateFailedError: print("** Stale conversation. Reloading...") length = len(history) diff --git a/openai_agents/customer_service/workflows/customer_service_workflow.py b/openai_agents/customer_service/workflows/customer_service_workflow.py index c816d868..0157d050 100644 --- a/openai_agents/customer_service/workflows/customer_service_workflow.py +++ b/openai_agents/customer_service/workflows/customer_service_workflow.py @@ -1,7 +1,7 @@ from __future__ import annotations as _annotations from agents import ( - Agent, + HandoffCallItem, HandoffOutputItem, ItemHelpers, MessageOutputItem, @@ -12,6 +12,7 @@ TResponseInputItem, trace, ) +from pydantic import dataclasses from temporalio import workflow from openai_agents.customer_service.customer_service import ( @@ -21,32 +22,65 @@ ) +@dataclasses.dataclass +class CustomerServiceWorkflowState: + printed_history: list[str] + current_agent_name: str + context: AirlineAgentContext + input_items: list[TResponseInputItem] + + @workflow.defn class CustomerServiceWorkflow: @workflow.init - def __init__(self, input_items: list[TResponseInputItem] | None = None): + def __init__( + self, customer_service_state: CustomerServiceWorkflowState | None = None + ): self.run_config = RunConfig() - self.chat_history: list[str] = [] - self.current_agent: Agent[AirlineAgentContext] = init_agents() - self.context = AirlineAgentContext() - self.input_items = [] if input_items is None else input_items + + starting_agent, self.agent_map = init_agents() + self.current_agent = ( + self.agent_map[customer_service_state.current_agent_name] + if customer_service_state + else starting_agent + ) + self.context = ( + customer_service_state.context + if customer_service_state + else AirlineAgentContext() + ) + self.printed_history: list[str] = ( + customer_service_state.printed_history if customer_service_state else [] + ) + self.input_items = ( + customer_service_state.input_items if customer_service_state else [] + ) @workflow.run - async def run(self, input_items: list[TResponseInputItem] | None = None): + async def run( + self, customer_service_state: CustomerServiceWorkflowState | None = None + ): await workflow.wait_condition( lambda: workflow.info().is_continue_as_new_suggested() and workflow.all_handlers_finished() ) - workflow.continue_as_new(self.input_items) + workflow.continue_as_new( + CustomerServiceWorkflowState( + printed_history=self.printed_history, + current_agent_name=self.current_agent.name, + context=self.context, + input_items=self.input_items, + ) + ) @workflow.query def get_chat_history(self) -> list[str]: - return self.chat_history + return self.printed_history @workflow.update async def process_user_message(self, input: ProcessUserMessageInput) -> list[str]: - length = len(self.chat_history) - self.chat_history.append(f"User: {input.user_input}") + length = len(self.printed_history) + self.printed_history.append(f"User: {input.user_input}") with trace("Customer service", group_id=workflow.info().workflow_id): self.input_items.append({"content": input.user_input, "role": "user"}) result = await Runner.run( @@ -59,27 +93,32 @@ async def process_user_message(self, input: ProcessUserMessageInput) -> list[str for new_item in result.new_items: agent_name = new_item.agent.name if isinstance(new_item, MessageOutputItem): - self.chat_history.append( + self.printed_history.append( f"{agent_name}: {ItemHelpers.text_message_output(new_item)}" ) elif isinstance(new_item, HandoffOutputItem): - self.chat_history.append( + self.printed_history.append( f"Handed off from {new_item.source_agent.name} to {new_item.target_agent.name}" ) + elif isinstance(new_item, HandoffCallItem): + self.printed_history.append( + f"{agent_name}: Handed off to tool {new_item.raw_item.name}" + ) elif isinstance(new_item, ToolCallItem): - self.chat_history.append(f"{agent_name}: Calling a tool") + self.printed_history.append(f"{agent_name}: Calling a tool") elif isinstance(new_item, ToolCallOutputItem): - self.chat_history.append( + self.printed_history.append( f"{agent_name}: Tool call output: {new_item.output}" ) else: - self.chat_history.append( + self.printed_history.append( f"{agent_name}: Skipping item: {new_item.__class__.__name__}" ) self.input_items = result.to_input_list() self.current_agent = result.last_agent - workflow.set_current_details("\n\n".join(self.chat_history)) - return self.chat_history[length:] + workflow.set_current_details("\n\n".join(self.printed_history)) + + return self.printed_history[length:] @process_user_message.validator def validate_process_user_message(self, input: ProcessUserMessageInput) -> None: @@ -87,5 +126,5 @@ def validate_process_user_message(self, input: ProcessUserMessageInput) -> None: raise ValueError("User input cannot be empty.") if len(input.user_input) > 1000: raise ValueError("User input is too long. Please limit to 1000 characters.") - if input.chat_length != len(self.chat_history): + if input.chat_length != len(self.printed_history): raise ValueError("Stale chat history. Please refresh the chat.") From 50c88caa2992d97683360ad55ca969a9139d10ca Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 29 Jul 2025 18:30:39 -0600 Subject: [PATCH 10/40] update table of contents for samples (#229) --- openai_agents/README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/openai_agents/README.md b/openai_agents/README.md index 96975ec2..8a51246d 100644 --- a/openai_agents/README.md +++ b/openai_agents/README.md @@ -1,6 +1,6 @@ # Temporal OpenAI Agents SDK Integration -⚠️ **Experimental** - This module is not yet stable and may change in the future. +⚠️ **Public Preview** - This integration is experimental and its interfaces may change prior to General Availability. This directory contains samples demonstrating how to use the [OpenAI Agents SDK](https://github.com/openai/openai-agents-python) with Temporal's durable execution engine. These samples are adapted from the [OpenAI Agents SDK examples](https://github.com/openai/openai-agents-python/tree/main/examples) and extended with Temporal's durability and orchestration capabilities. @@ -27,7 +27,12 @@ Each directory contains a complete example with its own README for detailed inst - **[Basic Examples](./basic/README.md)** - Simple agent examples including a hello world agent and a tools-enabled agent that can access external APIs like weather services. - **[Agent Patterns](./agent_patterns/README.md)** - Advanced patterns for agent composition, including using agents as tools within other agents. +- **[Tools](./tools/README.md)** - Demonstrates available tools such as file search, image generation, and others. +- **[Handoffs](./handoffs/README.md)** - Agents collaborating via handoffs. +- **[Hosted MCP](./hosted_mcp/README.md)** - Using the MCP client functionality of the OpenAI Responses API. +- **[Model Providers](./model_providers/README.md)** - Using custom LLM providers (e.g., Anthropic via LiteLLM). - **[Research Bot](./research_bot/README.md)** - Multi-agent research system with specialized roles: a planner agent, search agent, and writer agent working together to conduct comprehensive research. - **[Customer Service](./customer_service/README.md)** - Interactive customer service agent with escalation capabilities, demonstrating conversational workflows. - +- **[Reasoning Content](./reasoning_content/README.md)** - Example of how to retrieve the thought process of reasoning models. +- **[Financial Research Agent](./financial_research_agent/README.md)** - Multi-agent financial research system with planner, search, analyst, writer, and verifier agents collaborating. From 6d05457c784ec00277790b996d01b0a7a172995b Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Wed, 30 Jul 2025 00:02:22 -0400 Subject: [PATCH 11/40] Delete default groups (#217) * Delete default groups * Install all groups in tests Fixes #190 --- pyproject.toml | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 077dc912..b8b27840 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,20 +71,6 @@ cloud-export-to-parquet = [ "pyarrow>=19.0.1", ] -[tool.uv] -default-groups = [ - "dev", - "bedrock", - "dsl", - "encryption", - "gevent", - "langchain", - "nexus", - "open-telemetry", - "pydantic-converter", - "sentry", - "trio-async", -] [tool.hatch.build.targets.sdist] include = ["./**/*.py"] @@ -134,8 +120,8 @@ build-backend = "hatchling.build" [tool.poe.tasks] format = [{cmd = "uv run black ."}, {cmd = "uv run isort ."}] lint = [{cmd = "uv run black --check ."}, {cmd = "uv run isort --check-only ."}, {ref = "lint-types" }] -lint-types = "uv run mypy --check-untyped-defs --namespace-packages ." -test = "uv run pytest" +lint-types = "uv run --all-groups mypy --check-untyped-defs --namespace-packages ." +test = "uv run --all-groups pytest" [tool.pytest.ini_options] asyncio_mode = "auto" From 7ea40bfa6d2d3d3f58b7a5b7185231d2c399b657 Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Thu, 7 Aug 2025 09:12:55 -0700 Subject: [PATCH 12/40] add example for gpt-oss (#232) --- openai_agents/model_providers/README.md | 33 ++++++++++- .../model_providers/run_gpt_oss_worker.py | 58 +++++++++++++++++++ .../model_providers/run_gpt_oss_workflow.py | 27 +++++++++ ...ider.py => run_litellm_provider_worker.py} | 0 .../workflows/gpt_oss_workflow.py | 26 +++++++++ 5 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 openai_agents/model_providers/run_gpt_oss_worker.py create mode 100644 openai_agents/model_providers/run_gpt_oss_workflow.py rename openai_agents/model_providers/{run_worker_litellm_provider.py => run_litellm_provider_worker.py} (100%) create mode 100644 openai_agents/model_providers/workflows/gpt_oss_workflow.py diff --git a/openai_agents/model_providers/README.md b/openai_agents/model_providers/README.md index 097dc525..df8f286e 100644 --- a/openai_agents/model_providers/README.md +++ b/openai_agents/model_providers/README.md @@ -18,7 +18,7 @@ Start the LiteLLM provider worker: # Set the required environment variable for your chosen provider export ANTHROPIC_API_KEY="your_anthropic_api_key" # For Anthropic -uv run openai_agents/model_providers/run_worker_litellm_provider.py +uv run openai_agents/model_providers/run_litellm_provider_worker.py ``` Then run the example in a separate terminal: @@ -30,7 +30,36 @@ The example uses Anthropic Claude by default but can be modified to use other Li Find more LiteLLM providers at: https://docs.litellm.ai/docs/providers -## Not Yet Implemented +### Extra + +#### GPT-OSS with Ollama + +This example demonstrates tool calling using the gpt-oss reasoning model with a local Ollama server. +Running this example requires sufficiently powerful hardware (and involves a 14 GB model download. +It is adapted from the [OpenAI Cookbook example](https://cookbook.openai.com/articles/gpt-oss/run-locally-ollama#agents-sdk-integration). + + +Make sure you have [Ollama](https://ollama.com/) installed: +```bash +ollama serve +``` + +Download the `gpt-oss` model: +```bash +ollama pull gpt-oss:20b +``` + +Start the gpt-oss worker: +```bash +uv run openai_agents/model_providers/run_gpt_oss_worker.py +``` + +Then run the example in a separate terminal: +```bash +uv run openai_agents/model_providers/run_gpt_oss_workflow.py +``` + +### Not Yet Implemented - **Custom Example Agent** - Custom OpenAI client integration - **Custom Example Global** - Global default client configuration diff --git a/openai_agents/model_providers/run_gpt_oss_worker.py b/openai_agents/model_providers/run_gpt_oss_worker.py new file mode 100644 index 00000000..88c85fca --- /dev/null +++ b/openai_agents/model_providers/run_gpt_oss_worker.py @@ -0,0 +1,58 @@ +import asyncio +import logging +from datetime import timedelta +from typing import Optional + +from agents import Model, ModelProvider, OpenAIChatCompletionsModel +from openai import AsyncOpenAI +from temporalio.client import Client +from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin +from temporalio.worker import Worker + +from openai_agents.model_providers.workflows.gpt_oss_workflow import GptOssWorkflow + +ollama_client = AsyncOpenAI( + base_url="http://localhost:11434/v1", # Local Ollama API endpoint + api_key="ollama", # Ignored by Ollama +) + + +class CustomModelProvider(ModelProvider): + def get_model(self, model_name: Optional[str]) -> Model: + model = OpenAIChatCompletionsModel( + model=model_name if model_name else "gpt-oss:20b", + openai_client=ollama_client, + ) + return model + + +async def main(): + # Configure logging to show workflow debug messages + logging.basicConfig(level=logging.WARNING) + logging.getLogger("temporalio.workflow").setLevel(logging.DEBUG) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=30) + ), + model_provider=CustomModelProvider(), + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-model-providers-task-queue", + workflows=[ + GptOssWorkflow, + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/model_providers/run_gpt_oss_workflow.py b/openai_agents/model_providers/run_gpt_oss_workflow.py new file mode 100644 index 00000000..35df5979 --- /dev/null +++ b/openai_agents/model_providers/run_gpt_oss_workflow.py @@ -0,0 +1,27 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.model_providers.workflows.gpt_oss_workflow import GptOssWorkflow + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + result = await client.execute_workflow( + GptOssWorkflow.run, + "What's the weather in Tokyo?", + id="litellm-gpt-oss-workflow-id", + task_queue="openai-agents-model-providers-task-queue", + ) + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/model_providers/run_worker_litellm_provider.py b/openai_agents/model_providers/run_litellm_provider_worker.py similarity index 100% rename from openai_agents/model_providers/run_worker_litellm_provider.py rename to openai_agents/model_providers/run_litellm_provider_worker.py diff --git a/openai_agents/model_providers/workflows/gpt_oss_workflow.py b/openai_agents/model_providers/workflows/gpt_oss_workflow.py new file mode 100644 index 00000000..d7ed8021 --- /dev/null +++ b/openai_agents/model_providers/workflows/gpt_oss_workflow.py @@ -0,0 +1,26 @@ +from __future__ import annotations + +from agents import Agent, Runner, function_tool, set_tracing_disabled +from temporalio import workflow + + +@workflow.defn +class GptOssWorkflow: + @workflow.run + async def run(self, prompt: str) -> str: + set_tracing_disabled(disabled=True) + + @function_tool + def get_weather(city: str): + workflow.logger.debug(f"Getting weather for {city}") + return f"The weather in {city} is sunny." + + agent = Agent( + name="Assistant", + instructions="You only respond in haikus. When asked about the weather always use the tool to get the current weather..", + model="gpt-oss:20b", + tools=[get_weather], + ) + + result = await Runner.run(agent, prompt) + return result.final_output From a98d4ea88a34bf02999a3f6d1d28ad935c0257bb Mon Sep 17 00:00:00 2001 From: Greg Brown Date: Tue, 12 Aug 2025 13:18:06 +0100 Subject: [PATCH 13/40] feat: add example using Sentry V2 SDK (#140) --- pyproject.toml | 5 +- sentry/README.md | 29 ++++- sentry/activity.py | 25 +++++ sentry/images/sentry.jpeg | Bin 0 -> 577699 bytes sentry/interceptor.py | 64 +++++------ sentry/starter.py | 20 ++-- sentry/worker.py | 96 ++++++++++------ sentry/workflow.py | 38 +++++++ tests/sentry/fake_sentry_transport.py | 17 +++ tests/sentry/test_interceptor.py | 156 ++++++++++++++++++++++++++ uv.lock | 8 +- 11 files changed, 372 insertions(+), 86 deletions(-) create mode 100644 sentry/activity.py create mode 100644 sentry/images/sentry.jpeg create mode 100644 sentry/workflow.py create mode 100644 tests/sentry/fake_sentry_transport.py create mode 100644 tests/sentry/test_interceptor.py diff --git a/pyproject.toml b/pyproject.toml index b8b27840..fa5a0300 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -59,7 +59,7 @@ openai-agents = [ "temporalio[openai-agents] >= 1.15.0", ] pydantic-converter = ["pydantic>=2.10.6,<3"] -sentry = ["sentry-sdk>=1.11.0,<2"] +sentry = ["sentry-sdk>=2.13.0"] trio-async = [ "trio>=0.28.0,<0.29", "trio-asyncio>=0.15.0,<0.16", @@ -143,5 +143,4 @@ ignore_errors = true [[tool.mypy.overrides]] module = "opentelemetry.*" -ignore_errors = true - +ignore_errors = true \ No newline at end of file diff --git a/sentry/README.md b/sentry/README.md index 33a7b535..1cc75cf6 100644 --- a/sentry/README.md +++ b/sentry/README.md @@ -1,19 +1,40 @@ # Sentry Sample -This sample shows how to configure [Sentry](https://sentry.io) to intercept and capture errors from the Temporal SDK. +This sample shows how to configure [Sentry](https://sentry.io) SDK (version 2) to intercept and capture errors from the Temporal SDK +for workflows and activities. The integration adds some useful context to the errors, such as the activity type, task queue, etc. + +## Further details + +This is a small modification of the original example Sentry integration in this repo based on SDK v1. The integration +didn't work properly with Sentry SDK v2 due to some internal changes in the Sentry SDK that broke the worker sandbox. +Additionally, the v1 SDK has been deprecated and is only receiving security patches and will reach EOL some time in the future. +If you still need to use Sentry SDK v1, check the original example at this [commit](https://github.com/temporalio/samples-python/blob/090b96d750bafc10d4aad5ad506bb2439c413d5e/sentry). + +## Running the Sample For this sample, the optional `sentry` dependency group must be included. To include, run: - uv sync --group sentry + uv sync --no-default-groups --dev --group sentry + +> Note: this integration breaks when `gevent` is installed (e.g. by the gevent sample) so make sure to only install +> the `sentry` group and run the scripts below as described. To run, first see [README.md](../README.md) for prerequisites. Set `SENTRY_DSN` environment variable to the Sentry DSN. Then, run the following from the root directory to start the worker: + export SENTRY_DSN= # You'll need a Sentry account to test against + export ENVIRONMENT=dev uv run sentry/worker.py This will start the worker. Then, in another terminal, run the following to execute the workflow: uv run sentry/starter.py -The workflow should complete with the hello result. If you alter the workflow or the activity to raise an -`ApplicationError` instead, it should appear in Sentry. \ No newline at end of file +You should see the activity fail causing an error to be reported to Sentry. + +## Screenshot + +The screenshot below shows the extra tags and context included in the +Sentry error from the exception thrown in the activity. + +![Sentry screenshot](images/sentry.jpeg) diff --git a/sentry/activity.py b/sentry/activity.py new file mode 100644 index 00000000..148cd0d2 --- /dev/null +++ b/sentry/activity.py @@ -0,0 +1,25 @@ +from dataclasses import dataclass + +from temporalio import activity + + +@dataclass +class WorkingActivityInput: + message: str + + +@activity.defn +async def working_activity(input: WorkingActivityInput) -> str: + activity.logger.info("Running activity with parameter %s" % input) + return "Success" + + +@dataclass +class BrokenActivityInput: + message: str + + +@activity.defn +async def broken_activity(input: BrokenActivityInput) -> str: + activity.logger.info("Running activity with parameter %s" % input) + raise Exception("Activity failed!") diff --git a/sentry/images/sentry.jpeg b/sentry/images/sentry.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..0f62825bb674f9cada6fe06457aa56d7ff42bc5c GIT binary patch literal 577699 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 z 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 Any: # https://docs.sentry.io/platforms/python/troubleshooting/#addressing-concurrency-issues - with Hub(Hub.current): - set_tag("temporal.execution_type", "activity") - set_tag("module", input.fn.__module__ + "." + input.fn.__qualname__) - + with sentry_sdk.isolation_scope() as scope: + scope.set_tag("temporal.execution_type", "activity") + scope.set_tag("module", input.fn.__module__ + "." + input.fn.__qualname__) activity_info = activity.info() - _set_common_workflow_tags(activity_info) - set_tag("temporal.activity.id", activity_info.activity_id) - set_tag("temporal.activity.type", activity_info.activity_type) - set_tag("temporal.activity.task_queue", activity_info.task_queue) - set_tag("temporal.workflow.namespace", activity_info.workflow_namespace) - set_tag("temporal.workflow.run_id", activity_info.workflow_run_id) + scope.set_tag("temporal.workflow.type", activity_info.workflow_type) + scope.set_tag("temporal.workflow.id", activity_info.workflow_id) + scope.set_tag("temporal.activity.id", activity_info.activity_id) + scope.set_tag("temporal.activity.type", activity_info.activity_type) + scope.set_tag("temporal.activity.task_queue", activity_info.task_queue) + scope.set_tag( + "temporal.workflow.namespace", activity_info.workflow_namespace + ) + scope.set_tag("temporal.workflow.run_id", activity_info.workflow_run_id) try: return await super().execute_activity(input) except Exception as e: if len(input.args) == 1: [arg] = input.args if is_dataclass(arg) and not isinstance(arg, type): - set_context("temporal.activity.input", asdict(arg)) - set_context("temporal.activity.info", activity.info().__dict__) - capture_exception() + scope.set_context("temporal.activity.input", asdict(arg)) + scope.set_context("temporal.activity.info", activity.info().__dict__) + scope.capture_exception() raise e class _SentryWorkflowInterceptor(WorkflowInboundInterceptor): async def execute_workflow(self, input: ExecuteWorkflowInput) -> Any: # https://docs.sentry.io/platforms/python/troubleshooting/#addressing-concurrency-issues - with Hub(Hub.current): - set_tag("temporal.execution_type", "workflow") - set_tag("module", input.run_fn.__module__ + "." + input.run_fn.__qualname__) + with sentry_sdk.isolation_scope() as scope: + scope.set_tag("temporal.execution_type", "workflow") + scope.set_tag( + "module", input.run_fn.__module__ + "." + input.run_fn.__qualname__ + ) workflow_info = workflow.info() - _set_common_workflow_tags(workflow_info) - set_tag("temporal.workflow.task_queue", workflow_info.task_queue) - set_tag("temporal.workflow.namespace", workflow_info.namespace) - set_tag("temporal.workflow.run_id", workflow_info.run_id) + scope.set_tag("temporal.workflow.type", workflow_info.workflow_type) + scope.set_tag("temporal.workflow.id", workflow_info.workflow_id) + scope.set_tag("temporal.workflow.task_queue", workflow_info.task_queue) + scope.set_tag("temporal.workflow.namespace", workflow_info.namespace) + scope.set_tag("temporal.workflow.run_id", workflow_info.run_id) try: return await super().execute_workflow(input) except Exception as e: if len(input.args) == 1: [arg] = input.args if is_dataclass(arg) and not isinstance(arg, type): - set_context("temporal.workflow.input", asdict(arg)) - set_context("temporal.workflow.info", workflow.info().__dict__) - + scope.set_context("temporal.workflow.input", asdict(arg)) + scope.set_context("temporal.workflow.info", workflow.info().__dict__) if not workflow.unsafe.is_replaying(): with workflow.unsafe.sandbox_unrestricted(): - capture_exception() + scope.capture_exception() raise e @@ -78,9 +81,6 @@ class SentryInterceptor(Interceptor): def intercept_activity( self, next: ActivityInboundInterceptor ) -> ActivityInboundInterceptor: - """Implementation of - :py:meth:`temporalio.worker.Interceptor.intercept_activity`. - """ return _SentryActivityInboundInterceptor(super().intercept_activity(next)) def workflow_interceptor_class( diff --git a/sentry/starter.py b/sentry/starter.py index 9d0a0dc7..372a732c 100644 --- a/sentry/starter.py +++ b/sentry/starter.py @@ -1,9 +1,8 @@ import asyncio -import os from temporalio.client import Client -from sentry.worker import GreetingWorkflow +from sentry.workflow import SentryExampleWorkflow, SentryExampleWorkflowInput async def main(): @@ -11,13 +10,16 @@ async def main(): client = await Client.connect("localhost:7233") # Run workflow - result = await client.execute_workflow( - GreetingWorkflow.run, - "World", - id="sentry-workflow-id", - task_queue="sentry-task-queue", - ) - print(f"Workflow result: {result}") + try: + result = await client.execute_workflow( + SentryExampleWorkflow.run, + SentryExampleWorkflowInput(option="broken"), + id="sentry-workflow-id", + task_queue="sentry-task-queue", + ) + print(f"Workflow result: {result}") + except Exception: + print("Workflow failed - check Sentry for details") if __name__ == "__main__": diff --git a/sentry/worker.py b/sentry/worker.py index 1db0826b..723b8e52 100644 --- a/sentry/worker.py +++ b/sentry/worker.py @@ -1,64 +1,92 @@ import asyncio -import logging import os -from dataclasses import dataclass -from datetime import timedelta import sentry_sdk -from temporalio import activity, workflow +from sentry_sdk.integrations.asyncio import AsyncioIntegration +from sentry_sdk.types import Event, Hint from temporalio.client import Client from temporalio.worker import Worker +from temporalio.worker.workflow_sandbox import ( + SandboxedWorkflowRunner, + SandboxRestrictions, +) +from sentry.activity import broken_activity, working_activity from sentry.interceptor import SentryInterceptor +from sentry.workflow import SentryExampleWorkflow +interrupt_event = asyncio.Event() -@dataclass -class ComposeGreetingInput: - greeting: str - name: str +def before_send(event: Event, hint: Hint) -> Event | None: + # Filter out __ShutdownRequested events raised by the worker's internals + if str(hint.get("exc_info", [None])[0].__name__) == "_ShutdownRequested": + return None -@activity.defn -async def compose_greeting(input: ComposeGreetingInput) -> str: - activity.logger.info("Running activity with parameter %s" % input) - return f"{input.greeting}, {input.name}!" + return event -@workflow.defn -class GreetingWorkflow: - @workflow.run - async def run(self, name: str) -> str: - workflow.logger.info("Running workflow with parameter %s" % name) - return await workflow.execute_activity( - compose_greeting, - ComposeGreetingInput("Hello", name), - start_to_close_timeout=timedelta(seconds=10), +def initialise_sentry() -> None: + sentry_dsn = os.environ.get("SENTRY_DSN") + if not sentry_dsn: + print( + "SENTRY_DSN environment variable is not set. Sentry will not be initialized." ) + return + environment = os.environ.get("ENVIRONMENT") + sentry_sdk.init( + dsn=sentry_dsn, + environment=environment, + integrations=[ + AsyncioIntegration(), + ], + attach_stacktrace=True, + before_send=before_send, + ) + print(f"Sentry SDK initialized for environment: {environment!r}") -async def main(): - # Uncomment the line below to see logging - # logging.basicConfig(level=logging.INFO) +async def main(): # Initialize the Sentry SDK - sentry_sdk.init( - dsn=os.environ.get("SENTRY_DSN"), - ) + initialise_sentry() # Start client client = await Client.connect("localhost:7233") # Run a worker for the workflow - worker = Worker( + async with Worker( client, task_queue="sentry-task-queue", - workflows=[GreetingWorkflow], - activities=[compose_greeting], + workflows=[SentryExampleWorkflow], + activities=[broken_activity, working_activity], interceptors=[SentryInterceptor()], # Use SentryInterceptor for error reporting - ) - - await worker.run() + workflow_runner=SandboxedWorkflowRunner( + restrictions=SandboxRestrictions.default.with_passthrough_modules( + "sentry_sdk" + ) + ), + ): + # Wait until interrupted + print("Worker started, ctrl+c to exit") + await interrupt_event.wait() + print("Shutting down") if __name__ == "__main__": - asyncio.run(main()) + # Note: "Addressing Concurrency Issues" section in Sentry docs recommends using + # the AsyncioIntegration: "If you do concurrency with asyncio coroutines, make + # sure to use the AsyncioIntegration which will clone the correct scope in your Tasks" + # See https://docs.sentry.io/platforms/python/troubleshooting/ + # + # However, this captures all unhandled exceptions in the event loop. + # So handle shutdown gracefully to avoid CancelledError and KeyboardInterrupt + # exceptions being captured as errors. Sentry also captures the worker's + # _ShutdownRequested exception, which is probably not useful. We've filtered this + # out in Sentry's before_send function. + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + interrupt_event.set() + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/sentry/workflow.py b/sentry/workflow.py new file mode 100644 index 00000000..4cb779ea --- /dev/null +++ b/sentry/workflow.py @@ -0,0 +1,38 @@ +import typing +from dataclasses import dataclass +from datetime import timedelta + +from temporalio import workflow +from temporalio.common import RetryPolicy + +from sentry.activity import WorkingActivityInput, working_activity + +with workflow.unsafe.imports_passed_through(): + from sentry.activity import BrokenActivityInput, broken_activity + + +@dataclass +class SentryExampleWorkflowInput: + option: typing.Literal["working", "broken"] + + +@workflow.defn +class SentryExampleWorkflow: + @workflow.run + async def run(self, input: SentryExampleWorkflowInput) -> str: + workflow.logger.info("Running workflow with parameter %r" % input) + + if input.option == "working": + return await workflow.execute_activity( + working_activity, + WorkingActivityInput(message="Hello, Temporal!"), + start_to_close_timeout=timedelta(seconds=10), + retry_policy=RetryPolicy(maximum_attempts=1), + ) + + return await workflow.execute_activity( + broken_activity, + BrokenActivityInput(message="Hello, Temporal!"), + start_to_close_timeout=timedelta(seconds=10), + retry_policy=RetryPolicy(maximum_attempts=1), + ) diff --git a/tests/sentry/fake_sentry_transport.py b/tests/sentry/fake_sentry_transport.py new file mode 100644 index 00000000..7d1b087d --- /dev/null +++ b/tests/sentry/fake_sentry_transport.py @@ -0,0 +1,17 @@ +import sentry_sdk +import sentry_sdk.types + + +class FakeSentryTransport: + """A fake transport that captures Sentry events in memory""" + + # Note: we could extend from sentry_sdk.transport.Transport + # but `sentry_sdk.init` also takes a simple callable that takes + # an Event rather than a serialised Envelope object, so testing + # is easier. + + def __init__(self): + self.events: list[sentry_sdk.types.Event] = [] + + def __call__(self, event: sentry_sdk.types.Event) -> None: + self.events.append(event) diff --git a/tests/sentry/test_interceptor.py b/tests/sentry/test_interceptor.py new file mode 100644 index 00000000..731bad8c --- /dev/null +++ b/tests/sentry/test_interceptor.py @@ -0,0 +1,156 @@ +import unittest.mock +from collections import abc + +import pytest +import sentry_sdk +import temporalio.activity +import temporalio.workflow +from sentry_sdk.integrations.asyncio import AsyncioIntegration +from temporalio.client import Client +from temporalio.worker import Worker +from temporalio.worker.workflow_sandbox import ( + SandboxedWorkflowRunner, + SandboxRestrictions, +) + +from sentry.activity import broken_activity, working_activity +from sentry.interceptor import SentryInterceptor +from sentry.workflow import SentryExampleWorkflow, SentryExampleWorkflowInput +from tests.sentry.fake_sentry_transport import FakeSentryTransport + + +@pytest.fixture +def transport() -> FakeSentryTransport: + """Fixture to provide a fake transport for Sentry SDK.""" + return FakeSentryTransport() + + +@pytest.fixture(autouse=True) +def sentry_init(transport: FakeSentryTransport) -> None: + """Initialize Sentry for testing.""" + sentry_sdk.init( + transport=transport, + integrations=[ + AsyncioIntegration(), + ], + ) + + +@pytest.fixture +async def worker(client: Client) -> abc.AsyncIterator[Worker]: + """Fixture to provide a worker for testing.""" + async with Worker( + client, + task_queue="sentry-task-queue", + workflows=[SentryExampleWorkflow], + activities=[broken_activity, working_activity], + interceptors=[SentryInterceptor()], + workflow_runner=SandboxedWorkflowRunner( + restrictions=SandboxRestrictions.default.with_passthrough_modules( + "sentry_sdk" + ) + ), + ) as worker: + yield worker + + +async def test_sentry_interceptor_reports_no_errors_when_workflow_succeeds( + client: Client, worker: Worker, transport: FakeSentryTransport +) -> None: + """Test that Sentry interceptor reports no errors when workflow succeeds.""" + # WHEN + try: + await client.execute_workflow( + SentryExampleWorkflow.run, + SentryExampleWorkflowInput(option="working"), + id="sentry-workflow-id", + task_queue=worker.task_queue, + ) + except Exception: + pytest.fail("Workflow should not raise an exception") + + # THEN + assert len(transport.events) == 0, "No events should be captured" + + +async def test_sentry_interceptor_captures_errors( + client: Client, worker: Worker, transport: FakeSentryTransport +) -> None: + """Test that errors are captured with correct Sentry metadata.""" + # WHEN + try: + await client.execute_workflow( + SentryExampleWorkflow.run, + SentryExampleWorkflowInput(option="broken"), + id="sentry-workflow-id", + task_queue=worker.task_queue, + ) + pytest.fail("Workflow should raise an exception") + except Exception: + pass + + # THEN + # there should be two events: one for the failed activity and one for the failed workflow + assert len(transport.events) == 2, "Two events should be captured" + + # Check the first event - should be the activity exception + # -------------------------------------------------------- + event = transport.events[0] + + # Check exception was captured + assert event["exception"]["values"][0]["type"] == "Exception" + assert event["exception"]["values"][0]["value"] == "Activity failed!" + + # Check useful metadata were captured as tags + assert event["tags"] == { + "temporal.execution_type": "activity", + "module": "sentry.activity.broken_activity", + "temporal.workflow.type": "SentryExampleWorkflow", + "temporal.workflow.id": "sentry-workflow-id", + "temporal.activity.id": "1", + "temporal.activity.type": "broken_activity", + "temporal.activity.task_queue": "sentry-task-queue", + "temporal.workflow.namespace": "default", + "temporal.workflow.run_id": unittest.mock.ANY, + } + + # Check activity input was captured as context + assert event["contexts"]["temporal.activity.input"] == { + "message": "Hello, Temporal!", + } + + # Check activity info was captured as context + activity_info = temporalio.activity.Info( + **event["contexts"]["temporal.activity.info"] # type: ignore + ) + assert activity_info.activity_type == "broken_activity" + + # Check the second event - should be the workflow exception + # --------------------------------------------------------- + event = transport.events[1] + + # Check exception was captured + assert event["exception"]["values"][0]["type"] == "ApplicationError" + assert event["exception"]["values"][0]["value"] == "Activity failed!" + + # Check useful metadata were captured as tags + assert event["tags"] == { + "temporal.execution_type": "workflow", + "module": "sentry.workflow.SentryExampleWorkflow.run", + "temporal.workflow.type": "SentryExampleWorkflow", + "temporal.workflow.id": "sentry-workflow-id", + "temporal.workflow.task_queue": "sentry-task-queue", + "temporal.workflow.namespace": "default", + "temporal.workflow.run_id": unittest.mock.ANY, + } + + # Check workflow input was captured as context + assert event["contexts"]["temporal.workflow.input"] == { + "option": "broken", + } + + # Check workflow info was captured as context + workflow_info = temporalio.workflow.Info( + **event["contexts"]["temporal.workflow.info"] # type: ignore + ) + assert workflow_info.workflow_type == "SentryExampleWorkflow" diff --git a/uv.lock b/uv.lock index 8fc1c4b4..9b1309d1 100644 --- a/uv.lock +++ b/uv.lock @@ -2477,15 +2477,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "1.45.1" +version = "2.34.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/c8/28/02c0cd9184f9108e3c52519f9628b215077a3854240e0b17ae845e664855/sentry_sdk-1.45.1.tar.gz", hash = "sha256:a16c997c0f4e3df63c0fc5e4207ccb1ab37900433e0f72fef88315d317829a26", size = 244774, upload-time = "2024-07-26T13:48:32.375Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3a/38/10d6bfe23df1bfc65ac2262ed10b45823f47f810b0057d3feeea1ca5c7ed/sentry_sdk-2.34.1.tar.gz", hash = "sha256:69274eb8c5c38562a544c3e9f68b5be0a43be4b697f5fd385bf98e4fbe672687", size = 336969, upload-time = "2025-07-30T11:13:37.93Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/9f/105366a122efa93f0cb1914f841747d160788e4d022d0488d2d44c2ba26c/sentry_sdk-1.45.1-py2.py3-none-any.whl", hash = "sha256:608887855ccfe39032bfd03936e3a1c4f4fc99b3a4ac49ced54a4220de61c9c1", size = 267163, upload-time = "2024-07-26T13:48:29.38Z" }, + { url = "https://files.pythonhosted.org/packages/2d/3e/bb34de65a5787f76848a533afbb6610e01fbcdd59e76d8679c254e02255c/sentry_sdk-2.34.1-py2.py3-none-any.whl", hash = "sha256:b7a072e1cdc5abc48101d5146e1ae680fa81fe886d8d95aaa25a0b450c818d32", size = 357743, upload-time = "2025-07-30T11:13:36.145Z" }, ] [[package]] @@ -2748,7 +2748,7 @@ openai-agents = [ { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.15.0" }, ] pydantic-converter = [{ name = "pydantic", specifier = ">=2.10.6,<3" }] -sentry = [{ name = "sentry-sdk", specifier = ">=1.11.0,<2" }] +sentry = [{ name = "sentry-sdk", specifier = ">=2.13.0" }] trio-async = [ { name = "trio", specifier = ">=0.28.0,<0.29" }, { name = "trio-asyncio", specifier = ">=0.15.0,<0.16" }, From c0b37a49854e0ed21af87a57ad77ea81ca60f1c4 Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Tue, 12 Aug 2025 11:56:55 -0700 Subject: [PATCH 14/40] External client configuration sample (#228) * External client configuration sample * update sample * linting * address review --- README.md | 1 + env_config/README.md | 43 +++++++++++++++++++++++++++++ env_config/__init__.py | 1 + env_config/config.toml | 40 +++++++++++++++++++++++++++ env_config/load_from_file.py | 46 +++++++++++++++++++++++++++++++ env_config/load_profile.py | 52 ++++++++++++++++++++++++++++++++++++ 6 files changed, 183 insertions(+) create mode 100644 env_config/README.md create mode 100644 env_config/__init__.py create mode 100644 env_config/config.toml create mode 100644 env_config/load_from_file.py create mode 100644 env_config/load_profile.py diff --git a/README.md b/README.md index 4a4bb829..43d2cba6 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [custom_metric](custom_metric) - Custom metric to record the workflow type in the activity schedule to start latency. * [dsl](dsl) - DSL workflow that executes steps defined in a YAML file. * [encryption](encryption) - Apply end-to-end encryption for all input/output. +* [env_config](env_config) - Load client configuration from TOML files with programmatic overrides. * [gevent_async](gevent_async) - Combine gevent and Temporal. * [langchain](langchain) - Orchestrate workflows for LangChain. * [message_passing/introduction](message_passing/introduction/) - Introduction to queries, signals, and updates. diff --git a/env_config/README.md b/env_config/README.md new file mode 100644 index 00000000..6496900a --- /dev/null +++ b/env_config/README.md @@ -0,0 +1,43 @@ +# Temporal External Client Configuration Samples + +This directory contains Python samples that demonstrate how to use the Temporal SDK's external client configuration feature. This feature allows you to configure a `temporalio.client.Client` using a TOML file and/or programmatic overrides, decoupling connection settings from your application code. + +## Prerequisites + +To run, first see [README.md](../README.md) for prerequisites. + +## Configuration File + +The `config.toml` file defines three profiles for different environments: + +- `[profile.default]`: A working configuration for local development. +- `[profile.staging]`: A configuration with an intentionally **incorrect** address (`localhost:9999`) to demonstrate how it can be corrected by an override. +- `[profile.prod]`: A non-runnable, illustrative-only configuration showing a realistic setup for Temporal Cloud with placeholder credentials. This profile is not used by the samples but serves as a reference. + +## Samples + +The following Python scripts demonstrate different ways to load and use these configuration profiles. Each runnable sample highlights a unique feature. + +### `load_from_file.py` + +This sample shows the most common use case: loading the `default` profile from the `config.toml` file. + +**To run this sample:** + +```bash +uv run env_config/load_from_file.py +``` + +### `load_profile.py` + +This sample demonstrates loading the `staging` profile by name (which has an incorrect address) and then correcting the address programmatically. This highlights the recommended approach for overriding configuration values at runtime. + +**To run this sample:** + +```bash +uv run env_config/load_profile.py +``` + +## Running the Samples + +You can run each sample script directly from the root of the `samples-python` repository. Ensure you have the necessary dependencies installed by running `pip install -e .` (or the equivalent for your environment). \ No newline at end of file diff --git a/env_config/__init__.py b/env_config/__init__.py new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/env_config/__init__.py @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/env_config/config.toml b/env_config/config.toml new file mode 100644 index 00000000..81f07f78 --- /dev/null +++ b/env_config/config.toml @@ -0,0 +1,40 @@ +# This is a sample configuration file for demonstrating Temporal's environment +# configuration feature. It defines multiple profiles for different environments, +# such as local development, production, and staging. + +# Default profile for local development +[profile.default] +address = "localhost:7233" +namespace = "default" + +# Optional: Add custom gRPC headers +[profile.default.grpc_meta] +my-custom-header = "development-value" +trace-id = "dev-trace-123" + +# Staging profile with inline certificate data +[profile.staging] +address = "localhost:9999" +namespace = "staging" + +# An example production profile for Temporal Cloud +[profile.prod] +address = "your-namespace.a1b2c.tmprl.cloud:7233" +namespace = "your-namespace" +# Replace with your actual Temporal Cloud API key +api_key = "your-api-key-here" + +# TLS configuration for production +[profile.prod.tls] +# TLS is auto-enabled when an API key is present, but you can configure it +# explicitly. +# disabled = false + +# Use certificate files for mTLS. Replace with actual paths. +client_cert_path = "/etc/temporal/certs/client.pem" +client_key_path = "/etc/temporal/certs/client.key" + +# Custom headers for production +[profile.prod.grpc_meta] +environment = "production" +service-version = "v1.2.3" \ No newline at end of file diff --git a/env_config/load_from_file.py b/env_config/load_from_file.py new file mode 100644 index 00000000..ab3bad14 --- /dev/null +++ b/env_config/load_from_file.py @@ -0,0 +1,46 @@ +""" +This sample demonstrates loading the default environment configuration profile +from a TOML file. +""" + +import asyncio +from pathlib import Path + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def main(): + """ + Loads the default profile from the config.toml file in this directory. + """ + print("--- Loading default profile from config.toml ---") + + # For this sample to be self-contained, we explicitly provide the path to + # the config.toml file included in this directory. + # By default though, the config.toml file will be loaded from + # ~/.config/temporalio/temporal.toml (or the equivalent standard config directory on your OS). + config_file = Path(__file__).parent / "config.toml" + + # load_client_connect_config is a helper that loads a profile and prepares + # the config dictionary for Client.connect. By default, it loads the + # "default" profile. + connect_config = ClientConfig.load_client_connect_config( + config_file=str(config_file) + ) + + print(f"Loaded 'default' profile from {config_file}.") + print(f" Address: {connect_config.get('target_host')}") + print(f" Namespace: {connect_config.get('namespace')}") + print(f" gRPC Metadata: {connect_config.get('rpc_metadata')}") + + print("\nAttempting to connect to client...") + try: + await Client.connect(**connect_config) # type: ignore + print("βœ… Client connected successfully!") + except Exception as e: + print(f"❌ Failed to connect: {e}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/env_config/load_profile.py b/env_config/load_profile.py new file mode 100644 index 00000000..fe4f51cf --- /dev/null +++ b/env_config/load_profile.py @@ -0,0 +1,52 @@ +""" +This sample demonstrates loading a named environment configuration profile and +programmatically overriding its values. +""" + +import asyncio +from pathlib import Path + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def main(): + """ + Demonstrates loading a named profile and overriding values programmatically. + """ + print("--- Loading 'staging' profile with programmatic overrides ---") + + config_file = Path(__file__).parent / "config.toml" + profile_name = "staging" + + print( + "The 'staging' profile in config.toml has an incorrect address (localhost:9999)." + ) + print("We'll programmatically override it to the correct address.") + + # Load the 'staging' profile. + connect_config = ClientConfig.load_client_connect_config( + profile=profile_name, + config_file=str(config_file), + ) + + # Override the target host to the correct address. + # This is the recommended way to override configuration values. + connect_config["target_host"] = "localhost:7233" + + print(f"\nLoaded '{profile_name}' profile from {config_file} with overrides.") + print( + f" Address: {connect_config.get('target_host')} (overridden from localhost:9999)" + ) + print(f" Namespace: {connect_config.get('namespace')}") + + print("\nAttempting to connect to client...") + try: + await Client.connect(**connect_config) # type: ignore + print("βœ… Client connected successfully!") + except Exception as e: + print(f"❌ Failed to connect: {e}") + + +if __name__ == "__main__": + asyncio.run(main()) From 6047af020c1aa498287f8f393c91ed1807387eab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mendoza=20P=C3=A9rez?= Date: Wed, 13 Aug 2025 07:00:50 +0200 Subject: [PATCH 15/40] remove-unused-parameter (#234) --- tests/updatable_timer/updatable_timer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/updatable_timer/updatable_timer_test.py b/tests/updatable_timer/updatable_timer_test.py index f1e38245..1f3d8ae0 100644 --- a/tests/updatable_timer/updatable_timer_test.py +++ b/tests/updatable_timer/updatable_timer_test.py @@ -10,7 +10,7 @@ from updatable_timer.workflow import Workflow -async def test_updatable_timer_workflow(client: Client): +async def test_updatable_timer_workflow(): logging.basicConfig(level=logging.DEBUG) task_queue_name = str(uuid.uuid4()) From 0cae31358ea35d503016043fb576396e353514c8 Mon Sep 17 00:00:00 2001 From: Jinjia Date: Mon, 25 Aug 2025 22:00:18 +0300 Subject: [PATCH 16/40] fix worker task queue name in basic example (#237) --- openai_agents/basic/run_worker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openai_agents/basic/run_worker.py b/openai_agents/basic/run_worker.py index f9bc0bf5..94d6a882 100644 --- a/openai_agents/basic/run_worker.py +++ b/openai_agents/basic/run_worker.py @@ -47,7 +47,7 @@ async def main(): worker = Worker( client, - task_queue="openai-agents-task-queue", + task_queue="openai-agents-basic-task-queue", workflows=[ HelloWorldAgent, ToolsWorkflow, From 2f36e1a10bbc2265dd6818b1f7e5bfe41d1371bf Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Wed, 3 Sep 2025 10:41:37 -0400 Subject: [PATCH 17/40] Invoke workflow-backed op in two-stage style (#242) --- hello_nexus/caller/workflows.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hello_nexus/caller/workflows.py b/hello_nexus/caller/workflows.py index 240b8b8c..2016f99f 100644 --- a/hello_nexus/caller/workflows.py +++ b/hello_nexus/caller/workflows.py @@ -21,15 +21,15 @@ def __init__(self): @workflow.run async def run(self, name: str) -> tuple[MyOutput, MyOutput]: # Start the nexus operation and wait for the result in one go, using execute_operation. - wf_result = await self.nexus_client.execute_operation( - MyNexusService.my_workflow_run_operation, + op_1_result = await self.nexus_client.execute_operation( + MyNexusService.my_sync_operation, MyInput(name), ) # Alternatively, you can use start_operation to obtain the operation handle and # then `await` the handle to obtain the result. - sync_operation_handle = await self.nexus_client.start_operation( - MyNexusService.my_sync_operation, + op_2_handle = await self.nexus_client.start_operation( + MyNexusService.my_workflow_run_operation, MyInput(name), ) - sync_result = await sync_operation_handle - return sync_result, wf_result + op_2_result = await op_2_handle + return op_1_result, op_2_result From 0c66e2f5e68942b3c8abdebd889e8b85b352fe32 Mon Sep 17 00:00:00 2001 From: Spencer Judge Date: Wed, 10 Sep 2025 13:57:36 -0700 Subject: [PATCH 18/40] Add nexus multiple args sample (#244) * Add nexus multiple args sample * Autoformat * Ugh, StrEnum only 3.11 * Remove pointless comment * Add snipsync --- nexus_multiple_args/README.md | 33 ++++++++++++ nexus_multiple_args/__init__.py | 0 nexus_multiple_args/caller/__init__.py | 0 nexus_multiple_args/caller/app.py | 53 +++++++++++++++++++ nexus_multiple_args/caller/workflows.py | 30 +++++++++++ nexus_multiple_args/handler/__init__.py | 0 .../handler/service_handler.py | 39 ++++++++++++++ nexus_multiple_args/handler/worker.py | 45 ++++++++++++++++ nexus_multiple_args/handler/workflows.py | 32 +++++++++++ nexus_multiple_args/service.py | 34 ++++++++++++ tests/hello_nexus/hello_nexus_test.py | 2 +- tests/helpers/__init__.py | 0 .../helpers.py => helpers/nexus.py} | 0 tests/nexus_multiple_args/__init__.py | 0 .../nexus_multiple_args_test.py | 50 +++++++++++++++++ 15 files changed, 317 insertions(+), 1 deletion(-) create mode 100644 nexus_multiple_args/README.md create mode 100644 nexus_multiple_args/__init__.py create mode 100644 nexus_multiple_args/caller/__init__.py create mode 100644 nexus_multiple_args/caller/app.py create mode 100644 nexus_multiple_args/caller/workflows.py create mode 100644 nexus_multiple_args/handler/__init__.py create mode 100644 nexus_multiple_args/handler/service_handler.py create mode 100644 nexus_multiple_args/handler/worker.py create mode 100644 nexus_multiple_args/handler/workflows.py create mode 100644 nexus_multiple_args/service.py create mode 100644 tests/helpers/__init__.py rename tests/{hello_nexus/helpers.py => helpers/nexus.py} (100%) create mode 100644 tests/nexus_multiple_args/__init__.py create mode 100644 tests/nexus_multiple_args/nexus_multiple_args_test.py diff --git a/nexus_multiple_args/README.md b/nexus_multiple_args/README.md new file mode 100644 index 00000000..8da0f146 --- /dev/null +++ b/nexus_multiple_args/README.md @@ -0,0 +1,33 @@ +This sample shows how to map a Nexus operation to a handler workflow that takes multiple input arguments. The Nexus operation receives a single input object but unpacks it into multiple arguments when starting the workflow. + +### Sample directory structure + +- [service.py](./service.py) - shared Nexus service definition +- [caller](./caller) - a caller workflow that executes Nexus operations, together with a worker and starter code +- [handler](./handler) - Nexus operation handlers, together with a workflow used by the Nexus operation, and a worker that polls for both workflow and Nexus tasks. + +### Instructions + +Start a Temporal server. (See the main samples repo [README](../README.md)). + +Run the following: + +``` +temporal operator namespace create --namespace nexus-multiple-args-handler-namespace +temporal operator namespace create --namespace nexus-multiple-args-caller-namespace + +temporal operator nexus endpoint create \ + --name nexus-multiple-args-nexus-endpoint \ + --target-namespace nexus-multiple-args-handler-namespace \ + --target-task-queue nexus-multiple-args-handler-task-queue +``` + +In one terminal, run the Temporal worker in the handler namespace: +``` +uv run nexus_multiple_args/handler/worker.py +``` + +In another terminal, run the Temporal worker in the caller namespace and start the caller workflow: +``` +uv run nexus_multiple_args/caller/app.py +``` \ No newline at end of file diff --git a/nexus_multiple_args/__init__.py b/nexus_multiple_args/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_multiple_args/caller/__init__.py b/nexus_multiple_args/caller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_multiple_args/caller/app.py b/nexus_multiple_args/caller/app.py new file mode 100644 index 00000000..88aadbf9 --- /dev/null +++ b/nexus_multiple_args/caller/app.py @@ -0,0 +1,53 @@ +import asyncio +import uuid +from typing import Optional + +from temporalio.client import Client +from temporalio.worker import Worker + +from nexus_multiple_args.caller.workflows import CallerWorkflow + +NAMESPACE = "nexus-multiple-args-caller-namespace" +TASK_QUEUE = "nexus-multiple-args-caller-task-queue" + + +async def execute_caller_workflow( + client: Optional[Client] = None, +) -> tuple[str, str]: + client = client or await Client.connect( + "localhost:7233", + namespace=NAMESPACE, + ) + + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[CallerWorkflow], + ): + # Execute workflow with English language + result1 = await client.execute_workflow( + CallerWorkflow.run, + args=["Nexus", "en"], + id=str(uuid.uuid4()), + task_queue=TASK_QUEUE, + ) + + # Execute workflow with Spanish language + result2 = await client.execute_workflow( + CallerWorkflow.run, + args=["Nexus", "es"], + id=str(uuid.uuid4()), + task_queue=TASK_QUEUE, + ) + + return result1, result2 + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + results = loop.run_until_complete(execute_caller_workflow()) + for result in results: + print(result) + except KeyboardInterrupt: + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_multiple_args/caller/workflows.py b/nexus_multiple_args/caller/workflows.py new file mode 100644 index 00000000..940a032f --- /dev/null +++ b/nexus_multiple_args/caller/workflows.py @@ -0,0 +1,30 @@ +from temporalio import workflow + +with workflow.unsafe.imports_passed_through(): + from nexus_multiple_args.service import HelloInput, MyNexusService + +NEXUS_ENDPOINT = "nexus-multiple-args-nexus-endpoint" + + +# This is a workflow that calls a nexus operation with multiple arguments. +@workflow.defn +class CallerWorkflow: + # An __init__ method is always optional on a workflow class. Here we use it to set the + # nexus client, but that could alternatively be done in the run method. + def __init__(self): + self.nexus_client = workflow.create_nexus_client( + service=MyNexusService, + endpoint=NEXUS_ENDPOINT, + ) + + # The workflow run method demonstrates calling a nexus operation with multiple arguments + # packed into an input object. + @workflow.run + async def run(self, name: str, language: str) -> str: + # Start the nexus operation and wait for the result in one go, using execute_operation. + # The multiple arguments (name and language) are packed into a HelloInput object. + result = await self.nexus_client.execute_operation( + MyNexusService.hello, + HelloInput(name=name, language=language), + ) + return result.message diff --git a/nexus_multiple_args/handler/__init__.py b/nexus_multiple_args/handler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_multiple_args/handler/service_handler.py b/nexus_multiple_args/handler/service_handler.py new file mode 100644 index 00000000..c2ddfb92 --- /dev/null +++ b/nexus_multiple_args/handler/service_handler.py @@ -0,0 +1,39 @@ +from __future__ import annotations + +import uuid + +import nexusrpc +from temporalio import nexus + +from nexus_multiple_args.handler.workflows import HelloHandlerWorkflow +from nexus_multiple_args.service import HelloInput, HelloOutput, MyNexusService + + +# @@@SNIPSTART samples-python-nexus-handler-multiargs +@nexusrpc.handler.service_handler(service=MyNexusService) +class MyNexusServiceHandler: + """ + Service handler that demonstrates multiple argument handling in Nexus operations. + """ + + # This is a nexus operation that is backed by a Temporal workflow. + # The key feature here is that it demonstrates how to map a single input object + # (HelloInput) to a workflow that takes multiple individual arguments. + @nexus.workflow_run_operation + async def hello( + self, ctx: nexus.WorkflowRunOperationContext, input: HelloInput + ) -> nexus.WorkflowHandle[HelloOutput]: + """ + Start a workflow with multiple arguments unpacked from the input object. + """ + return await ctx.start_workflow( + HelloHandlerWorkflow.run, + args=[ + input.name, # First argument: name + input.language, # Second argument: language + ], + id=str(uuid.uuid4()), + ) + + +# @@@SNIPEND diff --git a/nexus_multiple_args/handler/worker.py b/nexus_multiple_args/handler/worker.py new file mode 100644 index 00000000..d12a7ee1 --- /dev/null +++ b/nexus_multiple_args/handler/worker.py @@ -0,0 +1,45 @@ +import asyncio +import logging +from typing import Optional + +from temporalio.client import Client +from temporalio.worker import Worker + +from nexus_multiple_args.handler.service_handler import MyNexusServiceHandler +from nexus_multiple_args.handler.workflows import HelloHandlerWorkflow + +interrupt_event = asyncio.Event() + +NAMESPACE = "nexus-multiple-args-handler-namespace" +TASK_QUEUE = "nexus-multiple-args-handler-task-queue" + + +async def main(client: Optional[Client] = None): + logging.basicConfig(level=logging.INFO) + + client = client or await Client.connect( + "localhost:7233", + namespace=NAMESPACE, + ) + + # Start the worker, passing the Nexus service handler instance, in addition to the + # workflow classes that are started by your nexus operations, and any activities + # needed. This Worker will poll for both workflow tasks and Nexus tasks. + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[HelloHandlerWorkflow], + nexus_service_handlers=[MyNexusServiceHandler()], + ): + logging.info("Worker started, ctrl+c to exit") + await interrupt_event.wait() + logging.info("Shutting down") + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + interrupt_event.set() + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_multiple_args/handler/workflows.py b/nexus_multiple_args/handler/workflows.py new file mode 100644 index 00000000..15bd0824 --- /dev/null +++ b/nexus_multiple_args/handler/workflows.py @@ -0,0 +1,32 @@ +from temporalio import workflow + +with workflow.unsafe.imports_passed_through(): + from nexus_multiple_args.service import HelloOutput + + +# This is the workflow that is started by the `hello` nexus operation. +# It demonstrates handling multiple arguments passed from the Nexus service. +@workflow.defn +class HelloHandlerWorkflow: + @workflow.run + async def run(self, name: str, language: str) -> HelloOutput: + """ + Handle the hello workflow with multiple arguments. + + This method receives the individual arguments (name and language) + that were unpacked from the HelloInput in the service handler. + """ + if language == "en": + message = f"Hello {name} πŸ‘‹" + elif language == "fr": + message = f"Bonjour {name} πŸ‘‹" + elif language == "de": + message = f"Hallo {name} πŸ‘‹" + elif language == "es": + message = f"Β‘Hola! {name} πŸ‘‹" + elif language == "tr": + message = f"Merhaba {name} πŸ‘‹" + else: + raise ValueError(f"Unsupported language: {language}") + + return HelloOutput(message=message) diff --git a/nexus_multiple_args/service.py b/nexus_multiple_args/service.py new file mode 100644 index 00000000..ccae11fd --- /dev/null +++ b/nexus_multiple_args/service.py @@ -0,0 +1,34 @@ +""" +This is a Nexus service definition that demonstrates multiple argument handling. + +A service definition defines a Nexus service as a named collection of operations, each +with input and output types. It does not implement operation handling: see the service +handler and operation handlers in nexus_multiple_args.handler.service_handler for that. + +A Nexus service definition is used by Nexus callers (e.g. a Temporal workflow) to create +type-safe clients, and it is used by Nexus handlers to validate that they implement +correctly-named operation handlers with the correct input and output types. + +The service defined in this file features one operation: hello, where hello +demonstrates handling multiple arguments through a single input object. +""" + +from dataclasses import dataclass + +import nexusrpc + + +@dataclass +class HelloInput: + name: str + language: str + + +@dataclass +class HelloOutput: + message: str + + +@nexusrpc.service +class MyNexusService: + hello: nexusrpc.Operation[HelloInput, HelloOutput] diff --git a/tests/hello_nexus/hello_nexus_test.py b/tests/hello_nexus/hello_nexus_test.py index f9a8807d..fecfe17c 100644 --- a/tests/hello_nexus/hello_nexus_test.py +++ b/tests/hello_nexus/hello_nexus_test.py @@ -8,7 +8,7 @@ import hello_nexus.caller.app import hello_nexus.caller.workflows import hello_nexus.handler.worker -from tests.hello_nexus.helpers import create_nexus_endpoint, delete_nexus_endpoint +from tests.helpers.nexus import create_nexus_endpoint, delete_nexus_endpoint async def test_nexus_service_basic(client: Client, env: WorkflowEnvironment): diff --git a/tests/helpers/__init__.py b/tests/helpers/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/hello_nexus/helpers.py b/tests/helpers/nexus.py similarity index 100% rename from tests/hello_nexus/helpers.py rename to tests/helpers/nexus.py diff --git a/tests/nexus_multiple_args/__init__.py b/tests/nexus_multiple_args/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/nexus_multiple_args/nexus_multiple_args_test.py b/tests/nexus_multiple_args/nexus_multiple_args_test.py new file mode 100644 index 00000000..682b8f20 --- /dev/null +++ b/tests/nexus_multiple_args/nexus_multiple_args_test.py @@ -0,0 +1,50 @@ +import asyncio +import sys + +import pytest +from temporalio.client import Client +from temporalio.testing import WorkflowEnvironment + +import nexus_multiple_args.caller.app +import nexus_multiple_args.caller.workflows +import nexus_multiple_args.handler.worker +from tests.helpers.nexus import create_nexus_endpoint, delete_nexus_endpoint + + +async def test_nexus_multiple_args(client: Client, env: WorkflowEnvironment): + if env.supports_time_skipping: + pytest.skip("Nexus tests don't work under the Java test server") + + if sys.version_info[:2] < (3, 10): + pytest.skip("Sample is written for Python >= 3.10") + + create_response = await create_nexus_endpoint( + name=nexus_multiple_args.caller.workflows.NEXUS_ENDPOINT, + task_queue=nexus_multiple_args.handler.worker.TASK_QUEUE, + client=client, + ) + try: + handler_worker_task = asyncio.create_task( + nexus_multiple_args.handler.worker.main( + client, + ) + ) + await asyncio.sleep(1) + results = await nexus_multiple_args.caller.app.execute_caller_workflow( + client, + ) + nexus_multiple_args.handler.worker.interrupt_event.set() + await handler_worker_task + nexus_multiple_args.handler.worker.interrupt_event.clear() + + # Verify the expected output messages + assert results == ( + "Hello Nexus πŸ‘‹", + "Β‘Hola! Nexus πŸ‘‹", + ) + finally: + await delete_nexus_endpoint( + id=create_response.endpoint.id, + version=create_response.endpoint.version, + client=client, + ) From 8597fddd1589f5fb5c9a7152a6b63b43053d93a1 Mon Sep 17 00:00:00 2001 From: Spencer Judge Date: Wed, 17 Sep 2025 16:12:07 -0700 Subject: [PATCH 19/40] Update worker versioning sample to use deployments (#246) --- .gitignore | 1 + worker_versioning/README.md | 30 +++-- worker_versioning/activities.py | 20 ++- worker_versioning/app.py | 139 +++++++++++++++++++++ worker_versioning/example.py | 116 ------------------ worker_versioning/workerv1.py | 40 ++++++ worker_versioning/workerv1_1.py | 40 ++++++ worker_versioning/workerv2.py | 40 ++++++ worker_versioning/workflow_v1.py | 27 ----- worker_versioning/workflow_v1_1.py | 45 ------- worker_versioning/workflow_v2.py | 36 ------ worker_versioning/workflows.py | 189 +++++++++++++++++++++++++++++ 12 files changed, 487 insertions(+), 236 deletions(-) create mode 100644 worker_versioning/app.py delete mode 100644 worker_versioning/example.py create mode 100644 worker_versioning/workerv1.py create mode 100644 worker_versioning/workerv1_1.py create mode 100644 worker_versioning/workerv2.py delete mode 100644 worker_versioning/workflow_v1.py delete mode 100644 worker_versioning/workflow_v1_1.py delete mode 100644 worker_versioning/workflow_v2.py create mode 100644 worker_versioning/workflows.py diff --git a/.gitignore b/.gitignore index 41afe5f8..157a7418 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ __pycache__ .vscode .DS_Store +.claude diff --git a/worker_versioning/README.md b/worker_versioning/README.md index 2fd44bc4..0ff423f1 100644 --- a/worker_versioning/README.md +++ b/worker_versioning/README.md @@ -1,12 +1,26 @@ -# Worker Versioning Sample +## Worker Versioning -This sample shows you how you can use the [Worker Versioning](https://docs.temporal.io/workers#worker-versioning) -feature to deploy incompatible changes to workflow code more easily. +This sample demonstrates how to use Temporal's Worker Versioning feature to safely deploy updates to workflow and activity code. It shows the difference between auto-upgrading and pinned workflows, and how to manage worker deployments with different build IDs. -To run, first see [README.md](../README.md) for prerequisites. Then, run the following from the root directory: +The sample creates multiple worker versions (1.0, 1.1, and 2.0) within one deployment and demonstrates: +- **Auto-upgrading workflows**: Automatically and controllably migrate to newer worker versions +- **Pinned workflows**: Stay on the original worker version throughout their lifecycle +- **Compatible vs incompatible changes**: How to make safe updates using `workflow.patched` - uv run worker_versioning/example.py +### Steps to run this sample: -This will add some Build IDs to a Task Queue, and will also run Workers with those versions to show how you can -mark add versions, mark them as compatible (or not) with one another, and run Workers at specific versions. You'll -see that only the workers only process Workflow Tasks assigned versions they are compatible with. +1) Run a [Temporal service](https://github.com/temporalio/samples-python/tree/main/#how-to-use). + Ensure that you're using at least Server version 1.28.0 (CLI version 1.4.0). + +2) Start the main application (this will guide you through the sample): +```bash +uv run worker_versioning/app.py +``` + +3) Follow the prompts to start workers in separate terminals: + - When prompted, run: `uv run worker_versioning/workerv1.py` + - When prompted, run: `uv run worker_versioning/workerv1_1.py` + - When prompted, run: `uv run worker_versioning/workerv2.py` + +The sample will show how auto-upgrading workflows migrate to newer workers while pinned workflows +remain on their original version. diff --git a/worker_versioning/activities.py b/worker_versioning/activities.py index 4115e0fd..50c0700f 100644 --- a/worker_versioning/activities.py +++ b/worker_versioning/activities.py @@ -1,11 +1,23 @@ +from dataclasses import dataclass + from temporalio import activity +@dataclass +class IncompatibleActivityInput: + """Input for the incompatible activity.""" + + called_by: str + more_data: str + + @activity.defn -async def greet(inp: str) -> str: - return f"Hi from {inp}" +async def some_activity(called_by: str) -> str: + """Basic activity for the workflow.""" + return f"some_activity called by {called_by}" @activity.defn -async def super_greet(inp: str, some_number: int) -> str: - return f"Hi from {inp} with {some_number}" +async def some_incompatible_activity(input_data: IncompatibleActivityInput) -> str: + """Incompatible activity that takes different input.""" + return f"some_incompatible_activity called by {input_data.called_by} with {input_data.more_data}" diff --git a/worker_versioning/app.py b/worker_versioning/app.py new file mode 100644 index 00000000..8b32aa94 --- /dev/null +++ b/worker_versioning/app.py @@ -0,0 +1,139 @@ +"""Main application for the worker versioning sample.""" + +import asyncio +import logging +import uuid + +from temporalio.client import Client + +TASK_QUEUE = "worker-versioning" +DEPLOYMENT_NAME = "my-deployment" + +logging.basicConfig(level=logging.INFO) + + +async def main() -> None: + client = await Client.connect("localhost:7233") + + # Wait for v1 worker and set as current version + logging.info( + "Waiting for v1 worker to appear. Run `python worker_versioning/workerv1.py` in another terminal" + ) + await wait_for_worker_and_make_current(client, "1.0") + + # Start auto-upgrading and pinned workflows. Importantly, note that when we start the workflows, + # we are using a workflow type name which does *not* include the version number. We defined them + # with versioned names so we could show changes to the code, but here when the client invokes + # them, we're demonstrating that the client remains version-agnostic. + auto_upgrade_workflow_id = "worker-versioning-versioning-autoupgrade_" + str( + uuid.uuid4() + ) + auto_upgrade_execution = await client.start_workflow( + "AutoUpgrading", + id=auto_upgrade_workflow_id, + task_queue=TASK_QUEUE, + ) + + pinned_workflow_id = "worker-versioning-versioning-pinned_" + str(uuid.uuid4()) + pinned_execution = await client.start_workflow( + "Pinned", + id=pinned_workflow_id, + task_queue=TASK_QUEUE, + ) + + logging.info("Started auto-upgrading workflow: %s", auto_upgrade_execution.id) + logging.info("Started pinned workflow: %s", pinned_execution.id) + + # Signal both workflows a few times to drive them + await advance_workflows(auto_upgrade_execution, pinned_execution) + + # Now wait for the v1.1 worker to appear and become current + logging.info( + "Waiting for v1.1 worker to appear. Run `python worker_versioning/workerv1_1.py` in another terminal" + ) + await wait_for_worker_and_make_current(client, "1.1") + + # Once it has, we will continue to advance the workflows. + # The auto-upgrade workflow will now make progress on the new worker, while the pinned one will + # keep progressing on the old worker. + await advance_workflows(auto_upgrade_execution, pinned_execution) + + # Finally we'll start the v2 worker, and again it'll become the new current version + logging.info( + "Waiting for v2 worker to appear. Run `python worker_versioning/workerv2.py` in another terminal" + ) + await wait_for_worker_and_make_current(client, "2.0") + + # Once it has we'll start one more new workflow, another pinned one, to demonstrate that new + # pinned workflows start on the current version. + pinned_workflow_2_id = "worker-versioning-versioning-pinned-2_" + str(uuid.uuid4()) + pinned_execution_2 = await client.start_workflow( + "Pinned", + id=pinned_workflow_2_id, + task_queue=TASK_QUEUE, + ) + logging.info("Started pinned workflow v2: %s", pinned_execution_2.id) + + # Now we'll conclude all workflows. You should be able to see in your server UI that the pinned + # workflow always stayed on 1.0, while the auto-upgrading workflow migrated. + for handle in [auto_upgrade_execution, pinned_execution, pinned_execution_2]: + await handle.signal("do_next_signal", "conclude") + await handle.result() + + logging.info("All workflows completed") + + +async def advance_workflows(auto_upgrade_execution, pinned_execution): + """Signal both workflows a few times to drive them.""" + for i in range(3): + await auto_upgrade_execution.signal("do_next_signal", "do-activity") + await pinned_execution.signal("do_next_signal", "some-signal") + + +async def wait_for_worker_and_make_current(client: Client, build_id: str) -> None: + import temporalio.api.workflowservice.v1 as wsv1 + from temporalio.common import WorkerDeploymentVersion + + target_version = WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id=build_id + ) + + while True: + try: + describe_request = wsv1.DescribeWorkerDeploymentRequest( + namespace=client.namespace, + deployment_name=DEPLOYMENT_NAME, + ) + response = await client.workflow_service.describe_worker_deployment( + describe_request + ) + + for version_summary in response.worker_deployment_info.version_summaries: + if ( + version_summary.deployment_version.deployment_name + == target_version.deployment_name + and version_summary.deployment_version.build_id + == target_version.build_id + ): + break + else: + await asyncio.sleep(1) + continue + + break + + except Exception: + await asyncio.sleep(1) + continue + + # Once the version is available, set it as current + set_request = wsv1.SetWorkerDeploymentCurrentVersionRequest( + namespace=client.namespace, + deployment_name=DEPLOYMENT_NAME, + build_id=target_version.build_id, + ) + await client.workflow_service.set_worker_deployment_current_version(set_request) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/worker_versioning/example.py b/worker_versioning/example.py deleted file mode 100644 index 97354303..00000000 --- a/worker_versioning/example.py +++ /dev/null @@ -1,116 +0,0 @@ -import asyncio -import uuid - -from temporalio.client import BuildIdOpAddNewCompatible, BuildIdOpAddNewDefault, Client -from temporalio.worker import Worker - -from worker_versioning.activities import greet, super_greet -from worker_versioning.workflow_v1 import MyWorkflow as MyWorkflowV1 -from worker_versioning.workflow_v1_1 import MyWorkflow as MyWorkflowV1_1 -from worker_versioning.workflow_v2 import MyWorkflow as MyWorkflowV2 - - -async def main(): - client = await Client.connect("localhost:7233") - task_queue = f"worker-versioning-{uuid.uuid4()}" - - # Start a 1.0 worker - async with Worker( - client, - task_queue=task_queue, - workflows=[MyWorkflowV1], - activities=[greet, super_greet], - build_id="1.0", - use_worker_versioning=True, - ): - # Add 1.0 as the default version for the queue - await client.update_worker_build_id_compatibility( - task_queue, BuildIdOpAddNewDefault("1.0") - ) - - # Start a workflow which will run on the 1.0 worker - handle = await client.start_workflow( - MyWorkflowV1.run, - task_queue=task_queue, - id=f"worker-versioning-v1-{uuid.uuid4()}", - ) - # Signal the workflow to proceed - await handle.signal(MyWorkflowV1.proceeder, "go") - - # Give a chance for the worker to process the signal - # TODO Better? - await asyncio.sleep(1) - - # Add 1.1 as the default version for the queue, compatible with 1.0 - await client.update_worker_build_id_compatibility( - task_queue, BuildIdOpAddNewCompatible("1.1", "1.0") - ) - - # Stop the old worker, and start a 1.1 worker. We do this to speed along the example, since the - # 1.0 worker may continue to process tasks briefly after we make 1.1 the new default. - async with Worker( - client, - task_queue=task_queue, - workflows=[MyWorkflowV1_1], - activities=[greet, super_greet], - build_id="1.1", - use_worker_versioning=True, - ): - # Continue driving the workflow. Take note that the new version of the workflow run by the 1.1 - # worker is the one that takes over! You might see a workflow task timeout, if the 1.0 worker is - # processing a task as the version update happens. That's normal. - await handle.signal(MyWorkflowV1.proceeder, "go") - - # Add a new *incompatible* version to the task queue, which will become the new overall default for the queue. - await client.update_worker_build_id_compatibility( - task_queue, BuildIdOpAddNewDefault("2.0") - ) - - # Start a 2.0 worker - async with Worker( - client, - task_queue=task_queue, - workflows=[MyWorkflowV2], - activities=[greet, super_greet], - build_id="2.0", - use_worker_versioning=True, - ): - # Start a new workflow. Note that it will run on the new 2.0 version, without the client invocation changing - # at all! Note here we can use `MyWorkflowV1.run` because the signature of the workflow has not changed. - handle2 = await client.start_workflow( - MyWorkflowV1.run, - task_queue=task_queue, - id=f"worker-versioning-v2-{uuid.uuid4()}", - ) - - # Drive both workflows once more before concluding them. The first workflow will continue running on the 1.1 - # worker. - await handle.signal(MyWorkflowV1.proceeder, "go") - await handle2.signal(MyWorkflowV1.proceeder, "go") - await handle.signal(MyWorkflowV1.proceeder, "finish") - await handle2.signal(MyWorkflowV1.proceeder, "finish") - - # Wait for both workflows to complete - await handle.result() - await handle2.result() - - # Lastly we'll demonstrate how you can use the gRPC api to determine if certain build IDs are ready to be - # retired. There's more information in the documentation, but here's a quick example that shows us how to - # tell when the 1.0 worker can be retired: - - # There is a 5 minute buffer before we will consider IDs no longer reachable by new workflows, to - # account for replication in multi-cluster setups. Uncomment the following line to wait long enough to see - # the 1.0 worker become unreachable. - # await asyncio.sleep(60 * 5) - reachability = await client.get_worker_task_reachability( - build_ids=["2.0", "1.0", "1.1"] - ) - - if not reachability.build_id_reachability["1.0"].task_queue_reachability[ - task_queue - ]: - print("1.0 is ready to be retired!") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/worker_versioning/workerv1.py b/worker_versioning/workerv1.py new file mode 100644 index 00000000..13c4ed4b --- /dev/null +++ b/worker_versioning/workerv1.py @@ -0,0 +1,40 @@ +"""Worker v1 for the worker versioning sample.""" + +import asyncio +import logging + +from temporalio.client import Client +from temporalio.common import WorkerDeploymentVersion +from temporalio.worker import Worker, WorkerDeploymentConfig + +from worker_versioning.activities import some_activity, some_incompatible_activity +from worker_versioning.app import DEPLOYMENT_NAME, TASK_QUEUE +from worker_versioning.workflows import AutoUpgradingWorkflowV1, PinnedWorkflowV1 + +logging.basicConfig(level=logging.INFO) + + +async def main() -> None: + """Run worker v1.""" + client = await Client.connect("localhost:7233") + + # Create worker v1 + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[AutoUpgradingWorkflowV1, PinnedWorkflowV1], + activities=[some_activity, some_incompatible_activity], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id="1.0" + ), + use_worker_versioning=True, + ), + ) + + logging.info("Starting worker v1 (build 1.0)") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/worker_versioning/workerv1_1.py b/worker_versioning/workerv1_1.py new file mode 100644 index 00000000..779db3f9 --- /dev/null +++ b/worker_versioning/workerv1_1.py @@ -0,0 +1,40 @@ +"""Worker v1.1 for the worker versioning sample.""" + +import asyncio +import logging + +from temporalio.client import Client +from temporalio.common import WorkerDeploymentVersion +from temporalio.worker import Worker, WorkerDeploymentConfig + +from worker_versioning.activities import some_activity, some_incompatible_activity +from worker_versioning.app import DEPLOYMENT_NAME, TASK_QUEUE +from worker_versioning.workflows import AutoUpgradingWorkflowV1b, PinnedWorkflowV1 + +logging.basicConfig(level=logging.INFO) + + +async def main() -> None: + """Run worker v1.1.""" + client = await Client.connect("localhost:7233") + + # Create worker v1.1 + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[AutoUpgradingWorkflowV1b, PinnedWorkflowV1], + activities=[some_activity, some_incompatible_activity], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id="1.1" + ), + use_worker_versioning=True, + ), + ) + + logging.info("Starting worker v1.1 (build 1.1)") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/worker_versioning/workerv2.py b/worker_versioning/workerv2.py new file mode 100644 index 00000000..107e1a52 --- /dev/null +++ b/worker_versioning/workerv2.py @@ -0,0 +1,40 @@ +"""Worker v2 for the worker versioning sample.""" + +import asyncio +import logging + +from temporalio.client import Client +from temporalio.common import WorkerDeploymentVersion +from temporalio.worker import Worker, WorkerDeploymentConfig + +from worker_versioning.activities import some_activity, some_incompatible_activity +from worker_versioning.app import DEPLOYMENT_NAME, TASK_QUEUE +from worker_versioning.workflows import AutoUpgradingWorkflowV1b, PinnedWorkflowV2 + +logging.basicConfig(level=logging.INFO) + + +async def main() -> None: + """Run worker v2.""" + client = await Client.connect("localhost:7233") + + # Create worker v2 + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[AutoUpgradingWorkflowV1b, PinnedWorkflowV2], + activities=[some_activity, some_incompatible_activity], + deployment_config=WorkerDeploymentConfig( + version=WorkerDeploymentVersion( + deployment_name=DEPLOYMENT_NAME, build_id="2.0" + ), + use_worker_versioning=True, + ), + ) + + logging.info("Starting worker v2 (build 2.0)") + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/worker_versioning/workflow_v1.py b/worker_versioning/workflow_v1.py deleted file mode 100644 index 1cef9095..00000000 --- a/worker_versioning/workflow_v1.py +++ /dev/null @@ -1,27 +0,0 @@ -from datetime import timedelta - -from temporalio import workflow - -with workflow.unsafe.imports_passed_through(): - from worker_versioning.activities import greet - - -@workflow.defn -class MyWorkflow: - """The 1.0 version of the workflow we'll be making changes to""" - - should_finish: bool = False - - @workflow.run - async def run(self) -> str: - workflow.logger.info("Running workflow V1") - await workflow.wait_condition(lambda: self.should_finish) - return "Concluded workflow on V1" - - @workflow.signal - async def proceeder(self, inp: str): - await workflow.execute_activity( - greet, "V1", start_to_close_timeout=timedelta(seconds=5) - ) - if inp == "finish": - self.should_finish = True diff --git a/worker_versioning/workflow_v1_1.py b/worker_versioning/workflow_v1_1.py deleted file mode 100644 index e2f22943..00000000 --- a/worker_versioning/workflow_v1_1.py +++ /dev/null @@ -1,45 +0,0 @@ -from datetime import timedelta - -from temporalio import workflow - -with workflow.unsafe.imports_passed_through(): - from worker_versioning.activities import greet, super_greet - - -@workflow.defn -class MyWorkflow: - """ - The 1.1 version of the workflow, which is compatible with the first version. - - The compatible changes we've made are: - - Altering the log lines - - Using the `patched` API to properly introduce branching behavior while maintaining - compatibility - """ - - should_finish: bool = False - - @workflow.run - async def run(self) -> str: - workflow.logger.info("Running workflow V1.1") - await workflow.wait_condition(lambda: self.should_finish) - return "Concluded workflow on V1.1" - - @workflow.signal - async def proceeder(self, inp: str): - if workflow.patched("different-activity"): - await workflow.execute_activity( - super_greet, - args=["V1.1", 100], - start_to_close_timeout=timedelta(seconds=5), - ) - else: - # Note it is a valid compatible change to alter the input to an activity. However, because - # we're using the patched API, this branch would only be taken if the workflow was started on - # a v1 worker. - await workflow.execute_activity( - greet, "V1.1", start_to_close_timeout=timedelta(seconds=5) - ) - - if inp == "finish": - self.should_finish = True diff --git a/worker_versioning/workflow_v2.py b/worker_versioning/workflow_v2.py deleted file mode 100644 index dcb0a20e..00000000 --- a/worker_versioning/workflow_v2.py +++ /dev/null @@ -1,36 +0,0 @@ -import asyncio -from datetime import timedelta - -from temporalio import workflow - -with workflow.unsafe.imports_passed_through(): - from worker_versioning.activities import greet - - -@workflow.defn -class MyWorkflow: - """ - The 2.0 version of the workflow, which is fully incompatible with the other workflows, since it - alters the sequence of commands without using `patched`. - """ - - should_finish: bool = False - - @workflow.run - async def run(self) -> str: - workflow.logger.info("Running workflow V2") - await workflow.wait_condition(lambda: self.should_finish) - return "Concluded workflow on V2" - - @workflow.signal - async def proceeder(self, inp: str): - await asyncio.sleep(1) - await workflow.execute_activity( - greet, "V2", start_to_close_timeout=timedelta(seconds=5) - ) - await workflow.execute_activity( - greet, "V2", start_to_close_timeout=timedelta(seconds=5) - ) - - if inp == "finish": - self.should_finish = True diff --git a/worker_versioning/workflows.py b/worker_versioning/workflows.py new file mode 100644 index 00000000..a09c371a --- /dev/null +++ b/worker_versioning/workflows.py @@ -0,0 +1,189 @@ +"""Workflow definitions for the worker versioning sample.""" + +from datetime import timedelta + +from temporalio import common, workflow + +with workflow.unsafe.imports_passed_through(): + from worker_versioning.activities import ( + IncompatibleActivityInput, + some_activity, + some_incompatible_activity, + ) + + +@workflow.defn( + name="AutoUpgrading", versioning_behavior=common.VersioningBehavior.AUTO_UPGRADE +) +class AutoUpgradingWorkflowV1: + """AutoUpgradingWorkflowV1 will automatically move to the latest worker version. We'll be making + changes to it, which must be replay safe. + + Note that generally you won't want or need to include a version number in your workflow name if + you're using the worker versioning feature. This sample does it to illustrate changes to the + same code over time - but really what we're demonstrating here is the evolution of what would + have been one workflow definition. + """ + + def __init__(self) -> None: + self.signals: list[str] = [] + + @workflow.run + async def run(self) -> None: + workflow.logger.info( + "Changing workflow v1 started.", extra={"StartTime": workflow.now()} + ) + + # This workflow will listen for signals from our starter, and upon each signal either run + # an activity, or conclude execution. + while True: + await workflow.wait_condition(lambda: len(self.signals) > 0) + signal = self.signals.pop(0) + + if signal == "do-activity": + workflow.logger.info("Changing workflow v1 running activity") + await workflow.execute_activity( + some_activity, "v1", start_to_close_timeout=timedelta(seconds=10) + ) + else: + workflow.logger.info("Concluding workflow v1") + return + + @workflow.signal + async def do_next_signal(self, signal: str) -> None: + """Signal to perform next action.""" + self.signals.append(signal) + + +@workflow.defn( + name="AutoUpgrading", versioning_behavior=common.VersioningBehavior.AUTO_UPGRADE +) +class AutoUpgradingWorkflowV1b: + """AutoUpgradingWorkflowV1b represents us having made *compatible* changes to + AutoUpgradingWorkflowV1. + + The compatible changes we've made are: + - Altering the log lines + - Using the workflow.patched API to properly introduce branching behavior while maintaining + compatibility + """ + + def __init__(self) -> None: + self.signals: list[str] = [] + + @workflow.run + async def run(self) -> None: + workflow.logger.info( + "Changing workflow v1b started.", extra={"StartTime": workflow.now()} + ) + + # This workflow will listen for signals from our starter, and upon each signal either run + # an activity, or conclude execution. + while True: + await workflow.wait_condition(lambda: len(self.signals) > 0) + signal = self.signals.pop(0) + + if signal == "do-activity": + workflow.logger.info("Changing workflow v1b running activity") + if workflow.patched("DifferentActivity"): + await workflow.execute_activity( + some_incompatible_activity, + IncompatibleActivityInput(called_by="v1b", more_data="hello!"), + start_to_close_timeout=timedelta(seconds=10), + ) + else: + # Note it is a valid compatible change to alter the input to an activity. + # However, because we're using the patched API, this branch will never be + # taken. + await workflow.execute_activity( + some_activity, + "v1b", + start_to_close_timeout=timedelta(seconds=10), + ) + else: + workflow.logger.info("Concluding workflow v1b") + break + + @workflow.signal + async def do_next_signal(self, signal: str) -> None: + """Signal to perform next action.""" + self.signals.append(signal) + + +@workflow.defn(name="Pinned", versioning_behavior=common.VersioningBehavior.PINNED) +class PinnedWorkflowV1: + """PinnedWorkflowV1 demonstrates a workflow that likely has a short lifetime, and we want to always + stay pinned to the same version it began on. + + Note that generally you won't want or need to include a version number in your workflow name if + you're using the worker versioning feature. This sample does it to illustrate changes to the + same code over time - but really what we're demonstrating here is the evolution of what would + have been one workflow definition. + """ + + def __init__(self) -> None: + self.signals: list[str] = [] + + @workflow.run + async def run(self) -> None: + workflow.logger.info( + "Pinned Workflow v1 started.", extra={"StartTime": workflow.now()} + ) + + while True: + await workflow.wait_condition(lambda: len(self.signals) > 0) + signal = self.signals.pop(0) + if signal == "conclude": + break + + await workflow.execute_activity( + some_activity, + "Pinned-v1", + start_to_close_timeout=timedelta(seconds=10), + ) + + @workflow.signal + async def do_next_signal(self, signal: str) -> None: + """Signal to perform next action.""" + self.signals.append(signal) + + +@workflow.defn(name="Pinned", versioning_behavior=common.VersioningBehavior.PINNED) +class PinnedWorkflowV2: + """PinnedWorkflowV2 has changes that would make it incompatible with v1, and aren't protected by + a patch. + """ + + def __init__(self) -> None: + self.signals: list[str] = [] + + @workflow.run + async def run(self) -> None: + workflow.logger.info( + "Pinned Workflow v2 started.", extra={"StartTime": workflow.now()} + ) + + # Here we call an activity where we didn't before, which is an incompatible change. + await workflow.execute_activity( + some_activity, + "Pinned-v2", + start_to_close_timeout=timedelta(seconds=10), + ) + + while True: + await workflow.wait_condition(lambda: len(self.signals) > 0) + signal = self.signals.pop(0) + if signal == "conclude": + break + + # We've also changed the activity type here, another incompatible change + await workflow.execute_activity( + some_incompatible_activity, + IncompatibleActivityInput(called_by="Pinned-v2", more_data="hi"), + start_to_close_timeout=timedelta(seconds=10), + ) + + @workflow.signal + async def do_next_signal(self, signal: str) -> None: + """Signal to perform next action.""" + self.signals.append(signal) From 326204aed1238c55a66958ddf138b79a0ff1e32e Mon Sep 17 00:00:00 2001 From: tconley1428 Date: Tue, 23 Sep 2025 16:30:30 -0700 Subject: [PATCH 20/40] Update SDK version to 1.18 (#247) * Update SDK version to 1.18 * Update openai breaking change --- .../activities/reasoning_activities.py | 1 + pyproject.toml | 4 +- uv.lock | 309 +++++++++--------- 3 files changed, 158 insertions(+), 156 deletions(-) diff --git a/openai_agents/reasoning_content/activities/reasoning_activities.py b/openai_agents/reasoning_content/activities/reasoning_activities.py index b111a742..1f7ef9ef 100644 --- a/openai_agents/reasoning_content/activities/reasoning_activities.py +++ b/openai_agents/reasoning_content/activities/reasoning_activities.py @@ -31,6 +31,7 @@ async def get_reasoning_response( tracing=ModelTracing.DISABLED, previous_response_id=None, prompt=None, + conversation_id=None, ) # Extract reasoning content and regular content from the response diff --git a/pyproject.toml b/pyproject.toml index fa5a0300..3a73a8d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.15.0,<2"] +dependencies = ["temporalio>=1.18.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" @@ -56,7 +56,7 @@ open-telemetry = [ ] openai-agents = [ "openai-agents[litellm] >= 0.2.3", - "temporalio[openai-agents] >= 1.15.0", + "temporalio[openai-agents] >= 1.18.0", ] pydantic-converter = ["pydantic>=2.10.6,<3"] sentry = ["sentry-sdk>=2.13.0"] diff --git a/uv.lock b/uv.lock index 9b1309d1..374d5c99 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "black" version = "22.12.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -196,7 +196,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -210,7 +210,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -219,7 +219,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pycparser" }, ] @@ -276,7 +276,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -337,7 +337,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -349,7 +349,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -358,7 +358,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi" }, ] @@ -381,7 +381,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -390,7 +390,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -403,7 +403,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -412,7 +412,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -424,7 +424,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -438,7 +438,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -447,7 +447,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -541,7 +541,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -550,7 +550,7 @@ wheels = [ [[package]] name = "gevent" version = "25.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -598,7 +598,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -610,7 +610,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -661,7 +661,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama" }, ] @@ -673,7 +673,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.73.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/79/e8/b43b851537da2e2f03fa8be1aef207e5cbfb1a2e014fbb6b40d24c177cd3/grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87", size = 12730355, upload-time = "2025-06-26T01:53:24.622Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/51/a5748ab2773d893d099b92653039672f7e26dd35741020972b84d604066f/grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55", size = 5365087, upload-time = "2025-06-26T01:51:44.541Z" }, @@ -721,7 +721,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -730,7 +730,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -745,7 +745,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -758,7 +758,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -794,7 +794,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -809,7 +809,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -818,7 +818,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -837,7 +837,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -846,7 +846,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "zipp" }, ] @@ -858,7 +858,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -867,7 +867,7 @@ wheels = [ [[package]] name = "isort" version = "5.13.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markupsafe" }, ] @@ -888,7 +888,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -960,7 +960,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpointer" }, ] @@ -981,7 +981,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -990,7 +990,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "referencing" }, ] @@ -1017,7 +1017,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1041,7 +1041,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1061,7 +1061,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1078,7 +1078,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, ] @@ -1105,7 +1105,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1121,7 +1121,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mdurl" }, ] @@ -1155,7 +1155,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "packaging" }, ] @@ -1225,7 +1225,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1247,7 +1247,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1256,7 +1256,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1358,7 +1358,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1397,7 +1397,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -1418,7 +1418,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1427,7 +1427,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1458,8 +1458,8 @@ wheels = [ [[package]] name = "openai" -version = "1.97.1" -source = { registry = "https://pypi.org/simple" } +version = "1.108.1" +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1470,15 +1470,15 @@ dependencies = [ { name = "tqdm" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a6/57/1c471f6b3efb879d26686d31582997615e969f3bb4458111c9705e56332e/openai-1.97.1.tar.gz", hash = "sha256:a744b27ae624e3d4135225da9b1c89c107a2a7e5bc4c93e5b7b5214772ce7a4e", size = 494267, upload-time = "2025-07-22T13:10:12.607Z" } +sdist = { url = "https://files.pythonhosted.org/packages/25/7a/3f2fbdf82a22d48405c1872f7c3176a705eee80ff2d2715d29472089171f/openai-1.108.1.tar.gz", hash = "sha256:6648468c1aec4eacfa554001e933a9fa075f57bacfc27588c2e34456cee9fef9", size = 563735, upload-time = "2025-09-19T16:52:20.399Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ee/35/412a0e9c3f0d37c94ed764b8ac7adae2d834dbd20e69f6aca582118e0f55/openai-1.97.1-py3-none-any.whl", hash = "sha256:4e96bbdf672ec3d44968c9ea39d2c375891db1acc1794668d8149d5fa6000606", size = 764380, upload-time = "2025-07-22T13:10:10.689Z" }, + { url = "https://files.pythonhosted.org/packages/38/87/6ad18ce0e7b910e3706480451df48ff9e0af3b55e5db565adafd68a0706a/openai-1.108.1-py3-none-any.whl", hash = "sha256:952fc027e300b2ac23be92b064eac136a2bc58274cec16f5d2906c361340d59b", size = 948394, upload-time = "2025-09-19T16:52:18.369Z" }, ] [[package]] name = "openai-agents" -version = "0.2.3" -source = { registry = "https://pypi.org/simple" } +version = "0.3.1" +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1488,9 +1488,9 @@ dependencies = [ { name = "types-requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e3/17/1f9eefb99fde956e5912a00fbdd03d50ebc734cc45a80b8fe4007d3813c2/openai_agents-0.2.3.tar.gz", hash = "sha256:95d4ad194c5c0cf1a40038cb701eee8ecdaaf7698d87bb13e3c2c5cff80c4b4d", size = 1464947, upload-time = "2025-07-21T19:34:20.595Z" } +sdist = { url = "https://files.pythonhosted.org/packages/57/d9/2940db8114d8e1e3b8cfa1943432e73721ada20c8dc8514aaee15e858c09/openai_agents-0.3.1.tar.gz", hash = "sha256:c39471f62d859c3ed20f3f69704e830f0d0e2a4e321aa1f21eb924f7a16347a8", size = 1722367, upload-time = "2025-09-18T17:21:12.84Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/a7/d6bdf69a54c15d237a2be979981f33dab8f5da53f9bc2e734fb2b58592ca/openai_agents-0.2.3-py3-none-any.whl", hash = "sha256:15c5602de7076a5df6d11f07a18ffe0cf4f6811f6135b301acdd1998398a6d5c", size = 161393, upload-time = "2025-07-21T19:34:18.883Z" }, + { url = "https://files.pythonhosted.org/packages/41/34/08564f0285a3d8f425588cb9141b1cd14be2e56e39630f5593de3f4f6558/openai_agents-0.3.1-py3-none-any.whl", hash = "sha256:10a2d68c4d993b395cc5048979748fb9747179c14741a3d07a009efb5e5566e6", size = 193894, upload-time = "2025-09-18T17:21:11.144Z" }, ] [package.optional-dependencies] @@ -1501,7 +1501,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1526,7 +1526,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -1556,7 +1556,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1570,7 +1570,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1583,7 +1583,7 @@ wheels = [ [[package]] name = "orjson" version = "3.10.18" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810, upload-time = "2025-04-29T23:30:08.423Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927, upload-time = "2025-04-29T23:28:08.643Z" }, @@ -1649,7 +1649,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, ] @@ -1661,7 +1661,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1670,7 +1670,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1718,7 +1718,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1727,7 +1727,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1736,7 +1736,7 @@ wheels = [ [[package]] name = "platformdirs" version = "4.3.8" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1745,7 +1745,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1754,7 +1754,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1768,7 +1768,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1857,7 +1857,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1871,7 +1871,7 @@ wheels = [ [[package]] name = "pyarrow" version = "20.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/23/77094eb8ee0dbe88441689cb6afc40ac312a1e15d3a7acc0586999518222/pyarrow-20.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c7dd06fd7d7b410ca5dc839cc9d485d2bc4ae5240851bcd45d85105cc90a47d7", size = 30832591, upload-time = "2025-04-27T12:27:27.89Z" }, @@ -1924,7 +1924,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1933,7 +1933,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1948,7 +1948,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2035,7 +2035,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2049,7 +2049,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2058,7 +2058,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2071,7 +2071,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2088,7 +2088,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, ] @@ -2101,7 +2101,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2114,7 +2114,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "six" }, ] @@ -2126,7 +2126,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2135,7 +2135,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2144,7 +2144,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2153,7 +2153,7 @@ wheels = [ [[package]] name = "pywin32" version = "310" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, @@ -2172,7 +2172,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2216,7 +2216,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2230,7 +2230,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2299,7 +2299,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2314,7 +2314,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "requests" }, ] @@ -2326,7 +2326,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2340,7 +2340,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2466,7 +2466,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, ] @@ -2478,7 +2478,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2500,7 +2500,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2509,7 +2509,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2518,7 +2518,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2527,7 +2527,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2572,7 +2572,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2596,8 +2596,8 @@ wheels = [ [[package]] name = "temporalio" -version = "1.15.0" -source = { registry = "https://pypi.org/simple" } +version = "1.18.0" +source = { registry = "https://test.pypi.org/simple/" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2605,17 +2605,18 @@ dependencies = [ { 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" } +sdist = { url = "https://test-files.pythonhosted.org/packages/7e/20/b52c96b37bf00ead6e8a4a197075770ebad516db765cc3abca8396de0689/temporalio-1.18.0.tar.gz", hash = "sha256:7ff7f833eb1e7697084b4ed9d86c3167cbff1ec77f1b40df774313a5d0fd5f6d", size = 1781572, upload-time = "2025-09-19T23:33:44.168Z" } 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" }, + { url = "https://test-files.pythonhosted.org/packages/2f/28/c5a4ee259748450ac0765837f8c78cbfa36800264158d98bd2cde4496d87/temporalio-1.18.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ac5d30d8b010c9b042065ea1259da7638db1a0a25e81ee4be0671a393ed329c5", size = 12734753, upload-time = "2025-09-19T23:32:54.477Z" }, + { url = "https://test-files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:19315d192247230c9bd7c60a566c2b3a80ad4d9de891c6aa13df63d72d3ec169", size = 12323141, upload-time = "2025-09-19T23:33:06.214Z" }, + { url = "https://test-files.pythonhosted.org/packages/6d/76/82415b43c68e2c6bb3a85e8800555d206767815088c8cad0ade9a06bd7ac/temporalio-1.18.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a023b25033e48b2e43f623a78737047a45b8cb553f69f457d09272fce5c723da", size = 12694061, upload-time = "2025-09-19T23:33:18.12Z" }, + { url = "https://test-files.pythonhosted.org/packages/41/60/176a3224c2739fee270052dd9224ae36370c4e13d2ab1bb96a2f9bbb513c/temporalio-1.18.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:695211dddbcffc20077d5b3b9a9b41bd09f60393c4ff211bcc7d6d895d607cc1", size = 12879404, upload-time = "2025-09-19T23:33:29.329Z" }, + { url = "https://test-files.pythonhosted.org/packages/e3/8d/e3809b356262d1d398d8cbb78df1e19d460c0a89e6ab64ca8d9c05d5fe5a/temporalio-1.18.0-cp39-abi3-win_amd64.whl", hash = "sha256:e3f691bd0a01a22c0fe40e87b6236cc8a292628e3a5a490880d1bf94709249c9", size = 13088041, upload-time = "2025-09-19T23:33:40.025Z" }, ] [package.optional-dependencies] openai-agents = [ + { name = "mcp" }, { name = "openai-agents" }, ] opentelemetry = [ @@ -2697,7 +2698,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.15.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.18.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2745,7 +2746,7 @@ open-telemetry = [ ] openai-agents = [ { name = "openai-agents", extras = ["litellm"], specifier = ">=0.2.3" }, - { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.15.0" }, + { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.18.0" }, ] pydantic-converter = [{ name = "pydantic", specifier = ">=2.10.6,<3" }] sentry = [{ name = "sentry-sdk", specifier = ">=2.13.0" }] @@ -2757,7 +2758,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2766,7 +2767,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2802,7 +2803,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2827,7 +2828,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2866,7 +2867,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2878,7 +2879,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2896,7 +2897,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2912,7 +2913,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -2921,7 +2922,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -2930,7 +2931,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "urllib3" }, ] @@ -2942,7 +2943,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2951,7 +2952,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -2964,7 +2965,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2976,7 +2977,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2985,7 +2986,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -2994,7 +2995,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3019,7 +3020,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3051,7 +3052,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -3151,7 +3152,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3210,7 +3211,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3309,7 +3310,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3318,7 +3319,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] @@ -3330,7 +3331,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] From e4f24427a96e8a22fefba0b9faee560dab1dd1ca Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Tue, 30 Sep 2025 14:21:27 +0100 Subject: [PATCH 21/40] nexus sync operations (query & update) (#252) --- hello_nexus/README.md | 2 +- hello_nexus/service.py | 3 +- message_passing/introduction/starter.py | 13 +- message_passing/introduction/workflows.py | 27 ++-- nexus_sync_operations/README.md | 39 ++++++ nexus_sync_operations/__init__.py | 0 nexus_sync_operations/caller/__init__.py | 0 nexus_sync_operations/caller/app.py | 41 ++++++ nexus_sync_operations/caller/workflows.py | 46 +++++++ nexus_sync_operations/endpoint_description.md | 4 + nexus_sync_operations/handler/__init__.py | 0 .../handler/service_handler.py | 83 ++++++++++++ nexus_sync_operations/handler/worker.py | 50 ++++++++ nexus_sync_operations/service.py | 20 +++ .../introduction/test_introduction_sample.py | 8 +- .../nexus_sync_operations_test.py | 118 ++++++++++++++++++ 16 files changed, 432 insertions(+), 22 deletions(-) create mode 100644 nexus_sync_operations/README.md create mode 100644 nexus_sync_operations/__init__.py create mode 100644 nexus_sync_operations/caller/__init__.py create mode 100644 nexus_sync_operations/caller/app.py create mode 100644 nexus_sync_operations/caller/workflows.py create mode 100644 nexus_sync_operations/endpoint_description.md create mode 100644 nexus_sync_operations/handler/__init__.py create mode 100644 nexus_sync_operations/handler/service_handler.py create mode 100644 nexus_sync_operations/handler/worker.py create mode 100644 nexus_sync_operations/service.py create mode 100644 tests/nexus_sync_operations/nexus_sync_operations_test.py diff --git a/hello_nexus/README.md b/hello_nexus/README.md index bf26ce47..e8067ec3 100644 --- a/hello_nexus/README.md +++ b/hello_nexus/README.md @@ -12,7 +12,7 @@ call the operations from a workflow. Start a Temporal server. (See the main samples repo [README](../README.md)). -Run the following: +Run the following to create the caller and handler namespaces, and the Nexus endpoint: ``` temporal operator namespace create --namespace hello-nexus-basic-handler-namespace diff --git a/hello_nexus/service.py b/hello_nexus/service.py index 6528775d..352375ca 100644 --- a/hello_nexus/service.py +++ b/hello_nexus/service.py @@ -9,7 +9,8 @@ type-safe clients, and it is used by Nexus handlers to validate that they implement correctly-named operation handlers with the correct input and output types. -The service defined in this file features two operations: echo and hello. +The service defined in this file exposes two operations: my_sync_operation and +my_workflow_run_operation. """ from dataclasses import dataclass diff --git a/message_passing/introduction/starter.py b/message_passing/introduction/starter.py index 13a48c3a..b71dd44d 100644 --- a/message_passing/introduction/starter.py +++ b/message_passing/introduction/starter.py @@ -9,6 +9,7 @@ GetLanguagesInput, GreetingWorkflow, Language, + SetLanguageInput, ) @@ -28,20 +29,20 @@ async def main(client: Optional[Client] = None): # πŸ‘‰ Execute an Update previous_language = await wf_handle.execute_update( - GreetingWorkflow.set_language, Language.CHINESE + GreetingWorkflow.set_language, SetLanguageInput(language=Language.CHINESE) ) - current_language = await wf_handle.query(GreetingWorkflow.get_language) - print(f"language changed: {previous_language.name} -> {current_language.name}") + assert await wf_handle.query(GreetingWorkflow.get_language) == Language.CHINESE + print(f"language changed: {previous_language.name} -> {Language.CHINESE.name}") # πŸ‘‰ Start an Update and then wait for it to complete update_handle = await wf_handle.start_update( GreetingWorkflow.set_language_using_activity, - Language.ARABIC, + SetLanguageInput(language=Language.ARABIC), wait_for_stage=WorkflowUpdateStage.ACCEPTED, ) previous_language = await update_handle.result() - current_language = await wf_handle.query(GreetingWorkflow.get_language) - print(f"language changed: {previous_language.name} -> {current_language.name}") + assert await wf_handle.query(GreetingWorkflow.get_language) == Language.ARABIC + print(f"language changed: {previous_language.name} -> {Language.ARABIC.name}") # πŸ‘‰ Send a Signal await wf_handle.signal(GreetingWorkflow.approve, ApproveInput(name="")) diff --git a/message_passing/introduction/workflows.py b/message_passing/introduction/workflows.py index 97d2b874..8988d581 100644 --- a/message_passing/introduction/workflows.py +++ b/message_passing/introduction/workflows.py @@ -16,6 +16,11 @@ class GetLanguagesInput: include_unsupported: bool +@dataclass +class SetLanguageInput: + language: Language + + @dataclass class ApproveInput: name: str @@ -74,21 +79,21 @@ def approve(self, input: ApproveInput) -> None: self.approver_name = input.name @workflow.update - def set_language(self, language: Language) -> Language: + def set_language(self, input: SetLanguageInput) -> Language: # πŸ‘‰ An Update handler can mutate the Workflow state and return a value. - previous_language, self.language = self.language, language + previous_language, self.language = self.language, input.language return previous_language @set_language.validator - def validate_language(self, language: Language) -> None: - if language not in self.greetings: + def validate_language(self, input: SetLanguageInput) -> None: + if input.language not in self.greetings: # πŸ‘‰ In an Update validator you raise any exception to reject the Update. - raise ValueError(f"{language.name} is not supported") + raise ValueError(f"{input.language.name} is not supported") @workflow.update - async def set_language_using_activity(self, language: Language) -> Language: + async def set_language_using_activity(self, input: SetLanguageInput) -> Language: # πŸ‘‰ This update handler is async, so it can execute an activity. - if language not in self.greetings: + if input.language not in self.greetings: # πŸ‘‰ We use a lock so that, if this handler is executed multiple # times, each execution can schedule the activity only when the # previously scheduled activity has completed. This ensures that @@ -96,7 +101,7 @@ async def set_language_using_activity(self, language: Language) -> Language: async with self.lock: greeting = await workflow.execute_activity( call_greeting_service, - language, + input.language, start_to_close_timeout=timedelta(seconds=10), ) # πŸ‘‰ The requested language might not be supported by the remote @@ -108,10 +113,10 @@ async def set_language_using_activity(self, language: Language) -> Language: # this purpose.) if greeting is None: raise ApplicationError( - f"Greeting service does not support {language.name}" + f"Greeting service does not support {input.language.name}" ) - self.greetings[language] = greeting - previous_language, self.language = self.language, language + self.greetings[input.language] = greeting + previous_language, self.language = self.language, input.language return previous_language @workflow.query diff --git a/nexus_sync_operations/README.md b/nexus_sync_operations/README.md new file mode 100644 index 00000000..10e266ec --- /dev/null +++ b/nexus_sync_operations/README.md @@ -0,0 +1,39 @@ +This sample shows how to create a Nexus service that is backed by a long-running workflow and +exposes operations that execute updates and queries against that workflow. The long-running +workflow, and the updates/queries are private implementation detail of the nexus service: the caller +does not know how the operations are implemented. + +### Sample directory structure + +- [service.py](./service.py) - shared Nexus service definition +- [caller](./caller) - a caller workflow that executes Nexus operations, together with a worker and starter code +- [handler](./handler) - Nexus operation handlers, together with a workflow used by one of the Nexus operations, and a worker that polls for both workflow, activity, and Nexus tasks. + + +### Instructions + +Start a Temporal server. (See the main samples repo [README](../README.md)). + +Run the following to create the caller and handler namespaces, and the Nexus endpoint: + +``` +temporal operator namespace create --namespace nexus-sync-operations-handler-namespace +temporal operator namespace create --namespace nexus-sync-operations-caller-namespace + +temporal operator nexus endpoint create \ + --name nexus-sync-operations-nexus-endpoint \ + --target-namespace nexus-sync-operations-handler-namespace \ + --target-task-queue nexus-sync-operations-handler-task-queue \ + --description-file nexus_sync_operations/endpoint_description.md +``` + +In one terminal, run the Temporal worker in the handler namespace: +``` +uv run nexus_sync_operations/handler/worker.py +``` + +In another terminal, run the Temporal worker in the caller namespace and start the caller +workflow: +``` +uv run nexus_sync_operations/caller/app.py +``` diff --git a/nexus_sync_operations/__init__.py b/nexus_sync_operations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_sync_operations/caller/__init__.py b/nexus_sync_operations/caller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_sync_operations/caller/app.py b/nexus_sync_operations/caller/app.py new file mode 100644 index 00000000..4966415c --- /dev/null +++ b/nexus_sync_operations/caller/app.py @@ -0,0 +1,41 @@ +import asyncio +import uuid +from typing import Optional + +from temporalio.client import Client +from temporalio.worker import Worker + +from nexus_sync_operations.caller.workflows import CallerWorkflow + +NAMESPACE = "nexus-sync-operations-caller-namespace" +TASK_QUEUE = "nexus-sync-operations-caller-task-queue" + + +async def execute_caller_workflow( + client: Optional[Client] = None, +) -> None: + client = client or await Client.connect( + "localhost:7233", + namespace=NAMESPACE, + ) + + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[CallerWorkflow], + ): + log = await client.execute_workflow( + CallerWorkflow.run, + id=str(uuid.uuid4()), + task_queue=TASK_QUEUE, + ) + for line in log: + print(line) + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(execute_caller_workflow()) + except KeyboardInterrupt: + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_sync_operations/caller/workflows.py b/nexus_sync_operations/caller/workflows.py new file mode 100644 index 00000000..a358d764 --- /dev/null +++ b/nexus_sync_operations/caller/workflows.py @@ -0,0 +1,46 @@ +""" +This is a workflow that calls nexus operations. The caller does not have information about how these +operations are implemented by the nexus service. +""" + +from temporalio import workflow + +from message_passing.introduction import Language +from message_passing.introduction.workflows import GetLanguagesInput, SetLanguageInput + +with workflow.unsafe.imports_passed_through(): + from nexus_sync_operations.service import GreetingService + +NEXUS_ENDPOINT = "nexus-sync-operations-nexus-endpoint" + + +@workflow.defn +class CallerWorkflow: + @workflow.run + async def run(self) -> list[str]: + log = [] + nexus_client = workflow.create_nexus_client( + service=GreetingService, + endpoint=NEXUS_ENDPOINT, + ) + + # Get supported languages + supported_languages = await nexus_client.execute_operation( + GreetingService.get_languages, GetLanguagesInput(include_unsupported=False) + ) + log.append(f"supported languages: {supported_languages}") + + # Set language + previous_language = await nexus_client.execute_operation( + GreetingService.set_language, + SetLanguageInput(language=Language.ARABIC), + ) + assert ( + await nexus_client.execute_operation(GreetingService.get_language, None) + == Language.ARABIC + ) + log.append( + f"language changed: {previous_language.name} -> {Language.ARABIC.name}" + ) + + return log diff --git a/nexus_sync_operations/endpoint_description.md b/nexus_sync_operations/endpoint_description.md new file mode 100644 index 00000000..a33b60cf --- /dev/null +++ b/nexus_sync_operations/endpoint_description.md @@ -0,0 +1,4 @@ +## Service: [GreetingService](https://github.com/temporalio/samples-python/blob/main/nexus_sync_operations/service.py) +- operation: `get_languages` +- operation: `get_language` +- operation: `set_language` diff --git a/nexus_sync_operations/handler/__init__.py b/nexus_sync_operations/handler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_sync_operations/handler/service_handler.py b/nexus_sync_operations/handler/service_handler.py new file mode 100644 index 00000000..626948f0 --- /dev/null +++ b/nexus_sync_operations/handler/service_handler.py @@ -0,0 +1,83 @@ +""" +This file demonstrates how to implement a Nexus service that is backed by a long-running workflow +and exposes operations that perform updates and queries against that workflow. +""" + +from __future__ import annotations + +import nexusrpc +from temporalio import nexus +from temporalio.client import Client, WorkflowHandle +from temporalio.common import WorkflowIDConflictPolicy + +from message_passing.introduction import Language +from message_passing.introduction.workflows import ( + GetLanguagesInput, + GreetingWorkflow, + SetLanguageInput, +) +from nexus_sync_operations.service import GreetingService + + +@nexusrpc.handler.service_handler(service=GreetingService) +class GreetingServiceHandler: + def __init__(self, workflow_id: str): + self.workflow_id = workflow_id + + @classmethod + async def create( + cls, workflow_id: str, client: Client, task_queue: str + ) -> GreetingServiceHandler: + # Start the long-running "entity" workflow, if it is not already running. + await client.start_workflow( + GreetingWorkflow.run, + id=workflow_id, + task_queue=task_queue, + id_conflict_policy=WorkflowIDConflictPolicy.USE_EXISTING, + ) + return cls(workflow_id) + + @property + def greeting_workflow_handle(self) -> WorkflowHandle[GreetingWorkflow, str]: + # In nexus operation handler code, nexus.client() is always available, returning a client + # connected to the handler namespace (it's the same client instance that your nexus worker + # is using to poll the server for nexus tasks). This client can be used to interact with the + # handler namespace, for example to send signals, queries, or updates. Remember however, + # that a sync_operation handler must return quickly (no more than a few seconds). To do + # long-running work in a nexus operation handler, use + # temporalio.nexus.workflow_run_operation (see the hello_nexus sample). + return nexus.client().get_workflow_handle_for( + GreetingWorkflow.run, self.workflow_id + ) + + # πŸ‘‰ This is a handler for a nexus operation whose internal implementation involves executing a + # query against a long-running workflow that is private to the nexus service. + @nexusrpc.handler.sync_operation + async def get_languages( + self, ctx: nexusrpc.handler.StartOperationContext, input: GetLanguagesInput + ) -> list[Language]: + return await self.greeting_workflow_handle.query( + GreetingWorkflow.get_languages, input + ) + + # πŸ‘‰ This is a handler for a nexus operation whose internal implementation involves executing a + # query against a long-running workflow that is private to the nexus service. + @nexusrpc.handler.sync_operation + async def get_language( + self, ctx: nexusrpc.handler.StartOperationContext, input: None + ) -> Language: + return await self.greeting_workflow_handle.query(GreetingWorkflow.get_language) + + # πŸ‘‰ This is a handler for a nexus operation whose internal implementation involves executing an + # update against a long-running workflow that is private to the nexus service. Although updates + # can run for an arbitrarily long time, when exposing an update via a nexus sync operation the + # update should execute quickly (sync operations must complete in under 10s). + @nexusrpc.handler.sync_operation + async def set_language( + self, + ctx: nexusrpc.handler.StartOperationContext, + input: SetLanguageInput, + ) -> Language: + return await self.greeting_workflow_handle.execute_update( + GreetingWorkflow.set_language_using_activity, input + ) diff --git a/nexus_sync_operations/handler/worker.py b/nexus_sync_operations/handler/worker.py new file mode 100644 index 00000000..5545adc0 --- /dev/null +++ b/nexus_sync_operations/handler/worker.py @@ -0,0 +1,50 @@ +import asyncio +import logging +from typing import Optional + +from temporalio.client import Client +from temporalio.worker import Worker + +from message_passing.introduction.activities import call_greeting_service +from message_passing.introduction.workflows import GreetingWorkflow +from nexus_sync_operations.handler.service_handler import GreetingServiceHandler + +interrupt_event = asyncio.Event() + +NAMESPACE = "nexus-sync-operations-handler-namespace" +TASK_QUEUE = "nexus-sync-operations-handler-task-queue" + + +async def main(client: Optional[Client] = None): + logging.basicConfig(level=logging.INFO) + + client = client or await Client.connect( + "localhost:7233", + namespace=NAMESPACE, + ) + + # Create the nexus service handler instance, starting the long-running entity workflow that + # backs the Nexus service + greeting_service_handler = await GreetingServiceHandler.create( + "nexus-sync-operations-greeting-workflow", client, TASK_QUEUE + ) + + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[GreetingWorkflow], + activities=[call_greeting_service], + nexus_service_handlers=[greeting_service_handler], + ): + logging.info("Worker started, ctrl+c to exit") + await interrupt_event.wait() + logging.info("Shutting down") + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + interrupt_event.set() + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_sync_operations/service.py b/nexus_sync_operations/service.py new file mode 100644 index 00000000..3436d5f3 --- /dev/null +++ b/nexus_sync_operations/service.py @@ -0,0 +1,20 @@ +""" +This module defines a Nexus service that exposes three operations. + +It is used by the nexus service handler to validate that the operation handlers implement the +correct input and output types, and by the caller workflow to create a type-safe client. It does not +contain the implementation of the operations; see nexus_sync_operations.handler.service_handler for +that. +""" + +import nexusrpc + +from message_passing.introduction import Language +from message_passing.introduction.workflows import GetLanguagesInput, SetLanguageInput + + +@nexusrpc.service +class GreetingService: + get_languages: nexusrpc.Operation[GetLanguagesInput, list[Language]] + get_language: nexusrpc.Operation[None, Language] + set_language: nexusrpc.Operation[SetLanguageInput, Language] diff --git a/tests/message_passing/introduction/test_introduction_sample.py b/tests/message_passing/introduction/test_introduction_sample.py index de981dc2..17c1b14d 100644 --- a/tests/message_passing/introduction/test_introduction_sample.py +++ b/tests/message_passing/introduction/test_introduction_sample.py @@ -10,6 +10,7 @@ GetLanguagesInput, GreetingWorkflow, Language, + SetLanguageInput, call_greeting_service, ) @@ -63,7 +64,7 @@ async def test_set_language(client: Client, env: WorkflowEnvironment): ) assert await wf_handle.query(GreetingWorkflow.get_language) == Language.ENGLISH previous_language = await wf_handle.execute_update( - GreetingWorkflow.set_language, Language.CHINESE + GreetingWorkflow.set_language, SetLanguageInput(language=Language.CHINESE) ) assert previous_language == Language.ENGLISH assert await wf_handle.query(GreetingWorkflow.get_language) == Language.CHINESE @@ -88,7 +89,8 @@ async def test_set_invalid_language(client: Client, env: WorkflowEnvironment): with pytest.raises(WorkflowUpdateFailedError): await wf_handle.execute_update( - GreetingWorkflow.set_language, Language.ARABIC + GreetingWorkflow.set_language, + SetLanguageInput(language=Language.ARABIC), ) @@ -117,7 +119,7 @@ async def test_set_language_that_is_only_available_via_remote_service( assert await wf_handle.query(GreetingWorkflow.get_language) == Language.ENGLISH previous_language = await wf_handle.execute_update( GreetingWorkflow.set_language_using_activity, - Language.ARABIC, + SetLanguageInput(language=Language.ARABIC), ) assert previous_language == Language.ENGLISH assert await wf_handle.query(GreetingWorkflow.get_language) == Language.ARABIC diff --git a/tests/nexus_sync_operations/nexus_sync_operations_test.py b/tests/nexus_sync_operations/nexus_sync_operations_test.py new file mode 100644 index 00000000..d74168cb --- /dev/null +++ b/tests/nexus_sync_operations/nexus_sync_operations_test.py @@ -0,0 +1,118 @@ +import asyncio +import uuid +from typing import Type + +import pytest +from temporalio import workflow +from temporalio.client import Client +from temporalio.testing import WorkflowEnvironment +from temporalio.worker import Worker + +import nexus_sync_operations.handler.service_handler +import nexus_sync_operations.handler.worker +from message_passing.introduction import Language +from message_passing.introduction.workflows import GetLanguagesInput, SetLanguageInput +from nexus_sync_operations.caller.workflows import CallerWorkflow +from tests.helpers.nexus import create_nexus_endpoint, delete_nexus_endpoint + +with workflow.unsafe.imports_passed_through(): + from nexus_sync_operations.service import GreetingService + + +NEXUS_ENDPOINT = "nexus-sync-operations-nexus-endpoint" + + +@workflow.defn +class TestCallerWorkflow: + """Test workflow that calls Nexus operations and makes assertions.""" + + @workflow.run + async def run(self) -> None: + nexus_client = workflow.create_nexus_client( + service=GreetingService, + endpoint=NEXUS_ENDPOINT, + ) + + supported_languages = await nexus_client.execute_operation( + GreetingService.get_languages, GetLanguagesInput(include_unsupported=False) + ) + assert supported_languages == [Language.CHINESE, Language.ENGLISH] + + initial_language = await nexus_client.execute_operation( + GreetingService.get_language, None + ) + assert initial_language == Language.ENGLISH + + previous_language = await nexus_client.execute_operation( + GreetingService.set_language, + SetLanguageInput(language=Language.CHINESE), + ) + assert previous_language == Language.ENGLISH + + current_language = await nexus_client.execute_operation( + GreetingService.get_language, None + ) + assert current_language == Language.CHINESE + + previous_language = await nexus_client.execute_operation( + GreetingService.set_language, + SetLanguageInput(language=Language.ARABIC), + ) + assert previous_language == Language.CHINESE + + current_language = await nexus_client.execute_operation( + GreetingService.get_language, None + ) + assert current_language == Language.ARABIC + + +async def test_nexus_sync_operations(client: Client, env: WorkflowEnvironment): + if env.supports_time_skipping: + pytest.skip("Nexus tests don't work under the Java test server") + + await _run_caller_workflow(client, TestCallerWorkflow) + + +async def test_nexus_sync_operations_caller_workflow( + client: Client, env: WorkflowEnvironment +): + """ + Runs the CallerWorkflow from the sample to ensure it executes without errors. + """ + if env.supports_time_skipping: + pytest.skip("Nexus tests don't work under the Java test server") + + await _run_caller_workflow(client, CallerWorkflow) + + +async def _run_caller_workflow(client: Client, workflow: Type): + create_response = await create_nexus_endpoint( + name=NEXUS_ENDPOINT, + task_queue=nexus_sync_operations.handler.worker.TASK_QUEUE, + client=client, + ) + try: + handler_worker_task = asyncio.create_task( + nexus_sync_operations.handler.worker.main(client) + ) + try: + async with Worker( + client, + task_queue="test-caller-task-queue", + workflows=[workflow], + ): + await client.execute_workflow( + workflow.run, + id=str(uuid.uuid4()), + task_queue="test-caller-task-queue", + ) + finally: + nexus_sync_operations.handler.worker.interrupt_event.set() + await handler_worker_task + nexus_sync_operations.handler.worker.interrupt_event.clear() + finally: + await delete_nexus_endpoint( + id=create_response.endpoint.id, + version=create_response.endpoint.version, + client=client, + ) From 7b437d5c70f574df233013f5b00ab29f7e952fca Mon Sep 17 00:00:00 2001 From: Johann Schleier-Smith Date: Tue, 30 Sep 2025 10:28:56 -0700 Subject: [PATCH 22/40] OpenAI Agents SDK - MCP Samples (#250) * file system mcp server example * typo * stateful and stateless demos * wip * update to provider * provider * title * add more examples * Update SDK version to 1.18 * Update openai breaking change * cleanup + formatting * cleanup * WIP sequential thinking * memory stateful mcp * cleanup * interface updates * minimize dependency version changes * naming consistency * openai agents upgrade --------- Co-authored-by: Tim Conley --- openai_agents/README.md | 2 +- openai_agents/mcp/README.md | 91 ++++++ openai_agents/mcp/run_file_system_worker.py | 62 ++++ openai_agents/mcp/run_file_system_workflow.py | 29 ++ .../run_memory_research_scratchpad_worker.py | 59 ++++ ...run_memory_research_scratchpad_workflow.py | 29 ++ openai_agents/mcp/run_prompt_server_worker.py | 64 ++++ .../mcp/run_prompt_server_workflow.py | 29 ++ openai_agents/mcp/run_sse_worker.py | 64 ++++ openai_agents/mcp/run_sse_workflow.py | 29 ++ .../mcp/run_streamable_http_worker.py | 64 ++++ .../mcp/run_streamable_http_workflow.py | 29 ++ .../mcp/sample_files/favorite_books.txt | 20 ++ .../mcp/sample_files/favorite_cities.txt | 4 + .../mcp/sample_files/favorite_songs.txt | 10 + openai_agents/mcp/servers/prompt_server.py | 58 ++++ openai_agents/mcp/servers/tools_server.py | 44 +++ .../mcp/workflows/file_system_workflow.py | 40 +++ .../memory_research_scratchpad_workflow.py | 122 +++++++ .../mcp/workflows/prompt_server_workflow.py | 79 +++++ openai_agents/mcp/workflows/sse_workflow.py | 38 +++ .../mcp/workflows/streamable_http_workflow.py | 40 +++ pyproject.toml | 5 +- uv.lock | 300 +++++++++--------- 24 files changed, 1159 insertions(+), 152 deletions(-) create mode 100644 openai_agents/mcp/README.md create mode 100644 openai_agents/mcp/run_file_system_worker.py create mode 100644 openai_agents/mcp/run_file_system_workflow.py create mode 100644 openai_agents/mcp/run_memory_research_scratchpad_worker.py create mode 100644 openai_agents/mcp/run_memory_research_scratchpad_workflow.py create mode 100644 openai_agents/mcp/run_prompt_server_worker.py create mode 100644 openai_agents/mcp/run_prompt_server_workflow.py create mode 100644 openai_agents/mcp/run_sse_worker.py create mode 100644 openai_agents/mcp/run_sse_workflow.py create mode 100644 openai_agents/mcp/run_streamable_http_worker.py create mode 100644 openai_agents/mcp/run_streamable_http_workflow.py create mode 100644 openai_agents/mcp/sample_files/favorite_books.txt create mode 100644 openai_agents/mcp/sample_files/favorite_cities.txt create mode 100644 openai_agents/mcp/sample_files/favorite_songs.txt create mode 100644 openai_agents/mcp/servers/prompt_server.py create mode 100644 openai_agents/mcp/servers/tools_server.py create mode 100644 openai_agents/mcp/workflows/file_system_workflow.py create mode 100644 openai_agents/mcp/workflows/memory_research_scratchpad_workflow.py create mode 100644 openai_agents/mcp/workflows/prompt_server_workflow.py create mode 100644 openai_agents/mcp/workflows/sse_workflow.py create mode 100644 openai_agents/mcp/workflows/streamable_http_workflow.py diff --git a/openai_agents/README.md b/openai_agents/README.md index 8a51246d..9404278f 100644 --- a/openai_agents/README.md +++ b/openai_agents/README.md @@ -30,9 +30,9 @@ Each directory contains a complete example with its own README for detailed inst - **[Tools](./tools/README.md)** - Demonstrates available tools such as file search, image generation, and others. - **[Handoffs](./handoffs/README.md)** - Agents collaborating via handoffs. - **[Hosted MCP](./hosted_mcp/README.md)** - Using the MCP client functionality of the OpenAI Responses API. +- **[MCP](./mcp/README.md)** - Local MCP servers (filesystem/stdio, streamable HTTP, SSE, prompt server) integrated with Temporal workflows. - **[Model Providers](./model_providers/README.md)** - Using custom LLM providers (e.g., Anthropic via LiteLLM). - **[Research Bot](./research_bot/README.md)** - Multi-agent research system with specialized roles: a planner agent, search agent, and writer agent working together to conduct comprehensive research. - **[Customer Service](./customer_service/README.md)** - Interactive customer service agent with escalation capabilities, demonstrating conversational workflows. - **[Reasoning Content](./reasoning_content/README.md)** - Example of how to retrieve the thought process of reasoning models. - **[Financial Research Agent](./financial_research_agent/README.md)** - Multi-agent financial research system with planner, search, analyst, writer, and verifier agents collaborating. - diff --git a/openai_agents/mcp/README.md b/openai_agents/mcp/README.md new file mode 100644 index 00000000..d9a172f3 --- /dev/null +++ b/openai_agents/mcp/README.md @@ -0,0 +1,91 @@ +# MCP Examples + +Integration with MCP (Model Context Protocol) servers using OpenAI agents in Temporal workflows. + +*Adapted from [OpenAI Agents SDK MCP examples](https://github.com/openai/openai-agents-python/tree/main/examples/mcp)* + +Before running these examples, be sure to review the [prerequisites and background on the integration](../README.md). + + +## Running the Examples + +### Stdio MCP + +First, start the worker: +```bash +uv run openai_agents/mcp/run_file_system_worker.py +``` + +Run the workflow: +```bash +uv run openai_agents/mcp/run_file_system_workflow.py +``` + +This sample assumes that the worker and `run_file_system_workflow.py` are on the same machine. + + +### Streamable HTTP MCP + +First, start the worker: +```bash +uv run openai_agents/mcp/servers/tools_server.py --transport=streamable-http +``` + +Then start the worker: +```bash +uv run openai_agents/mcp/run_streamable_http_worker.py +``` + +Finally, run the workflow: +```bash +uv run openai_agents/mcp/run_streamable_http_workflow.py +``` + +### SSE MCP + +First, start the MCP server: +```bash +uv run openai_agents/mcp/servers/tools_server.py --transport=sse +``` + +Then start the worker: +```bash +uv run openai_agents/mcp/run_sse_worker.py +``` + +Finally, run the workflow: +```bash +uv run openai_agents/mcp/run_sse_workflow.py +``` + +### Prompt Server MCP + +First, start the MCP server: +```bash +uv run openai_agents/mcp/servers/prompt_server.py +``` + +Then start the worker: +```bash +uv run openai_agents/mcp/run_prompt_server_worker.py +``` + +Finally, run the workflow: +```bash +uv run openai_agents/mcp/run_prompt_server_workflow.py +``` + + +### Memory MCP (Research Scratchpad) + +Demonstrates durable note-taking with the Memory MCP server: write seed notes, query by tags, synthesize a brief with citations, then update and delete notes. + +Start the worker: +```bash +uv run openai_agents/mcp/run_memory_research_scratchpad_worker.py +``` + +Run the research scratchpad workflow: +```bash +uv run openai_agents/mcp/run_memory_research_scratchpad_workflow.py +``` diff --git a/openai_agents/mcp/run_file_system_worker.py b/openai_agents/mcp/run_file_system_worker.py new file mode 100644 index 00000000..0eb440bb --- /dev/null +++ b/openai_agents/mcp/run_file_system_worker.py @@ -0,0 +1,62 @@ +from __future__ import annotations + +import asyncio +import logging +import os +from datetime import timedelta + +from agents.mcp import MCPServerStdio +from temporalio.client import Client +from temporalio.contrib.openai_agents import ( + ModelActivityParameters, + OpenAIAgentsPlugin, + StatelessMCPServerProvider, +) +from temporalio.worker import Worker + +from openai_agents.mcp.workflows.file_system_workflow import FileSystemWorkflow + + +async def main(): + logging.basicConfig(level=logging.INFO) + current_dir = os.path.dirname(os.path.abspath(__file__)) + samples_dir = os.path.join(current_dir, "sample_files") + + file_system_server = StatelessMCPServerProvider( + lambda: MCPServerStdio( + name="FileSystemServer", + params={ + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir], + }, + ) + ) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ), + mcp_server_providers=[file_system_server], + ), + ], + ) + + worker = Worker( + client, + task_queue=f"openai-agents-mcp-filesystem-task-queue", + workflows=[ + FileSystemWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_file_system_workflow.py b/openai_agents/mcp/run_file_system_workflow.py new file mode 100644 index 00000000..a52e7d56 --- /dev/null +++ b/openai_agents/mcp/run_file_system_workflow.py @@ -0,0 +1,29 @@ +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.mcp.workflows.file_system_workflow import FileSystemWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin(), + ], + ) + + # Execute a workflow + result = await client.execute_workflow( + FileSystemWorkflow.run, + id="file-system-workflow", + task_queue="openai-agents-mcp-filesystem-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_memory_research_scratchpad_worker.py b/openai_agents/mcp/run_memory_research_scratchpad_worker.py new file mode 100644 index 00000000..fb1d8494 --- /dev/null +++ b/openai_agents/mcp/run_memory_research_scratchpad_worker.py @@ -0,0 +1,59 @@ +from __future__ import annotations + +import asyncio +import logging +from datetime import timedelta + +from agents.mcp import MCPServerStdio +from temporalio.client import Client +from temporalio.contrib.openai_agents import ( + ModelActivityParameters, + OpenAIAgentsPlugin, + StatefulMCPServerProvider, +) +from temporalio.worker import Worker + +from openai_agents.mcp.workflows.memory_research_scratchpad_workflow import ( + MemoryResearchScratchpadWorkflow, +) + + +async def main(): + logging.basicConfig(level=logging.INFO) + + memory_server_provider = StatefulMCPServerProvider( + lambda: MCPServerStdio( + name="MemoryServer", + params={ + "command": "npx", + "args": ["-y", "@modelcontextprotocol/server-memory"], + }, + ) + ) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ), + mcp_server_providers=[memory_server_provider], + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-mcp-memory-task-queue", + workflows=[ + MemoryResearchScratchpadWorkflow, + ], + activities=[], + ) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_memory_research_scratchpad_workflow.py b/openai_agents/mcp/run_memory_research_scratchpad_workflow.py new file mode 100644 index 00000000..03969fb4 --- /dev/null +++ b/openai_agents/mcp/run_memory_research_scratchpad_workflow.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.mcp.workflows.memory_research_scratchpad_workflow import ( + MemoryResearchScratchpadWorkflow, +) + + +async def main(): + client = await Client.connect( + "localhost:7233", + plugins=[OpenAIAgentsPlugin()], + ) + + result = await client.execute_workflow( + MemoryResearchScratchpadWorkflow.run, + id="memory-research-scratchpad-workflow", + task_queue="openai-agents-mcp-memory-task-queue", + ) + + print(f"Result:\n{result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_prompt_server_worker.py b/openai_agents/mcp/run_prompt_server_worker.py new file mode 100644 index 00000000..e390c0ac --- /dev/null +++ b/openai_agents/mcp/run_prompt_server_worker.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import asyncio +import logging +from datetime import timedelta + +from agents.mcp import MCPServerStreamableHttp +from temporalio.client import Client +from temporalio.contrib.openai_agents import ( + ModelActivityParameters, + OpenAIAgentsPlugin, + StatelessMCPServerProvider, +) +from temporalio.worker import Worker + +from openai_agents.mcp.workflows.prompt_server_workflow import PromptServerWorkflow + + +async def main(): + logging.basicConfig(level=logging.INFO) + + print("Setting up worker...\n") + + try: + prompt_server_provider = StatelessMCPServerProvider( + lambda: MCPServerStreamableHttp( + name="PromptServer", + params={ + "url": "http://localhost:8000/mcp", + }, + ) + ) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=120) + ), + mcp_server_providers=[prompt_server_provider], + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-mcp-prompt-task-queue", + workflows=[ + PromptServerWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + except Exception as e: + print(f"Worker failed: {e}") + raise + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_prompt_server_workflow.py b/openai_agents/mcp/run_prompt_server_workflow.py new file mode 100644 index 00000000..79e4bf65 --- /dev/null +++ b/openai_agents/mcp/run_prompt_server_workflow.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.mcp.workflows.prompt_server_workflow import PromptServerWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[OpenAIAgentsPlugin()], + ) + + # Execute a workflow + result = await client.execute_workflow( + PromptServerWorkflow.run, + id="prompt-server-workflow", + task_queue="openai-agents-mcp-prompt-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_sse_worker.py b/openai_agents/mcp/run_sse_worker.py new file mode 100644 index 00000000..406e65bf --- /dev/null +++ b/openai_agents/mcp/run_sse_worker.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import asyncio +import logging +from datetime import timedelta + +from agents.mcp import MCPServerSse +from temporalio.client import Client +from temporalio.contrib.openai_agents import ( + ModelActivityParameters, + OpenAIAgentsPlugin, + StatelessMCPServerProvider, +) +from temporalio.worker import Worker + +from openai_agents.mcp.workflows.sse_workflow import SseWorkflow + + +async def main(): + logging.basicConfig(level=logging.INFO) + + print("Setting up worker...\n") + + try: + sse_server_provider = StatelessMCPServerProvider( + lambda: MCPServerSse( + name="SseServer", + params={ + "url": "http://localhost:8000/sse", + }, + ) + ) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ), + mcp_server_providers=[sse_server_provider], + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-mcp-sse-task-queue", + workflows=[ + SseWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + except Exception as e: + print(f"Worker failed: {e}") + raise + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_sse_workflow.py b/openai_agents/mcp/run_sse_workflow.py new file mode 100644 index 00000000..42a45596 --- /dev/null +++ b/openai_agents/mcp/run_sse_workflow.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.mcp.workflows.sse_workflow import SseWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[OpenAIAgentsPlugin()], + ) + + # Execute a workflow + result = await client.execute_workflow( + SseWorkflow.run, + id="sse-workflow", + task_queue="openai-agents-mcp-sse-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_streamable_http_worker.py b/openai_agents/mcp/run_streamable_http_worker.py new file mode 100644 index 00000000..9c178b6f --- /dev/null +++ b/openai_agents/mcp/run_streamable_http_worker.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import asyncio +import logging +from datetime import timedelta + +from agents.mcp import MCPServerStreamableHttp +from temporalio.client import Client +from temporalio.contrib.openai_agents import ( + ModelActivityParameters, + OpenAIAgentsPlugin, + StatelessMCPServerProvider, +) +from temporalio.worker import Worker + +from openai_agents.mcp.workflows.streamable_http_workflow import StreamableHttpWorkflow + + +async def main(): + logging.basicConfig(level=logging.INFO) + + print("Setting up worker...\n") + + try: + streamable_http_server_provider = StatelessMCPServerProvider( + lambda: MCPServerStreamableHttp( + name="StreamableHttpServer", + params={ + "url": "http://localhost:8000/mcp", + }, + ) + ) + + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[ + OpenAIAgentsPlugin( + model_params=ModelActivityParameters( + start_to_close_timeout=timedelta(seconds=60) + ), + mcp_server_providers=[streamable_http_server_provider], + ), + ], + ) + + worker = Worker( + client, + task_queue="openai-agents-mcp-streamable-http-task-queue", + workflows=[ + StreamableHttpWorkflow, + ], + activities=[ + # No custom activities needed for these workflows + ], + ) + await worker.run() + except Exception as e: + print(f"Worker failed: {e}") + raise + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/run_streamable_http_workflow.py b/openai_agents/mcp/run_streamable_http_workflow.py new file mode 100644 index 00000000..aa5d1bac --- /dev/null +++ b/openai_agents/mcp/run_streamable_http_workflow.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +import asyncio + +from temporalio.client import Client +from temporalio.contrib.openai_agents import OpenAIAgentsPlugin + +from openai_agents.mcp.workflows.streamable_http_workflow import StreamableHttpWorkflow + + +async def main(): + # Create client connected to server at the given address + client = await Client.connect( + "localhost:7233", + plugins=[OpenAIAgentsPlugin()], + ) + + # Execute a workflow + result = await client.execute_workflow( + StreamableHttpWorkflow.run, + id="streamable-http-workflow", + task_queue="openai-agents-mcp-streamable-http-task-queue", + ) + + print(f"Result: {result}") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/openai_agents/mcp/sample_files/favorite_books.txt b/openai_agents/mcp/sample_files/favorite_books.txt new file mode 100644 index 00000000..c55f457e --- /dev/null +++ b/openai_agents/mcp/sample_files/favorite_books.txt @@ -0,0 +1,20 @@ +1. To Kill a Mockingbird – Harper Lee +2. Pride and Prejudice – Jane Austen +3. 1984 – George Orwell +4. The Hobbit – J.R.R. Tolkien +5. Harry Potter and the Sorcerer’s Stone – J.K. Rowling +6. The Great Gatsby – F. Scott Fitzgerald +7. Charlotte’s Web – E.B. White +8. Anne of Green Gables – Lucy Maud Montgomery +9. The Alchemist – Paulo Coelho +10. Little Women – Louisa May Alcott +11. The Catcher in the Rye – J.D. Salinger +12. Animal Farm – George Orwell +13. The Chronicles of Narnia: The Lion, the Witch, and the Wardrobe – C.S. Lewis +14. The Book Thief – Markus Zusak +15. A Wrinkle in Time – Madeleine L’Engle +16. The Secret Garden – Frances Hodgson Burnett +17. Moby-Dick – Herman Melville +18. Fahrenheit 451 – Ray Bradbury +19. Jane Eyre – Charlotte BrontΓ« +20. The Little Prince – Antoine de Saint-ExupΓ©ry \ No newline at end of file diff --git a/openai_agents/mcp/sample_files/favorite_cities.txt b/openai_agents/mcp/sample_files/favorite_cities.txt new file mode 100644 index 00000000..1d3354f2 --- /dev/null +++ b/openai_agents/mcp/sample_files/favorite_cities.txt @@ -0,0 +1,4 @@ +- In the summer, I love visiting London. +- In the winter, Tokyo is great. +- In the spring, San Francisco. +- In the fall, New York is the best. \ No newline at end of file diff --git a/openai_agents/mcp/sample_files/favorite_songs.txt b/openai_agents/mcp/sample_files/favorite_songs.txt new file mode 100644 index 00000000..d659bb58 --- /dev/null +++ b/openai_agents/mcp/sample_files/favorite_songs.txt @@ -0,0 +1,10 @@ +1. "Here Comes the Sun" – The Beatles +2. "Imagine" – John Lennon +3. "Bohemian Rhapsody" – Queen +4. "Shake It Off" – Taylor Swift +5. "Billie Jean" – Michael Jackson +6. "Uptown Funk" – Mark Ronson ft. Bruno Mars +7. "Don’t Stop Believin’" – Journey +8. "Dancing Queen" – ABBA +9. "Happy" – Pharrell Williams +10. "Wonderwall" – Oasis diff --git a/openai_agents/mcp/servers/prompt_server.py b/openai_agents/mcp/servers/prompt_server.py new file mode 100644 index 00000000..07f025ce --- /dev/null +++ b/openai_agents/mcp/servers/prompt_server.py @@ -0,0 +1,58 @@ +from mcp.server.fastmcp import FastMCP + +# Create server +mcp = FastMCP("Prompt Server") + + +# Instruction-generating prompts (user-controlled) +@mcp.prompt() +def generate_code_review_instructions( + focus: str = "general code quality", language: str = "python" +) -> str: + """Generate agent instructions for code review tasks""" + print(f"[debug-server] generate_code_review_instructions({focus}, {language})") + + return f"""You are a senior {language} code review specialist. Your role is to provide comprehensive code analysis with focus on {focus}. + +INSTRUCTIONS: +- Analyze code for quality, security, performance, and best practices +- Provide specific, actionable feedback with examples +- Identify potential bugs, vulnerabilities, and optimization opportunities +- Suggest improvements with code examples when applicable +- Be constructive and educational in your feedback +- Focus particularly on {focus} aspects + +RESPONSE FORMAT: +1. Overall Assessment +2. Specific Issues Found +3. Security Considerations +4. Performance Notes +5. Recommended Improvements +6. Best Practices Suggestions + +Use the available tools to check current time if you need timestamps for your analysis.""" + + +@mcp.prompt() +def generate_review_rubric(target: str = "application code") -> str: + """Generate a scoring rubric for reviewing code or plans""" + return f"""You are evaluating {target}. Score each category 1-5 and justify briefly. + +CATEGORIES: +- Correctness and Reliability +- Security and Risk +- Performance and Efficiency +- Readability and Maintainability +- Testability and Coverage +- Compliance with Style/Guidelines + +FORMAT: +- Overall Score (1-5) +- Category Scores (bulleted) +- Top 3 Issues (with impact level and suggested fix) +- Quick Wins (3 bullets) +""" + + +if __name__ == "__main__": + mcp.run(transport="streamable-http") diff --git a/openai_agents/mcp/servers/tools_server.py b/openai_agents/mcp/servers/tools_server.py new file mode 100644 index 00000000..a329c7ee --- /dev/null +++ b/openai_agents/mcp/servers/tools_server.py @@ -0,0 +1,44 @@ +import argparse +import random + +import requests +from mcp.server.fastmcp import FastMCP + +# Create server +mcp = FastMCP("Tools Server") + + +@mcp.tool() +def add(a: int, b: int) -> int: + """Add two numbers""" + print(f"[debug-server] add({a}, {b})") + return a + b + + +@mcp.tool() +def get_secret_word() -> str: + print("[debug-server] get_secret_word()") + return random.choice(["apple", "banana", "cherry"]) + + +@mcp.tool() +def get_current_weather(city: str) -> str: + print(f"[debug-server] get_current_weather({city})") + + endpoint = "https://wttr.in" + response = requests.get(f"{endpoint}/{city}") + return response.text + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="MCP Tools Server") + parser.add_argument( + "--transport", + choices=["streamable-http", "sse"], + default="streamable-http", + help="Transport type (default: streamable-http)", + ) + args = parser.parse_args() + + print(f"Starting Tools Server with {args.transport} transport...") + mcp.run(transport=args.transport) diff --git a/openai_agents/mcp/workflows/file_system_workflow.py b/openai_agents/mcp/workflows/file_system_workflow.py new file mode 100644 index 00000000..b3528c18 --- /dev/null +++ b/openai_agents/mcp/workflows/file_system_workflow.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from agents import Agent, Runner, trace +from agents.mcp import MCPServer +from temporalio import workflow +from temporalio.contrib import openai_agents + + +@workflow.defn +class FileSystemWorkflow: + @workflow.run + async def run(self) -> str: + with trace(workflow_name="MCP File System Example"): + server: MCPServer = openai_agents.workflow.stateless_mcp_server( + "FileSystemServer" + ) + agent = Agent( + name="Assistant", + instructions="Use the tools to read the filesystem and answer questions based on those files.", + mcp_servers=[server], + ) + + # List the files it can read + message = "Read the files and list them." + workflow.logger.info(f"Running: {message}") + result1 = await Runner.run(starting_agent=agent, input=message) + + # Ask about books + message = "What is my #1 favorite book?" + workflow.logger.info(f"Running: {message}") + result2 = await Runner.run(starting_agent=agent, input=message) + + # Ask a question that reads then reasons. + message = ( + "Look at my favorite songs. Suggest one new song that I might like." + ) + workflow.logger.info(f"Running: {message}") + result3 = await Runner.run(starting_agent=agent, input=message) + + return f"{result1.final_output}\n\n{result2.final_output}\n\n{result3.final_output}" diff --git a/openai_agents/mcp/workflows/memory_research_scratchpad_workflow.py b/openai_agents/mcp/workflows/memory_research_scratchpad_workflow.py new file mode 100644 index 00000000..1812a452 --- /dev/null +++ b/openai_agents/mcp/workflows/memory_research_scratchpad_workflow.py @@ -0,0 +1,122 @@ +from __future__ import annotations + +from agents import Agent, Runner, trace +from agents.model_settings import ModelSettings +from temporalio import workflow +from temporalio.contrib import openai_agents as temporal_openai_agents + +SEED_NOTES = [ + ( + "scratchpad/ai-sum/001", + "Study A (2024-04)", + "Summaries reduced triage time by 22% (n=60).", + ["ai-summarization", "email", "kpi"], + ), + ( + "scratchpad/ai-sum/002", + "User preference", + "Users prefer action-first summaries with 5–8 bullets max.", + ["ai-summarization", "email", "ux"], + ), + ( + "scratchpad/ai-sum/003", + "Risk: misleading summaries", + "Hallucination risk; mitigation: confidence thresholds + easy fallback to original email.", + ["ai-summarization", "email", "risk"], + ), + ( + "scratchpad/ai-sum/004", + "Latency consideration", + "Cold-start latency noticeable on first open; can cache or precompute in background.", + ["ai-summarization", "email", "perf"], + ), + ( + "scratchpad/ai-sum/005", + "Adoption insight", + "Admin controls improve enterprise adoption; opt-in increases trust and perceived control.", + ["ai-summarization", "email", "adoption"], + ), +] + + +@workflow.defn +class MemoryResearchScratchpadWorkflow: + @workflow.run + async def run(self) -> str: + async with temporal_openai_agents.workflow.stateful_mcp_server( + "MemoryServer", + ) as server: + with trace(workflow_name="MCP Memory Scratchpad Example"): + agent = Agent( + name="Research Scratchpad Agent", + instructions=( + "Use the Memory MCP tools to persist, query, update, and delete notes." + " Keep IDs short and consistent. Synthesis must rely only on recalled notes and include simple" + " citations of the form '(Note: id)'. Keep the brief to 5 bullets." + ), + mcp_servers=[server], + model_settings=ModelSettings(tool_choice="required"), + ) + + # Step 1: Write seed notes to memory + write_prompt_lines = [ + "Store the following notes in memory. Use the given id and tags for each entry.", + "After storing, confirm each (id, tags) that was written.", + "", + ] + for note_id, title, content, tags in SEED_NOTES: + # Store tags as separate observation lines so search can reliably match them + tag_obs = ", ".join([f"tag: {t}" for t in tags]) + write_prompt_lines.append( + f"- id: {note_id}; title: {title}; content: {content}; observations: [{tag_obs}]" + ) + write_prompt = "\n".join(write_prompt_lines) + workflow.logger.info("Writing seed notes to memory") + r1 = await Runner.run(starting_agent=agent, input=write_prompt) + + # Step 2: Query by tags + query_prompt = ( + "Search memory for notes that contain BOTH observations 'tag: ai-summarization' and 'tag: email'. " + "If the search returns empty, list entities with the name prefix 'scratchpad/ai-sum/' and filter to those that have both tag observations. " + "For the resulting ids, call retrieve_entities to fetch their observations, then return a normalized list of (id, title, 1–2 key points) based on the retrieved entities." + ) + workflow.logger.info("Querying notes by tags") + r2 = await Runner.run( + starting_agent=agent, + input=query_prompt, + previous_response_id=r1.last_response_id, + ) + + # Step 3: Synthesis with citations + synth_prompt = ( + "Using only the recalled notes, produce a 5-bullet brief. " + "Include one citation per bullet in the form '(Note: id)'. Do not introduce new facts." + ) + workflow.logger.info("Synthesizing brief from recalled notes") + r3 = await Runner.run( + starting_agent=agent, + input=synth_prompt, + previous_response_id=r2.last_response_id, + ) + + # Step 4: Update and re-query (optional demonstration) + update_prompt = ( + "Update the note 'scratchpad/ai-sum/003' to include more precise mitigation:" + " 'threshold=0.7; fallback to full email on low confidence'. Then delete the note" + " 'scratchpad/ai-sum/005'. Finally, list only the remaining 'risk' notes with (id, updated content)." + ) + workflow.logger.info( + "Updating one note and deleting another, then re-listing risk notes" + ) + r4 = await Runner.run( + starting_agent=agent, + input=update_prompt, + previous_response_id=r3.last_response_id, + ) + + return ( + f"WRITE CONFIRMATIONS:\n{r1.final_output}\n\n" + f"QUERY RESULTS:\n{r2.final_output}\n\n" + f"SYNTHESIS:\n{r3.final_output}\n\n" + f"UPDATES:\n{r4.final_output}" + ) diff --git a/openai_agents/mcp/workflows/prompt_server_workflow.py b/openai_agents/mcp/workflows/prompt_server_workflow.py new file mode 100644 index 00000000..0a873561 --- /dev/null +++ b/openai_agents/mcp/workflows/prompt_server_workflow.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +from agents import Agent, Runner, trace +from agents.mcp import MCPServer +from temporalio import workflow +from temporalio.contrib import openai_agents + + +@workflow.defn +class PromptServerWorkflow: + @workflow.run + async def run(self) -> str: + with trace(workflow_name="Prompt Server Example"): + outputs: list[str] = [] + server: MCPServer = openai_agents.workflow.stateless_mcp_server( + "PromptServer" + ) + + # Show available prompts + workflow.logger.info("=== AVAILABLE PROMPTS ===") + outputs.append("=== AVAILABLE PROMPTS ===") + prompts_result = await server.list_prompts() + workflow.logger.info("User can select from these prompts:") + outputs.append("User can select from these prompts:") + for i, prompt in enumerate(prompts_result.prompts, 1): + line = f" {i}. {prompt.name} - {prompt.description}" + workflow.logger.info(line) + outputs.append(line) + workflow.logger.info("") + outputs.append("") + + # Demo code review with user-selected prompt + workflow.logger.info("=== CODE REVIEW DEMO ===") + + # Get instructions from prompt + workflow.logger.info( + "Getting instructions from prompt: generate_code_review_instructions" + ) + try: + prompt_result = await server.get_prompt( + "generate_code_review_instructions", + {"focus": "security vulnerabilities", "language": "python"}, + ) + content = prompt_result.messages[0].content + instructions = ( + content.text if hasattr(content, "text") else str(content) + ) + workflow.logger.info("Generated instructions") + preview = instructions[:200].replace("\n", " ") + ( + "..." if len(instructions) > 200 else "" + ) + outputs.append("=== INSTRUCTIONS (PREVIEW) ===") + outputs.append(preview) + except Exception as e: + workflow.logger.info(f"Failed to get instructions: {e}") + instructions = f"You are a helpful assistant. Error: {e}" + outputs.append(f"Failed to get instructions: {e}") + + agent = Agent( + name="Code Reviewer Agent", + instructions=instructions, + ) + + message = """Please review this code: + +def process_user_input(user_input): + command = f"echo {user_input}" + os.system(command) + return "Command executed" + +""" + + workflow.logger.info(f"Running: {message[:60]}...") + outputs.append("=== REVIEW OUTPUT ===") + result = await Runner.run(starting_agent=agent, input=message) + workflow.logger.info(result.final_output) + outputs.append(result.final_output) + workflow.logger.info("\n" + "=" * 50 + "\n") + return "\n".join(outputs) diff --git a/openai_agents/mcp/workflows/sse_workflow.py b/openai_agents/mcp/workflows/sse_workflow.py new file mode 100644 index 00000000..c8b80e03 --- /dev/null +++ b/openai_agents/mcp/workflows/sse_workflow.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +from agents import Agent, Runner, trace +from agents.mcp import MCPServer +from agents.model_settings import ModelSettings +from temporalio import workflow +from temporalio.contrib import openai_agents + + +@workflow.defn +class SseWorkflow: + @workflow.run + async def run(self) -> str: + with trace(workflow_name="SSE Example"): + server: MCPServer = openai_agents.workflow.stateless_mcp_server("SseServer") + agent = Agent( + name="Assistant", + instructions="Use the tools to answer the questions.", + mcp_servers=[server], + model_settings=ModelSettings(tool_choice="required"), + ) + + # Use the `add` tool to add two numbers + message = "Add these numbers: 7 and 22." + workflow.logger.info(f"Running: {message}") + result1 = await Runner.run(starting_agent=agent, input=message) + + # Run the `get_weather` tool + message = "What's the weather in Tokyo?" + workflow.logger.info(f"Running: {message}") + result2 = await Runner.run(starting_agent=agent, input=message) + + # Run the `get_secret_word` tool + message = "What's the secret word?" + workflow.logger.info(f"Running: {message}") + result3 = await Runner.run(starting_agent=agent, input=message) + + return f"{result1.final_output}\n\n{result2.final_output}\n\n{result3.final_output}" diff --git a/openai_agents/mcp/workflows/streamable_http_workflow.py b/openai_agents/mcp/workflows/streamable_http_workflow.py new file mode 100644 index 00000000..98b7d576 --- /dev/null +++ b/openai_agents/mcp/workflows/streamable_http_workflow.py @@ -0,0 +1,40 @@ +from __future__ import annotations + +from agents import Agent, Runner, trace +from agents.mcp import MCPServer +from agents.model_settings import ModelSettings +from temporalio import workflow +from temporalio.contrib import openai_agents + + +@workflow.defn +class StreamableHttpWorkflow: + @workflow.run + async def run(self) -> str: + with trace(workflow_name="Streamable HTTP Example"): + server: MCPServer = openai_agents.workflow.stateless_mcp_server( + "StreamableHttpServer" + ) + agent = Agent( + name="Assistant", + instructions="Use the tools to answer the questions.", + mcp_servers=[server], + model_settings=ModelSettings(tool_choice="required"), + ) + + # Use the `add` tool to add two numbers + message = "Add these numbers: 7 and 22." + workflow.logger.info(f"Running: {message}") + result1 = await Runner.run(starting_agent=agent, input=message) + + # Run the `get_weather` tool + message = "What's the weather in Tokyo?" + workflow.logger.info(f"Running: {message}") + result2 = await Runner.run(starting_agent=agent, input=message) + + # Run the `get_secret_word` tool + message = "What's the secret word?" + workflow.logger.info(f"Running: {message}") + result3 = await Runner.run(starting_agent=agent, input=message) + + return f"{result1.final_output}\n\n{result2.final_output}\n\n{result3.final_output}" diff --git a/pyproject.toml b/pyproject.toml index 3a73a8d1..73007250 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,8 +55,9 @@ open-telemetry = [ "opentelemetry-exporter-otlp-proto-grpc", ] openai-agents = [ - "openai-agents[litellm] >= 0.2.3", + "openai-agents[litellm] == 0.3.2", "temporalio[openai-agents] >= 1.18.0", + "requests>=2.32.0,<3", ] pydantic-converter = ["pydantic>=2.10.6,<3"] sentry = ["sentry-sdk>=2.13.0"] @@ -143,4 +144,4 @@ ignore_errors = true [[tool.mypy.overrides]] module = "opentelemetry.*" -ignore_errors = true \ No newline at end of file +ignore_errors = true diff --git a/uv.lock b/uv.lock index 374d5c99..73424b77 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "black" version = "22.12.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -196,7 +196,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -210,7 +210,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -219,7 +219,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] @@ -276,7 +276,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -337,7 +337,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -349,7 +349,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -358,7 +358,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] @@ -381,7 +381,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -390,7 +390,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -403,7 +403,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -412,7 +412,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -424,7 +424,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -438,7 +438,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -447,7 +447,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple/" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -541,7 +541,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -550,7 +550,7 @@ wheels = [ [[package]] name = "gevent" version = "25.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -598,7 +598,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -610,7 +610,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -661,7 +661,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] @@ -673,7 +673,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.73.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/79/e8/b43b851537da2e2f03fa8be1aef207e5cbfb1a2e014fbb6b40d24c177cd3/grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87", size = 12730355, upload-time = "2025-06-26T01:53:24.622Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/51/a5748ab2773d893d099b92653039672f7e26dd35741020972b84d604066f/grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55", size = 5365087, upload-time = "2025-06-26T01:51:44.541Z" }, @@ -721,7 +721,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -730,7 +730,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -745,7 +745,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -758,7 +758,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -794,7 +794,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -809,7 +809,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -818,7 +818,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -837,7 +837,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -846,7 +846,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] @@ -858,7 +858,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -867,7 +867,7 @@ wheels = [ [[package]] name = "isort" version = "5.13.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] @@ -888,7 +888,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple/" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -960,7 +960,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpointer" }, ] @@ -981,7 +981,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -990,7 +990,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] @@ -1017,7 +1017,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1041,7 +1041,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1061,7 +1061,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1078,7 +1078,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, ] @@ -1105,7 +1105,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1121,7 +1121,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] @@ -1155,7 +1155,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple/" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] @@ -1225,7 +1225,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1247,7 +1247,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1256,7 +1256,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1358,7 +1358,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1397,7 +1397,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -1418,7 +1418,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1427,7 +1427,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1459,7 +1459,7 @@ wheels = [ [[package]] name = "openai" version = "1.108.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1477,8 +1477,8 @@ wheels = [ [[package]] name = "openai-agents" -version = "0.3.1" -source = { registry = "https://pypi.org/simple/" } +version = "0.3.2" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1488,9 +1488,9 @@ dependencies = [ { name = "types-requests" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/57/d9/2940db8114d8e1e3b8cfa1943432e73721ada20c8dc8514aaee15e858c09/openai_agents-0.3.1.tar.gz", hash = "sha256:c39471f62d859c3ed20f3f69704e830f0d0e2a4e321aa1f21eb924f7a16347a8", size = 1722367, upload-time = "2025-09-18T17:21:12.84Z" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/9f/dafa9f80653778179822e1abf77c7f0d9da5a16806c96b5bb9e0e46bd747/openai_agents-0.3.2.tar.gz", hash = "sha256:b71ac04ee9f502f1bc0f4d142407df4ec69db4442db86c4da252b4558fa90cd5", size = 1727988, upload-time = "2025-09-23T20:37:20.7Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/41/34/08564f0285a3d8f425588cb9141b1cd14be2e56e39630f5593de3f4f6558/openai_agents-0.3.1-py3-none-any.whl", hash = "sha256:10a2d68c4d993b395cc5048979748fb9747179c14741a3d07a009efb5e5566e6", size = 193894, upload-time = "2025-09-18T17:21:11.144Z" }, + { url = "https://files.pythonhosted.org/packages/27/7e/6a8437f9f40937bb473ceb120a65e1b37bc87bcee6da67be4c05b25c6a89/openai_agents-0.3.2-py3-none-any.whl", hash = "sha256:55e02c57f2aaf3170ff0aa0ab7c337c28fd06b43b3bb9edc28b77ffd8142b425", size = 194221, upload-time = "2025-09-23T20:37:19.121Z" }, ] [package.optional-dependencies] @@ -1501,7 +1501,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1526,7 +1526,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -1556,7 +1556,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1570,7 +1570,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1583,7 +1583,7 @@ wheels = [ [[package]] name = "orjson" version = "3.10.18" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810, upload-time = "2025-04-29T23:30:08.423Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927, upload-time = "2025-04-29T23:28:08.643Z" }, @@ -1649,7 +1649,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] @@ -1661,7 +1661,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1670,7 +1670,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1718,7 +1718,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1727,7 +1727,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1736,7 +1736,7 @@ wheels = [ [[package]] name = "platformdirs" version = "4.3.8" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1745,7 +1745,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1754,7 +1754,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1768,7 +1768,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1857,7 +1857,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1871,7 +1871,7 @@ wheels = [ [[package]] name = "pyarrow" version = "20.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/23/77094eb8ee0dbe88441689cb6afc40ac312a1e15d3a7acc0586999518222/pyarrow-20.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c7dd06fd7d7b410ca5dc839cc9d485d2bc4ae5240851bcd45d85105cc90a47d7", size = 30832591, upload-time = "2025-04-27T12:27:27.89Z" }, @@ -1924,7 +1924,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1933,7 +1933,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1948,7 +1948,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2035,7 +2035,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2049,7 +2049,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2058,7 +2058,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2071,7 +2071,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2088,7 +2088,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] @@ -2101,7 +2101,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2114,7 +2114,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] @@ -2126,7 +2126,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2135,7 +2135,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2144,7 +2144,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2153,7 +2153,7 @@ wheels = [ [[package]] name = "pywin32" version = "310" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, @@ -2172,7 +2172,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple/" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2216,7 +2216,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2230,7 +2230,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2299,7 +2299,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2314,7 +2314,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] @@ -2326,7 +2326,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2340,7 +2340,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2466,7 +2466,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] @@ -2478,7 +2478,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2500,7 +2500,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2509,7 +2509,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2518,7 +2518,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2527,7 +2527,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2572,7 +2572,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2597,7 +2597,7 @@ wheels = [ [[package]] name = "temporalio" version = "1.18.0" -source = { registry = "https://test.pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2605,13 +2605,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://test-files.pythonhosted.org/packages/7e/20/b52c96b37bf00ead6e8a4a197075770ebad516db765cc3abca8396de0689/temporalio-1.18.0.tar.gz", hash = "sha256:7ff7f833eb1e7697084b4ed9d86c3167cbff1ec77f1b40df774313a5d0fd5f6d", size = 1781572, upload-time = "2025-09-19T23:33:44.168Z" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/20/b52c96b37bf00ead6e8a4a197075770ebad516db765cc3abca8396de0689/temporalio-1.18.0.tar.gz", hash = "sha256:7ff7f833eb1e7697084b4ed9d86c3167cbff1ec77f1b40df774313a5d0fd5f6d", size = 1781572, upload-time = "2025-09-19T23:40:52.511Z" } wheels = [ - { url = "https://test-files.pythonhosted.org/packages/2f/28/c5a4ee259748450ac0765837f8c78cbfa36800264158d98bd2cde4496d87/temporalio-1.18.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ac5d30d8b010c9b042065ea1259da7638db1a0a25e81ee4be0671a393ed329c5", size = 12734753, upload-time = "2025-09-19T23:32:54.477Z" }, - { url = "https://test-files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:19315d192247230c9bd7c60a566c2b3a80ad4d9de891c6aa13df63d72d3ec169", size = 12323141, upload-time = "2025-09-19T23:33:06.214Z" }, - { url = "https://test-files.pythonhosted.org/packages/6d/76/82415b43c68e2c6bb3a85e8800555d206767815088c8cad0ade9a06bd7ac/temporalio-1.18.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a023b25033e48b2e43f623a78737047a45b8cb553f69f457d09272fce5c723da", size = 12694061, upload-time = "2025-09-19T23:33:18.12Z" }, - { url = "https://test-files.pythonhosted.org/packages/41/60/176a3224c2739fee270052dd9224ae36370c4e13d2ab1bb96a2f9bbb513c/temporalio-1.18.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:695211dddbcffc20077d5b3b9a9b41bd09f60393c4ff211bcc7d6d895d607cc1", size = 12879404, upload-time = "2025-09-19T23:33:29.329Z" }, - { url = "https://test-files.pythonhosted.org/packages/e3/8d/e3809b356262d1d398d8cbb78df1e19d460c0a89e6ab64ca8d9c05d5fe5a/temporalio-1.18.0-cp39-abi3-win_amd64.whl", hash = "sha256:e3f691bd0a01a22c0fe40e87b6236cc8a292628e3a5a490880d1bf94709249c9", size = 13088041, upload-time = "2025-09-19T23:33:40.025Z" }, + { url = "https://files.pythonhosted.org/packages/2f/28/c5a4ee259748450ac0765837f8c78cbfa36800264158d98bd2cde4496d87/temporalio-1.18.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ac5d30d8b010c9b042065ea1259da7638db1a0a25e81ee4be0671a393ed329c5", size = 12734753, upload-time = "2025-09-19T23:40:06.575Z" }, + { url = "https://files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:19315d192247230c9bd7c60a566c2b3a80ad4d9de891c6aa13df63d72d3ec169", size = 12323141, upload-time = "2025-09-19T23:40:16.817Z" }, + { url = "https://files.pythonhosted.org/packages/6d/76/82415b43c68e2c6bb3a85e8800555d206767815088c8cad0ade9a06bd7ac/temporalio-1.18.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a023b25033e48b2e43f623a78737047a45b8cb553f69f457d09272fce5c723da", size = 12694061, upload-time = "2025-09-19T23:40:26.388Z" }, + { url = "https://files.pythonhosted.org/packages/41/60/176a3224c2739fee270052dd9224ae36370c4e13d2ab1bb96a2f9bbb513c/temporalio-1.18.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:695211dddbcffc20077d5b3b9a9b41bd09f60393c4ff211bcc7d6d895d607cc1", size = 12879404, upload-time = "2025-09-19T23:40:37.487Z" }, + { url = "https://files.pythonhosted.org/packages/e3/8d/e3809b356262d1d398d8cbb78df1e19d460c0a89e6ab64ca8d9c05d5fe5a/temporalio-1.18.0-cp39-abi3-win_amd64.whl", hash = "sha256:e3f691bd0a01a22c0fe40e87b6236cc8a292628e3a5a490880d1bf94709249c9", size = 13088041, upload-time = "2025-09-19T23:40:49.469Z" }, ] [package.optional-dependencies] @@ -2684,6 +2684,7 @@ open-telemetry = [ ] openai-agents = [ { name = "openai-agents", extra = ["litellm"] }, + { name = "requests" }, { name = "temporalio", extra = ["openai-agents"] }, ] pydantic-converter = [ @@ -2745,7 +2746,8 @@ open-telemetry = [ { name = "temporalio", extras = ["opentelemetry"] }, ] openai-agents = [ - { name = "openai-agents", extras = ["litellm"], specifier = ">=0.2.3" }, + { name = "openai-agents", extras = ["litellm"], specifier = "==0.3.2" }, + { name = "requests", specifier = ">=2.32.0,<3" }, { name = "temporalio", extras = ["openai-agents"], specifier = ">=1.18.0" }, ] pydantic-converter = [{ name = "pydantic", specifier = ">=2.10.6,<3" }] @@ -2758,7 +2760,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2767,7 +2769,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2803,7 +2805,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2828,7 +2830,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2867,7 +2869,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2879,7 +2881,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2897,7 +2899,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2913,7 +2915,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -2922,7 +2924,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -2931,7 +2933,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] @@ -2943,7 +2945,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2952,7 +2954,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -2965,7 +2967,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2977,7 +2979,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2986,7 +2988,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -2995,7 +2997,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3020,7 +3022,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3052,7 +3054,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -3152,7 +3154,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3211,7 +3213,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3310,7 +3312,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -3319,7 +3321,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] @@ -3331,7 +3333,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] From 158157b7999920c592448008c6f63610dda523e1 Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Thu, 9 Oct 2025 09:45:04 -0700 Subject: [PATCH 23/40] Eager workflow start sample (#256) * Eager workflow start sample * Formatting * Update README --- README.md | 1 + eager_wf_start/README.md | 16 ++++++++++ eager_wf_start/__init__.py | 0 eager_wf_start/activities.py | 6 ++++ eager_wf_start/run.py | 42 +++++++++++++++++++++++++++ eager_wf_start/workflows.py | 15 ++++++++++ tests/conftest.py | 2 ++ tests/eager_wf_start/__init__.py | 0 tests/eager_wf_start/workflow_test.py | 29 ++++++++++++++++++ 9 files changed, 111 insertions(+) create mode 100644 eager_wf_start/README.md create mode 100644 eager_wf_start/__init__.py create mode 100644 eager_wf_start/activities.py create mode 100644 eager_wf_start/run.py create mode 100644 eager_wf_start/workflows.py create mode 100644 tests/eager_wf_start/__init__.py create mode 100644 tests/eager_wf_start/workflow_test.py diff --git a/README.md b/README.md index 43d2cba6..d9ae57a3 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [custom_decorator](custom_decorator) - Custom decorator to auto-heartbeat a long-running activity. * [custom_metric](custom_metric) - Custom metric to record the workflow type in the activity schedule to start latency. * [dsl](dsl) - DSL workflow that executes steps defined in a YAML file. +* [eager_wf_start](eager_wf_start) - Run a workflow using Eager Workflow Start * [encryption](encryption) - Apply end-to-end encryption for all input/output. * [env_config](env_config) - Load client configuration from TOML files with programmatic overrides. * [gevent_async](gevent_async) - Combine gevent and Temporal. diff --git a/eager_wf_start/README.md b/eager_wf_start/README.md new file mode 100644 index 00000000..834c6a55 --- /dev/null +++ b/eager_wf_start/README.md @@ -0,0 +1,16 @@ +# Eager Workflow Start + +This sample shows how to create a workflow that uses Eager Workflow Start. + +The target use case is workflows whose first task needs to execute quickly (ex: payment verification in an online checkout workflow). That work typically can't be done directly in the workflow (ex: using web APIs, databases, etc.), and also needs to avoid the overhead of dispatching another task. Using a Local Activity suffices both needs, which this sample demonstrates. + +You can read more about Eager Workflow Start in our: + +- [Eager Workflow Start blog](https://temporal.io/blog/improving-latency-with-eager-workflow-start) +- [Worker Performance Docs](https://docs.temporal.io/develop/worker-performance#eager-workflow-start) + +To run, first see the main [README.md](../README.md) for prerequisites. + +Then run the sample via: + + uv run eager_wf_start/run.py \ No newline at end of file diff --git a/eager_wf_start/__init__.py b/eager_wf_start/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eager_wf_start/activities.py b/eager_wf_start/activities.py new file mode 100644 index 00000000..6533140f --- /dev/null +++ b/eager_wf_start/activities.py @@ -0,0 +1,6 @@ +from temporalio import activity + + +@activity.defn() +async def greeting(name: str) -> str: + return f"Hello {name}!" diff --git a/eager_wf_start/run.py b/eager_wf_start/run.py new file mode 100644 index 00000000..c1daf82a --- /dev/null +++ b/eager_wf_start/run.py @@ -0,0 +1,42 @@ +import asyncio +import uuid + +from temporalio.client import Client +from temporalio.worker import Worker + +from eager_wf_start.activities import greeting +from eager_wf_start.workflows import EagerWorkflow + +TASK_QUEUE = "eager-wf-start-task-queue" + + +async def main(): + + # Note that the worker and client run in the same process and share the same client connection. + client = await Client.connect("localhost:7233") + worker = Worker( + client, + task_queue=TASK_QUEUE, + workflows=[EagerWorkflow], + activities=[greeting], + ) + + # Run worker in the background + async with worker: + # Start workflow(s) while worker is running + wf_handle = await client.start_workflow( + EagerWorkflow.run, + "Temporal", + id=f"eager-workflow-id-{uuid.uuid4()}", + task_queue=TASK_QUEUE, + request_eager_start=True, + ) + + # This is an internal flag not intended to be used publicly. + # It is used here purely to display that the workflow was eagerly started. + print(f"Workflow eagerly started: {wf_handle.__temporal_eagerly_started}") + print(await wf_handle.result()) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/eager_wf_start/workflows.py b/eager_wf_start/workflows.py new file mode 100644 index 00000000..9107d402 --- /dev/null +++ b/eager_wf_start/workflows.py @@ -0,0 +1,15 @@ +from datetime import timedelta + +from temporalio import workflow + +with workflow.unsafe.imports_passed_through(): + from eager_wf_start.activities import greeting + + +@workflow.defn +class EagerWorkflow: + @workflow.run + async def run(self, name: str) -> str: + return await workflow.execute_local_activity( + greeting, name, schedule_to_close_timeout=timedelta(seconds=5) + ) diff --git a/tests/conftest.py b/tests/conftest.py index e63a059b..65de246e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -45,6 +45,8 @@ async def env(request) -> AsyncGenerator[WorkflowEnvironment, None]: dev_server_extra_args=[ "--dynamic-config-value", "frontend.enableExecuteMultiOperation=true", + "--dynamic-config-value", + "system.enableEagerWorkflowStart=true", ] ) elif env_type == "time-skipping": diff --git a/tests/eager_wf_start/__init__.py b/tests/eager_wf_start/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/eager_wf_start/workflow_test.py b/tests/eager_wf_start/workflow_test.py new file mode 100644 index 00000000..1080f5bc --- /dev/null +++ b/tests/eager_wf_start/workflow_test.py @@ -0,0 +1,29 @@ +import uuid + +from temporalio.client import Client +from temporalio.worker import Worker + +from eager_wf_start.activities import greeting +from eager_wf_start.workflows import EagerWorkflow + + +async def test_eager_wf_start(client: Client): + task_queue_name = str(uuid.uuid4()) + + async with Worker( + client, + task_queue=task_queue_name, + workflows=[EagerWorkflow], + activities=[greeting], + ): + handle = await client.start_workflow( + EagerWorkflow.run, + "Temporal", + id=f"workflow-{uuid.uuid4()}", + task_queue=task_queue_name, + request_eager_start=True, + ) + print("HANDLE", handle.__temporal_eagerly_started) + assert handle.__temporal_eagerly_started + result = await handle.result() + assert result == "Hello Temporal!" From b9614573c9637b55a834a4e0741ed580dd75ba53 Mon Sep 17 00:00:00 2001 From: Andrew Yuan Date: Mon, 20 Oct 2025 15:07:16 -0700 Subject: [PATCH 24/40] Replace references to tctl with Temporal CLI (#260) --- resource_pool/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resource_pool/README.md b/resource_pool/README.md index fe48e1ab..5b746d7b 100644 --- a/resource_pool/README.md +++ b/resource_pool/README.md @@ -16,7 +16,7 @@ You should see output indicating that the `ResourcePoolWorkflow` serialized acce You can query the set of current resource resource holders with: - tctl wf query -w resource_pool --qt get_current_holders + temporal workflow query --workflow-id resource_pool --name get_current_holders # Other approaches @@ -41,7 +41,7 @@ Temporal's durable execution guarantees, this can only happen if: If a leak were to happen, you could discover the identity of the leaker using the query above, then: - tctl wf signal -w resource_pool --name release_resource --input '{ "release_key": "" } + temporal workflow signal --workflow-id resource_pool --name release_resource --input '{ "release_key": "" }' Performance: A single ResourcePoolWorkflow scales to tens, but not hundreds, of request/release events per second. It is best suited for allocating resources to long-running workflows. Actual performance will depend on your temporal server's From 092eaad2802b631724a0535ee0550f8653fd3369 Mon Sep 17 00:00:00 2001 From: Kent Gruber Date: Tue, 28 Oct 2025 12:32:10 -0400 Subject: [PATCH 25/40] Set explicit permissions for GitHub Actions workflows (#261) This change was made by an automated process to ensure all GitHub Actions workflows have explicitly defined permissions as per best practices. --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ed53fe1..f41c09d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,7 @@ name: Continuous Integration +permissions: + contents: read + actions: write on: # rebuild any PRs and main branch changes pull_request: push: From ff0f1343822e532a5c377f02003002d2dcac4f79 Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Mon, 10 Nov 2025 18:52:45 -0800 Subject: [PATCH 26/40] update samples to use environment configuration for client (#233) * update samples to use environment configuration for client * linting fixes * update to direct profile mutation * mutate config as dict * update client config usage * Update temporalio dependency (includes optional profile commit) * remove unused toml & util * Update SDK version to 1.18 (#247) * Update SDK version to 1.18 * Update openai breaking change * update samples to use environment configuration for client * linting fixes * update to direct profile mutation * update new samples to use envconfig * linting again * remove redundant files/code --------- Co-authored-by: tconley1428 --- activity_worker/activity_worker.py | 5 +- batch_sliding_window/starter.py | 5 +- batch_sliding_window/worker.py | 5 +- bedrock/basic/run_worker.py | 6 +- bedrock/basic/send_message.py | 5 +- bedrock/entity/end_chat.py | 5 +- bedrock/entity/get_history.py | 6 +- bedrock/entity/run_worker.py | 6 +- bedrock/entity/send_message.py | 5 +- bedrock/signals_and_queries/get_history.py | 6 +- bedrock/signals_and_queries/run_worker.py | 6 +- bedrock/signals_and_queries/send_message.py | 5 +- cloud_export_to_parquet/create_schedule.py | 6 +- cloud_export_to_parquet/run_worker.py | 5 +- context_propagation/starter.py | 6 +- context_propagation/worker.py | 6 +- custom_converter/starter.py | 6 +- custom_converter/worker.py | 6 +- custom_decorator/starter.py | 5 +- custom_decorator/worker.py | 5 +- custom_metric/starter.py | 8 +- custom_metric/worker.py | 5 +- dsl/starter.py | 5 +- dsl/worker.py | 5 +- eager_wf_start/run.py | 6 +- encryption/starter.py | 6 +- encryption/worker.py | 5 +- gevent_async/starter.py | 5 +- gevent_async/worker.py | 5 +- hello/hello_activity.py | 7 +- hello/hello_activity_async.py | 5 +- hello/hello_activity_choice.py | 6 +- hello/hello_activity_heartbeat.py | 5 +- hello/hello_activity_method.py | 5 +- hello/hello_activity_multiprocess.py | 5 +- hello/hello_activity_retry.py | 5 +- hello/hello_async_activity_completion.py | 5 +- hello/hello_cancellation.py | 6 +- hello/hello_change_log_level.py | 6 +- hello/hello_child_workflow.py | 6 +- hello/hello_continue_as_new.py | 5 +- hello/hello_cron.py | 5 +- hello/hello_exception.py | 5 +- hello/hello_local_activity.py | 5 +- hello/hello_parallel_activity.py | 5 +- hello/hello_patch.py | 5 +- hello/hello_query.py | 6 +- hello/hello_search_attributes.py | 5 +- hello/hello_signal.py | 6 +- hello/hello_update.py | 5 +- hello_nexus/caller/app.py | 11 +- hello_nexus/handler/worker.py | 11 +- langchain/starter.py | 9 +- langchain/worker.py | 6 +- message_passing/introduction/starter.py | 7 +- message_passing/introduction/worker.py | 5 +- .../safe_message_handlers/starter.py | 5 +- .../safe_message_handlers/worker.py | 5 +- .../lazy_initialization/starter.py | 13 +- .../lazy_initialization/worker.py | 5 +- .../waiting_for_handlers/starter.py | 6 +- .../waiting_for_handlers/worker.py | 5 +- .../starter.py | 6 +- .../worker.py | 6 +- nexus_multiple_args/caller/app.py | 10 +- nexus_multiple_args/handler/worker.py | 10 +- nexus_sync_operations/caller/app.py | 10 +- nexus_sync_operations/handler/worker.py | 10 +- open_telemetry/starter.py | 5 +- open_telemetry/worker.py | 6 +- .../basic/run_agent_lifecycle_workflow.py | 5 +- .../basic/run_remote_image_workflow.py | 10 +- .../handoffs/run_message_filter_workflow.py | 6 +- openai_agents/mcp/run_file_system_worker.py | 5 +- openai_agents/mcp/run_file_system_workflow.py | 5 +- .../run_memory_research_scratchpad_worker.py | 5 +- ...run_memory_research_scratchpad_workflow.py | 9 +- openai_agents/mcp/run_prompt_server_worker.py | 5 +- .../mcp/run_prompt_server_workflow.py | 5 +- openai_agents/mcp/run_sse_worker.py | 5 +- openai_agents/mcp/run_sse_workflow.py | 5 +- .../mcp/run_streamable_http_worker.py | 5 +- .../mcp/run_streamable_http_workflow.py | 5 +- patching/starter.py | 5 +- patching/worker.py | 5 +- polling/frequent/run_frequent.py | 6 +- polling/frequent/run_worker.py | 5 +- polling/infrequent/run_infrequent.py | 6 +- polling/infrequent/run_worker.py | 5 +- polling/periodic_sequence/run_periodic.py | 6 +- polling/periodic_sequence/run_worker.py | 5 +- prometheus/starter.py | 6 +- prometheus/worker.py | 6 +- pydantic_converter/starter.py | 9 +- pydantic_converter/worker.py | 8 +- pydantic_converter_v1/starter.py | 9 +- pydantic_converter_v1/worker.py | 8 +- replay/replayer.py | 5 +- replay/starter.py | 5 +- replay/worker.py | 5 +- resource_pool/starter.py | 5 +- resource_pool/worker.py | 5 +- schedules/backfill_schedule.py | 6 +- schedules/delete_schedule.py | 6 +- schedules/describe_schedule.py | 6 +- schedules/list_schedule.py | 5 +- schedules/pause_schedule.py | 6 +- schedules/run_worker.py | 6 +- schedules/start_schedule.py | 6 +- schedules/trigger_schedule.py | 6 +- schedules/update_schedule.py | 6 +- sentry/starter.py | 6 +- sentry/worker.py | 6 +- sleep_for_days/starter.py | 7 +- sleep_for_days/worker.py | 5 +- trio_async/starter.py | 5 +- trio_async/worker.py | 5 +- updatable_timer/starter.py | 6 +- updatable_timer/wake_up_time_updater.py | 7 +- updatable_timer/worker.py | 6 +- uv.lock | 274 +++++++++--------- worker_specific_task_queues/starter.py | 5 +- worker_specific_task_queues/worker.py | 5 +- worker_versioning/app.py | 5 +- worker_versioning/workerv1.py | 3 + worker_versioning/workerv1_1.py | 5 +- worker_versioning/workerv2.py | 5 +- 127 files changed, 728 insertions(+), 293 deletions(-) diff --git a/activity_worker/activity_worker.py b/activity_worker/activity_worker.py index 3e613169..986b0ae9 100644 --- a/activity_worker/activity_worker.py +++ b/activity_worker/activity_worker.py @@ -4,6 +4,7 @@ from temporalio import activity from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker task_queue = "say-hello-task-queue" @@ -18,7 +19,9 @@ async def say_hello_activity(name: str) -> str: async def main(): # Create client to localhost on default namespace - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run activity worker async with Worker(client, task_queue=task_queue, activities=[say_hello_activity]): diff --git a/batch_sliding_window/starter.py b/batch_sliding_window/starter.py index d9a24971..7e3b1fb3 100644 --- a/batch_sliding_window/starter.py +++ b/batch_sliding_window/starter.py @@ -6,6 +6,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from batch_sliding_window.batch_workflow import ( ProcessBatchWorkflow, @@ -19,7 +20,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Create client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create unique workflow ID with timestamp timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S") diff --git a/batch_sliding_window/worker.py b/batch_sliding_window/worker.py index c0968bc3..a72ed96c 100644 --- a/batch_sliding_window/worker.py +++ b/batch_sliding_window/worker.py @@ -6,6 +6,7 @@ from temporalio import worker from temporalio.client import Client +from temporalio.envconfig import ClientConfig from batch_sliding_window.batch_workflow import ProcessBatchWorkflow from batch_sliding_window.record_loader_activity import RecordLoader @@ -19,7 +20,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Create client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create RecordLoader activity with sample data record_loader = RecordLoader(record_count=90) diff --git a/bedrock/basic/run_worker.py b/bedrock/basic/run_worker.py index fee8aa5d..085b695c 100644 --- a/bedrock/basic/run_worker.py +++ b/bedrock/basic/run_worker.py @@ -3,6 +3,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from workflows import BasicBedrockWorkflow @@ -11,7 +12,10 @@ async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + activities = BedrockActivities() # Run the worker diff --git a/bedrock/basic/send_message.py b/bedrock/basic/send_message.py index 1b4cc995..692a4927 100644 --- a/bedrock/basic/send_message.py +++ b/bedrock/basic/send_message.py @@ -2,12 +2,15 @@ import sys from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import BasicBedrockWorkflow async def main(prompt: str) -> str: # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Start the workflow workflow_id = "basic-bedrock-workflow" diff --git a/bedrock/entity/end_chat.py b/bedrock/entity/end_chat.py index 49125306..19984202 100644 --- a/bedrock/entity/end_chat.py +++ b/bedrock/entity/end_chat.py @@ -2,12 +2,15 @@ import sys from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import EntityBedrockWorkflow async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) workflow_id = "entity-bedrock-workflow" diff --git a/bedrock/entity/get_history.py b/bedrock/entity/get_history.py index 1600886e..ffcfa31e 100644 --- a/bedrock/entity/get_history.py +++ b/bedrock/entity/get_history.py @@ -1,12 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import EntityBedrockWorkflow async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + workflow_id = "entity-bedrock-workflow" handle = client.get_workflow_handle(workflow_id) diff --git a/bedrock/entity/run_worker.py b/bedrock/entity/run_worker.py index 3e3b1e64..ecc76c52 100644 --- a/bedrock/entity/run_worker.py +++ b/bedrock/entity/run_worker.py @@ -3,6 +3,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from workflows import EntityBedrockWorkflow @@ -11,7 +12,10 @@ async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + activities = BedrockActivities() # Run the worker diff --git a/bedrock/entity/send_message.py b/bedrock/entity/send_message.py index 177b4b69..be7897f0 100644 --- a/bedrock/entity/send_message.py +++ b/bedrock/entity/send_message.py @@ -2,12 +2,15 @@ import sys from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import BedrockParams, EntityBedrockWorkflow async def main(prompt): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) workflow_id = "entity-bedrock-workflow" diff --git a/bedrock/signals_and_queries/get_history.py b/bedrock/signals_and_queries/get_history.py index 0bdf0861..2bd6049f 100644 --- a/bedrock/signals_and_queries/get_history.py +++ b/bedrock/signals_and_queries/get_history.py @@ -1,12 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import SignalQueryBedrockWorkflow async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + workflow_id = "bedrock-workflow-with-signals" handle = client.get_workflow_handle(workflow_id) diff --git a/bedrock/signals_and_queries/run_worker.py b/bedrock/signals_and_queries/run_worker.py index b3e709a9..9d611588 100644 --- a/bedrock/signals_and_queries/run_worker.py +++ b/bedrock/signals_and_queries/run_worker.py @@ -3,6 +3,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from workflows import SignalQueryBedrockWorkflow @@ -11,7 +12,10 @@ async def main(): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + activities = BedrockActivities() # Run the worker diff --git a/bedrock/signals_and_queries/send_message.py b/bedrock/signals_and_queries/send_message.py index 67b8b37e..35a9df1c 100644 --- a/bedrock/signals_and_queries/send_message.py +++ b/bedrock/signals_and_queries/send_message.py @@ -2,12 +2,15 @@ import sys from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflows import SignalQueryBedrockWorkflow async def main(prompt): # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) workflow_id = "bedrock-workflow-with-signals" inactivity_timeout_minutes = 1 diff --git a/cloud_export_to_parquet/create_schedule.py b/cloud_export_to_parquet/create_schedule.py index f425d4c6..1f40a3ed 100644 --- a/cloud_export_to_parquet/create_schedule.py +++ b/cloud_export_to_parquet/create_schedule.py @@ -10,6 +10,7 @@ ScheduleSpec, WorkflowFailureError, ) +from temporalio.envconfig import ClientConfig from cloud_export_to_parquet.workflows import ( ProtoToParquet, @@ -20,7 +21,10 @@ async def main() -> None: """Main function to run temporal workflow.""" # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + # TODO: update s3_bucket and namespace to the actual usecase wf_input = ProtoToParquetWorkflowInput( num_delay_hour=2, diff --git a/cloud_export_to_parquet/run_worker.py b/cloud_export_to_parquet/run_worker.py index df02de11..6062abcd 100644 --- a/cloud_export_to_parquet/run_worker.py +++ b/cloud_export_to_parquet/run_worker.py @@ -2,6 +2,7 @@ from concurrent.futures import ThreadPoolExecutor from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from temporalio.worker.workflow_sandbox import ( SandboxedWorkflowRunner, @@ -18,7 +19,9 @@ async def main() -> None: """Main worker function.""" # Create client connected to server at the given address - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run the worker worker: Worker = Worker( diff --git a/context_propagation/starter.py b/context_propagation/starter.py index 2865eee2..4d141dc0 100644 --- a/context_propagation/starter.py +++ b/context_propagation/starter.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from context_propagation import interceptor, shared, workflows @@ -12,9 +13,12 @@ async def main(): # Set the user ID shared.user_id.set("some-user") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use our interceptor interceptors=[interceptor.ContextPropagationInterceptor()], ) diff --git a/context_propagation/worker.py b/context_propagation/worker.py index 14d954da..70ffa368 100644 --- a/context_propagation/worker.py +++ b/context_propagation/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from context_propagation import activities, interceptor, workflows @@ -12,9 +13,12 @@ async def main(): logging.basicConfig(level=logging.INFO) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use our interceptor interceptors=[interceptor.ContextPropagationInterceptor()], ) diff --git a/custom_converter/starter.py b/custom_converter/starter.py index 54fdf162..cc500ae4 100644 --- a/custom_converter/starter.py +++ b/custom_converter/starter.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from custom_converter.shared import ( GreetingInput, @@ -11,9 +12,12 @@ async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, # Without this we get: # TypeError: Object of type GreetingInput is not JSON serializable data_converter=greeting_data_converter, diff --git a/custom_converter/worker.py b/custom_converter/worker.py index 96214cdd..17186aee 100644 --- a/custom_converter/worker.py +++ b/custom_converter/worker.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from custom_converter.shared import greeting_data_converter @@ -10,9 +11,12 @@ async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, # Without this, when trying to run a workflow, we get: # KeyError: 'Unknown payload encoding my-greeting-encoding data_converter=greeting_data_converter, diff --git a/custom_decorator/starter.py b/custom_decorator/starter.py index 98bf542f..aff675da 100644 --- a/custom_decorator/starter.py +++ b/custom_decorator/starter.py @@ -1,13 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from custom_decorator.worker import WaitForCancelWorkflow async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Start the workflow handle = await client.start_workflow( diff --git a/custom_decorator/worker.py b/custom_decorator/worker.py index 7d0d25ca..0d25145b 100644 --- a/custom_decorator/worker.py +++ b/custom_decorator/worker.py @@ -4,6 +4,7 @@ from temporalio import activity, workflow from temporalio.client import Client from temporalio.common import RetryPolicy +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from custom_decorator.activity_utils import auto_heartbeater @@ -51,7 +52,9 @@ def cancel_activity(self) -> None: async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/custom_metric/starter.py b/custom_metric/starter.py index ded3a626..aeb6d2b7 100644 --- a/custom_metric/starter.py +++ b/custom_metric/starter.py @@ -2,15 +2,15 @@ import uuid from temporalio.client import Client +from temporalio.envconfig import ClientConfig from custom_metric.workflow import StartTwoActivitiesWorkflow async def main(): - - client = await Client.connect( - "localhost:7233", - ) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) await client.start_workflow( StartTwoActivitiesWorkflow.run, diff --git a/custom_metric/worker.py b/custom_metric/worker.py index 9ffad207..6a3be69a 100644 --- a/custom_metric/worker.py +++ b/custom_metric/worker.py @@ -3,6 +3,7 @@ from temporalio import activity from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.runtime import PrometheusConfig, Runtime, TelemetryConfig from temporalio.worker import ( ActivityInboundInterceptor, @@ -48,8 +49,10 @@ async def main(): runtime = Runtime( telemetry=TelemetryConfig(metrics=PrometheusConfig(bind_address="0.0.0.0:9090")) ) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, runtime=runtime, ) worker = Worker( diff --git a/dsl/starter.py b/dsl/starter.py index e530b10e..eb0f328d 100644 --- a/dsl/starter.py +++ b/dsl/starter.py @@ -6,6 +6,7 @@ import dacite import yaml from temporalio.client import Client +from temporalio.envconfig import ClientConfig from dsl.workflow import DSLInput, DSLWorkflow @@ -16,7 +17,9 @@ async def main(dsl_yaml: str) -> None: dsl_input = dacite.from_dict(DSLInput, yaml.safe_load(dsl_yaml)) # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run workflow result = await client.execute_workflow( diff --git a/dsl/worker.py b/dsl/worker.py index 9945492e..e52ec872 100644 --- a/dsl/worker.py +++ b/dsl/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from dsl.activities import DSLActivities @@ -12,7 +13,9 @@ async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the activities and workflow activities = DSLActivities() diff --git a/eager_wf_start/run.py b/eager_wf_start/run.py index c1daf82a..51a1ddf6 100644 --- a/eager_wf_start/run.py +++ b/eager_wf_start/run.py @@ -2,6 +2,7 @@ import uuid from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from eager_wf_start.activities import greeting @@ -13,7 +14,10 @@ async def main(): # Note that the worker and client run in the same process and share the same client connection. - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + worker = Worker( client, task_queue=TASK_QUEUE, diff --git a/encryption/starter.py b/encryption/starter.py index 4c39f553..f2570936 100644 --- a/encryption/starter.py +++ b/encryption/starter.py @@ -3,15 +3,19 @@ import temporalio.converter from temporalio.client import Client +from temporalio.envconfig import ClientConfig from encryption.codec import EncryptionCodec from encryption.worker import GreetingWorkflow async def main(): + # Load configuration + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use the default converter, but change the codec data_converter=dataclasses.replace( temporalio.converter.default(), payload_codec=EncryptionCodec() diff --git a/encryption/worker.py b/encryption/worker.py index b99a2eab..d3387c70 100644 --- a/encryption/worker.py +++ b/encryption/worker.py @@ -4,6 +4,7 @@ import temporalio.converter from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from encryption.codec import EncryptionCodec @@ -20,9 +21,11 @@ async def run(self, name: str) -> str: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use the default converter, but change the codec data_converter=dataclasses.replace( temporalio.converter.default(), payload_codec=EncryptionCodec() diff --git a/gevent_async/starter.py b/gevent_async/starter.py index 43e8356b..010803e5 100644 --- a/gevent_async/starter.py +++ b/gevent_async/starter.py @@ -7,6 +7,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from gevent_async import workflow from gevent_async.executor import GeventExecutor @@ -24,7 +25,9 @@ def main(): async def async_main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run workflow result = await client.execute_workflow( diff --git a/gevent_async/worker.py b/gevent_async/worker.py index 9b4945cf..219908af 100644 --- a/gevent_async/worker.py +++ b/gevent_async/worker.py @@ -9,6 +9,7 @@ import gevent from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from gevent_async import activity, workflow @@ -39,7 +40,9 @@ async def async_main(): ) # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create an executor for use by Temporal. This cannot be the outer one # running this async main. The max_workers here needs to have enough room to diff --git a/hello/hello_activity.py b/hello/hello_activity.py index 13b5fcbb..69226772 100644 --- a/hello/hello_activity.py +++ b/hello/hello_activity.py @@ -5,6 +5,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -42,8 +43,12 @@ async def main(): # import logging # logging.basicConfig(level=logging.INFO) + # Load configuration + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_activity_async.py b/hello/hello_activity_async.py index fd14a2cf..6c1e195a 100644 --- a/hello/hello_activity_async.py +++ b/hello/hello_activity_async.py @@ -4,6 +4,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -42,7 +43,9 @@ async def main(): # logging.basicConfig(level=logging.INFO) # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_activity_choice.py b/hello/hello_activity_choice.py index 7d01b019..139d4006 100644 --- a/hello/hello_activity_choice.py +++ b/hello/hello_activity_choice.py @@ -7,6 +7,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker # Activities that will be called by the workflow @@ -80,8 +81,11 @@ async def run(self, shopping_list: ShoppingList) -> str: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_activity_heartbeat.py b/hello/hello_activity_heartbeat.py index 230621d3..a7a8ffe9 100644 --- a/hello/hello_activity_heartbeat.py +++ b/hello/hello_activity_heartbeat.py @@ -6,6 +6,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -41,7 +42,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_activity_method.py b/hello/hello_activity_method.py index db527263..0073ae45 100644 --- a/hello/hello_activity_method.py +++ b/hello/hello_activity_method.py @@ -3,6 +3,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -32,7 +33,9 @@ async def run(self) -> None: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create our database client that can then be used in the activity db_client = MyDatabaseClient() diff --git a/hello/hello_activity_multiprocess.py b/hello/hello_activity_multiprocess.py index 6630234d..5751a210 100644 --- a/hello/hello_activity_multiprocess.py +++ b/hello/hello_activity_multiprocess.py @@ -8,6 +8,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import SharedStateManager, Worker @@ -43,7 +44,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_activity_retry.py b/hello/hello_activity_retry.py index f1acd529..c5007dfb 100644 --- a/hello/hello_activity_retry.py +++ b/hello/hello_activity_retry.py @@ -6,6 +6,7 @@ from temporalio import activity, workflow from temporalio.client import Client from temporalio.common import RetryPolicy +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -45,7 +46,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_async_activity_completion.py b/hello/hello_async_activity_completion.py index 10aa89df..21a003df 100644 --- a/hello/hello_async_activity_completion.py +++ b/hello/hello_async_activity_completion.py @@ -4,6 +4,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -68,7 +69,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow composer = GreetingComposer(client) diff --git a/hello/hello_cancellation.py b/hello/hello_cancellation.py index 5bf38a66..aaf0aa90 100644 --- a/hello/hello_cancellation.py +++ b/hello/hello_cancellation.py @@ -7,6 +7,7 @@ from temporalio import activity, workflow from temporalio.client import Client, WorkflowFailureError +from temporalio.envconfig import ClientConfig from temporalio.exceptions import CancelledError from temporalio.worker import Worker @@ -50,8 +51,11 @@ async def run(self) -> None: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_change_log_level.py b/hello/hello_change_log_level.py index 89bb2e1d..4b7697f4 100644 --- a/hello/hello_change_log_level.py +++ b/hello/hello_change_log_level.py @@ -11,6 +11,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker # --- Begin logging set‑up ---------------------------------------------------------- @@ -50,7 +51,10 @@ async def run(self): async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + async with Worker( client, task_queue="hello-change-log-level-task-queue", diff --git a/hello/hello_child_workflow.py b/hello/hello_child_workflow.py index 2be0bc1b..6f99af5b 100644 --- a/hello/hello_child_workflow.py +++ b/hello/hello_child_workflow.py @@ -3,6 +3,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -31,8 +32,11 @@ async def run(self, name: str) -> str: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_continue_as_new.py b/hello/hello_continue_as_new.py index 586aac1d..a4947019 100644 --- a/hello/hello_continue_as_new.py +++ b/hello/hello_continue_as_new.py @@ -3,6 +3,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -22,7 +23,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_cron.py b/hello/hello_cron.py index dbb5cba6..cf1bc4b1 100644 --- a/hello/hello_cron.py +++ b/hello/hello_cron.py @@ -5,6 +5,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -33,7 +34,9 @@ async def run(self, name: str) -> None: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_exception.py b/hello/hello_exception.py index 628c10c5..a2d49633 100644 --- a/hello/hello_exception.py +++ b/hello/hello_exception.py @@ -8,6 +8,7 @@ from temporalio import activity, workflow from temporalio.client import Client, WorkflowFailureError from temporalio.common import RetryPolicy +from temporalio.envconfig import ClientConfig from temporalio.exceptions import FailureError from temporalio.worker import Worker @@ -39,7 +40,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_local_activity.py b/hello/hello_local_activity.py index 374c29c5..a1dd08ed 100644 --- a/hello/hello_local_activity.py +++ b/hello/hello_local_activity.py @@ -5,6 +5,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -32,7 +33,9 @@ async def run(self, name: str) -> str: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_parallel_activity.py b/hello/hello_parallel_activity.py index b32b02bb..680534ab 100644 --- a/hello/hello_parallel_activity.py +++ b/hello/hello_parallel_activity.py @@ -5,6 +5,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -41,7 +42,9 @@ async def run(self) -> List[str]: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_patch.py b/hello/hello_patch.py index e511ad5b..a26e5474 100644 --- a/hello/hello_patch.py +++ b/hello/hello_patch.py @@ -6,6 +6,7 @@ from temporalio import activity, exceptions, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -101,7 +102,9 @@ async def main(): # logging.basicConfig(level=logging.INFO) # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Set workflow_class to the proper class based on version workflow_class = "" diff --git a/hello/hello_query.py b/hello/hello_query.py index 8deb30ba..7ed132d1 100644 --- a/hello/hello_query.py +++ b/hello/hello_query.py @@ -2,6 +2,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -26,8 +27,11 @@ def greeting(self) -> str: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_search_attributes.py b/hello/hello_search_attributes.py index 8b504ea6..c858692a 100644 --- a/hello/hello_search_attributes.py +++ b/hello/hello_search_attributes.py @@ -2,6 +2,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -16,7 +17,9 @@ async def run(self) -> None: async def main(): # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_signal.py b/hello/hello_signal.py index a4f9b554..ed7ce7b3 100644 --- a/hello/hello_signal.py +++ b/hello/hello_signal.py @@ -3,6 +3,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -40,8 +41,11 @@ def exit(self) -> None: async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello/hello_update.py b/hello/hello_update.py index 111d95b1..4daa250a 100644 --- a/hello/hello_update.py +++ b/hello/hello_update.py @@ -2,6 +2,7 @@ from temporalio import workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -22,7 +23,9 @@ async def update_workflow_status(self) -> str: async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/hello_nexus/caller/app.py b/hello_nexus/caller/app.py index 40785b90..639456fa 100644 --- a/hello_nexus/caller/app.py +++ b/hello_nexus/caller/app.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from hello_nexus.caller.workflows import CallerWorkflow @@ -15,10 +16,12 @@ async def execute_caller_workflow( client: Optional[Client] = None, ) -> tuple[MyOutput, MyOutput]: - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if not client: + config = ClientConfig.load_client_connect_config() + # Override the namespace from config file. + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) async with Worker( client, diff --git a/hello_nexus/handler/worker.py b/hello_nexus/handler/worker.py index 0bdd6c01..ded9c5ab 100644 --- a/hello_nexus/handler/worker.py +++ b/hello_nexus/handler/worker.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from hello_nexus.handler.service_handler import MyNexusServiceHandler @@ -17,10 +18,12 @@ async def main(client: Optional[Client] = None): logging.basicConfig(level=logging.INFO) - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if not client: + config = ClientConfig.load_client_connect_config() + # Override the address and namespace from the config file. + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) # Start the worker, passing the Nexus service handler instance, in addition to the # workflow classes that are started by your nexus operations, and any activities diff --git a/langchain/starter.py b/langchain/starter.py index 2e3d0d5a..6d9e00c2 100644 --- a/langchain/starter.py +++ b/langchain/starter.py @@ -7,13 +7,18 @@ from fastapi import FastAPI, HTTPException from langchain_interceptor import LangChainContextPropagationInterceptor from temporalio.client import Client +from temporalio.envconfig import ClientConfig from workflow import LangChainWorkflow, TranslateWorkflowParams @asynccontextmanager async def lifespan(app: FastAPI): - app.state.temporal_client = await Client.connect( - "localhost:7233", interceptors=[LangChainContextPropagationInterceptor()] + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + + client = await Client.connect( + **config, + interceptors=[LangChainContextPropagationInterceptor()], ) yield diff --git a/langchain/worker.py b/langchain/worker.py index 1b680432..b7fb7741 100644 --- a/langchain/worker.py +++ b/langchain/worker.py @@ -3,6 +3,7 @@ from activities import translate_phrase from langchain_interceptor import LangChainContextPropagationInterceptor from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from workflow import LangChainChildWorkflow, LangChainWorkflow @@ -10,7 +11,10 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + worker = Worker( client, task_queue="langchain-task-queue", diff --git a/message_passing/introduction/starter.py b/message_passing/introduction/starter.py index b71dd44d..aa5b8967 100644 --- a/message_passing/introduction/starter.py +++ b/message_passing/introduction/starter.py @@ -2,6 +2,7 @@ from typing import Optional from temporalio.client import Client, WorkflowUpdateStage +from temporalio.envconfig import ClientConfig from message_passing.introduction import TASK_QUEUE from message_passing.introduction.workflows import ( @@ -14,7 +15,11 @@ async def main(client: Optional[Client] = None): - client = client or await Client.connect("localhost:7233") + if not client: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + wf_handle = await client.start_workflow( GreetingWorkflow.run, id="greeting-workflow-1234", diff --git a/message_passing/introduction/worker.py b/message_passing/introduction/worker.py index 25f4121f..34974801 100644 --- a/message_passing/introduction/worker.py +++ b/message_passing/introduction/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.introduction import TASK_QUEUE @@ -14,7 +15,9 @@ async def main(): logging.basicConfig(level=logging.INFO) - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async with Worker( client, diff --git a/message_passing/safe_message_handlers/starter.py b/message_passing/safe_message_handlers/starter.py index 7ffe13d9..9bc5c661 100644 --- a/message_passing/safe_message_handlers/starter.py +++ b/message_passing/safe_message_handlers/starter.py @@ -6,6 +6,7 @@ from temporalio import common from temporalio.client import Client, WorkflowHandle +from temporalio.envconfig import ClientConfig from message_passing.safe_message_handlers.workflow import ( ClusterManagerAssignNodesToJobInput, @@ -54,7 +55,9 @@ async def do_cluster_lifecycle(wf: WorkflowHandle, delay_seconds: Optional[int] async def main(should_test_continue_as_new: bool): # Connect to Temporal - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) print("Starting cluster") cluster_manager_handle = await client.start_workflow( diff --git a/message_passing/safe_message_handlers/worker.py b/message_passing/safe_message_handlers/worker.py index 34e71290..31e538d4 100644 --- a/message_passing/safe_message_handlers/worker.py +++ b/message_passing/safe_message_handlers/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.safe_message_handlers.workflow import ( @@ -16,7 +17,9 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async with Worker( client, diff --git a/message_passing/update_with_start/lazy_initialization/starter.py b/message_passing/update_with_start/lazy_initialization/starter.py index b3274f9d..ec874939 100644 --- a/message_passing/update_with_start/lazy_initialization/starter.py +++ b/message_passing/update_with_start/lazy_initialization/starter.py @@ -9,6 +9,7 @@ WorkflowHandle, WorkflowUpdateFailedError, ) +from temporalio.envconfig import ClientConfig from temporalio.exceptions import ApplicationError from message_passing.update_with_start.lazy_initialization import TASK_QUEUE @@ -61,12 +62,14 @@ async def handle_add_item_request( async def main(): print("πŸ›’") session_id = f"session-{uuid.uuid4()}" - temporal_client = await Client.connect("localhost:7233") - subtotal_1, _ = await handle_add_item_request( - session_id, "sku-123", 1, temporal_client - ) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + + subtotal_1, _ = await handle_add_item_request(session_id, "sku-123", 1, client) subtotal_2, wf_handle = await handle_add_item_request( - session_id, "sku-456", 1, temporal_client + session_id, "sku-456", 1, client ) print(f"subtotals were, {[subtotal_1, subtotal_2]}") await wf_handle.signal(ShoppingCartWorkflow.checkout) diff --git a/message_passing/update_with_start/lazy_initialization/worker.py b/message_passing/update_with_start/lazy_initialization/worker.py index 1964b43e..1cc4f6ff 100644 --- a/message_passing/update_with_start/lazy_initialization/worker.py +++ b/message_passing/update_with_start/lazy_initialization/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.update_with_start.lazy_initialization import TASK_QUEUE, workflows @@ -13,7 +14,9 @@ async def main(): logging.basicConfig(level=logging.INFO) - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async with Worker( client, diff --git a/message_passing/waiting_for_handlers/starter.py b/message_passing/waiting_for_handlers/starter.py index 908095c5..76829e0b 100644 --- a/message_passing/waiting_for_handlers/starter.py +++ b/message_passing/waiting_for_handlers/starter.py @@ -1,6 +1,7 @@ import asyncio from temporalio import client, common +from temporalio.envconfig import ClientConfig from message_passing.waiting_for_handlers import ( TASK_QUEUE, @@ -12,7 +13,10 @@ async def starter(exit_type: WorkflowExitType): - cl = await client.Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + cl = await client.Client.connect(**config) + wf_handle = await cl.start_workflow( WaitingForHandlersWorkflow.run, WorkflowInput(exit_type=exit_type), diff --git a/message_passing/waiting_for_handlers/worker.py b/message_passing/waiting_for_handlers/worker.py index 9eea60a3..e32a2dcb 100644 --- a/message_passing/waiting_for_handlers/worker.py +++ b/message_passing/waiting_for_handlers/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.waiting_for_handlers import TASK_QUEUE @@ -16,7 +17,9 @@ async def main(): logging.basicConfig(level=logging.INFO) - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async with Worker( client, diff --git a/message_passing/waiting_for_handlers_and_compensation/starter.py b/message_passing/waiting_for_handlers_and_compensation/starter.py index 812bee5f..fbc5ae04 100644 --- a/message_passing/waiting_for_handlers_and_compensation/starter.py +++ b/message_passing/waiting_for_handlers_and_compensation/starter.py @@ -1,6 +1,7 @@ import asyncio from temporalio import client, common +from temporalio.envconfig import ClientConfig from message_passing.waiting_for_handlers_and_compensation import ( TASK_QUEUE, @@ -14,7 +15,10 @@ async def starter(exit_type: WorkflowExitType): - cl = await client.Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + cl = await client.Client.connect(**config) + wf_handle = await cl.start_workflow( WaitingForHandlersAndCompensationWorkflow.run, WorkflowInput(exit_type=exit_type), diff --git a/message_passing/waiting_for_handlers_and_compensation/worker.py b/message_passing/waiting_for_handlers_and_compensation/worker.py index 7daf768f..2a27769d 100644 --- a/message_passing/waiting_for_handlers_and_compensation/worker.py +++ b/message_passing/waiting_for_handlers_and_compensation/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.waiting_for_handlers_and_compensation import TASK_QUEUE @@ -19,8 +20,9 @@ async def main(): logging.basicConfig(level=logging.INFO) - - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async with Worker( client, diff --git a/nexus_multiple_args/caller/app.py b/nexus_multiple_args/caller/app.py index 88aadbf9..b4d7ebc3 100644 --- a/nexus_multiple_args/caller/app.py +++ b/nexus_multiple_args/caller/app.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from nexus_multiple_args.caller.workflows import CallerWorkflow @@ -14,10 +15,11 @@ async def execute_caller_workflow( client: Optional[Client] = None, ) -> tuple[str, str]: - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if client is None: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) async with Worker( client, diff --git a/nexus_multiple_args/handler/worker.py b/nexus_multiple_args/handler/worker.py index d12a7ee1..079d08ae 100644 --- a/nexus_multiple_args/handler/worker.py +++ b/nexus_multiple_args/handler/worker.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from nexus_multiple_args.handler.service_handler import MyNexusServiceHandler @@ -17,10 +18,11 @@ async def main(client: Optional[Client] = None): logging.basicConfig(level=logging.INFO) - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if client is None: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) # Start the worker, passing the Nexus service handler instance, in addition to the # workflow classes that are started by your nexus operations, and any activities diff --git a/nexus_sync_operations/caller/app.py b/nexus_sync_operations/caller/app.py index 4966415c..375628d2 100644 --- a/nexus_sync_operations/caller/app.py +++ b/nexus_sync_operations/caller/app.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from nexus_sync_operations.caller.workflows import CallerWorkflow @@ -14,10 +15,11 @@ async def execute_caller_workflow( client: Optional[Client] = None, ) -> None: - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if client is None: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) async with Worker( client, diff --git a/nexus_sync_operations/handler/worker.py b/nexus_sync_operations/handler/worker.py index 5545adc0..7783055a 100644 --- a/nexus_sync_operations/handler/worker.py +++ b/nexus_sync_operations/handler/worker.py @@ -3,6 +3,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from message_passing.introduction.activities import call_greeting_service @@ -18,10 +19,11 @@ async def main(client: Optional[Client] = None): logging.basicConfig(level=logging.INFO) - client = client or await Client.connect( - "localhost:7233", - namespace=NAMESPACE, - ) + if client is None: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE), + client = await Client.connect(**config) # Create the nexus service handler instance, starting the long-running entity workflow that # backs the Nexus service diff --git a/open_telemetry/starter.py b/open_telemetry/starter.py index 86360368..9e8650b0 100644 --- a/open_telemetry/starter.py +++ b/open_telemetry/starter.py @@ -2,6 +2,7 @@ from temporalio.client import Client from temporalio.contrib.opentelemetry import TracingInterceptor +from temporalio.envconfig import ClientConfig from open_telemetry.worker import GreetingWorkflow, init_runtime_with_telemetry @@ -9,9 +10,11 @@ async def main(): runtime = init_runtime_with_telemetry() + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use OpenTelemetry interceptor interceptors=[TracingInterceptor()], runtime=runtime, diff --git a/open_telemetry/worker.py b/open_telemetry/worker.py index 04095ca7..631bd008 100644 --- a/open_telemetry/worker.py +++ b/open_telemetry/worker.py @@ -9,6 +9,7 @@ from temporalio import activity, workflow from temporalio.client import Client from temporalio.contrib.opentelemetry import TracingInterceptor +from temporalio.envconfig import ClientConfig from temporalio.runtime import OpenTelemetryConfig, Runtime, TelemetryConfig from temporalio.worker import Worker @@ -50,9 +51,12 @@ def init_runtime_with_telemetry() -> Runtime: async def main(): runtime = init_runtime_with_telemetry() + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, # Use OpenTelemetry interceptor interceptors=[TracingInterceptor()], runtime=runtime, diff --git a/openai_agents/basic/run_agent_lifecycle_workflow.py b/openai_agents/basic/run_agent_lifecycle_workflow.py index 7d3d8619..2cd16c60 100644 --- a/openai_agents/basic/run_agent_lifecycle_workflow.py +++ b/openai_agents/basic/run_agent_lifecycle_workflow.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from openai_agents.basic.workflows.agent_lifecycle_workflow import ( AgentLifecycleWorkflow, @@ -8,7 +9,9 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) user_input = input("Enter a max number: ") max_number = int(user_input) diff --git a/openai_agents/basic/run_remote_image_workflow.py b/openai_agents/basic/run_remote_image_workflow.py index f7c41b9a..f2175f7f 100644 --- a/openai_agents/basic/run_remote_image_workflow.py +++ b/openai_agents/basic/run_remote_image_workflow.py @@ -2,16 +2,18 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.basic.workflows.remote_image_workflow import RemoteImageWorkflow async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect( - "localhost:7233", - plugins=[ - OpenAIAgentsPlugin(), - ], + **config, + plugins=[OpenAIAgentsPlugin()], ) # Use the URL from the original example diff --git a/openai_agents/handoffs/run_message_filter_workflow.py b/openai_agents/handoffs/run_message_filter_workflow.py index 7ecb9f47..c2b2ba3d 100644 --- a/openai_agents/handoffs/run_message_filter_workflow.py +++ b/openai_agents/handoffs/run_message_filter_workflow.py @@ -3,6 +3,7 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.handoffs.workflows.message_filter_workflow import ( MessageFilterWorkflow, @@ -10,9 +11,12 @@ async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Create client connected to server at the given address client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin(), ], diff --git a/openai_agents/mcp/run_file_system_worker.py b/openai_agents/mcp/run_file_system_worker.py index 0eb440bb..f7bd2909 100644 --- a/openai_agents/mcp/run_file_system_worker.py +++ b/openai_agents/mcp/run_file_system_worker.py @@ -12,6 +12,7 @@ OpenAIAgentsPlugin, StatelessMCPServerProvider, ) +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from openai_agents.mcp.workflows.file_system_workflow import FileSystemWorkflow @@ -33,8 +34,10 @@ async def main(): ) # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( diff --git a/openai_agents/mcp/run_file_system_workflow.py b/openai_agents/mcp/run_file_system_workflow.py index a52e7d56..d076d3d5 100644 --- a/openai_agents/mcp/run_file_system_workflow.py +++ b/openai_agents/mcp/run_file_system_workflow.py @@ -2,14 +2,17 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.mcp.workflows.file_system_workflow import FileSystemWorkflow async def main(): # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin(), ], diff --git a/openai_agents/mcp/run_memory_research_scratchpad_worker.py b/openai_agents/mcp/run_memory_research_scratchpad_worker.py index fb1d8494..5e5f4b00 100644 --- a/openai_agents/mcp/run_memory_research_scratchpad_worker.py +++ b/openai_agents/mcp/run_memory_research_scratchpad_worker.py @@ -11,6 +11,7 @@ OpenAIAgentsPlugin, StatefulMCPServerProvider, ) +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from openai_agents.mcp.workflows.memory_research_scratchpad_workflow import ( @@ -32,8 +33,10 @@ async def main(): ) # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( diff --git a/openai_agents/mcp/run_memory_research_scratchpad_workflow.py b/openai_agents/mcp/run_memory_research_scratchpad_workflow.py index 03969fb4..bf724f9a 100644 --- a/openai_agents/mcp/run_memory_research_scratchpad_workflow.py +++ b/openai_agents/mcp/run_memory_research_scratchpad_workflow.py @@ -4,6 +4,7 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.mcp.workflows.memory_research_scratchpad_workflow import ( MemoryResearchScratchpadWorkflow, @@ -11,9 +12,13 @@ async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", - plugins=[OpenAIAgentsPlugin()], + **config, + plugins=[ + OpenAIAgentsPlugin(), + ], ) result = await client.execute_workflow( diff --git a/openai_agents/mcp/run_prompt_server_worker.py b/openai_agents/mcp/run_prompt_server_worker.py index e390c0ac..cff8d1d7 100644 --- a/openai_agents/mcp/run_prompt_server_worker.py +++ b/openai_agents/mcp/run_prompt_server_worker.py @@ -11,6 +11,7 @@ OpenAIAgentsPlugin, StatelessMCPServerProvider, ) +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from openai_agents.mcp.workflows.prompt_server_workflow import PromptServerWorkflow @@ -32,8 +33,10 @@ async def main(): ) # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( diff --git a/openai_agents/mcp/run_prompt_server_workflow.py b/openai_agents/mcp/run_prompt_server_workflow.py index 79e4bf65..9cad2725 100644 --- a/openai_agents/mcp/run_prompt_server_workflow.py +++ b/openai_agents/mcp/run_prompt_server_workflow.py @@ -4,14 +4,17 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.mcp.workflows.prompt_server_workflow import PromptServerWorkflow async def main(): # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[OpenAIAgentsPlugin()], ) diff --git a/openai_agents/mcp/run_sse_worker.py b/openai_agents/mcp/run_sse_worker.py index 406e65bf..d9f9dd38 100644 --- a/openai_agents/mcp/run_sse_worker.py +++ b/openai_agents/mcp/run_sse_worker.py @@ -11,6 +11,7 @@ OpenAIAgentsPlugin, StatelessMCPServerProvider, ) +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from openai_agents.mcp.workflows.sse_workflow import SseWorkflow @@ -32,8 +33,10 @@ async def main(): ) # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( diff --git a/openai_agents/mcp/run_sse_workflow.py b/openai_agents/mcp/run_sse_workflow.py index 42a45596..8effd5fe 100644 --- a/openai_agents/mcp/run_sse_workflow.py +++ b/openai_agents/mcp/run_sse_workflow.py @@ -4,14 +4,17 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.mcp.workflows.sse_workflow import SseWorkflow async def main(): # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[OpenAIAgentsPlugin()], ) diff --git a/openai_agents/mcp/run_streamable_http_worker.py b/openai_agents/mcp/run_streamable_http_worker.py index 9c178b6f..210634bb 100644 --- a/openai_agents/mcp/run_streamable_http_worker.py +++ b/openai_agents/mcp/run_streamable_http_worker.py @@ -11,6 +11,7 @@ OpenAIAgentsPlugin, StatelessMCPServerProvider, ) +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from openai_agents.mcp.workflows.streamable_http_workflow import StreamableHttpWorkflow @@ -32,8 +33,10 @@ async def main(): ) # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[ OpenAIAgentsPlugin( model_params=ModelActivityParameters( diff --git a/openai_agents/mcp/run_streamable_http_workflow.py b/openai_agents/mcp/run_streamable_http_workflow.py index aa5d1bac..b691e456 100644 --- a/openai_agents/mcp/run_streamable_http_workflow.py +++ b/openai_agents/mcp/run_streamable_http_workflow.py @@ -4,14 +4,17 @@ from temporalio.client import Client from temporalio.contrib.openai_agents import OpenAIAgentsPlugin +from temporalio.envconfig import ClientConfig from openai_agents.mcp.workflows.streamable_http_workflow import StreamableHttpWorkflow async def main(): # Create client connected to server at the given address + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect( - "localhost:7233", + **config, plugins=[OpenAIAgentsPlugin()], ) diff --git a/patching/starter.py b/patching/starter.py index 9e6d7f31..f1b92f32 100644 --- a/patching/starter.py +++ b/patching/starter.py @@ -2,6 +2,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig # Since it's just used for typing purposes, it doesn't matter which one we # import @@ -17,7 +18,9 @@ async def main(): raise RuntimeError("Either --start-workflow or --query-workflow is required") # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) if args.start_workflow: handle = await client.start_workflow( diff --git a/patching/worker.py b/patching/worker.py index 8f1e3c82..417c8ef9 100644 --- a/patching/worker.py +++ b/patching/worker.py @@ -2,6 +2,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from patching.activities import post_patch_activity, pre_patch_activity @@ -30,7 +31,9 @@ async def main(): raise RuntimeError("Unrecognized workflow") # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/polling/frequent/run_frequent.py b/polling/frequent/run_frequent.py index 664a677c..42048092 100644 --- a/polling/frequent/run_frequent.py +++ b/polling/frequent/run_frequent.py @@ -1,12 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from polling.frequent.workflows import GreetingWorkflow async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + result = await client.execute_workflow( GreetingWorkflow.run, "World", diff --git a/polling/frequent/run_worker.py b/polling/frequent/run_worker.py index 00fcc27e..cf5ccb78 100644 --- a/polling/frequent/run_worker.py +++ b/polling/frequent/run_worker.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from polling.frequent.activities import compose_greeting @@ -8,7 +9,9 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) worker = Worker( client, diff --git a/polling/infrequent/run_infrequent.py b/polling/infrequent/run_infrequent.py index 7cf206f2..8a0ea871 100644 --- a/polling/infrequent/run_infrequent.py +++ b/polling/infrequent/run_infrequent.py @@ -1,12 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from polling.infrequent.workflows import GreetingWorkflow async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + result = await client.execute_workflow( GreetingWorkflow.run, "World", diff --git a/polling/infrequent/run_worker.py b/polling/infrequent/run_worker.py index f600b949..f52a8082 100644 --- a/polling/infrequent/run_worker.py +++ b/polling/infrequent/run_worker.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from polling.infrequent.activities import compose_greeting @@ -8,7 +9,9 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) worker = Worker( client, diff --git a/polling/periodic_sequence/run_periodic.py b/polling/periodic_sequence/run_periodic.py index f2ddcf7a..393fb8be 100644 --- a/polling/periodic_sequence/run_periodic.py +++ b/polling/periodic_sequence/run_periodic.py @@ -1,12 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from polling.periodic_sequence.workflows import GreetingWorkflow async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + result = await client.execute_workflow( GreetingWorkflow.run, "World", diff --git a/polling/periodic_sequence/run_worker.py b/polling/periodic_sequence/run_worker.py index e04ac4dc..9689ef2f 100644 --- a/polling/periodic_sequence/run_worker.py +++ b/polling/periodic_sequence/run_worker.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from polling.periodic_sequence.activities import compose_greeting @@ -8,7 +9,9 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) worker = Worker( client, diff --git a/prometheus/starter.py b/prometheus/starter.py index b94f5601..571aee07 100644 --- a/prometheus/starter.py +++ b/prometheus/starter.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from prometheus.worker import GreetingWorkflow, init_runtime_with_prometheus @@ -10,9 +11,12 @@ async def main(): runtime = init_runtime_with_prometheus(9001) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, runtime=runtime, ) diff --git a/prometheus/worker.py b/prometheus/worker.py index 5e7d64ab..b41b75c5 100644 --- a/prometheus/worker.py +++ b/prometheus/worker.py @@ -3,6 +3,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.runtime import PrometheusConfig, Runtime, TelemetryConfig from temporalio.worker import Worker @@ -38,9 +39,12 @@ def init_runtime_with_prometheus(port: int) -> Runtime: async def main(): runtime = init_runtime_with_prometheus(9000) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client client = await Client.connect( - "localhost:7233", + **config, runtime=runtime, ) diff --git a/pydantic_converter/starter.py b/pydantic_converter/starter.py index 7cc4cc2d..47766be6 100644 --- a/pydantic_converter/starter.py +++ b/pydantic_converter/starter.py @@ -5,15 +5,22 @@ from temporalio.client import Client from temporalio.contrib.pydantic import pydantic_data_converter +from temporalio.envconfig import ClientConfig from pydantic_converter.worker import MyPydanticModel, MyWorkflow async def main(): logging.basicConfig(level=logging.INFO) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client using the Pydantic converter + client = await Client.connect( - "localhost:7233", data_converter=pydantic_data_converter + **config, + data_converter=pydantic_data_converter, ) # Run workflow diff --git a/pydantic_converter/worker.py b/pydantic_converter/worker.py index eac0966c..8acc1125 100644 --- a/pydantic_converter/worker.py +++ b/pydantic_converter/worker.py @@ -6,6 +6,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker # Always pass through external modules to the sandbox that you know are safe for @@ -41,9 +42,14 @@ async def run(self, models: List[MyPydanticModel]) -> List[MyPydanticModel]: async def main(): logging.basicConfig(level=logging.INFO) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client using the Pydantic converter client = await Client.connect( - "localhost:7233", data_converter=pydantic_data_converter + **config, + data_converter=pydantic_data_converter, ) # Run a worker for the workflow diff --git a/pydantic_converter_v1/starter.py b/pydantic_converter_v1/starter.py index 8ab58bdc..33b0ad28 100644 --- a/pydantic_converter_v1/starter.py +++ b/pydantic_converter_v1/starter.py @@ -4,6 +4,7 @@ from ipaddress import IPv4Address from temporalio.client import Client +from temporalio.envconfig import ClientConfig from pydantic_converter_v1.converter import pydantic_data_converter from pydantic_converter_v1.worker import MyPydanticModel, MyWorkflow @@ -11,9 +12,15 @@ async def main(): logging.basicConfig(level=logging.INFO) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client using the Pydantic converter + client = await Client.connect( - "localhost:7233", data_converter=pydantic_data_converter + **config, + data_converter=pydantic_data_converter, ) # Run workflow diff --git a/pydantic_converter_v1/worker.py b/pydantic_converter_v1/worker.py index 5c22b6f1..5ff65e1e 100644 --- a/pydantic_converter_v1/worker.py +++ b/pydantic_converter_v1/worker.py @@ -7,6 +7,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from temporalio.worker.workflow_sandbox import ( SandboxedWorkflowRunner, @@ -70,9 +71,14 @@ def new_sandbox_runner() -> SandboxedWorkflowRunner: async def main(): logging.basicConfig(level=logging.INFO) + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client using the Pydantic converter + client = await Client.connect( - "localhost:7233", data_converter=pydantic_data_converter + **config, + data_converter=pydantic_data_converter, ) # Run a worker for the workflow diff --git a/replay/replayer.py b/replay/replayer.py index 49f16313..4787b33b 100644 --- a/replay/replayer.py +++ b/replay/replayer.py @@ -1,6 +1,7 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Replayer from replay.worker import JustActivity, JustTimer, TimerThenActivity @@ -8,7 +9,9 @@ async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Fetch the histories of the workflows to be replayed workflows = client.list_workflows('WorkflowId="replayer-workflow-id"') diff --git a/replay/starter.py b/replay/starter.py index daf07098..228e50c3 100644 --- a/replay/starter.py +++ b/replay/starter.py @@ -1,13 +1,16 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from replay.worker import JustActivity, JustTimer, TimerThenActivity async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a few workflows # Importantly, normally we would *not* advise re-using the same workflow ID for all of these, diff --git a/replay/worker.py b/replay/worker.py index 3aebc099..4ac57da2 100644 --- a/replay/worker.py +++ b/replay/worker.py @@ -5,6 +5,7 @@ from temporalio import activity, workflow from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker @@ -71,7 +72,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/resource_pool/starter.py b/resource_pool/starter.py index 2ae1ab44..2a50357a 100644 --- a/resource_pool/starter.py +++ b/resource_pool/starter.py @@ -3,6 +3,7 @@ from temporalio.client import Client, WorkflowFailureError, WorkflowHandle from temporalio.common import WorkflowIDConflictPolicy +from temporalio.envconfig import ClientConfig from resource_pool.pool_client.resource_pool_workflow import ( ResourcePoolWorkflow, @@ -17,7 +18,9 @@ async def main() -> None: # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Initialize the resource pool resource_pool_handle = await client.start_workflow( diff --git a/resource_pool/worker.py b/resource_pool/worker.py index cb3a06dd..253e5f8e 100644 --- a/resource_pool/worker.py +++ b/resource_pool/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from resource_pool.pool_client.resource_pool_workflow import ResourcePoolWorkflow @@ -12,7 +13,9 @@ async def main() -> None: logging.basicConfig(level=logging.INFO) # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow worker = Worker( diff --git a/schedules/backfill_schedule.py b/schedules/backfill_schedule.py index 769b6a78..708ad07f 100644 --- a/schedules/backfill_schedule.py +++ b/schedules/backfill_schedule.py @@ -2,10 +2,14 @@ from datetime import datetime, timedelta from temporalio.client import Client, ScheduleBackfill, ScheduleOverlapPolicy +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/schedules/delete_schedule.py b/schedules/delete_schedule.py index b6265636..d7b64394 100644 --- a/schedules/delete_schedule.py +++ b/schedules/delete_schedule.py @@ -1,10 +1,14 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/schedules/describe_schedule.py b/schedules/describe_schedule.py index 22bb832d..0db3fba5 100644 --- a/schedules/describe_schedule.py +++ b/schedules/describe_schedule.py @@ -1,10 +1,14 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/schedules/list_schedule.py b/schedules/list_schedule.py index a863aeee..15c0fd6a 100644 --- a/schedules/list_schedule.py +++ b/schedules/list_schedule.py @@ -1,10 +1,13 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig async def main() -> None: - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) async for schedule in await client.list_schedules(): print(f"List Schedule Info: {schedule.info}.") diff --git a/schedules/pause_schedule.py b/schedules/pause_schedule.py index a6f8721c..79a9ca03 100644 --- a/schedules/pause_schedule.py +++ b/schedules/pause_schedule.py @@ -1,10 +1,14 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/schedules/run_worker.py b/schedules/run_worker.py index 5252b1f7..00d14aaa 100644 --- a/schedules/run_worker.py +++ b/schedules/run_worker.py @@ -1,13 +1,17 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from your_activities import your_activity from your_workflows import YourSchedulesWorkflow async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + worker = Worker( client, task_queue="schedules-task-queue", diff --git a/schedules/start_schedule.py b/schedules/start_schedule.py index 6089be95..ead6202b 100644 --- a/schedules/start_schedule.py +++ b/schedules/start_schedule.py @@ -9,11 +9,15 @@ ScheduleSpec, ScheduleState, ) +from temporalio.envconfig import ClientConfig from your_workflows import YourSchedulesWorkflow async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + await client.create_schedule( "workflow-schedule-id", Schedule( diff --git a/schedules/trigger_schedule.py b/schedules/trigger_schedule.py index ca1f38f1..30939d32 100644 --- a/schedules/trigger_schedule.py +++ b/schedules/trigger_schedule.py @@ -1,10 +1,14 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/schedules/update_schedule.py b/schedules/update_schedule.py index 979c23a8..709eeda3 100644 --- a/schedules/update_schedule.py +++ b/schedules/update_schedule.py @@ -6,10 +6,14 @@ ScheduleUpdate, ScheduleUpdateInput, ) +from temporalio.envconfig import ClientConfig async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_schedule_handle( "workflow-schedule-id", ) diff --git a/sentry/starter.py b/sentry/starter.py index 372a732c..aa3f6271 100644 --- a/sentry/starter.py +++ b/sentry/starter.py @@ -1,13 +1,17 @@ import asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from sentry.workflow import SentryExampleWorkflow, SentryExampleWorkflowInput async def main(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Connect client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run workflow try: diff --git a/sentry/worker.py b/sentry/worker.py index 723b8e52..1bcd153e 100644 --- a/sentry/worker.py +++ b/sentry/worker.py @@ -5,6 +5,7 @@ from sentry_sdk.integrations.asyncio import AsyncioIntegration from sentry_sdk.types import Event, Hint from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from temporalio.worker.workflow_sandbox import ( SandboxedWorkflowRunner, @@ -51,8 +52,11 @@ async def main(): # Initialize the Sentry SDK initialise_sentry() + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + # Start client - client = await Client.connect("localhost:7233") + client = await Client.connect(**config) # Run a worker for the workflow async with Worker( diff --git a/sleep_for_days/starter.py b/sleep_for_days/starter.py index 765842b2..98dc083d 100644 --- a/sleep_for_days/starter.py +++ b/sleep_for_days/starter.py @@ -3,13 +3,18 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from sleep_for_days import TASK_QUEUE from sleep_for_days.workflows import SleepForDaysWorkflow async def main(client: Optional[Client] = None): - client = client or await Client.connect("localhost:7233") + if not client: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + wf_handle = await client.start_workflow( SleepForDaysWorkflow.run, id=f"sleep-for-days-workflow-id-{uuid.uuid4()}", diff --git a/sleep_for_days/worker.py b/sleep_for_days/worker.py index d03ec726..59799607 100644 --- a/sleep_for_days/worker.py +++ b/sleep_for_days/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from sleep_for_days import TASK_QUEUE @@ -10,7 +11,9 @@ async def main(): - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) worker = Worker( client, diff --git a/trio_async/starter.py b/trio_async/starter.py index 67f7568b..6535ca98 100644 --- a/trio_async/starter.py +++ b/trio_async/starter.py @@ -2,6 +2,7 @@ import trio_asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from trio_async import workflows @@ -11,7 +12,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Execute the workflow result = await client.execute_workflow( diff --git a/trio_async/worker.py b/trio_async/worker.py index 29f059b4..f1c2a30b 100644 --- a/trio_async/worker.py +++ b/trio_async/worker.py @@ -5,6 +5,7 @@ import trio_asyncio from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from trio_async import activities, workflows @@ -15,7 +16,9 @@ async def main(): logging.basicConfig(level=logging.INFO) # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Temporal runs threaded activities and workflow tasks via run_in_executor. # Due to how trio_asyncio works, you can only do run_in_executor with their diff --git a/updatable_timer/starter.py b/updatable_timer/starter.py index 88b4d0d4..8ce0f4f9 100644 --- a/updatable_timer/starter.py +++ b/updatable_timer/starter.py @@ -5,6 +5,7 @@ from temporalio import exceptions from temporalio.client import Client +from temporalio.envconfig import ClientConfig from updatable_timer import TASK_QUEUE from updatable_timer.workflow import Workflow @@ -13,7 +14,10 @@ async def main(client: Optional[Client] = None): logging.basicConfig(level=logging.INFO) - client = client or await Client.connect("localhost:7233") + if not client: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) try: handle = await client.start_workflow( Workflow.run, diff --git a/updatable_timer/wake_up_time_updater.py b/updatable_timer/wake_up_time_updater.py index f406c186..43d24838 100644 --- a/updatable_timer/wake_up_time_updater.py +++ b/updatable_timer/wake_up_time_updater.py @@ -4,6 +4,7 @@ from typing import Optional from temporalio.client import Client +from temporalio.envconfig import ClientConfig from updatable_timer.workflow import Workflow @@ -11,7 +12,11 @@ async def main(client: Optional[Client] = None): logging.basicConfig(level=logging.INFO) - client = client or await Client.connect("localhost:7233") + if not client: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + handle = client.get_workflow_handle(workflow_id="updatable-timer-workflow") # signal workflow about the wake up time change await handle.signal( diff --git a/updatable_timer/worker.py b/updatable_timer/worker.py index 096fa1ff..8bb3d47a 100644 --- a/updatable_timer/worker.py +++ b/updatable_timer/worker.py @@ -2,6 +2,7 @@ import logging from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from updatable_timer import TASK_QUEUE @@ -13,7 +14,10 @@ async def main(): logging.basicConfig(level=logging.INFO) - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + async with Worker( client, task_queue=TASK_QUEUE, diff --git a/uv.lock b/uv.lock index 73424b77..7ec7d623 100644 --- a/uv.lock +++ b/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.13'", @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "black" version = "22.12.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -196,7 +196,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -210,7 +210,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -219,7 +219,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pycparser" }, ] @@ -276,7 +276,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -337,7 +337,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -349,7 +349,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -358,7 +358,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi" }, ] @@ -381,7 +381,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -390,7 +390,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -403,7 +403,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -412,7 +412,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -424,7 +424,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -438,7 +438,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -447,7 +447,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -541,7 +541,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -550,7 +550,7 @@ wheels = [ [[package]] name = "gevent" version = "25.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -598,7 +598,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -610,7 +610,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -661,7 +661,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama" }, ] @@ -673,7 +673,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.73.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/79/e8/b43b851537da2e2f03fa8be1aef207e5cbfb1a2e014fbb6b40d24c177cd3/grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87", size = 12730355, upload-time = "2025-06-26T01:53:24.622Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/51/a5748ab2773d893d099b92653039672f7e26dd35741020972b84d604066f/grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55", size = 5365087, upload-time = "2025-06-26T01:51:44.541Z" }, @@ -721,7 +721,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -730,7 +730,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -745,7 +745,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -758,7 +758,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -794,7 +794,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -809,7 +809,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -818,7 +818,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -837,7 +837,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -846,7 +846,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "zipp" }, ] @@ -858,7 +858,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -867,7 +867,7 @@ wheels = [ [[package]] name = "isort" version = "5.13.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markupsafe" }, ] @@ -888,7 +888,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -960,7 +960,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpointer" }, ] @@ -981,7 +981,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -990,7 +990,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "referencing" }, ] @@ -1017,7 +1017,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1041,7 +1041,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1061,7 +1061,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1078,7 +1078,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, ] @@ -1105,7 +1105,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1121,7 +1121,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mdurl" }, ] @@ -1155,7 +1155,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "packaging" }, ] @@ -1225,7 +1225,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1247,7 +1247,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1256,7 +1256,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1358,7 +1358,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1397,7 +1397,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -1418,7 +1418,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1427,7 +1427,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1501,7 +1501,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1526,7 +1526,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -1556,7 +1556,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1570,7 +1570,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1583,7 +1583,7 @@ wheels = [ [[package]] name = "orjson" version = "3.10.18" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810, upload-time = "2025-04-29T23:30:08.423Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927, upload-time = "2025-04-29T23:28:08.643Z" }, @@ -1649,7 +1649,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, ] @@ -1661,7 +1661,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1670,7 +1670,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1718,7 +1718,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1727,7 +1727,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1736,7 +1736,7 @@ wheels = [ [[package]] name = "platformdirs" version = "4.3.8" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1745,7 +1745,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1754,7 +1754,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1768,7 +1768,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1857,7 +1857,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1871,7 +1871,7 @@ wheels = [ [[package]] name = "pyarrow" version = "20.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/23/77094eb8ee0dbe88441689cb6afc40ac312a1e15d3a7acc0586999518222/pyarrow-20.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c7dd06fd7d7b410ca5dc839cc9d485d2bc4ae5240851bcd45d85105cc90a47d7", size = 30832591, upload-time = "2025-04-27T12:27:27.89Z" }, @@ -1924,7 +1924,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1933,7 +1933,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1948,7 +1948,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2035,7 +2035,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2049,7 +2049,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2058,7 +2058,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2071,7 +2071,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2088,7 +2088,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, ] @@ -2101,7 +2101,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2114,7 +2114,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "six" }, ] @@ -2126,7 +2126,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2135,7 +2135,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2144,7 +2144,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2153,7 +2153,7 @@ wheels = [ [[package]] name = "pywin32" version = "310" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, @@ -2172,7 +2172,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2216,7 +2216,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2230,7 +2230,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2299,7 +2299,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2314,7 +2314,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "requests" }, ] @@ -2326,7 +2326,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2340,7 +2340,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2466,7 +2466,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, ] @@ -2478,7 +2478,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2500,7 +2500,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2509,7 +2509,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2518,7 +2518,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2527,7 +2527,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2572,7 +2572,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2760,7 +2760,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2769,7 +2769,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2805,7 +2805,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2830,7 +2830,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2869,7 +2869,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2881,7 +2881,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2899,7 +2899,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2915,7 +2915,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -2924,7 +2924,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -2933,7 +2933,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "urllib3" }, ] @@ -2945,7 +2945,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2954,7 +2954,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -2967,7 +2967,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2979,7 +2979,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2988,7 +2988,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -2997,7 +2997,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3022,7 +3022,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3054,7 +3054,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -3154,7 +3154,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3213,7 +3213,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3312,7 +3312,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3321,7 +3321,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] @@ -3333,7 +3333,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] diff --git a/worker_specific_task_queues/starter.py b/worker_specific_task_queues/starter.py index c55c63be..61009436 100644 --- a/worker_specific_task_queues/starter.py +++ b/worker_specific_task_queues/starter.py @@ -2,13 +2,16 @@ from uuid import uuid4 from temporalio.client import Client +from temporalio.envconfig import ClientConfig from worker_specific_task_queues.tasks import FileProcessing async def main(): # Connect client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Start 10 concurrent workflows futures = [] diff --git a/worker_specific_task_queues/worker.py b/worker_specific_task_queues/worker.py index 30ea18b6..95824cfd 100644 --- a/worker_specific_task_queues/worker.py +++ b/worker_specific_task_queues/worker.py @@ -6,6 +6,7 @@ from temporalio import activity from temporalio.client import Client +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker from worker_specific_task_queues import tasks @@ -31,7 +32,9 @@ async def select_task_queue() -> str: return task_queue # Start client - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Run a worker to distribute the workflows run_futures = [] diff --git a/worker_versioning/app.py b/worker_versioning/app.py index 8b32aa94..78e1d641 100644 --- a/worker_versioning/app.py +++ b/worker_versioning/app.py @@ -5,6 +5,7 @@ import uuid from temporalio.client import Client +from temporalio.envconfig import ClientConfig TASK_QUEUE = "worker-versioning" DEPLOYMENT_NAME = "my-deployment" @@ -13,7 +14,9 @@ async def main() -> None: - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Wait for v1 worker and set as current version logging.info( diff --git a/worker_versioning/workerv1.py b/worker_versioning/workerv1.py index 13c4ed4b..221b5ca9 100644 --- a/worker_versioning/workerv1.py +++ b/worker_versioning/workerv1.py @@ -5,6 +5,7 @@ from temporalio.client import Client from temporalio.common import WorkerDeploymentVersion +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker, WorkerDeploymentConfig from worker_versioning.activities import some_activity, some_incompatible_activity @@ -16,6 +17,8 @@ async def main() -> None: """Run worker v1.""" + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") client = await Client.connect("localhost:7233") # Create worker v1 diff --git a/worker_versioning/workerv1_1.py b/worker_versioning/workerv1_1.py index 779db3f9..4f21d616 100644 --- a/worker_versioning/workerv1_1.py +++ b/worker_versioning/workerv1_1.py @@ -5,6 +5,7 @@ from temporalio.client import Client from temporalio.common import WorkerDeploymentVersion +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker, WorkerDeploymentConfig from worker_versioning.activities import some_activity, some_incompatible_activity @@ -16,7 +17,9 @@ async def main() -> None: """Run worker v1.1.""" - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create worker v1.1 worker = Worker( diff --git a/worker_versioning/workerv2.py b/worker_versioning/workerv2.py index 107e1a52..557f70ab 100644 --- a/worker_versioning/workerv2.py +++ b/worker_versioning/workerv2.py @@ -5,6 +5,7 @@ from temporalio.client import Client from temporalio.common import WorkerDeploymentVersion +from temporalio.envconfig import ClientConfig from temporalio.worker import Worker, WorkerDeploymentConfig from worker_versioning.activities import some_activity, some_incompatible_activity @@ -16,7 +17,9 @@ async def main() -> None: """Run worker v2.""" - client = await Client.connect("localhost:7233") + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) # Create worker v2 worker = Worker( From 74fdf502e0d646dc18ab60a304b472f3460be2ef Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Thu, 13 Nov 2025 15:11:31 -0800 Subject: [PATCH 27/40] Update to Temporal SDK 1.19.0 (#262) * update to temporal sdk 1.19.0 * Fix breaking changes from 1.19.0 in MCP samples --- openai_agents/mcp/run_file_system_worker.py | 3 +- .../run_memory_research_scratchpad_worker.py | 5 +- openai_agents/mcp/run_prompt_server_worker.py | 3 +- openai_agents/mcp/run_sse_worker.py | 3 +- .../mcp/run_streamable_http_worker.py | 3 +- pyproject.toml | 2 +- uv.lock | 287 +++++++++--------- 7 files changed, 155 insertions(+), 151 deletions(-) diff --git a/openai_agents/mcp/run_file_system_worker.py b/openai_agents/mcp/run_file_system_worker.py index f7bd2909..2ed8dffd 100644 --- a/openai_agents/mcp/run_file_system_worker.py +++ b/openai_agents/mcp/run_file_system_worker.py @@ -24,13 +24,14 @@ async def main(): samples_dir = os.path.join(current_dir, "sample_files") file_system_server = StatelessMCPServerProvider( + "FileSystemServer", lambda: MCPServerStdio( name="FileSystemServer", params={ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-filesystem", samples_dir], }, - ) + ), ) # Create client connected to server at the given address diff --git a/openai_agents/mcp/run_memory_research_scratchpad_worker.py b/openai_agents/mcp/run_memory_research_scratchpad_worker.py index 5e5f4b00..536ab974 100644 --- a/openai_agents/mcp/run_memory_research_scratchpad_worker.py +++ b/openai_agents/mcp/run_memory_research_scratchpad_worker.py @@ -23,13 +23,14 @@ async def main(): logging.basicConfig(level=logging.INFO) memory_server_provider = StatefulMCPServerProvider( - lambda: MCPServerStdio( + "MemoryServer", + lambda _: MCPServerStdio( name="MemoryServer", params={ "command": "npx", "args": ["-y", "@modelcontextprotocol/server-memory"], }, - ) + ), ) # Create client connected to server at the given address diff --git a/openai_agents/mcp/run_prompt_server_worker.py b/openai_agents/mcp/run_prompt_server_worker.py index cff8d1d7..08b68fae 100644 --- a/openai_agents/mcp/run_prompt_server_worker.py +++ b/openai_agents/mcp/run_prompt_server_worker.py @@ -24,12 +24,13 @@ async def main(): try: prompt_server_provider = StatelessMCPServerProvider( + "PromptServer", lambda: MCPServerStreamableHttp( name="PromptServer", params={ "url": "http://localhost:8000/mcp", }, - ) + ), ) # Create client connected to server at the given address diff --git a/openai_agents/mcp/run_sse_worker.py b/openai_agents/mcp/run_sse_worker.py index d9f9dd38..8ed719bd 100644 --- a/openai_agents/mcp/run_sse_worker.py +++ b/openai_agents/mcp/run_sse_worker.py @@ -24,12 +24,13 @@ async def main(): try: sse_server_provider = StatelessMCPServerProvider( + "SseServer", lambda: MCPServerSse( name="SseServer", params={ "url": "http://localhost:8000/sse", }, - ) + ), ) # Create client connected to server at the given address diff --git a/openai_agents/mcp/run_streamable_http_worker.py b/openai_agents/mcp/run_streamable_http_worker.py index 210634bb..72414727 100644 --- a/openai_agents/mcp/run_streamable_http_worker.py +++ b/openai_agents/mcp/run_streamable_http_worker.py @@ -24,12 +24,13 @@ async def main(): try: streamable_http_server_provider = StatelessMCPServerProvider( + "StreamableHttpServer", lambda: MCPServerStreamableHttp( name="StreamableHttpServer", params={ "url": "http://localhost:8000/mcp", }, - ) + ), ) # Create client connected to server at the given address diff --git a/pyproject.toml b/pyproject.toml index 73007250..ed007f47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.18.0,<2"] +dependencies = ["temporalio>=1.19.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" diff --git a/uv.lock b/uv.lock index 7ec7d623..b2c83a73 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "black" version = "22.12.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "mypy-extensions" }, @@ -182,7 +182,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -196,7 +196,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -210,7 +210,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -219,7 +219,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] @@ -276,7 +276,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -337,7 +337,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -349,7 +349,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -358,7 +358,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] @@ -381,7 +381,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -390,7 +390,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -403,7 +403,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -412,7 +412,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -424,7 +424,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -438,7 +438,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -447,7 +447,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple/" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -541,7 +541,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -550,7 +550,7 @@ wheels = [ [[package]] name = "gevent" version = "25.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -598,7 +598,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -610,7 +610,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -661,7 +661,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] @@ -673,7 +673,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.73.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/79/e8/b43b851537da2e2f03fa8be1aef207e5cbfb1a2e014fbb6b40d24c177cd3/grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87", size = 12730355, upload-time = "2025-06-26T01:53:24.622Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/8f/51/a5748ab2773d893d099b92653039672f7e26dd35741020972b84d604066f/grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55", size = 5365087, upload-time = "2025-06-26T01:51:44.541Z" }, @@ -721,7 +721,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -730,7 +730,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -745,7 +745,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -758,7 +758,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -794,7 +794,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -809,7 +809,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -818,7 +818,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -837,7 +837,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -846,7 +846,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] @@ -858,7 +858,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -867,7 +867,7 @@ wheels = [ [[package]] name = "isort" version = "5.13.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] @@ -888,7 +888,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple/" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -960,7 +960,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpointer" }, ] @@ -981,7 +981,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -990,7 +990,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] @@ -1017,7 +1017,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1041,7 +1041,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1061,7 +1061,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1078,7 +1078,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, ] @@ -1105,7 +1105,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1121,7 +1121,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] @@ -1155,7 +1155,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple/" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] @@ -1225,7 +1225,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1247,7 +1247,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1256,7 +1256,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1358,7 +1358,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1397,7 +1397,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -1418,7 +1418,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1427,7 +1427,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1501,7 +1501,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1526,7 +1526,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -1556,7 +1556,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1570,7 +1570,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1583,7 +1583,7 @@ wheels = [ [[package]] name = "orjson" version = "3.10.18" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810, upload-time = "2025-04-29T23:30:08.423Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927, upload-time = "2025-04-29T23:28:08.643Z" }, @@ -1649,7 +1649,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] @@ -1661,7 +1661,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1670,7 +1670,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1718,7 +1718,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1727,7 +1727,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1736,7 +1736,7 @@ wheels = [ [[package]] name = "platformdirs" version = "4.3.8" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1745,7 +1745,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1754,7 +1754,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1768,7 +1768,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1857,7 +1857,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1871,7 +1871,7 @@ wheels = [ [[package]] name = "pyarrow" version = "20.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/5b/23/77094eb8ee0dbe88441689cb6afc40ac312a1e15d3a7acc0586999518222/pyarrow-20.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c7dd06fd7d7b410ca5dc839cc9d485d2bc4ae5240851bcd45d85105cc90a47d7", size = 30832591, upload-time = "2025-04-27T12:27:27.89Z" }, @@ -1924,7 +1924,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1933,7 +1933,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.11.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1948,7 +1948,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.33.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2035,7 +2035,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2049,7 +2049,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2058,7 +2058,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2071,7 +2071,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2088,7 +2088,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] @@ -2101,7 +2101,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2114,7 +2114,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] @@ -2126,7 +2126,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2135,7 +2135,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2144,7 +2144,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2153,7 +2153,7 @@ wheels = [ [[package]] name = "pywin32" version = "310" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, @@ -2172,7 +2172,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple/" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2216,7 +2216,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2230,7 +2230,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2299,7 +2299,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2314,7 +2314,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] @@ -2326,7 +2326,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2340,7 +2340,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2466,7 +2466,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] @@ -2478,7 +2478,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2491,7 +2491,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2500,7 +2500,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2509,7 +2509,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2518,7 +2518,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2527,7 +2527,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2572,7 +2572,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2596,7 +2596,7 @@ wheels = [ [[package]] name = "temporalio" -version = "1.18.0" +version = "1.19.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, @@ -2605,13 +2605,12 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/7e/20/b52c96b37bf00ead6e8a4a197075770ebad516db765cc3abca8396de0689/temporalio-1.18.0.tar.gz", hash = "sha256:7ff7f833eb1e7697084b4ed9d86c3167cbff1ec77f1b40df774313a5d0fd5f6d", size = 1781572, upload-time = "2025-09-19T23:40:52.511Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2f/28/c5a4ee259748450ac0765837f8c78cbfa36800264158d98bd2cde4496d87/temporalio-1.18.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:ac5d30d8b010c9b042065ea1259da7638db1a0a25e81ee4be0671a393ed329c5", size = 12734753, upload-time = "2025-09-19T23:40:06.575Z" }, - { url = "https://files.pythonhosted.org/packages/be/94/24bd903b5594420a4d131bfa3de965313f9a409af77b47e9a9a56d85bb9e/temporalio-1.18.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:19315d192247230c9bd7c60a566c2b3a80ad4d9de891c6aa13df63d72d3ec169", size = 12323141, upload-time = "2025-09-19T23:40:16.817Z" }, - { url = "https://files.pythonhosted.org/packages/6d/76/82415b43c68e2c6bb3a85e8800555d206767815088c8cad0ade9a06bd7ac/temporalio-1.18.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a023b25033e48b2e43f623a78737047a45b8cb553f69f457d09272fce5c723da", size = 12694061, upload-time = "2025-09-19T23:40:26.388Z" }, - { url = "https://files.pythonhosted.org/packages/41/60/176a3224c2739fee270052dd9224ae36370c4e13d2ab1bb96a2f9bbb513c/temporalio-1.18.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:695211dddbcffc20077d5b3b9a9b41bd09f60393c4ff211bcc7d6d895d607cc1", size = 12879404, upload-time = "2025-09-19T23:40:37.487Z" }, - { url = "https://files.pythonhosted.org/packages/e3/8d/e3809b356262d1d398d8cbb78df1e19d460c0a89e6ab64ca8d9c05d5fe5a/temporalio-1.18.0-cp39-abi3-win_amd64.whl", hash = "sha256:e3f691bd0a01a22c0fe40e87b6236cc8a292628e3a5a490880d1bf94709249c9", size = 13088041, upload-time = "2025-09-19T23:40:49.469Z" }, + { url = "https://files.pythonhosted.org/packages/3f/92/0775d831fa245d61b74db2059d5a24a04cef0532ed2c48310a5ab007de9c/temporalio-1.19.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c2d6d5cad8aec56e048705aa4f0bab83fec15343757ea7acf8504f2e0c289b60", size = 13175255, upload-time = "2025-11-13T22:35:54.22Z" }, + { url = "https://files.pythonhosted.org/packages/e2/e1/2a818fefc0023eb132bfff1a03440bcaff154d4d97445ef88a40c23c20c8/temporalio-1.19.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:d85c89018cba9471ce529d90c9cee5bcc31790fd64176b9ada32cc76440f8d73", size = 12854549, upload-time = "2025-11-13T22:35:57.217Z" }, + { url = "https://files.pythonhosted.org/packages/ff/78/fe5c8c9b112b38e01aba845335df17a8bbfd60a434ffe3c1c4737ced40a0/temporalio-1.19.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f772f0698d60f808bc3c4a055fb53e40d757fa646411845b911863eebbf0549d", size = 13237772, upload-time = "2025-11-13T22:36:00.511Z" }, + { url = "https://files.pythonhosted.org/packages/d9/82/be0fd31119651f518f8db8685fd61976d9d5bbecf3b562d51f13a6442a17/temporalio-1.19.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f706c8f49771daf342ac8daa8ed07f4124fae943177f9feef458a1255aee717c", size = 13374621, upload-time = "2025-11-13T22:36:03.431Z" }, + { url = "https://files.pythonhosted.org/packages/d8/94/18f6ae06ffd91507ded9111af1041146a5ba4b56e9256520c5ce82629fc4/temporalio-1.19.0-cp310-abi3-win_amd64.whl", hash = "sha256:162459c293553be39994f20c635a132f7332ae71bd7ba4042f8473701fcf1c7c", size = 14256891, upload-time = "2025-11-13T22:36:06.778Z" }, ] [package.optional-dependencies] @@ -2699,7 +2698,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.18.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.19.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2760,7 +2759,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2769,7 +2768,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2805,7 +2804,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2830,7 +2829,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2869,7 +2868,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2881,7 +2880,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2899,7 +2898,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2915,7 +2914,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -2924,7 +2923,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -2933,7 +2932,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] @@ -2945,7 +2944,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2954,7 +2953,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -2967,7 +2966,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2979,7 +2978,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2988,7 +2987,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -2997,7 +2996,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3022,7 +3021,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3054,7 +3053,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -3154,7 +3153,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3213,7 +3212,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3312,7 +3311,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -3321,7 +3320,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] @@ -3333,7 +3332,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] From 6de4916879ea7fa2f4da0dd7d224be1643521175 Mon Sep 17 00:00:00 2001 From: Andrew Yuan Date: Fri, 5 Dec 2025 09:21:25 -0800 Subject: [PATCH 28/40] Update Python SDK to 1.20.0 (#264) * v1.20.0 * Use new mac runners, run CI against 3.14 instead of 3.13 * update uv.lock * upgrade uv.lock for pyarrow for 3.14 support * upgrade uv.lock for orjson for 3.14 support * pydantic should be the last package to upgrade * tiktoken * loosen ver for gevent * grpcio * Skip test for trio-async for Python 3.14 and newer, add to README * Didn't place the skip high enough * Put it too high * black to ruff * Add to readme for 3.14 for Sentry * format --- .github/workflows/ci.yml | 6 +- bedrock/basic/workflows.py | 1 - bedrock/entity/workflows.py | 1 - cloud_export_to_parquet/workflows.py | 2 +- custom_converter/shared.py | 2 +- custom_metric/worker.py | 1 - eager_wf_start/run.py | 1 - env_config/__init__.py | 1 - gevent_async/worker.py | 2 - hello/hello_activity.py | 1 - hello/hello_activity_async.py | 1 - hello/hello_activity_choice.py | 1 - hello/hello_activity_heartbeat.py | 1 - hello/hello_activity_method.py | 1 - hello/hello_activity_multiprocess.py | 1 - hello/hello_activity_retry.py | 1 - hello/hello_async_activity_completion.py | 1 - hello/hello_cancellation.py | 1 - hello/hello_child_workflow.py | 1 - hello/hello_continue_as_new.py | 1 - hello/hello_cron.py | 1 - hello/hello_exception.py | 1 - hello/hello_local_activity.py | 1 - hello/hello_mtls.py | 1 - hello/hello_parallel_activity.py | 1 - hello/hello_query.py | 1 - hello/hello_search_attributes.py | 1 - hello/hello_signal.py | 1 - .../waiting_for_handlers/starter.py | 4 +- .../starter.py | 4 +- nexus_sync_operations/handler/worker.py | 2 +- .../workflows/forcing_tool_use_workflow.py | 7 +- .../workflows/agent_lifecycle_workflow.py | 1 - .../dynamic_system_prompt_workflow.py | 6 +- .../customer_service/customer_service.py | 6 +- pyproject.toml | 16 +- sentry/README.md | 2 + tests/hello/hello_change_log_level_test.py | 1 - tests/resource_pool/workflow_test.py | 8 +- tests/sentry/test_interceptor.py | 8 + tests/trio_async/workflow_test.py | 5 + trio_async/README.md | 2 + trio_async/worker.py | 1 - uv.lock | 821 ++++++++++-------- 44 files changed, 501 insertions(+), 429 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f41c09d1..4443cbdd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,13 +15,13 @@ jobs: strategy: fail-fast: true matrix: - python: ["3.10", "3.13"] + python: ["3.10", "3.14"] os: [ubuntu-latest, macos-intel, macos-arm, windows-latest] include: - os: macos-intel - runsOn: macos-13 + runsOn: macos-15-intel - os: macos-arm - runsOn: macos-14 + runsOn: macos-latest runs-on: ${{ matrix.runsOn || matrix.os }} steps: - uses: astral-sh/setup-uv@v5 diff --git a/bedrock/basic/workflows.py b/bedrock/basic/workflows.py index 9968704d..0ebf0216 100644 --- a/bedrock/basic/workflows.py +++ b/bedrock/basic/workflows.py @@ -10,7 +10,6 @@ class BasicBedrockWorkflow: @workflow.run async def run(self, prompt: str) -> str: - workflow.logger.info("Prompt: %s" % prompt) response = await workflow.execute_activity_method( diff --git a/bedrock/entity/workflows.py b/bedrock/entity/workflows.py index 3dfdf530..710f0916 100644 --- a/bedrock/entity/workflows.py +++ b/bedrock/entity/workflows.py @@ -31,7 +31,6 @@ async def run( self, params: BedrockParams, ) -> str: - if params and params.conversation_summary: self.conversation_history.append( ("conversation_summary", params.conversation_summary) diff --git a/cloud_export_to_parquet/workflows.py b/cloud_export_to_parquet/workflows.py index 2d3edd88..3c9fe270 100644 --- a/cloud_export_to_parquet/workflows.py +++ b/cloud_export_to_parquet/workflows.py @@ -7,9 +7,9 @@ with workflow.unsafe.imports_passed_through(): from cloud_export_to_parquet.data_trans_activities import ( DataTransAndLandActivityInput, + GetObjectKeysActivityInput, data_trans_and_land, get_object_keys, - GetObjectKeysActivityInput, ) from dataclasses import dataclass diff --git a/custom_converter/shared.py b/custom_converter/shared.py index c94b8dbb..2aa71f16 100644 --- a/custom_converter/shared.py +++ b/custom_converter/shared.py @@ -54,7 +54,7 @@ def __init__(self) -> None: # Just add ours as first before the defaults super().__init__( GreetingEncodingPayloadConverter(), - *DefaultPayloadConverter.default_encoding_payload_converters + *DefaultPayloadConverter.default_encoding_payload_converters, ) diff --git a/custom_metric/worker.py b/custom_metric/worker.py index 6a3be69a..38793985 100644 --- a/custom_metric/worker.py +++ b/custom_metric/worker.py @@ -25,7 +25,6 @@ def intercept_activity( class CustomScheduleToStartInterceptor(ActivityInboundInterceptor): async def execute_activity(self, input: ExecuteActivityInput): - schedule_to_start = ( activity.info().started_time - activity.info().current_attempt_scheduled_time diff --git a/eager_wf_start/run.py b/eager_wf_start/run.py index 51a1ddf6..34d807e0 100644 --- a/eager_wf_start/run.py +++ b/eager_wf_start/run.py @@ -12,7 +12,6 @@ async def main(): - # Note that the worker and client run in the same process and share the same client connection. config = ClientConfig.load_client_connect_config() config.setdefault("target_host", "localhost:7233") diff --git a/env_config/__init__.py b/env_config/__init__.py index 0519ecba..e69de29b 100644 --- a/env_config/__init__.py +++ b/env_config/__init__.py @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/gevent_async/worker.py b/gevent_async/worker.py index 219908af..db419399 100644 --- a/gevent_async/worker.py +++ b/gevent_async/worker.py @@ -48,7 +48,6 @@ async def async_main(): # running this async main. The max_workers here needs to have enough room to # support the max concurrent activities/workflows settings. with GeventExecutor(max_workers=200) as executor: - # Run a worker for the workflow and activities async with Worker( client, @@ -68,7 +67,6 @@ async def async_main(): max_concurrent_activities=100, max_concurrent_workflow_tasks=100, ): - # Wait until interrupted logging.info("Worker started, ctrl+c to exit") await interrupt_event.wait() diff --git a/hello/hello_activity.py b/hello/hello_activity.py index 69226772..c7972c2e 100644 --- a/hello/hello_activity.py +++ b/hello/hello_activity.py @@ -61,7 +61,6 @@ async def main(): # This same thread pool could be passed to multiple workers if desired. activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_async.py b/hello/hello_activity_async.py index 6c1e195a..47b5bd79 100644 --- a/hello/hello_activity_async.py +++ b/hello/hello_activity_async.py @@ -57,7 +57,6 @@ async def main(): # to supply an activity executor because they run in # the worker's event loop. ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_choice.py b/hello/hello_activity_choice.py index 139d4006..6da9fe69 100644 --- a/hello/hello_activity_choice.py +++ b/hello/hello_activity_choice.py @@ -95,7 +95,6 @@ async def main(): activities=[order_apples, order_bananas, order_cherries, order_oranges], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_heartbeat.py b/hello/hello_activity_heartbeat.py index a7a8ffe9..2b80f9a6 100644 --- a/hello/hello_activity_heartbeat.py +++ b/hello/hello_activity_heartbeat.py @@ -54,7 +54,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_method.py b/hello/hello_activity_method.py index 0073ae45..d87bc8e7 100644 --- a/hello/hello_activity_method.py +++ b/hello/hello_activity_method.py @@ -50,7 +50,6 @@ async def main(): workflows=[MyWorkflow], activities=[my_activities.do_database_thing], ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_multiprocess.py b/hello/hello_activity_multiprocess.py index 5751a210..c7793c2c 100644 --- a/hello/hello_activity_multiprocess.py +++ b/hello/hello_activity_multiprocess.py @@ -68,7 +68,6 @@ async def main(): multiprocessing.Manager() ), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_activity_retry.py b/hello/hello_activity_retry.py index c5007dfb..105aa847 100644 --- a/hello/hello_activity_retry.py +++ b/hello/hello_activity_retry.py @@ -58,7 +58,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_async_activity_completion.py b/hello/hello_async_activity_completion.py index 21a003df..e777c49f 100644 --- a/hello/hello_async_activity_completion.py +++ b/hello/hello_async_activity_completion.py @@ -81,7 +81,6 @@ async def main(): workflows=[GreetingWorkflow], activities=[composer.compose_greeting], ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_cancellation.py b/hello/hello_cancellation.py index aaf0aa90..a74bc2b4 100644 --- a/hello/hello_cancellation.py +++ b/hello/hello_cancellation.py @@ -65,7 +65,6 @@ async def main(): activities=[never_complete_activity, cleanup_activity], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to start the workflow. # Note, in many production setups, the client would be in a completely # separate process from the worker. diff --git a/hello/hello_child_workflow.py b/hello/hello_child_workflow.py index 6f99af5b..136b788f 100644 --- a/hello/hello_child_workflow.py +++ b/hello/hello_child_workflow.py @@ -44,7 +44,6 @@ async def main(): task_queue="hello-child-workflow-task-queue", workflows=[GreetingWorkflow, ComposeGreetingWorkflow], ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_continue_as_new.py b/hello/hello_continue_as_new.py index a4947019..a899c7fc 100644 --- a/hello/hello_continue_as_new.py +++ b/hello/hello_continue_as_new.py @@ -33,7 +33,6 @@ async def main(): task_queue="hello-continue-as-new-task-queue", workflows=[LoopingWorkflow], ): - # While the worker is running, use the client to run the workflow. Note, # in many production setups, the client would be in a completely # separate process from the worker. diff --git a/hello/hello_cron.py b/hello/hello_cron.py index cf1bc4b1..1ca29ea1 100644 --- a/hello/hello_cron.py +++ b/hello/hello_cron.py @@ -46,7 +46,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - print("Running workflow once a minute") # While the worker is running, use the client to start the workflow. diff --git a/hello/hello_exception.py b/hello/hello_exception.py index a2d49633..6e94bf7c 100644 --- a/hello/hello_exception.py +++ b/hello/hello_exception.py @@ -52,7 +52,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_local_activity.py b/hello/hello_local_activity.py index a1dd08ed..8954ea42 100644 --- a/hello/hello_local_activity.py +++ b/hello/hello_local_activity.py @@ -45,7 +45,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_mtls.py b/hello/hello_mtls.py index 3ed15354..b88c5f85 100644 --- a/hello/hello_mtls.py +++ b/hello/hello_mtls.py @@ -82,7 +82,6 @@ async def main(): activities=[compose_greeting], activity_executor=ThreadPoolExecutor(5), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_parallel_activity.py b/hello/hello_parallel_activity.py index 680534ab..42931a70 100644 --- a/hello/hello_parallel_activity.py +++ b/hello/hello_parallel_activity.py @@ -54,7 +54,6 @@ async def main(): activities=[say_hello_activity], activity_executor=ThreadPoolExecutor(10), ): - # While the worker is running, use the client to run the workflow and # print out its result. Note, in many production setups, the client # would be in a completely separate process from the worker. diff --git a/hello/hello_query.py b/hello/hello_query.py index 7ed132d1..d1bc54aa 100644 --- a/hello/hello_query.py +++ b/hello/hello_query.py @@ -39,7 +39,6 @@ async def main(): task_queue="hello-query-task-queue", workflows=[GreetingWorkflow], ): - # While the worker is running, use the client to start the workflow. # Note, in many production setups, the client would be in a completely # separate process from the worker. diff --git a/hello/hello_search_attributes.py b/hello/hello_search_attributes.py index c858692a..d6d1a205 100644 --- a/hello/hello_search_attributes.py +++ b/hello/hello_search_attributes.py @@ -27,7 +27,6 @@ async def main(): task_queue="hello-search-attributes-task-queue", workflows=[GreetingWorkflow], ): - # While the worker is running, use the client to start the workflow. # Note, in many production setups, the client would be in a completely # separate process from the worker. diff --git a/hello/hello_signal.py b/hello/hello_signal.py index ed7ce7b3..02b9d3ce 100644 --- a/hello/hello_signal.py +++ b/hello/hello_signal.py @@ -53,7 +53,6 @@ async def main(): task_queue="hello-signal-task-queue", workflows=[GreetingWorkflow], ): - # While the worker is running, use the client to start the workflow. # Note, in many production setups, the client would be in a completely # separate process from the worker. diff --git a/message_passing/waiting_for_handlers/starter.py b/message_passing/waiting_for_handlers/starter.py index 76829e0b..9d3fbc0c 100644 --- a/message_passing/waiting_for_handlers/starter.py +++ b/message_passing/waiting_for_handlers/starter.py @@ -37,7 +37,9 @@ async def _check_run( wait_for_stage=client.WorkflowUpdateStage.ACCEPTED, ) except Exception as e: - print(f" πŸ”΄ caught exception while starting update: {e}: {e.__cause__ or ''}") + print( + f" πŸ”΄ caught exception while starting update: {e}: {e.__cause__ or ''}" + ) if exit_type == WorkflowExitType.CANCELLATION: await wf_handle.cancel() diff --git a/message_passing/waiting_for_handlers_and_compensation/starter.py b/message_passing/waiting_for_handlers_and_compensation/starter.py index fbc5ae04..6f25c9a5 100644 --- a/message_passing/waiting_for_handlers_and_compensation/starter.py +++ b/message_passing/waiting_for_handlers_and_compensation/starter.py @@ -39,7 +39,9 @@ async def _check_run( wait_for_stage=client.WorkflowUpdateStage.ACCEPTED, ) except Exception as e: - print(f" πŸ”΄ caught exception while starting update: {e}: {e.__cause__ or ''}") + print( + f" πŸ”΄ caught exception while starting update: {e}: {e.__cause__ or ''}" + ) if exit_type == WorkflowExitType.CANCELLATION: await wf_handle.cancel() diff --git a/nexus_sync_operations/handler/worker.py b/nexus_sync_operations/handler/worker.py index 7783055a..97c8eb04 100644 --- a/nexus_sync_operations/handler/worker.py +++ b/nexus_sync_operations/handler/worker.py @@ -22,7 +22,7 @@ async def main(client: Optional[Client] = None): if client is None: config = ClientConfig.load_client_connect_config() config.setdefault("target_host", "localhost:7233") - config.setdefault("namespace", NAMESPACE), + config.setdefault("namespace", NAMESPACE) client = await Client.connect(**config) # Create the nexus service handler instance, starting the long-running entity workflow that diff --git a/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py b/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py index a8eaedd6..9d3aee3b 100644 --- a/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py +++ b/openai_agents/agent_patterns/workflows/forcing_tool_use_workflow.py @@ -59,9 +59,10 @@ async def run(self, tool_use_behavior: str = "default") -> str: config = RunConfig() if tool_use_behavior == "default": - behavior: Literal[ - "run_llm_again", "stop_on_first_tool" - ] | ToolsToFinalOutputFunction = "run_llm_again" + behavior: ( + Literal["run_llm_again", "stop_on_first_tool"] + | ToolsToFinalOutputFunction + ) = "run_llm_again" elif tool_use_behavior == "first_tool": behavior = "stop_on_first_tool" elif tool_use_behavior == "custom": diff --git a/openai_agents/basic/workflows/agent_lifecycle_workflow.py b/openai_agents/basic/workflows/agent_lifecycle_workflow.py index 61cdad90..c016d150 100644 --- a/openai_agents/basic/workflows/agent_lifecycle_workflow.py +++ b/openai_agents/basic/workflows/agent_lifecycle_workflow.py @@ -71,7 +71,6 @@ class FinalResult(BaseModel): class AgentLifecycleWorkflow: @workflow.run async def run(self, max_number: int) -> FinalResult: - multiply_agent = Agent( name="Multiply Agent", instructions="Multiply the number by 2 and then return the final result.", diff --git a/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py b/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py index 00e77fbb..fb7ce109 100644 --- a/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py +++ b/openai_agents/basic/workflows/dynamic_system_prompt_workflow.py @@ -26,9 +26,9 @@ class DynamicSystemPromptWorkflow: @workflow.run async def run(self, user_message: str, style: Optional[str] = None) -> str: if style is None: - selected_style: Literal[ - "haiku", "pirate", "robot" - ] = workflow.random().choice(["haiku", "pirate", "robot"]) + selected_style: Literal["haiku", "pirate", "robot"] = ( + workflow.random().choice(["haiku", "pirate", "robot"]) + ) else: # Validate that the provided style is one of the allowed values if style not in ["haiku", "pirate", "robot"]: diff --git a/openai_agents/customer_service/customer_service.py b/openai_agents/customer_service/customer_service.py index 88f6e3cd..45997033 100644 --- a/openai_agents/customer_service/customer_service.py +++ b/openai_agents/customer_service/customer_service.py @@ -77,9 +77,9 @@ async def on_seat_booking_handoff( ### AGENTS -def init_agents() -> Tuple[ - Agent[AirlineAgentContext], Dict[str, Agent[AirlineAgentContext]] -]: +def init_agents() -> ( + Tuple[Agent[AirlineAgentContext], Dict[str, Agent[AirlineAgentContext]]] +): """ Initialize the agents for the airline customer service workflow. :return: triage agent diff --git a/pyproject.toml b/pyproject.toml index ed007f47..2bc7f73a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.19.0,<2"] +dependencies = ["temporalio>=1.20.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" @@ -16,8 +16,7 @@ Documentation = "https://docs.temporal.io/docs/python" [dependency-groups] dev = [ - "black>=22.3.0,<23", - "isort>=5.10.1,<6", + "ruff>=0.5.0,<0.6", "mypy>=1.4.1,<2", "pytest>=7.1.2,<8", "pytest-asyncio>=0.18.3,<0.19", @@ -37,7 +36,7 @@ encryption = [ "cryptography>=38.0.1,<39", "aiohttp>=3.8.1,<4", ] -gevent = ["gevent==25.4.2 ; python_version >= '3.8'"] +gevent = ["gevent>=25.4.2 ; python_version >= '3.8'"] langchain = [ "langchain>=0.1.7,<0.2 ; python_version >= '3.8.1' and python_version < '4.0'", "langchain-openai>=0.0.6,<0.0.7 ; python_version >= '3.8.1' and python_version < '4.0'", @@ -119,8 +118,8 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.poe.tasks] -format = [{cmd = "uv run black ."}, {cmd = "uv run isort ."}] -lint = [{cmd = "uv run black --check ."}, {cmd = "uv run isort --check-only ."}, {ref = "lint-types" }] +format = [{cmd = "uv run ruff check --select I --fix"}, {cmd = "uv run ruff format"}] +lint = [{cmd = "uv run ruff check --select I"}, {cmd = "uv run ruff format --check"}, {ref = "lint-types"}] lint-types = "uv run --all-groups mypy --check-untyped-defs --namespace-packages ." test = "uv run --all-groups pytest" @@ -130,9 +129,8 @@ log_cli = true log_cli_level = "INFO" log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)" -[tool.isort] -profile = "black" -skip_gitignore = true +[tool.ruff] +target-version = "py310" [tool.mypy] ignore_missing_imports = true diff --git a/sentry/README.md b/sentry/README.md index 1cc75cf6..0062f815 100644 --- a/sentry/README.md +++ b/sentry/README.md @@ -3,6 +3,8 @@ This sample shows how to configure [Sentry](https://sentry.io) SDK (version 2) to intercept and capture errors from the Temporal SDK for workflows and activities. The integration adds some useful context to the errors, such as the activity type, task queue, etc. +Note: Sentry currently does not support Python 3.14, likewise this sample does not support Python 3.14. + ## Further details This is a small modification of the original example Sentry integration in this repo based on SDK v1. The integration diff --git a/tests/hello/hello_change_log_level_test.py b/tests/hello/hello_change_log_level_test.py index e3cd2334..e83e08c4 100644 --- a/tests/hello/hello_change_log_level_test.py +++ b/tests/hello/hello_change_log_level_test.py @@ -10,7 +10,6 @@ async def test_workflow_with_log_capture(client: Client): - log_stream = io.StringIO() handler = logging.StreamHandler(log_stream) handler.setLevel(logging.ERROR) diff --git a/tests/resource_pool/workflow_test.py b/tests/resource_pool/workflow_test.py index 42a6fbde..b5ae95e3 100644 --- a/tests/resource_pool/workflow_test.py +++ b/tests/resource_pool/workflow_test.py @@ -70,10 +70,10 @@ async def use_resource_mock(input: UseResourceActivityInput) -> None: holder = None # Are all the resources free, per the query? - handle: WorkflowHandle[ - ResourcePoolWorkflow, None - ] = client.get_workflow_handle_for( - ResourcePoolWorkflow.run, RESOURCE_POOL_WORKFLOW_ID + handle: WorkflowHandle[ResourcePoolWorkflow, None] = ( + client.get_workflow_handle_for( + ResourcePoolWorkflow.run, RESOURCE_POOL_WORKFLOW_ID + ) ) query_result = await handle.query(ResourcePoolWorkflow.get_current_holders) assert query_result == {"r_a": None, "r_b": None, "r_c": None} diff --git a/tests/sentry/test_interceptor.py b/tests/sentry/test_interceptor.py index 731bad8c..f9f931e8 100644 --- a/tests/sentry/test_interceptor.py +++ b/tests/sentry/test_interceptor.py @@ -1,7 +1,15 @@ +import sys import unittest.mock from collections import abc import pytest + +if sys.version_info >= (3, 14): + pytest.skip( + "Sentry does not support Python 3.14 yet.", + allow_module_level=True, + ) + import sentry_sdk import temporalio.activity import temporalio.workflow diff --git a/tests/trio_async/workflow_test.py b/tests/trio_async/workflow_test.py index cce95fac..15d678aa 100644 --- a/tests/trio_async/workflow_test.py +++ b/tests/trio_async/workflow_test.py @@ -2,6 +2,11 @@ import uuid import pytest + +if sys.version_info >= (3, 14): + pytest.skip("trio-asyncio not supported on Python 3.14+", allow_module_level=True) + + import trio_asyncio from temporalio.client import Client from temporalio.worker import Worker diff --git a/trio_async/README.md b/trio_async/README.md index 4c9770fb..dfa02eab 100644 --- a/trio_async/README.md +++ b/trio_async/README.md @@ -5,6 +5,8 @@ This sample shows how to use Temporal asyncio with [Trio](https://trio.readthedo and worker in a Trio setting, and how Trio-based code can run in both asyncio async activities and threaded sync activities. +NOTE: This sample only works on Python versions < 3.14. + For this sample, the optional `trio_async` dependency group must be included. To include, run: uv sync --group trio_async diff --git a/trio_async/worker.py b/trio_async/worker.py index f1c2a30b..7cb9685f 100644 --- a/trio_async/worker.py +++ b/trio_async/worker.py @@ -26,7 +26,6 @@ async def main(): # for both activities and workflow tasks and by default the worker supports # 100 max concurrent activity tasks and 100 max concurrent workflow tasks. with trio_asyncio.TrioExecutor(max_workers=200) as thread_executor: - # Run a worker for the workflow async with Worker( client, diff --git a/uv.lock b/uv.lock index b2c83a73..cbe5db3f 100644 --- a/uv.lock +++ b/uv.lock @@ -159,26 +159,6 @@ 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 = "22.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "mypy-extensions" }, - { name = "pathspec" }, - { name = "platformdirs" }, - { name = "tomli", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a6/59/e873cc6807fb62c11131e5258ca15577a3b7452abad08dc49286cf8245e8/black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f", size = 553112, upload-time = "2022-12-09T15:57:04.428Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/79/d9/60852a6fc2f85374db20a9767dacfe50c2172eb8388f46018c8daf836995/black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d", size = 1556665, upload-time = "2022-12-09T16:04:10.897Z" }, - { url = "https://files.pythonhosted.org/packages/71/57/975782465cc6b514f2c972421e29b933dfbb51d4a95948a4e0e94f36ea38/black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351", size = 1205632, upload-time = "2022-12-09T16:14:38.465Z" }, - { url = "https://files.pythonhosted.org/packages/e9/e0/6aa02d14785c4039b38bfed6f9ee28a952b2d101c64fc97b15811fa8bd04/black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f", size = 1536577, upload-time = "2022-12-09T16:04:12.721Z" }, - { url = "https://files.pythonhosted.org/packages/4c/49/420dcfccba3215dc4e5790fa47572ef14129df1c5e95dd87b5ad30211b01/black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4", size = 1209873, upload-time = "2022-12-09T16:14:40.318Z" }, - { url = "https://files.pythonhosted.org/packages/0c/51/1f7f93c0555eaf4cbb628e26ba026e3256174a45bd9397ff1ea7cf96bad5/black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf", size = 167343, upload-time = "2022-12-09T15:57:02.229Z" }, -] - [[package]] name = "boto3" version = "1.39.4" @@ -549,7 +529,7 @@ wheels = [ [[package]] name = "gevent" -version = "25.4.2" +version = "25.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, @@ -557,42 +537,46 @@ dependencies = [ { name = "zope-event" }, { name = "zope-interface" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/00/e5/a2d9c2d5bfb575973bca7733b23e7f8649f1079c18140a8680a551f3963e/gevent-25.4.2.tar.gz", hash = "sha256:7ffba461458ed28a85a01285ea0e0dc14f883204d17ce5ed82fa839a9d620028", size = 6342241, upload-time = "2025-04-24T14:44:53.858Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/96/43/9afbeb648fe70a4c9877f6f02466ef2ba0f4af2f90dae1f2b3da16fb1ab2/gevent-25.4.2-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:677e5d1c7d0a0b4240644321f10b8e3b36fd4ca5fc1b45d0e4989e6884375537", size = 2994750, upload-time = "2025-04-24T13:58:43.648Z" }, - { url = "https://files.pythonhosted.org/packages/c7/56/db9b46bc8a0dfc3599a4caa74245645bbf8ee0395cf8447df8d03029f7e7/gevent-25.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11bc2374ce3f1db3a243522c4d30b9e86e2dc0f2905f083fff288afa8ef8031f", size = 1822606, upload-time = "2025-04-24T14:41:04.741Z" }, - { url = "https://files.pythonhosted.org/packages/f9/d4/099ab14d1a6875b752ee4aee76ad88bd6c300aae7234cd188e579bec9034/gevent-25.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9100693f2bd8237ce7ce99a2b62da128196d8abcda331049e67ad6afb8cff23a", size = 1906193, upload-time = "2025-04-24T14:38:52.529Z" }, - { url = "https://files.pythonhosted.org/packages/d2/fa/0aef581e8db9aab83053c11a413be7f9e674294c07b67b93f242b0a744f9/gevent-25.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:22f33261b32e28433af7a96388ce33b77e903a648fc868b993304af2c1bca05b", size = 1852101, upload-time = "2025-04-24T14:45:43.668Z" }, - { url = "https://files.pythonhosted.org/packages/48/5e/bdb7f40ea3173017092d74bb2a3b43d4877beb5f2efd925e4013d9ba258b/gevent-25.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c1d1a66a28372d505e0d8f6f1fdb62f7d5b3423e49431f41b99bd9133f006b7", size = 2182149, upload-time = "2025-04-24T14:17:54.002Z" }, - { url = "https://files.pythonhosted.org/packages/34/e2/c550ccd60433768ef56ef9a8d3decf68c7737a06706e0fb624377aa46c14/gevent-25.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:fdf9aec76a7285b00fb64ec942cd9ff88f8765874a5abf99c4e8c5374b3133e9", size = 1859716, upload-time = "2025-04-24T14:55:57.154Z" }, - { url = "https://files.pythonhosted.org/packages/21/6b/8bfa9012d0bf042bc2c8248c82c0246d0fbd5f824c0a909a2ee80e69839c/gevent-25.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7442b3ffac08f6239d6463ee2943fd9a619b64b2db11cec292acf8caccb70536", size = 2216299, upload-time = "2025-04-24T14:20:30.617Z" }, - { url = "https://files.pythonhosted.org/packages/da/9e/ea62cded14753ca88f1d5bbbb73de95aa50e327ac4b71d7a61d4c1ce72f6/gevent-25.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:d7999e4d4b3597b706a333f9a7bf2efbd8365cd244312405f33b4870fa3b411d", size = 1700526, upload-time = "2025-04-24T15:36:25.127Z" }, - { url = "https://files.pythonhosted.org/packages/66/2e/4f47a9f83c32986321b53feeb43b05def242737c359f5b08e4466e32e45a/gevent-25.4.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:2270a8607661e609c44e4f72811b6380dcfede558041e4ee3134e66753865038", size = 2924625, upload-time = "2025-04-24T13:54:26.008Z" }, - { url = "https://files.pythonhosted.org/packages/30/1c/d75d492210283916e7b7dc974f154ae8f1ff4db2a9e418e06e6948f00c55/gevent-25.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb89ed32e2b766fcb1afc52847e33d8c369d2b40f23d4c96977fd092b5a0ea86", size = 1785690, upload-time = "2025-04-24T14:41:06.087Z" }, - { url = "https://files.pythonhosted.org/packages/57/f5/02e53a06434922f79fff9a4a1954eff2513363a637539c0d67ef665793db/gevent-25.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43469ed40ea6cfb1c88e8d85a57aa5f52dd6b3b94a2e499752ab7e60a90c7dba", size = 1865941, upload-time = "2025-04-24T14:38:54.912Z" }, - { url = "https://files.pythonhosted.org/packages/28/82/a7f32b13fb676403ee50cba71fb58b21419f40bc1241ead4ccffd08ee253/gevent-25.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd59c0dbcae2808a1e26e07d3858b5a935635be195c8ea967a4bc32599381523", size = 1812146, upload-time = "2025-04-24T14:45:45.525Z" }, - { url = "https://files.pythonhosted.org/packages/37/72/64caed658faa11594c15e09e99af350662bc8d5178c0895fe2f2738576c5/gevent-25.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ccbc835939416a7df7834b79c655409a2a9d2deb9bf119b28dedf72a168f7895", size = 2089655, upload-time = "2025-04-24T14:17:55.829Z" }, - { url = "https://files.pythonhosted.org/packages/fd/3f/490836ec293a178dce91d4f0f3e1dd60d1afad14273009c941821ce7f42f/gevent-25.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:feb5f2f44dcdad1a6b80e7ce24e7557ce25d01ff13b7a74ca276d113adf9d4af", size = 1815163, upload-time = "2025-04-24T14:56:00.085Z" }, - { url = "https://files.pythonhosted.org/packages/9f/2f/4c884332d2a57a0e49591627fb66203e09c43d065590cc20b3e48d83e11e/gevent-25.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:91408dd197c13ca0f1e0d5cdcc9870c674963bb87a7e370b2884d1426d73834f", size = 2117584, upload-time = "2025-04-24T14:20:31.844Z" }, - { url = "https://files.pythonhosted.org/packages/77/65/43316b582320520ae461792aa6b4c0d76a87f91c01b8d20a9836a873c186/gevent-25.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:12b596c027cf546a235231d421473483fdf7fa586d38162d36b07c8efa9081ba", size = 1682411, upload-time = "2025-04-24T15:26:50.78Z" }, - { url = "https://files.pythonhosted.org/packages/43/67/3c9a560d3b64510dc053714375b3d9f2c3d98192dc85b78a6e6f8b9a284b/gevent-25.4.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5940174c7d1ffc7bb4b0ea9f2908f4f361eb03ada9e145d3590b8df1e61c379b", size = 2969979, upload-time = "2025-04-24T13:53:02.272Z" }, - { url = "https://files.pythonhosted.org/packages/39/ee/594a40e09d9d56b76a04265ea37b825ec8e7b98cd41e8012eda413f233e6/gevent-25.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b7ae7ad4ff9c4492d4b633702e35153509b07dc6ffd20f1577076d7647c9caba", size = 1805780, upload-time = "2025-04-24T14:41:07.77Z" }, - { url = "https://files.pythonhosted.org/packages/d6/87/0707bfae4cc3728eb8d5fc29018b5ac3e0e1f8efca237d267d1d3abc7153/gevent-25.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d68fdf9bff0068367126983d7d85765124c292b4bc3d4d19ed8138335d8426a7", size = 1885718, upload-time = "2025-04-24T14:38:56.616Z" }, - { url = "https://files.pythonhosted.org/packages/09/c6/4f35473d46ca8cfbffeee5e6f89ac29370280b3f34682ed8f0fea907f987/gevent-25.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ff92408011d78e4ffe297331ff30cded39a3e22845ba237516c646f6a485a241", size = 1845102, upload-time = "2025-04-24T14:45:47.309Z" }, - { url = "https://files.pythonhosted.org/packages/7a/9b/d2269957be2867802d10bcb28e17eba64783067057d55e91e57207294c05/gevent-25.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a7c70ab6d33dfeb43bfe982c636609d8f90506dacaaa1f409a3c43c66d578fb1", size = 2084973, upload-time = "2025-04-24T14:17:57.551Z" }, - { url = "https://files.pythonhosted.org/packages/6b/59/9a069d16d8b6b7ef82b0d241de9041b1341c9f132fbd096b80d6d1bc2345/gevent-25.4.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:8e740bc08ba4c34951f4bb6351dbe04209416e12d620691fb57e115b218a7818", size = 1822891, upload-time = "2025-04-24T14:56:02.733Z" }, - { url = "https://files.pythonhosted.org/packages/96/0d/815808f04cef2410a93521814e51de7554874012fc49c5ca7197f86ac340/gevent-25.4.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c535d96ded6e26b37fadda9242a49fea6308754da5945173940614b7520c07b4", size = 2115665, upload-time = "2025-04-24T14:20:33.14Z" }, - { url = "https://files.pythonhosted.org/packages/42/b4/15e5f9c06d50843c0e7c87d580acc2ac4e47fef0195c2d3f73c3bd54e3f0/gevent-25.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:c62bf14557d2cb54f5e3c1ba0a3b3f4b69bf0441081c32d63b205763b495b251", size = 1679652, upload-time = "2025-04-24T15:18:59.902Z" }, - { url = "https://files.pythonhosted.org/packages/7d/1d/195936c1e0c5b1dc89a8b534c05d080d24d760f6913632cbb13d9430c907/gevent-25.4.2-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:f735f57bc19d0f8bbc784093cfb7953a9ad66612b05c3ff876ec7951a96d7edd", size = 2996686, upload-time = "2025-04-24T13:54:13.935Z" }, - { url = "https://files.pythonhosted.org/packages/52/2a/a82de55db10ca17e210a61548a421d65d144045a62958d172537d4ea6f26/gevent-25.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63aecf1e43b8d01086ea574ed05f7272ed40c48dd41fa3d061e3c5ca900abcdd", size = 1809379, upload-time = "2025-04-24T14:41:09.455Z" }, - { url = "https://files.pythonhosted.org/packages/77/73/3508d539c96e435d883aa07c67ad5859505af33346795c8c575501d3ebda/gevent-25.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f12e570777027f807dc7dc3ea1945ea040befaf1c9485deb6f24d7110009fc12", size = 1887353, upload-time = "2025-04-24T14:38:58.497Z" }, - { url = "https://files.pythonhosted.org/packages/4d/40/911e4eca7958bea73d3889433e780b59413f3d7bbd4d24cadc0a2f276528/gevent-25.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44acca4196d4a174c2b4817642564526898f42f72992dc1818b834b2bbf17582", size = 1848809, upload-time = "2025-04-24T14:45:49.118Z" }, - { url = "https://files.pythonhosted.org/packages/59/eb/ccf5a2d7cb8ed2814b69fbe9cf46a8875f275fa0e5984889b1cbb0a67492/gevent-25.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:75d2fdd24f3948c085d341281648014760f5cb23de9b29f710083e6911b2e605", size = 2084966, upload-time = "2025-04-24T14:17:58.762Z" }, - { url = "https://files.pythonhosted.org/packages/7d/19/a1aadd6f3da55f18bb10877ccda7245be0c3b5e6acdc3c882fe54f412e01/gevent-25.4.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:0cc1d6093f482547ac522ab1a985429d8c12494518eeca354c956f0ff6de7a94", size = 1824458, upload-time = "2025-04-24T14:56:04.588Z" }, - { url = "https://files.pythonhosted.org/packages/0f/70/ee8b5a4df0a6f587c44a102ad46356d626d652e35f46eeec05c5ba1575de/gevent-25.4.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:fe4a3e3fa3a16ed9b12b6ff0922208ef83287e066e696b82b96d33723d8207f2", size = 2116628, upload-time = "2025-04-24T14:20:34.344Z" }, - { url = "https://files.pythonhosted.org/packages/13/c6/50ee863dd09dd31f61892b847b684fde730473487bcae3240acd9e3e412c/gevent-25.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:8b90913360b1af058b279160679d804d4917a8661f128b2f7625f8665c39450f", size = 1678856, upload-time = "2025-04-24T15:09:25.348Z" }, - { url = "https://files.pythonhosted.org/packages/54/d8/e29cc7f90ae7aa9e8f5298ca5a157bab34bfbc65d070385b28f4d72af1ac/gevent-25.4.2-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:b0a656eccd9cb115d01c9bbe55bfe84cf20c8422c495503f41aef747b193c33d", size = 3007128, upload-time = "2025-04-24T13:54:45.421Z" }, - { url = "https://files.pythonhosted.org/packages/d7/de/1ef71b44947a8eed12f852a2b68fd5df4219e38645202d7835f2b727303f/gevent-25.4.2-pp310-pypy310_pp73-macosx_11_0_universal2.whl", hash = "sha256:498f548330c4724e3b0cee0d75551165fc9e4309ae3ddcba3d644aaa866ca9c3", size = 1288325, upload-time = "2025-04-24T13:54:37.995Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/9e/48/b3ef2673ffb940f980966694e40d6d32560f3ffa284ecaeb5ea3a90a6d3f/gevent-25.9.1.tar.gz", hash = "sha256:adf9cd552de44a4e6754c51ff2e78d9193b7fa6eab123db9578a210e657235dd", size = 5059025, upload-time = "2025-09-17T16:15:34.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ae/c7/2c60fc4e5c9144f2b91e23af8d87c626870ad3183cfd09d2b3ba6d699178/gevent-25.9.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:856b990be5590e44c3a3dc6c8d48a40eaccbb42e99d2b791d11d1e7711a4297e", size = 1831980, upload-time = "2025-09-17T15:41:22.597Z" }, + { url = "https://files.pythonhosted.org/packages/2e/ae/49bf0a01f95a1c92c001d7b3f482a2301626b8a0617f448c4cd14ca9b5d4/gevent-25.9.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:fe1599d0b30e6093eb3213551751b24feeb43db79f07e89d98dd2f3330c9063e", size = 1918777, upload-time = "2025-09-17T15:48:57.223Z" }, + { url = "https://files.pythonhosted.org/packages/88/3f/266d2eb9f5d75c184a55a39e886b53a4ea7f42ff31f195220a363f0e3f9e/gevent-25.9.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:f0d8b64057b4bf1529b9ef9bd2259495747fba93d1f836c77bfeaacfec373fd0", size = 1869235, upload-time = "2025-09-17T15:49:18.255Z" }, + { url = "https://files.pythonhosted.org/packages/76/24/c0c7c7db70ca74c7b1918388ebda7c8c2a3c3bff0bbfbaa9280ed04b3340/gevent-25.9.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b56cbc820e3136ba52cd690bdf77e47a4c239964d5f80dc657c1068e0fe9521c", size = 2177334, upload-time = "2025-09-17T15:15:10.073Z" }, + { url = "https://files.pythonhosted.org/packages/4c/1e/de96bd033c03955f54c455b51a5127b1d540afcfc97838d1801fafce6d2e/gevent-25.9.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c5fa9ce5122c085983e33e0dc058f81f5264cebe746de5c401654ab96dddfca8", size = 1847708, upload-time = "2025-09-17T15:52:38.475Z" }, + { url = "https://files.pythonhosted.org/packages/26/8b/6851e9cd3e4f322fa15c1d196cbf1a8a123da69788b078227dd13dd4208f/gevent-25.9.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:03c74fec58eda4b4edc043311fca8ba4f8744ad1632eb0a41d5ec25413581975", size = 2234274, upload-time = "2025-09-17T15:24:07.797Z" }, + { url = "https://files.pythonhosted.org/packages/0f/d8/b1178b70538c91493bec283018b47c16eab4bac9ddf5a3d4b7dd905dab60/gevent-25.9.1-cp310-cp310-win_amd64.whl", hash = "sha256:a8ae9f895e8651d10b0a8328a61c9c53da11ea51b666388aa99b0ce90f9fdc27", size = 1695326, upload-time = "2025-09-17T20:10:25.455Z" }, + { url = "https://files.pythonhosted.org/packages/81/86/03f8db0704fed41b0fa830425845f1eb4e20c92efa3f18751ee17809e9c6/gevent-25.9.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:18e5aff9e8342dc954adb9c9c524db56c2f3557999463445ba3d9cbe3dada7b7", size = 1792418, upload-time = "2025-09-17T15:41:24.384Z" }, + { url = "https://files.pythonhosted.org/packages/5f/35/f6b3a31f0849a62cfa2c64574bcc68a781d5499c3195e296e892a121a3cf/gevent-25.9.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1cdf6db28f050ee103441caa8b0448ace545364f775059d5e2de089da975c457", size = 1875700, upload-time = "2025-09-17T15:48:59.652Z" }, + { url = "https://files.pythonhosted.org/packages/66/1e/75055950aa9b48f553e061afa9e3728061b5ccecca358cef19166e4ab74a/gevent-25.9.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:812debe235a8295be3b2a63b136c2474241fa5c58af55e6a0f8cfc29d4936235", size = 1831365, upload-time = "2025-09-17T15:49:19.426Z" }, + { url = "https://files.pythonhosted.org/packages/31/e8/5c1f6968e5547e501cfa03dcb0239dff55e44c3660a37ec534e32a0c008f/gevent-25.9.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b28b61ff9216a3d73fe8f35669eefcafa957f143ac534faf77e8a19eb9e6883a", size = 2122087, upload-time = "2025-09-17T15:15:12.329Z" }, + { url = "https://files.pythonhosted.org/packages/c0/2c/ebc5d38a7542af9fb7657bfe10932a558bb98c8a94e4748e827d3823fced/gevent-25.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5e4b6278b37373306fc6b1e5f0f1cf56339a1377f67c35972775143d8d7776ff", size = 1808776, upload-time = "2025-09-17T15:52:40.16Z" }, + { url = "https://files.pythonhosted.org/packages/e6/26/e1d7d6c8ffbf76fe1fbb4e77bdb7f47d419206adc391ec40a8ace6ebbbf0/gevent-25.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d99f0cb2ce43c2e8305bf75bee61a8bde06619d21b9d0316ea190fc7a0620a56", size = 2179141, upload-time = "2025-09-17T15:24:09.895Z" }, + { url = "https://files.pythonhosted.org/packages/1d/6c/bb21fd9c095506aeeaa616579a356aa50935165cc0f1e250e1e0575620a7/gevent-25.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:72152517ecf548e2f838c61b4be76637d99279dbaa7e01b3924df040aa996586", size = 1677941, upload-time = "2025-09-17T19:59:50.185Z" }, + { url = "https://files.pythonhosted.org/packages/f7/49/e55930ba5259629eb28ac7ee1abbca971996a9165f902f0249b561602f24/gevent-25.9.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:46b188248c84ffdec18a686fcac5dbb32365d76912e14fda350db5dc0bfd4f86", size = 2955991, upload-time = "2025-09-17T14:52:30.568Z" }, + { url = "https://files.pythonhosted.org/packages/aa/88/63dc9e903980e1da1e16541ec5c70f2b224ec0a8e34088cb42794f1c7f52/gevent-25.9.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f2b54ea3ca6f0c763281cd3f96010ac7e98c2e267feb1221b5a26e2ca0b9a692", size = 1808503, upload-time = "2025-09-17T15:41:25.59Z" }, + { url = "https://files.pythonhosted.org/packages/7a/8d/7236c3a8f6ef7e94c22e658397009596fa90f24c7d19da11ad7ab3a9248e/gevent-25.9.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7a834804ac00ed8a92a69d3826342c677be651b1c3cd66cc35df8bc711057aa2", size = 1890001, upload-time = "2025-09-17T15:49:01.227Z" }, + { url = "https://files.pythonhosted.org/packages/4f/63/0d7f38c4a2085ecce26b50492fc6161aa67250d381e26d6a7322c309b00f/gevent-25.9.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:323a27192ec4da6b22a9e51c3d9d896ff20bc53fdc9e45e56eaab76d1c39dd74", size = 1855335, upload-time = "2025-09-17T15:49:20.582Z" }, + { url = "https://files.pythonhosted.org/packages/95/18/da5211dfc54c7a57e7432fd9a6ffeae1ce36fe5a313fa782b1c96529ea3d/gevent-25.9.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6ea78b39a2c51d47ff0f130f4c755a9a4bbb2dd9721149420ad4712743911a51", size = 2109046, upload-time = "2025-09-17T15:15:13.817Z" }, + { url = "https://files.pythonhosted.org/packages/a6/5a/7bb5ec8e43a2c6444853c4a9f955f3e72f479d7c24ea86c95fb264a2de65/gevent-25.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:dc45cd3e1cc07514a419960af932a62eb8515552ed004e56755e4bf20bad30c5", size = 1827099, upload-time = "2025-09-17T15:52:41.384Z" }, + { url = "https://files.pythonhosted.org/packages/ca/d4/b63a0a60635470d7d986ef19897e893c15326dd69e8fb342c76a4f07fe9e/gevent-25.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:34e01e50c71eaf67e92c186ee0196a039d6e4f4b35670396baed4a2d8f1b347f", size = 2172623, upload-time = "2025-09-17T15:24:12.03Z" }, + { url = "https://files.pythonhosted.org/packages/d5/98/caf06d5d22a7c129c1fb2fc1477306902a2c8ddfd399cd26bbbd4caf2141/gevent-25.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:4acd6bcd5feabf22c7c5174bd3b9535ee9f088d2bbce789f740ad8d6554b18f3", size = 1682837, upload-time = "2025-09-17T19:48:47.318Z" }, + { url = "https://files.pythonhosted.org/packages/5a/77/b97f086388f87f8ad3e01364f845004aef0123d4430241c7c9b1f9bde742/gevent-25.9.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:4f84591d13845ee31c13f44bdf6bd6c3dbf385b5af98b2f25ec328213775f2ed", size = 2973739, upload-time = "2025-09-17T14:53:30.279Z" }, + { url = "https://files.pythonhosted.org/packages/3c/2e/9d5f204ead343e5b27bbb2fedaec7cd0009d50696b2266f590ae845d0331/gevent-25.9.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9cdbb24c276a2d0110ad5c978e49daf620b153719ac8a548ce1250a7eb1b9245", size = 1809165, upload-time = "2025-09-17T15:41:27.193Z" }, + { url = "https://files.pythonhosted.org/packages/10/3e/791d1bf1eb47748606d5f2c2aa66571f474d63e0176228b1f1fd7b77ab37/gevent-25.9.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:88b6c07169468af631dcf0fdd3658f9246d6822cc51461d43f7c44f28b0abb82", size = 1890638, upload-time = "2025-09-17T15:49:02.45Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5c/9ad0229b2b4d81249ca41e4f91dd8057deaa0da6d4fbe40bf13cdc5f7a47/gevent-25.9.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b7bb0e29a7b3e6ca9bed2394aa820244069982c36dc30b70eb1004dd67851a48", size = 1857118, upload-time = "2025-09-17T15:49:22.125Z" }, + { url = "https://files.pythonhosted.org/packages/49/2a/3010ed6c44179a3a5c5c152e6de43a30ff8bc2c8de3115ad8733533a018f/gevent-25.9.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2951bb070c0ee37b632ac9134e4fdaad70d2e660c931bb792983a0837fe5b7d7", size = 2111598, upload-time = "2025-09-17T15:15:15.226Z" }, + { url = "https://files.pythonhosted.org/packages/08/75/6bbe57c19a7aa4527cc0f9afcdf5a5f2aed2603b08aadbccb5bf7f607ff4/gevent-25.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4e17c2d57e9a42e25f2a73d297b22b60b2470a74be5a515b36c984e1a246d47", size = 1829059, upload-time = "2025-09-17T15:52:42.596Z" }, + { url = "https://files.pythonhosted.org/packages/06/6e/19a9bee9092be45679cb69e4dd2e0bf5f897b7140b4b39c57cc123d24829/gevent-25.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8d94936f8f8b23d9de2251798fcb603b84f083fdf0d7f427183c1828fb64f117", size = 2173529, upload-time = "2025-09-17T15:24:13.897Z" }, + { url = "https://files.pythonhosted.org/packages/ca/4f/50de9afd879440e25737e63f5ba6ee764b75a3abe17376496ab57f432546/gevent-25.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:eb51c5f9537b07da673258b4832f6635014fee31690c3f0944d34741b69f92fa", size = 1681518, upload-time = "2025-09-17T19:39:47.488Z" }, + { url = "https://files.pythonhosted.org/packages/15/1a/948f8167b2cdce573cf01cec07afc64d0456dc134b07900b26ac7018b37e/gevent-25.9.1-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:1a3fe4ea1c312dbf6b375b416925036fe79a40054e6bf6248ee46526ea628be1", size = 2982934, upload-time = "2025-09-17T14:54:11.302Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ec/726b146d1d3aad82e03d2e1e1507048ab6072f906e83f97f40667866e582/gevent-25.9.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0adb937f13e5fb90cca2edf66d8d7e99d62a299687400ce2edee3f3504009356", size = 1813982, upload-time = "2025-09-17T15:41:28.506Z" }, + { url = "https://files.pythonhosted.org/packages/35/5d/5f83f17162301662bd1ce702f8a736a8a8cac7b7a35e1d8b9866938d1f9d/gevent-25.9.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:427f869a2050a4202d93cf7fd6ab5cffb06d3e9113c10c967b6e2a0d45237cb8", size = 1894902, upload-time = "2025-09-17T15:49:03.702Z" }, + { url = "https://files.pythonhosted.org/packages/83/cd/cf5e74e353f60dab357829069ffc300a7bb414c761f52cf8c0c6e9728b8d/gevent-25.9.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:c049880175e8c93124188f9d926af0a62826a3b81aa6d3074928345f8238279e", size = 1861792, upload-time = "2025-09-17T15:49:23.279Z" }, + { url = "https://files.pythonhosted.org/packages/dd/65/b9a4526d4a4edce26fe4b3b993914ec9dc64baabad625a3101e51adb17f3/gevent-25.9.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b5a67a0974ad9f24721034d1e008856111e0535f1541499f72a733a73d658d1c", size = 2113215, upload-time = "2025-09-17T15:15:16.34Z" }, + { url = "https://files.pythonhosted.org/packages/e5/be/7d35731dfaf8370795b606e515d964a0967e129db76ea7873f552045dd39/gevent-25.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1d0f5d8d73f97e24ea8d24d8be0f51e0cf7c54b8021c1fddb580bf239474690f", size = 1833449, upload-time = "2025-09-17T15:52:43.75Z" }, + { url = "https://files.pythonhosted.org/packages/65/58/7bc52544ea5e63af88c4a26c90776feb42551b7555a1c89c20069c168a3f/gevent-25.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddd3ff26e5c4240d3fbf5516c2d9d5f2a998ef87cfb73e1429cfaeaaec860fa6", size = 2176034, upload-time = "2025-09-17T15:24:15.676Z" }, + { url = "https://files.pythonhosted.org/packages/c2/69/a7c4ba2ffbc7c7dbf6d8b4f5d0f0a421f7815d229f4909854266c445a3d4/gevent-25.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:bb63c0d6cb9950cc94036a4995b9cc4667b8915366613449236970f4394f94d7", size = 1703019, upload-time = "2025-09-17T19:30:55.272Z" }, ] [[package]] @@ -672,50 +656,63 @@ wheels = [ [[package]] name = "grpcio" -version = "1.73.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/e8/b43b851537da2e2f03fa8be1aef207e5cbfb1a2e014fbb6b40d24c177cd3/grpcio-1.73.1.tar.gz", hash = "sha256:7fce2cd1c0c1116cf3850564ebfc3264fba75d3c74a7414373f1238ea365ef87", size = 12730355, upload-time = "2025-06-26T01:53:24.622Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8f/51/a5748ab2773d893d099b92653039672f7e26dd35741020972b84d604066f/grpcio-1.73.1-cp310-cp310-linux_armv7l.whl", hash = "sha256:2d70f4ddd0a823436c2624640570ed6097e40935c9194482475fe8e3d9754d55", size = 5365087, upload-time = "2025-06-26T01:51:44.541Z" }, - { url = "https://files.pythonhosted.org/packages/ae/12/c5ee1a5dfe93dbc2eaa42a219e2bf887250b52e2e2ee5c036c4695f2769c/grpcio-1.73.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:3841a8a5a66830261ab6a3c2a3dc539ed84e4ab019165f77b3eeb9f0ba621f26", size = 10608921, upload-time = "2025-06-26T01:51:48.111Z" }, - { url = "https://files.pythonhosted.org/packages/c4/6d/b0c6a8120f02b7d15c5accda6bfc43bc92be70ada3af3ba6d8e077c00374/grpcio-1.73.1-cp310-cp310-manylinux_2_17_aarch64.whl", hash = "sha256:628c30f8e77e0258ab788750ec92059fc3d6628590fb4b7cea8c102503623ed7", size = 5803221, upload-time = "2025-06-26T01:51:50.486Z" }, - { url = "https://files.pythonhosted.org/packages/a6/7a/3c886d9f1c1e416ae81f7f9c7d1995ae72cd64712d29dab74a6bafacb2d2/grpcio-1.73.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:67a0468256c9db6d5ecb1fde4bf409d016f42cef649323f0a08a72f352d1358b", size = 6444603, upload-time = "2025-06-26T01:51:52.203Z" }, - { url = "https://files.pythonhosted.org/packages/42/07/f143a2ff534982c9caa1febcad1c1073cdec732f6ac7545d85555a900a7e/grpcio-1.73.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68b84d65bbdebd5926eb5c53b0b9ec3b3f83408a30e4c20c373c5337b4219ec5", size = 6040969, upload-time = "2025-06-26T01:51:55.028Z" }, - { url = "https://files.pythonhosted.org/packages/fb/0f/523131b7c9196d0718e7b2dac0310eb307b4117bdbfef62382e760f7e8bb/grpcio-1.73.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c54796ca22b8349cc594d18b01099e39f2b7ffb586ad83217655781a350ce4da", size = 6132201, upload-time = "2025-06-26T01:51:56.867Z" }, - { url = "https://files.pythonhosted.org/packages/ad/18/010a055410eef1d3a7a1e477ec9d93b091ac664ad93e9c5f56d6cc04bdee/grpcio-1.73.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:75fc8e543962ece2f7ecd32ada2d44c0c8570ae73ec92869f9af8b944863116d", size = 6774718, upload-time = "2025-06-26T01:51:58.338Z" }, - { url = "https://files.pythonhosted.org/packages/16/11/452bfc1ab39d8ee748837ab8ee56beeae0290861052948785c2c445fb44b/grpcio-1.73.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6a6037891cd2b1dd1406b388660522e1565ed340b1fea2955b0234bdd941a862", size = 6304362, upload-time = "2025-06-26T01:51:59.802Z" }, - { url = "https://files.pythonhosted.org/packages/1e/1c/c75ceee626465721e5cb040cf4b271eff817aa97388948660884cb7adffa/grpcio-1.73.1-cp310-cp310-win32.whl", hash = "sha256:cce7265b9617168c2d08ae570fcc2af4eaf72e84f8c710ca657cc546115263af", size = 3679036, upload-time = "2025-06-26T01:52:01.817Z" }, - { url = "https://files.pythonhosted.org/packages/62/2e/42cb31b6cbd671a7b3dbd97ef33f59088cf60e3cf2141368282e26fafe79/grpcio-1.73.1-cp310-cp310-win_amd64.whl", hash = "sha256:6a2b372e65fad38842050943f42ce8fee00c6f2e8ea4f7754ba7478d26a356ee", size = 4340208, upload-time = "2025-06-26T01:52:03.674Z" }, - { url = "https://files.pythonhosted.org/packages/e4/41/921565815e871d84043e73e2c0e748f0318dab6fa9be872cd042778f14a9/grpcio-1.73.1-cp311-cp311-linux_armv7l.whl", hash = "sha256:ba2cea9f7ae4bc21f42015f0ec98f69ae4179848ad744b210e7685112fa507a1", size = 5363853, upload-time = "2025-06-26T01:52:05.5Z" }, - { url = "https://files.pythonhosted.org/packages/b0/cc/9c51109c71d068e4d474becf5f5d43c9d63038cec1b74112978000fa72f4/grpcio-1.73.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:d74c3f4f37b79e746271aa6cdb3a1d7e4432aea38735542b23adcabaaee0c097", size = 10621476, upload-time = "2025-06-26T01:52:07.211Z" }, - { url = "https://files.pythonhosted.org/packages/8f/d3/33d738a06f6dbd4943f4d377468f8299941a7c8c6ac8a385e4cef4dd3c93/grpcio-1.73.1-cp311-cp311-manylinux_2_17_aarch64.whl", hash = "sha256:5b9b1805a7d61c9e90541cbe8dfe0a593dfc8c5c3a43fe623701b6a01b01d710", size = 5807903, upload-time = "2025-06-26T01:52:09.466Z" }, - { url = "https://files.pythonhosted.org/packages/5d/47/36deacd3c967b74e0265f4c608983e897d8bb3254b920f8eafdf60e4ad7e/grpcio-1.73.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3215f69a0670a8cfa2ab53236d9e8026bfb7ead5d4baabe7d7dc11d30fda967", size = 6448172, upload-time = "2025-06-26T01:52:11.459Z" }, - { url = "https://files.pythonhosted.org/packages/0e/64/12d6dc446021684ee1428ea56a3f3712048a18beeadbdefa06e6f8814a6e/grpcio-1.73.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc5eccfd9577a5dc7d5612b2ba90cca4ad14c6d949216c68585fdec9848befb1", size = 6044226, upload-time = "2025-06-26T01:52:12.987Z" }, - { url = "https://files.pythonhosted.org/packages/72/4b/6bae2d88a006000f1152d2c9c10ffd41d0131ca1198e0b661101c2e30ab9/grpcio-1.73.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:dc7d7fd520614fce2e6455ba89791458020a39716951c7c07694f9dbae28e9c0", size = 6135690, upload-time = "2025-06-26T01:52:14.92Z" }, - { url = "https://files.pythonhosted.org/packages/38/64/02c83b5076510784d1305025e93e0d78f53bb6a0213c8c84cfe8a00c5c48/grpcio-1.73.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:105492124828911f85127e4825d1c1234b032cb9d238567876b5515d01151379", size = 6775867, upload-time = "2025-06-26T01:52:16.446Z" }, - { url = "https://files.pythonhosted.org/packages/42/72/a13ff7ba6c68ccffa35dacdc06373a76c0008fd75777cba84d7491956620/grpcio-1.73.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:610e19b04f452ba6f402ac9aa94eb3d21fbc94553368008af634812c4a85a99e", size = 6308380, upload-time = "2025-06-26T01:52:18.417Z" }, - { url = "https://files.pythonhosted.org/packages/65/ae/d29d948021faa0070ec33245c1ae354e2aefabd97e6a9a7b6dcf0fb8ef6b/grpcio-1.73.1-cp311-cp311-win32.whl", hash = "sha256:d60588ab6ba0ac753761ee0e5b30a29398306401bfbceffe7d68ebb21193f9d4", size = 3679139, upload-time = "2025-06-26T01:52:20.171Z" }, - { url = "https://files.pythonhosted.org/packages/af/66/e1bbb0c95ea222947f0829b3db7692c59b59bcc531df84442e413fa983d9/grpcio-1.73.1-cp311-cp311-win_amd64.whl", hash = "sha256:6957025a4608bb0a5ff42abd75bfbb2ed99eda29d5992ef31d691ab54b753643", size = 4342558, upload-time = "2025-06-26T01:52:22.137Z" }, - { url = "https://files.pythonhosted.org/packages/b8/41/456caf570c55d5ac26f4c1f2db1f2ac1467d5bf3bcd660cba3e0a25b195f/grpcio-1.73.1-cp312-cp312-linux_armv7l.whl", hash = "sha256:921b25618b084e75d424a9f8e6403bfeb7abef074bb6c3174701e0f2542debcf", size = 5334621, upload-time = "2025-06-26T01:52:23.602Z" }, - { url = "https://files.pythonhosted.org/packages/2a/c2/9a15e179e49f235bb5e63b01590658c03747a43c9775e20c4e13ca04f4c4/grpcio-1.73.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:277b426a0ed341e8447fbf6c1d6b68c952adddf585ea4685aa563de0f03df887", size = 10601131, upload-time = "2025-06-26T01:52:25.691Z" }, - { url = "https://files.pythonhosted.org/packages/0c/1d/1d39e90ef6348a0964caa7c5c4d05f3bae2c51ab429eb7d2e21198ac9b6d/grpcio-1.73.1-cp312-cp312-manylinux_2_17_aarch64.whl", hash = "sha256:96c112333309493c10e118d92f04594f9055774757f5d101b39f8150f8c25582", size = 5759268, upload-time = "2025-06-26T01:52:27.631Z" }, - { url = "https://files.pythonhosted.org/packages/8a/2b/2dfe9ae43de75616177bc576df4c36d6401e0959833b2e5b2d58d50c1f6b/grpcio-1.73.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f48e862aed925ae987eb7084409a80985de75243389dc9d9c271dd711e589918", size = 6409791, upload-time = "2025-06-26T01:52:29.711Z" }, - { url = "https://files.pythonhosted.org/packages/6e/66/e8fe779b23b5a26d1b6949e5c70bc0a5fd08f61a6ec5ac7760d589229511/grpcio-1.73.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:83a6c2cce218e28f5040429835fa34a29319071079e3169f9543c3fbeff166d2", size = 6003728, upload-time = "2025-06-26T01:52:31.352Z" }, - { url = "https://files.pythonhosted.org/packages/a9/39/57a18fcef567784108c4fc3f5441cb9938ae5a51378505aafe81e8e15ecc/grpcio-1.73.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:65b0458a10b100d815a8426b1442bd17001fdb77ea13665b2f7dc9e8587fdc6b", size = 6103364, upload-time = "2025-06-26T01:52:33.028Z" }, - { url = "https://files.pythonhosted.org/packages/c5/46/28919d2aa038712fc399d02fa83e998abd8c1f46c2680c5689deca06d1b2/grpcio-1.73.1-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:0a9f3ea8dce9eae9d7cb36827200133a72b37a63896e0e61a9d5ec7d61a59ab1", size = 6749194, upload-time = "2025-06-26T01:52:34.734Z" }, - { url = "https://files.pythonhosted.org/packages/3d/56/3898526f1fad588c5d19a29ea0a3a4996fb4fa7d7c02dc1be0c9fd188b62/grpcio-1.73.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:de18769aea47f18e782bf6819a37c1c528914bfd5683b8782b9da356506190c8", size = 6283902, upload-time = "2025-06-26T01:52:36.503Z" }, - { url = "https://files.pythonhosted.org/packages/dc/64/18b77b89c5870d8ea91818feb0c3ffb5b31b48d1b0ee3e0f0d539730fea3/grpcio-1.73.1-cp312-cp312-win32.whl", hash = "sha256:24e06a5319e33041e322d32c62b1e728f18ab8c9dbc91729a3d9f9e3ed336642", size = 3668687, upload-time = "2025-06-26T01:52:38.678Z" }, - { url = "https://files.pythonhosted.org/packages/3c/52/302448ca6e52f2a77166b2e2ed75f5d08feca4f2145faf75cb768cccb25b/grpcio-1.73.1-cp312-cp312-win_amd64.whl", hash = "sha256:303c8135d8ab176f8038c14cc10d698ae1db9c480f2b2823f7a987aa2a4c5646", size = 4334887, upload-time = "2025-06-26T01:52:40.743Z" }, - { url = "https://files.pythonhosted.org/packages/37/bf/4ca20d1acbefabcaba633ab17f4244cbbe8eca877df01517207bd6655914/grpcio-1.73.1-cp313-cp313-linux_armv7l.whl", hash = "sha256:b310824ab5092cf74750ebd8a8a8981c1810cb2b363210e70d06ef37ad80d4f9", size = 5335615, upload-time = "2025-06-26T01:52:42.896Z" }, - { url = "https://files.pythonhosted.org/packages/75/ed/45c345f284abec5d4f6d77cbca9c52c39b554397eb7de7d2fcf440bcd049/grpcio-1.73.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:8f5a6df3fba31a3485096ac85b2e34b9666ffb0590df0cd044f58694e6a1f6b5", size = 10595497, upload-time = "2025-06-26T01:52:44.695Z" }, - { url = "https://files.pythonhosted.org/packages/a4/75/bff2c2728018f546d812b755455014bc718f8cdcbf5c84f1f6e5494443a8/grpcio-1.73.1-cp313-cp313-manylinux_2_17_aarch64.whl", hash = "sha256:052e28fe9c41357da42250a91926a3e2f74c046575c070b69659467ca5aa976b", size = 5765321, upload-time = "2025-06-26T01:52:46.871Z" }, - { url = "https://files.pythonhosted.org/packages/70/3b/14e43158d3b81a38251b1d231dfb45a9b492d872102a919fbf7ba4ac20cd/grpcio-1.73.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1c0bf15f629b1497436596b1cbddddfa3234273490229ca29561209778ebe182", size = 6415436, upload-time = "2025-06-26T01:52:49.134Z" }, - { url = "https://files.pythonhosted.org/packages/e5/3f/81d9650ca40b54338336fd360f36773be8cb6c07c036e751d8996eb96598/grpcio-1.73.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ab860d5bfa788c5a021fba264802e2593688cd965d1374d31d2b1a34cacd854", size = 6007012, upload-time = "2025-06-26T01:52:51.076Z" }, - { url = "https://files.pythonhosted.org/packages/55/f4/59edf5af68d684d0f4f7ad9462a418ac517201c238551529098c9aa28cb0/grpcio-1.73.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ad1d958c31cc91ab050bd8a91355480b8e0683e21176522bacea225ce51163f2", size = 6105209, upload-time = "2025-06-26T01:52:52.773Z" }, - { url = "https://files.pythonhosted.org/packages/e4/a8/700d034d5d0786a5ba14bfa9ce974ed4c976936c2748c2bd87aa50f69b36/grpcio-1.73.1-cp313-cp313-musllinux_1_1_i686.whl", hash = "sha256:f43ffb3bd415c57224c7427bfb9e6c46a0b6e998754bfa0d00f408e1873dcbb5", size = 6753655, upload-time = "2025-06-26T01:52:55.064Z" }, - { url = "https://files.pythonhosted.org/packages/1f/29/efbd4ac837c23bc48e34bbaf32bd429f0dc9ad7f80721cdb4622144c118c/grpcio-1.73.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:686231cdd03a8a8055f798b2b54b19428cdf18fa1549bee92249b43607c42668", size = 6287288, upload-time = "2025-06-26T01:52:57.33Z" }, - { url = "https://files.pythonhosted.org/packages/d8/61/c6045d2ce16624bbe18b5d169c1a5ce4d6c3a47bc9d0e5c4fa6a50ed1239/grpcio-1.73.1-cp313-cp313-win32.whl", hash = "sha256:89018866a096e2ce21e05eabed1567479713ebe57b1db7cbb0f1e3b896793ba4", size = 3668151, upload-time = "2025-06-26T01:52:59.405Z" }, - { url = "https://files.pythonhosted.org/packages/c2/d7/77ac689216daee10de318db5aa1b88d159432dc76a130948a56b3aa671a2/grpcio-1.73.1-cp313-cp313-win_amd64.whl", hash = "sha256:4a68f8c9966b94dff693670a5cf2b54888a48a5011c5d9ce2295a1a1465ee84f", size = 4335747, upload-time = "2025-06-26T01:53:01.233Z" }, +version = "1.76.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b6/e0/318c1ce3ae5a17894d5791e87aea147587c9e702f24122cc7a5c8bbaeeb1/grpcio-1.76.0.tar.gz", hash = "sha256:7be78388d6da1a25c0d5ec506523db58b18be22d9c37d8d3a32c08be4987bd73", size = 12785182, upload-time = "2025-10-21T16:23:12.106Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/88/17/ff4795dc9a34b6aee6ec379f1b66438a3789cd1315aac0cbab60d92f74b3/grpcio-1.76.0-cp310-cp310-linux_armv7l.whl", hash = "sha256:65a20de41e85648e00305c1bb09a3598f840422e522277641145a32d42dcefcc", size = 5840037, upload-time = "2025-10-21T16:20:25.069Z" }, + { url = "https://files.pythonhosted.org/packages/4e/ff/35f9b96e3fa2f12e1dcd58a4513a2e2294a001d64dec81677361b7040c9a/grpcio-1.76.0-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:40ad3afe81676fd9ec6d9d406eda00933f218038433980aa19d401490e46ecde", size = 11836482, upload-time = "2025-10-21T16:20:30.113Z" }, + { url = "https://files.pythonhosted.org/packages/3e/1c/8374990f9545e99462caacea5413ed783014b3b66ace49e35c533f07507b/grpcio-1.76.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:035d90bc79eaa4bed83f524331d55e35820725c9fbb00ffa1904d5550ed7ede3", size = 6407178, upload-time = "2025-10-21T16:20:32.733Z" }, + { url = "https://files.pythonhosted.org/packages/1e/77/36fd7d7c75a6c12542c90a6d647a27935a1ecaad03e0ffdb7c42db6b04d2/grpcio-1.76.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:4215d3a102bd95e2e11b5395c78562967959824156af11fa93d18fdd18050990", size = 7075684, upload-time = "2025-10-21T16:20:35.435Z" }, + { url = "https://files.pythonhosted.org/packages/38/f7/e3cdb252492278e004722306c5a8935eae91e64ea11f0af3437a7de2e2b7/grpcio-1.76.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:49ce47231818806067aea3324d4bf13825b658ad662d3b25fada0bdad9b8a6af", size = 6611133, upload-time = "2025-10-21T16:20:37.541Z" }, + { url = "https://files.pythonhosted.org/packages/7e/20/340db7af162ccd20a0893b5f3c4a5d676af7b71105517e62279b5b61d95a/grpcio-1.76.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8cc3309d8e08fd79089e13ed4819d0af72aa935dd8f435a195fd152796752ff2", size = 7195507, upload-time = "2025-10-21T16:20:39.643Z" }, + { url = "https://files.pythonhosted.org/packages/10/f0/b2160addc1487bd8fa4810857a27132fb4ce35c1b330c2f3ac45d697b106/grpcio-1.76.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:971fd5a1d6e62e00d945423a567e42eb1fa678ba89072832185ca836a94daaa6", size = 8160651, upload-time = "2025-10-21T16:20:42.492Z" }, + { url = "https://files.pythonhosted.org/packages/2c/2c/ac6f98aa113c6ef111b3f347854e99ebb7fb9d8f7bb3af1491d438f62af4/grpcio-1.76.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9d9adda641db7207e800a7f089068f6f645959f2df27e870ee81d44701dd9db3", size = 7620568, upload-time = "2025-10-21T16:20:45.995Z" }, + { url = "https://files.pythonhosted.org/packages/90/84/7852f7e087285e3ac17a2703bc4129fafee52d77c6c82af97d905566857e/grpcio-1.76.0-cp310-cp310-win32.whl", hash = "sha256:063065249d9e7e0782d03d2bca50787f53bd0fb89a67de9a7b521c4a01f1989b", size = 3998879, upload-time = "2025-10-21T16:20:48.592Z" }, + { url = "https://files.pythonhosted.org/packages/10/30/d3d2adcbb6dd3ff59d6ac3df6ef830e02b437fb5c90990429fd180e52f30/grpcio-1.76.0-cp310-cp310-win_amd64.whl", hash = "sha256:a6ae758eb08088d36812dd5d9af7a9859c05b1e0f714470ea243694b49278e7b", size = 4706892, upload-time = "2025-10-21T16:20:50.697Z" }, + { url = "https://files.pythonhosted.org/packages/a0/00/8163a1beeb6971f66b4bbe6ac9457b97948beba8dd2fc8e1281dce7f79ec/grpcio-1.76.0-cp311-cp311-linux_armv7l.whl", hash = "sha256:2e1743fbd7f5fa713a1b0a8ac8ebabf0ec980b5d8809ec358d488e273b9cf02a", size = 5843567, upload-time = "2025-10-21T16:20:52.829Z" }, + { url = "https://files.pythonhosted.org/packages/10/c1/934202f5cf335e6d852530ce14ddb0fef21be612ba9ecbbcbd4d748ca32d/grpcio-1.76.0-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:a8c2cf1209497cf659a667d7dea88985e834c24b7c3b605e6254cbb5076d985c", size = 11848017, upload-time = "2025-10-21T16:20:56.705Z" }, + { url = "https://files.pythonhosted.org/packages/11/0b/8dec16b1863d74af6eb3543928600ec2195af49ca58b16334972f6775663/grpcio-1.76.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:08caea849a9d3c71a542827d6df9d5a69067b0a1efbea8a855633ff5d9571465", size = 6412027, upload-time = "2025-10-21T16:20:59.3Z" }, + { url = "https://files.pythonhosted.org/packages/d7/64/7b9e6e7ab910bea9d46f2c090380bab274a0b91fb0a2fe9b0cd399fffa12/grpcio-1.76.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:f0e34c2079d47ae9f6188211db9e777c619a21d4faba6977774e8fa43b085e48", size = 7075913, upload-time = "2025-10-21T16:21:01.645Z" }, + { url = "https://files.pythonhosted.org/packages/68/86/093c46e9546073cefa789bd76d44c5cb2abc824ca62af0c18be590ff13ba/grpcio-1.76.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8843114c0cfce61b40ad48df65abcfc00d4dba82eae8718fab5352390848c5da", size = 6615417, upload-time = "2025-10-21T16:21:03.844Z" }, + { url = "https://files.pythonhosted.org/packages/f7/b6/5709a3a68500a9c03da6fb71740dcdd5ef245e39266461a03f31a57036d8/grpcio-1.76.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8eddfb4d203a237da6f3cc8a540dad0517d274b5a1e9e636fd8d2c79b5c1d397", size = 7199683, upload-time = "2025-10-21T16:21:06.195Z" }, + { url = "https://files.pythonhosted.org/packages/91/d3/4b1f2bf16ed52ce0b508161df3a2d186e4935379a159a834cb4a7d687429/grpcio-1.76.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:32483fe2aab2c3794101c2a159070584e5db11d0aa091b2c0ea9c4fc43d0d749", size = 8163109, upload-time = "2025-10-21T16:21:08.498Z" }, + { url = "https://files.pythonhosted.org/packages/5c/61/d9043f95f5f4cf085ac5dd6137b469d41befb04bd80280952ffa2a4c3f12/grpcio-1.76.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dcfe41187da8992c5f40aa8c5ec086fa3672834d2be57a32384c08d5a05b4c00", size = 7626676, upload-time = "2025-10-21T16:21:10.693Z" }, + { url = "https://files.pythonhosted.org/packages/36/95/fd9a5152ca02d8881e4dd419cdd790e11805979f499a2e5b96488b85cf27/grpcio-1.76.0-cp311-cp311-win32.whl", hash = "sha256:2107b0c024d1b35f4083f11245c0e23846ae64d02f40b2b226684840260ed054", size = 3997688, upload-time = "2025-10-21T16:21:12.746Z" }, + { url = "https://files.pythonhosted.org/packages/60/9c/5c359c8d4c9176cfa3c61ecd4efe5affe1f38d9bae81e81ac7186b4c9cc8/grpcio-1.76.0-cp311-cp311-win_amd64.whl", hash = "sha256:522175aba7af9113c48ec10cc471b9b9bd4f6ceb36aeb4544a8e2c80ed9d252d", size = 4709315, upload-time = "2025-10-21T16:21:15.26Z" }, + { url = "https://files.pythonhosted.org/packages/bf/05/8e29121994b8d959ffa0afd28996d452f291b48cfc0875619de0bde2c50c/grpcio-1.76.0-cp312-cp312-linux_armv7l.whl", hash = "sha256:81fd9652b37b36f16138611c7e884eb82e0cec137c40d3ef7c3f9b3ed00f6ed8", size = 5799718, upload-time = "2025-10-21T16:21:17.939Z" }, + { url = "https://files.pythonhosted.org/packages/d9/75/11d0e66b3cdf998c996489581bdad8900db79ebd83513e45c19548f1cba4/grpcio-1.76.0-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:04bbe1bfe3a68bbfd4e52402ab7d4eb59d72d02647ae2042204326cf4bbad280", size = 11825627, upload-time = "2025-10-21T16:21:20.466Z" }, + { url = "https://files.pythonhosted.org/packages/28/50/2f0aa0498bc188048f5d9504dcc5c2c24f2eb1a9337cd0fa09a61a2e75f0/grpcio-1.76.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d388087771c837cdb6515539f43b9d4bf0b0f23593a24054ac16f7a960be16f4", size = 6359167, upload-time = "2025-10-21T16:21:23.122Z" }, + { url = "https://files.pythonhosted.org/packages/66/e5/bbf0bb97d29ede1d59d6588af40018cfc345b17ce979b7b45424628dc8bb/grpcio-1.76.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:9f8f757bebaaea112c00dba718fc0d3260052ce714e25804a03f93f5d1c6cc11", size = 7044267, upload-time = "2025-10-21T16:21:25.995Z" }, + { url = "https://files.pythonhosted.org/packages/f5/86/f6ec2164f743d9609691115ae8ece098c76b894ebe4f7c94a655c6b03e98/grpcio-1.76.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:980a846182ce88c4f2f7e2c22c56aefd515daeb36149d1c897f83cf57999e0b6", size = 6573963, upload-time = "2025-10-21T16:21:28.631Z" }, + { url = "https://files.pythonhosted.org/packages/60/bc/8d9d0d8505feccfdf38a766d262c71e73639c165b311c9457208b56d92ae/grpcio-1.76.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f92f88e6c033db65a5ae3d97905c8fea9c725b63e28d5a75cb73b49bda5024d8", size = 7164484, upload-time = "2025-10-21T16:21:30.837Z" }, + { url = "https://files.pythonhosted.org/packages/67/e6/5d6c2fc10b95edf6df9b8f19cf10a34263b7fd48493936fffd5085521292/grpcio-1.76.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4baf3cbe2f0be3289eb68ac8ae771156971848bb8aaff60bad42005539431980", size = 8127777, upload-time = "2025-10-21T16:21:33.577Z" }, + { url = "https://files.pythonhosted.org/packages/3f/c8/dce8ff21c86abe025efe304d9e31fdb0deaaa3b502b6a78141080f206da0/grpcio-1.76.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:615ba64c208aaceb5ec83bfdce7728b80bfeb8be97562944836a7a0a9647d882", size = 7594014, upload-time = "2025-10-21T16:21:41.882Z" }, + { url = "https://files.pythonhosted.org/packages/e0/42/ad28191ebf983a5d0ecef90bab66baa5a6b18f2bfdef9d0a63b1973d9f75/grpcio-1.76.0-cp312-cp312-win32.whl", hash = "sha256:45d59a649a82df5718fd9527ce775fd66d1af35e6d31abdcdc906a49c6822958", size = 3984750, upload-time = "2025-10-21T16:21:44.006Z" }, + { url = "https://files.pythonhosted.org/packages/9e/00/7bd478cbb851c04a48baccaa49b75abaa8e4122f7d86da797500cccdd771/grpcio-1.76.0-cp312-cp312-win_amd64.whl", hash = "sha256:c088e7a90b6017307f423efbb9d1ba97a22aa2170876223f9709e9d1de0b5347", size = 4704003, upload-time = "2025-10-21T16:21:46.244Z" }, + { url = "https://files.pythonhosted.org/packages/fc/ed/71467ab770effc9e8cef5f2e7388beb2be26ed642d567697bb103a790c72/grpcio-1.76.0-cp313-cp313-linux_armv7l.whl", hash = "sha256:26ef06c73eb53267c2b319f43e6634c7556ea37672029241a056629af27c10e2", size = 5807716, upload-time = "2025-10-21T16:21:48.475Z" }, + { url = "https://files.pythonhosted.org/packages/2c/85/c6ed56f9817fab03fa8a111ca91469941fb514e3e3ce6d793cb8f1e1347b/grpcio-1.76.0-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:45e0111e73f43f735d70786557dc38141185072d7ff8dc1829d6a77ac1471468", size = 11821522, upload-time = "2025-10-21T16:21:51.142Z" }, + { url = "https://files.pythonhosted.org/packages/ac/31/2b8a235ab40c39cbc141ef647f8a6eb7b0028f023015a4842933bc0d6831/grpcio-1.76.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:83d57312a58dcfe2a3a0f9d1389b299438909a02db60e2f2ea2ae2d8034909d3", size = 6362558, upload-time = "2025-10-21T16:21:54.213Z" }, + { url = "https://files.pythonhosted.org/packages/bd/64/9784eab483358e08847498ee56faf8ff6ea8e0a4592568d9f68edc97e9e9/grpcio-1.76.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:3e2a27c89eb9ac3d81ec8835e12414d73536c6e620355d65102503064a4ed6eb", size = 7049990, upload-time = "2025-10-21T16:21:56.476Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/8c12319a6369434e7a184b987e8e9f3b49a114c489b8315f029e24de4837/grpcio-1.76.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61f69297cba3950a524f61c7c8ee12e55c486cb5f7db47ff9dcee33da6f0d3ae", size = 6575387, upload-time = "2025-10-21T16:21:59.051Z" }, + { url = "https://files.pythonhosted.org/packages/15/0f/f12c32b03f731f4a6242f771f63039df182c8b8e2cf8075b245b409259d4/grpcio-1.76.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6a15c17af8839b6801d554263c546c69c4d7718ad4321e3166175b37eaacca77", size = 7166668, upload-time = "2025-10-21T16:22:02.049Z" }, + { url = "https://files.pythonhosted.org/packages/ff/2d/3ec9ce0c2b1d92dd59d1c3264aaec9f0f7c817d6e8ac683b97198a36ed5a/grpcio-1.76.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:25a18e9810fbc7e7f03ec2516addc116a957f8cbb8cbc95ccc80faa072743d03", size = 8124928, upload-time = "2025-10-21T16:22:04.984Z" }, + { url = "https://files.pythonhosted.org/packages/1a/74/fd3317be5672f4856bcdd1a9e7b5e17554692d3db9a3b273879dc02d657d/grpcio-1.76.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:931091142fd8cc14edccc0845a79248bc155425eee9a98b2db2ea4f00a235a42", size = 7589983, upload-time = "2025-10-21T16:22:07.881Z" }, + { url = "https://files.pythonhosted.org/packages/45/bb/ca038cf420f405971f19821c8c15bcbc875505f6ffadafe9ffd77871dc4c/grpcio-1.76.0-cp313-cp313-win32.whl", hash = "sha256:5e8571632780e08526f118f74170ad8d50fb0a48c23a746bef2a6ebade3abd6f", size = 3984727, upload-time = "2025-10-21T16:22:10.032Z" }, + { url = "https://files.pythonhosted.org/packages/41/80/84087dc56437ced7cdd4b13d7875e7439a52a261e3ab4e06488ba6173b0a/grpcio-1.76.0-cp313-cp313-win_amd64.whl", hash = "sha256:f9f7bd5faab55f47231ad8dba7787866b69f5e93bc306e3915606779bbfb4ba8", size = 4702799, upload-time = "2025-10-21T16:22:12.709Z" }, + { url = "https://files.pythonhosted.org/packages/b4/46/39adac80de49d678e6e073b70204091e76631e03e94928b9ea4ecf0f6e0e/grpcio-1.76.0-cp314-cp314-linux_armv7l.whl", hash = "sha256:ff8a59ea85a1f2191a0ffcc61298c571bc566332f82e5f5be1b83c9d8e668a62", size = 5808417, upload-time = "2025-10-21T16:22:15.02Z" }, + { url = "https://files.pythonhosted.org/packages/9c/f5/a4531f7fb8b4e2a60b94e39d5d924469b7a6988176b3422487be61fe2998/grpcio-1.76.0-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:06c3d6b076e7b593905d04fdba6a0525711b3466f43b3400266f04ff735de0cd", size = 11828219, upload-time = "2025-10-21T16:22:17.954Z" }, + { url = "https://files.pythonhosted.org/packages/4b/1c/de55d868ed7a8bd6acc6b1d6ddc4aa36d07a9f31d33c912c804adb1b971b/grpcio-1.76.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd5ef5932f6475c436c4a55e4336ebbe47bd3272be04964a03d316bbf4afbcbc", size = 6367826, upload-time = "2025-10-21T16:22:20.721Z" }, + { url = "https://files.pythonhosted.org/packages/59/64/99e44c02b5adb0ad13ab3adc89cb33cb54bfa90c74770f2607eea629b86f/grpcio-1.76.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:b331680e46239e090f5b3cead313cc772f6caa7d0fc8de349337563125361a4a", size = 7049550, upload-time = "2025-10-21T16:22:23.637Z" }, + { url = "https://files.pythonhosted.org/packages/43/28/40a5be3f9a86949b83e7d6a2ad6011d993cbe9b6bd27bea881f61c7788b6/grpcio-1.76.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:2229ae655ec4e8999599469559e97630185fdd53ae1e8997d147b7c9b2b72cba", size = 6575564, upload-time = "2025-10-21T16:22:26.016Z" }, + { url = "https://files.pythonhosted.org/packages/4b/a9/1be18e6055b64467440208a8559afac243c66a8b904213af6f392dc2212f/grpcio-1.76.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:490fa6d203992c47c7b9e4a9d39003a0c2bcc1c9aa3c058730884bbbb0ee9f09", size = 7176236, upload-time = "2025-10-21T16:22:28.362Z" }, + { url = "https://files.pythonhosted.org/packages/0f/55/dba05d3fcc151ce6e81327541d2cc8394f442f6b350fead67401661bf041/grpcio-1.76.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:479496325ce554792dba6548fae3df31a72cef7bad71ca2e12b0e58f9b336bfc", size = 8125795, upload-time = "2025-10-21T16:22:31.075Z" }, + { url = "https://files.pythonhosted.org/packages/4a/45/122df922d05655f63930cf42c9e3f72ba20aadb26c100ee105cad4ce4257/grpcio-1.76.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1c9b93f79f48b03ada57ea24725d83a30284a012ec27eab2cf7e50a550cbbbcc", size = 7592214, upload-time = "2025-10-21T16:22:33.831Z" }, + { url = "https://files.pythonhosted.org/packages/4a/6e/0b899b7f6b66e5af39e377055fb4a6675c9ee28431df5708139df2e93233/grpcio-1.76.0-cp314-cp314-win32.whl", hash = "sha256:747fa73efa9b8b1488a95d0ba1039c8e2dca0f741612d80415b1e1c560febf4e", size = 4062961, upload-time = "2025-10-21T16:22:36.468Z" }, + { url = "https://files.pythonhosted.org/packages/19/41/0b430b01a2eb38ee887f88c1f07644a1df8e289353b78e82b37ef988fb64/grpcio-1.76.0-cp314-cp314-win_amd64.whl", hash = "sha256:922fa70ba549fce362d2e2871ab542082d66e2aaf0c19480ea453905b01f384e", size = 4834462, upload-time = "2025-10-21T16:22:39.772Z" }, ] [[package]] @@ -864,15 +861,6 @@ 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 = "isort" -version = "5.13.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/87/f9/c1eb8635a24e87ade2efce21e3ce8cd6b8630bb685ddc9cdaca1349b2eb5/isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109", size = 175303, upload-time = "2023-12-13T20:37:26.124Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/b3/8def84f539e7d2289a02f0524b944b15d7c75dab7628bedf1c4f0992029c/isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6", size = 92310, upload-time = "2023-12-13T20:37:23.244Z" }, -] - [[package]] name = "jinja2" version = "3.1.6" @@ -1405,14 +1393,14 @@ wheels = [ [[package]] name = "nexus-rpc" -version = "1.1.0" +version = "1.2.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" } +sdist = { url = "https://files.pythonhosted.org/packages/06/50/95d7bc91f900da5e22662c82d9bf0f72a4b01f2a552708bf2f43807707a1/nexus_rpc-1.2.0.tar.gz", hash = "sha256:b4ddaffa4d3996aaeadf49b80dfcdfbca48fe4cb616defaf3b3c5c2c8fc61890", size = 74142, upload-time = "2025-11-17T19:17:06.798Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/13/04/eaac430d0e6bf21265ae989427d37e94be5e41dc216879f1fbb6c5339942/nexus_rpc-1.2.0-py3-none-any.whl", hash = "sha256:977876f3af811ad1a09b2961d3d1ac9233bda43ff0febbb0c9906483b9d9f8a3", size = 28166, upload-time = "2025-11-17T19:17:05.64Z" }, ] [[package]] @@ -1582,68 +1570,83 @@ wheels = [ [[package]] name = "orjson" -version = "3.10.18" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/81/0b/fea456a3ffe74e70ba30e01ec183a9b26bec4d497f61dcfce1b601059c60/orjson-3.10.18.tar.gz", hash = "sha256:e8da3947d92123eda795b68228cafe2724815621fe35e8e320a9e9593a4bcd53", size = 5422810, upload-time = "2025-04-29T23:30:08.423Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/27/16/2ceb9fb7bc2b11b1e4a3ea27794256e93dee2309ebe297fd131a778cd150/orjson-3.10.18-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a45e5d68066b408e4bc383b6e4ef05e717c65219a9e1390abc6155a520cac402", size = 248927, upload-time = "2025-04-29T23:28:08.643Z" }, - { url = "https://files.pythonhosted.org/packages/3d/e1/d3c0a2bba5b9906badd121da449295062b289236c39c3a7801f92c4682b0/orjson-3.10.18-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be3b9b143e8b9db05368b13b04c84d37544ec85bb97237b3a923f076265ec89c", size = 136995, upload-time = "2025-04-29T23:28:11.503Z" }, - { url = "https://files.pythonhosted.org/packages/d7/51/698dd65e94f153ee5ecb2586c89702c9e9d12f165a63e74eb9ea1299f4e1/orjson-3.10.18-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9b0aa09745e2c9b3bf779b096fa71d1cc2d801a604ef6dd79c8b1bfef52b2f92", size = 132893, upload-time = "2025-04-29T23:28:12.751Z" }, - { url = "https://files.pythonhosted.org/packages/b3/e5/155ce5a2c43a85e790fcf8b985400138ce5369f24ee6770378ee6b691036/orjson-3.10.18-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53a245c104d2792e65c8d225158f2b8262749ffe64bc7755b00024757d957a13", size = 137017, upload-time = "2025-04-29T23:28:14.498Z" }, - { url = "https://files.pythonhosted.org/packages/46/bb/6141ec3beac3125c0b07375aee01b5124989907d61c72c7636136e4bd03e/orjson-3.10.18-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9495ab2611b7f8a0a8a505bcb0f0cbdb5469caafe17b0e404c3c746f9900469", size = 138290, upload-time = "2025-04-29T23:28:16.211Z" }, - { url = "https://files.pythonhosted.org/packages/77/36/6961eca0b66b7809d33c4ca58c6bd4c23a1b914fb23aba2fa2883f791434/orjson-3.10.18-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:73be1cbcebadeabdbc468f82b087df435843c809cd079a565fb16f0f3b23238f", size = 142828, upload-time = "2025-04-29T23:28:18.065Z" }, - { url = "https://files.pythonhosted.org/packages/8b/2f/0c646d5fd689d3be94f4d83fa9435a6c4322c9b8533edbb3cd4bc8c5f69a/orjson-3.10.18-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe8936ee2679e38903df158037a2f1c108129dee218975122e37847fb1d4ac68", size = 132806, upload-time = "2025-04-29T23:28:19.782Z" }, - { url = "https://files.pythonhosted.org/packages/ea/af/65907b40c74ef4c3674ef2bcfa311c695eb934710459841b3c2da212215c/orjson-3.10.18-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7115fcbc8525c74e4c2b608129bef740198e9a120ae46184dac7683191042056", size = 135005, upload-time = "2025-04-29T23:28:21.367Z" }, - { url = "https://files.pythonhosted.org/packages/c7/d1/68bd20ac6a32cd1f1b10d23e7cc58ee1e730e80624e3031d77067d7150fc/orjson-3.10.18-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:771474ad34c66bc4d1c01f645f150048030694ea5b2709b87d3bda273ffe505d", size = 413418, upload-time = "2025-04-29T23:28:23.097Z" }, - { url = "https://files.pythonhosted.org/packages/31/31/c701ec0bcc3e80e5cb6e319c628ef7b768aaa24b0f3b4c599df2eaacfa24/orjson-3.10.18-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7c14047dbbea52886dd87169f21939af5d55143dad22d10db6a7514f058156a8", size = 153288, upload-time = "2025-04-29T23:28:25.02Z" }, - { url = "https://files.pythonhosted.org/packages/d9/31/5e1aa99a10893a43cfc58009f9da840990cc8a9ebb75aa452210ba18587e/orjson-3.10.18-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:641481b73baec8db14fdf58f8967e52dc8bda1f2aba3aa5f5c1b07ed6df50b7f", size = 137181, upload-time = "2025-04-29T23:28:26.318Z" }, - { url = "https://files.pythonhosted.org/packages/bf/8c/daba0ac1b8690011d9242a0f37235f7d17df6d0ad941021048523b76674e/orjson-3.10.18-cp310-cp310-win32.whl", hash = "sha256:607eb3ae0909d47280c1fc657c4284c34b785bae371d007595633f4b1a2bbe06", size = 142694, upload-time = "2025-04-29T23:28:28.092Z" }, - { url = "https://files.pythonhosted.org/packages/16/62/8b687724143286b63e1d0fab3ad4214d54566d80b0ba9d67c26aaf28a2f8/orjson-3.10.18-cp310-cp310-win_amd64.whl", hash = "sha256:8770432524ce0eca50b7efc2a9a5f486ee0113a5fbb4231526d414e6254eba92", size = 134600, upload-time = "2025-04-29T23:28:29.422Z" }, - { url = "https://files.pythonhosted.org/packages/97/c7/c54a948ce9a4278794f669a353551ce7db4ffb656c69a6e1f2264d563e50/orjson-3.10.18-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e0a183ac3b8e40471e8d843105da6fbe7c070faab023be3b08188ee3f85719b8", size = 248929, upload-time = "2025-04-29T23:28:30.716Z" }, - { url = "https://files.pythonhosted.org/packages/9e/60/a9c674ef1dd8ab22b5b10f9300e7e70444d4e3cda4b8258d6c2488c32143/orjson-3.10.18-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5ef7c164d9174362f85238d0cd4afdeeb89d9e523e4651add6a5d458d6f7d42d", size = 133364, upload-time = "2025-04-29T23:28:32.392Z" }, - { url = "https://files.pythonhosted.org/packages/c1/4e/f7d1bdd983082216e414e6d7ef897b0c2957f99c545826c06f371d52337e/orjson-3.10.18-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afd14c5d99cdc7bf93f22b12ec3b294931518aa019e2a147e8aa2f31fd3240f7", size = 136995, upload-time = "2025-04-29T23:28:34.024Z" }, - { url = "https://files.pythonhosted.org/packages/17/89/46b9181ba0ea251c9243b0c8ce29ff7c9796fa943806a9c8b02592fce8ea/orjson-3.10.18-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7b672502323b6cd133c4af6b79e3bea36bad2d16bca6c1f645903fce83909a7a", size = 132894, upload-time = "2025-04-29T23:28:35.318Z" }, - { url = "https://files.pythonhosted.org/packages/ca/dd/7bce6fcc5b8c21aef59ba3c67f2166f0a1a9b0317dcca4a9d5bd7934ecfd/orjson-3.10.18-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:51f8c63be6e070ec894c629186b1c0fe798662b8687f3d9fdfa5e401c6bd7679", size = 137016, upload-time = "2025-04-29T23:28:36.674Z" }, - { url = "https://files.pythonhosted.org/packages/1c/4a/b8aea1c83af805dcd31c1f03c95aabb3e19a016b2a4645dd822c5686e94d/orjson-3.10.18-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3f9478ade5313d724e0495d167083c6f3be0dd2f1c9c8a38db9a9e912cdaf947", size = 138290, upload-time = "2025-04-29T23:28:38.3Z" }, - { url = "https://files.pythonhosted.org/packages/36/d6/7eb05c85d987b688707f45dcf83c91abc2251e0dd9fb4f7be96514f838b1/orjson-3.10.18-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:187aefa562300a9d382b4b4eb9694806e5848b0cedf52037bb5c228c61bb66d4", size = 142829, upload-time = "2025-04-29T23:28:39.657Z" }, - { url = "https://files.pythonhosted.org/packages/d2/78/ddd3ee7873f2b5f90f016bc04062713d567435c53ecc8783aab3a4d34915/orjson-3.10.18-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da552683bc9da222379c7a01779bddd0ad39dd699dd6300abaf43eadee38334", size = 132805, upload-time = "2025-04-29T23:28:40.969Z" }, - { url = "https://files.pythonhosted.org/packages/8c/09/c8e047f73d2c5d21ead9c180203e111cddeffc0848d5f0f974e346e21c8e/orjson-3.10.18-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e450885f7b47a0231979d9c49b567ed1c4e9f69240804621be87c40bc9d3cf17", size = 135008, upload-time = "2025-04-29T23:28:42.284Z" }, - { url = "https://files.pythonhosted.org/packages/0c/4b/dccbf5055ef8fb6eda542ab271955fc1f9bf0b941a058490293f8811122b/orjson-3.10.18-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5e3c9cc2ba324187cd06287ca24f65528f16dfc80add48dc99fa6c836bb3137e", size = 413419, upload-time = "2025-04-29T23:28:43.673Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f3/1eac0c5e2d6d6790bd2025ebfbefcbd37f0d097103d76f9b3f9302af5a17/orjson-3.10.18-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:50ce016233ac4bfd843ac5471e232b865271d7d9d44cf9d33773bcd883ce442b", size = 153292, upload-time = "2025-04-29T23:28:45.573Z" }, - { url = "https://files.pythonhosted.org/packages/1f/b4/ef0abf64c8f1fabf98791819ab502c2c8c1dc48b786646533a93637d8999/orjson-3.10.18-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b3ceff74a8f7ffde0b2785ca749fc4e80e4315c0fd887561144059fb1c138aa7", size = 137182, upload-time = "2025-04-29T23:28:47.229Z" }, - { url = "https://files.pythonhosted.org/packages/a9/a3/6ea878e7b4a0dc5c888d0370d7752dcb23f402747d10e2257478d69b5e63/orjson-3.10.18-cp311-cp311-win32.whl", hash = "sha256:fdba703c722bd868c04702cac4cb8c6b8ff137af2623bc0ddb3b3e6a2c8996c1", size = 142695, upload-time = "2025-04-29T23:28:48.564Z" }, - { url = "https://files.pythonhosted.org/packages/79/2a/4048700a3233d562f0e90d5572a849baa18ae4e5ce4c3ba6247e4ece57b0/orjson-3.10.18-cp311-cp311-win_amd64.whl", hash = "sha256:c28082933c71ff4bc6ccc82a454a2bffcef6e1d7379756ca567c772e4fb3278a", size = 134603, upload-time = "2025-04-29T23:28:50.442Z" }, - { url = "https://files.pythonhosted.org/packages/03/45/10d934535a4993d27e1c84f1810e79ccf8b1b7418cef12151a22fe9bb1e1/orjson-3.10.18-cp311-cp311-win_arm64.whl", hash = "sha256:a6c7c391beaedd3fa63206e5c2b7b554196f14debf1ec9deb54b5d279b1b46f5", size = 131400, upload-time = "2025-04-29T23:28:51.838Z" }, - { url = "https://files.pythonhosted.org/packages/21/1a/67236da0916c1a192d5f4ccbe10ec495367a726996ceb7614eaa687112f2/orjson-3.10.18-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:50c15557afb7f6d63bc6d6348e0337a880a04eaa9cd7c9d569bcb4e760a24753", size = 249184, upload-time = "2025-04-29T23:28:53.612Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bc/c7f1db3b1d094dc0c6c83ed16b161a16c214aaa77f311118a93f647b32dc/orjson-3.10.18-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:356b076f1662c9813d5fa56db7d63ccceef4c271b1fb3dd522aca291375fcf17", size = 133279, upload-time = "2025-04-29T23:28:55.055Z" }, - { url = "https://files.pythonhosted.org/packages/af/84/664657cd14cc11f0d81e80e64766c7ba5c9b7fc1ec304117878cc1b4659c/orjson-3.10.18-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:559eb40a70a7494cd5beab2d73657262a74a2c59aff2068fdba8f0424ec5b39d", size = 136799, upload-time = "2025-04-29T23:28:56.828Z" }, - { url = "https://files.pythonhosted.org/packages/9a/bb/f50039c5bb05a7ab024ed43ba25d0319e8722a0ac3babb0807e543349978/orjson-3.10.18-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3c29eb9a81e2fbc6fd7ddcfba3e101ba92eaff455b8d602bf7511088bbc0eae", size = 132791, upload-time = "2025-04-29T23:28:58.751Z" }, - { url = "https://files.pythonhosted.org/packages/93/8c/ee74709fc072c3ee219784173ddfe46f699598a1723d9d49cbc78d66df65/orjson-3.10.18-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6612787e5b0756a171c7d81ba245ef63a3533a637c335aa7fcb8e665f4a0966f", size = 137059, upload-time = "2025-04-29T23:29:00.129Z" }, - { url = "https://files.pythonhosted.org/packages/6a/37/e6d3109ee004296c80426b5a62b47bcadd96a3deab7443e56507823588c5/orjson-3.10.18-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ac6bd7be0dcab5b702c9d43d25e70eb456dfd2e119d512447468f6405b4a69c", size = 138359, upload-time = "2025-04-29T23:29:01.704Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5d/387dafae0e4691857c62bd02839a3bf3fa648eebd26185adfac58d09f207/orjson-3.10.18-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9f72f100cee8dde70100406d5c1abba515a7df926d4ed81e20a9730c062fe9ad", size = 142853, upload-time = "2025-04-29T23:29:03.576Z" }, - { url = "https://files.pythonhosted.org/packages/27/6f/875e8e282105350b9a5341c0222a13419758545ae32ad6e0fcf5f64d76aa/orjson-3.10.18-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9dca85398d6d093dd41dc0983cbf54ab8e6afd1c547b6b8a311643917fbf4e0c", size = 133131, upload-time = "2025-04-29T23:29:05.753Z" }, - { url = "https://files.pythonhosted.org/packages/48/b2/73a1f0b4790dcb1e5a45f058f4f5dcadc8a85d90137b50d6bbc6afd0ae50/orjson-3.10.18-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22748de2a07fcc8781a70edb887abf801bb6142e6236123ff93d12d92db3d406", size = 134834, upload-time = "2025-04-29T23:29:07.35Z" }, - { url = "https://files.pythonhosted.org/packages/56/f5/7ed133a5525add9c14dbdf17d011dd82206ca6840811d32ac52a35935d19/orjson-3.10.18-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3a83c9954a4107b9acd10291b7f12a6b29e35e8d43a414799906ea10e75438e6", size = 413368, upload-time = "2025-04-29T23:29:09.301Z" }, - { url = "https://files.pythonhosted.org/packages/11/7c/439654221ed9c3324bbac7bdf94cf06a971206b7b62327f11a52544e4982/orjson-3.10.18-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:303565c67a6c7b1f194c94632a4a39918e067bd6176a48bec697393865ce4f06", size = 153359, upload-time = "2025-04-29T23:29:10.813Z" }, - { url = "https://files.pythonhosted.org/packages/48/e7/d58074fa0cc9dd29a8fa2a6c8d5deebdfd82c6cfef72b0e4277c4017563a/orjson-3.10.18-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:86314fdb5053a2f5a5d881f03fca0219bfdf832912aa88d18676a5175c6916b5", size = 137466, upload-time = "2025-04-29T23:29:12.26Z" }, - { url = "https://files.pythonhosted.org/packages/57/4d/fe17581cf81fb70dfcef44e966aa4003360e4194d15a3f38cbffe873333a/orjson-3.10.18-cp312-cp312-win32.whl", hash = "sha256:187ec33bbec58c76dbd4066340067d9ece6e10067bb0cc074a21ae3300caa84e", size = 142683, upload-time = "2025-04-29T23:29:13.865Z" }, - { url = "https://files.pythonhosted.org/packages/e6/22/469f62d25ab5f0f3aee256ea732e72dc3aab6d73bac777bd6277955bceef/orjson-3.10.18-cp312-cp312-win_amd64.whl", hash = "sha256:f9f94cf6d3f9cd720d641f8399e390e7411487e493962213390d1ae45c7814fc", size = 134754, upload-time = "2025-04-29T23:29:15.338Z" }, - { url = "https://files.pythonhosted.org/packages/10/b0/1040c447fac5b91bc1e9c004b69ee50abb0c1ffd0d24406e1350c58a7fcb/orjson-3.10.18-cp312-cp312-win_arm64.whl", hash = "sha256:3d600be83fe4514944500fa8c2a0a77099025ec6482e8087d7659e891f23058a", size = 131218, upload-time = "2025-04-29T23:29:17.324Z" }, - { url = "https://files.pythonhosted.org/packages/04/f0/8aedb6574b68096f3be8f74c0b56d36fd94bcf47e6c7ed47a7bd1474aaa8/orjson-3.10.18-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:69c34b9441b863175cc6a01f2935de994025e773f814412030f269da4f7be147", size = 249087, upload-time = "2025-04-29T23:29:19.083Z" }, - { url = "https://files.pythonhosted.org/packages/bc/f7/7118f965541aeac6844fcb18d6988e111ac0d349c9b80cda53583e758908/orjson-3.10.18-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:1ebeda919725f9dbdb269f59bc94f861afbe2a27dce5608cdba2d92772364d1c", size = 133273, upload-time = "2025-04-29T23:29:20.602Z" }, - { url = "https://files.pythonhosted.org/packages/fb/d9/839637cc06eaf528dd8127b36004247bf56e064501f68df9ee6fd56a88ee/orjson-3.10.18-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5adf5f4eed520a4959d29ea80192fa626ab9a20b2ea13f8f6dc58644f6927103", size = 136779, upload-time = "2025-04-29T23:29:22.062Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/f226ecfef31a1f0e7d6bf9a31a0bbaf384c7cbe3fce49cc9c2acc51f902a/orjson-3.10.18-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7592bb48a214e18cd670974f289520f12b7aed1fa0b2e2616b8ed9e069e08595", size = 132811, upload-time = "2025-04-29T23:29:23.602Z" }, - { url = "https://files.pythonhosted.org/packages/73/2d/371513d04143c85b681cf8f3bce743656eb5b640cb1f461dad750ac4b4d4/orjson-3.10.18-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f872bef9f042734110642b7a11937440797ace8c87527de25e0c53558b579ccc", size = 137018, upload-time = "2025-04-29T23:29:25.094Z" }, - { url = "https://files.pythonhosted.org/packages/69/cb/a4d37a30507b7a59bdc484e4a3253c8141bf756d4e13fcc1da760a0b00cb/orjson-3.10.18-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0315317601149c244cb3ecef246ef5861a64824ccbcb8018d32c66a60a84ffbc", size = 138368, upload-time = "2025-04-29T23:29:26.609Z" }, - { url = "https://files.pythonhosted.org/packages/1e/ae/cd10883c48d912d216d541eb3db8b2433415fde67f620afe6f311f5cd2ca/orjson-3.10.18-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e0da26957e77e9e55a6c2ce2e7182a36a6f6b180ab7189315cb0995ec362e049", size = 142840, upload-time = "2025-04-29T23:29:28.153Z" }, - { url = "https://files.pythonhosted.org/packages/6d/4c/2bda09855c6b5f2c055034c9eda1529967b042ff8d81a05005115c4e6772/orjson-3.10.18-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb70d489bc79b7519e5803e2cc4c72343c9dc1154258adf2f8925d0b60da7c58", size = 133135, upload-time = "2025-04-29T23:29:29.726Z" }, - { url = "https://files.pythonhosted.org/packages/13/4a/35971fd809a8896731930a80dfff0b8ff48eeb5d8b57bb4d0d525160017f/orjson-3.10.18-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e9e86a6af31b92299b00736c89caf63816f70a4001e750bda179e15564d7a034", size = 134810, upload-time = "2025-04-29T23:29:31.269Z" }, - { url = "https://files.pythonhosted.org/packages/99/70/0fa9e6310cda98365629182486ff37a1c6578e34c33992df271a476ea1cd/orjson-3.10.18-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:c382a5c0b5931a5fc5405053d36c1ce3fd561694738626c77ae0b1dfc0242ca1", size = 413491, upload-time = "2025-04-29T23:29:33.315Z" }, - { url = "https://files.pythonhosted.org/packages/32/cb/990a0e88498babddb74fb97855ae4fbd22a82960e9b06eab5775cac435da/orjson-3.10.18-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:8e4b2ae732431127171b875cb2668f883e1234711d3c147ffd69fe5be51a8012", size = 153277, upload-time = "2025-04-29T23:29:34.946Z" }, - { url = "https://files.pythonhosted.org/packages/92/44/473248c3305bf782a384ed50dd8bc2d3cde1543d107138fd99b707480ca1/orjson-3.10.18-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2d808e34ddb24fc29a4d4041dcfafbae13e129c93509b847b14432717d94b44f", size = 137367, upload-time = "2025-04-29T23:29:36.52Z" }, - { url = "https://files.pythonhosted.org/packages/ad/fd/7f1d3edd4ffcd944a6a40e9f88af2197b619c931ac4d3cfba4798d4d3815/orjson-3.10.18-cp313-cp313-win32.whl", hash = "sha256:ad8eacbb5d904d5591f27dee4031e2c1db43d559edb8f91778efd642d70e6bea", size = 142687, upload-time = "2025-04-29T23:29:38.292Z" }, - { url = "https://files.pythonhosted.org/packages/4b/03/c75c6ad46be41c16f4cfe0352a2d1450546f3c09ad2c9d341110cd87b025/orjson-3.10.18-cp313-cp313-win_amd64.whl", hash = "sha256:aed411bcb68bf62e85588f2a7e03a6082cc42e5a2796e06e72a962d7c6310b52", size = 134794, upload-time = "2025-04-29T23:29:40.349Z" }, - { url = "https://files.pythonhosted.org/packages/c2/28/f53038a5a72cc4fd0b56c1eafb4ef64aec9685460d5ac34de98ca78b6e29/orjson-3.10.18-cp313-cp313-win_arm64.whl", hash = "sha256:f54c1385a0e6aba2f15a40d703b858bedad36ded0491e55d35d905b2c34a4cc3", size = 131186, upload-time = "2025-04-29T23:29:41.922Z" }, +version = "3.11.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, + { url = "https://files.pythonhosted.org/packages/44/1f/da46563c08bef33c41fd63c660abcd2184b4d2b950c8686317d03b9f5f0c/orjson-3.11.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a69ab657a4e6733133a3dca82768f2f8b884043714e8d2b9ba9f52b6efef5c44", size = 130622, upload-time = "2025-10-24T15:48:31.361Z" }, + { url = "https://files.pythonhosted.org/packages/02/bd/b551a05d0090eab0bf8008a13a14edc0f3c3e0236aa6f5b697760dd2817b/orjson-3.11.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3740bffd9816fc0326ddc406098a3a8f387e42223f5f455f2a02a9f834ead80c", size = 129344, upload-time = "2025-10-24T15:48:32.71Z" }, + { url = "https://files.pythonhosted.org/packages/87/6c/9ddd5e609f443b2548c5e7df3c44d0e86df2c68587a0e20c50018cdec535/orjson-3.11.4-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:65fd2f5730b1bf7f350c6dc896173d3460d235c4be007af73986d7cd9a2acd23", size = 136633, upload-time = "2025-10-24T15:48:34.128Z" }, + { url = "https://files.pythonhosted.org/packages/95/f2/9f04f2874c625a9fb60f6918c33542320661255323c272e66f7dcce14df2/orjson-3.11.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fdc3ae730541086158d549c97852e2eea6820665d4faf0f41bf99df41bc11ea", size = 137695, upload-time = "2025-10-24T15:48:35.654Z" }, + { url = "https://files.pythonhosted.org/packages/d2/c2/c7302afcbdfe8a891baae0e2cee091583a30e6fa613e8bdf33b0e9c8a8c7/orjson-3.11.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e10b4d65901da88845516ce9f7f9736f9638d19a1d483b3883dc0182e6e5edba", size = 136879, upload-time = "2025-10-24T15:48:37.483Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3a/b31c8f0182a3e27f48e703f46e61bb769666cd0dac4700a73912d07a1417/orjson-3.11.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fb6a03a678085f64b97f9d4a9ae69376ce91a3a9e9b56a82b1580d8e1d501aff", size = 136374, upload-time = "2025-10-24T15:48:38.624Z" }, + { url = "https://files.pythonhosted.org/packages/29/d0/fd9ab96841b090d281c46df566b7f97bc6c8cd9aff3f3ebe99755895c406/orjson-3.11.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2c82e4f0b1c712477317434761fbc28b044c838b6b1240d895607441412371ac", size = 140519, upload-time = "2025-10-24T15:48:39.756Z" }, + { url = "https://files.pythonhosted.org/packages/d6/ce/36eb0f15978bb88e33a3480e1a3fb891caa0f189ba61ce7713e0ccdadabf/orjson-3.11.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d58c166a18f44cc9e2bad03a327dc2d1a3d2e85b847133cfbafd6bfc6719bd79", size = 406522, upload-time = "2025-10-24T15:48:41.198Z" }, + { url = "https://files.pythonhosted.org/packages/85/11/e8af3161a288f5c6a00c188fc729c7ba193b0cbc07309a1a29c004347c30/orjson-3.11.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:94f206766bf1ea30e1382e4890f763bd1eefddc580e08fec1ccdc20ddd95c827", size = 149790, upload-time = "2025-10-24T15:48:42.664Z" }, + { url = "https://files.pythonhosted.org/packages/ea/96/209d52db0cf1e10ed48d8c194841e383e23c2ced5a2ee766649fe0e32d02/orjson-3.11.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:41bf25fb39a34cf8edb4398818523277ee7096689db352036a9e8437f2f3ee6b", size = 140040, upload-time = "2025-10-24T15:48:44.042Z" }, + { url = "https://files.pythonhosted.org/packages/ef/0e/526db1395ccb74c3d59ac1660b9a325017096dc5643086b38f27662b4add/orjson-3.11.4-cp310-cp310-win32.whl", hash = "sha256:fa9627eba4e82f99ca6d29bc967f09aba446ee2b5a1ea728949ede73d313f5d3", size = 135955, upload-time = "2025-10-24T15:48:45.495Z" }, + { url = "https://files.pythonhosted.org/packages/e6/69/18a778c9de3702b19880e73c9866b91cc85f904b885d816ba1ab318b223c/orjson-3.11.4-cp310-cp310-win_amd64.whl", hash = "sha256:23ef7abc7fca96632d8174ac115e668c1e931b8fe4dde586e92a500bf1914dcc", size = 131577, upload-time = "2025-10-24T15:48:46.609Z" }, + { url = "https://files.pythonhosted.org/packages/63/1d/1ea6005fffb56715fd48f632611e163d1604e8316a5bad2288bee9a1c9eb/orjson-3.11.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:5e59d23cd93ada23ec59a96f215139753fbfe3a4d989549bcb390f8c00370b39", size = 243498, upload-time = "2025-10-24T15:48:48.101Z" }, + { url = "https://files.pythonhosted.org/packages/37/d7/ffed10c7da677f2a9da307d491b9eb1d0125b0307019c4ad3d665fd31f4f/orjson-3.11.4-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5c3aedecfc1beb988c27c79d52ebefab93b6c3921dbec361167e6559aba2d36d", size = 128961, upload-time = "2025-10-24T15:48:49.571Z" }, + { url = "https://files.pythonhosted.org/packages/a2/96/3e4d10a18866d1368f73c8c44b7fe37cc8a15c32f2a7620be3877d4c55a3/orjson-3.11.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da9e5301f1c2caa2a9a4a303480d79c9ad73560b2e7761de742ab39fe59d9175", size = 130321, upload-time = "2025-10-24T15:48:50.713Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1f/465f66e93f434f968dd74d5b623eb62c657bdba2332f5a8be9f118bb74c7/orjson-3.11.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8873812c164a90a79f65368f8f96817e59e35d0cc02786a5356f0e2abed78040", size = 129207, upload-time = "2025-10-24T15:48:52.193Z" }, + { url = "https://files.pythonhosted.org/packages/28/43/d1e94837543321c119dff277ae8e348562fe8c0fafbb648ef7cb0c67e521/orjson-3.11.4-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5d7feb0741ebb15204e748f26c9638e6665a5fa93c37a2c73d64f1669b0ddc63", size = 136323, upload-time = "2025-10-24T15:48:54.806Z" }, + { url = "https://files.pythonhosted.org/packages/bf/04/93303776c8890e422a5847dd012b4853cdd88206b8bbd3edc292c90102d1/orjson-3.11.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:01ee5487fefee21e6910da4c2ee9eef005bee568a0879834df86f888d2ffbdd9", size = 137440, upload-time = "2025-10-24T15:48:56.326Z" }, + { url = "https://files.pythonhosted.org/packages/1e/ef/75519d039e5ae6b0f34d0336854d55544ba903e21bf56c83adc51cd8bf82/orjson-3.11.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d40d46f348c0321df01507f92b95a377240c4ec31985225a6668f10e2676f9a", size = 136680, upload-time = "2025-10-24T15:48:57.476Z" }, + { url = "https://files.pythonhosted.org/packages/b5/18/bf8581eaae0b941b44efe14fee7b7862c3382fbc9a0842132cfc7cf5ecf4/orjson-3.11.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95713e5fc8af84d8edc75b785d2386f653b63d62b16d681687746734b4dfc0be", size = 136160, upload-time = "2025-10-24T15:48:59.631Z" }, + { url = "https://files.pythonhosted.org/packages/c4/35/a6d582766d351f87fc0a22ad740a641b0a8e6fc47515e8614d2e4790ae10/orjson-3.11.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ad73ede24f9083614d6c4ca9a85fe70e33be7bf047ec586ee2363bc7418fe4d7", size = 140318, upload-time = "2025-10-24T15:49:00.834Z" }, + { url = "https://files.pythonhosted.org/packages/76/b3/5a4801803ab2e2e2d703bce1a56540d9f99a9143fbec7bf63d225044fef8/orjson-3.11.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:842289889de515421f3f224ef9c1f1efb199a32d76d8d2ca2706fa8afe749549", size = 406330, upload-time = "2025-10-24T15:49:02.327Z" }, + { url = "https://files.pythonhosted.org/packages/80/55/a8f682f64833e3a649f620eafefee175cbfeb9854fc5b710b90c3bca45df/orjson-3.11.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3b2427ed5791619851c52a1261b45c233930977e7de8cf36de05636c708fa905", size = 149580, upload-time = "2025-10-24T15:49:03.517Z" }, + { url = "https://files.pythonhosted.org/packages/ad/e4/c132fa0c67afbb3eb88274fa98df9ac1f631a675e7877037c611805a4413/orjson-3.11.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c36e524af1d29982e9b190573677ea02781456b2e537d5840e4538a5ec41907", size = 139846, upload-time = "2025-10-24T15:49:04.761Z" }, + { url = "https://files.pythonhosted.org/packages/54/06/dc3491489efd651fef99c5908e13951abd1aead1257c67f16135f95ce209/orjson-3.11.4-cp311-cp311-win32.whl", hash = "sha256:87255b88756eab4a68ec61837ca754e5d10fa8bc47dc57f75cedfeaec358d54c", size = 135781, upload-time = "2025-10-24T15:49:05.969Z" }, + { url = "https://files.pythonhosted.org/packages/79/b7/5e5e8d77bd4ea02a6ac54c42c818afb01dd31961be8a574eb79f1d2cfb1e/orjson-3.11.4-cp311-cp311-win_amd64.whl", hash = "sha256:e2d5d5d798aba9a0e1fede8d853fa899ce2cb930ec0857365f700dffc2c7af6a", size = 131391, upload-time = "2025-10-24T15:49:07.355Z" }, + { url = "https://files.pythonhosted.org/packages/0f/dc/9484127cc1aa213be398ed735f5f270eedcb0c0977303a6f6ddc46b60204/orjson-3.11.4-cp311-cp311-win_arm64.whl", hash = "sha256:6bb6bb41b14c95d4f2702bce9975fda4516f1db48e500102fc4d8119032ff045", size = 126252, upload-time = "2025-10-24T15:49:08.869Z" }, + { url = "https://files.pythonhosted.org/packages/63/51/6b556192a04595b93e277a9ff71cd0cc06c21a7df98bcce5963fa0f5e36f/orjson-3.11.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d4371de39319d05d3f482f372720b841c841b52f5385bd99c61ed69d55d9ab50", size = 243571, upload-time = "2025-10-24T15:49:10.008Z" }, + { url = "https://files.pythonhosted.org/packages/1c/2c/2602392ddf2601d538ff11848b98621cd465d1a1ceb9db9e8043181f2f7b/orjson-3.11.4-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e41fd3b3cac850eaae78232f37325ed7d7436e11c471246b87b2cd294ec94853", size = 128891, upload-time = "2025-10-24T15:49:11.297Z" }, + { url = "https://files.pythonhosted.org/packages/4e/47/bf85dcf95f7a3a12bf223394a4f849430acd82633848d52def09fa3f46ad/orjson-3.11.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:600e0e9ca042878c7fdf189cf1b028fe2c1418cc9195f6cb9824eb6ed99cb938", size = 130137, upload-time = "2025-10-24T15:49:12.544Z" }, + { url = "https://files.pythonhosted.org/packages/b4/4d/a0cb31007f3ab6f1fd2a1b17057c7c349bc2baf8921a85c0180cc7be8011/orjson-3.11.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7bbf9b333f1568ef5da42bc96e18bf30fd7f8d54e9ae066d711056add508e415", size = 129152, upload-time = "2025-10-24T15:49:13.754Z" }, + { url = "https://files.pythonhosted.org/packages/f7/ef/2811def7ce3d8576b19e3929fff8f8f0d44bc5eb2e0fdecb2e6e6cc6c720/orjson-3.11.4-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4806363144bb6e7297b8e95870e78d30a649fdc4e23fc84daa80c8ebd366ce44", size = 136834, upload-time = "2025-10-24T15:49:15.307Z" }, + { url = "https://files.pythonhosted.org/packages/00/d4/9aee9e54f1809cec8ed5abd9bc31e8a9631d19460e3b8470145d25140106/orjson-3.11.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad355e8308493f527d41154e9053b86a5be892b3b359a5c6d5d95cda23601cb2", size = 137519, upload-time = "2025-10-24T15:49:16.557Z" }, + { url = "https://files.pythonhosted.org/packages/db/ea/67bfdb5465d5679e8ae8d68c11753aaf4f47e3e7264bad66dc2f2249e643/orjson-3.11.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a7517482667fb9f0ff1b2f16fe5829296ed7a655d04d68cd9711a4d8a4e708", size = 136749, upload-time = "2025-10-24T15:49:17.796Z" }, + { url = "https://files.pythonhosted.org/packages/01/7e/62517dddcfce6d53a39543cd74d0dccfcbdf53967017c58af68822100272/orjson-3.11.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97eb5942c7395a171cbfecc4ef6701fc3c403e762194683772df4c54cfbb2210", size = 136325, upload-time = "2025-10-24T15:49:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/18/ae/40516739f99ab4c7ec3aaa5cc242d341fcb03a45d89edeeaabc5f69cb2cf/orjson-3.11.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:149d95d5e018bdd822e3f38c103b1a7c91f88d38a88aada5c4e9b3a73a244241", size = 140204, upload-time = "2025-10-24T15:49:20.545Z" }, + { url = "https://files.pythonhosted.org/packages/82/18/ff5734365623a8916e3a4037fcef1cd1782bfc14cf0992afe7940c5320bf/orjson-3.11.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:624f3951181eb46fc47dea3d221554e98784c823e7069edb5dbd0dc826ac909b", size = 406242, upload-time = "2025-10-24T15:49:21.884Z" }, + { url = "https://files.pythonhosted.org/packages/e1/43/96436041f0a0c8c8deca6a05ebeaf529bf1de04839f93ac5e7c479807aec/orjson-3.11.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:03bfa548cf35e3f8b3a96c4e8e41f753c686ff3d8e182ce275b1751deddab58c", size = 150013, upload-time = "2025-10-24T15:49:23.185Z" }, + { url = "https://files.pythonhosted.org/packages/1b/48/78302d98423ed8780479a1e682b9aecb869e8404545d999d34fa486e573e/orjson-3.11.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:525021896afef44a68148f6ed8a8bf8375553d6066c7f48537657f64823565b9", size = 139951, upload-time = "2025-10-24T15:49:24.428Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/ad613fdcdaa812f075ec0875143c3d37f8654457d2af17703905425981bf/orjson-3.11.4-cp312-cp312-win32.whl", hash = "sha256:b58430396687ce0f7d9eeb3dd47761ca7d8fda8e9eb92b3077a7a353a75efefa", size = 136049, upload-time = "2025-10-24T15:49:25.973Z" }, + { url = "https://files.pythonhosted.org/packages/b9/3c/9cf47c3ff5f39b8350fb21ba65d789b6a1129d4cbb3033ba36c8a9023520/orjson-3.11.4-cp312-cp312-win_amd64.whl", hash = "sha256:c6dbf422894e1e3c80a177133c0dda260f81428f9de16d61041949f6a2e5c140", size = 131461, upload-time = "2025-10-24T15:49:27.259Z" }, + { url = "https://files.pythonhosted.org/packages/c6/3b/e2425f61e5825dc5b08c2a5a2b3af387eaaca22a12b9c8c01504f8614c36/orjson-3.11.4-cp312-cp312-win_arm64.whl", hash = "sha256:d38d2bc06d6415852224fcc9c0bfa834c25431e466dc319f0edd56cca81aa96e", size = 126167, upload-time = "2025-10-24T15:49:28.511Z" }, + { url = "https://files.pythonhosted.org/packages/23/15/c52aa7112006b0f3d6180386c3a46ae057f932ab3425bc6f6ac50431cca1/orjson-3.11.4-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:2d6737d0e616a6e053c8b4acc9eccea6b6cce078533666f32d140e4f85002534", size = 243525, upload-time = "2025-10-24T15:49:29.737Z" }, + { url = "https://files.pythonhosted.org/packages/ec/38/05340734c33b933fd114f161f25a04e651b0c7c33ab95e9416ade5cb44b8/orjson-3.11.4-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:afb14052690aa328cc118a8e09f07c651d301a72e44920b887c519b313d892ff", size = 128871, upload-time = "2025-10-24T15:49:31.109Z" }, + { url = "https://files.pythonhosted.org/packages/55/b9/ae8d34899ff0c012039b5a7cb96a389b2476e917733294e498586b45472d/orjson-3.11.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38aa9e65c591febb1b0aed8da4d469eba239d434c218562df179885c94e1a3ad", size = 130055, upload-time = "2025-10-24T15:49:33.382Z" }, + { url = "https://files.pythonhosted.org/packages/33/aa/6346dd5073730451bee3681d901e3c337e7ec17342fb79659ec9794fc023/orjson-3.11.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f2cf4dfaf9163b0728d061bebc1e08631875c51cd30bf47cb9e3293bfbd7dcd5", size = 129061, upload-time = "2025-10-24T15:49:34.935Z" }, + { url = "https://files.pythonhosted.org/packages/39/e4/8eea51598f66a6c853c380979912d17ec510e8e66b280d968602e680b942/orjson-3.11.4-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:89216ff3dfdde0e4070932e126320a1752c9d9a758d6a32ec54b3b9334991a6a", size = 136541, upload-time = "2025-10-24T15:49:36.923Z" }, + { url = "https://files.pythonhosted.org/packages/9a/47/cb8c654fa9adcc60e99580e17c32b9e633290e6239a99efa6b885aba9dbc/orjson-3.11.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9daa26ca8e97fae0ce8aa5d80606ef8f7914e9b129b6b5df9104266f764ce436", size = 137535, upload-time = "2025-10-24T15:49:38.307Z" }, + { url = "https://files.pythonhosted.org/packages/43/92/04b8cc5c2b729f3437ee013ce14a60ab3d3001465d95c184758f19362f23/orjson-3.11.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c8b2769dc31883c44a9cd126560327767f848eb95f99c36c9932f51090bfce9", size = 136703, upload-time = "2025-10-24T15:49:40.795Z" }, + { url = "https://files.pythonhosted.org/packages/aa/fd/d0733fcb9086b8be4ebcfcda2d0312865d17d0d9884378b7cffb29d0763f/orjson-3.11.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1469d254b9884f984026bd9b0fa5bbab477a4bfe558bba6848086f6d43eb5e73", size = 136293, upload-time = "2025-10-24T15:49:42.347Z" }, + { url = "https://files.pythonhosted.org/packages/c2/d7/3c5514e806837c210492d72ae30ccf050ce3f940f45bf085bab272699ef4/orjson-3.11.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:68e44722541983614e37117209a194e8c3ad07838ccb3127d96863c95ec7f1e0", size = 140131, upload-time = "2025-10-24T15:49:43.638Z" }, + { url = "https://files.pythonhosted.org/packages/9c/dd/ba9d32a53207babf65bd510ac4d0faaa818bd0df9a9c6f472fe7c254f2e3/orjson-3.11.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8e7805fda9672c12be2f22ae124dcd7b03928d6c197544fe12174b86553f3196", size = 406164, upload-time = "2025-10-24T15:49:45.498Z" }, + { url = "https://files.pythonhosted.org/packages/8e/f9/f68ad68f4af7c7bde57cd514eaa2c785e500477a8bc8f834838eb696a685/orjson-3.11.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:04b69c14615fb4434ab867bf6f38b2d649f6f300af30a6705397e895f7aec67a", size = 149859, upload-time = "2025-10-24T15:49:46.981Z" }, + { url = "https://files.pythonhosted.org/packages/b6/d2/7f847761d0c26818395b3d6b21fb6bc2305d94612a35b0a30eae65a22728/orjson-3.11.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:639c3735b8ae7f970066930e58cf0ed39a852d417c24acd4a25fc0b3da3c39a6", size = 139926, upload-time = "2025-10-24T15:49:48.321Z" }, + { url = "https://files.pythonhosted.org/packages/9f/37/acd14b12dc62db9a0e1d12386271b8661faae270b22492580d5258808975/orjson-3.11.4-cp313-cp313-win32.whl", hash = "sha256:6c13879c0d2964335491463302a6ca5ad98105fc5db3565499dcb80b1b4bd839", size = 136007, upload-time = "2025-10-24T15:49:49.938Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a9/967be009ddf0a1fffd7a67de9c36656b28c763659ef91352acc02cbe364c/orjson-3.11.4-cp313-cp313-win_amd64.whl", hash = "sha256:09bf242a4af98732db9f9a1ec57ca2604848e16f132e3f72edfd3c5c96de009a", size = 131314, upload-time = "2025-10-24T15:49:51.248Z" }, + { url = "https://files.pythonhosted.org/packages/cb/db/399abd6950fbd94ce125cb8cd1a968def95174792e127b0642781e040ed4/orjson-3.11.4-cp313-cp313-win_arm64.whl", hash = "sha256:a85f0adf63319d6c1ba06fb0dbf997fced64a01179cf17939a6caca662bf92de", size = 126152, upload-time = "2025-10-24T15:49:52.922Z" }, + { url = "https://files.pythonhosted.org/packages/25/e3/54ff63c093cc1697e758e4fceb53164dd2661a7d1bcd522260ba09f54533/orjson-3.11.4-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:42d43a1f552be1a112af0b21c10a5f553983c2a0938d2bbb8ecd8bc9fb572803", size = 243501, upload-time = "2025-10-24T15:49:54.288Z" }, + { url = "https://files.pythonhosted.org/packages/ac/7d/e2d1076ed2e8e0ae9badca65bf7ef22710f93887b29eaa37f09850604e09/orjson-3.11.4-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:26a20f3fbc6c7ff2cb8e89c4c5897762c9d88cf37330c6a117312365d6781d54", size = 128862, upload-time = "2025-10-24T15:49:55.961Z" }, + { url = "https://files.pythonhosted.org/packages/9f/37/ca2eb40b90621faddfa9517dfe96e25f5ae4d8057a7c0cdd613c17e07b2c/orjson-3.11.4-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6e3f20be9048941c7ffa8fc523ccbd17f82e24df1549d1d1fe9317712d19938e", size = 130047, upload-time = "2025-10-24T15:49:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/c7/62/1021ed35a1f2bad9040f05fa4cc4f9893410df0ba3eaa323ccf899b1c90a/orjson-3.11.4-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aac364c758dc87a52e68e349924d7e4ded348dedff553889e4d9f22f74785316", size = 129073, upload-time = "2025-10-24T15:49:58.782Z" }, + { url = "https://files.pythonhosted.org/packages/e8/3f/f84d966ec2a6fd5f73b1a707e7cd876813422ae4bf9f0145c55c9c6a0f57/orjson-3.11.4-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d5c54a6d76e3d741dcc3f2707f8eeb9ba2a791d3adbf18f900219b62942803b1", size = 136597, upload-time = "2025-10-24T15:50:00.12Z" }, + { url = "https://files.pythonhosted.org/packages/32/78/4fa0aeca65ee82bbabb49e055bd03fa4edea33f7c080c5c7b9601661ef72/orjson-3.11.4-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f28485bdca8617b79d44627f5fb04336897041dfd9fa66d383a49d09d86798bc", size = 137515, upload-time = "2025-10-24T15:50:01.57Z" }, + { url = "https://files.pythonhosted.org/packages/c1/9d/0c102e26e7fde40c4c98470796d050a2ec1953897e2c8ab0cb95b0759fa2/orjson-3.11.4-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bfc2a484cad3585e4ba61985a6062a4c2ed5c7925db6d39f1fa267c9d166487f", size = 136703, upload-time = "2025-10-24T15:50:02.944Z" }, + { url = "https://files.pythonhosted.org/packages/df/ac/2de7188705b4cdfaf0b6c97d2f7849c17d2003232f6e70df98602173f788/orjson-3.11.4-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e34dbd508cb91c54f9c9788923daca129fe5b55c5b4eebe713bf5ed3791280cf", size = 136311, upload-time = "2025-10-24T15:50:04.441Z" }, + { url = "https://files.pythonhosted.org/packages/e0/52/847fcd1a98407154e944feeb12e3b4d487a0e264c40191fb44d1269cbaa1/orjson-3.11.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:b13c478fa413d4b4ee606ec8e11c3b2e52683a640b006bb586b3041c2ca5f606", size = 140127, upload-time = "2025-10-24T15:50:07.398Z" }, + { url = "https://files.pythonhosted.org/packages/c1/ae/21d208f58bdb847dd4d0d9407e2929862561841baa22bdab7aea10ca088e/orjson-3.11.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:724ca721ecc8a831b319dcd72cfa370cc380db0bf94537f08f7edd0a7d4e1780", size = 406201, upload-time = "2025-10-24T15:50:08.796Z" }, + { url = "https://files.pythonhosted.org/packages/8d/55/0789d6de386c8366059db098a628e2ad8798069e94409b0d8935934cbcb9/orjson-3.11.4-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:977c393f2e44845ce1b540e19a786e9643221b3323dae190668a98672d43fb23", size = 149872, upload-time = "2025-10-24T15:50:10.234Z" }, + { url = "https://files.pythonhosted.org/packages/cc/1d/7ff81ea23310e086c17b41d78a72270d9de04481e6113dbe2ac19118f7fb/orjson-3.11.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1e539e382cf46edec157ad66b0b0872a90d829a6b71f17cb633d6c160a223155", size = 139931, upload-time = "2025-10-24T15:50:11.623Z" }, + { url = "https://files.pythonhosted.org/packages/77/92/25b886252c50ed64be68c937b562b2f2333b45afe72d53d719e46a565a50/orjson-3.11.4-cp314-cp314-win32.whl", hash = "sha256:d63076d625babab9db5e7836118bdfa086e60f37d8a174194ae720161eb12394", size = 136065, upload-time = "2025-10-24T15:50:13.025Z" }, + { url = "https://files.pythonhosted.org/packages/63/b8/718eecf0bb7e9d64e4956afaafd23db9f04c776d445f59fe94f54bdae8f0/orjson-3.11.4-cp314-cp314-win_amd64.whl", hash = "sha256:0a54d6635fa3aaa438ae32e8570b9f0de36f3f6562c308d2a2a452e8b0592db1", size = 131310, upload-time = "2025-10-24T15:50:14.46Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bf/def5e25d4d8bfce296a9a7c8248109bf58622c21618b590678f945a2c59c/orjson-3.11.4-cp314-cp314-win_arm64.whl", hash = "sha256:78b999999039db3cf58f6d230f524f04f75f129ba3d1ca2ed121f8657e575d3d", size = 126151, upload-time = "2025-10-24T15:50:15.878Z" }, ] [[package]] @@ -1733,15 +1736,6 @@ 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 = "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" @@ -1870,55 +1864,59 @@ wheels = [ [[package]] name = "pyarrow" -version = "20.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/ee/a7810cb9f3d6e9238e61d312076a9859bf3668fd21c69744de9532383912/pyarrow-20.0.0.tar.gz", hash = "sha256:febc4a913592573c8d5805091a6c2b5064c8bd6e002131f01061797d91c783c1", size = 1125187, upload-time = "2025-04-27T12:34:23.264Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5b/23/77094eb8ee0dbe88441689cb6afc40ac312a1e15d3a7acc0586999518222/pyarrow-20.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:c7dd06fd7d7b410ca5dc839cc9d485d2bc4ae5240851bcd45d85105cc90a47d7", size = 30832591, upload-time = "2025-04-27T12:27:27.89Z" }, - { url = "https://files.pythonhosted.org/packages/c3/d5/48cc573aff00d62913701d9fac478518f693b30c25f2c157550b0b2565cb/pyarrow-20.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:d5382de8dc34c943249b01c19110783d0d64b207167c728461add1ecc2db88e4", size = 32273686, upload-time = "2025-04-27T12:27:36.816Z" }, - { url = "https://files.pythonhosted.org/packages/37/df/4099b69a432b5cb412dd18adc2629975544d656df3d7fda6d73c5dba935d/pyarrow-20.0.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6415a0d0174487456ddc9beaead703d0ded5966129fa4fd3114d76b5d1c5ceae", size = 41337051, upload-time = "2025-04-27T12:27:44.4Z" }, - { url = "https://files.pythonhosted.org/packages/4c/27/99922a9ac1c9226f346e3a1e15e63dee6f623ed757ff2893f9d6994a69d3/pyarrow-20.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15aa1b3b2587e74328a730457068dc6c89e6dcbf438d4369f572af9d320a25ee", size = 42404659, upload-time = "2025-04-27T12:27:51.715Z" }, - { url = "https://files.pythonhosted.org/packages/21/d1/71d91b2791b829c9e98f1e0d85be66ed93aff399f80abb99678511847eaa/pyarrow-20.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5605919fbe67a7948c1f03b9f3727d82846c053cd2ce9303ace791855923fd20", size = 40695446, upload-time = "2025-04-27T12:27:59.643Z" }, - { url = "https://files.pythonhosted.org/packages/f1/ca/ae10fba419a6e94329707487835ec721f5a95f3ac9168500bcf7aa3813c7/pyarrow-20.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a5704f29a74b81673d266e5ec1fe376f060627c2e42c5c7651288ed4b0db29e9", size = 42278528, upload-time = "2025-04-27T12:28:07.297Z" }, - { url = "https://files.pythonhosted.org/packages/7a/a6/aba40a2bf01b5d00cf9cd16d427a5da1fad0fb69b514ce8c8292ab80e968/pyarrow-20.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:00138f79ee1b5aca81e2bdedb91e3739b987245e11fa3c826f9e57c5d102fb75", size = 42918162, upload-time = "2025-04-27T12:28:15.716Z" }, - { url = "https://files.pythonhosted.org/packages/93/6b/98b39650cd64f32bf2ec6d627a9bd24fcb3e4e6ea1873c5e1ea8a83b1a18/pyarrow-20.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f2d67ac28f57a362f1a2c1e6fa98bfe2f03230f7e15927aecd067433b1e70ce8", size = 44550319, upload-time = "2025-04-27T12:28:27.026Z" }, - { url = "https://files.pythonhosted.org/packages/ab/32/340238be1eb5037e7b5de7e640ee22334417239bc347eadefaf8c373936d/pyarrow-20.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:4a8b029a07956b8d7bd742ffca25374dd3f634b35e46cc7a7c3fa4c75b297191", size = 25770759, upload-time = "2025-04-27T12:28:33.702Z" }, - { url = "https://files.pythonhosted.org/packages/47/a2/b7930824181ceadd0c63c1042d01fa4ef63eee233934826a7a2a9af6e463/pyarrow-20.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:24ca380585444cb2a31324c546a9a56abbe87e26069189e14bdba19c86c049f0", size = 30856035, upload-time = "2025-04-27T12:28:40.78Z" }, - { url = "https://files.pythonhosted.org/packages/9b/18/c765770227d7f5bdfa8a69f64b49194352325c66a5c3bb5e332dfd5867d9/pyarrow-20.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:95b330059ddfdc591a3225f2d272123be26c8fa76e8c9ee1a77aad507361cfdb", size = 32309552, upload-time = "2025-04-27T12:28:47.051Z" }, - { url = "https://files.pythonhosted.org/packages/44/fb/dfb2dfdd3e488bb14f822d7335653092dde150cffc2da97de6e7500681f9/pyarrow-20.0.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f0fb1041267e9968c6d0d2ce3ff92e3928b243e2b6d11eeb84d9ac547308232", size = 41334704, upload-time = "2025-04-27T12:28:55.064Z" }, - { url = "https://files.pythonhosted.org/packages/58/0d/08a95878d38808051a953e887332d4a76bc06c6ee04351918ee1155407eb/pyarrow-20.0.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8ff87cc837601532cc8242d2f7e09b4e02404de1b797aee747dd4ba4bd6313f", size = 42399836, upload-time = "2025-04-27T12:29:02.13Z" }, - { url = "https://files.pythonhosted.org/packages/f3/cd/efa271234dfe38f0271561086eedcad7bc0f2ddd1efba423916ff0883684/pyarrow-20.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:7a3a5dcf54286e6141d5114522cf31dd67a9e7c9133d150799f30ee302a7a1ab", size = 40711789, upload-time = "2025-04-27T12:29:09.951Z" }, - { url = "https://files.pythonhosted.org/packages/46/1f/7f02009bc7fc8955c391defee5348f510e589a020e4b40ca05edcb847854/pyarrow-20.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a6ad3e7758ecf559900261a4df985662df54fb7fdb55e8e3b3aa99b23d526b62", size = 42301124, upload-time = "2025-04-27T12:29:17.187Z" }, - { url = "https://files.pythonhosted.org/packages/4f/92/692c562be4504c262089e86757a9048739fe1acb4024f92d39615e7bab3f/pyarrow-20.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6bb830757103a6cb300a04610e08d9636f0cd223d32f388418ea893a3e655f1c", size = 42916060, upload-time = "2025-04-27T12:29:24.253Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ec/9f5c7e7c828d8e0a3c7ef50ee62eca38a7de2fa6eb1b8fa43685c9414fef/pyarrow-20.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:96e37f0766ecb4514a899d9a3554fadda770fb57ddf42b63d80f14bc20aa7db3", size = 44547640, upload-time = "2025-04-27T12:29:32.782Z" }, - { url = "https://files.pythonhosted.org/packages/54/96/46613131b4727f10fd2ffa6d0d6f02efcc09a0e7374eff3b5771548aa95b/pyarrow-20.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:3346babb516f4b6fd790da99b98bed9708e3f02e734c84971faccb20736848dc", size = 25781491, upload-time = "2025-04-27T12:29:38.464Z" }, - { url = "https://files.pythonhosted.org/packages/a1/d6/0c10e0d54f6c13eb464ee9b67a68b8c71bcf2f67760ef5b6fbcddd2ab05f/pyarrow-20.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:75a51a5b0eef32727a247707d4755322cb970be7e935172b6a3a9f9ae98404ba", size = 30815067, upload-time = "2025-04-27T12:29:44.384Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e2/04e9874abe4094a06fd8b0cbb0f1312d8dd7d707f144c2ec1e5e8f452ffa/pyarrow-20.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:211d5e84cecc640c7a3ab900f930aaff5cd2702177e0d562d426fb7c4f737781", size = 32297128, upload-time = "2025-04-27T12:29:52.038Z" }, - { url = "https://files.pythonhosted.org/packages/31/fd/c565e5dcc906a3b471a83273039cb75cb79aad4a2d4a12f76cc5ae90a4b8/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ba3cf4182828be7a896cbd232aa8dd6a31bd1f9e32776cc3796c012855e1199", size = 41334890, upload-time = "2025-04-27T12:29:59.452Z" }, - { url = "https://files.pythonhosted.org/packages/af/a9/3bdd799e2c9b20c1ea6dc6fa8e83f29480a97711cf806e823f808c2316ac/pyarrow-20.0.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c3a01f313ffe27ac4126f4c2e5ea0f36a5fc6ab51f8726cf41fee4b256680bd", size = 42421775, upload-time = "2025-04-27T12:30:06.875Z" }, - { url = "https://files.pythonhosted.org/packages/10/f7/da98ccd86354c332f593218101ae56568d5dcedb460e342000bd89c49cc1/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:a2791f69ad72addd33510fec7bb14ee06c2a448e06b649e264c094c5b5f7ce28", size = 40687231, upload-time = "2025-04-27T12:30:13.954Z" }, - { url = "https://files.pythonhosted.org/packages/bb/1b/2168d6050e52ff1e6cefc61d600723870bf569cbf41d13db939c8cf97a16/pyarrow-20.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:4250e28a22302ce8692d3a0e8ec9d9dde54ec00d237cff4dfa9c1fbf79e472a8", size = 42295639, upload-time = "2025-04-27T12:30:21.949Z" }, - { url = "https://files.pythonhosted.org/packages/b2/66/2d976c0c7158fd25591c8ca55aee026e6d5745a021915a1835578707feb3/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:89e030dc58fc760e4010148e6ff164d2f44441490280ef1e97a542375e41058e", size = 42908549, upload-time = "2025-04-27T12:30:29.551Z" }, - { url = "https://files.pythonhosted.org/packages/31/a9/dfb999c2fc6911201dcbf348247f9cc382a8990f9ab45c12eabfd7243a38/pyarrow-20.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6102b4864d77102dbbb72965618e204e550135a940c2534711d5ffa787df2a5a", size = 44557216, upload-time = "2025-04-27T12:30:36.977Z" }, - { url = "https://files.pythonhosted.org/packages/a0/8e/9adee63dfa3911be2382fb4d92e4b2e7d82610f9d9f668493bebaa2af50f/pyarrow-20.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:96d6a0a37d9c98be08f5ed6a10831d88d52cac7b13f5287f1e0f625a0de8062b", size = 25660496, upload-time = "2025-04-27T12:30:42.809Z" }, - { url = "https://files.pythonhosted.org/packages/9b/aa/daa413b81446d20d4dad2944110dcf4cf4f4179ef7f685dd5a6d7570dc8e/pyarrow-20.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:a15532e77b94c61efadde86d10957950392999503b3616b2ffcef7621a002893", size = 30798501, upload-time = "2025-04-27T12:30:48.351Z" }, - { url = "https://files.pythonhosted.org/packages/ff/75/2303d1caa410925de902d32ac215dc80a7ce7dd8dfe95358c165f2adf107/pyarrow-20.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:dd43f58037443af715f34f1322c782ec463a3c8a94a85fdb2d987ceb5658e061", size = 32277895, upload-time = "2025-04-27T12:30:55.238Z" }, - { url = "https://files.pythonhosted.org/packages/92/41/fe18c7c0b38b20811b73d1bdd54b1fccba0dab0e51d2048878042d84afa8/pyarrow-20.0.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa0d288143a8585806e3cc7c39566407aab646fb9ece164609dac1cfff45f6ae", size = 41327322, upload-time = "2025-04-27T12:31:05.587Z" }, - { url = "https://files.pythonhosted.org/packages/da/ab/7dbf3d11db67c72dbf36ae63dcbc9f30b866c153b3a22ef728523943eee6/pyarrow-20.0.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6953f0114f8d6f3d905d98e987d0924dabce59c3cda380bdfaa25a6201563b4", size = 42411441, upload-time = "2025-04-27T12:31:15.675Z" }, - { url = "https://files.pythonhosted.org/packages/90/c3/0c7da7b6dac863af75b64e2f827e4742161128c350bfe7955b426484e226/pyarrow-20.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:991f85b48a8a5e839b2128590ce07611fae48a904cae6cab1f089c5955b57eb5", size = 40677027, upload-time = "2025-04-27T12:31:24.631Z" }, - { url = "https://files.pythonhosted.org/packages/be/27/43a47fa0ff9053ab5203bb3faeec435d43c0d8bfa40179bfd076cdbd4e1c/pyarrow-20.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:97c8dc984ed09cb07d618d57d8d4b67a5100a30c3818c2fb0b04599f0da2de7b", size = 42281473, upload-time = "2025-04-27T12:31:31.311Z" }, - { url = "https://files.pythonhosted.org/packages/bc/0b/d56c63b078876da81bbb9ba695a596eabee9b085555ed12bf6eb3b7cab0e/pyarrow-20.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:9b71daf534f4745818f96c214dbc1e6124d7daf059167330b610fc69b6f3d3e3", size = 42893897, upload-time = "2025-04-27T12:31:39.406Z" }, - { url = "https://files.pythonhosted.org/packages/92/ac/7d4bd020ba9145f354012838692d48300c1b8fe5634bfda886abcada67ed/pyarrow-20.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e8b88758f9303fa5a83d6c90e176714b2fd3852e776fc2d7e42a22dd6c2fb368", size = 44543847, upload-time = "2025-04-27T12:31:45.997Z" }, - { url = "https://files.pythonhosted.org/packages/9d/07/290f4abf9ca702c5df7b47739c1b2c83588641ddfa2cc75e34a301d42e55/pyarrow-20.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:30b3051b7975801c1e1d387e17c588d8ab05ced9b1e14eec57915f79869b5031", size = 25653219, upload-time = "2025-04-27T12:31:54.11Z" }, - { url = "https://files.pythonhosted.org/packages/95/df/720bb17704b10bd69dde086e1400b8eefb8f58df3f8ac9cff6c425bf57f1/pyarrow-20.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:ca151afa4f9b7bc45bcc791eb9a89e90a9eb2772767d0b1e5389609c7d03db63", size = 30853957, upload-time = "2025-04-27T12:31:59.215Z" }, - { url = "https://files.pythonhosted.org/packages/d9/72/0d5f875efc31baef742ba55a00a25213a19ea64d7176e0fe001c5d8b6e9a/pyarrow-20.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:4680f01ecd86e0dd63e39eb5cd59ef9ff24a9d166db328679e36c108dc993d4c", size = 32247972, upload-time = "2025-04-27T12:32:05.369Z" }, - { url = "https://files.pythonhosted.org/packages/d5/bc/e48b4fa544d2eea72f7844180eb77f83f2030b84c8dad860f199f94307ed/pyarrow-20.0.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f4c8534e2ff059765647aa69b75d6543f9fef59e2cd4c6d18015192565d2b70", size = 41256434, upload-time = "2025-04-27T12:32:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/c3/01/974043a29874aa2cf4f87fb07fd108828fc7362300265a2a64a94965e35b/pyarrow-20.0.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e1f8a47f4b4ae4c69c4d702cfbdfe4d41e18e5c7ef6f1bb1c50918c1e81c57b", size = 42353648, upload-time = "2025-04-27T12:32:20.766Z" }, - { url = "https://files.pythonhosted.org/packages/68/95/cc0d3634cde9ca69b0e51cbe830d8915ea32dda2157560dda27ff3b3337b/pyarrow-20.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:a1f60dc14658efaa927f8214734f6a01a806d7690be4b3232ba526836d216122", size = 40619853, upload-time = "2025-04-27T12:32:28.1Z" }, - { url = "https://files.pythonhosted.org/packages/29/c2/3ad40e07e96a3e74e7ed7cc8285aadfa84eb848a798c98ec0ad009eb6bcc/pyarrow-20.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:204a846dca751428991346976b914d6d2a82ae5b8316a6ed99789ebf976551e6", size = 42241743, upload-time = "2025-04-27T12:32:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/eb/cb/65fa110b483339add6a9bc7b6373614166b14e20375d4daa73483755f830/pyarrow-20.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f3b117b922af5e4c6b9a9115825726cac7d8b1421c37c2b5e24fbacc8930612c", size = 42839441, upload-time = "2025-04-27T12:32:46.64Z" }, - { url = "https://files.pythonhosted.org/packages/98/7b/f30b1954589243207d7a0fbc9997401044bf9a033eec78f6cb50da3f304a/pyarrow-20.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e724a3fd23ae5b9c010e7be857f4405ed5e679db5c93e66204db1a69f733936a", size = 44503279, upload-time = "2025-04-27T12:32:56.503Z" }, - { url = "https://files.pythonhosted.org/packages/37/40/ad395740cd641869a13bcf60851296c89624662575621968dcfafabaa7f6/pyarrow-20.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:82f1ee5133bd8f49d31be1299dc07f585136679666b502540db854968576faf9", size = 25944982, upload-time = "2025-04-27T12:33:04.72Z" }, +version = "22.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, + { url = "https://files.pythonhosted.org/packages/6c/41/3184b8192a120306270c5307f105b70320fdaa592c99843c5ef78aaefdcf/pyarrow-22.0.0-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:44d2d26cda26d18f7af7db71453b7b783788322d756e81730acb98f24eb90ace", size = 35942085, upload-time = "2025-10-24T10:03:38.146Z" }, + { url = "https://files.pythonhosted.org/packages/d9/3d/a1eab2f6f08001f9fb714b8ed5cfb045e2fe3e3e3c0c221f2c9ed1e6d67d/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b9d71701ce97c95480fecb0039ec5bb889e75f110da72005743451339262f4ce", size = 44964613, upload-time = "2025-10-24T10:03:46.516Z" }, + { url = "https://files.pythonhosted.org/packages/46/46/a1d9c24baf21cfd9ce994ac820a24608decf2710521b29223d4334985127/pyarrow-22.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:710624ab925dc2b05a6229d47f6f0dac1c1155e6ed559be7109f684eba048a48", size = 47627059, upload-time = "2025-10-24T10:03:55.353Z" }, + { url = "https://files.pythonhosted.org/packages/3a/4c/f711acb13075c1391fd54bc17e078587672c575f8de2a6e62509af026dcf/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f963ba8c3b0199f9d6b794c90ec77545e05eadc83973897a4523c9e8d84e9340", size = 47947043, upload-time = "2025-10-24T10:04:05.408Z" }, + { url = "https://files.pythonhosted.org/packages/4e/70/1f3180dd7c2eab35c2aca2b29ace6c519f827dcd4cfeb8e0dca41612cf7a/pyarrow-22.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd0d42297ace400d8febe55f13fdf46e86754842b860c978dfec16f081e5c653", size = 50206505, upload-time = "2025-10-24T10:04:15.786Z" }, + { url = "https://files.pythonhosted.org/packages/80/07/fea6578112c8c60ffde55883a571e4c4c6bc7049f119d6b09333b5cc6f73/pyarrow-22.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:00626d9dc0f5ef3a75fe63fd68b9c7c8302d2b5bbc7f74ecaedba83447a24f84", size = 28101641, upload-time = "2025-10-24T10:04:22.57Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b7/18f611a8cdc43417f9394a3ccd3eace2f32183c08b9eddc3d17681819f37/pyarrow-22.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:3e294c5eadfb93d78b0763e859a0c16d4051fc1c5231ae8956d61cb0b5666f5a", size = 34272022, upload-time = "2025-10-24T10:04:28.973Z" }, + { url = "https://files.pythonhosted.org/packages/26/5c/f259e2526c67eb4b9e511741b19870a02363a47a35edbebc55c3178db22d/pyarrow-22.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:69763ab2445f632d90b504a815a2a033f74332997052b721002298ed6de40f2e", size = 35995834, upload-time = "2025-10-24T10:04:35.467Z" }, + { url = "https://files.pythonhosted.org/packages/50/8d/281f0f9b9376d4b7f146913b26fac0aa2829cd1ee7e997f53a27411bbb92/pyarrow-22.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:b41f37cabfe2463232684de44bad753d6be08a7a072f6a83447eeaf0e4d2a215", size = 45030348, upload-time = "2025-10-24T10:04:43.366Z" }, + { url = "https://files.pythonhosted.org/packages/f5/e5/53c0a1c428f0976bf22f513d79c73000926cb00b9c138d8e02daf2102e18/pyarrow-22.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:35ad0f0378c9359b3f297299c3309778bb03b8612f987399a0333a560b43862d", size = 47699480, upload-time = "2025-10-24T10:04:51.486Z" }, + { url = "https://files.pythonhosted.org/packages/95/e1/9dbe4c465c3365959d183e6345d0a8d1dc5b02ca3f8db4760b3bc834cf25/pyarrow-22.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8382ad21458075c2e66a82a29d650f963ce51c7708c7c0ff313a8c206c4fd5e8", size = 48011148, upload-time = "2025-10-24T10:04:59.585Z" }, + { url = "https://files.pythonhosted.org/packages/c5/b4/7caf5d21930061444c3cf4fa7535c82faf5263e22ce43af7c2759ceb5b8b/pyarrow-22.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1a812a5b727bc09c3d7ea072c4eebf657c2f7066155506ba31ebf4792f88f016", size = 50276964, upload-time = "2025-10-24T10:05:08.175Z" }, + { url = "https://files.pythonhosted.org/packages/ae/f3/cec89bd99fa3abf826f14d4e53d3d11340ce6f6af4d14bdcd54cd83b6576/pyarrow-22.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:ec5d40dd494882704fb876c16fa7261a69791e784ae34e6b5992e977bd2e238c", size = 28106517, upload-time = "2025-10-24T10:05:14.314Z" }, + { url = "https://files.pythonhosted.org/packages/af/63/ba23862d69652f85b615ca14ad14f3bcfc5bf1b99ef3f0cd04ff93fdad5a/pyarrow-22.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bea79263d55c24a32b0d79c00a1c58bb2ee5f0757ed95656b01c0fb310c5af3d", size = 34211578, upload-time = "2025-10-24T10:05:21.583Z" }, + { url = "https://files.pythonhosted.org/packages/b1/d0/f9ad86fe809efd2bcc8be32032fa72e8b0d112b01ae56a053006376c5930/pyarrow-22.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:12fe549c9b10ac98c91cf791d2945e878875d95508e1a5d14091a7aaa66d9cf8", size = 35989906, upload-time = "2025-10-24T10:05:29.485Z" }, + { url = "https://files.pythonhosted.org/packages/b4/a8/f910afcb14630e64d673f15904ec27dd31f1e009b77033c365c84e8c1e1d/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:334f900ff08ce0423407af97e6c26ad5d4e3b0763645559ece6fbf3747d6a8f5", size = 45021677, upload-time = "2025-10-24T10:05:38.274Z" }, + { url = "https://files.pythonhosted.org/packages/13/95/aec81f781c75cd10554dc17a25849c720d54feafb6f7847690478dcf5ef8/pyarrow-22.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:c6c791b09c57ed76a18b03f2631753a4960eefbbca80f846da8baefc6491fcfe", size = 47726315, upload-time = "2025-10-24T10:05:47.314Z" }, + { url = "https://files.pythonhosted.org/packages/bb/d4/74ac9f7a54cfde12ee42734ea25d5a3c9a45db78f9def949307a92720d37/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c3200cb41cdbc65156e5f8c908d739b0dfed57e890329413da2748d1a2cd1a4e", size = 47990906, upload-time = "2025-10-24T10:05:58.254Z" }, + { url = "https://files.pythonhosted.org/packages/2e/71/fedf2499bf7a95062eafc989ace56572f3343432570e1c54e6599d5b88da/pyarrow-22.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ac93252226cf288753d8b46280f4edf3433bf9508b6977f8dd8526b521a1bbb9", size = 50306783, upload-time = "2025-10-24T10:06:08.08Z" }, + { url = "https://files.pythonhosted.org/packages/68/ed/b202abd5a5b78f519722f3d29063dda03c114711093c1995a33b8e2e0f4b/pyarrow-22.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:44729980b6c50a5f2bfcc2668d36c569ce17f8b17bccaf470c4313dcbbf13c9d", size = 27972883, upload-time = "2025-10-24T10:06:14.204Z" }, + { url = "https://files.pythonhosted.org/packages/a6/d6/d0fac16a2963002fc22c8fa75180a838737203d558f0ed3b564c4a54eef5/pyarrow-22.0.0-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:e6e95176209257803a8b3d0394f21604e796dadb643d2f7ca21b66c9c0b30c9a", size = 34204629, upload-time = "2025-10-24T10:06:20.274Z" }, + { url = "https://files.pythonhosted.org/packages/c6/9c/1d6357347fbae062ad3f17082f9ebc29cc733321e892c0d2085f42a2212b/pyarrow-22.0.0-cp313-cp313-macosx_12_0_x86_64.whl", hash = "sha256:001ea83a58024818826a9e3f89bf9310a114f7e26dfe404a4c32686f97bd7901", size = 35985783, upload-time = "2025-10-24T10:06:27.301Z" }, + { url = "https://files.pythonhosted.org/packages/ff/c0/782344c2ce58afbea010150df07e3a2f5fdad299cd631697ae7bd3bac6e3/pyarrow-22.0.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:ce20fe000754f477c8a9125543f1936ea5b8867c5406757c224d745ed033e691", size = 45020999, upload-time = "2025-10-24T10:06:35.387Z" }, + { url = "https://files.pythonhosted.org/packages/1b/8b/5362443737a5307a7b67c1017c42cd104213189b4970bf607e05faf9c525/pyarrow-22.0.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:e0a15757fccb38c410947df156f9749ae4a3c89b2393741a50521f39a8cf202a", size = 47724601, upload-time = "2025-10-24T10:06:43.551Z" }, + { url = "https://files.pythonhosted.org/packages/69/4d/76e567a4fc2e190ee6072967cb4672b7d9249ac59ae65af2d7e3047afa3b/pyarrow-22.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cedb9dd9358e4ea1d9bce3665ce0797f6adf97ff142c8e25b46ba9cdd508e9b6", size = 48001050, upload-time = "2025-10-24T10:06:52.284Z" }, + { url = "https://files.pythonhosted.org/packages/01/5e/5653f0535d2a1aef8223cee9d92944cb6bccfee5cf1cd3f462d7cb022790/pyarrow-22.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:252be4a05f9d9185bb8c18e83764ebcfea7185076c07a7a662253af3a8c07941", size = 50307877, upload-time = "2025-10-24T10:07:02.405Z" }, + { url = "https://files.pythonhosted.org/packages/2d/f8/1d0bd75bf9328a3b826e24a16e5517cd7f9fbf8d34a3184a4566ef5a7f29/pyarrow-22.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:a4893d31e5ef780b6edcaf63122df0f8d321088bb0dee4c8c06eccb1ca28d145", size = 27977099, upload-time = "2025-10-24T10:08:07.259Z" }, + { url = "https://files.pythonhosted.org/packages/90/81/db56870c997805bf2b0f6eeeb2d68458bf4654652dccdcf1bf7a42d80903/pyarrow-22.0.0-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:f7fe3dbe871294ba70d789be16b6e7e52b418311e166e0e3cba9522f0f437fb1", size = 34336685, upload-time = "2025-10-24T10:07:11.47Z" }, + { url = "https://files.pythonhosted.org/packages/1c/98/0727947f199aba8a120f47dfc229eeb05df15bcd7a6f1b669e9f882afc58/pyarrow-22.0.0-cp313-cp313t-macosx_12_0_x86_64.whl", hash = "sha256:ba95112d15fd4f1105fb2402c4eab9068f0554435e9b7085924bcfaac2cc306f", size = 36032158, upload-time = "2025-10-24T10:07:18.626Z" }, + { url = "https://files.pythonhosted.org/packages/96/b4/9babdef9c01720a0785945c7cf550e4acd0ebcd7bdd2e6f0aa7981fa85e2/pyarrow-22.0.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:c064e28361c05d72eed8e744c9605cbd6d2bb7481a511c74071fd9b24bc65d7d", size = 44892060, upload-time = "2025-10-24T10:07:26.002Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ca/2f8804edd6279f78a37062d813de3f16f29183874447ef6d1aadbb4efa0f/pyarrow-22.0.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:6f9762274496c244d951c819348afbcf212714902742225f649cf02823a6a10f", size = 47504395, upload-time = "2025-10-24T10:07:34.09Z" }, + { url = "https://files.pythonhosted.org/packages/b9/f0/77aa5198fd3943682b2e4faaf179a674f0edea0d55d326d83cb2277d9363/pyarrow-22.0.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:a9d9ffdc2ab696f6b15b4d1f7cec6658e1d788124418cb30030afbae31c64746", size = 48066216, upload-time = "2025-10-24T10:07:43.528Z" }, + { url = "https://files.pythonhosted.org/packages/79/87/a1937b6e78b2aff18b706d738c9e46ade5bfcf11b294e39c87706a0089ac/pyarrow-22.0.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:ec1a15968a9d80da01e1d30349b2b0d7cc91e96588ee324ce1b5228175043e95", size = 50288552, upload-time = "2025-10-24T10:07:53.519Z" }, + { url = "https://files.pythonhosted.org/packages/60/ae/b5a5811e11f25788ccfdaa8f26b6791c9807119dffcf80514505527c384c/pyarrow-22.0.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bba208d9c7decf9961998edf5c65e3ea4355d5818dd6cd0f6809bec1afb951cc", size = 28262504, upload-time = "2025-10-24T10:08:00.932Z" }, + { url = "https://files.pythonhosted.org/packages/bd/b0/0fa4d28a8edb42b0a7144edd20befd04173ac79819547216f8a9f36f9e50/pyarrow-22.0.0-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:9bddc2cade6561f6820d4cd73f99a0243532ad506bc510a75a5a65a522b2d74d", size = 34224062, upload-time = "2025-10-24T10:08:14.101Z" }, + { url = "https://files.pythonhosted.org/packages/0f/a8/7a719076b3c1be0acef56a07220c586f25cd24de0e3f3102b438d18ae5df/pyarrow-22.0.0-cp314-cp314-macosx_12_0_x86_64.whl", hash = "sha256:e70ff90c64419709d38c8932ea9fe1cc98415c4f87ea8da81719e43f02534bc9", size = 35990057, upload-time = "2025-10-24T10:08:21.842Z" }, + { url = "https://files.pythonhosted.org/packages/89/3c/359ed54c93b47fb6fe30ed16cdf50e3f0e8b9ccfb11b86218c3619ae50a8/pyarrow-22.0.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:92843c305330aa94a36e706c16209cd4df274693e777ca47112617db7d0ef3d7", size = 45068002, upload-time = "2025-10-24T10:08:29.034Z" }, + { url = "https://files.pythonhosted.org/packages/55/fc/4945896cc8638536ee787a3bd6ce7cec8ec9acf452d78ec39ab328efa0a1/pyarrow-22.0.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:6dda1ddac033d27421c20d7a7943eec60be44e0db4e079f33cc5af3b8280ccde", size = 47737765, upload-time = "2025-10-24T10:08:38.559Z" }, + { url = "https://files.pythonhosted.org/packages/cd/5e/7cb7edeb2abfaa1f79b5d5eb89432356155c8426f75d3753cbcb9592c0fd/pyarrow-22.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:84378110dd9a6c06323b41b56e129c504d157d1a983ce8f5443761eb5256bafc", size = 48048139, upload-time = "2025-10-24T10:08:46.784Z" }, + { url = "https://files.pythonhosted.org/packages/88/c6/546baa7c48185f5e9d6e59277c4b19f30f48c94d9dd938c2a80d4d6b067c/pyarrow-22.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:854794239111d2b88b40b6ef92aa478024d1e5074f364033e73e21e3f76b25e0", size = 50314244, upload-time = "2025-10-24T10:08:55.771Z" }, + { url = "https://files.pythonhosted.org/packages/3c/79/755ff2d145aafec8d347bf18f95e4e81c00127f06d080135dfc86aea417c/pyarrow-22.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:b883fe6fd85adad7932b3271c38ac289c65b7337c2c132e9569f9d3940620730", size = 28757501, upload-time = "2025-10-24T10:09:59.891Z" }, + { url = "https://files.pythonhosted.org/packages/0e/d2/237d75ac28ced3147912954e3c1a174df43a95f4f88e467809118a8165e0/pyarrow-22.0.0-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7a820d8ae11facf32585507c11f04e3f38343c1e784c9b5a8b1da5c930547fe2", size = 34355506, upload-time = "2025-10-24T10:09:02.953Z" }, + { url = "https://files.pythonhosted.org/packages/1e/2c/733dfffe6d3069740f98e57ff81007809067d68626c5faef293434d11bd6/pyarrow-22.0.0-cp314-cp314t-macosx_12_0_x86_64.whl", hash = "sha256:c6ec3675d98915bf1ec8b3c7986422682f7232ea76cad276f4c8abd5b7319b70", size = 36047312, upload-time = "2025-10-24T10:09:10.334Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2b/29d6e3782dc1f299727462c1543af357a0f2c1d3c160ce199950d9ca51eb/pyarrow-22.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:3e739edd001b04f654b166204fc7a9de896cf6007eaff33409ee9e50ceaff754", size = 45081609, upload-time = "2025-10-24T10:09:18.61Z" }, + { url = "https://files.pythonhosted.org/packages/8d/42/aa9355ecc05997915af1b7b947a7f66c02dcaa927f3203b87871c114ba10/pyarrow-22.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:7388ac685cab5b279a41dfe0a6ccd99e4dbf322edfb63e02fc0443bf24134e91", size = 47703663, upload-time = "2025-10-24T10:09:27.369Z" }, + { url = "https://files.pythonhosted.org/packages/ee/62/45abedde480168e83a1de005b7b7043fd553321c1e8c5a9a114425f64842/pyarrow-22.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f633074f36dbc33d5c05b5dc75371e5660f1dbf9c8b1d95669def05e5425989c", size = 48066543, upload-time = "2025-10-24T10:09:34.908Z" }, + { url = "https://files.pythonhosted.org/packages/84/e9/7878940a5b072e4f3bf998770acafeae13b267f9893af5f6d4ab3904b67e/pyarrow-22.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:4c19236ae2402a8663a2c8f21f1870a03cc57f0bef7e4b6eb3238cc82944de80", size = 50288838, upload-time = "2025-10-24T10:09:44.394Z" }, + { url = "https://files.pythonhosted.org/packages/7b/03/f335d6c52b4a4761bcc83499789a1e2e16d9d201a58c327a9b5cc9a41bd9/pyarrow-22.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:0c34fe18094686194f204a3b1787a27456897d8a2d62caf84b61e8dfbc0252ae", size = 29185594, upload-time = "2025-10-24T10:09:53.111Z" }, ] [[package]] @@ -1932,7 +1930,7 @@ wheels = [ [[package]] name = "pydantic" -version = "2.11.7" +version = "2.12.5" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, @@ -1940,96 +1938,127 @@ dependencies = [ { 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" } +sdist = { url = "https://files.pythonhosted.org/packages/69/44/36f1a6e523abc58ae5f928898e4aca2e0ea509b5aa6f6f392a5d882be928/pydantic-2.12.5.tar.gz", hash = "sha256:4d351024c75c0f085a9febbb665ce8c0c6ec5d30e903bdb6394b7ede26aebb49", size = 821591, upload-time = "2025-11-26T15:11:46.471Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] [[package]] name = "pydantic-core" -version = "2.33.2" +version = "2.41.5" 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/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" }, - { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" }, - { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" }, - { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" }, - { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" }, - { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" }, - { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" }, - { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" }, - { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" }, - { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, - { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, - { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, - { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, - { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, - { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, - { 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" }, - { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, - { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, - { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" }, - { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" }, - { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" }, - { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, - { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, - { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/71/70/23b021c950c2addd24ec408e9ab05d59b035b39d97cdc1130e1bce647bb6/pydantic_core-2.41.5.tar.gz", hash = "sha256:08daa51ea16ad373ffd5e7606252cc32f07bc72b28284b6bc9c6df804816476e", size = 460952, upload-time = "2025-11-04T13:43:49.098Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c6/90/32c9941e728d564b411d574d8ee0cf09b12ec978cb22b294995bae5549a5/pydantic_core-2.41.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:77b63866ca88d804225eaa4af3e664c5faf3568cea95360d21f4725ab6e07146", size = 2107298, upload-time = "2025-11-04T13:39:04.116Z" }, + { url = "https://files.pythonhosted.org/packages/fb/a8/61c96a77fe28993d9a6fb0f4127e05430a267b235a124545d79fea46dd65/pydantic_core-2.41.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dfa8a0c812ac681395907e71e1274819dec685fec28273a28905df579ef137e2", size = 1901475, upload-time = "2025-11-04T13:39:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/5d/b6/338abf60225acc18cdc08b4faef592d0310923d19a87fba1faf05af5346e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5921a4d3ca3aee735d9fd163808f5e8dd6c6972101e4adbda9a4667908849b97", size = 1918815, upload-time = "2025-11-04T13:39:10.41Z" }, + { url = "https://files.pythonhosted.org/packages/d1/1c/2ed0433e682983d8e8cba9c8d8ef274d4791ec6a6f24c58935b90e780e0a/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e25c479382d26a2a41b7ebea1043564a937db462816ea07afa8a44c0866d52f9", size = 2065567, upload-time = "2025-11-04T13:39:12.244Z" }, + { url = "https://files.pythonhosted.org/packages/b3/24/cf84974ee7d6eae06b9e63289b7b8f6549d416b5c199ca2d7ce13bbcf619/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f547144f2966e1e16ae626d8ce72b4cfa0caedc7fa28052001c94fb2fcaa1c52", size = 2230442, upload-time = "2025-11-04T13:39:13.962Z" }, + { url = "https://files.pythonhosted.org/packages/fd/21/4e287865504b3edc0136c89c9c09431be326168b1eb7841911cbc877a995/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f52298fbd394f9ed112d56f3d11aabd0d5bd27beb3084cc3d8ad069483b8941", size = 2350956, upload-time = "2025-11-04T13:39:15.889Z" }, + { url = "https://files.pythonhosted.org/packages/a8/76/7727ef2ffa4b62fcab916686a68a0426b9b790139720e1934e8ba797e238/pydantic_core-2.41.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:100baa204bb412b74fe285fb0f3a385256dad1d1879f0a5cb1499ed2e83d132a", size = 2068253, upload-time = "2025-11-04T13:39:17.403Z" }, + { url = "https://files.pythonhosted.org/packages/d5/8c/a4abfc79604bcb4c748e18975c44f94f756f08fb04218d5cb87eb0d3a63e/pydantic_core-2.41.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:05a2c8852530ad2812cb7914dc61a1125dc4e06252ee98e5638a12da6cc6fb6c", size = 2177050, upload-time = "2025-11-04T13:39:19.351Z" }, + { url = "https://files.pythonhosted.org/packages/67/b1/de2e9a9a79b480f9cb0b6e8b6ba4c50b18d4e89852426364c66aa82bb7b3/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29452c56df2ed968d18d7e21f4ab0ac55e71dc59524872f6fc57dcf4a3249ed2", size = 2147178, upload-time = "2025-11-04T13:39:21Z" }, + { url = "https://files.pythonhosted.org/packages/16/c1/dfb33f837a47b20417500efaa0378adc6635b3c79e8369ff7a03c494b4ac/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:d5160812ea7a8a2ffbe233d8da666880cad0cbaf5d4de74ae15c313213d62556", size = 2341833, upload-time = "2025-11-04T13:39:22.606Z" }, + { url = "https://files.pythonhosted.org/packages/47/36/00f398642a0f4b815a9a558c4f1dca1b4020a7d49562807d7bc9ff279a6c/pydantic_core-2.41.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:df3959765b553b9440adfd3c795617c352154e497a4eaf3752555cfb5da8fc49", size = 2321156, upload-time = "2025-11-04T13:39:25.843Z" }, + { url = "https://files.pythonhosted.org/packages/7e/70/cad3acd89fde2010807354d978725ae111ddf6d0ea46d1ea1775b5c1bd0c/pydantic_core-2.41.5-cp310-cp310-win32.whl", hash = "sha256:1f8d33a7f4d5a7889e60dc39856d76d09333d8a6ed0f5f1190635cbec70ec4ba", size = 1989378, upload-time = "2025-11-04T13:39:27.92Z" }, + { url = "https://files.pythonhosted.org/packages/76/92/d338652464c6c367e5608e4488201702cd1cbb0f33f7b6a85a60fe5f3720/pydantic_core-2.41.5-cp310-cp310-win_amd64.whl", hash = "sha256:62de39db01b8d593e45871af2af9e497295db8d73b085f6bfd0b18c83c70a8f9", size = 2013622, upload-time = "2025-11-04T13:39:29.848Z" }, + { url = "https://files.pythonhosted.org/packages/e8/72/74a989dd9f2084b3d9530b0915fdda64ac48831c30dbf7c72a41a5232db8/pydantic_core-2.41.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a3a52f6156e73e7ccb0f8cced536adccb7042be67cb45f9562e12b319c119da6", size = 2105873, upload-time = "2025-11-04T13:39:31.373Z" }, + { url = "https://files.pythonhosted.org/packages/12/44/37e403fd9455708b3b942949e1d7febc02167662bf1a7da5b78ee1ea2842/pydantic_core-2.41.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7f3bf998340c6d4b0c9a2f02d6a400e51f123b59565d74dc60d252ce888c260b", size = 1899826, upload-time = "2025-11-04T13:39:32.897Z" }, + { url = "https://files.pythonhosted.org/packages/33/7f/1d5cab3ccf44c1935a359d51a8a2a9e1a654b744b5e7f80d41b88d501eec/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:378bec5c66998815d224c9ca994f1e14c0c21cb95d2f52b6021cc0b2a58f2a5a", size = 1917869, upload-time = "2025-11-04T13:39:34.469Z" }, + { url = "https://files.pythonhosted.org/packages/6e/6a/30d94a9674a7fe4f4744052ed6c5e083424510be1e93da5bc47569d11810/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e7b576130c69225432866fe2f4a469a85a54ade141d96fd396dffcf607b558f8", size = 2063890, upload-time = "2025-11-04T13:39:36.053Z" }, + { url = "https://files.pythonhosted.org/packages/50/be/76e5d46203fcb2750e542f32e6c371ffa9b8ad17364cf94bb0818dbfb50c/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6cb58b9c66f7e4179a2d5e0f849c48eff5c1fca560994d6eb6543abf955a149e", size = 2229740, upload-time = "2025-11-04T13:39:37.753Z" }, + { url = "https://files.pythonhosted.org/packages/d3/ee/fed784df0144793489f87db310a6bbf8118d7b630ed07aa180d6067e653a/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:88942d3a3dff3afc8288c21e565e476fc278902ae4d6d134f1eeda118cc830b1", size = 2350021, upload-time = "2025-11-04T13:39:40.94Z" }, + { url = "https://files.pythonhosted.org/packages/c8/be/8fed28dd0a180dca19e72c233cbf58efa36df055e5b9d90d64fd1740b828/pydantic_core-2.41.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f31d95a179f8d64d90f6831d71fa93290893a33148d890ba15de25642c5d075b", size = 2066378, upload-time = "2025-11-04T13:39:42.523Z" }, + { url = "https://files.pythonhosted.org/packages/b0/3b/698cf8ae1d536a010e05121b4958b1257f0b5522085e335360e53a6b1c8b/pydantic_core-2.41.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c1df3d34aced70add6f867a8cf413e299177e0c22660cc767218373d0779487b", size = 2175761, upload-time = "2025-11-04T13:39:44.553Z" }, + { url = "https://files.pythonhosted.org/packages/b8/ba/15d537423939553116dea94ce02f9c31be0fa9d0b806d427e0308ec17145/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4009935984bd36bd2c774e13f9a09563ce8de4abaa7226f5108262fa3e637284", size = 2146303, upload-time = "2025-11-04T13:39:46.238Z" }, + { url = "https://files.pythonhosted.org/packages/58/7f/0de669bf37d206723795f9c90c82966726a2ab06c336deba4735b55af431/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:34a64bc3441dc1213096a20fe27e8e128bd3ff89921706e83c0b1ac971276594", size = 2340355, upload-time = "2025-11-04T13:39:48.002Z" }, + { url = "https://files.pythonhosted.org/packages/e5/de/e7482c435b83d7e3c3ee5ee4451f6e8973cff0eb6007d2872ce6383f6398/pydantic_core-2.41.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c9e19dd6e28fdcaa5a1de679aec4141f691023916427ef9bae8584f9c2fb3b0e", size = 2319875, upload-time = "2025-11-04T13:39:49.705Z" }, + { url = "https://files.pythonhosted.org/packages/fe/e6/8c9e81bb6dd7560e33b9053351c29f30c8194b72f2d6932888581f503482/pydantic_core-2.41.5-cp311-cp311-win32.whl", hash = "sha256:2c010c6ded393148374c0f6f0bf89d206bf3217f201faa0635dcd56bd1520f6b", size = 1987549, upload-time = "2025-11-04T13:39:51.842Z" }, + { url = "https://files.pythonhosted.org/packages/11/66/f14d1d978ea94d1bc21fc98fcf570f9542fe55bfcc40269d4e1a21c19bf7/pydantic_core-2.41.5-cp311-cp311-win_amd64.whl", hash = "sha256:76ee27c6e9c7f16f47db7a94157112a2f3a00e958bc626e2f4ee8bec5c328fbe", size = 2011305, upload-time = "2025-11-04T13:39:53.485Z" }, + { url = "https://files.pythonhosted.org/packages/56/d8/0e271434e8efd03186c5386671328154ee349ff0354d83c74f5caaf096ed/pydantic_core-2.41.5-cp311-cp311-win_arm64.whl", hash = "sha256:4bc36bbc0b7584de96561184ad7f012478987882ebf9f9c389b23f432ea3d90f", size = 1972902, upload-time = "2025-11-04T13:39:56.488Z" }, + { url = "https://files.pythonhosted.org/packages/5f/5d/5f6c63eebb5afee93bcaae4ce9a898f3373ca23df3ccaef086d0233a35a7/pydantic_core-2.41.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:f41a7489d32336dbf2199c8c0a215390a751c5b014c2c1c5366e817202e9cdf7", size = 2110990, upload-time = "2025-11-04T13:39:58.079Z" }, + { url = "https://files.pythonhosted.org/packages/aa/32/9c2e8ccb57c01111e0fd091f236c7b371c1bccea0fa85247ac55b1e2b6b6/pydantic_core-2.41.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:070259a8818988b9a84a449a2a7337c7f430a22acc0859c6b110aa7212a6d9c0", size = 1896003, upload-time = "2025-11-04T13:39:59.956Z" }, + { url = "https://files.pythonhosted.org/packages/68/b8/a01b53cb0e59139fbc9e4fda3e9724ede8de279097179be4ff31f1abb65a/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e96cea19e34778f8d59fe40775a7a574d95816eb150850a85a7a4c8f4b94ac69", size = 1919200, upload-time = "2025-11-04T13:40:02.241Z" }, + { url = "https://files.pythonhosted.org/packages/38/de/8c36b5198a29bdaade07b5985e80a233a5ac27137846f3bc2d3b40a47360/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed2e99c456e3fadd05c991f8f437ef902e00eedf34320ba2b0842bd1c3ca3a75", size = 2052578, upload-time = "2025-11-04T13:40:04.401Z" }, + { url = "https://files.pythonhosted.org/packages/00/b5/0e8e4b5b081eac6cb3dbb7e60a65907549a1ce035a724368c330112adfdd/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65840751b72fbfd82c3c640cff9284545342a4f1eb1586ad0636955b261b0b05", size = 2208504, upload-time = "2025-11-04T13:40:06.072Z" }, + { url = "https://files.pythonhosted.org/packages/77/56/87a61aad59c7c5b9dc8caad5a41a5545cba3810c3e828708b3d7404f6cef/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e536c98a7626a98feb2d3eaf75944ef6f3dbee447e1f841eae16f2f0a72d8ddc", size = 2335816, upload-time = "2025-11-04T13:40:07.835Z" }, + { url = "https://files.pythonhosted.org/packages/0d/76/941cc9f73529988688a665a5c0ecff1112b3d95ab48f81db5f7606f522d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eceb81a8d74f9267ef4081e246ffd6d129da5d87e37a77c9bde550cb04870c1c", size = 2075366, upload-time = "2025-11-04T13:40:09.804Z" }, + { url = "https://files.pythonhosted.org/packages/d3/43/ebef01f69baa07a482844faaa0a591bad1ef129253ffd0cdaa9d8a7f72d3/pydantic_core-2.41.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d38548150c39b74aeeb0ce8ee1d8e82696f4a4e16ddc6de7b1d8823f7de4b9b5", size = 2171698, upload-time = "2025-11-04T13:40:12.004Z" }, + { url = "https://files.pythonhosted.org/packages/b1/87/41f3202e4193e3bacfc2c065fab7706ebe81af46a83d3e27605029c1f5a6/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c23e27686783f60290e36827f9c626e63154b82b116d7fe9adba1fda36da706c", size = 2132603, upload-time = "2025-11-04T13:40:13.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7d/4c00df99cb12070b6bccdef4a195255e6020a550d572768d92cc54dba91a/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:482c982f814460eabe1d3bb0adfdc583387bd4691ef00b90575ca0d2b6fe2294", size = 2329591, upload-time = "2025-11-04T13:40:15.672Z" }, + { url = "https://files.pythonhosted.org/packages/cc/6a/ebf4b1d65d458f3cda6a7335d141305dfa19bdc61140a884d165a8a1bbc7/pydantic_core-2.41.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:bfea2a5f0b4d8d43adf9d7b8bf019fb46fdd10a2e5cde477fbcb9d1fa08c68e1", size = 2319068, upload-time = "2025-11-04T13:40:17.532Z" }, + { url = "https://files.pythonhosted.org/packages/49/3b/774f2b5cd4192d5ab75870ce4381fd89cf218af999515baf07e7206753f0/pydantic_core-2.41.5-cp312-cp312-win32.whl", hash = "sha256:b74557b16e390ec12dca509bce9264c3bbd128f8a2c376eaa68003d7f327276d", size = 1985908, upload-time = "2025-11-04T13:40:19.309Z" }, + { url = "https://files.pythonhosted.org/packages/86/45/00173a033c801cacf67c190fef088789394feaf88a98a7035b0e40d53dc9/pydantic_core-2.41.5-cp312-cp312-win_amd64.whl", hash = "sha256:1962293292865bca8e54702b08a4f26da73adc83dd1fcf26fbc875b35d81c815", size = 2020145, upload-time = "2025-11-04T13:40:21.548Z" }, + { url = "https://files.pythonhosted.org/packages/f9/22/91fbc821fa6d261b376a3f73809f907cec5ca6025642c463d3488aad22fb/pydantic_core-2.41.5-cp312-cp312-win_arm64.whl", hash = "sha256:1746d4a3d9a794cacae06a5eaaccb4b8643a131d45fbc9af23e353dc0a5ba5c3", size = 1976179, upload-time = "2025-11-04T13:40:23.393Z" }, + { url = "https://files.pythonhosted.org/packages/87/06/8806241ff1f70d9939f9af039c6c35f2360cf16e93c2ca76f184e76b1564/pydantic_core-2.41.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:941103c9be18ac8daf7b7adca8228f8ed6bb7a1849020f643b3a14d15b1924d9", size = 2120403, upload-time = "2025-11-04T13:40:25.248Z" }, + { url = "https://files.pythonhosted.org/packages/94/02/abfa0e0bda67faa65fef1c84971c7e45928e108fe24333c81f3bfe35d5f5/pydantic_core-2.41.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:112e305c3314f40c93998e567879e887a3160bb8689ef3d2c04b6cc62c33ac34", size = 1896206, upload-time = "2025-11-04T13:40:27.099Z" }, + { url = "https://files.pythonhosted.org/packages/15/df/a4c740c0943e93e6500f9eb23f4ca7ec9bf71b19e608ae5b579678c8d02f/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cbaad15cb0c90aa221d43c00e77bb33c93e8d36e0bf74760cd00e732d10a6a0", size = 1919307, upload-time = "2025-11-04T13:40:29.806Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e3/6324802931ae1d123528988e0e86587c2072ac2e5394b4bc2bc34b61ff6e/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:03ca43e12fab6023fc79d28ca6b39b05f794ad08ec2feccc59a339b02f2b3d33", size = 2063258, upload-time = "2025-11-04T13:40:33.544Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d4/2230d7151d4957dd79c3044ea26346c148c98fbf0ee6ebd41056f2d62ab5/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc799088c08fa04e43144b164feb0c13f9a0bc40503f8df3e9fde58a3c0c101e", size = 2214917, upload-time = "2025-11-04T13:40:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/e6/9f/eaac5df17a3672fef0081b6c1bb0b82b33ee89aa5cec0d7b05f52fd4a1fa/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:97aeba56665b4c3235a0e52b2c2f5ae9cd071b8a8310ad27bddb3f7fb30e9aa2", size = 2332186, upload-time = "2025-11-04T13:40:37.436Z" }, + { url = "https://files.pythonhosted.org/packages/cf/4e/35a80cae583a37cf15604b44240e45c05e04e86f9cfd766623149297e971/pydantic_core-2.41.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:406bf18d345822d6c21366031003612b9c77b3e29ffdb0f612367352aab7d586", size = 2073164, upload-time = "2025-11-04T13:40:40.289Z" }, + { url = "https://files.pythonhosted.org/packages/bf/e3/f6e262673c6140dd3305d144d032f7bd5f7497d3871c1428521f19f9efa2/pydantic_core-2.41.5-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b93590ae81f7010dbe380cdeab6f515902ebcbefe0b9327cc4804d74e93ae69d", size = 2179146, upload-time = "2025-11-04T13:40:42.809Z" }, + { url = "https://files.pythonhosted.org/packages/75/c7/20bd7fc05f0c6ea2056a4565c6f36f8968c0924f19b7d97bbfea55780e73/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:01a3d0ab748ee531f4ea6c3e48ad9dac84ddba4b0d82291f87248f2f9de8d740", size = 2137788, upload-time = "2025-11-04T13:40:44.752Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8d/34318ef985c45196e004bc46c6eab2eda437e744c124ef0dbe1ff2c9d06b/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:6561e94ba9dacc9c61bce40e2d6bdc3bfaa0259d3ff36ace3b1e6901936d2e3e", size = 2340133, upload-time = "2025-11-04T13:40:46.66Z" }, + { url = "https://files.pythonhosted.org/packages/9c/59/013626bf8c78a5a5d9350d12e7697d3d4de951a75565496abd40ccd46bee/pydantic_core-2.41.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:915c3d10f81bec3a74fbd4faebe8391013ba61e5a1a8d48c4455b923bdda7858", size = 2324852, upload-time = "2025-11-04T13:40:48.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/d9/c248c103856f807ef70c18a4f986693a46a8ffe1602e5d361485da502d20/pydantic_core-2.41.5-cp313-cp313-win32.whl", hash = "sha256:650ae77860b45cfa6e2cdafc42618ceafab3a2d9a3811fcfbd3bbf8ac3c40d36", size = 1994679, upload-time = "2025-11-04T13:40:50.619Z" }, + { url = "https://files.pythonhosted.org/packages/9e/8b/341991b158ddab181cff136acd2552c9f35bd30380422a639c0671e99a91/pydantic_core-2.41.5-cp313-cp313-win_amd64.whl", hash = "sha256:79ec52ec461e99e13791ec6508c722742ad745571f234ea6255bed38c6480f11", size = 2019766, upload-time = "2025-11-04T13:40:52.631Z" }, + { url = "https://files.pythonhosted.org/packages/73/7d/f2f9db34af103bea3e09735bb40b021788a5e834c81eedb541991badf8f5/pydantic_core-2.41.5-cp313-cp313-win_arm64.whl", hash = "sha256:3f84d5c1b4ab906093bdc1ff10484838aca54ef08de4afa9de0f5f14d69639cd", size = 1981005, upload-time = "2025-11-04T13:40:54.734Z" }, + { url = "https://files.pythonhosted.org/packages/ea/28/46b7c5c9635ae96ea0fbb779e271a38129df2550f763937659ee6c5dbc65/pydantic_core-2.41.5-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:3f37a19d7ebcdd20b96485056ba9e8b304e27d9904d233d7b1015db320e51f0a", size = 2119622, upload-time = "2025-11-04T13:40:56.68Z" }, + { url = "https://files.pythonhosted.org/packages/74/1a/145646e5687e8d9a1e8d09acb278c8535ebe9e972e1f162ed338a622f193/pydantic_core-2.41.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1d1d9764366c73f996edd17abb6d9d7649a7eb690006ab6adbda117717099b14", size = 1891725, upload-time = "2025-11-04T13:40:58.807Z" }, + { url = "https://files.pythonhosted.org/packages/23/04/e89c29e267b8060b40dca97bfc64a19b2a3cf99018167ea1677d96368273/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:25e1c2af0fce638d5f1988b686f3b3ea8cd7de5f244ca147c777769e798a9cd1", size = 1915040, upload-time = "2025-11-04T13:41:00.853Z" }, + { url = "https://files.pythonhosted.org/packages/84/a3/15a82ac7bd97992a82257f777b3583d3e84bdb06ba6858f745daa2ec8a85/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:506d766a8727beef16b7adaeb8ee6217c64fc813646b424d0804d67c16eddb66", size = 2063691, upload-time = "2025-11-04T13:41:03.504Z" }, + { url = "https://files.pythonhosted.org/packages/74/9b/0046701313c6ef08c0c1cf0e028c67c770a4e1275ca73131563c5f2a310a/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4819fa52133c9aa3c387b3328f25c1facc356491e6135b459f1de698ff64d869", size = 2213897, upload-time = "2025-11-04T13:41:05.804Z" }, + { url = "https://files.pythonhosted.org/packages/8a/cd/6bac76ecd1b27e75a95ca3a9a559c643b3afcd2dd62086d4b7a32a18b169/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2b761d210c9ea91feda40d25b4efe82a1707da2ef62901466a42492c028553a2", size = 2333302, upload-time = "2025-11-04T13:41:07.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/d2/ef2074dc020dd6e109611a8be4449b98cd25e1b9b8a303c2f0fca2f2bcf7/pydantic_core-2.41.5-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22f0fb8c1c583a3b6f24df2470833b40207e907b90c928cc8d3594b76f874375", size = 2064877, upload-time = "2025-11-04T13:41:09.827Z" }, + { url = "https://files.pythonhosted.org/packages/18/66/e9db17a9a763d72f03de903883c057b2592c09509ccfe468187f2a2eef29/pydantic_core-2.41.5-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c870e99878c634505236d81e5443092fba820f0373997ff75f90f68cd553", size = 2180680, upload-time = "2025-11-04T13:41:12.379Z" }, + { url = "https://files.pythonhosted.org/packages/d3/9e/3ce66cebb929f3ced22be85d4c2399b8e85b622db77dad36b73c5387f8f8/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:0177272f88ab8312479336e1d777f6b124537d47f2123f89cb37e0accea97f90", size = 2138960, upload-time = "2025-11-04T13:41:14.627Z" }, + { url = "https://files.pythonhosted.org/packages/a6/62/205a998f4327d2079326b01abee48e502ea739d174f0a89295c481a2272e/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:63510af5e38f8955b8ee5687740d6ebf7c2a0886d15a6d65c32814613681bc07", size = 2339102, upload-time = "2025-11-04T13:41:16.868Z" }, + { url = "https://files.pythonhosted.org/packages/3c/0d/f05e79471e889d74d3d88f5bd20d0ed189ad94c2423d81ff8d0000aab4ff/pydantic_core-2.41.5-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e56ba91f47764cc14f1daacd723e3e82d1a89d783f0f5afe9c364b8bb491ccdb", size = 2326039, upload-time = "2025-11-04T13:41:18.934Z" }, + { url = "https://files.pythonhosted.org/packages/ec/e1/e08a6208bb100da7e0c4b288eed624a703f4d129bde2da475721a80cab32/pydantic_core-2.41.5-cp314-cp314-win32.whl", hash = "sha256:aec5cf2fd867b4ff45b9959f8b20ea3993fc93e63c7363fe6851424c8a7e7c23", size = 1995126, upload-time = "2025-11-04T13:41:21.418Z" }, + { url = "https://files.pythonhosted.org/packages/48/5d/56ba7b24e9557f99c9237e29f5c09913c81eeb2f3217e40e922353668092/pydantic_core-2.41.5-cp314-cp314-win_amd64.whl", hash = "sha256:8e7c86f27c585ef37c35e56a96363ab8de4e549a95512445b85c96d3e2f7c1bf", size = 2015489, upload-time = "2025-11-04T13:41:24.076Z" }, + { url = "https://files.pythonhosted.org/packages/4e/bb/f7a190991ec9e3e0ba22e4993d8755bbc4a32925c0b5b42775c03e8148f9/pydantic_core-2.41.5-cp314-cp314-win_arm64.whl", hash = "sha256:e672ba74fbc2dc8eea59fb6d4aed6845e6905fc2a8afe93175d94a83ba2a01a0", size = 1977288, upload-time = "2025-11-04T13:41:26.33Z" }, + { url = "https://files.pythonhosted.org/packages/92/ed/77542d0c51538e32e15afe7899d79efce4b81eee631d99850edc2f5e9349/pydantic_core-2.41.5-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8566def80554c3faa0e65ac30ab0932b9e3a5cd7f8323764303d468e5c37595a", size = 2120255, upload-time = "2025-11-04T13:41:28.569Z" }, + { url = "https://files.pythonhosted.org/packages/bb/3d/6913dde84d5be21e284439676168b28d8bbba5600d838b9dca99de0fad71/pydantic_core-2.41.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:b80aa5095cd3109962a298ce14110ae16b8c1aece8b72f9dafe81cf597ad80b3", size = 1863760, upload-time = "2025-11-04T13:41:31.055Z" }, + { url = "https://files.pythonhosted.org/packages/5a/f0/e5e6b99d4191da102f2b0eb9687aaa7f5bea5d9964071a84effc3e40f997/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3006c3dd9ba34b0c094c544c6006cc79e87d8612999f1a5d43b769b89181f23c", size = 1878092, upload-time = "2025-11-04T13:41:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/71/48/36fb760642d568925953bcc8116455513d6e34c4beaa37544118c36aba6d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:72f6c8b11857a856bcfa48c86f5368439f74453563f951e473514579d44aa612", size = 2053385, upload-time = "2025-11-04T13:41:35.508Z" }, + { url = "https://files.pythonhosted.org/packages/20/25/92dc684dd8eb75a234bc1c764b4210cf2646479d54b47bf46061657292a8/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cb1b2f9742240e4bb26b652a5aeb840aa4b417c7748b6f8387927bc6e45e40d", size = 2218832, upload-time = "2025-11-04T13:41:37.732Z" }, + { url = "https://files.pythonhosted.org/packages/e2/09/f53e0b05023d3e30357d82eb35835d0f6340ca344720a4599cd663dca599/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd3d54f38609ff308209bd43acea66061494157703364ae40c951f83ba99a1a9", size = 2327585, upload-time = "2025-11-04T13:41:40Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4e/2ae1aa85d6af35a39b236b1b1641de73f5a6ac4d5a7509f77b814885760c/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2ff4321e56e879ee8d2a879501c8e469414d948f4aba74a2d4593184eb326660", size = 2041078, upload-time = "2025-11-04T13:41:42.323Z" }, + { url = "https://files.pythonhosted.org/packages/cd/13/2e215f17f0ef326fc72afe94776edb77525142c693767fc347ed6288728d/pydantic_core-2.41.5-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d0d2568a8c11bf8225044aa94409e21da0cb09dcdafe9ecd10250b2baad531a9", size = 2173914, upload-time = "2025-11-04T13:41:45.221Z" }, + { url = "https://files.pythonhosted.org/packages/02/7a/f999a6dcbcd0e5660bc348a3991c8915ce6599f4f2c6ac22f01d7a10816c/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:a39455728aabd58ceabb03c90e12f71fd30fa69615760a075b9fec596456ccc3", size = 2129560, upload-time = "2025-11-04T13:41:47.474Z" }, + { url = "https://files.pythonhosted.org/packages/3a/b1/6c990ac65e3b4c079a4fb9f5b05f5b013afa0f4ed6780a3dd236d2cbdc64/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:239edca560d05757817c13dc17c50766136d21f7cd0fac50295499ae24f90fdf", size = 2329244, upload-time = "2025-11-04T13:41:49.992Z" }, + { url = "https://files.pythonhosted.org/packages/d9/02/3c562f3a51afd4d88fff8dffb1771b30cfdfd79befd9883ee094f5b6c0d8/pydantic_core-2.41.5-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:2a5e06546e19f24c6a96a129142a75cee553cc018ffee48a460059b1185f4470", size = 2331955, upload-time = "2025-11-04T13:41:54.079Z" }, + { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906, upload-time = "2025-11-04T13:41:56.606Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607, upload-time = "2025-11-04T13:41:58.889Z" }, + { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769, upload-time = "2025-11-04T13:42:01.186Z" }, + { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441, upload-time = "2025-11-04T13:42:39.557Z" }, + { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291, upload-time = "2025-11-04T13:42:42.169Z" }, + { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632, upload-time = "2025-11-04T13:42:44.564Z" }, + { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905, upload-time = "2025-11-04T13:42:47.156Z" }, + { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495, upload-time = "2025-11-04T13:42:49.689Z" }, + { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388, upload-time = "2025-11-04T13:42:52.215Z" }, + { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879, upload-time = "2025-11-04T13:42:56.483Z" }, + { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, + { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351, upload-time = "2025-11-04T13:43:02.058Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363, upload-time = "2025-11-04T13:43:05.159Z" }, + { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615, upload-time = "2025-11-04T13:43:08.116Z" }, + { url = "https://files.pythonhosted.org/packages/99/0a/99a53d06dd0348b2008f2f30884b34719c323f16c3be4e6cc1203b74a91d/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:16f80f7abe3351f8ea6858914ddc8c77e02578544a0ebc15b4c2e1a0e813b0b2", size = 2175369, upload-time = "2025-11-04T13:43:12.49Z" }, + { url = "https://files.pythonhosted.org/packages/6d/94/30ca3b73c6d485b9bb0bc66e611cff4a7138ff9736b7e66bcf0852151636/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:33cb885e759a705b426baada1fe68cbb0a2e68e34c5d0d0289a364cf01709093", size = 2144218, upload-time = "2025-11-04T13:43:15.431Z" }, + { url = "https://files.pythonhosted.org/packages/87/57/31b4f8e12680b739a91f472b5671294236b82586889ef764b5fbc6669238/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:c8d8b4eb992936023be7dee581270af5c6e0697a8559895f527f5b7105ecd36a", size = 2329951, upload-time = "2025-11-04T13:43:18.062Z" }, + { url = "https://files.pythonhosted.org/packages/7d/73/3c2c8edef77b8f7310e6fb012dbc4b8551386ed575b9eb6fb2506e28a7eb/pydantic_core-2.41.5-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:242a206cd0318f95cd21bdacff3fcc3aab23e79bba5cac3db5a841c9ef9c6963", size = 2318428, upload-time = "2025-11-04T13:43:20.679Z" }, + { url = "https://files.pythonhosted.org/packages/2f/02/8559b1f26ee0d502c74f9cca5c0d2fd97e967e083e006bbbb4e97f3a043a/pydantic_core-2.41.5-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d3a978c4f57a597908b7e697229d996d77a6d3c94901e9edee593adada95ce1a", size = 2147009, upload-time = "2025-11-04T13:43:23.286Z" }, + { url = "https://files.pythonhosted.org/packages/5f/9b/1b3f0e9f9305839d7e84912f9e8bfbd191ed1b1ef48083609f0dabde978c/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b2379fa7ed44ddecb5bfe4e48577d752db9fc10be00a6b7446e9663ba143de26", size = 2101980, upload-time = "2025-11-04T13:43:25.97Z" }, + { url = "https://files.pythonhosted.org/packages/a4/ed/d71fefcb4263df0da6a85b5d8a7508360f2f2e9b3bf5814be9c8bccdccc1/pydantic_core-2.41.5-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:266fb4cbf5e3cbd0b53669a6d1b039c45e3ce651fd5442eff4d07c2cc8d66808", size = 1923865, upload-time = "2025-11-04T13:43:28.763Z" }, + { url = "https://files.pythonhosted.org/packages/ce/3a/626b38db460d675f873e4444b4bb030453bbe7b4ba55df821d026a0493c4/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58133647260ea01e4d0500089a8c4f07bd7aa6ce109682b1426394988d8aaacc", size = 2134256, upload-time = "2025-11-04T13:43:31.71Z" }, + { url = "https://files.pythonhosted.org/packages/83/d9/8412d7f06f616bbc053d30cb4e5f76786af3221462ad5eee1f202021eb4e/pydantic_core-2.41.5-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:287dad91cfb551c363dc62899a80e9e14da1f0e2b6ebde82c806612ca2a13ef1", size = 2174762, upload-time = "2025-11-04T13:43:34.744Z" }, + { url = "https://files.pythonhosted.org/packages/55/4c/162d906b8e3ba3a99354e20faa1b49a85206c47de97a639510a0e673f5da/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:03b77d184b9eb40240ae9fd676ca364ce1085f203e1b1256f8ab9984dca80a84", size = 2143141, upload-time = "2025-11-04T13:43:37.701Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f2/f11dd73284122713f5f89fc940f370d035fa8e1e078d446b3313955157fe/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:a668ce24de96165bb239160b3d854943128f4334822900534f2fe947930e5770", size = 2330317, upload-time = "2025-11-04T13:43:40.406Z" }, + { url = "https://files.pythonhosted.org/packages/88/9d/b06ca6acfe4abb296110fb1273a4d848a0bfb2ff65f3ee92127b3244e16b/pydantic_core-2.41.5-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:f14f8f046c14563f8eb3f45f499cc658ab8d10072961e07225e507adb700e93f", size = 2316992, upload-time = "2025-11-04T13:43:43.602Z" }, + { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] [[package]] @@ -2152,21 +2181,24 @@ wheels = [ [[package]] name = "pywin32" -version = "310" +version = "311" source = { registry = "https://pypi.org/simple" } wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, + { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, + { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, + { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, + { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, + { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, + { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, + { 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]] @@ -2463,6 +2495,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c8/ed/9de62c2150ca8e2e5858acf3f4f4d0d180a38feef9fdab4078bea63d8dba/rpds_py-0.26.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:e99685fc95d386da368013e7fb4269dd39c30d99f812a8372d62f244f662709c", size = 555334, upload-time = "2025-07-01T15:56:51.703Z" }, ] +[[package]] +name = "ruff" +version = "0.5.7" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817, upload-time = "2024-08-08T15:43:07.467Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571, upload-time = "2024-08-08T15:41:56.537Z" }, + { url = "https://files.pythonhosted.org/packages/a4/10/1be32aeaab8728f78f673e7a47dd813222364479b2d6573dbcf0085e83ea/ruff-0.5.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:00cc8872331055ee017c4f1071a8a31ca0809ccc0657da1d154a1d2abac5c0be", size = 8685138, upload-time = "2024-08-08T15:42:02.833Z" }, + { url = "https://files.pythonhosted.org/packages/3d/1d/c218ce83beb4394ba04d05e9aa2ae6ce9fba8405688fe878b0fdb40ce855/ruff-0.5.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eaf3d86a1fdac1aec8a3417a63587d93f906c678bb9ed0b796da7b59c1114a1e", size = 8266785, upload-time = "2024-08-08T15:42:08.321Z" }, + { url = "https://files.pythonhosted.org/packages/26/79/7f49509bd844476235b40425756def366b227a9714191c91f02fb2178635/ruff-0.5.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a01c34400097b06cf8a6e61b35d6d456d5bd1ae6961542de18ec81eaf33b4cb8", size = 9983964, upload-time = "2024-08-08T15:42:12.419Z" }, + { url = "https://files.pythonhosted.org/packages/bf/b1/939836b70bf9fcd5e5cd3ea67fdb8abb9eac7631351d32f26544034a35e4/ruff-0.5.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fcc8054f1a717e2213500edaddcf1dbb0abad40d98e1bd9d0ad364f75c763eea", size = 9359490, upload-time = "2024-08-08T15:42:16.713Z" }, + { url = "https://files.pythonhosted.org/packages/32/7d/b3db19207de105daad0c8b704b2c6f2a011f9c07017bd58d8d6e7b8eba19/ruff-0.5.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f70284e73f36558ef51602254451e50dd6cc479f8b6f8413a95fcb5db4a55fc", size = 10170833, upload-time = "2024-08-08T15:42:20.54Z" }, + { url = "https://files.pythonhosted.org/packages/a2/45/eae9da55f3357a1ac04220230b8b07800bf516e6dd7e1ad20a2ff3b03b1b/ruff-0.5.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:a78ad870ae3c460394fc95437d43deb5c04b5c29297815a2a1de028903f19692", size = 10896360, upload-time = "2024-08-08T15:42:25.2Z" }, + { url = "https://files.pythonhosted.org/packages/99/67/4388b36d145675f4c51ebec561fcd4298a0e2550c81e629116f83ce45a39/ruff-0.5.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9ccd078c66a8e419475174bfe60a69adb36ce04f8d4e91b006f1329d5cd44bcf", size = 10477094, upload-time = "2024-08-08T15:42:29.553Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9c/f5e6ed1751dc187a4ecf19a4970dd30a521c0ee66b7941c16e292a4043fb/ruff-0.5.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7e31c9bad4ebf8fdb77b59cae75814440731060a09a0e0077d559a556453acbb", size = 11480896, upload-time = "2024-08-08T15:42:33.772Z" }, + { url = "https://files.pythonhosted.org/packages/c8/3b/2b683be597bbd02046678fc3fc1c199c641512b20212073b58f173822bb3/ruff-0.5.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d796327eed8e168164346b769dd9a27a70e0298d667b4ecee6877ce8095ec8e", size = 10179702, upload-time = "2024-08-08T15:42:38.038Z" }, + { url = "https://files.pythonhosted.org/packages/f1/38/c2d94054dc4b3d1ea4c2ba3439b2a7095f08d1c8184bc41e6abe2a688be7/ruff-0.5.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:4a09ea2c3f7778cc635e7f6edf57d566a8ee8f485f3c4454db7771efb692c499", size = 9982855, upload-time = "2024-08-08T15:42:42.031Z" }, + { url = "https://files.pythonhosted.org/packages/7d/e7/1433db2da505ffa8912dcf5b28a8743012ee780cbc20ad0bf114787385d9/ruff-0.5.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a36d8dcf55b3a3bc353270d544fb170d75d2dff41eba5df57b4e0b67a95bb64e", size = 9433156, upload-time = "2024-08-08T15:42:45.339Z" }, + { url = "https://files.pythonhosted.org/packages/e0/36/4fa43250e67741edeea3d366f59a1dc993d4d89ad493a36cbaa9889895f2/ruff-0.5.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:9369c218f789eefbd1b8d82a8cf25017b523ac47d96b2f531eba73770971c9e5", size = 9782971, upload-time = "2024-08-08T15:42:49.354Z" }, + { url = "https://files.pythonhosted.org/packages/80/0e/8c276103d518e5cf9202f70630aaa494abf6fc71c04d87c08b6d3cd07a4b/ruff-0.5.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:b88ca3db7eb377eb24fb7c82840546fb7acef75af4a74bd36e9ceb37a890257e", size = 10247775, upload-time = "2024-08-08T15:42:53.294Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b9/673096d61276f39291b729dddde23c831a5833d98048349835782688a0ec/ruff-0.5.7-py3-none-win32.whl", hash = "sha256:33d61fc0e902198a3e55719f4be6b375b28f860b09c281e4bdbf783c0566576a", size = 7841772, upload-time = "2024-08-08T15:42:57.488Z" }, + { url = "https://files.pythonhosted.org/packages/67/1c/4520c98bfc06b9c73cd1457686d4d3935d40046b1ddea08403e5a6deff51/ruff-0.5.7-py3-none-win_amd64.whl", hash = "sha256:083bbcbe6fadb93cd86709037acc510f86eed5a314203079df174c40bbbca6b3", size = 8699779, upload-time = "2024-08-08T15:43:00.429Z" }, + { url = "https://files.pythonhosted.org/packages/38/23/b3763a237d2523d40a31fe2d1a301191fe392dd48d3014977d079cf8c0bd/ruff-0.5.7-py3-none-win_arm64.whl", hash = "sha256:2dca26154ff9571995107221d0aeaad0e75a77b5a682d6236cf89a58c70b76f4", size = 8091891, upload-time = "2024-08-08T15:43:04.162Z" }, +] + [[package]] name = "s3transfer" version = "0.13.0" @@ -2596,7 +2653,7 @@ wheels = [ [[package]] name = "temporalio" -version = "1.19.0" +version = "1.20.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, @@ -2605,12 +2662,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] +sdist = { url = "https://files.pythonhosted.org/packages/21/db/7d5118d28b0918888e1ec98f56f659fdb006351e06d95f30f4274962a76f/temporalio-1.20.0.tar.gz", hash = "sha256:5a6a85b7d298b7359bffa30025f7deac83c74ac095a4c6952fbf06c249a2a67c", size = 1850498, upload-time = "2025-11-25T21:25:20.225Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/3f/92/0775d831fa245d61b74db2059d5a24a04cef0532ed2c48310a5ab007de9c/temporalio-1.19.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:c2d6d5cad8aec56e048705aa4f0bab83fec15343757ea7acf8504f2e0c289b60", size = 13175255, upload-time = "2025-11-13T22:35:54.22Z" }, - { url = "https://files.pythonhosted.org/packages/e2/e1/2a818fefc0023eb132bfff1a03440bcaff154d4d97445ef88a40c23c20c8/temporalio-1.19.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:d85c89018cba9471ce529d90c9cee5bcc31790fd64176b9ada32cc76440f8d73", size = 12854549, upload-time = "2025-11-13T22:35:57.217Z" }, - { url = "https://files.pythonhosted.org/packages/ff/78/fe5c8c9b112b38e01aba845335df17a8bbfd60a434ffe3c1c4737ced40a0/temporalio-1.19.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f772f0698d60f808bc3c4a055fb53e40d757fa646411845b911863eebbf0549d", size = 13237772, upload-time = "2025-11-13T22:36:00.511Z" }, - { url = "https://files.pythonhosted.org/packages/d9/82/be0fd31119651f518f8db8685fd61976d9d5bbecf3b562d51f13a6442a17/temporalio-1.19.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f706c8f49771daf342ac8daa8ed07f4124fae943177f9feef458a1255aee717c", size = 13374621, upload-time = "2025-11-13T22:36:03.431Z" }, - { url = "https://files.pythonhosted.org/packages/d8/94/18f6ae06ffd91507ded9111af1041146a5ba4b56e9256520c5ce82629fc4/temporalio-1.19.0-cp310-abi3-win_amd64.whl", hash = "sha256:162459c293553be39994f20c635a132f7332ae71bd7ba4042f8473701fcf1c7c", size = 14256891, upload-time = "2025-11-13T22:36:06.778Z" }, + { url = "https://files.pythonhosted.org/packages/f4/1b/e69052aa6003eafe595529485d9c62d1382dd5e671108f1bddf544fb6032/temporalio-1.20.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:fba70314b4068f8b1994bddfa0e2ad742483f0ae714d2ef52e63013ccfd7042e", size = 12061638, upload-time = "2025-11-25T21:24:57.918Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/3e8c67ed7f23bedfa231c6ac29a7a9c12b89881da7694732270f3ecd6b0c/temporalio-1.20.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffc5bb6cabc6ae67f0bfba44de6a9c121603134ae18784a2ff3a7f230ad99080", size = 11562603, upload-time = "2025-11-25T21:25:01.721Z" }, + { url = "https://files.pythonhosted.org/packages/6d/be/ed0cc11702210522a79e09703267ebeca06eb45832b873a58de3ca76b9d0/temporalio-1.20.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1e80c1e4cdf88fa8277177f563edc91466fe4dc13c0322f26e55c76b6a219e6", size = 11824016, upload-time = "2025-11-25T21:25:06.771Z" }, + { url = "https://files.pythonhosted.org/packages/9d/97/09c5cafabc80139d97338a2bdd8ec22e08817dfd2949ab3e5b73565006eb/temporalio-1.20.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba92d909188930860c9d89ca6d7a753bc5a67e4e9eac6cea351477c967355eed", size = 12189521, upload-time = "2025-11-25T21:25:12.091Z" }, + { url = "https://files.pythonhosted.org/packages/11/23/5689c014a76aff3b744b3ee0d80815f63b1362637814f5fbb105244df09b/temporalio-1.20.0-cp310-abi3-win_amd64.whl", hash = "sha256:eacfd571b653e0a0f4aa6593f4d06fc628797898f0900d400e833a1f40cad03a", size = 12745027, upload-time = "2025-11-25T21:25:16.827Z" }, ] [package.optional-dependencies] @@ -2642,15 +2700,14 @@ cloud-export-to-parquet = [ { name = "pyarrow" }, ] dev = [ - { name = "black" }, { name = "frozenlist" }, - { name = "isort" }, { name = "mypy" }, { name = "poethepoet" }, { name = "pyright" }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-pretty" }, + { name = "ruff" }, { name = "types-pyyaml" }, ] dsl = [ @@ -2698,7 +2755,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.19.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.20.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2709,15 +2766,14 @@ cloud-export-to-parquet = [ { name = "pyarrow", specifier = ">=19.0.1" }, ] dev = [ - { name = "black", specifier = ">=22.3.0,<23" }, { name = "frozenlist", specifier = ">=1.4.0,<2" }, - { name = "isort", specifier = ">=5.10.1,<6" }, { name = "mypy", specifier = ">=1.4.1,<2" }, { name = "poethepoet", specifier = ">=0.36.0" }, { name = "pyright", specifier = ">=1.1.394" }, { name = "pytest", specifier = ">=7.1.2,<8" }, { name = "pytest-asyncio", specifier = ">=0.18.3,<0.19" }, { name = "pytest-pretty", specifier = ">=1.3.0" }, + { name = "ruff", specifier = ">=0.5.0,<0.6" }, { name = "types-pyyaml", specifier = ">=6.0.12.20241230,<7" }, ] dsl = [ @@ -2729,7 +2785,7 @@ encryption = [ { name = "aiohttp", specifier = ">=3.8.1,<4" }, { name = "cryptography", specifier = ">=38.0.1,<39" }, ] -gevent = [{ name = "gevent", marker = "python_full_version >= '3.8'", specifier = "==25.4.2" }] +gevent = [{ name = "gevent", marker = "python_full_version >= '3.8'", specifier = ">=25.4.2" }] langchain = [ { name = "fastapi", specifier = ">=0.115.12" }, { name = "langchain", marker = "python_full_version >= '3.9' and python_full_version < '4'", specifier = ">=0.1.7,<0.2" }, @@ -2767,38 +2823,63 @@ wheels = [ [[package]] name = "tiktoken" -version = "0.9.0" +version = "0.12.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/ea/cf/756fedf6981e82897f2d570dd25fa597eb3f4459068ae0572d7e888cfd6f/tiktoken-0.9.0.tar.gz", hash = "sha256:d02a5ca6a938e0490e1ff957bc48c8b078c88cb83977be1625b1fd8aac792c5d", size = 35991, upload-time = "2025-02-14T06:03:01.003Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/64/f3/50ec5709fad61641e4411eb1b9ac55b99801d71f1993c29853f256c726c9/tiktoken-0.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:586c16358138b96ea804c034b8acf3f5d3f0258bd2bc3b0227af4af5d622e382", size = 1065770, upload-time = "2025-02-14T06:02:01.251Z" }, - { url = "https://files.pythonhosted.org/packages/d6/f8/5a9560a422cf1755b6e0a9a436e14090eeb878d8ec0f80e0cd3d45b78bf4/tiktoken-0.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d9c59ccc528c6c5dd51820b3474402f69d9a9e1d656226848ad68a8d5b2e5108", size = 1009314, upload-time = "2025-02-14T06:02:02.869Z" }, - { url = "https://files.pythonhosted.org/packages/bc/20/3ed4cfff8f809cb902900ae686069e029db74567ee10d017cb254df1d598/tiktoken-0.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0968d5beeafbca2a72c595e8385a1a1f8af58feaebb02b227229b69ca5357fd", size = 1143140, upload-time = "2025-02-14T06:02:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/f1/95/cc2c6d79df8f113bdc6c99cdec985a878768120d87d839a34da4bd3ff90a/tiktoken-0.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92a5fb085a6a3b7350b8fc838baf493317ca0e17bd95e8642f95fc69ecfed1de", size = 1197860, upload-time = "2025-02-14T06:02:06.268Z" }, - { url = "https://files.pythonhosted.org/packages/c7/6c/9c1a4cc51573e8867c9381db1814223c09ebb4716779c7f845d48688b9c8/tiktoken-0.9.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15a2752dea63d93b0332fb0ddb05dd909371ededa145fe6a3242f46724fa7990", size = 1259661, upload-time = "2025-02-14T06:02:08.889Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4c/22eb8e9856a2b1808d0a002d171e534eac03f96dbe1161978d7389a59498/tiktoken-0.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:26113fec3bd7a352e4b33dbaf1bd8948de2507e30bd95a44e2b1156647bc01b4", size = 894026, upload-time = "2025-02-14T06:02:12.841Z" }, - { url = "https://files.pythonhosted.org/packages/4d/ae/4613a59a2a48e761c5161237fc850eb470b4bb93696db89da51b79a871f1/tiktoken-0.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:f32cc56168eac4851109e9b5d327637f15fd662aa30dd79f964b7c39fbadd26e", size = 1065987, upload-time = "2025-02-14T06:02:14.174Z" }, - { url = "https://files.pythonhosted.org/packages/3f/86/55d9d1f5b5a7e1164d0f1538a85529b5fcba2b105f92db3622e5d7de6522/tiktoken-0.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:45556bc41241e5294063508caf901bf92ba52d8ef9222023f83d2483a3055348", size = 1009155, upload-time = "2025-02-14T06:02:15.384Z" }, - { url = "https://files.pythonhosted.org/packages/03/58/01fb6240df083b7c1916d1dcb024e2b761213c95d576e9f780dfb5625a76/tiktoken-0.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03935988a91d6d3216e2ec7c645afbb3d870b37bcb67ada1943ec48678e7ee33", size = 1142898, upload-time = "2025-02-14T06:02:16.666Z" }, - { url = "https://files.pythonhosted.org/packages/b1/73/41591c525680cd460a6becf56c9b17468d3711b1df242c53d2c7b2183d16/tiktoken-0.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b3d80aad8d2c6b9238fc1a5524542087c52b860b10cbf952429ffb714bc1136", size = 1197535, upload-time = "2025-02-14T06:02:18.595Z" }, - { url = "https://files.pythonhosted.org/packages/7d/7c/1069f25521c8f01a1a182f362e5c8e0337907fae91b368b7da9c3e39b810/tiktoken-0.9.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b2a21133be05dc116b1d0372af051cd2c6aa1d2188250c9b553f9fa49301b336", size = 1259548, upload-time = "2025-02-14T06:02:20.729Z" }, - { url = "https://files.pythonhosted.org/packages/6f/07/c67ad1724b8e14e2b4c8cca04b15da158733ac60136879131db05dda7c30/tiktoken-0.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:11a20e67fdf58b0e2dea7b8654a288e481bb4fc0289d3ad21291f8d0849915fb", size = 893895, upload-time = "2025-02-14T06:02:22.67Z" }, - { url = "https://files.pythonhosted.org/packages/cf/e5/21ff33ecfa2101c1bb0f9b6df750553bd873b7fb532ce2cb276ff40b197f/tiktoken-0.9.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e88f121c1c22b726649ce67c089b90ddda8b9662545a8aeb03cfef15967ddd03", size = 1065073, upload-time = "2025-02-14T06:02:24.768Z" }, - { url = "https://files.pythonhosted.org/packages/8e/03/a95e7b4863ee9ceec1c55983e4cc9558bcfd8f4f80e19c4f8a99642f697d/tiktoken-0.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a6600660f2f72369acb13a57fb3e212434ed38b045fd8cc6cdd74947b4b5d210", size = 1008075, upload-time = "2025-02-14T06:02:26.92Z" }, - { url = "https://files.pythonhosted.org/packages/40/10/1305bb02a561595088235a513ec73e50b32e74364fef4de519da69bc8010/tiktoken-0.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95e811743b5dfa74f4b227927ed86cbc57cad4df859cb3b643be797914e41794", size = 1140754, upload-time = "2025-02-14T06:02:28.124Z" }, - { url = "https://files.pythonhosted.org/packages/1b/40/da42522018ca496432ffd02793c3a72a739ac04c3794a4914570c9bb2925/tiktoken-0.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99376e1370d59bcf6935c933cb9ba64adc29033b7e73f5f7569f3aad86552b22", size = 1196678, upload-time = "2025-02-14T06:02:29.845Z" }, - { url = "https://files.pythonhosted.org/packages/5c/41/1e59dddaae270ba20187ceb8aa52c75b24ffc09f547233991d5fd822838b/tiktoken-0.9.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:badb947c32739fb6ddde173e14885fb3de4d32ab9d8c591cbd013c22b4c31dd2", size = 1259283, upload-time = "2025-02-14T06:02:33.838Z" }, - { url = "https://files.pythonhosted.org/packages/5b/64/b16003419a1d7728d0d8c0d56a4c24325e7b10a21a9dd1fc0f7115c02f0a/tiktoken-0.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:5a62d7a25225bafed786a524c1b9f0910a1128f4232615bf3f8257a73aaa3b16", size = 894897, upload-time = "2025-02-14T06:02:36.265Z" }, - { url = "https://files.pythonhosted.org/packages/7a/11/09d936d37f49f4f494ffe660af44acd2d99eb2429d60a57c71318af214e0/tiktoken-0.9.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2b0e8e05a26eda1249e824156d537015480af7ae222ccb798e5234ae0285dbdb", size = 1064919, upload-time = "2025-02-14T06:02:37.494Z" }, - { url = "https://files.pythonhosted.org/packages/80/0e/f38ba35713edb8d4197ae602e80837d574244ced7fb1b6070b31c29816e0/tiktoken-0.9.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:27d457f096f87685195eea0165a1807fae87b97b2161fe8c9b1df5bd74ca6f63", size = 1007877, upload-time = "2025-02-14T06:02:39.516Z" }, - { url = "https://files.pythonhosted.org/packages/fe/82/9197f77421e2a01373e27a79dd36efdd99e6b4115746ecc553318ecafbf0/tiktoken-0.9.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cf8ded49cddf825390e36dd1ad35cd49589e8161fdcb52aa25f0583e90a3e01", size = 1140095, upload-time = "2025-02-14T06:02:41.791Z" }, - { url = "https://files.pythonhosted.org/packages/f2/bb/4513da71cac187383541facd0291c4572b03ec23c561de5811781bbd988f/tiktoken-0.9.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cc156cb314119a8bb9748257a2eaebd5cc0753b6cb491d26694ed42fc7cb3139", size = 1195649, upload-time = "2025-02-14T06:02:43Z" }, - { url = "https://files.pythonhosted.org/packages/fa/5c/74e4c137530dd8504e97e3a41729b1103a4ac29036cbfd3250b11fd29451/tiktoken-0.9.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cd69372e8c9dd761f0ab873112aba55a0e3e506332dd9f7522ca466e817b1b7a", size = 1258465, upload-time = "2025-02-14T06:02:45.046Z" }, - { url = "https://files.pythonhosted.org/packages/de/a8/8f499c179ec900783ffe133e9aab10044481679bb9aad78436d239eee716/tiktoken-0.9.0-cp313-cp313-win_amd64.whl", hash = "sha256:5ea0edb6f83dc56d794723286215918c1cde03712cbbafa0348b33448faf5b95", size = 894669, upload-time = "2025-02-14T06:02:47.341Z" }, +sdist = { url = "https://files.pythonhosted.org/packages/7d/ab/4d017d0f76ec3171d469d80fc03dfbb4e48a4bcaddaa831b31d526f05edc/tiktoken-0.12.0.tar.gz", hash = "sha256:b18ba7ee2b093863978fcb14f74b3707cdc8d4d4d3836853ce7ec60772139931", size = 37806, upload-time = "2025-10-06T20:22:45.419Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/89/b3/2cb7c17b6c4cf8ca983204255d3f1d95eda7213e247e6947a0ee2c747a2c/tiktoken-0.12.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3de02f5a491cfd179aec916eddb70331814bd6bf764075d39e21d5862e533970", size = 1051991, upload-time = "2025-10-06T20:21:34.098Z" }, + { url = "https://files.pythonhosted.org/packages/27/0f/df139f1df5f6167194ee5ab24634582ba9a1b62c6b996472b0277ec80f66/tiktoken-0.12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b6cfb6d9b7b54d20af21a912bfe63a2727d9cfa8fbda642fd8322c70340aad16", size = 995798, upload-time = "2025-10-06T20:21:35.579Z" }, + { url = "https://files.pythonhosted.org/packages/ef/5d/26a691f28ab220d5edc09b9b787399b130f24327ef824de15e5d85ef21aa/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:cde24cdb1b8a08368f709124f15b36ab5524aac5fa830cc3fdce9c03d4fb8030", size = 1129865, upload-time = "2025-10-06T20:21:36.675Z" }, + { url = "https://files.pythonhosted.org/packages/b2/94/443fab3d4e5ebecac895712abd3849b8da93b7b7dec61c7db5c9c7ebe40c/tiktoken-0.12.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:6de0da39f605992649b9cfa6f84071e3f9ef2cec458d08c5feb1b6f0ff62e134", size = 1152856, upload-time = "2025-10-06T20:21:37.873Z" }, + { url = "https://files.pythonhosted.org/packages/54/35/388f941251b2521c70dd4c5958e598ea6d2c88e28445d2fb8189eecc1dfc/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6faa0534e0eefbcafaccb75927a4a380463a2eaa7e26000f0173b920e98b720a", size = 1195308, upload-time = "2025-10-06T20:21:39.577Z" }, + { url = "https://files.pythonhosted.org/packages/f8/00/c6681c7f833dd410576183715a530437a9873fa910265817081f65f9105f/tiktoken-0.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:82991e04fc860afb933efb63957affc7ad54f83e2216fe7d319007dab1ba5892", size = 1255697, upload-time = "2025-10-06T20:21:41.154Z" }, + { url = "https://files.pythonhosted.org/packages/5f/d2/82e795a6a9bafa034bf26a58e68fe9a89eeaaa610d51dbeb22106ba04f0a/tiktoken-0.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:6fb2995b487c2e31acf0a9e17647e3b242235a20832642bb7a9d1a181c0c1bb1", size = 879375, upload-time = "2025-10-06T20:21:43.201Z" }, + { url = "https://files.pythonhosted.org/packages/de/46/21ea696b21f1d6d1efec8639c204bdf20fde8bafb351e1355c72c5d7de52/tiktoken-0.12.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6e227c7f96925003487c33b1b32265fad2fbcec2b7cf4817afb76d416f40f6bb", size = 1051565, upload-time = "2025-10-06T20:21:44.566Z" }, + { url = "https://files.pythonhosted.org/packages/c9/d9/35c5d2d9e22bb2a5f74ba48266fb56c63d76ae6f66e02feb628671c0283e/tiktoken-0.12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c06cf0fcc24c2cb2adb5e185c7082a82cba29c17575e828518c2f11a01f445aa", size = 995284, upload-time = "2025-10-06T20:21:45.622Z" }, + { url = "https://files.pythonhosted.org/packages/01/84/961106c37b8e49b9fdcf33fe007bb3a8fdcc380c528b20cc7fbba80578b8/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:f18f249b041851954217e9fd8e5c00b024ab2315ffda5ed77665a05fa91f42dc", size = 1129201, upload-time = "2025-10-06T20:21:47.074Z" }, + { url = "https://files.pythonhosted.org/packages/6a/d0/3d9275198e067f8b65076a68894bb52fd253875f3644f0a321a720277b8a/tiktoken-0.12.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:47a5bc270b8c3db00bb46ece01ef34ad050e364b51d406b6f9730b64ac28eded", size = 1152444, upload-time = "2025-10-06T20:21:48.139Z" }, + { url = "https://files.pythonhosted.org/packages/78/db/a58e09687c1698a7c592e1038e01c206569b86a0377828d51635561f8ebf/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:508fa71810c0efdcd1b898fda574889ee62852989f7c1667414736bcb2b9a4bd", size = 1195080, upload-time = "2025-10-06T20:21:49.246Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/a9e4d2bf91d515c0f74afc526fd773a812232dd6cda33ebea7f531202325/tiktoken-0.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a1af81a6c44f008cba48494089dd98cccb8b313f55e961a52f5b222d1e507967", size = 1255240, upload-time = "2025-10-06T20:21:50.274Z" }, + { url = "https://files.pythonhosted.org/packages/9d/15/963819345f1b1fb0809070a79e9dd96938d4ca41297367d471733e79c76c/tiktoken-0.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:3e68e3e593637b53e56f7237be560f7a394451cb8c11079755e80ae64b9e6def", size = 879422, upload-time = "2025-10-06T20:21:51.734Z" }, + { url = "https://files.pythonhosted.org/packages/a4/85/be65d39d6b647c79800fd9d29241d081d4eeb06271f383bb87200d74cf76/tiktoken-0.12.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b97f74aca0d78a1ff21b8cd9e9925714c15a9236d6ceacf5c7327c117e6e21e8", size = 1050728, upload-time = "2025-10-06T20:21:52.756Z" }, + { url = "https://files.pythonhosted.org/packages/4a/42/6573e9129bc55c9bf7300b3a35bef2c6b9117018acca0dc760ac2d93dffe/tiktoken-0.12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2b90f5ad190a4bb7c3eb30c5fa32e1e182ca1ca79f05e49b448438c3e225a49b", size = 994049, upload-time = "2025-10-06T20:21:53.782Z" }, + { url = "https://files.pythonhosted.org/packages/66/c5/ed88504d2f4a5fd6856990b230b56d85a777feab84e6129af0822f5d0f70/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:65b26c7a780e2139e73acc193e5c63ac754021f160df919add909c1492c0fb37", size = 1129008, upload-time = "2025-10-06T20:21:54.832Z" }, + { url = "https://files.pythonhosted.org/packages/f4/90/3dae6cc5436137ebd38944d396b5849e167896fc2073da643a49f372dc4f/tiktoken-0.12.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:edde1ec917dfd21c1f2f8046b86348b0f54a2c0547f68149d8600859598769ad", size = 1152665, upload-time = "2025-10-06T20:21:56.129Z" }, + { url = "https://files.pythonhosted.org/packages/a3/fe/26df24ce53ffde419a42f5f53d755b995c9318908288c17ec3f3448313a3/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:35a2f8ddd3824608b3d650a000c1ef71f730d0c56486845705a8248da00f9fe5", size = 1194230, upload-time = "2025-10-06T20:21:57.546Z" }, + { url = "https://files.pythonhosted.org/packages/20/cc/b064cae1a0e9fac84b0d2c46b89f4e57051a5f41324e385d10225a984c24/tiktoken-0.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:83d16643edb7fa2c99eff2ab7733508aae1eebb03d5dfc46f5565862810f24e3", size = 1254688, upload-time = "2025-10-06T20:21:58.619Z" }, + { url = "https://files.pythonhosted.org/packages/81/10/b8523105c590c5b8349f2587e2fdfe51a69544bd5a76295fc20f2374f470/tiktoken-0.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffc5288f34a8bc02e1ea7047b8d041104791d2ddbf42d1e5fa07822cbffe16bd", size = 878694, upload-time = "2025-10-06T20:21:59.876Z" }, + { url = "https://files.pythonhosted.org/packages/00/61/441588ee21e6b5cdf59d6870f86beb9789e532ee9718c251b391b70c68d6/tiktoken-0.12.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:775c2c55de2310cc1bc9a3ad8826761cbdc87770e586fd7b6da7d4589e13dab3", size = 1050802, upload-time = "2025-10-06T20:22:00.96Z" }, + { url = "https://files.pythonhosted.org/packages/1f/05/dcf94486d5c5c8d34496abe271ac76c5b785507c8eae71b3708f1ad9b45a/tiktoken-0.12.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a01b12f69052fbe4b080a2cfb867c4de12c704b56178edf1d1d7b273561db160", size = 993995, upload-time = "2025-10-06T20:22:02.788Z" }, + { url = "https://files.pythonhosted.org/packages/a0/70/5163fe5359b943f8db9946b62f19be2305de8c3d78a16f629d4165e2f40e/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:01d99484dc93b129cd0964f9d34eee953f2737301f18b3c7257bf368d7615baa", size = 1128948, upload-time = "2025-10-06T20:22:03.814Z" }, + { url = "https://files.pythonhosted.org/packages/0c/da/c028aa0babf77315e1cef357d4d768800c5f8a6de04d0eac0f377cb619fa/tiktoken-0.12.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:4a1a4fcd021f022bfc81904a911d3df0f6543b9e7627b51411da75ff2fe7a1be", size = 1151986, upload-time = "2025-10-06T20:22:05.173Z" }, + { url = "https://files.pythonhosted.org/packages/a0/5a/886b108b766aa53e295f7216b509be95eb7d60b166049ce2c58416b25f2a/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:981a81e39812d57031efdc9ec59fa32b2a5a5524d20d4776574c4b4bd2e9014a", size = 1194222, upload-time = "2025-10-06T20:22:06.265Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f8/4db272048397636ac7a078d22773dd2795b1becee7bc4922fe6207288d57/tiktoken-0.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9baf52f84a3f42eef3ff4e754a0db79a13a27921b457ca9832cf944c6be4f8f3", size = 1255097, upload-time = "2025-10-06T20:22:07.403Z" }, + { url = "https://files.pythonhosted.org/packages/8e/32/45d02e2e0ea2be3a9ed22afc47d93741247e75018aac967b713b2941f8ea/tiktoken-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b8a0cd0c789a61f31bf44851defbd609e8dd1e2c8589c614cc1060940ef1f697", size = 879117, upload-time = "2025-10-06T20:22:08.418Z" }, + { url = "https://files.pythonhosted.org/packages/ce/76/994fc868f88e016e6d05b0da5ac24582a14c47893f4474c3e9744283f1d5/tiktoken-0.12.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d5f89ea5680066b68bcb797ae85219c72916c922ef0fcdd3480c7d2315ffff16", size = 1050309, upload-time = "2025-10-06T20:22:10.939Z" }, + { url = "https://files.pythonhosted.org/packages/f6/b8/57ef1456504c43a849821920d582a738a461b76a047f352f18c0b26c6516/tiktoken-0.12.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:b4e7ed1c6a7a8a60a3230965bdedba8cc58f68926b835e519341413370e0399a", size = 993712, upload-time = "2025-10-06T20:22:12.115Z" }, + { url = "https://files.pythonhosted.org/packages/72/90/13da56f664286ffbae9dbcfadcc625439142675845baa62715e49b87b68b/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:fc530a28591a2d74bce821d10b418b26a094bf33839e69042a6e86ddb7a7fb27", size = 1128725, upload-time = "2025-10-06T20:22:13.541Z" }, + { url = "https://files.pythonhosted.org/packages/05/df/4f80030d44682235bdaecd7346c90f67ae87ec8f3df4a3442cb53834f7e4/tiktoken-0.12.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:06a9f4f49884139013b138920a4c393aa6556b2f8f536345f11819389c703ebb", size = 1151875, upload-time = "2025-10-06T20:22:14.559Z" }, + { url = "https://files.pythonhosted.org/packages/22/1f/ae535223a8c4ef4c0c1192e3f9b82da660be9eb66b9279e95c99288e9dab/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:04f0e6a985d95913cabc96a741c5ffec525a2c72e9df086ff17ebe35985c800e", size = 1194451, upload-time = "2025-10-06T20:22:15.545Z" }, + { url = "https://files.pythonhosted.org/packages/78/a7/f8ead382fce0243cb625c4f266e66c27f65ae65ee9e77f59ea1653b6d730/tiktoken-0.12.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:0ee8f9ae00c41770b5f9b0bb1235474768884ae157de3beb5439ca0fd70f3e25", size = 1253794, upload-time = "2025-10-06T20:22:16.624Z" }, + { url = "https://files.pythonhosted.org/packages/93/e0/6cc82a562bc6365785a3ff0af27a2a092d57c47d7a81d9e2295d8c36f011/tiktoken-0.12.0-cp313-cp313t-win_amd64.whl", hash = "sha256:dc2dd125a62cb2b3d858484d6c614d136b5b848976794edfb63688d539b8b93f", size = 878777, upload-time = "2025-10-06T20:22:18.036Z" }, + { url = "https://files.pythonhosted.org/packages/72/05/3abc1db5d2c9aadc4d2c76fa5640134e475e58d9fbb82b5c535dc0de9b01/tiktoken-0.12.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:a90388128df3b3abeb2bfd1895b0681412a8d7dc644142519e6f0a97c2111646", size = 1050188, upload-time = "2025-10-06T20:22:19.563Z" }, + { url = "https://files.pythonhosted.org/packages/e3/7b/50c2f060412202d6c95f32b20755c7a6273543b125c0985d6fa9465105af/tiktoken-0.12.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:da900aa0ad52247d8794e307d6446bd3cdea8e192769b56276695d34d2c9aa88", size = 993978, upload-time = "2025-10-06T20:22:20.702Z" }, + { url = "https://files.pythonhosted.org/packages/14/27/bf795595a2b897e271771cd31cb847d479073497344c637966bdf2853da1/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:285ba9d73ea0d6171e7f9407039a290ca77efcdb026be7769dccc01d2c8d7fff", size = 1129271, upload-time = "2025-10-06T20:22:22.06Z" }, + { url = "https://files.pythonhosted.org/packages/f5/de/9341a6d7a8f1b448573bbf3425fa57669ac58258a667eb48a25dfe916d70/tiktoken-0.12.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:d186a5c60c6a0213f04a7a802264083dea1bbde92a2d4c7069e1a56630aef830", size = 1151216, upload-time = "2025-10-06T20:22:23.085Z" }, + { url = "https://files.pythonhosted.org/packages/75/0d/881866647b8d1be4d67cb24e50d0c26f9f807f994aa1510cb9ba2fe5f612/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:604831189bd05480f2b885ecd2d1986dc7686f609de48208ebbbddeea071fc0b", size = 1194860, upload-time = "2025-10-06T20:22:24.602Z" }, + { url = "https://files.pythonhosted.org/packages/b3/1e/b651ec3059474dab649b8d5b69f5c65cd8fcd8918568c1935bd4136c9392/tiktoken-0.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:8f317e8530bb3a222547b85a58583238c8f74fd7a7408305f9f63246d1a0958b", size = 1254567, upload-time = "2025-10-06T20:22:25.671Z" }, + { url = "https://files.pythonhosted.org/packages/80/57/ce64fd16ac390fafde001268c364d559447ba09b509181b2808622420eec/tiktoken-0.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:399c3dd672a6406719d84442299a490420b458c44d3ae65516302a99675888f3", size = 921067, upload-time = "2025-10-06T20:22:26.753Z" }, + { url = "https://files.pythonhosted.org/packages/ac/a4/72eed53e8976a099539cdd5eb36f241987212c29629d0a52c305173e0a68/tiktoken-0.12.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:c2c714c72bc00a38ca969dae79e8266ddec999c7ceccd603cc4f0d04ccd76365", size = 1050473, upload-time = "2025-10-06T20:22:27.775Z" }, + { url = "https://files.pythonhosted.org/packages/e6/d7/0110b8f54c008466b19672c615f2168896b83706a6611ba6e47313dbc6e9/tiktoken-0.12.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:cbb9a3ba275165a2cb0f9a83f5d7025afe6b9d0ab01a22b50f0e74fee2ad253e", size = 993855, upload-time = "2025-10-06T20:22:28.799Z" }, + { url = "https://files.pythonhosted.org/packages/5f/77/4f268c41a3957c418b084dd576ea2fad2e95da0d8e1ab705372892c2ca22/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:dfdfaa5ffff8993a3af94d1125870b1d27aed7cb97aa7eb8c1cefdbc87dbee63", size = 1129022, upload-time = "2025-10-06T20:22:29.981Z" }, + { url = "https://files.pythonhosted.org/packages/4e/2b/fc46c90fe5028bd094cd6ee25a7db321cb91d45dc87531e2bdbb26b4867a/tiktoken-0.12.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:584c3ad3d0c74f5269906eb8a659c8bfc6144a52895d9261cdaf90a0ae5f4de0", size = 1150736, upload-time = "2025-10-06T20:22:30.996Z" }, + { url = "https://files.pythonhosted.org/packages/28/c0/3c7a39ff68022ddfd7d93f3337ad90389a342f761c4d71de99a3ccc57857/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:54c891b416a0e36b8e2045b12b33dd66fb34a4fe7965565f1b482da50da3e86a", size = 1194908, upload-time = "2025-10-06T20:22:32.073Z" }, + { url = "https://files.pythonhosted.org/packages/ab/0d/c1ad6f4016a3968c048545f5d9b8ffebf577774b2ede3e2e352553b685fe/tiktoken-0.12.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5edb8743b88d5be814b1a8a8854494719080c28faaa1ccbef02e87354fe71ef0", size = 1253706, upload-time = "2025-10-06T20:22:33.385Z" }, + { url = "https://files.pythonhosted.org/packages/af/df/c7891ef9d2712ad774777271d39fdef63941ffba0a9d59b7ad1fd2765e57/tiktoken-0.12.0-cp314-cp314t-win_amd64.whl", hash = "sha256:f61c0aea5565ac82e2ec50a05e02a6c44734e91b51c10510b084ea1b8e633a71", size = 920667, upload-time = "2025-10-06T20:22:34.444Z" }, ] [[package]] @@ -2965,14 +3046,14 @@ wheels = [ [[package]] name = "typing-inspection" -version = "0.4.1" +version = "0.4.2" 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" } +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } 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" }, + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, ] [[package]] From 5140187cbe0c908fe7ce03176e83f2c419f93882 Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Tue, 16 Dec 2025 10:05:24 -0800 Subject: [PATCH 29/40] Workflow multiprocessing (#263) * WIP add workflow_multiprocessing sample * Add README content and other minor improvements * remove html table that rendered poorly. switch to print over logger for simplicity * remove syntax highlighting on blocks * Apply some minor improvements to the readme * fix broken link in top level README * remove inaccurate comment in starter.py * remove unused workflow input * run formatter. Ignore linter error on multiprocessing.get_context b/c both ForkContext and SpawnContext are acceptable for what we need * rename to worker_multiprocessing --- README.md | 1 + pyproject.toml | 33 +++--- sleep_for_days/README.md | 2 +- worker_multiprocessing/README.md | 93 +++++++++++++++++ worker_multiprocessing/__init__.py | 2 + worker_multiprocessing/activities.py | 8 ++ worker_multiprocessing/starter.py | 48 +++++++++ worker_multiprocessing/worker.py | 146 +++++++++++++++++++++++++++ worker_multiprocessing/workflows.py | 22 ++++ 9 files changed, 336 insertions(+), 19 deletions(-) create mode 100644 worker_multiprocessing/README.md create mode 100644 worker_multiprocessing/__init__.py create mode 100644 worker_multiprocessing/activities.py create mode 100644 worker_multiprocessing/starter.py create mode 100644 worker_multiprocessing/worker.py create mode 100644 worker_multiprocessing/workflows.py diff --git a/README.md b/README.md index d9ae57a3..5a39e834 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [updatable_timer](updatable_timer) - A timer that can be updated while sleeping. * [worker_specific_task_queues](worker_specific_task_queues) - Use unique task queues to ensure activities run on specific workers. * [worker_versioning](worker_versioning) - Use the Worker Versioning feature to more easily version your workflows & other code. +* [worker_multiprocessing](worker_multiprocessing) - Leverage Python multiprocessing to parallelize workflow tasks and other CPU bound operations by running multiple workers. ## Test diff --git a/pyproject.toml b/pyproject.toml index 2bc7f73a..794bcb92 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,15 +27,8 @@ dev = [ "poethepoet>=0.36.0", ] bedrock = ["boto3>=1.34.92,<2"] -dsl = [ - "pyyaml>=6.0.1,<7", - "types-pyyaml>=6.0.12,<7", - "dacite>=1.8.1,<2", -] -encryption = [ - "cryptography>=38.0.1,<39", - "aiohttp>=3.8.1,<4", -] +dsl = ["pyyaml>=6.0.1,<7", "types-pyyaml>=6.0.12,<7", "dacite>=1.8.1,<2"] +encryption = ["cryptography>=38.0.1,<39", "aiohttp>=3.8.1,<4"] gevent = ["gevent>=25.4.2 ; python_version >= '3.8'"] langchain = [ "langchain>=0.1.7,<0.2 ; python_version >= '3.8.1' and python_version < '4.0'", @@ -46,9 +39,7 @@ langchain = [ "tqdm>=4.62.0,<5", "uvicorn[standard]>=0.24.0.post1,<0.25", ] -nexus = [ - "nexus-rpc>=1.1.0,<2", -] +nexus = ["nexus-rpc>=1.1.0,<2"] open-telemetry = [ "temporalio[opentelemetry]", "opentelemetry-exporter-otlp-proto-grpc", @@ -60,10 +51,7 @@ openai-agents = [ ] pydantic-converter = ["pydantic>=2.10.6,<3"] sentry = ["sentry-sdk>=2.13.0"] -trio-async = [ - "trio>=0.28.0,<0.29", - "trio-asyncio>=0.15.0,<0.16", -] +trio-async = ["trio>=0.28.0,<0.29", "trio-asyncio>=0.15.0,<0.16"] cloud-export-to-parquet = [ "pandas>=2.2.2,<3 ; python_version >= '3.10' and python_version < '4.0'", "numpy>=1.26.0,<2 ; python_version >= '3.10' and python_version < '3.13'", @@ -71,6 +59,8 @@ cloud-export-to-parquet = [ "pyarrow>=19.0.1", ] +[tool.hatch.metadata] +allow-direct-references = true [tool.hatch.build.targets.sdist] include = ["./**/*.py"] @@ -118,8 +108,15 @@ requires = ["hatchling"] build-backend = "hatchling.build" [tool.poe.tasks] -format = [{cmd = "uv run ruff check --select I --fix"}, {cmd = "uv run ruff format"}] -lint = [{cmd = "uv run ruff check --select I"}, {cmd = "uv run ruff format --check"}, {ref = "lint-types"}] +format = [ + { cmd = "uv run ruff check --select I --fix" }, + { cmd = "uv run ruff format" }, +] +lint = [ + { cmd = "uv run ruff check --select I" }, + { cmd = "uv run ruff format --check" }, + { ref = "lint-types" }, +] lint-types = "uv run --all-groups mypy --check-untyped-defs --namespace-packages ." test = "uv run --all-groups pytest" diff --git a/sleep_for_days/README.md b/sleep_for_days/README.md index 69302cc7..5117fcdb 100644 --- a/sleep_for_days/README.md +++ b/sleep_for_days/README.md @@ -2,7 +2,7 @@ This sample demonstrates how to create a Temporal workflow that runs forever, sending an email every 30 days. -To run, first see the main [README.md](../../README.md) for prerequisites. +To run, first see the main [README.md](../README.md) for prerequisites. Then create two terminals. diff --git a/worker_multiprocessing/README.md b/worker_multiprocessing/README.md new file mode 100644 index 00000000..a4f06f86 --- /dev/null +++ b/worker_multiprocessing/README.md @@ -0,0 +1,93 @@ +# Worker Multiprocessing Sample + + +## Python Concurrency Limitations + +CPU-bound tasks effectively cannot run in parallel in Python due to the [Global Interpreter Lock (GIL)](https://docs.python.org/3/glossary.html#term-global-interpreter-lock). The Python standard library's [`threading` module](https://docs.python.org/3/library/threading.html) provides the following guidance: + +> CPython implementation detail: In CPython, due to the Global Interpreter Lock, only one thread can execute Python code at once (even though certain performance-oriented libraries might overcome this limitation). If you want your application to make better use of the computational resources of multi-core machines, you are advised to use multiprocessing or concurrent.futures.ProcessPoolExecutor. However, threading is still an appropriate model if you want to run multiple I/O-bound tasks simultaneously. + +## Temporal Workflow Tasks in Python + +[Temporal Workflow Tasks](https://docs.temporal.io/tasks#workflow-task) are CPU-bound operations and therefore cannot be run concurrently using threads or an async runtime. Instead, we can use [`concurrent.futures.ProcessPoolExecutor`](https://docs.python.org/3/library/concurrent.futures.html#concurrent.futures.ProcessPoolExecutor) or the [`multiprocessing` module](https://docs.python.org/3/library/multiprocessing.html), as suggested by the `threading` documentation, to more appropriately utilize machine resources. + +This sample demonstrates how to use `concurrent.futures.ProcessPoolExecutor` to run multiple workflow worker processes. + +## Running the Sample + +To run, first see the root [README.md](../README.md) for prerequisites. Then execute the following commands from the root directory: + +``` +uv run worker_multiprocessing/worker.py +uv run worker_multiprocessing/starter.py +``` + +Both `worker.py` and `starter.py` have minimal arguments that can be adjusted to modify how the sample runs. + +``` +uv run worker_multiprocessing/worker.py -h + +usage: worker.py [-h] [-w NUM_WORKFLOW_WORKERS] [-a NUM_ACTIVITY_WORKERS] + +options: + -h, --help show this help message and exit + -w, --num-workflow-workers NUM_WORKFLOW_WORKERS + -a, --num-activity-workers NUM_ACTIVITY_WORKERS +``` + +``` +uv run worker_multiprocessing/starter.py -h + +usage: starter.py [-h] [-n NUM_WORKFLOWS] + +options: + -h, --help show this help message and exit + -n, --num-workflows NUM_WORKFLOWS + the number of workflows to execute +``` + +## Example Output + +``` +uv run worker_multiprocessing/worker.py + +starting 2 workflow worker(s) and 1 activity worker(s) +waiting for keyboard interrupt or for all workers to exit +workflow-worker:0 starting +workflow-worker:1 starting +activity-worker:0 starting +workflow-worker:0 shutting down +activity-worker:0 shutting down +workflow-worker:1 shutting down +``` + + +``` +uv run worker_multiprocessing/starter.py + +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19179 | activity-pid:19180 | wf-ending-pid:19179 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +wf-starting-pid:19178 | activity-pid:19180 | wf-ending-pid:19178 +``` diff --git a/worker_multiprocessing/__init__.py b/worker_multiprocessing/__init__.py new file mode 100644 index 00000000..d9e30b8a --- /dev/null +++ b/worker_multiprocessing/__init__.py @@ -0,0 +1,2 @@ +WORKFLOW_TASK_QUEUE = "workflow-task-queue" +ACTIVITY_TASK_QUEUE = "activity-task-queue" diff --git a/worker_multiprocessing/activities.py b/worker_multiprocessing/activities.py new file mode 100644 index 00000000..dbbbc677 --- /dev/null +++ b/worker_multiprocessing/activities.py @@ -0,0 +1,8 @@ +import os + +from temporalio import activity + + +@activity.defn +async def echo_pid_activity(input: str) -> str: + return f"{input} | activity-pid:{os.getpid()}" diff --git a/worker_multiprocessing/starter.py b/worker_multiprocessing/starter.py new file mode 100644 index 00000000..3267694d --- /dev/null +++ b/worker_multiprocessing/starter.py @@ -0,0 +1,48 @@ +import argparse +import asyncio +import uuid + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +from worker_multiprocessing import WORKFLOW_TASK_QUEUE +from worker_multiprocessing.workflows import ParallelizedWorkflow + + +class Args(argparse.Namespace): + num_workflows: int + + +async def main(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-n", + "--num-workflows", + help="the number of workflows to execute", + type=int, + default=25, + ) + args = parser.parse_args(namespace=Args()) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + + # Start several workflows + wf_handles = [ + client.execute_workflow( + ParallelizedWorkflow.run, + id=f"greeting-workflow-id-{uuid.uuid4()}", + task_queue=WORKFLOW_TASK_QUEUE, + ) + for _ in range(args.num_workflows) + ] + + # Wait for workflow completion + for wf in asyncio.as_completed(wf_handles): + result = await wf + print(result) + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/worker_multiprocessing/worker.py b/worker_multiprocessing/worker.py new file mode 100644 index 00000000..bda69ba6 --- /dev/null +++ b/worker_multiprocessing/worker.py @@ -0,0 +1,146 @@ +import argparse +import asyncio +import concurrent.futures +import dataclasses +import multiprocessing +import traceback +from typing import Literal + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.runtime import Runtime, TelemetryConfig +from temporalio.worker import PollerBehaviorSimpleMaximum, Worker +from temporalio.worker.workflow_sandbox import ( + SandboxedWorkflowRunner, + SandboxRestrictions, +) + +from worker_multiprocessing import ACTIVITY_TASK_QUEUE, WORKFLOW_TASK_QUEUE +from worker_multiprocessing.activities import echo_pid_activity +from worker_multiprocessing.workflows import ParallelizedWorkflow + +# Immediately prevent the default Runtime from being created to ensure +# each process creates it's own +Runtime.prevent_default() + + +class Args(argparse.Namespace): + num_workflow_workers: int + num_activity_workers: int + + @property + def total_workers(self) -> int: + return self.num_activity_workers + self.num_workflow_workers + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("-w", "--num-workflow-workers", type=int, default=2) + parser.add_argument("-a", "--num-activity-workers", type=int, default=1) + args = parser.parse_args(namespace=Args()) + print( + f"starting {args.num_workflow_workers} workflow worker(s) and {args.num_activity_workers} activity worker(s)" + ) + + # This sample prefers fork to avoid re-importing modules + # and decrease startup time. Fork is not available on all + # operating systems, so we fallback to 'spawn' when not available + try: + mp_ctx = multiprocessing.get_context("fork") + except ValueError: + mp_ctx = multiprocessing.get_context("spawn") # type: ignore + + with concurrent.futures.ProcessPoolExecutor( + args.total_workers, mp_context=mp_ctx + ) as executor: + # Start workflow workers by submitting them to the + # ProcessPoolExecutor + worker_futures = [ + executor.submit(worker_entry, "workflow", i) + for i in range(args.num_workflow_workers) + ] + + # In this sample, we start activity workers as separate processes in the + # same way we do workflow workers. In production, activity workers + # are often deployed separately from workflow workers to account for + # differing scaling characteristics. + worker_futures.extend( + [ + executor.submit(worker_entry, "activity", i) + for i in range(args.num_activity_workers) + ] + ) + + try: + print("waiting for keyboard interrupt or for all workers to exit") + for worker in concurrent.futures.as_completed(worker_futures): + print("ERROR: worker exited unexpectedly") + if worker.exception(): + traceback.print_exception(worker.exception()) + except KeyboardInterrupt: + pass + + +def worker_entry(worker_type: Literal["workflow", "activity"], id: int): + Runtime.set_default(Runtime(telemetry=TelemetryConfig())) + + async def run_worker(): + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**config) + + if worker_type == "workflow": + worker = workflow_worker(client) + else: + worker = activity_worker(client) + + try: + print(f"{worker_type}-worker:{id} starting") + await asyncio.shield(worker.run()) + except asyncio.CancelledError: + print(f"{worker_type}-worker:{id} shutting down") + await worker.shutdown() + + asyncio.run(run_worker()) + + +def workflow_worker(client: Client) -> Worker: + """ + Create a workflow worker that is configured to leverage being run + as many child processes. + """ + return Worker( + client, + task_queue=WORKFLOW_TASK_QUEUE, + workflows=[ParallelizedWorkflow], + # Workflow tasks are CPU bound, but generally execute quickly. + # Because we're leveraging multiprocessing to achieve parallelism, + # we want each workflow worker to be confirgured for small workflow + # task processing. + max_concurrent_workflow_tasks=2, + workflow_task_poller_behavior=PollerBehaviorSimpleMaximum(2), + # Allow workflows to access the os module to access the pid + workflow_runner=SandboxedWorkflowRunner( + restrictions=dataclasses.replace( + SandboxRestrictions.default, + invalid_module_members=SandboxRestrictions.invalid_module_members_default.with_child_unrestricted( + "os" + ), + ) + ), + ) + + +def activity_worker(client: Client) -> Worker: + """ + Create a basic activity worker + """ + return Worker( + client, + task_queue=ACTIVITY_TASK_QUEUE, + activities=[echo_pid_activity], + ) + + +if __name__ == "__main__": + main() diff --git a/worker_multiprocessing/workflows.py b/worker_multiprocessing/workflows.py new file mode 100644 index 00000000..04f6b635 --- /dev/null +++ b/worker_multiprocessing/workflows.py @@ -0,0 +1,22 @@ +import os +from datetime import timedelta + +from temporalio import workflow + +from worker_multiprocessing import ACTIVITY_TASK_QUEUE +from worker_multiprocessing.activities import echo_pid_activity + + +@workflow.defn +class ParallelizedWorkflow: + @workflow.run + async def run(self) -> str: + pid = os.getpid() + activity_result = await workflow.execute_activity( + echo_pid_activity, + f"wf-starting-pid:{pid}", + task_queue=ACTIVITY_TASK_QUEUE, + start_to_close_timeout=timedelta(seconds=10), + ) + + return f"{activity_result} | wf-ending-pid:{pid}" From cff0a7056539b40e57768337064df3d0d0a920c4 Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Thu, 18 Dec 2025 13:49:09 -0800 Subject: [PATCH 30/40] Bump temporal SDK to 1.21.0 (#269) --- pyproject.toml | 2 +- uv.lock | 296 ++++++++++++++++++++++++------------------------- 2 files changed, 149 insertions(+), 149 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 794bcb92..00813456 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.20.0,<2"] +dependencies = ["temporalio>=1.21.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" diff --git a/uv.lock b/uv.lock index cbe5db3f..09a2436a 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -176,7 +176,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -190,7 +190,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -199,7 +199,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pycparser" }, ] @@ -256,7 +256,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -317,7 +317,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -329,7 +329,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -338,7 +338,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi" }, ] @@ -361,7 +361,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -370,7 +370,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -383,7 +383,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -392,7 +392,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -404,7 +404,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -418,7 +418,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -427,7 +427,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -521,7 +521,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -530,7 +530,7 @@ wheels = [ [[package]] name = "gevent" version = "25.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -582,7 +582,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -594,7 +594,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -645,7 +645,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama" }, ] @@ -657,7 +657,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.76.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -718,7 +718,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -727,7 +727,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -742,7 +742,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -755,7 +755,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -791,7 +791,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -806,7 +806,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -815,7 +815,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -834,7 +834,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -843,7 +843,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "zipp" }, ] @@ -855,7 +855,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -864,7 +864,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markupsafe" }, ] @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -948,7 +948,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -957,7 +957,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpointer" }, ] @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -978,7 +978,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -993,7 +993,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "referencing" }, ] @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1029,7 +1029,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1049,7 +1049,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1066,7 +1066,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1081,7 +1081,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, ] @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1109,7 +1109,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1131,7 +1131,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mdurl" }, ] @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1201,7 +1201,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "packaging" }, ] @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1235,7 +1235,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1244,7 +1244,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1346,7 +1346,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1385,7 +1385,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1393,20 +1393,20 @@ wheels = [ [[package]] name = "nexus-rpc" -version = "1.2.0" -source = { registry = "https://pypi.org/simple" } +version = "1.3.0" +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/06/50/95d7bc91f900da5e22662c82d9bf0f72a4b01f2a552708bf2f43807707a1/nexus_rpc-1.2.0.tar.gz", hash = "sha256:b4ddaffa4d3996aaeadf49b80dfcdfbca48fe4cb616defaf3b3c5c2c8fc61890", size = 74142, upload-time = "2025-11-17T19:17:06.798Z" } +sdist = { url = "https://files.pythonhosted.org/packages/2e/f2/d54f5c03d8f4672ccc0875787a385f53dcb61f98a8ae594b5620e85b9cb3/nexus_rpc-1.3.0.tar.gz", hash = "sha256:e56d3b57b60d707ce7a72f83f23f106b86eca1043aa658e44582ab5ff30ab9ad", size = 75650, upload-time = "2025-12-08T22:59:13.002Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/13/04/eaac430d0e6bf21265ae989427d37e94be5e41dc216879f1fbb6c5339942/nexus_rpc-1.2.0-py3-none-any.whl", hash = "sha256:977876f3af811ad1a09b2961d3d1ac9233bda43ff0febbb0c9906483b9d9f8a3", size = 28166, upload-time = "2025-11-17T19:17:05.64Z" }, + { url = "https://files.pythonhosted.org/packages/d6/74/0afd841de3199c148146c1d43b4bfb5605b2f1dc4c9a9087fe395091ea5a/nexus_rpc-1.3.0-py3-none-any.whl", hash = "sha256:aee0707b4861b22d8124ecb3f27d62dafbe8777dc50c66c91e49c006f971b92d", size = 28873, upload-time = "2025-12-08T22:59:12.024Z" }, ] [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1415,7 +1415,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1447,7 +1447,7 @@ wheels = [ [[package]] name = "openai" version = "1.108.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1466,7 +1466,7 @@ wheels = [ [[package]] name = "openai-agents" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1489,7 +1489,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1502,7 +1502,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1532,7 +1532,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1558,7 +1558,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1571,7 +1571,7 @@ wheels = [ [[package]] name = "orjson" version = "3.11.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, @@ -1652,7 +1652,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, ] @@ -1664,7 +1664,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1673,7 +1673,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1721,7 +1721,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1730,7 +1730,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1739,7 +1739,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1748,7 +1748,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1762,7 +1762,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1851,7 +1851,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1865,7 +1865,7 @@ wheels = [ [[package]] name = "pyarrow" version = "22.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, @@ -1922,7 +1922,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1931,7 +1931,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.12.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1946,7 +1946,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.41.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2064,7 +2064,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2078,7 +2078,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2087,7 +2087,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2100,7 +2100,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2117,7 +2117,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, ] @@ -2130,7 +2130,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2143,7 +2143,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "six" }, ] @@ -2155,7 +2155,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2164,7 +2164,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2173,7 +2173,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2182,7 +2182,7 @@ wheels = [ [[package]] name = "pywin32" version = "311" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, @@ -2204,7 +2204,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2248,7 +2248,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2262,7 +2262,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2331,7 +2331,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2346,7 +2346,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "requests" }, ] @@ -2358,7 +2358,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2372,7 +2372,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2498,7 +2498,7 @@ wheels = [ [[package]] name = "ruff" version = "0.5.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817, upload-time = "2024-08-08T15:43:07.467Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571, upload-time = "2024-08-08T15:41:56.537Z" }, @@ -2523,7 +2523,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, ] @@ -2535,7 +2535,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2548,7 +2548,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2557,7 +2557,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2566,7 +2566,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2575,7 +2575,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2629,7 +2629,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -2641,7 +2641,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2653,8 +2653,8 @@ wheels = [ [[package]] name = "temporalio" -version = "1.20.0" -source = { registry = "https://pypi.org/simple" } +version = "1.21.0" +source = { registry = "https://test.pypi.org/simple/" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2662,13 +2662,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/21/db/7d5118d28b0918888e1ec98f56f659fdb006351e06d95f30f4274962a76f/temporalio-1.20.0.tar.gz", hash = "sha256:5a6a85b7d298b7359bffa30025f7deac83c74ac095a4c6952fbf06c249a2a67c", size = 1850498, upload-time = "2025-11-25T21:25:20.225Z" } +sdist = { url = "https://test-files.pythonhosted.org/packages/61/b7/62d06b55f5ef628112e3c62423aa571d7fe3b6d625e7b495c94782eaaf98/temporalio-1.21.0.tar.gz", hash = "sha256:0c36891a29ebbdc437dd273df1784f37912ec7bbf9b4aeb0ec387940e34065a3", size = 1854373, upload-time = "2025-12-18T21:22:38.073Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f4/1b/e69052aa6003eafe595529485d9c62d1382dd5e671108f1bddf544fb6032/temporalio-1.20.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:fba70314b4068f8b1994bddfa0e2ad742483f0ae714d2ef52e63013ccfd7042e", size = 12061638, upload-time = "2025-11-25T21:24:57.918Z" }, - { url = "https://files.pythonhosted.org/packages/ae/3b/3e8c67ed7f23bedfa231c6ac29a7a9c12b89881da7694732270f3ecd6b0c/temporalio-1.20.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:ffc5bb6cabc6ae67f0bfba44de6a9c121603134ae18784a2ff3a7f230ad99080", size = 11562603, upload-time = "2025-11-25T21:25:01.721Z" }, - { url = "https://files.pythonhosted.org/packages/6d/be/ed0cc11702210522a79e09703267ebeca06eb45832b873a58de3ca76b9d0/temporalio-1.20.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1e80c1e4cdf88fa8277177f563edc91466fe4dc13c0322f26e55c76b6a219e6", size = 11824016, upload-time = "2025-11-25T21:25:06.771Z" }, - { url = "https://files.pythonhosted.org/packages/9d/97/09c5cafabc80139d97338a2bdd8ec22e08817dfd2949ab3e5b73565006eb/temporalio-1.20.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba92d909188930860c9d89ca6d7a753bc5a67e4e9eac6cea351477c967355eed", size = 12189521, upload-time = "2025-11-25T21:25:12.091Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/5689c014a76aff3b744b3ee0d80815f63b1362637814f5fbb105244df09b/temporalio-1.20.0-cp310-abi3-win_amd64.whl", hash = "sha256:eacfd571b653e0a0f4aa6593f4d06fc628797898f0900d400e833a1f40cad03a", size = 12745027, upload-time = "2025-11-25T21:25:16.827Z" }, + { url = "https://test-files.pythonhosted.org/packages/68/c4/fd713d238d0e1ee4168345217c4290ea245bcd657717088ddce2907313ec/temporalio-1.21.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:787e31f1cecd9adb76643bc43782876963ca601c793f032d17e7015b518cc5ed", size = 12032507, upload-time = "2025-12-18T21:22:23.882Z" }, + { url = "https://test-files.pythonhosted.org/packages/24/58/68f3ca32d7eb2484981ef9f275ed050667cf08ef4261fba69cae8b3d5727/temporalio-1.21.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:32d1d6e91d0c545122052086fe03cc4f87f27c685585d43c9f7e9a4ee6f7d41c", size = 11558973, upload-time = "2025-12-18T21:22:26.74Z" }, + { url = "https://test-files.pythonhosted.org/packages/93/c6/c3dcf0bef4c7993e96297ac48fc2436aa313cdd1cbac61defb2475f0e19f/temporalio-1.21.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464e3ad200cfc9ffcf40aa0ac30faf40d67205ab4bf81625e973ec796102991f", size = 11810058, upload-time = "2025-12-18T21:22:29.477Z" }, + { url = "https://test-files.pythonhosted.org/packages/96/89/0437b47e6901c2c6b0d03feb4d738afdab1a0d333b9ec934c0fed2c6cf37/temporalio-1.21.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3478fbce8d5a9c39178057dad115fdfed817afd5e6cea26919ac47afed05b88", size = 12144682, upload-time = "2025-12-18T21:22:32.08Z" }, + { url = "https://test-files.pythonhosted.org/packages/95/6d/a87ddf1ed31a0df752748defe96d992ce85b11b80f5a56acb8d4509be209/temporalio-1.21.0-cp310-abi3-win_amd64.whl", hash = "sha256:f053d3b7991588b46c28bc90ca25b0d74b4aaf5e27927320c03962f72738553b", size = 12692318, upload-time = "2025-12-18T21:22:35.092Z" }, ] [package.optional-dependencies] @@ -2755,7 +2755,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.20.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.21.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2815,7 +2815,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2824,7 +2824,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.12.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2885,7 +2885,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2910,7 +2910,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2949,7 +2949,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2961,7 +2961,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2979,7 +2979,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2995,7 +2995,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -3004,7 +3004,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -3013,7 +3013,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "urllib3" }, ] @@ -3025,7 +3025,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3034,7 +3034,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -3047,7 +3047,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -3059,7 +3059,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3068,7 +3068,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -3077,7 +3077,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3102,7 +3102,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3134,7 +3134,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -3234,7 +3234,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3293,7 +3293,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3392,7 +3392,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3401,7 +3401,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] @@ -3413,7 +3413,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] From 230fdf8951a0178e8eedd781637856c526380878 Mon Sep 17 00:00:00 2001 From: Alex Mazzeo Date: Fri, 19 Dec 2025 14:37:49 -0800 Subject: [PATCH 31/40] Update to Python SDK 1.21.1 (#271) --- pyproject.toml | 2 +- uv.lock | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 00813456..bf97ef04 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.21.0,<2"] +dependencies = ["temporalio>=1.21.1,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" diff --git a/uv.lock b/uv.lock index 09a2436a..81feead4 100644 --- a/uv.lock +++ b/uv.lock @@ -2653,7 +2653,7 @@ wheels = [ [[package]] name = "temporalio" -version = "1.21.0" +version = "1.21.1" source = { registry = "https://test.pypi.org/simple/" } dependencies = [ { name = "nexus-rpc" }, @@ -2662,13 +2662,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://test-files.pythonhosted.org/packages/61/b7/62d06b55f5ef628112e3c62423aa571d7fe3b6d625e7b495c94782eaaf98/temporalio-1.21.0.tar.gz", hash = "sha256:0c36891a29ebbdc437dd273df1784f37912ec7bbf9b4aeb0ec387940e34065a3", size = 1854373, upload-time = "2025-12-18T21:22:38.073Z" } +sdist = { url = "https://test-files.pythonhosted.org/packages/1b/9c/b4faa1f5ebb7cc7c264456012cbad083ea3f350abe6ea0921584ab46a51e/temporalio-1.21.1.tar.gz", hash = "sha256:9d4fbfd5d8cf1afdbf9e9c34f68158073904cee227eb602602ed86c39e992bd8", size = 1854258, upload-time = "2025-12-19T21:59:36.582Z" } wheels = [ - { url = "https://test-files.pythonhosted.org/packages/68/c4/fd713d238d0e1ee4168345217c4290ea245bcd657717088ddce2907313ec/temporalio-1.21.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:787e31f1cecd9adb76643bc43782876963ca601c793f032d17e7015b518cc5ed", size = 12032507, upload-time = "2025-12-18T21:22:23.882Z" }, - { url = "https://test-files.pythonhosted.org/packages/24/58/68f3ca32d7eb2484981ef9f275ed050667cf08ef4261fba69cae8b3d5727/temporalio-1.21.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:32d1d6e91d0c545122052086fe03cc4f87f27c685585d43c9f7e9a4ee6f7d41c", size = 11558973, upload-time = "2025-12-18T21:22:26.74Z" }, - { url = "https://test-files.pythonhosted.org/packages/93/c6/c3dcf0bef4c7993e96297ac48fc2436aa313cdd1cbac61defb2475f0e19f/temporalio-1.21.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:464e3ad200cfc9ffcf40aa0ac30faf40d67205ab4bf81625e973ec796102991f", size = 11810058, upload-time = "2025-12-18T21:22:29.477Z" }, - { url = "https://test-files.pythonhosted.org/packages/96/89/0437b47e6901c2c6b0d03feb4d738afdab1a0d333b9ec934c0fed2c6cf37/temporalio-1.21.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3478fbce8d5a9c39178057dad115fdfed817afd5e6cea26919ac47afed05b88", size = 12144682, upload-time = "2025-12-18T21:22:32.08Z" }, - { url = "https://test-files.pythonhosted.org/packages/95/6d/a87ddf1ed31a0df752748defe96d992ce85b11b80f5a56acb8d4509be209/temporalio-1.21.0-cp310-abi3-win_amd64.whl", hash = "sha256:f053d3b7991588b46c28bc90ca25b0d74b4aaf5e27927320c03962f72738553b", size = 12692318, upload-time = "2025-12-18T21:22:35.092Z" }, + { url = "https://test-files.pythonhosted.org/packages/db/87/61b9e53cb5f71ca4474e30c8454be9c3622da7f72109b6d4de9b47490d4c/temporalio-1.21.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:476c575a8eb16ee0ebc388de42c8582465c5b2e01e6c662b23585b96afdda29e", size = 12034086, upload-time = "2025-12-19T21:59:23.255Z" }, + { url = "https://test-files.pythonhosted.org/packages/9d/ac/d7354048cc02de74cb11edf8d339c1579ffd9080c47782d0c1bf4d78df66/temporalio-1.21.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:1ba3980d6dff925aeff09d7de0bf82336a2c0159096801e9e755e0f01524a9a7", size = 11553488, upload-time = "2025-12-19T21:59:26.216Z" }, + { url = "https://test-files.pythonhosted.org/packages/52/c2/7cabddc869ccd12cb9b9abdb94277eb401bcaa23185383d8861482b15ac2/temporalio-1.21.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38dd23396e7a8acad1419873d189e2ae49ae4357b1c2a005f19e94aaaf702f90", size = 11809946, upload-time = "2025-12-19T21:59:28.604Z" }, + { url = "https://test-files.pythonhosted.org/packages/ca/72/4f0b647c6b4b9467dbcd4d7aa69a714bdd63731c7cb6798daade8ad8786d/temporalio-1.21.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f62aabb4df8855e40a1f66bd2b9d9226ebb4e2641377dceaf4eab4aaf708a6", size = 12144443, upload-time = "2025-12-19T21:59:31.443Z" }, + { url = "https://test-files.pythonhosted.org/packages/b5/b2/cf5402ab0b962d3f017190dcadebbbffa43f94b9513014aa39e790fc0a1e/temporalio-1.21.1-cp310-abi3-win_amd64.whl", hash = "sha256:a9bebb9f55f287b44fc88e9446e3abf1f91c7e6bff1842b40b04260ce6d9ce24", size = 12692499, upload-time = "2025-12-19T21:59:34.196Z" }, ] [package.optional-dependencies] @@ -2755,7 +2755,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.21.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.21.1,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] From cad16b7dee160aff48a76897551f87564dae289b Mon Sep 17 00:00:00 2001 From: Thomas Hardy Date: Tue, 17 Feb 2026 17:26:20 -0500 Subject: [PATCH 32/40] use v1.22.0 (#277) --- pyproject.toml | 2 +- uv.lock | 290 ++++++++++++++++++++++++------------------------- 2 files changed, 146 insertions(+), 146 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index bf97ef04..c7d9e3b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.21.1,<2"] +dependencies = ["temporalio>=1.22.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" diff --git a/uv.lock b/uv.lock index 81feead4..7080542e 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -176,7 +176,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -190,7 +190,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -199,7 +199,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pycparser" }, ] @@ -256,7 +256,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -317,7 +317,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -329,7 +329,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -338,7 +338,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi" }, ] @@ -361,7 +361,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -370,7 +370,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -383,7 +383,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -392,7 +392,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -404,7 +404,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -418,7 +418,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -427,7 +427,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple/" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -521,7 +521,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -530,7 +530,7 @@ wheels = [ [[package]] name = "gevent" version = "25.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -582,7 +582,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -594,7 +594,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -645,7 +645,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama" }, ] @@ -657,7 +657,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.76.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -718,7 +718,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -727,7 +727,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -742,7 +742,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -755,7 +755,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -791,7 +791,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -806,7 +806,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -815,7 +815,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -834,7 +834,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -843,7 +843,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "zipp" }, ] @@ -855,7 +855,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -864,7 +864,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markupsafe" }, ] @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple/" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -948,7 +948,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -957,7 +957,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpointer" }, ] @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -978,7 +978,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -993,7 +993,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "referencing" }, ] @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1029,7 +1029,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1049,7 +1049,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1066,7 +1066,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1081,7 +1081,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "langchain-core" }, ] @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1109,7 +1109,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1131,7 +1131,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mdurl" }, ] @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple/" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1201,7 +1201,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "packaging" }, ] @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1235,7 +1235,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1244,7 +1244,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1346,7 +1346,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1385,7 +1385,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1394,7 +1394,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1415,7 +1415,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1447,7 +1447,7 @@ wheels = [ [[package]] name = "openai" version = "1.108.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1466,7 +1466,7 @@ wheels = [ [[package]] name = "openai-agents" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1489,7 +1489,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1502,7 +1502,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1532,7 +1532,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "protobuf" }, ] @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1558,7 +1558,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1571,7 +1571,7 @@ wheels = [ [[package]] name = "orjson" version = "3.11.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, @@ -1652,7 +1652,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, ] @@ -1664,7 +1664,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1673,7 +1673,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1721,7 +1721,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1730,7 +1730,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1739,7 +1739,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1748,7 +1748,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1762,7 +1762,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple/" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1851,7 +1851,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1865,7 +1865,7 @@ wheels = [ [[package]] name = "pyarrow" version = "22.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, @@ -1922,7 +1922,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -1931,7 +1931,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.12.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1946,7 +1946,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.41.5" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -2064,7 +2064,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2078,7 +2078,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2087,7 +2087,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2100,7 +2100,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2117,7 +2117,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, ] @@ -2130,7 +2130,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2143,7 +2143,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "six" }, ] @@ -2155,7 +2155,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2164,7 +2164,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2173,7 +2173,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2182,7 +2182,7 @@ wheels = [ [[package]] name = "pywin32" version = "311" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, @@ -2204,7 +2204,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple/" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2248,7 +2248,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2262,7 +2262,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2331,7 +2331,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2346,7 +2346,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "requests" }, ] @@ -2358,7 +2358,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2372,7 +2372,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2498,7 +2498,7 @@ wheels = [ [[package]] name = "ruff" version = "0.5.7" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817, upload-time = "2024-08-08T15:43:07.467Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571, upload-time = "2024-08-08T15:41:56.537Z" }, @@ -2523,7 +2523,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "botocore" }, ] @@ -2535,7 +2535,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2548,7 +2548,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2557,7 +2557,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2566,7 +2566,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -2575,7 +2575,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2629,7 +2629,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -2641,7 +2641,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2653,8 +2653,8 @@ wheels = [ [[package]] name = "temporalio" -version = "1.21.1" -source = { registry = "https://test.pypi.org/simple/" } +version = "1.22.0" +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2662,13 +2662,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://test-files.pythonhosted.org/packages/1b/9c/b4faa1f5ebb7cc7c264456012cbad083ea3f350abe6ea0921584ab46a51e/temporalio-1.21.1.tar.gz", hash = "sha256:9d4fbfd5d8cf1afdbf9e9c34f68158073904cee227eb602602ed86c39e992bd8", size = 1854258, upload-time = "2025-12-19T21:59:36.582Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b5/28/2a79a1e98e4280924f08ea0989ee045aa0b65f17f8d4f2ae7b53c2f4c38d/temporalio-1.22.0.tar.gz", hash = "sha256:896452fad246de2277cbb0408e4e0899882da1843480d5cbb57c7a5767440834", size = 1906162, upload-time = "2026-02-03T20:58:37.042Z" } wheels = [ - { url = "https://test-files.pythonhosted.org/packages/db/87/61b9e53cb5f71ca4474e30c8454be9c3622da7f72109b6d4de9b47490d4c/temporalio-1.21.1-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:476c575a8eb16ee0ebc388de42c8582465c5b2e01e6c662b23585b96afdda29e", size = 12034086, upload-time = "2025-12-19T21:59:23.255Z" }, - { url = "https://test-files.pythonhosted.org/packages/9d/ac/d7354048cc02de74cb11edf8d339c1579ffd9080c47782d0c1bf4d78df66/temporalio-1.21.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:1ba3980d6dff925aeff09d7de0bf82336a2c0159096801e9e755e0f01524a9a7", size = 11553488, upload-time = "2025-12-19T21:59:26.216Z" }, - { url = "https://test-files.pythonhosted.org/packages/52/c2/7cabddc869ccd12cb9b9abdb94277eb401bcaa23185383d8861482b15ac2/temporalio-1.21.1-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38dd23396e7a8acad1419873d189e2ae49ae4357b1c2a005f19e94aaaf702f90", size = 11809946, upload-time = "2025-12-19T21:59:28.604Z" }, - { url = "https://test-files.pythonhosted.org/packages/ca/72/4f0b647c6b4b9467dbcd4d7aa69a714bdd63731c7cb6798daade8ad8786d/temporalio-1.21.1-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b3f62aabb4df8855e40a1f66bd2b9d9226ebb4e2641377dceaf4eab4aaf708a6", size = 12144443, upload-time = "2025-12-19T21:59:31.443Z" }, - { url = "https://test-files.pythonhosted.org/packages/b5/b2/cf5402ab0b962d3f017190dcadebbbffa43f94b9513014aa39e790fc0a1e/temporalio-1.21.1-cp310-abi3-win_amd64.whl", hash = "sha256:a9bebb9f55f287b44fc88e9446e3abf1f91c7e6bff1842b40b04260ce6d9ce24", size = 12692499, upload-time = "2025-12-19T21:59:34.196Z" }, + { url = "https://files.pythonhosted.org/packages/da/00/4dd57b3be03cc22523fd7083a3f63700188d7856ada875c99e71ca9a72bd/temporalio-1.22.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:532ef90cdee487a76c46eb71348f94f0a8a432e9dd241a0552b384314bbe28c0", size = 12198015, upload-time = "2026-02-03T20:57:04.056Z" }, + { url = "https://files.pythonhosted.org/packages/a7/15/1c24ea8005f1abc58dbb35b26ea93e5067afc385e56dda0e50c64c75cc07/temporalio-1.22.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a5f8646c1a0c36d5d4472462f2d315bafa7e2c9b1f52f15a07d01d1ccc33778", size = 11697647, upload-time = "2026-02-03T20:57:26.252Z" }, + { url = "https://files.pythonhosted.org/packages/09/2e/b65ec41f73030a109c253ac30545e4aac19044cd30083231b9b5993914e8/temporalio-1.22.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8cf7c909f7d6bc236a45aa09fc347cb53b02fa3287df29409d0500fc21c0dc5", size = 11972722, upload-time = "2026-02-03T20:57:47.371Z" }, + { url = "https://files.pythonhosted.org/packages/b4/de/048bf901417940f62bd69243d95762a63e97a5ad138c514c76852d364cd6/temporalio-1.22.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac4adf1ac20f594066b8091de22f463a31f0926c23be1e990519fd6dbbb9d1b", size = 12275101, upload-time = "2026-02-03T20:58:09.636Z" }, + { url = "https://files.pythonhosted.org/packages/14/8e/f5852ef5326990ae5a15cb5f764254df1d086463ddc8244766d13872c3d3/temporalio-1.22.0-cp310-abi3-win_amd64.whl", hash = "sha256:4453ba03681e4ed39bf410f76997b7e0b9ec239d0dff7cabd53eb89c7fbaa6b0", size = 12713408, upload-time = "2026-02-03T20:58:32.086Z" }, ] [package.optional-dependencies] @@ -2755,7 +2755,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.21.1,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.22.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2815,7 +2815,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2824,7 +2824,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.12.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2885,7 +2885,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2910,7 +2910,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2949,7 +2949,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2961,7 +2961,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2979,7 +2979,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2995,7 +2995,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -3004,7 +3004,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -3013,7 +3013,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "urllib3" }, ] @@ -3025,7 +3025,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -3034,7 +3034,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -3047,7 +3047,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "typing-extensions" }, ] @@ -3059,7 +3059,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -3068,7 +3068,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -3077,7 +3077,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3102,7 +3102,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3134,7 +3134,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "anyio" }, ] @@ -3234,7 +3234,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3293,7 +3293,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3392,7 +3392,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple/" } +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" }, @@ -3401,7 +3401,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] @@ -3413,7 +3413,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple/" } +source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "setuptools" }, ] From 827d5656a156bab39dd770dbcbf587a7bf2252d1 Mon Sep 17 00:00:00 2001 From: tconley1428 Date: Wed, 18 Feb 2026 10:55:49 -0800 Subject: [PATCH 33/40] Update sdk version to 1.23.0 (#278) * Update sdk version to 1.23.0 * Fix changes from workflow info being optional --- custom_metric/worker.py | 2 +- polling/test_service.py | 2 +- pyproject.toml | 2 +- tests/resource_pool/workflow_test.py | 2 +- uv.lock | 290 +++++++++++++-------------- 5 files changed, 149 insertions(+), 149 deletions(-) diff --git a/custom_metric/worker.py b/custom_metric/worker.py index 38793985..21dd9c93 100644 --- a/custom_metric/worker.py +++ b/custom_metric/worker.py @@ -39,7 +39,7 @@ async def execute_activity(self, input: ExecuteActivityInput): unit="duration", ) histogram.record( - schedule_to_start, {"workflow_type": activity.info().workflow_type} + schedule_to_start, {"workflow_type": activity.info().workflow_type or ""} ) return await self.next.execute_activity(input) diff --git a/polling/test_service.py b/polling/test_service.py index 63494572..994b98ce 100644 --- a/polling/test_service.py +++ b/polling/test_service.py @@ -4,7 +4,7 @@ from temporalio import activity from temporalio.exceptions import ApplicationError, ApplicationErrorCategory -attempts = Counter[str]() +attempts = Counter[str | None]() ERROR_ATTEMPTS = 5 diff --git a/pyproject.toml b/pyproject.toml index c7d9e3b0..caae123c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,7 +6,7 @@ authors = [{ name = "Temporal Technologies Inc", email = "sdk@temporal.io" }] requires-python = ">=3.10" readme = "README.md" license = "MIT" -dependencies = ["temporalio>=1.22.0,<2"] +dependencies = ["temporalio>=1.23.0,<2"] [project.urls] Homepage = "https://github.com/temporalio/samples-python" diff --git a/tests/resource_pool/workflow_test.py b/tests/resource_pool/workflow_test.py index b5ae95e3..0d2eb654 100644 --- a/tests/resource_pool/workflow_test.py +++ b/tests/resource_pool/workflow_test.py @@ -28,7 +28,7 @@ async def test_resource_pool_workflow(client: Client): # Mock out the activity to count executions @activity.defn(name="use_resource") async def use_resource_mock(input: UseResourceActivityInput) -> None: - workflow_id = activity.info().workflow_id + workflow_id = activity.info().workflow_id or "" resource_usage[input.resource].append((workflow_id, "start")) # We need a small sleep here to bait out races await asyncio.sleep(0.05) diff --git a/uv.lock b/uv.lock index 7080542e..dd39daa7 100644 --- a/uv.lock +++ b/uv.lock @@ -12,7 +12,7 @@ resolution-markers = [ [[package]] name = "aiohappyeyeballs" version = "2.6.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -21,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" version = "3.12.14" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohappyeyeballs" }, { name = "aiosignal" }, @@ -107,7 +107,7 @@ wheels = [ [[package]] name = "aiosignal" version = "1.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "frozenlist" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -120,7 +120,7 @@ wheels = [ [[package]] name = "annotated-types" version = "0.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -129,7 +129,7 @@ wheels = [ [[package]] name = "anyio" version = "4.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "idna" }, @@ -144,7 +144,7 @@ wheels = [ [[package]] name = "async-timeout" version = "4.0.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/87/d6/21b30a550dafea84b1b8eee21b5e23fa16d010ae006011221f33dcd8d7f8/async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f", size = 8345, upload-time = "2023-08-10T16:35:56.907Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721, upload-time = "2023-08-10T16:35:55.203Z" }, @@ -153,7 +153,7 @@ wheels = [ [[package]] name = "attrs" version = "25.3.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -162,7 +162,7 @@ wheels = [ [[package]] name = "boto3" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, { name = "jmespath" }, @@ -176,7 +176,7 @@ wheels = [ [[package]] name = "botocore" version = "1.39.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, @@ -190,7 +190,7 @@ wheels = [ [[package]] name = "certifi" version = "2025.7.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/de/8a/c729b6b60c66a38f590c4e774decc4b2ec7b0576be8f1aa984a53ffa812a/certifi-2025.7.9.tar.gz", hash = "sha256:c1d2ec05395148ee10cf672ffc28cd37ea0ab0d99f9cc74c43e588cbd111b079", size = 160386, upload-time = "2025-07-09T02:13:58.874Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/66/f3/80a3f974c8b535d394ff960a11ac20368e06b736da395b551a49ce950cce/certifi-2025.7.9-py3-none-any.whl", hash = "sha256:d842783a14f8fdd646895ac26f719a061408834473cfc10203f6a575beb15d39", size = 159230, upload-time = "2025-07-09T02:13:57.007Z" }, @@ -199,7 +199,7 @@ wheels = [ [[package]] name = "cffi" version = "1.17.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pycparser" }, ] @@ -256,7 +256,7 @@ wheels = [ [[package]] name = "charset-normalizer" version = "3.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, @@ -317,7 +317,7 @@ wheels = [ [[package]] name = "click" version = "8.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -329,7 +329,7 @@ wheels = [ [[package]] name = "colorama" version = "0.4.6" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -338,7 +338,7 @@ wheels = [ [[package]] name = "cryptography" version = "38.0.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi" }, ] @@ -361,7 +361,7 @@ wheels = [ [[package]] name = "dacite" version = "1.9.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/55/a0/7ca79796e799a3e782045d29bf052b5cde7439a2bbb17f15ff44f7aacc63/dacite-1.9.2.tar.gz", hash = "sha256:6ccc3b299727c7aa17582f0021f6ae14d5de47c7227932c47fec4cdfefd26f09", size = 22420, upload-time = "2025-02-05T09:27:29.757Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/94/35/386550fd60316d1e37eccdda609b074113298f23cef5bddb2049823fe666/dacite-1.9.2-py3-none-any.whl", hash = "sha256:053f7c3f5128ca2e9aceb66892b1a3c8936d02c686e707bee96e19deef4bc4a0", size = 16600, upload-time = "2025-02-05T09:27:24.345Z" }, @@ -370,7 +370,7 @@ wheels = [ [[package]] name = "dataclasses-json" version = "0.6.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "marshmallow" }, { name = "typing-inspect" }, @@ -383,7 +383,7 @@ wheels = [ [[package]] name = "distro" version = "1.9.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -392,7 +392,7 @@ wheels = [ [[package]] name = "exceptiongroup" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -404,7 +404,7 @@ wheels = [ [[package]] name = "fastapi" version = "0.116.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "starlette" }, @@ -418,7 +418,7 @@ wheels = [ [[package]] name = "filelock" version = "3.18.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/0a/10/c23352565a6544bdc5353e0b15fc1c563352101f30e24bf500207a54df9a/filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2", size = 18075, upload-time = "2025-03-14T07:11:40.47Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/4d/36/2a115987e2d8c300a974597416d9de88f2444426de9571f4b59b2cca3acc/filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de", size = 16215, upload-time = "2025-03-14T07:11:39.145Z" }, @@ -427,7 +427,7 @@ wheels = [ [[package]] name = "frozenlist" version = "1.7.0" -source = { registry = "https://pypi.org/simple" } +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/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, @@ -521,7 +521,7 @@ wheels = [ [[package]] name = "fsspec" version = "2025.7.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -530,7 +530,7 @@ wheels = [ [[package]] name = "gevent" version = "25.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "cffi", marker = "platform_python_implementation == 'CPython' and sys_platform == 'win32'" }, { name = "greenlet", marker = "platform_python_implementation == 'CPython'" }, @@ -582,7 +582,7 @@ wheels = [ [[package]] name = "googleapis-common-protos" version = "1.70.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -594,7 +594,7 @@ wheels = [ [[package]] name = "greenlet" version = "3.2.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c9/92/bb85bd6e80148a4d2e0c59f7c0c2891029f8fd510183afc7d8d2feeed9b6/greenlet-3.2.3.tar.gz", hash = "sha256:8b0dd8ae4c0d6f5e54ee55ba935eeb3d735a9b58a8a1e5b5cbab64e01a39f365", size = 185752, upload-time = "2025-06-05T16:16:09.955Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/92/db/b4c12cff13ebac2786f4f217f06588bccd8b53d260453404ef22b121fc3a/greenlet-3.2.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:1afd685acd5597349ee6d7a88a8bec83ce13c106ac78c196ee9dde7c04fe87be", size = 268977, upload-time = "2025-06-05T16:10:24.001Z" }, @@ -645,7 +645,7 @@ wheels = [ [[package]] name = "griffe" version = "1.7.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama" }, ] @@ -657,7 +657,7 @@ wheels = [ [[package]] name = "grpcio" version = "1.76.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -718,7 +718,7 @@ wheels = [ [[package]] name = "h11" version = "0.16.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -727,7 +727,7 @@ wheels = [ [[package]] name = "hf-xet" version = "1.1.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/ed/d4/7685999e85945ed0d7f0762b686ae7015035390de1161dcea9d5276c134c/hf_xet-1.1.5.tar.gz", hash = "sha256:69ebbcfd9ec44fdc2af73441619eeb06b94ee34511bbcf57cd423820090f5694", size = 495969, upload-time = "2025-06-20T21:48:38.007Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/00/89/a1119eebe2836cb25758e7661d6410d3eae982e2b5e974bcc4d250be9012/hf_xet-1.1.5-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:f52c2fa3635b8c37c7764d8796dfa72706cc4eded19d638331161e82b0792e23", size = 2687929, upload-time = "2025-06-20T21:48:32.284Z" }, @@ -742,7 +742,7 @@ wheels = [ [[package]] name = "httpcore" version = "1.0.9" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "h11" }, @@ -755,7 +755,7 @@ wheels = [ [[package]] name = "httptools" version = "0.6.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, @@ -791,7 +791,7 @@ wheels = [ [[package]] name = "httpx" version = "0.28.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "certifi" }, @@ -806,7 +806,7 @@ wheels = [ [[package]] name = "httpx-sse" version = "0.4.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -815,7 +815,7 @@ wheels = [ [[package]] name = "huggingface-hub" version = "0.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "filelock" }, { name = "fsspec" }, @@ -834,7 +834,7 @@ wheels = [ [[package]] name = "idna" version = "3.10" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -843,7 +843,7 @@ wheels = [ [[package]] name = "importlib-metadata" version = "8.7.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "zipp" }, ] @@ -855,7 +855,7 @@ wheels = [ [[package]] name = "iniconfig" version = "2.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -864,7 +864,7 @@ wheels = [ [[package]] name = "jinja2" version = "3.1.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markupsafe" }, ] @@ -876,7 +876,7 @@ wheels = [ [[package]] name = "jiter" version = "0.10.0" -source = { registry = "https://pypi.org/simple" } +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/be/7e/4011b5c77bec97cb2b572f566220364e3e21b51c48c5bd9c4a9c26b41b67/jiter-0.10.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:cd2fb72b02478f06a900a5782de2ef47e0396b3e1f7d5aba30daeb1fce66f303", size = 317215, upload-time = "2025-05-18T19:03:04.303Z" }, @@ -948,7 +948,7 @@ wheels = [ [[package]] name = "jmespath" version = "1.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/00/2a/e867e8531cf3e36b41201936b7fa7ba7b5702dbef42922193f05c8976cd6/jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe", size = 25843, upload-time = "2022-06-17T18:00:12.224Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/31/b4/b9b800c45527aadd64d5b442f9b932b00648617eb5d63d2c7a6587b7cafc/jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980", size = 20256, upload-time = "2022-06-17T18:00:10.251Z" }, @@ -957,7 +957,7 @@ wheels = [ [[package]] name = "jsonpatch" version = "1.33" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpointer" }, ] @@ -969,7 +969,7 @@ wheels = [ [[package]] name = "jsonpointer" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/6a/0a/eebeb1fa92507ea94016a2a790b93c2ae41a7e18778f85471dc54475ed25/jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef", size = 9114, upload-time = "2024-06-10T19:24:42.462Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/71/92/5e77f98553e9e75130c78900d000368476aed74276eb8ae8796f65f00918/jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942", size = 7595, upload-time = "2024-06-10T19:24:40.698Z" }, @@ -978,7 +978,7 @@ wheels = [ [[package]] name = "jsonschema" version = "4.24.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "jsonschema-specifications" }, @@ -993,7 +993,7 @@ wheels = [ [[package]] name = "jsonschema-specifications" version = "2025.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "referencing" }, ] @@ -1005,7 +1005,7 @@ wheels = [ [[package]] name = "langchain" version = "0.1.20" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "async-timeout", marker = "python_full_version < '3.11'" }, @@ -1029,7 +1029,7 @@ wheels = [ [[package]] name = "langchain-community" version = "0.0.38" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "dataclasses-json" }, @@ -1049,7 +1049,7 @@ wheels = [ [[package]] name = "langchain-core" version = "0.1.53" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "jsonpatch" }, { name = "langsmith" }, @@ -1066,7 +1066,7 @@ wheels = [ [[package]] name = "langchain-openai" version = "0.0.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, { name = "numpy" }, @@ -1081,7 +1081,7 @@ wheels = [ [[package]] name = "langchain-text-splitters" version = "0.0.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "langchain-core" }, ] @@ -1093,7 +1093,7 @@ wheels = [ [[package]] name = "langsmith" version = "0.1.147" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "httpx" }, { name = "orjson", marker = "platform_python_implementation != 'PyPy'" }, @@ -1109,7 +1109,7 @@ wheels = [ [[package]] name = "litellm" version = "1.74.8" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "aiohttp" }, { name = "click" }, @@ -1131,7 +1131,7 @@ wheels = [ [[package]] name = "markdown-it-py" version = "3.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mdurl" }, ] @@ -1143,7 +1143,7 @@ wheels = [ [[package]] name = "markupsafe" version = "3.0.2" -source = { registry = "https://pypi.org/simple" } +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/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, @@ -1201,7 +1201,7 @@ wheels = [ [[package]] name = "marshmallow" version = "3.26.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "packaging" }, ] @@ -1213,7 +1213,7 @@ wheels = [ [[package]] name = "mcp" version = "1.11.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "httpx" }, @@ -1235,7 +1235,7 @@ wheels = [ [[package]] name = "mdurl" version = "0.1.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1244,7 +1244,7 @@ wheels = [ [[package]] name = "multidict" version = "6.6.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] @@ -1346,7 +1346,7 @@ wheels = [ [[package]] name = "mypy" version = "1.16.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "pathspec" }, @@ -1385,7 +1385,7 @@ wheels = [ [[package]] name = "mypy-extensions" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1394,7 +1394,7 @@ wheels = [ [[package]] name = "nexus-rpc" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -1406,7 +1406,7 @@ wheels = [ [[package]] name = "nodeenv" version = "1.9.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/43/16/fc88b08840de0e0a72a2f9d8c6bae36be573e475a6326ae854bcc549fc45/nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f", size = 47437, upload-time = "2024-06-04T18:44:11.171Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/1d/1b658dbd2b9fa9c4c9f32accbfc0205d532c8c6194dc0f2a4c0428e7128a/nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9", size = 22314, upload-time = "2024-06-04T18:44:08.352Z" }, @@ -1415,7 +1415,7 @@ wheels = [ [[package]] name = "numpy" version = "1.26.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/94/ace0fdea5241a27d13543ee117cbc65868e82213fb31a8eb7fe9ff23f313/numpy-1.26.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9ff0f4f29c51e2803569d7a51c2304de5554655a60c5d776e35b4a41413830d0", size = 20631468, upload-time = "2024-02-05T23:48:01.194Z" }, @@ -1447,7 +1447,7 @@ wheels = [ [[package]] name = "openai" version = "1.108.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "distro" }, @@ -1466,7 +1466,7 @@ wheels = [ [[package]] name = "openai-agents" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "griffe" }, { name = "mcp" }, @@ -1489,7 +1489,7 @@ litellm = [ [[package]] name = "opentelemetry-api" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "importlib-metadata" }, { name = "typing-extensions" }, @@ -1502,7 +1502,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-common" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-proto" }, ] @@ -1514,7 +1514,7 @@ wheels = [ [[package]] name = "opentelemetry-exporter-otlp-proto-grpc" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "googleapis-common-protos" }, { name = "grpcio" }, @@ -1532,7 +1532,7 @@ wheels = [ [[package]] name = "opentelemetry-proto" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "protobuf" }, ] @@ -1544,7 +1544,7 @@ wheels = [ [[package]] name = "opentelemetry-sdk" version = "1.35.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "opentelemetry-semantic-conventions" }, @@ -1558,7 +1558,7 @@ wheels = [ [[package]] name = "opentelemetry-semantic-conventions" version = "0.56b0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "opentelemetry-api" }, { name = "typing-extensions" }, @@ -1571,7 +1571,7 @@ wheels = [ [[package]] name = "orjson" version = "3.11.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/c6/fe/ed708782d6709cc60eb4c2d8a361a440661f74134675c72990f2c48c785f/orjson-3.11.4.tar.gz", hash = "sha256:39485f4ab4c9b30a3943cfe99e1a213c4776fb69e8abd68f66b83d5a0b0fdc6d", size = 5945188, upload-time = "2025-10-24T15:50:38.027Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/e0/30/5aed63d5af1c8b02fbd2a8d83e2a6c8455e30504c50dbf08c8b51403d873/orjson-3.11.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:e3aa2118a3ece0d25489cbe48498de8a5d580e42e8d9979f65bf47900a15aba1", size = 243870, upload-time = "2025-10-24T15:48:28.908Z" }, @@ -1652,7 +1652,7 @@ wheels = [ [[package]] name = "outcome" version = "1.3.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, ] @@ -1664,7 +1664,7 @@ wheels = [ [[package]] name = "packaging" version = "23.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/fb/2b/9b9c33ffed44ee921d0967086d653047286054117d584f1b1a7c22ceaf7b/packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5", size = 146714, upload-time = "2023-10-01T13:50:05.279Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7", size = 53011, upload-time = "2023-10-01T13:50:03.745Z" }, @@ -1673,7 +1673,7 @@ wheels = [ [[package]] name = "pandas" version = "2.3.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, @@ -1721,7 +1721,7 @@ wheels = [ [[package]] name = "pastel" version = "0.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/76/f1/4594f5e0fcddb6953e5b8fe00da8c317b8b41b547e2b3ae2da7512943c62/pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d", size = 7555, upload-time = "2020-09-16T19:21:12.43Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/aa/18/a8444036c6dd65ba3624c63b734d3ba95ba63ace513078e1580590075d21/pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364", size = 5955, upload-time = "2020-09-16T19:21:11.409Z" }, @@ -1730,7 +1730,7 @@ wheels = [ [[package]] name = "pathspec" version = "0.12.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1739,7 +1739,7 @@ wheels = [ [[package]] name = "pluggy" version = "1.6.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1748,7 +1748,7 @@ wheels = [ [[package]] name = "poethepoet" version = "0.36.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pastel" }, { name = "pyyaml" }, @@ -1762,7 +1762,7 @@ wheels = [ [[package]] name = "propcache" version = "0.3.2" -source = { registry = "https://pypi.org/simple" } +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/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, @@ -1851,7 +1851,7 @@ wheels = [ [[package]] name = "protobuf" version = "5.29.5" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1865,7 +1865,7 @@ wheels = [ [[package]] name = "pyarrow" version = "22.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/30/53/04a7fdc63e6056116c9ddc8b43bc28c12cdd181b85cbeadb79278475f3ae/pyarrow-22.0.0.tar.gz", hash = "sha256:3d600dc583260d845c7d8a6db540339dd883081925da2bd1c5cb808f720b3cd9", size = 1151151, upload-time = "2025-10-24T12:30:00.762Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d9/9b/cb3f7e0a345353def531ca879053e9ef6b9f38ed91aebcf68b09ba54dec0/pyarrow-22.0.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:77718810bd3066158db1e95a63c160ad7ce08c6b0710bc656055033e39cdad88", size = 34223968, upload-time = "2025-10-24T10:03:31.21Z" }, @@ -1922,7 +1922,7 @@ wheels = [ [[package]] name = "pycparser" version = "2.22" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -1931,7 +1931,7 @@ wheels = [ [[package]] name = "pydantic" version = "2.12.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "annotated-types" }, { name = "pydantic-core" }, @@ -1946,7 +1946,7 @@ wheels = [ [[package]] name = "pydantic-core" version = "2.41.5" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -2064,7 +2064,7 @@ wheels = [ [[package]] name = "pydantic-settings" version = "2.10.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pydantic" }, { name = "python-dotenv" }, @@ -2078,7 +2078,7 @@ wheels = [ [[package]] name = "pygments" version = "2.19.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2087,7 +2087,7 @@ wheels = [ [[package]] name = "pyright" version = "1.1.403" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "nodeenv" }, { name = "typing-extensions" }, @@ -2100,7 +2100,7 @@ wheels = [ [[package]] name = "pytest" version = "7.4.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, @@ -2117,7 +2117,7 @@ wheels = [ [[package]] name = "pytest-asyncio" version = "0.18.3" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, ] @@ -2130,7 +2130,7 @@ wheels = [ [[package]] name = "pytest-pretty" version = "1.3.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "pytest" }, { name = "rich" }, @@ -2143,7 +2143,7 @@ wheels = [ [[package]] name = "python-dateutil" version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "six" }, ] @@ -2155,7 +2155,7 @@ wheels = [ [[package]] name = "python-dotenv" version = "1.1.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2164,7 +2164,7 @@ wheels = [ [[package]] name = "python-multipart" version = "0.0.20" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2173,7 +2173,7 @@ wheels = [ [[package]] name = "pytz" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/f8/bf/abbd3cdfb8fbc7fb3d4d38d320f2441b1e7cbe29be4f23797b4a2b5d8aac/pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3", size = 320884, upload-time = "2025-03-25T02:25:00.538Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/81/c4/34e93fe5f5429d7570ec1fa436f1986fb1f00c3e0f43a589fe2bbcd22c3f/pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00", size = 509225, upload-time = "2025-03-25T02:24:58.468Z" }, @@ -2182,7 +2182,7 @@ wheels = [ [[package]] name = "pywin32" version = "311" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } wheels = [ { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, @@ -2204,7 +2204,7 @@ wheels = [ [[package]] name = "pyyaml" version = "6.0.2" -source = { registry = "https://pypi.org/simple" } +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/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, @@ -2248,7 +2248,7 @@ wheels = [ [[package]] name = "referencing" version = "0.36.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "rpds-py" }, @@ -2262,7 +2262,7 @@ wheels = [ [[package]] name = "regex" version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, @@ -2331,7 +2331,7 @@ wheels = [ [[package]] name = "requests" version = "2.32.4" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "charset-normalizer" }, @@ -2346,7 +2346,7 @@ wheels = [ [[package]] name = "requests-toolbelt" version = "1.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "requests" }, ] @@ -2358,7 +2358,7 @@ wheels = [ [[package]] name = "rich" version = "14.0.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "markdown-it-py" }, { name = "pygments" }, @@ -2372,7 +2372,7 @@ wheels = [ [[package]] name = "rpds-py" version = "0.26.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a5/aa/4456d84bbb54adc6a916fb10c9b374f78ac840337644e4a5eda229c81275/rpds_py-0.26.0.tar.gz", hash = "sha256:20dae58a859b0906f0685642e591056f1e787f3a8b39c8e8749a45dc7d26bdb0", size = 27385, upload-time = "2025-07-01T15:57:13.958Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/b9/31/1459645f036c3dfeacef89e8e5825e430c77dde8489f3b99eaafcd4a60f5/rpds_py-0.26.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:4c70c70f9169692b36307a95f3d8c0a9fcd79f7b4a383aad5eaa0e9718b79b37", size = 372466, upload-time = "2025-07-01T15:53:40.55Z" }, @@ -2498,7 +2498,7 @@ wheels = [ [[package]] name = "ruff" version = "0.5.7" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/bf/2b/69e5e412f9d390adbdbcbf4f64d6914fa61b44b08839a6584655014fc524/ruff-0.5.7.tar.gz", hash = "sha256:8dfc0a458797f5d9fb622dd0efc52d796f23f0a1493a9527f4e49a550ae9a7e5", size = 2449817, upload-time = "2024-08-08T15:43:07.467Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/6b/eb/06e06aaf96af30a68e83b357b037008c54a2ddcbad4f989535007c700394/ruff-0.5.7-py3-none-linux_armv6l.whl", hash = "sha256:548992d342fc404ee2e15a242cdbea4f8e39a52f2e7752d0e4cbe88d2d2f416a", size = 9570571, upload-time = "2024-08-08T15:41:56.537Z" }, @@ -2523,7 +2523,7 @@ wheels = [ [[package]] name = "s3transfer" version = "0.13.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "botocore" }, ] @@ -2535,7 +2535,7 @@ wheels = [ [[package]] name = "sentry-sdk" version = "2.34.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, @@ -2548,7 +2548,7 @@ wheels = [ [[package]] name = "setuptools" version = "80.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, @@ -2557,7 +2557,7 @@ wheels = [ [[package]] name = "six" version = "1.17.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2566,7 +2566,7 @@ wheels = [ [[package]] name = "sniffio" version = "1.3.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -2575,7 +2575,7 @@ wheels = [ [[package]] name = "sortedcontainers" version = "2.4.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/e8/c4/ba2f8066cceb6f23394729afe52f3bf7adec04bf9ed2c820b39e19299111/sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88", size = 30594, upload-time = "2021-05-16T22:03:42.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/32/46/9cb0e58b2deb7f82b84065f37f3bffeb12413f947f9388e4cac22c4621ce/sortedcontainers-2.4.0-py2.py3-none-any.whl", hash = "sha256:a163dcaede0f1c021485e957a39245190e74249897e2ae4b2aa38595db237ee0", size = 29575, upload-time = "2021-05-16T22:03:41.177Z" }, @@ -2584,7 +2584,7 @@ wheels = [ [[package]] name = "sqlalchemy" version = "2.0.41" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "greenlet", marker = "(python_full_version < '3.14' and platform_machine == 'AMD64') or (python_full_version < '3.14' and platform_machine == 'WIN32') or (python_full_version < '3.14' and platform_machine == 'aarch64') or (python_full_version < '3.14' and platform_machine == 'amd64') or (python_full_version < '3.14' and platform_machine == 'ppc64le') or (python_full_version < '3.14' and platform_machine == 'win32') or (python_full_version < '3.14' and platform_machine == 'x86_64')" }, { name = "typing-extensions" }, @@ -2629,7 +2629,7 @@ wheels = [ [[package]] name = "sse-starlette" version = "2.4.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -2641,7 +2641,7 @@ wheels = [ [[package]] name = "starlette" version = "0.47.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, @@ -2653,8 +2653,8 @@ wheels = [ [[package]] name = "temporalio" -version = "1.22.0" -source = { registry = "https://pypi.org/simple" } +version = "1.23.0" +source = { registry = "https://test.pypi.org/simple/" } dependencies = [ { name = "nexus-rpc" }, { name = "protobuf" }, @@ -2662,13 +2662,13 @@ dependencies = [ { name = "types-protobuf" }, { name = "typing-extensions" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b5/28/2a79a1e98e4280924f08ea0989ee045aa0b65f17f8d4f2ae7b53c2f4c38d/temporalio-1.22.0.tar.gz", hash = "sha256:896452fad246de2277cbb0408e4e0899882da1843480d5cbb57c7a5767440834", size = 1906162, upload-time = "2026-02-03T20:58:37.042Z" } +sdist = { url = "https://test-files.pythonhosted.org/packages/67/48/ba7413e2fab8dcd277b9df00bafa572da24e9ca32de2f38d428dc3a2825c/temporalio-1.23.0.tar.gz", hash = "sha256:72750494b00eb73ded9db76195e3a9b53ff548780f73d878ec3f807ee3191410", size = 1933051, upload-time = "2026-02-18T17:40:03.902Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/00/4dd57b3be03cc22523fd7083a3f63700188d7856ada875c99e71ca9a72bd/temporalio-1.22.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:532ef90cdee487a76c46eb71348f94f0a8a432e9dd241a0552b384314bbe28c0", size = 12198015, upload-time = "2026-02-03T20:57:04.056Z" }, - { url = "https://files.pythonhosted.org/packages/a7/15/1c24ea8005f1abc58dbb35b26ea93e5067afc385e56dda0e50c64c75cc07/temporalio-1.22.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a5f8646c1a0c36d5d4472462f2d315bafa7e2c9b1f52f15a07d01d1ccc33778", size = 11697647, upload-time = "2026-02-03T20:57:26.252Z" }, - { url = "https://files.pythonhosted.org/packages/09/2e/b65ec41f73030a109c253ac30545e4aac19044cd30083231b9b5993914e8/temporalio-1.22.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8cf7c909f7d6bc236a45aa09fc347cb53b02fa3287df29409d0500fc21c0dc5", size = 11972722, upload-time = "2026-02-03T20:57:47.371Z" }, - { url = "https://files.pythonhosted.org/packages/b4/de/048bf901417940f62bd69243d95762a63e97a5ad138c514c76852d364cd6/temporalio-1.22.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ac4adf1ac20f594066b8091de22f463a31f0926c23be1e990519fd6dbbb9d1b", size = 12275101, upload-time = "2026-02-03T20:58:09.636Z" }, - { url = "https://files.pythonhosted.org/packages/14/8e/f5852ef5326990ae5a15cb5f764254df1d086463ddc8244766d13872c3d3/temporalio-1.22.0-cp310-abi3-win_amd64.whl", hash = "sha256:4453ba03681e4ed39bf410f76997b7e0b9ec239d0dff7cabd53eb89c7fbaa6b0", size = 12713408, upload-time = "2026-02-03T20:58:32.086Z" }, + { url = "https://test-files.pythonhosted.org/packages/6f/71/26c8f21dca9092201b3b9cb7aff42460b4864b5999aa4c6a4343ac66f1fd/temporalio-1.23.0-cp310-abi3-macosx_10_12_x86_64.whl", hash = "sha256:6b69ac8d75f2d90e66f4edce4316f6a33badc4a30b22efc50e9eddaa9acdc216", size = 12311037, upload-time = "2026-02-18T17:39:27.941Z" }, + { url = "https://test-files.pythonhosted.org/packages/ec/47/43102816139f2d346680cb7cc1e53da5f6968355ac65b4d35d4edbfca896/temporalio-1.23.0-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:1bbbb2f9c3cdd09451565163f6d741e51f109694c49435d475fdfa42b597219d", size = 11821906, upload-time = "2026-02-18T17:39:35.343Z" }, + { url = "https://test-files.pythonhosted.org/packages/00/b0/899ff28464a0e17adf17476bdfac8faf4ea41870358ff2d14737e43f9e66/temporalio-1.23.0-cp310-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf6570e0ee696f99a38d855da4441a890c7187357c16505ed458ac9ef274ed70", size = 12063601, upload-time = "2026-02-18T17:39:43.299Z" }, + { url = "https://test-files.pythonhosted.org/packages/ed/17/b8c6d2ec3e113c6a788322513a5ff635bdd54b3791d092ed0e273467748a/temporalio-1.23.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b82d6cca54c9f376b50e941dd10d12f7fe5b692a314fb087be72cd2898646a79", size = 12394579, upload-time = "2026-02-18T17:39:52.935Z" }, + { url = "https://test-files.pythonhosted.org/packages/b4/b7/f9ef7fd5ee65aef7d59ab1e95cb1b45df2fe49c17e3aa4d650ae3322f015/temporalio-1.23.0-cp310-abi3-win_amd64.whl", hash = "sha256:43c3b99a46dd329761a256f3855710c4a5b322afc879785e468bdd0b94faace6", size = 12834494, upload-time = "2026-02-18T17:40:00.858Z" }, ] [package.optional-dependencies] @@ -2755,7 +2755,7 @@ trio-async = [ ] [package.metadata] -requires-dist = [{ name = "temporalio", specifier = ">=1.22.0,<2" }] +requires-dist = [{ name = "temporalio", specifier = ">=1.23.0,<2" }] [package.metadata.requires-dev] bedrock = [{ name = "boto3", specifier = ">=1.34.92,<2" }] @@ -2815,7 +2815,7 @@ trio-async = [ [[package]] name = "tenacity" version = "8.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/a3/4d/6a19536c50b849338fcbe9290d562b52cbdcf30d8963d3588a68a4107df1/tenacity-8.5.0.tar.gz", hash = "sha256:8bc6c0c8a09b31e6cad13c47afbed1a567518250a9a171418582ed8d9c20ca78", size = 47309, upload-time = "2024-07-05T07:25:31.836Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/d2/3f/8ba87d9e287b9d385a02a7114ddcef61b26f86411e121c9003eb509a1773/tenacity-8.5.0-py3-none-any.whl", hash = "sha256:b594c2a5945830c267ce6b79a166228323ed52718f30302c1359836112346687", size = 28165, upload-time = "2024-07-05T07:25:29.591Z" }, @@ -2824,7 +2824,7 @@ wheels = [ [[package]] name = "tiktoken" version = "0.12.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "regex" }, { name = "requests" }, @@ -2885,7 +2885,7 @@ wheels = [ [[package]] name = "tokenizers" version = "0.21.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "huggingface-hub" }, ] @@ -2910,7 +2910,7 @@ wheels = [ [[package]] name = "tomli" version = "2.2.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/18/87/302344fed471e44a87289cf4967697d07e532f2421fdaf868a303cbae4ff/tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff", size = 17175, upload-time = "2024-11-27T22:38:36.873Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/43/ca/75707e6efa2b37c77dadb324ae7d9571cb424e61ea73fad7c56c2d14527f/tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249", size = 131077, upload-time = "2024-11-27T22:37:54.956Z" }, @@ -2949,7 +2949,7 @@ wheels = [ [[package]] name = "tqdm" version = "4.67.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "colorama", marker = "sys_platform == 'win32'" }, ] @@ -2961,7 +2961,7 @@ wheels = [ [[package]] name = "trio" version = "0.28.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "attrs" }, { name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" }, @@ -2979,7 +2979,7 @@ wheels = [ [[package]] name = "trio-asyncio" version = "0.15.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, { name = "greenlet" }, @@ -2995,7 +2995,7 @@ wheels = [ [[package]] name = "types-protobuf" version = "6.30.2.20250703" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/dc/54/d63ce1eee8e93c4d710bbe2c663ec68e3672cf4f2fca26eecd20981c0c5d/types_protobuf-6.30.2.20250703.tar.gz", hash = "sha256:609a974754bbb71fa178fc641f51050395e8e1849f49d0420a6281ed8d1ddf46", size = 62300, upload-time = "2025-07-03T03:14:05.74Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/7e/2b/5d0377c3d6e0f49d4847ad2c40629593fee4a5c9ec56eba26a15c708fbc0/types_protobuf-6.30.2.20250703-py3-none-any.whl", hash = "sha256:fa5aff9036e9ef432d703abbdd801b436a249b6802e4df5ef74513e272434e57", size = 76489, upload-time = "2025-07-03T03:14:04.453Z" }, @@ -3004,7 +3004,7 @@ wheels = [ [[package]] name = "types-pyyaml" version = "6.0.12.20250516" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/4e/22/59e2aeb48ceeee1f7cd4537db9568df80d62bdb44a7f9e743502ea8aab9c/types_pyyaml-6.0.12.20250516.tar.gz", hash = "sha256:9f21a70216fc0fa1b216a8176db5f9e0af6eb35d2f2932acb87689d03a5bf6ba", size = 17378, upload-time = "2025-05-16T03:08:04.897Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/99/5f/e0af6f7f6a260d9af67e1db4f54d732abad514252a7a378a6c4d17dd1036/types_pyyaml-6.0.12.20250516-py3-none-any.whl", hash = "sha256:8478208feaeb53a34cb5d970c56a7cd76b72659442e733e268a94dc72b2d0530", size = 20312, upload-time = "2025-05-16T03:08:04.019Z" }, @@ -3013,7 +3013,7 @@ wheels = [ [[package]] name = "types-requests" version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "urllib3" }, ] @@ -3025,7 +3025,7 @@ wheels = [ [[package]] name = "typing-extensions" version = "4.14.1" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3034,7 +3034,7 @@ wheels = [ [[package]] name = "typing-inspect" version = "0.9.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "mypy-extensions" }, { name = "typing-extensions" }, @@ -3047,7 +3047,7 @@ wheels = [ [[package]] name = "typing-inspection" version = "0.4.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "typing-extensions" }, ] @@ -3059,7 +3059,7 @@ wheels = [ [[package]] name = "tzdata" version = "2025.2" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3068,7 +3068,7 @@ wheels = [ [[package]] name = "urllib3" version = "2.5.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, @@ -3077,7 +3077,7 @@ wheels = [ [[package]] name = "uvicorn" version = "0.24.0.post1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "click" }, { name = "h11" }, @@ -3102,7 +3102,7 @@ standard = [ [[package]] name = "uvloop" version = "0.21.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, @@ -3134,7 +3134,7 @@ wheels = [ [[package]] name = "watchfiles" version = "1.1.0" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "anyio" }, ] @@ -3234,7 +3234,7 @@ wheels = [ [[package]] name = "websockets" version = "15.0.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } wheels = [ { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, @@ -3293,7 +3293,7 @@ wheels = [ [[package]] name = "yarl" version = "1.20.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "idna" }, { name = "multidict" }, @@ -3392,7 +3392,7 @@ wheels = [ [[package]] name = "zipp" version = "3.23.0" -source = { registry = "https://pypi.org/simple" } +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" }, @@ -3401,7 +3401,7 @@ wheels = [ [[package]] name = "zope-event" version = "5.1" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] @@ -3413,7 +3413,7 @@ wheels = [ [[package]] name = "zope-interface" version = "7.2" -source = { registry = "https://pypi.org/simple" } +source = { registry = "https://pypi.org/simple/" } dependencies = [ { name = "setuptools" }, ] From e2381f7add2b8299d6b34c36ba80b70c089d8b28 Mon Sep 17 00:00:00 2001 From: Dan Davison Date: Tue, 24 Feb 2026 19:52:55 -0500 Subject: [PATCH 34/40] Standalone activity (#270) * Standalone Activity sample * Add sample to READMEs, update sample to include list_activities and count_activities * ruff format --------- Co-authored-by: Andrew Yuan --- README.md | 2 + hello/README.md | 3 +- hello/hello_standalone_activity.py | 77 ++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 hello/hello_standalone_activity.py diff --git a/README.md b/README.md index 5a39e834..8e7748de 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,8 @@ Some examples require extra dependencies. See each sample's directory for specif * [hello_search_attributes](hello/hello_search_attributes.py) - Start workflow with search attributes then change while running. * [hello_signal](hello/hello_signal.py) - Send signals to a workflow. + * [hello standalone activity](hello/hello_standalone_activity.py) - Execute an activity from outside of a workflow. + * [hello update](hello/hello_update.py) - Send a request to and a response from a client to a workflow execution. * [activity_worker](activity_worker) - Use Python activities from a workflow in another language. * [batch_sliding_window](batch_sliding_window) - Batch processing with a sliding window of child workflows. diff --git a/hello/README.md b/hello/README.md index c014d08c..48e8e67e 100644 --- a/hello/README.md +++ b/hello/README.md @@ -44,7 +44,8 @@ Replace `hello/hello_activity.py` in the command with any other example filename * [hello_search_attributes](hello_search_attributes.py) - Start workflow with search attributes then change while running. * [hello_signal](hello_signal.py) - Send signals to a workflow. -* [hello_update](hello_update.py) - Send a request to and a response from a client to a workflow execution. +* [hello standalone activity](hello_standalone_activity.py) - Execute an activity from outside of a workflow. +* [hello_update](hello_update.py) - **Send a request to and a response from a client to a workflow execution.** Note: To enable the workflow update, set the `frontend.enableUpdateWorkflowExecution` dynamic config value to true. diff --git a/hello/hello_standalone_activity.py b/hello/hello_standalone_activity.py new file mode 100644 index 00000000..541d687b --- /dev/null +++ b/hello/hello_standalone_activity.py @@ -0,0 +1,77 @@ +import asyncio +from dataclasses import dataclass +from datetime import timedelta + +from temporalio import activity +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +# This sample is very similar to hello_activity.py. The difference is that whereas in +# hello_activity.py the activity is orchestrated by a workflow, in this sample the activity is +# executed directly by a client ("standalone activity"). + + +@dataclass +class ComposeGreetingInput: + greeting: str + name: str + + +# This is just a normal activity. You could invoke it from a workflow but, in this sample, we are +# invoking it directly as a standalone activity. +@activity.defn +async def compose_greeting(input: ComposeGreetingInput) -> str: + activity.logger.info("Running activity with parameter %s" % input) + return f"{input.greeting}, {input.name}!" + + +async def my_client_code(client: Client): + # client.execute_activity starts the activity, and then uses a long-poll to wait for the + # activity to be completed by the worker. + result = await client.execute_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id="my-standalone-activity-id", + task_queue="hello-standalone-activity-task-queue", + start_to_close_timeout=timedelta(seconds=10), + ) + print(f"Activity result: {result}") + + activities = client.list_activities( + query="TaskQueue = 'hello-standalone-activity-task-queue'" + ) + print("ListActivity results:") + async for info in activities: + print( + f"\tActivityID: {info.activity_id}, Type: {info.activity_type}, Status: {info.status}" + ) + + count_result = await client.count_activities( + query="TaskQueue = 'hello-standalone-activity-task-queue'" + ) + print(f"Total activities: {count_result.count}") + + +async def main(): + # Uncomment the lines below to see logging output + # import logging + # logging.basicConfig(level=logging.INFO) + + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + + client = await Client.connect(**config) + + # Run a worker for the activity + async with Worker( + client, + task_queue="hello-standalone-activity-task-queue", + activities=[compose_greeting], + ): + # While the worker is running, use the client to execute the activity. + await my_client_code(client) + + +if __name__ == "__main__": + asyncio.run(main()) From 2fd1407e9a8e116b95899f4ce9dd794bbe2a121b Mon Sep 17 00:00:00 2001 From: Bill Richards Date: Wed, 25 Feb 2026 11:50:09 -0700 Subject: [PATCH 35/40] Fix potential race with the sliding window sample. Fixes #279 (#280) --- batch_sliding_window/sliding_window_workflow.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/batch_sliding_window/sliding_window_workflow.py b/batch_sliding_window/sliding_window_workflow.py index 87e4110d..a416fb99 100644 --- a/batch_sliding_window/sliding_window_workflow.py +++ b/batch_sliding_window/sliding_window_workflow.py @@ -108,6 +108,7 @@ async def _execute(self, input: SlidingWindowWorkflowInput) -> int: # Start child workflow for this record child_id = f"{workflow_id}/{record.id}" + self.current_records.add(record.id) child_handle = await workflow.start_child_workflow( RecordProcessorWorkflow.run, record, @@ -117,7 +118,6 @@ async def _execute(self, input: SlidingWindowWorkflowInput) -> int: ) self.children_started_by_this_run.append(child_handle) - self.current_records.add(record.id) return await self._continue_as_new_or_complete(input) From 3cb281ed52205b0e8e24a2124bdf33e23133c517 Mon Sep 17 00:00:00 2001 From: Quinn Klassen Date: Tue, 10 Mar 2026 10:44:57 -0700 Subject: [PATCH 36/40] Nexus cancellation sample (#281) Add sample for cancellation --- nexus_cancel/README.md | 50 ++++++++++++++++++ nexus_cancel/__init__.py | 0 nexus_cancel/caller/__init__.py | 0 nexus_cancel/caller/app.py | 43 +++++++++++++++ nexus_cancel/caller/workflows.py | 69 +++++++++++++++++++++++++ nexus_cancel/handler/__init__.py | 0 nexus_cancel/handler/service_handler.py | 27 ++++++++++ nexus_cancel/handler/worker.py | 48 +++++++++++++++++ nexus_cancel/handler/workflows.py | 49 ++++++++++++++++++ nexus_cancel/service.py | 35 +++++++++++++ 10 files changed, 321 insertions(+) create mode 100644 nexus_cancel/README.md create mode 100644 nexus_cancel/__init__.py create mode 100644 nexus_cancel/caller/__init__.py create mode 100644 nexus_cancel/caller/app.py create mode 100644 nexus_cancel/caller/workflows.py create mode 100644 nexus_cancel/handler/__init__.py create mode 100644 nexus_cancel/handler/service_handler.py create mode 100644 nexus_cancel/handler/worker.py create mode 100644 nexus_cancel/handler/workflows.py create mode 100644 nexus_cancel/service.py diff --git a/nexus_cancel/README.md b/nexus_cancel/README.md new file mode 100644 index 00000000..2f7f5703 --- /dev/null +++ b/nexus_cancel/README.md @@ -0,0 +1,50 @@ +# Nexus Cancellation + +This sample shows how a caller workflow can fan out multiple Nexus operations concurrently, take the first result, and cancel the rest using `WAIT_REQUESTED` cancellation semantics. + +With `WAIT_REQUESTED`, the caller proceeds once the handler has received the cancel request β€” it does not wait for the handler to finish processing the cancellation. + +Start a Temporal server. (See the main samples repo [README](../README.md)). + +Run the following: + +``` +temporal operator namespace create --namespace nexus-cancel-handler-namespace +temporal operator namespace create --namespace nexus-cancel-caller-namespace + +temporal operator nexus endpoint create \ + --name nexus-cancel-endpoint \ + --target-namespace nexus-cancel-handler-namespace \ + --target-task-queue nexus-cancel-handler-task-queue +``` + +Next, in separate terminal windows: + +## Nexus Handler Worker + +```bash +uv run nexus_cancel/handler/worker.py +``` + +## Nexus Caller App + +```bash +uv run nexus_cancel/caller/app.py +``` + +## Expected Output + +On the caller side, you should see a greeting in whichever language completed first: +``` +Hello Nexus πŸ‘‹ +``` + +On the handler side, you should see cancellation log messages for the remaining operations: +``` +HelloHandlerWorkflow was cancelled successfully. +HelloHandlerWorkflow was cancelled successfully. +HelloHandlerWorkflow was cancelled successfully. +HelloHandlerWorkflow was cancelled successfully. +``` + +The caller workflow returns before all handler workflows have completed their cancellation cleanup. This demonstrates `WAIT_REQUESTED` semantics: the caller didn't wait for the handler workflows to finish, but still guaranteed that all handlers received the cancellation request. diff --git a/nexus_cancel/__init__.py b/nexus_cancel/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_cancel/caller/__init__.py b/nexus_cancel/caller/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_cancel/caller/app.py b/nexus_cancel/caller/app.py new file mode 100644 index 00000000..bb74e9e0 --- /dev/null +++ b/nexus_cancel/caller/app.py @@ -0,0 +1,43 @@ +import asyncio +import uuid +from typing import Optional + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +from nexus_cancel.caller.workflows import HelloCallerWorkflow + +NAMESPACE = "nexus-cancel-caller-namespace" +TASK_QUEUE = "nexus-cancel-caller-task-queue" + + +async def execute_caller_workflow( + client: Optional[Client] = None, +) -> str: + if client is None: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) + + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[HelloCallerWorkflow], + ): + return await client.execute_workflow( + HelloCallerWorkflow.run, + "Nexus", + id=f"hello-caller-{uuid.uuid4()}", + task_queue=TASK_QUEUE, + ) + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + result = loop.run_until_complete(execute_caller_workflow()) + print(result) + except KeyboardInterrupt: + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_cancel/caller/workflows.py b/nexus_cancel/caller/workflows.py new file mode 100644 index 00000000..f8a2e1ff --- /dev/null +++ b/nexus_cancel/caller/workflows.py @@ -0,0 +1,69 @@ +""" +Caller workflow that demonstrates Nexus operation cancellation. + +Fans out 5 concurrent Nexus hello operations (one per language), takes the first +result, and cancels the rest using WAIT_REQUESTED cancellation semantics. +""" + +import asyncio +from datetime import timedelta + +from temporalio import workflow +from temporalio.exceptions import CancelledError, NexusOperationError + +with workflow.unsafe.imports_passed_through(): + from nexus_cancel.service import HelloInput, Language, NexusService + +NEXUS_ENDPOINT = "nexus-cancel-endpoint" + + +@workflow.defn +class HelloCallerWorkflow: + def __init__(self) -> None: + self.nexus_client = workflow.create_nexus_client( + service=NexusService, + endpoint=NEXUS_ENDPOINT, + ) + + @workflow.run + async def run(self, message: str) -> str: + # Fan out 5 concurrent Nexus calls, one per language. + # Each task starts and awaits its own operation so all race concurrently. + async def run_operation(language: Language): + handle = await self.nexus_client.start_operation( + NexusService.hello, + HelloInput(name=message, language=language), + schedule_to_close_timeout=timedelta(seconds=10), + cancellation_type=workflow.NexusOperationCancellationType.WAIT_REQUESTED, + ) + return await handle + + tasks = [asyncio.create_task(run_operation(lang)) for lang in Language] + + # Wait for the first operation to complete + workflow.logger.info( + f"Started {len(tasks)} operations, waiting for first to complete..." + ) + done, pending = await workflow.wait(tasks, return_when=asyncio.FIRST_COMPLETED) + + # Get the result from the first completed operation + result = await done.pop() + workflow.logger.info(f"First operation completed with: {result.message}") + + # Cancel all remaining operations + workflow.logger.info(f"Cancelling {len(pending)} remaining operations...") + for task in pending: + task.cancel() + + # Wait for all cancellations to be acknowledged. + # If the workflow completes before cancellation requests are delivered, + # the server drops them. Waiting ensures all handlers receive the + # cancellation. + for task in pending: + try: + await task + except (NexusOperationError, CancelledError): + # Expected: the operation was cancelled + workflow.logger.info("Operation was cancelled") + + return result.message diff --git a/nexus_cancel/handler/__init__.py b/nexus_cancel/handler/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/nexus_cancel/handler/service_handler.py b/nexus_cancel/handler/service_handler.py new file mode 100644 index 00000000..92868510 --- /dev/null +++ b/nexus_cancel/handler/service_handler.py @@ -0,0 +1,27 @@ +""" +Nexus service handler for the cancellation sample. + +The hello operation is backed by a workflow, using the Nexus request ID as the +workflow ID for idempotency across retries. +""" + +from __future__ import annotations + +import nexusrpc +from temporalio import nexus + +from nexus_cancel.handler.workflows import HelloHandlerWorkflow +from nexus_cancel.service import HelloInput, HelloOutput, NexusService + + +@nexusrpc.handler.service_handler(service=NexusService) +class NexusServiceHandler: + @nexus.workflow_run_operation + async def hello( + self, ctx: nexus.WorkflowRunOperationContext, input: HelloInput + ) -> nexus.WorkflowHandle[HelloOutput]: + return await ctx.start_workflow( + HelloHandlerWorkflow.run, + input, + id=ctx.request_id, + ) diff --git a/nexus_cancel/handler/worker.py b/nexus_cancel/handler/worker.py new file mode 100644 index 00000000..e29df355 --- /dev/null +++ b/nexus_cancel/handler/worker.py @@ -0,0 +1,48 @@ +""" +Worker for the handler namespace that processes Nexus operations and workflows. +""" + +import asyncio +import logging +from typing import Optional + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +from nexus_cancel.handler.service_handler import NexusServiceHandler +from nexus_cancel.handler.workflows import HelloHandlerWorkflow + +interrupt_event = asyncio.Event() + +NAMESPACE = "nexus-cancel-handler-namespace" +TASK_QUEUE = "nexus-cancel-handler-task-queue" + + +async def main(client: Optional[Client] = None): + logging.basicConfig(level=logging.INFO) + + if not client: + config = ClientConfig.load_client_connect_config() + config.setdefault("target_host", "localhost:7233") + config.setdefault("namespace", NAMESPACE) + client = await Client.connect(**config) + + async with Worker( + client, + task_queue=TASK_QUEUE, + workflows=[HelloHandlerWorkflow], + nexus_service_handlers=[NexusServiceHandler()], + ): + logging.info("Worker started, ctrl+c to exit") + await interrupt_event.wait() + logging.info("Shutting down") + + +if __name__ == "__main__": + loop = asyncio.new_event_loop() + try: + loop.run_until_complete(main()) + except KeyboardInterrupt: + interrupt_event.set() + loop.run_until_complete(loop.shutdown_asyncgens()) diff --git a/nexus_cancel/handler/workflows.py b/nexus_cancel/handler/workflows.py new file mode 100644 index 00000000..d799c62b --- /dev/null +++ b/nexus_cancel/handler/workflows.py @@ -0,0 +1,49 @@ +""" +Handler workflow started by the hello Nexus operation. + +Demonstrates how to handle cancellation from the caller workflow using a +detached cancellation scope (asyncio.shield) for cleanup work. +""" + +import asyncio + +from temporalio import workflow + +with workflow.unsafe.imports_passed_through(): + from nexus_cancel.service import HelloInput, HelloOutput, Language + +GREETINGS = { + Language.EN: "Hello {name} πŸ‘‹", + Language.FR: "Bonjour {name} πŸ‘‹", + Language.DE: "Hallo {name} πŸ‘‹", + Language.ES: "Β‘Hola! {name} πŸ‘‹", + Language.TR: "Merhaba {name} πŸ‘‹", +} + + +@workflow.defn +class HelloHandlerWorkflow: + @workflow.run + async def run(self, input: HelloInput) -> HelloOutput: + try: + # Sleep for a random duration to simulate work (0-5 seconds) + random_seconds = workflow.random().randint(0, 5) + workflow.logger.info(f"Working for {random_seconds} seconds...") + await asyncio.sleep(random_seconds) + + # Return a greeting based on the language + greeting = GREETINGS[input.language].format(name=input.name) + return HelloOutput(message=greeting) + + except asyncio.CancelledError: + # Perform cleanup in a detached cancellation scope. + # asyncio.shield prevents the cleanup work from being cancelled. + workflow.logger.info("Received cancellation request, performing cleanup...") + try: + cleanup_seconds = workflow.random().randint(0, 5) + await asyncio.shield(asyncio.sleep(cleanup_seconds)) + except asyncio.CancelledError: + pass + workflow.logger.info("HelloHandlerWorkflow was cancelled successfully.") + # Re-raise the cancellation error + raise diff --git a/nexus_cancel/service.py b/nexus_cancel/service.py new file mode 100644 index 00000000..454a32f7 --- /dev/null +++ b/nexus_cancel/service.py @@ -0,0 +1,35 @@ +""" +Nexus service definition for the cancellation sample. + +Defines a NexusService with a single `hello` operation that takes a name and +language, and returns a greeting message. +""" + +from dataclasses import dataclass +from enum import IntEnum + +import nexusrpc + + +class Language(IntEnum): + EN = 0 + FR = 1 + DE = 2 + ES = 3 + TR = 4 + + +@dataclass +class HelloInput: + name: str + language: Language + + +@dataclass +class HelloOutput: + message: str + + +@nexusrpc.service +class NexusService: + hello: nexusrpc.Operation[HelloInput, HelloOutput] From 0d22299224c577a68ac1846d24a016cdf55b4c38 Mon Sep 17 00:00:00 2001 From: Andrew Yuan Date: Tue, 10 Mar 2026 16:24:14 -0700 Subject: [PATCH 37/40] Add note on CLI version support (#282) --- README.md | 1 + hello/README.md | 1 + 2 files changed, 2 insertions(+) diff --git a/README.md b/README.md index 8e7748de..1e3860ed 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,7 @@ Some examples require extra dependencies. See each sample's directory for specif while running. * [hello_signal](hello/hello_signal.py) - Send signals to a workflow. * [hello standalone activity](hello/hello_standalone_activity.py) - Execute an activity from outside of a workflow. + * Note: Standalone activities is supported in CLI version [v1.6.2](https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity). * [hello update](hello/hello_update.py) - Send a request to and a response from a client to a workflow execution. * [activity_worker](activity_worker) - Use Python activities from a workflow in another language. diff --git a/hello/README.md b/hello/README.md index 48e8e67e..13495fd0 100644 --- a/hello/README.md +++ b/hello/README.md @@ -45,6 +45,7 @@ Replace `hello/hello_activity.py` in the command with any other example filename running. * [hello_signal](hello_signal.py) - Send signals to a workflow. * [hello standalone activity](hello_standalone_activity.py) - Execute an activity from outside of a workflow. + * Note: Standalone activities is supported in CLI version [v1.6.2](https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity). * [hello_update](hello_update.py) - **Send a request to and a response from a client to a workflow execution.** Note: To enable the workflow update, set the `frontend.enableUpdateWorkflowExecution` dynamic config value to true. From 5e9d1c7b1ad76f0e5654ea62230e7d927ad2861b Mon Sep 17 00:00:00 2001 From: Phil Prasek Date: Wed, 11 Mar 2026 10:14:25 -0700 Subject: [PATCH 38/40] Hello standalone activity (#284) * Make it non-`async def` * Add test * standalone activity samples to pair with docs for quickstart Signed-off-by: Phil Prasek * Remove hello/hello_standalone_activity.py in favor of top-level hello_standalone_activity/ sample The standalone activity sample now lives in its own top-level directory (added by Phil in fc08204). Update the test to import from the new location and update both READMEs accordingly. --------- Signed-off-by: Phil Prasek Co-authored-by: Dan Davison --- README.md | 5 +- hello/README.md | 2 - hello/hello_standalone_activity.py | 77 ------------ hello_standalone_activity/README.md | 115 ++++++++++++++++++ hello_standalone_activity/__init__.py | 0 hello_standalone_activity/count_activities.py | 23 ++++ hello_standalone_activity/execute_activity.py | 26 ++++ hello_standalone_activity/list_activities.py | 23 ++++ hello_standalone_activity/my_activity.py | 15 +++ hello_standalone_activity/start_activity.py | 31 +++++ hello_standalone_activity/worker.py | 26 ++++ tests/hello/hello_standalone_activity_test.py | 31 +++++ 12 files changed, 292 insertions(+), 82 deletions(-) delete mode 100644 hello/hello_standalone_activity.py create mode 100644 hello_standalone_activity/README.md create mode 100644 hello_standalone_activity/__init__.py create mode 100644 hello_standalone_activity/count_activities.py create mode 100644 hello_standalone_activity/execute_activity.py create mode 100644 hello_standalone_activity/list_activities.py create mode 100644 hello_standalone_activity/my_activity.py create mode 100644 hello_standalone_activity/start_activity.py create mode 100644 hello_standalone_activity/worker.py create mode 100644 tests/hello/hello_standalone_activity_test.py diff --git a/README.md b/README.md index 1e3860ed..d4d6a61b 100644 --- a/README.md +++ b/README.md @@ -55,8 +55,6 @@ Some examples require extra dependencies. See each sample's directory for specif * [hello_search_attributes](hello/hello_search_attributes.py) - Start workflow with search attributes then change while running. * [hello_signal](hello/hello_signal.py) - Send signals to a workflow. - * [hello standalone activity](hello/hello_standalone_activity.py) - Execute an activity from outside of a workflow. - * Note: Standalone activities is supported in CLI version [v1.6.2](https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity). * [hello update](hello/hello_update.py) - Send a request to and a response from a client to a workflow execution. * [activity_worker](activity_worker) - Use Python activities from a workflow in another language. @@ -72,6 +70,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [encryption](encryption) - Apply end-to-end encryption for all input/output. * [env_config](env_config) - Load client configuration from TOML files with programmatic overrides. * [gevent_async](gevent_async) - Combine gevent and Temporal. +* [hello_standalone_activity](hello_standalone_activity) - Use activities without using a workflow. * [langchain](langchain) - Orchestrate workflows for LangChain. * [message_passing/introduction](message_passing/introduction/) - Introduction to queries, signals, and updates. * [message_passing/safe_message_handlers](message_passing/safe_message_handlers/) - Safely handling updates and signals. @@ -87,7 +86,7 @@ Some examples require extra dependencies. See each sample's directory for specif * [updatable_timer](updatable_timer) - A timer that can be updated while sleeping. * [worker_specific_task_queues](worker_specific_task_queues) - Use unique task queues to ensure activities run on specific workers. * [worker_versioning](worker_versioning) - Use the Worker Versioning feature to more easily version your workflows & other code. -* [worker_multiprocessing](worker_multiprocessing) - Leverage Python multiprocessing to parallelize workflow tasks and other CPU bound operations by running multiple workers. +* [worker_multiprocessing](worker_multiprocessing) - Leverage Python multiprocessing to parallelize workflow tasks and other CPU bound operations by running multiple workers. ## Test diff --git a/hello/README.md b/hello/README.md index 13495fd0..7b5ca6eb 100644 --- a/hello/README.md +++ b/hello/README.md @@ -44,8 +44,6 @@ Replace `hello/hello_activity.py` in the command with any other example filename * [hello_search_attributes](hello_search_attributes.py) - Start workflow with search attributes then change while running. * [hello_signal](hello_signal.py) - Send signals to a workflow. -* [hello standalone activity](hello_standalone_activity.py) - Execute an activity from outside of a workflow. - * Note: Standalone activities is supported in CLI version [v1.6.2](https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity). * [hello_update](hello_update.py) - **Send a request to and a response from a client to a workflow execution.** Note: To enable the workflow update, set the `frontend.enableUpdateWorkflowExecution` dynamic config value to true. diff --git a/hello/hello_standalone_activity.py b/hello/hello_standalone_activity.py deleted file mode 100644 index 541d687b..00000000 --- a/hello/hello_standalone_activity.py +++ /dev/null @@ -1,77 +0,0 @@ -import asyncio -from dataclasses import dataclass -from datetime import timedelta - -from temporalio import activity -from temporalio.client import Client -from temporalio.envconfig import ClientConfig -from temporalio.worker import Worker - -# This sample is very similar to hello_activity.py. The difference is that whereas in -# hello_activity.py the activity is orchestrated by a workflow, in this sample the activity is -# executed directly by a client ("standalone activity"). - - -@dataclass -class ComposeGreetingInput: - greeting: str - name: str - - -# This is just a normal activity. You could invoke it from a workflow but, in this sample, we are -# invoking it directly as a standalone activity. -@activity.defn -async def compose_greeting(input: ComposeGreetingInput) -> str: - activity.logger.info("Running activity with parameter %s" % input) - return f"{input.greeting}, {input.name}!" - - -async def my_client_code(client: Client): - # client.execute_activity starts the activity, and then uses a long-poll to wait for the - # activity to be completed by the worker. - result = await client.execute_activity( - compose_greeting, - args=[ComposeGreetingInput("Hello", "World")], - id="my-standalone-activity-id", - task_queue="hello-standalone-activity-task-queue", - start_to_close_timeout=timedelta(seconds=10), - ) - print(f"Activity result: {result}") - - activities = client.list_activities( - query="TaskQueue = 'hello-standalone-activity-task-queue'" - ) - print("ListActivity results:") - async for info in activities: - print( - f"\tActivityID: {info.activity_id}, Type: {info.activity_type}, Status: {info.status}" - ) - - count_result = await client.count_activities( - query="TaskQueue = 'hello-standalone-activity-task-queue'" - ) - print(f"Total activities: {count_result.count}") - - -async def main(): - # Uncomment the lines below to see logging output - # import logging - # logging.basicConfig(level=logging.INFO) - - config = ClientConfig.load_client_connect_config() - config.setdefault("target_host", "localhost:7233") - - client = await Client.connect(**config) - - # Run a worker for the activity - async with Worker( - client, - task_queue="hello-standalone-activity-task-queue", - activities=[compose_greeting], - ): - # While the worker is running, use the client to execute the activity. - await my_client_code(client) - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/hello_standalone_activity/README.md b/hello_standalone_activity/README.md new file mode 100644 index 00000000..ebd63931 --- /dev/null +++ b/hello_standalone_activity/README.md @@ -0,0 +1,115 @@ +# Standalone Activity + +This sample shows how to execute Activities directly from a Temporal Client, without a Workflow. + +For full documentation, see [Standalone Activities - Python SDK](https://docs.temporal.io/develop/python/standalone-activities). + +### Sample directory structure + +- [my_activity.py](./my_activity.py) - Activity definition with `@activity.defn` +- [worker.py](./worker.py) - Worker that registers and runs the Activity +- [execute_activity.py](./execute_activity.py) - Execute a Standalone Activity and wait for the result +- [start_activity.py](./start_activity.py) - Start a Standalone Activity, get a handle, then wait for the result +- [list_activities.py](./list_activities.py) - List Standalone Activity Executions +- [count_activities.py](./count_activities.py) - Count Standalone Activity Executions + +### Quickstart + +**1. Start the Temporal dev server** + +```bash +temporal server start-dev +``` + +**2. Run the Worker** (in a separate terminal) + +```bash +uv run hello_standalone_activity/worker.py +``` + +**3. Execute a Standalone Activity** (in a separate terminal) + +Execute and wait for the result: + +```bash +uv run hello_standalone_activity/execute_activity.py +``` + +Or use the Temporal CLI: + +```bash +temporal activity execute \ + --type compose_greeting \ + --activity-id my-standalone-activity-id \ + --task-queue my-standalone-activity-task-queue \ + --start-to-close-timeout 10s \ + --input '{"greeting": "Hello", "name": "World"}' +``` + +**4. Start a Standalone Activity (without waiting)** + +Start, get a handle, then wait for the result: + +```bash +uv run hello_standalone_activity/start_activity.py +``` + +Or use the Temporal CLI: + +```bash +temporal activity start \ + --type compose_greeting \ + --activity-id my-standalone-activity-id \ + --task-queue my-standalone-activity-task-queue \ + --start-to-close-timeout 10s \ + --input '{"greeting": "Hello", "name": "World"}' +``` + +**5. List Standalone Activities** + +```bash +uv run hello_standalone_activity/list_activities.py +``` + +Or use the Temporal CLI: + +```bash +temporal activity list --query "TaskQueue = 'my-standalone-activity-task-queue'" +``` + +Note: `list` and `count` are only available in the [Standalone Activity prerelease CLI](https://github.com/temporalio/cli/releases/tag/v1.6.2-standalone-activity). + +**6. Count Standalone Activities** + +```bash +uv run hello_standalone_activity/count_activities.py +``` + +Or use the Temporal CLI: + +```bash +temporal activity count --query "TaskQueue = 'my-standalone-activity-task-queue'" +``` + +### Temporal Cloud + +The same code works against Temporal Cloud - just set environment variables. No code changes needed. + +**Connect with mTLS:** + +```bash +export TEMPORAL_ADDRESS=..tmprl.cloud:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_TLS_CLIENT_CERT_PATH='path/to/your/client.pem' +export TEMPORAL_TLS_CLIENT_KEY_PATH='path/to/your/client.key' +``` + +**Connect with an API key:** + +```bash +export TEMPORAL_ADDRESS=..api.temporal.io:7233 +export TEMPORAL_NAMESPACE=. +export TEMPORAL_API_KEY= +``` + +Then run the worker and starter as shown above. diff --git a/hello_standalone_activity/__init__.py b/hello_standalone_activity/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/hello_standalone_activity/count_activities.py b/hello_standalone_activity/count_activities.py new file mode 100644 index 00000000..14a89e7e --- /dev/null +++ b/hello_standalone_activity/count_activities.py @@ -0,0 +1,23 @@ +import asyncio + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + resp = await client.count_activities( + query="TaskQueue = 'my-standalone-activity-task-queue'", + ) + + print("Total activities:", resp.count) + + for group in resp.groups: + print(f"Group {group.group_values}: {group.count}") + + +if __name__ == "__main__": + asyncio.run(my_application()) diff --git a/hello_standalone_activity/execute_activity.py b/hello_standalone_activity/execute_activity.py new file mode 100644 index 00000000..529a1feb --- /dev/null +++ b/hello_standalone_activity/execute_activity.py @@ -0,0 +1,26 @@ +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +from hello_standalone_activity.my_activity import ComposeGreetingInput, compose_greeting + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + activity_result = await client.execute_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id="my-standalone-activity-id", + task_queue="my-standalone-activity-task-queue", + start_to_close_timeout=timedelta(seconds=10), + ) + print(f"Activity result: {activity_result}") + + +if __name__ == "__main__": + asyncio.run(my_application()) diff --git a/hello_standalone_activity/list_activities.py b/hello_standalone_activity/list_activities.py new file mode 100644 index 00000000..ef7af969 --- /dev/null +++ b/hello_standalone_activity/list_activities.py @@ -0,0 +1,23 @@ +import asyncio + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + activities = client.list_activities( + query="TaskQueue = 'my-standalone-activity-task-queue'", + ) + + async for info in activities: + print( + f"ActivityID: {info.activity_id}, Type: {info.activity_type}, Status: {info.status}" + ) + + +if __name__ == "__main__": + asyncio.run(my_application()) diff --git a/hello_standalone_activity/my_activity.py b/hello_standalone_activity/my_activity.py new file mode 100644 index 00000000..086b08a0 --- /dev/null +++ b/hello_standalone_activity/my_activity.py @@ -0,0 +1,15 @@ +from dataclasses import dataclass + +from temporalio import activity + + +@dataclass +class ComposeGreetingInput: + greeting: str + name: str + + +@activity.defn +def compose_greeting(input: ComposeGreetingInput) -> str: + activity.logger.info("Running activity with parameter %s" % input) + return f"{input.greeting}, {input.name}!" diff --git a/hello_standalone_activity/start_activity.py b/hello_standalone_activity/start_activity.py new file mode 100644 index 00000000..8aa9fa54 --- /dev/null +++ b/hello_standalone_activity/start_activity.py @@ -0,0 +1,31 @@ +import asyncio +from datetime import timedelta + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig + +from hello_standalone_activity.my_activity import ComposeGreetingInput, compose_greeting + + +async def my_application(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + + # Start the activity without waiting for the result + activity_handle = await client.start_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id="my-standalone-activity-id", + task_queue="my-standalone-activity-task-queue", + start_to_close_timeout=timedelta(seconds=10), + ) + print(f"Started activity: {activity_handle.id}") + + # Wait for the result + activity_result = await activity_handle.result() + print(f"Activity result: {activity_result}") + + +if __name__ == "__main__": + asyncio.run(my_application()) diff --git a/hello_standalone_activity/worker.py b/hello_standalone_activity/worker.py new file mode 100644 index 00000000..d093cc03 --- /dev/null +++ b/hello_standalone_activity/worker.py @@ -0,0 +1,26 @@ +import asyncio +from concurrent.futures import ThreadPoolExecutor + +from temporalio.client import Client +from temporalio.envconfig import ClientConfig +from temporalio.worker import Worker + +from hello_standalone_activity.my_activity import compose_greeting + + +async def main(): + connect_config = ClientConfig.load_client_connect_config() + connect_config.setdefault("target_host", "localhost:7233") + client = await Client.connect(**connect_config) + worker = Worker( + client, + task_queue="my-standalone-activity-task-queue", + activities=[compose_greeting], + activity_executor=ThreadPoolExecutor(5), + ) + print("worker running...", end="", flush=True) + await worker.run() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/tests/hello/hello_standalone_activity_test.py b/tests/hello/hello_standalone_activity_test.py new file mode 100644 index 00000000..d40b09fa --- /dev/null +++ b/tests/hello/hello_standalone_activity_test.py @@ -0,0 +1,31 @@ +import uuid +from concurrent.futures import ThreadPoolExecutor +from datetime import timedelta + +import pytest +from temporalio.client import Client +from temporalio.worker import Worker + +from hello_standalone_activity.my_activity import ComposeGreetingInput, compose_greeting + + +async def test_execute_standalone_activity(client: Client): + pytest.skip( + "Standalone Activity is not yet supported by `temporal server start-dev`" + ) + task_queue_name = str(uuid.uuid4()) + + async with Worker( + client, + task_queue=task_queue_name, + activities=[compose_greeting], + activity_executor=ThreadPoolExecutor(5), + ): + result = await client.execute_activity( + compose_greeting, + args=[ComposeGreetingInput("Hello", "World")], + id=str(uuid.uuid4()), + task_queue=task_queue_name, + start_to_close_timeout=timedelta(seconds=10), + ) + assert result == "Hello, World!" From ce5d8dda901374e0f0c416b74748afc0b4f95580 Mon Sep 17 00:00:00 2001 From: James Watkins-Harvey Date: Thu, 2 Apr 2026 17:16:33 -0400 Subject: [PATCH 39/40] Replace WorkflowIdReusePolicy.TerminateExisting by WorkflowIdConflictPolicy (#266) --- message_passing/safe_message_handlers/starter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/message_passing/safe_message_handlers/starter.py b/message_passing/safe_message_handlers/starter.py index 9bc5c661..c8f1b5d3 100644 --- a/message_passing/safe_message_handlers/starter.py +++ b/message_passing/safe_message_handlers/starter.py @@ -65,7 +65,7 @@ async def main(should_test_continue_as_new: bool): ClusterManagerInput(test_continue_as_new=should_test_continue_as_new), id=f"ClusterManagerWorkflow-{uuid.uuid4()}", task_queue="safe-message-handlers-task-queue", - id_reuse_policy=common.WorkflowIDReusePolicy.TERMINATE_IF_RUNNING, + id_conflict_policy=common.WorkflowIDConflictPolicy.TERMINATE_EXISTING, ) delay_seconds = 10 if should_test_continue_as_new else 1 await do_cluster_lifecycle(cluster_manager_handle, delay_seconds=delay_seconds) From 29fc4af7c1f350a30cd1d45b8ead4b3c9494aec4 Mon Sep 17 00:00:00 2001 From: xumaple <45406854+xumaple@users.noreply.github.com> Date: Wed, 15 Apr 2026 13:29:05 -0400 Subject: [PATCH 40/40] AI-18: Move set_tracing_disabled from workflow to worker startup (#288) * AI-18: Move set_tracing_disabled from workflow to worker startup set_tracing_disabled is a global side effect that shouldn't be called inside deterministic workflow code. Move it to the top of main() in the worker files where it runs once at process startup. Co-Authored-By: Claude Opus 4.6 (1M context) * AI-18: Add comment explaining why tracing is disabled at worker startup Co-Authored-By: Claude Opus 4.6 (1M context) * linting --------- Co-authored-by: Claude Opus 4.6 (1M context) --- openai_agents/model_providers/run_gpt_oss_worker.py | 12 +++++++++++- .../model_providers/run_litellm_provider_worker.py | 6 ++++++ .../model_providers/workflows/gpt_oss_workflow.py | 4 +--- .../workflows/litellm_auto_workflow.py | 4 +--- 4 files changed, 19 insertions(+), 7 deletions(-) diff --git a/openai_agents/model_providers/run_gpt_oss_worker.py b/openai_agents/model_providers/run_gpt_oss_worker.py index 88c85fca..59798a1d 100644 --- a/openai_agents/model_providers/run_gpt_oss_worker.py +++ b/openai_agents/model_providers/run_gpt_oss_worker.py @@ -3,7 +3,12 @@ from datetime import timedelta from typing import Optional -from agents import Model, ModelProvider, OpenAIChatCompletionsModel +from agents import ( + Model, + ModelProvider, + OpenAIChatCompletionsModel, + set_tracing_disabled, +) from openai import AsyncOpenAI from temporalio.client import Client from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin @@ -27,6 +32,11 @@ def get_model(self, model_name: Optional[str]) -> Model: async def main(): + # Disable Agents SDK tracing β€” the default exporter sends traces to OpenAI's + # backend, which requires an OpenAI API key not available in these samples. + # Call here rather than in the workflow because it's a global side effect. + set_tracing_disabled(disabled=True) + # Configure logging to show workflow debug messages logging.basicConfig(level=logging.WARNING) logging.getLogger("temporalio.workflow").setLevel(logging.DEBUG) diff --git a/openai_agents/model_providers/run_litellm_provider_worker.py b/openai_agents/model_providers/run_litellm_provider_worker.py index 5eb8b8b2..3441013c 100644 --- a/openai_agents/model_providers/run_litellm_provider_worker.py +++ b/openai_agents/model_providers/run_litellm_provider_worker.py @@ -1,6 +1,7 @@ import asyncio from datetime import timedelta +from agents import set_tracing_disabled from agents.extensions.models.litellm_provider import LitellmProvider from temporalio.client import Client from temporalio.contrib.openai_agents import ModelActivityParameters, OpenAIAgentsPlugin @@ -12,6 +13,11 @@ async def main(): + # Disable Agents SDK tracing β€” the default exporter sends traces to OpenAI's + # backend, which requires an OpenAI API key not available in these samples. + # Call here rather than in the workflow because it's a global side effect. + set_tracing_disabled(disabled=True) + # Create client connected to server at the given address client = await Client.connect( "localhost:7233", diff --git a/openai_agents/model_providers/workflows/gpt_oss_workflow.py b/openai_agents/model_providers/workflows/gpt_oss_workflow.py index d7ed8021..821844b3 100644 --- a/openai_agents/model_providers/workflows/gpt_oss_workflow.py +++ b/openai_agents/model_providers/workflows/gpt_oss_workflow.py @@ -1,6 +1,6 @@ from __future__ import annotations -from agents import Agent, Runner, function_tool, set_tracing_disabled +from agents import Agent, Runner, function_tool from temporalio import workflow @@ -8,8 +8,6 @@ class GptOssWorkflow: @workflow.run async def run(self, prompt: str) -> str: - set_tracing_disabled(disabled=True) - @function_tool def get_weather(city: str): workflow.logger.debug(f"Getting weather for {city}") diff --git a/openai_agents/model_providers/workflows/litellm_auto_workflow.py b/openai_agents/model_providers/workflows/litellm_auto_workflow.py index 4a67ded4..9fe3d40b 100644 --- a/openai_agents/model_providers/workflows/litellm_auto_workflow.py +++ b/openai_agents/model_providers/workflows/litellm_auto_workflow.py @@ -1,6 +1,6 @@ from __future__ import annotations -from agents import Agent, Runner, function_tool, set_tracing_disabled +from agents import Agent, Runner, function_tool from temporalio import workflow @@ -8,8 +8,6 @@ class LitellmAutoWorkflow: @workflow.run async def run(self, prompt: str) -> str: - set_tracing_disabled(disabled=True) - @function_tool def get_weather(city: str): return f"The weather in {city} is sunny."