From 69707e88799a60782288fea8cb52e3c5bd01a573 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=89=A7=E6=80=9D?= Date: Tue, 21 Jul 2026 10:31:27 +0800 Subject: [PATCH] feat: Support AgentScope GenAI instrumentation Add the opentelemetry-instrumentation-genai-agentscope package with v1/v2 support, chat/tool/agent spans, streaming, content capture, and a Weaver conformance scenario. Rebased onto current main and addressed review feedback: - Follow the established dependency/versioning pattern in pyproject.toml (>= x, Assisted-by: Claude Opus 4.8 --- .github/workflows/bump-package-major.yml | 1 + .github/workflows/bump-package-minor.yml | 1 + .github/workflows/prepare-backport-patch.yml | 1 + .github/workflows/prepare-release.yml | 1 + .github/workflows/release-package.yml | 1 + instrumentation/README.md | 1 + .../.changelog/.gitignore | 1 + .../.changelog/247.added | 1 + .../.gitignore | 3 + .../LICENSE | 201 ++ .../README.rst | 54 + .../pyproject.toml | 88 + .../genai/agentscope/__init__.py | 287 +++ .../genai/agentscope/_v2_middleware.py | 488 +++++ .../genai/agentscope/_wrapper.py | 329 ++++ .../genai/agentscope/message_converter.py | 673 +++++++ .../genai/agentscope/package.py | 33 + .../instrumentation/genai/agentscope/patch.py | 118 ++ .../instrumentation/genai/agentscope/utils.py | 576 ++++++ .../genai/agentscope/version.py | 4 + .../tests/__init__.py | 2 + .../tests/_test_helpers.py | 78 + ...Attributes.test_agent_span_attributes.yaml | 124 ++ ...tAgentBasic.test_agent_multiple_turns.yaml | 294 +++ ...TestAgentBasic.test_agent_simple_call.yaml | 99 + .../TestAgentBasic.test_agent_with_tool.yaml | 112 ++ ...ntError.test_agent_with_invalid_model.yaml | 126 ++ ...entCapture.test_span_content_disabled.yaml | 89 + ...test_span_content_with_span_and_event.yaml | 89 + ...ture.test_span_content_with_span_only.yaml | 84 + .../cassettes/orchestration_conformance.yaml | 321 +++ .../cassettes/test_model_call_async.yaml | 112 ++ .../cassettes/test_model_call_basic.yaml | 87 + .../test_model_call_multiple_sequential.yaml | 367 ++++ .../test_model_call_no_content_capture.yaml | 82 + .../cassettes/test_model_call_streaming.yaml | 92 + .../test_model_call_with_content_capture.yaml | 82 + .../test_model_call_with_messages.yaml | 89 + .../test_model_call_with_parameters.yaml | 155 ++ .../test_v2_agent_concurrent_e2e.yaml | 242 +++ .../test_v2_agent_non_streaming_e2e.yaml | 122 ++ .../test_v2_agent_streaming_e2e.yaml | 111 ++ .../tests/conformance/__init__.py | 2 + .../tests/conformance/orchestration.py | 148 ++ .../tests/conftest.py | 186 ++ .../tests/requirements.latest.txt | 43 + .../tests/requirements.oldest.txt | 22 + .../tests/test_agent.py | 183 ++ .../tests/test_call_chain_reentrancy.py | 74 + .../tests/test_conformance.py | 44 + .../tests/test_instrumentor.py | 95 + .../tests/test_model.py | 247 +++ .../tests/test_multimodal.py | 381 ++++ .../tests/test_span_content.py | 153 ++ .../tests/test_utils.py | 75 + .../tests/test_v2_instrumentation.py | 368 ++++ pyproject.toml | 1 + tox.ini | 20 + uv.lock | 1719 ++++++++++++++++- 59 files changed, 9577 insertions(+), 5 deletions(-) create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/.gitignore create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/247.added create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/.gitignore create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/LICENSE create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/README.rst create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/pyproject.toml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_v2_middleware.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_wrapper.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/message_converter.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/package.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/patch.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/utils.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/version.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/_test_helpers.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentAttributes.test_agent_span_attributes.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_multiple_turns.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_simple_call.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_with_tool.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentError.test_agent_with_invalid_model.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_disabled.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_and_event.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_only.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/orchestration_conformance.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_async.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_basic.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_multiple_sequential.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_no_content_capture.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_streaming.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_content_capture.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_messages.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_parameters.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_concurrent_e2e.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_non_streaming_e2e.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_streaming_e2e.yaml create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/__init__.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/orchestration.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conftest.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.oldest.txt create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_agent.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_call_chain_reentrancy.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_instrumentor.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_model.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_multimodal.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_span_content.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_utils.py create mode 100644 instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_v2_instrumentation.py diff --git a/.github/workflows/bump-package-major.yml b/.github/workflows/bump-package-major.yml index 4d7ad5b78..25ae988c0 100644 --- a/.github/workflows/bump-package-major.yml +++ b/.github/workflows/bump-package-major.yml @@ -5,6 +5,7 @@ on: package: type: choice options: + - opentelemetry-instrumentation-genai-agentscope - opentelemetry-instrumentation-genai-anthropic - opentelemetry-instrumentation-google-genai - opentelemetry-instrumentation-genai-langchain diff --git a/.github/workflows/bump-package-minor.yml b/.github/workflows/bump-package-minor.yml index 90445d14a..2907cc88e 100644 --- a/.github/workflows/bump-package-minor.yml +++ b/.github/workflows/bump-package-minor.yml @@ -5,6 +5,7 @@ on: package: type: choice options: + - opentelemetry-instrumentation-genai-agentscope - opentelemetry-instrumentation-genai-anthropic - opentelemetry-instrumentation-google-genai - opentelemetry-instrumentation-genai-langchain diff --git a/.github/workflows/prepare-backport-patch.yml b/.github/workflows/prepare-backport-patch.yml index b51e1b45b..59a98ed75 100644 --- a/.github/workflows/prepare-backport-patch.yml +++ b/.github/workflows/prepare-backport-patch.yml @@ -5,6 +5,7 @@ on: package: type: choice options: + - opentelemetry-instrumentation-genai-agentscope - opentelemetry-instrumentation-genai-anthropic - opentelemetry-instrumentation-google-genai - opentelemetry-instrumentation-genai-langchain diff --git a/.github/workflows/prepare-release.yml b/.github/workflows/prepare-release.yml index a70888d51..6a30ba660 100644 --- a/.github/workflows/prepare-release.yml +++ b/.github/workflows/prepare-release.yml @@ -6,6 +6,7 @@ on: type: choice options: - '' + - opentelemetry-instrumentation-genai-agentscope - opentelemetry-instrumentation-genai-anthropic - opentelemetry-instrumentation-google-genai - opentelemetry-instrumentation-genai-langchain diff --git a/.github/workflows/release-package.yml b/.github/workflows/release-package.yml index 4fad30758..7d6b5624d 100644 --- a/.github/workflows/release-package.yml +++ b/.github/workflows/release-package.yml @@ -5,6 +5,7 @@ on: package: type: choice options: + - opentelemetry-instrumentation-genai-agentscope - opentelemetry-instrumentation-genai-anthropic - opentelemetry-instrumentation-google-genai - opentelemetry-instrumentation-genai-langchain diff --git a/instrumentation/README.md b/instrumentation/README.md index 48ee952fe..cdcc741d3 100644 --- a/instrumentation/README.md +++ b/instrumentation/README.md @@ -1,6 +1,7 @@ | Instrumentation | Supported Packages | Metrics support | Semconv status | | --------------- | ------------------ | --------------- | -------------- | +| [opentelemetry-instrumentation-genai-agentscope](./opentelemetry-instrumentation-genai-agentscope) | agentscope >= 1.0.0, < 3.0.0 | No | development | [opentelemetry-instrumentation-genai-anthropic](./opentelemetry-instrumentation-genai-anthropic) | anthropic >= 0.16.0 | No | development | [opentelemetry-instrumentation-genai-claude-agent-sdk](./opentelemetry-instrumentation-genai-claude-agent-sdk) | claude-agent-sdk >= 0.1.14 | No | development | [opentelemetry-instrumentation-genai-langchain](./opentelemetry-instrumentation-genai-langchain) | langchain >= 0.3.21 | No | development diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/.gitignore b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/.gitignore new file mode 100644 index 000000000..f935021a8 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/.gitignore @@ -0,0 +1 @@ +!.gitignore diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/247.added b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/247.added new file mode 100644 index 000000000..354e9afc0 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.changelog/247.added @@ -0,0 +1 @@ +Add AgentScope instrumentation with v1/v2 support, tool execution spans, and Weaver conformance coverage. diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/.gitignore b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.gitignore new file mode 100644 index 000000000..b6abc5e16 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/.gitignore @@ -0,0 +1,3 @@ +examples/.env +examples/openai_agents_multi_agent_travel/.env +examples/**/.env diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/LICENSE b/instrumentation/opentelemetry-instrumentation-genai-agentscope/LICENSE new file mode 100644 index 000000000..d483259ea --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/LICENSE @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (which shall not include communication that is clearly marked or + otherwise designated in writing by the copyright owner as "Not a Work"). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based upon (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and derivative works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control + systems, and issue tracking systems that are managed by, or on behalf + of, the Licensor for the purpose of discussing and improving the Work, + but excluding communication that is clearly marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to use, reproduce, modify, distribute, and prepare + Derivative Works of, publicly display, publicly perform, sublicense, + and distribute the Work and such Derivative Works in Source or Object + form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, trademark, patent, + attribution and other notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright notice to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Support. When redistributing the Work or + Derivative Works thereof, You may choose to offer, and charge a fee + for, acceptance of support, warranty, indemnity, or other liability + obligations and/or rights consistent with this License. However, in + accepting such obligations, You may act only on Your own behalf and on + Your sole responsibility, not on behalf of any other Contributor, and + only if You agree to indemnify, defend, and hold each Contributor + harmless for any liability incurred by, or claims asserted against, + such Contributor by reason of your accepting any such warranty or support. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/README.rst b/instrumentation/opentelemetry-instrumentation-genai-agentscope/README.rst new file mode 100644 index 000000000..7a246ffbf --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/README.rst @@ -0,0 +1,54 @@ +OpenTelemetry AgentScope Instrumentation +======================================== + +|pypi| + +.. |pypi| image:: https://badge.fury.io/py/opentelemetry-instrumentation-genai-agentscope.svg + :target: https://pypi.org/project/opentelemetry-instrumentation-genai-agentscope/ + +This library allows tracing LLM, embedding, agent, and tool calls made by the +`AgentScope `_ framework. It +supports ``agentscope >= 1.0.0, < 3.0.0`` and emits telemetry through the shared +``opentelemetry-util-genai`` utilities following the GenAI semantic conventions. + +Installation +------------ + +:: + + pip install opentelemetry-instrumentation-genai-agentscope + +Usage +----- + +.. code-block:: python + + import asyncio + + from agentscope.model import DashScopeChatModel + + from opentelemetry.instrumentation.genai.agentscope import ( + AgentScopeInstrumentor, + ) + + AgentScopeInstrumentor().instrument() + + model = DashScopeChatModel(model_name="qwen-max") + messages = [{"role": "user", "content": "Hello, how are you?"}] + + asyncio.run(model(messages)) + + +Content capture +--------------- + +This instrumentation follows the shared ``opentelemetry-util-genai`` content +capture controls. Set ``OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT`` to +select whether prompt/response content is attached to spans and/or events; see +the ``opentelemetry-util-genai`` documentation for the supported capture modes. + +References +---------- + +* `OpenTelemetry Project `_ +* `OpenTelemetry Python Examples `_ diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/pyproject.toml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/pyproject.toml new file mode 100644 index 000000000..a118281c3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/pyproject.toml @@ -0,0 +1,88 @@ +[build-system] +requires = ["hatchling"] +build-backend = "hatchling.build" + +[project] +name = "opentelemetry-instrumentation-genai-agentscope" +dynamic = ["version"] +description = "OpenTelemetry AgentScope instrumentation" +readme = "README.rst" +license = "Apache-2.0" +requires-python = ">=3.10" +authors = [ + { name = "OpenTelemetry Authors", email = "cncf-opentelemetry-contributors@lists.cncf.io" }, +] +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", +] +dependencies = [ + "opentelemetry-api ~= 1.43", + "opentelemetry-instrumentation >= 0.64b0, <1", + "opentelemetry-semantic-conventions >= 0.64b0, <1", + "opentelemetry-util-genai >= 1.0b0, <2", +] + +[project.optional-dependencies] +instruments = [ + "agentscope >= 1.0.0, < 3.0.0", +] + +[project.entry-points.opentelemetry_instrumentor] +agentscope = "opentelemetry.instrumentation.genai.agentscope:AgentScopeInstrumentor" + +[project.urls] +Homepage = "https://github.com/open-telemetry/opentelemetry-python-genai/tree/main/instrumentation/opentelemetry-instrumentation-genai-agentscope" +Repository = "https://github.com/open-telemetry/opentelemetry-python-genai" + +[tool.hatch.version] +path = "src/opentelemetry/instrumentation/genai/agentscope/version.py" + +[tool.hatch.build.targets.sdist] +include = [ + "/src", +] + +[tool.hatch.build.targets.wheel] +packages = ["src/opentelemetry"] + +[tool.towncrier] +directory = ".changelog" +filename = "CHANGELOG.md" +start_string = "\n" +template = "../../scripts/changelog_template.j2" +issue_format = "[#{issue}](https://github.com/open-telemetry/opentelemetry-python-genai/pull/{issue})" +wrap = true +issue_pattern = "^(\\d+)" + +[[tool.towncrier.type]] +directory = "added" +name = "Added" +showcontent = true + +[[tool.towncrier.type]] +directory = "changed" +name = "Changed" +showcontent = true + +[[tool.towncrier.type]] +directory = "deprecated" +name = "Deprecated" +showcontent = true + +[[tool.towncrier.type]] +directory = "removed" +name = "Removed" +showcontent = true + +[[tool.towncrier.type]] +directory = "fixed" +name = "Fixed" +showcontent = true diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/__init__.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/__init__.py new file mode 100644 index 000000000..efd0314c3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/__init__.py @@ -0,0 +1,287 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +""" +AgentScope instrumentation supporting ``agentscope >= 1.0.0, < 3.0.0``. + +Usage +----- +.. code:: python + + import asyncio + from opentelemetry.instrumentation.genai.agentscope import ( + AgentScopeInstrumentor, + ) + from agentscope.model import DashScopeChatModel + + AgentScopeInstrumentor().instrument() + + model = DashScopeChatModel(model_name="qwen-max") + + messages = [{"role": "user", "content": "Hello, how are you?"}] + + async def call_model(): + response = await model(messages) + if hasattr(response, "__aiter__"): + result = [] + async for chunk in response: + result.append(chunk) + return result[-1] if result else response + return response + + result = asyncio.run(call_model()) + + AgentScopeInstrumentor().uninstrument() + +API +--- +""" + +from __future__ import annotations + +import logging +from importlib.metadata import PackageNotFoundError +from importlib.metadata import version as metadata_version +from typing import Any, Collection + +from wrapt import wrap_function_wrapper + +from opentelemetry.instrumentation.genai.agentscope.package import ( + get_installed_instrumentation_dependencies, +) +from opentelemetry.instrumentation.instrumentor import BaseInstrumentor +from opentelemetry.instrumentation.utils import unwrap +from opentelemetry.util.genai.handler import TelemetryHandler + +logger = logging.getLogger(__name__) + +_MODEL_MODULE = "agentscope.model" +_AGENT_MODULE = "agentscope.agent" +_EMBEDDING_MODULE = "agentscope.embedding" +_TOOL_MODULE = "agentscope.tool" + +__all__ = ["AgentScopeInstrumentor"] + + +class AgentScopeInstrumentor(BaseInstrumentor): + """OpenTelemetry instrumentor for the AgentScope framework.""" + + def __init__(self) -> None: + super().__init__() + self._handler: TelemetryHandler | None = None + self._agentscope_major: int | None = None + + def instrumentation_dependencies(self) -> Collection[str]: + return get_installed_instrumentation_dependencies() + + def _setup_tracing_patch(self, wrapped, instance, args, kwargs) -> None: # noqa: ARG002 + """Replace setup_tracing with a no-op so OTel handles tracing.""" + + def _check_tracing_enabled_patch( # noqa: ARG002 + self, wrapped, instance, args, kwargs + ) -> bool: + """Return False to disable tracing in the native AgentScope library.""" + return False + + def _instrument(self, **kwargs: Any) -> None: + tracer_provider = kwargs.get("tracer_provider") + meter_provider = kwargs.get("meter_provider") + logger_provider = kwargs.get("logger_provider") + + self._handler = TelemetryHandler( + tracer_provider=tracer_provider, + meter_provider=meter_provider, + logger_provider=logger_provider, + ) + + self._agentscope_major = _get_agentscope_major() + if self._agentscope_major >= 2: + self._instrument_v2() + else: + self._instrument_v1() + + def _instrument_v1(self) -> None: + from ._wrapper import ( # noqa: PLC0415 + AgentScopeAgentWrapper, + AgentScopeChatModelWrapper, + AgentScopeEmbeddingModelWrapper, + ) + from .patch import wrap_tool_call # noqa: PLC0415 + + try: + wrap_function_wrapper( + _MODEL_MODULE, + "ChatModelBase.__init__", + AgentScopeChatModelWrapper(handler=self._handler), + ) + except Exception as e: + logger.warning("Failed to instrument ChatModelBase: %s", e) + + try: + wrap_function_wrapper( + _AGENT_MODULE, + "AgentBase.__init__", + AgentScopeAgentWrapper(handler=self._handler), + ) + except Exception as e: + logger.warning("Failed to instrument AgentBase: %s", e) + + try: + wrap_function_wrapper( + _EMBEDDING_MODULE, + "EmbeddingModelBase.__init__", + AgentScopeEmbeddingModelWrapper(handler=self._handler), + ) + except Exception as e: + logger.warning("Failed to instrument EmbeddingModelBase: %s", e) + + try: + + def wrap_tool_with_handler(wrapped, instance, args, kwargs): + return wrap_tool_call( + wrapped, instance, args, kwargs, handler=self._handler + ) + + wrap_function_wrapper( + _TOOL_MODULE, + "Toolkit.call_tool_function", + wrap_tool_with_handler, + ) + except Exception as e: + logger.warning("Failed to instrument Toolkit: %s", e) + + # Disable AgentScope's native tracing to avoid duplicate spans. + try: + wrap_function_wrapper( + "agentscope.tracing", + "setup_tracing", + self._setup_tracing_patch, + ) + except Exception as e: + logger.warning("Failed to patch setup_tracing: %s", e) + + try: + wrap_function_wrapper( + "agentscope.tracing._trace", + "_check_tracing_enabled", + self._check_tracing_enabled_patch, + ) + except Exception as e: + logger.warning("Failed to patch _check_tracing_enabled: %s", e) + + def _uninstrument(self, **kwargs: Any) -> None: + del kwargs + if self._agentscope_major is None: + self._agentscope_major = _get_agentscope_major() + if self._agentscope_major >= 2: + self._uninstrument_v2() + else: + self._uninstrument_v1() + self._handler = None + self._agentscope_major = None + + def _uninstrument_v1(self) -> None: + try: + from ._wrapper import ( # noqa: PLC0415 + AgentScopeAgentWrapper, + AgentScopeChatModelWrapper, + AgentScopeEmbeddingModelWrapper, + ) + except Exception as e: + logger.warning("Failed to import AgentScope wrappers: %s", e) + AgentScopeAgentWrapper = None + AgentScopeChatModelWrapper = None + AgentScopeEmbeddingModelWrapper = None + + for wrapper_cls in ( + AgentScopeChatModelWrapper, + AgentScopeAgentWrapper, + AgentScopeEmbeddingModelWrapper, + ): + if wrapper_cls is not None: + try: + wrapper_cls.restore_original_methods() + except Exception as e: + logger.warning( + "Failed to restore %s methods: %s", + wrapper_cls.__name__, + e, + ) + + _unwrap_safely(_MODEL_MODULE, "ChatModelBase", "__init__") + _unwrap_safely(_AGENT_MODULE, "AgentBase", "__init__") + _unwrap_safely(_EMBEDDING_MODULE, "EmbeddingModelBase", "__init__") + _unwrap_safely(_TOOL_MODULE, "Toolkit", "call_tool_function") + + try: + import agentscope.tracing # noqa: PLC0415 + + unwrap(agentscope.tracing, "setup_tracing") + except Exception as e: + logger.warning("Failed to uninstrument setup_tracing: %s", e) + + try: + import agentscope.tracing._trace as agentscope_tracing_trace # noqa: PLC0415 + + unwrap(agentscope_tracing_trace, "_check_tracing_enabled") + except Exception as e: + logger.warning( + "Failed to uninstrument _check_tracing_enabled: %s", e + ) + + def _instrument_v2(self) -> None: + from ._v2_middleware import ( # noqa: PLC0415 + AgentScopeV2Middleware, + append_agentscope_middleware, + ) + + try: + + def wrap_agent_init(wrapped, instance, args, kwargs): + args, kwargs = append_agentscope_middleware( + args, + kwargs, + # Resolve the handler lazily so reinstrumentation uses the + # current handler instead of the one captured at init time. + AgentScopeV2Middleware(handler=lambda: self._handler), + ) + return wrapped(*args, **kwargs) + + wrap_function_wrapper( + _AGENT_MODULE, + "Agent.__init__", + wrap_agent_init, + ) + except Exception as e: + logger.warning("Failed to instrument AgentScope v2 Agent: %s", e) + + def _uninstrument_v2(self) -> None: + _unwrap_safely(_AGENT_MODULE, "Agent", "__init__") + + +def _unwrap_safely(module_name: str, class_name: str, method: str) -> None: + try: + module = __import__(module_name, fromlist=[class_name]) + target = getattr(module, class_name) + unwrap(target, method) + except Exception as e: + logger.warning( + "Failed to uninstrument %s.%s.%s: %s", + module_name, + class_name, + method, + e, + ) + + +def _get_agentscope_major() -> int: + try: + installed_version = metadata_version("agentscope") + except PackageNotFoundError: + return 1 + + major_text = installed_version.split(".", 1)[0] + try: + return int(major_text) + except ValueError: + return 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_v2_middleware.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_v2_middleware.py new file mode 100644 index 000000000..2fff3d526 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_v2_middleware.py @@ -0,0 +1,488 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""AgentScope v2 middleware instrumentation.""" + +from __future__ import annotations + +import inspect +import json +import logging +from collections.abc import AsyncGenerator, Awaitable, Callable, Sequence +from typing import Any +from urllib.parse import urlparse + +from agentscope.agent import Agent +from agentscope.message import Msg +from agentscope.middleware import MiddlewareBase +from agentscope.model import ChatModelBase, ChatResponse +from agentscope.tool import ToolResponse + +from opentelemetry.util.genai.handler import TelemetryHandler +from opentelemetry.util.genai.invocation import ( + AgentInvocation, + InferenceInvocation, +) +from opentelemetry.util.genai.types import ( + FunctionToolDefinition, + InputMessage, + MessagePart, + OutputMessage, + Reasoning, + Text, + ToolCallRequest, + ToolCallResponse, + ToolDefinition, +) + +logger = logging.getLogger(__name__) + +_MIDDLEWARE_PARAMETER = "middlewares" + + +def append_agentscope_middleware( + args: tuple[Any, ...], + kwargs: dict[str, Any], + middleware: "AgentScopeV2Middleware", +) -> tuple[tuple[Any, ...], dict[str, Any]]: + """Append the telemetry middleware to AgentScope v2 ``Agent.__init__`` inputs.""" + if _MIDDLEWARE_PARAMETER in kwargs: + kwargs = dict(kwargs) + kwargs[_MIDDLEWARE_PARAMETER] = _append_once( + kwargs.get(_MIDDLEWARE_PARAMETER), middleware + ) + return args, kwargs + + middleware_position = _middleware_arg_position() + if middleware_position is not None and len(args) > middleware_position: + updated_args = list(args) + updated_args[middleware_position] = _append_once( + updated_args[middleware_position], + middleware, + ) + return tuple(updated_args), kwargs + + kwargs = dict(kwargs) + kwargs[_MIDDLEWARE_PARAMETER] = [middleware] + return args, kwargs + + +def _append_once( + middlewares: Sequence[MiddlewareBase] | None, + middleware: "AgentScopeV2Middleware", +) -> list[MiddlewareBase]: + result = list(middlewares or []) + if any(isinstance(item, AgentScopeV2Middleware) for item in result): + return result + result.append(middleware) + return result + + +class AgentScopeV2Middleware(MiddlewareBase): + """Telemetry adapter for AgentScope v2 middleware hooks.""" + + def __init__(self, handler: Callable[[], TelemetryHandler | None]) -> None: + self._handler = handler + + async def on_reply( + self, + agent: Agent, + input_kwargs: dict, + next_handler: Callable[..., AsyncGenerator], + ) -> AsyncGenerator: + handler = self._handler() + if handler is None: + async for item in next_handler(**input_kwargs): + yield item + return + + invocation = _start_agent_invocation(handler, agent, input_kwargs) + last_msg = None + closed = False + try: + async for item in next_handler(**input_kwargs): + if isinstance(item, Msg): + last_msg = item + yield item + except GeneratorExit: + invocation.stop() + closed = True + raise + except BaseException as exc: + invocation.fail(exc) + closed = True + raise + else: + if last_msg is not None: + if handler.should_capture_content(): + invocation.output_messages = [_message_to_output(last_msg)] + if last_msg.usage is not None: + invocation.input_tokens = last_msg.usage.input_tokens + invocation.output_tokens = last_msg.usage.output_tokens + invocation.stop() + closed = True + finally: + if not closed: + invocation.stop() + + async def on_model_call( + self, + agent: Agent, + input_kwargs: dict, + next_handler: Callable[ + ..., + Awaitable[ChatResponse | AsyncGenerator[ChatResponse, None]], + ], + ) -> ChatResponse | AsyncGenerator[ChatResponse, None]: + model = input_kwargs.get("current_model") + if not isinstance(model, ChatModelBase): + return await next_handler(**input_kwargs) + + handler = self._handler() + if handler is None: + return await next_handler(**input_kwargs) + + invocation = _start_llm_invocation(handler, model, input_kwargs) + try: + result = await next_handler(**input_kwargs) + if inspect.isasyncgen(result): + return self._wrap_model_stream(result, invocation, handler) + + _finish_llm_invocation(invocation, result, handler) + invocation.stop() + return result + except BaseException as exc: + invocation.fail(exc) + raise + + async def _wrap_model_stream( + self, + result: AsyncGenerator[ChatResponse, None], + invocation: InferenceInvocation, + handler: TelemetryHandler, + ) -> AsyncGenerator[ChatResponse, None]: + last_chunk = None + closed = False + try: + async for chunk in result: + last_chunk = chunk + yield chunk + except GeneratorExit: + invocation.stop() + closed = True + raise + except BaseException as exc: + invocation.fail(exc) + closed = True + raise + else: + _finish_llm_invocation(invocation, last_chunk, handler) + invocation.stop() + closed = True + finally: + if not closed: + invocation.stop() + + async def on_acting( + self, + agent: Agent, + input_kwargs: dict, + next_handler: Callable[..., AsyncGenerator], + ) -> AsyncGenerator: + handler = self._handler() + if handler is None: + async for item in next_handler(**input_kwargs): + yield item + return + + tool_call = input_kwargs.get("tool_call") + invocation = handler.tool( + getattr(tool_call, "name", "unknown_tool"), + tool_call_id=getattr(tool_call, "id", None), + tool_type="function", + ) + if invocation.should_capture_content_on_span: + invocation.arguments = _loads_json( + getattr(tool_call, "input", None) + ) + last_item = None + closed = False + try: + async for item in next_handler(**input_kwargs): + last_item = item + yield item + except GeneratorExit: + invocation.stop() + closed = True + raise + except BaseException as exc: + invocation.fail(exc) + closed = True + raise + else: + if invocation.should_capture_content_on_span: + if isinstance(last_item, ToolResponse): + invocation.tool_result = _jsonable( + _blocks_to_parts(last_item.content) + ) + elif last_item is not None: + invocation.tool_result = str(last_item) + invocation.stop() + closed = True + finally: + if not closed: + invocation.stop() + + +def _start_agent_invocation( + handler: TelemetryHandler, + agent: Agent, + input_kwargs: dict[str, Any], +) -> AgentInvocation: + model = getattr(agent, "model", None) + request_model = getattr(model, "model", None) + invocation = handler.invoke_local_agent( + request_model=request_model, + agent_name=getattr(agent, "name", "unknown_agent"), + ) + invocation.provider = _get_provider_name(model) + session_id = getattr(getattr(agent, "state", None), "session_id", None) + invocation.agent_id = session_id + invocation.conversation_id = session_id + if handler.should_capture_content(): + invocation.input_messages = _messages_to_inputs( + input_kwargs.get("inputs") + ) + invocation.system_instruction = [ + Text(content=getattr(agent, "_system_prompt", "")) + ] + return invocation + + +def _start_llm_invocation( + handler: TelemetryHandler, + model: ChatModelBase, + input_kwargs: dict[str, Any], +) -> InferenceInvocation: + invocation = handler.inference( + _get_provider_name(model), + request_model=getattr(model, "model", None), + ) + server_address = _get_server_address(model) + if server_address is not None: + invocation.server_address = server_address + if handler.should_capture_content(): + invocation.input_messages = _messages_to_inputs( + input_kwargs.get("messages") + ) + invocation.tool_definitions = _tool_definitions(input_kwargs.get("tools")) + parameters = getattr(model, "parameters", None) + for source in (parameters, input_kwargs): + _set_if_present(invocation, "temperature", source) + _set_if_present(invocation, "top_p", source) + _set_if_present(invocation, "max_tokens", source) + return invocation + + +def _finish_llm_invocation( + invocation: InferenceInvocation, + response: ChatResponse | None, + handler: TelemetryHandler, +) -> None: + if response is None: + return + invocation.response_id = getattr(response, "id", None) + # AgentScope's ChatResponse carries no response model field, so mirror the + # request model (matching the v1 wrapper). + invocation.response_model_name = invocation.request_model + if handler.should_capture_content(): + invocation.output_messages = [_chat_response_to_output(response)] + else: + invocation.finish_reasons = [_response_finish_reason(response)] + usage = getattr(response, "usage", None) + if usage is not None: + invocation.input_tokens = getattr(usage, "input_tokens", None) + invocation.output_tokens = getattr(usage, "output_tokens", None) + + +def _messages_to_inputs(value: Any) -> list[InputMessage]: + if value is None: + return [] + if isinstance(value, Msg): + return [_message_to_input(value)] + if isinstance(value, list): + return [ + _message_to_input(item) for item in value if isinstance(item, Msg) + ] + return [] + + +def _message_to_input(msg: Msg) -> InputMessage: + return InputMessage(role=msg.role, parts=_blocks_to_parts(msg.content)) + + +def _message_to_output(msg: Msg) -> OutputMessage: + return OutputMessage( + role=msg.role, + parts=_blocks_to_parts(msg.content), + finish_reason="stop", + ) + + +def _response_finish_reason(response: ChatResponse) -> str: + if any( + getattr(block, "type", None) == "tool_call" + for block in response.content + ): + return "tool_calls" + return "stop" + + +def _chat_response_to_output(response: ChatResponse) -> OutputMessage: + return OutputMessage( + role="assistant", + parts=_blocks_to_parts(response.content), + finish_reason=_response_finish_reason(response), + ) + + +def _blocks_to_parts(blocks: Sequence[Any]) -> list[MessagePart]: + parts: list[MessagePart] = [] + for block in blocks: + block_type = getattr(block, "type", None) + if block_type == "text": + parts.append(Text(content=getattr(block, "text", ""))) + elif block_type == "thinking": + parts.append(Reasoning(content=getattr(block, "thinking", ""))) + elif block_type == "tool_call": + parts.append( + ToolCallRequest( + arguments=_loads_json(getattr(block, "input", None)), + name=getattr(block, "name", ""), + id=getattr(block, "id", None), + ) + ) + elif block_type == "tool_result": + parts.append( + ToolCallResponse( + response=_tool_result_response( + getattr(block, "output", "") + ), + id=getattr(block, "id", None), + ) + ) + return parts + + +def _tool_result_response(value: Any) -> Any: + if isinstance(value, (list, tuple)): + return _jsonable(_blocks_to_parts(value)) + return value + + +def _tool_definitions( + tools: list[dict[str, Any]] | None, +) -> list[ToolDefinition] | None: + if not tools: + return None + definitions: list[ToolDefinition] = [] + for tool in tools: + function = tool.get("function") if isinstance(tool, dict) else None + if not isinstance(function, dict): + continue + definitions.append( + FunctionToolDefinition( + name=function.get("name", ""), + description=function.get("description"), + parameters=function.get("parameters"), + ) + ) + return definitions or None + + +def _get_provider_name(model: Any) -> str: + class_name = model.__class__.__name__.lower() if model is not None else "" + if "dashscope" in class_name: + return "dashscope" + if "openai" in class_name: + return "openai" + if "anthropic" in class_name: + return "anthropic" + if "gemini" in class_name: + return "gcp.gen_ai" + if "ollama" in class_name: + return "ollama" + return "agentscope" + + +def _get_server_address(model: Any) -> str | None: + """Best-effort host for the ``server.address`` attribute on chat spans. + + Prefer an endpoint the model object exposes; DashScope models don't expose + one, so fall back to the dashscope SDK's global endpoint. + """ + for attr in ("base_http_api_url", "base_url"): + value = getattr(model, attr, None) + if isinstance(value, str) and value: + host = urlparse(value).hostname + if host: + return host + client = getattr(model, "client", None) + base_url = getattr(client, "base_url", None) + if base_url: + host = urlparse(str(base_url)).hostname + if host: + return host + if "dashscope" in model.__class__.__name__.lower(): + try: + import dashscope # noqa: PLC0415 + + host = urlparse(dashscope.base_http_api_url).hostname + if host: + return host + except Exception: + return "dashscope.aliyuncs.com" + return None + + +def _middleware_arg_position() -> int | None: + try: + parameters = list(inspect.signature(Agent.__init__).parameters) + return parameters.index(_MIDDLEWARE_PARAMETER) - 1 + except (TypeError, ValueError): + return None + + +def _loads_json(value: Any) -> Any: + if not isinstance(value, str): + return value + try: + return json.loads(value) + except ValueError: + return value + + +def _jsonable(value: Any) -> Any: + from dataclasses import asdict, is_dataclass # noqa: PLC0415 + + if is_dataclass(value) and not isinstance(value, type): + return _jsonable(asdict(value)) + if isinstance(value, (list, tuple)): + return [_jsonable(item) for item in value] + if isinstance(value, dict): + return {key: _jsonable(item) for key, item in value.items()} + return value + + +def _set_if_present( + invocation: InferenceInvocation, + field_name: str, + source: Any, +) -> None: + value = ( + source.get(field_name) + if isinstance(source, dict) + else getattr(source, field_name, None) + ) + if value is not None: + setattr(invocation, field_name, value) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_wrapper.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_wrapper.py new file mode 100644 index 000000000..c1a2e9e00 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/_wrapper.py @@ -0,0 +1,329 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Wrapper classes for AgentScope v1 instrumentation. + +Stacked ``ChatModelBase`` / ``AgentBase`` implementations (e.g. proxies where +each layer subclasses the base and ``__call__`` forwards to an inner model or +agent) share one logical invocation. A ``contextvars`` depth counter ensures +only the outermost ``__call__`` emits LLM / ``invoke_agent`` spans; inner +layers call through without duplicating telemetry. +""" + +from __future__ import annotations + +import contextvars +import logging +from collections.abc import AsyncGenerator +from functools import wraps +from typing import Any + +from opentelemetry.util.genai.handler import TelemetryHandler +from opentelemetry.util.genai.invocation import InferenceInvocation + +from .utils import ( + convert_agent_response_to_output_messages, + convert_chatresponse_to_output_messages, + start_agent_invocation, + start_embedding_invocation, + start_llm_invocation, +) + +logger = logging.getLogger(__name__) + +# Per-async-task nesting for stacked __call__ (proxy / decorator chains). +_CHAT_MODEL_CALL_DEPTH = contextvars.ContextVar( + "opentelemetry_agentscope_chat_model_call_depth", + default=0, +) +_AGENT_CALL_DEPTH = contextvars.ContextVar( + "opentelemetry_agentscope_agent_call_depth", + default=0, +) + + +class AgentScopeChatModelWrapper: + """Wrapper for ChatModelBase that hijacks __init__ to replace __call__.""" + + _original_methods: dict[type, dict[str, Any]] = {} + + def __init__(self, handler: TelemetryHandler) -> None: + self._handler = handler + self._instrumented_classes: set[type] = set() + + @classmethod + def restore_original_methods(cls) -> None: + """Restore all replaced original methods.""" + for class_obj, methods in cls._original_methods.items(): + for method_name, original_method in methods.items(): + setattr(class_obj, method_name, original_method) + cls._original_methods.clear() + + async def _wrap_streaming_response( + self, generator: AsyncGenerator, invocation: InferenceInvocation + ) -> AsyncGenerator: + """Wrap streaming response to finalize invocation once drained.""" + try: + last_chunk = None + async for chunk in generator: + last_chunk = chunk + yield chunk + + if last_chunk: + self._finish_llm(invocation, last_chunk) + + invocation.stop() + except GeneratorExit: + invocation.stop() + raise + except Exception as e: + invocation.fail(e) + raise + + def _finish_llm( + self, invocation: InferenceInvocation, result: Any + ) -> None: + if self._handler.should_capture_content(): + invocation.output_messages = ( + convert_chatresponse_to_output_messages(result) + ) + invocation.finish_reasons = ["stop"] + invocation.response_model_name = invocation.request_model + + if hasattr(result, "usage") and result.usage: + invocation.input_tokens = getattr( + result.usage, "input_tokens", None + ) + invocation.output_tokens = getattr( + result.usage, "output_tokens", None + ) + if hasattr(result, "id"): + invocation.response_id = getattr(result, "id", None) + + def __call__( + self, wrapped: Any, instance: Any, args: Any, kwargs: Any + ) -> Any: + """Hijack ChatModelBase.__init__ to replace the instance's __call__.""" + model_class = type(instance) + + if model_class in self._instrumented_classes: + return wrapped(*args, **kwargs) + + result = wrapped(*args, **kwargs) + + if not hasattr(model_class, "__call__") or not callable( + getattr(model_class, "__call__", None) + ): + return result + + original_call = model_class.__call__ + self._original_methods.setdefault(model_class, {})["__call__"] = ( + original_call + ) + handler = self._handler + + @wraps(original_call) + async def async_wrapped_call( + call_self: Any, *call_args: Any, **call_kwargs: Any + ) -> Any: + parent_depth = _CHAT_MODEL_CALL_DEPTH.get() + depth_token = _CHAT_MODEL_CALL_DEPTH.set(parent_depth + 1) + try: + if parent_depth > 0: + return await original_call( + call_self, *call_args, **call_kwargs + ) + + invocation = start_llm_invocation( + handler, call_self, call_args, call_kwargs + ) + + try: + result = await original_call( + call_self, *call_args, **call_kwargs + ) + + if isinstance(result, AsyncGenerator): + return self._wrap_streaming_response( + result, invocation + ) + + self._finish_llm(invocation, result) + invocation.stop() + return result + except Exception as e: + invocation.fail(e) + raise + finally: + _CHAT_MODEL_CALL_DEPTH.reset(depth_token) + + instance.__class__.__call__ = async_wrapped_call + self._instrumented_classes.add(model_class) + return result + + +class AgentScopeAgentWrapper: + """Wrapper for AgentBase that hijacks __init__ to replace __call__.""" + + _original_methods: dict[type, dict[str, Any]] = {} + + def __init__(self, handler: TelemetryHandler) -> None: + self._handler = handler + self._instrumented_classes: set[type] = set() + + @classmethod + def restore_original_methods(cls) -> None: + """Restore all replaced original methods.""" + for class_obj, methods in cls._original_methods.items(): + for method_name, original_method in methods.items(): + setattr(class_obj, method_name, original_method) + cls._original_methods.clear() + + def __call__( + self, wrapped: Any, instance: Any, args: Any, kwargs: Any + ) -> Any: + """Hijack AgentBase.__init__ to replace the instance's __call__.""" + agent_class = type(instance) + + if agent_class in self._instrumented_classes: + return wrapped(*args, **kwargs) + + result = wrapped(*args, **kwargs) + + if not hasattr(agent_class, "__call__") or not callable( + getattr(agent_class, "__call__", None) + ): + return result + + original_call = agent_class.__call__ + self._original_methods.setdefault(agent_class, {})["__call__"] = ( + original_call + ) + handler = self._handler + + @wraps(original_call) + async def async_wrapped_call( + call_self: Any, *call_args: Any, **call_kwargs: Any + ) -> Any: + parent_depth = _AGENT_CALL_DEPTH.get() + depth_token = _AGENT_CALL_DEPTH.set(parent_depth + 1) + try: + if parent_depth > 0: + return await original_call( + call_self, *call_args, **call_kwargs + ) + + try: + invocation = start_agent_invocation( + handler, call_self, call_args, call_kwargs + ) + except Exception as e: + logger.exception( + "Error starting agent instrumentation: %s", e + ) + return await original_call( + call_self, *call_args, **call_kwargs + ) + + try: + agent_result = await original_call( + call_self, *call_args, **call_kwargs + ) + + if handler.should_capture_content(): + invocation.output_messages = ( + convert_agent_response_to_output_messages( + agent_result + ) + ) + invocation.stop() + return agent_result + except Exception as e: + invocation.fail(e) + raise + finally: + _AGENT_CALL_DEPTH.reset(depth_token) + + instance.__class__.__call__ = async_wrapped_call + self._instrumented_classes.add(agent_class) + return result + + +class AgentScopeEmbeddingModelWrapper: + """Wrapper for EmbeddingModelBase that hijacks __init__ to replace __call__.""" + + _original_methods: dict[type, dict[str, Any]] = {} + + def __init__(self, handler: TelemetryHandler) -> None: + self._handler = handler + self._instrumented_classes: set[type] = set() + + @classmethod + def restore_original_methods(cls) -> None: + """Restore all replaced original methods.""" + for class_obj, methods in cls._original_methods.items(): + for method_name, original_method in methods.items(): + setattr(class_obj, method_name, original_method) + cls._original_methods.clear() + + def __call__( + self, wrapped: Any, instance: Any, args: Any, kwargs: Any + ) -> Any: + """Hijack EmbeddingModelBase.__init__ to replace __call__.""" + embedding_class = type(instance) + + if embedding_class in self._instrumented_classes: + return wrapped(*args, **kwargs) + + result = wrapped(*args, **kwargs) + + if not hasattr(embedding_class, "__call__") or not callable( + getattr(embedding_class, "__call__", None) + ): + return result + + original_call = embedding_class.__call__ + self._original_methods.setdefault(embedding_class, {})["__call__"] = ( + original_call + ) + handler = self._handler + + @wraps(original_call) + async def async_wrapped_call( + call_self: Any, *call_args: Any, **call_kwargs: Any + ) -> Any: + invocation = start_embedding_invocation( + handler, call_self, call_args, call_kwargs + ) + + try: + embedding_result = await original_call( + call_self, *call_args, **call_kwargs + ) + + if ( + hasattr(embedding_result, "embeddings") + and embedding_result.embeddings + ): + invocation.dimension_count = len( + embedding_result.embeddings[0] + ) + if ( + hasattr(embedding_result, "usage") + and embedding_result.usage + ): + tokens = getattr(embedding_result.usage, "tokens", None) + if tokens is not None: + invocation.input_tokens = tokens + + invocation.response_model_name = invocation.request_model + + invocation.stop() + return embedding_result + except Exception as e: + invocation.fail(e) + raise + + instance.__class__.__call__ = async_wrapped_call + self._instrumented_classes.add(embedding_class) + return result diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/message_converter.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/message_converter.py new file mode 100644 index 000000000..22a39f574 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/message_converter.py @@ -0,0 +1,673 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Message format converter for AgentScope instrumentation. + +This module provides utilities to convert messages from different AI model providers +into a unified format for OpenTelemetry instrumentation and frontend display. +""" + +from __future__ import annotations + +import json +import logging +from abc import ABC, abstractmethod +from typing import Any, Callable, Dict, List, Optional + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + +logger = logging.getLogger(__name__) + + +def _create_text_part_dict(content: str) -> Dict[str, Any]: + """Create text part as dict""" + return {"type": "text", "content": content} + + +def _create_tool_call_part_dict( + name: str, + call_id: Optional[str] = None, + arguments: Optional[Dict[str, Any]] = None, +) -> Dict[str, Any]: + """Create tool call part as dict""" + part = {"type": "tool_call", "name": name} + if call_id is not None: + part["id"] = call_id + if arguments is not None: + part["arguments"] = arguments + return part + + +def _create_tool_response_part_dict( + response: Any, + call_id: Optional[str] = None, +) -> Dict[str, Any]: + """Create tool response part as dict""" + part = {"type": "tool_call_response", "response": response} + if call_id is not None: + part["id"] = call_id + return part + + +def _create_generic_part_dict(part_type: str, **kwargs: Any) -> Dict[str, Any]: + """Create generic part as dict""" + part = {"type": part_type} + part.update(kwargs) + return part + + +class BaseMessageParser(ABC): + """Base class for message parsers""" + + @abstractmethod + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + """Parse single message to unified dict format with role and parts""" + pass + + def parse_messages( + self, messages: List[Dict[str, Any]] + ) -> List[Dict[str, Any]]: + """Parse message list to unified dict format""" + parsed_messages = [] + for msg in messages: + try: + parsed_msg = self.parse_message(msg) + if parsed_msg.get("parts"): # Only add messages with content + parsed_messages.append(parsed_msg) + except Exception as e: + logger.warning(f"Failed to parse message: {e}, message: {msg}") + continue + return parsed_messages + + def _get_role(self, msg: Dict[str, Any]) -> str: + """Get role with role mapping support""" + role = msg.get("role", "user") + # Gemini special handling + if role == "model": + return "assistant" + return role + + def _safe_json_loads(self, text: str) -> Dict[str, Any]: + """Safe JSON parsing""" + if isinstance(text, dict): + return text + try: + return json.loads(text) if isinstance(text, str) else {} + except json.JSONDecodeError: + return {} + + +class OpenAIMessageParser(BaseMessageParser): + """OpenAIformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + # Handle tool messages + if role == "tool": + part = _create_tool_response_part_dict( + response=msg.get("content", ""), + call_id=msg.get("tool_call_id", ""), + ) + parts.append(part) + else: + # Handle tool_calls + if "tool_calls" in msg and msg["tool_calls"]: + for tool_call in msg["tool_calls"]: + function_info = tool_call.get("function", {}) + arguments = self._safe_json_loads( + function_info.get("arguments", "{}") + ) + + part = _create_tool_call_part_dict( + name=function_info.get("name", "unknown_tool"), + call_id=tool_call.get("id", "unknown_id"), + arguments=arguments, + ) + parts.append(part) + + # Handle content + content = msg.get("content") + if isinstance(content, str): + if content.strip(): + parts.append(_create_text_part_dict(content)) + elif isinstance(content, list): + parts.extend(self._parse_content_list(content)) + + # Add empty text part if no parts and no tool_calls + if not parts and not msg.get("tool_calls"): + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + def _parse_content_list( + self, content_list: List[Any] + ) -> List[Dict[str, Any]]: + """Parse content list""" + parts = [] + for item in content_list: + if isinstance(item, dict): + content_type = item.get("type", "text") + if content_type == "text": + text_content = item.get("text", "") + if text_content: + parts.append(_create_text_part_dict(text_content)) + elif content_type == "image_url": + image_url = item.get("image_url", {}).get("url", "") + if image_url: + parts.append( + _create_generic_part_dict( + "image", content=image_url + ) + ) + elif content_type == "input_audio": + audio_data = item.get("input_audio", {}).get("data", "") + if audio_data: + parts.append( + _create_generic_part_dict( + "audio", content=audio_data + ) + ) + else: + parts.append( + _create_generic_part_dict( + content_type, + content=str(item), + hint="unsupported content type", + ) + ) + elif isinstance(item, str): + parts.append(_create_text_part_dict(item)) + return parts + + +class AnthropicMessageParser(BaseMessageParser): + """Anthropicformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + content = msg.get("content", []) + if isinstance(content, str): + parts.append(_create_text_part_dict(content)) + elif isinstance(content, list): + parts.extend(self._parse_content_list(content)) + + if not parts: + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + def _parse_content_list( + self, content_list: List[Any] + ) -> List[Dict[str, Any]]: + """Parse Anthropic content list""" + parts = [] + for item in content_list: + if isinstance(item, dict): + content_type = item.get("type", "text") + if content_type == "text": + text_content = item.get("text") + if not text_content: + continue + parts.append(_create_text_part_dict(text_content)) + elif content_type == "tool_use": + parts.append( + _create_tool_call_part_dict( + name=item.get("name", ""), + call_id=item.get("id", ""), + arguments=item.get("input", {}), + ) + ) + elif content_type == "tool_result": + result_text = self._extract_tool_result( + item.get("content", []) + ) + parts.append( + _create_tool_response_part_dict( + response=result_text, + call_id=item.get("tool_use_id", ""), + ) + ) + elif content_type == "image": + source = item.get("source", {}) + if source.get("type") == "url": + parts.append( + _create_generic_part_dict( + "image", content=source.get("url", "") + ) + ) + elif source.get("type") == "base64": + content_url = f"data:{source.get('media_type', 'image/png')};base64,{source.get('data', '')}" + parts.append( + _create_generic_part_dict( + "image", content=content_url + ) + ) + else: + parts.append( + _create_generic_part_dict( + content_type, + content=str(item), + hint="unsupported content type", + ) + ) + elif isinstance(item, str): + parts.append(_create_text_part_dict(item)) + return parts + + def _extract_tool_result(self, content_blocks: List[Any]) -> str: + """Extract tool call result""" + if isinstance(content_blocks, list): + result_text = "" + for block in content_blocks: + if isinstance(block, dict) and block.get("type") == "text": + result_text += block.get("text", "") + return result_text + return str(content_blocks) + + +class GeminiMessageParser(BaseMessageParser): + """Geminiformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + parts_list = msg.get("parts", []) + if isinstance(parts_list, list): + parts.extend(self._parse_parts_list(parts_list)) + + if not parts: + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + def _parse_parts_list(self, parts_list: List[Any]) -> List[Dict[str, Any]]: + """Parse Gemini parts list""" + parts = [] + for item in parts_list: + if isinstance(item, dict): + if "text" in item: + if not item["text"]: + continue + parts.append(_create_text_part_dict(item["text"])) + elif "function_call" in item: + func_call = item["function_call"] + parts.append( + _create_tool_call_part_dict( + name=func_call.get("name", ""), + call_id=func_call.get("id", ""), + arguments=func_call.get("args", {}), + ) + ) + elif "function_response" in item: + func_resp = item["function_response"] + response_content = func_resp.get("response", {}) + result_text = ( + response_content.get("output", "") + if isinstance(response_content, dict) + else str(response_content) + ) + parts.append( + _create_tool_response_part_dict( + response=result_text, + call_id=func_resp.get("id", ""), + ) + ) + elif "inline_data" in item: + parts.append(self._parse_inline_data(item["inline_data"])) + else: + parts.append( + _create_generic_part_dict( + "unknown", + content=str(item), + hint="unsupported part type", + ) + ) + elif isinstance(item, str): + parts.append(_create_text_part_dict(item)) + return parts + + def _parse_inline_data( + self, inline_data: Dict[str, Any] + ) -> Dict[str, Any]: + """Parse inline data""" + mime_type = inline_data.get("mime_type", "") + data = inline_data.get("data", "") + + if mime_type.startswith("image/"): + return _create_generic_part_dict( + "image", content=f"data:{mime_type};base64,{data}" + ) + elif mime_type.startswith("audio/"): + return _create_generic_part_dict("audio", content=data) + else: + return _create_generic_part_dict( + "unknown", + content=str(inline_data), + hint="unsupported inline_data type", + ) + + +class DashScopeMessageParser(BaseMessageParser): + """DashScopeformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + # Handle tool messages + if role == "tool": + parts.append( + _create_tool_response_part_dict( + response=msg.get("content", ""), + call_id=msg.get("tool_call_id", ""), + ) + ) + else: + # Handle tool_calls + if "tool_calls" in msg and msg["tool_calls"]: + for tool_call in msg["tool_calls"]: + function_info = tool_call.get("function", {}) + arguments = self._safe_json_loads( + function_info.get("arguments", "{}") + ) + + parts.append( + _create_tool_call_part_dict( + name=function_info.get("name", ""), + call_id=tool_call.get("id", ""), + arguments=arguments, + ) + ) + + # Handle content + content = msg.get("content") + if isinstance(content, str) and content.strip(): + parts.append(_create_text_part_dict(content)) + elif isinstance(content, list): + parts.extend(self._parse_content_list(content)) + + if not parts and not msg.get("tool_calls"): + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + def _parse_content_list( + self, content_list: List[Any] + ) -> List[Dict[str, Any]]: + """Parse DashScope content list""" + parts = [] + for item in content_list: + if isinstance(item, dict): + if "text" in item: + if not item["text"]: + continue + parts.append(_create_text_part_dict(item["text"])) + elif "image" in item: + parts.append( + _create_generic_part_dict( + "image", content=item["image"] + ) + ) + elif "audio" in item: + parts.append( + _create_generic_part_dict( + "audio", content=item["audio"] + ) + ) + else: + parts.append( + _create_generic_part_dict( + "unknown", + content=str(item), + hint="unsupported content type", + ) + ) + elif isinstance(item, str): + parts.append(_create_text_part_dict(item)) + return parts + + +class OllamaMessageParser(BaseMessageParser): + """Ollamaformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + # Handle tool messages + if role == "tool": + parts.append( + _create_tool_response_part_dict( + response=msg.get("content", ""), + call_id=msg.get("tool_call_id", ""), + ) + ) + else: + # Handle tool_calls + if "tool_calls" in msg and msg["tool_calls"]: + for tool_call in msg["tool_calls"]: + function_info = tool_call.get("function", {}) + parts.append( + _create_tool_call_part_dict( + name=function_info.get("name", ""), + call_id=tool_call.get("id", ""), + arguments=function_info.get("arguments", {}), + ) + ) + + # Handle text content + content = msg.get("content") + if isinstance(content, str) and content.strip(): + parts.append(_create_text_part_dict(content)) + elif content is None and not msg.get("tool_calls"): + parts.append(_create_text_part_dict("")) + + # Handle images (Ollama-specific images field) + if "images" in msg and msg["images"]: + for image_data in msg["images"]: + if isinstance(image_data, str): + parts.append( + _create_generic_part_dict( + "image", + content=f"data:image/png;base64,{image_data}", + ) + ) + else: + parts.append( + _create_generic_part_dict( + "image", content=str(image_data) + ) + ) + + if not parts and not msg.get("tool_calls"): + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + +class DeepSeekMessageParser(BaseMessageParser): + """DeepSeekformat message parser""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + # Handle tool messages + if role == "tool": + parts.append( + _create_tool_response_part_dict( + response=msg.get("content", ""), + call_id=msg.get("tool_call_id", ""), + ) + ) + else: + # Handle tool_calls + if "tool_calls" in msg and msg["tool_calls"]: + for tool_call in msg["tool_calls"]: + function_info = tool_call.get("function", {}) + arguments = self._safe_json_loads( + function_info.get("arguments", "{}") + ) + + parts.append( + _create_tool_call_part_dict( + name=function_info.get("name", ""), + call_id=tool_call.get("id", ""), + arguments=arguments, + ) + ) + + # Handle content + content = msg.get("content") + if isinstance(content, str) and content and content.strip(): + parts.append(_create_text_part_dict(content)) + elif content is None and msg.get("tool_calls"): + # DeepSeekcontent may be None when tool_calls present + pass # No need to add empty text + elif isinstance(content, list): + parts.extend(self._parse_content_list(content)) + + if not parts and not msg.get("tool_calls"): + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + def _parse_content_list( + self, content_list: List[Any] + ) -> List[Dict[str, Any]]: + """Parse DeepSeek content list""" + parts = [] + for item in content_list: + if isinstance(item, dict): + content_type = item.get("type", "text") + if content_type == "text": + text_content = item.get("text") + if not text_content: + continue + parts.append(_create_text_part_dict(text_content)) + else: + parts.append( + _create_generic_part_dict( + content_type, + content=str(item), + hint="unsupported content type", + ) + ) + elif isinstance(item, str): + parts.append(_create_text_part_dict(item)) + return parts + + +class DefaultMessageParser(BaseMessageParser): + """Default message parser for unknown formats""" + + def parse_message(self, msg: Dict[str, Any]) -> Dict[str, Any]: + role = self._get_role(msg) + parts = [] + + # Try to extract text from content field + content = msg.get("content", "") + if isinstance(content, str) and content.strip(): + parts.append(_create_text_part_dict(content)) + elif isinstance(content, list): + # Try to parse list format content + for item in content: + if isinstance(item, dict): + if "text" in item: + if not item["text"]: + continue + parts.append(_create_text_part_dict(str(item["text"]))) + else: + parts.append( + _create_generic_part_dict( + "unknown", + content=str(item), + hint="unknown format", + ) + ) + else: + parts.append(_create_text_part_dict(str(item))) + else: + parts.append(_create_text_part_dict(str(msg))) + + if not parts: + parts.append(_create_text_part_dict("")) + + return {"role": role, "parts": parts} + + +def get_message_converter( + provide_name: Optional[str], +) -> Callable[[List[Dict[str, Any]]], List[Dict[str, Any]]]: + """ + Return appropriate message format converter based on model type。 + + Args: + provide_name: AI model provider + + Returns: + Corresponding message conversion function with signature: + (messages: List[Dict[str, Any]]) -> List[Dict[str, Any]] + + Converted unified format complies with JSON Schema standard: + [ + { + "role": "user|assistant|tool|system", + "parts": [ + { + "type": "text", + "content": "..." + }, + { + "type": "tool_call", + "name": "...", + "id": "...", + "arguments": {...} + }, + { + "type": "tool_call_response", + "response": "...", + "id": "..." + } + ] + } + ] + """ + # Select corresponding parser + if provide_name == GenAIAttributes.GenAiProviderNameValues.OPENAI.value: + parser = OpenAIMessageParser() + elif ( + provide_name == GenAIAttributes.GenAiProviderNameValues.ANTHROPIC.value + ): + parser = AnthropicMessageParser() + elif ( + provide_name + == GenAIAttributes.GenAiProviderNameValues.GCP_GEMINI.value + ): + parser = GeminiMessageParser() + elif ( + provide_name == GenAIAttributes.GenAiProviderNameValues.DEEPSEEK.value + ): + parser = DeepSeekMessageParser() + elif ( + provide_name == "dashscope" + ): # AgentScopeGenAiProviderName.DASHSCOPE.value + parser = DashScopeMessageParser() + elif provide_name == "ollama": # AgentScopeGenAiProviderName.OLLAMA.value + parser = OllamaMessageParser() + elif ( + provide_name == "moonshot" + ): # AgentScopeGenAiProviderName.MOONSHOT.value + # Moonshot uses OpenAI-compatible API format + parser = OpenAIMessageParser() + else: + parser = DefaultMessageParser() + + return parser.parse_messages diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/package.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/package.py new file mode 100644 index 000000000..cd809e9aa --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/package.py @@ -0,0 +1,33 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +from __future__ import annotations + +from importlib.metadata import PackageNotFoundError, version + +_instruments_v1 = ("agentscope >= 1.0.0, < 2.0.0",) +_instruments_v2 = ("agentscope >= 2.0.0, < 3.0.0",) +_instruments = ("agentscope >= 1.0.0, < 3.0.0",) + +_supports_metrics = False + + +def get_installed_instrumentation_dependencies() -> tuple[str, ...]: + """Return the AgentScope dependency range matching the installed major.""" + # Imported lazily so tooling that execs this module (e.g. the instrumentation + # README generator) does not require ``packaging`` to be installed. + from packaging.requirements import Requirement # noqa: PLC0415 + + try: + installed_version = version("agentscope") + except PackageNotFoundError: + return _instruments + + for requirement in (_instruments_v2[0], _instruments_v1[0]): + if Requirement(requirement).specifier.contains( + installed_version, + prereleases=True, + ): + return (requirement,) + + return _instruments diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/patch.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/patch.py new file mode 100644 index 000000000..788adf616 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/patch.py @@ -0,0 +1,118 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Patch functions for AgentScope v1 tool instrumentation.""" + +from __future__ import annotations + +import logging +from typing import Any + +from opentelemetry.util.genai.handler import TelemetryHandler +from opentelemetry.util.genai.invocation import ToolInvocation + +logger = logging.getLogger(__name__) + + +def _get_tool_description(instance: Any, tool_name: str | None) -> str | None: + """Get tool description from toolkit.""" + if ( + not tool_name + or not hasattr(instance, "tools") + or not isinstance(instance.tools, dict) + ): + return None + + tool_obj = instance.tools.get(tool_name) + if not tool_obj: + return None + + json_schema = getattr(tool_obj, "json_schema", None) + if isinstance(json_schema, dict): + func_dict = json_schema.get("function", {}) + if isinstance(func_dict, dict): + description = func_dict.get("description") + if description: + return description + + return getattr(tool_obj, "description", None) + + +def _get_tool_result(chunk: Any) -> Any: + """Extract tool result from chunk.""" + if chunk is None: + return None + if hasattr(chunk, "content"): + return chunk.content + return chunk + + +async def _trace_async_generator_wrapper( + result_generator: Any, invocation: ToolInvocation +) -> Any: + """Trace tool execution by wrapping the async generator it returns. + + Collects the last yielded chunk to populate the tool result, then + finalizes the invocation once the generator is fully drained. + """ + last_chunk = None + try: + async for chunk in result_generator: + last_chunk = chunk + yield chunk + except GeneratorExit: + invocation.stop() + raise + except Exception as e: + invocation.fail(e) + raise + else: + if ( + last_chunk is not None + and invocation.should_capture_content_on_span + ): + result_content = _get_tool_result(last_chunk) + if result_content is not None: + invocation.tool_result = result_content + invocation.stop() + + +async def wrap_tool_call( + wrapped: Any, + instance: Any, + args: Any, + kwargs: Any, + handler: TelemetryHandler, +) -> Any: + """Async wrapper for ``Toolkit.call_tool_function``.""" + tool_call = args[0] if args else kwargs.get("tool_call", {}) + tool_name = ( + tool_call.get("name", "unknown_tool") + if isinstance(tool_call, dict) + else "unknown_tool" + ) + tool_id = tool_call.get("id") if isinstance(tool_call, dict) else None + tool_args = ( + tool_call.get("input", {}) if isinstance(tool_call, dict) else {} + ) + + tool_description = _get_tool_description(instance, tool_name) + + # NOTE: tool_type is set to "function" as agentscope currently only + # supports function-type tools. Update when other types are supported. + invocation = handler.tool( + tool_name, + tool_call_id=tool_id, + tool_type="function", + tool_description=tool_description, + ) + if invocation.should_capture_content_on_span: + invocation.arguments = tool_args + + try: + result_generator = await wrapped(*args, **kwargs) + except Exception as error: + invocation.fail(error) + raise + + return _trace_async_generator_wrapper(result_generator, invocation) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/utils.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/utils.py new file mode 100644 index 000000000..cf1fe4821 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/utils.py @@ -0,0 +1,576 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Data-extraction helpers for AgentScope instrumentation. + +These helpers translate AgentScope request/response objects into the +``opentelemetry-util-genai`` invocation model. Invocations are always created +through the public :class:`~opentelemetry.util.genai.handler.TelemetryHandler` +factory methods (``inference``/``embedding``/``invoke_local_agent``) — never +constructed directly. +""" + +from __future__ import annotations + +import base64 +import datetime +import enum +import inspect +import json +import logging +import mimetypes +from dataclasses import is_dataclass +from enum import Enum +from typing import Any, Dict, List, Optional, Tuple +from urllib.parse import urlparse + +from agentscope import _config +from agentscope.agent import AgentBase +from agentscope.embedding import EmbeddingModelBase +from agentscope.message import Msg +from agentscope.model import ChatModelBase, ChatResponse +from pydantic import BaseModel + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) +from opentelemetry.util.genai.handler import TelemetryHandler +from opentelemetry.util.genai.invocation import ( + AgentInvocation, + EmbeddingInvocation, + InferenceInvocation, +) +from opentelemetry.util.genai.types import ( + Blob, + FunctionToolDefinition, + GenericPart, + InputMessage, + MessagePart, + OutputMessage, + Reasoning, + Text, + ToolCallRequest, + ToolCallResponse, + ToolDefinition, + Uri, +) + +from .message_converter import get_message_converter + +logger = logging.getLogger(__name__) + + +class AgentScopeGenAiProviderName(str, Enum): + """Extended provider names not in standard OpenTelemetry semantic conventions.""" + + OLLAMA = "ollama" + DASHSCOPE = "dashscope" + MOONSHOT = "moonshot" + + +# Provider name mapping based on class names +_PROVIDER_NAME_MAP = { + "openai": GenAIAttributes.GenAiProviderNameValues.OPENAI.value, + "gemini": GenAIAttributes.GenAiProviderNameValues.GCP_GEMINI.value, + "anthropic": GenAIAttributes.GenAiProviderNameValues.ANTHROPIC.value, + "dashscope": AgentScopeGenAiProviderName.DASHSCOPE.value, + "ollama": AgentScopeGenAiProviderName.OLLAMA.value, +} + +# Base URL to provider mapping for OpenAI-compatible APIs +_BASE_URL_PROVIDER_MAP = [ + ("openai.com", GenAIAttributes.GenAiProviderNameValues.OPENAI.value), + ( + "api.deepseek.com", + GenAIAttributes.GenAiProviderNameValues.DEEPSEEK.value, + ), + ("dashscope.aliyuncs.com", AgentScopeGenAiProviderName.DASHSCOPE.value), +] + + +def get_provider_name(chat_model: ChatModelBase) -> str: + """Parse chat model provider name.""" + classname = chat_model.__class__.__name__ + prefix = classname.removesuffix("ChatModel").lower() + + # Special handling for DashScopeChatModel with base_http_api_url + if ( + prefix == "dashscope" + and hasattr(chat_model, "base_http_api_url") + and chat_model.base_http_api_url + ): + base_url = chat_model.base_http_api_url + for url_fragment, provider in _BASE_URL_PROVIDER_MAP: + if url_fragment in base_url: + return provider + + return _PROVIDER_NAME_MAP.get(prefix, "unknown") + + +def get_embedding_provider_name(embedding_model: EmbeddingModelBase) -> str: + """Parse embedding model provider name.""" + class_name = embedding_model.__class__.__name__ + + if "DashScope" in class_name: + return AgentScopeGenAiProviderName.DASHSCOPE.value + elif "OpenAI" in class_name: + return GenAIAttributes.GenAiProviderNameValues.OPENAI.value + elif "Gemini" in class_name: + return GenAIAttributes.GenAiProviderNameValues.GCP_GEMINI.value + elif "Ollama" in class_name: + return AgentScopeGenAiProviderName.OLLAMA.value + else: + model_name = getattr(embedding_model, "model_name", "") + if "text-embedding" in model_name: + if "qwen" in model_name or "dashscope" in model_name: + return AgentScopeGenAiProviderName.DASHSCOPE.value + else: + return GenAIAttributes.GenAiProviderNameValues.OPENAI.value + return "agentscope" + + +def _build_tool_definitions( + tools: list[dict[str, Any]] | None, + tool_choice: str | None, +) -> list[ToolDefinition] | None: + """Extract tool definitions for tracing as semconv tool-definition objects.""" + if tools is None or not isinstance(tools, list) or len(tools) == 0: + return None + + if tool_choice == "none": + return None + + definitions: list[ToolDefinition] = [] + for tool in tools: + if not isinstance(tool, dict) or "function" not in tool: + continue + func_def = tool["function"] + if not isinstance(func_def, dict): + continue + definitions.append( + FunctionToolDefinition( + name=func_def.get("name", ""), + description=func_def.get("description"), + parameters=func_def.get("parameters"), + ) + ) + + return definitions or None + + +def _to_serializable(obj: Any) -> Any: + """Convert an object to a JSON serializable type.""" + if isinstance(obj, (str, int, bool, float, type(None))): + return obj + elif isinstance(obj, (list, tuple, set, frozenset)): + return [_to_serializable(x) for x in obj] + elif isinstance(obj, dict): + return {str(key): _to_serializable(val) for (key, val) in obj.items()} + elif isinstance(obj, (Msg, BaseModel)) or is_dataclass(obj): + return repr(obj) + elif inspect.isclass(obj) and issubclass(obj, BaseModel): + return repr(obj) + elif isinstance(obj, (datetime.date, datetime.datetime, datetime.time)): + return obj.isoformat() + elif isinstance(obj, datetime.timedelta): + return obj.total_seconds() + elif isinstance(obj, enum.Enum): + return _to_serializable(obj.value) + else: + return str(obj) + + +def _serialize_to_str(value: Any) -> str: + """Serialize value to JSON string.""" + try: + return json.dumps(value, ensure_ascii=False) + except TypeError: + return json.dumps(_to_serializable(value), ensure_ascii=False) + + +def _convert_block_to_part(block: Dict[str, Any]) -> Dict[str, Any] | None: + """Convert content block to standardized part format.""" + block_type = block.get("type") + + if block_type == "text": + return {"type": "text", "content": block.get("text", "")} + + elif block_type == "thinking": + return { + "type": "reasoning", + "content": block.get("thinking", ""), + } + + elif block_type == "tool_use": + return { + "type": "tool_call", + "id": block.get("id", ""), + "name": block.get("name", ""), + "arguments": block.get("input", {}), + } + + elif block_type == "tool_result": + output = block.get("output", "") + result = ( + _serialize_to_str(output) + if isinstance(output, (list, dict)) + else str(output) + ) + return { + "type": "tool_call_response", + "id": block.get("id", ""), + "result": result, + } + + elif block_type in ["image", "audio", "video"]: + source = block.get("source", {}) + source_type = source.get("type") + media_type = source.get("media_type") + + if source_type == "url": + url = source.get("url", "") + # Infer mime_type from URL extension if not provided + if not media_type: + parsed_url = urlparse(url) + media_type, _ = mimetypes.guess_type(parsed_url.path) + return { + "type": "uri", + "uri": url, + "modality": block_type, + "mime_type": media_type, + } + elif source_type == "base64": + if not media_type: + default_media_types = { + "image": "image/jpeg", + "audio": "audio/wav", + "video": "video/mp4", + } + media_type = default_media_types.get(block_type, "unknown") + return { + "type": "blob", + "content": source.get("data", ""), + "media_type": media_type, + "modality": block_type, + } + + return None + + +def _format_msg_to_parts(msg: Msg) -> dict[str, Any]: + """Convert Msg to standard format (parts structure).""" + try: + parts = [] + for block in msg.get_content_blocks(): + part = _convert_block_to_part(block) + if part: + parts.append(part) + + formatted_msg = {"role": msg.role, "parts": parts} + if msg.name: + formatted_msg["name"] = msg.name + + return formatted_msg + + except Exception as e: + logger.debug("Error formatting message: %s", e) + return { + "role": msg.role, + "parts": [ + { + "type": "text", + "content": str(msg.content) if msg.content else "", + } + ], + } + + +def _decode_base64(data: Any) -> bytes | None: + if isinstance(data, bytes): + return data + if not isinstance(data, str): + return None + try: + return base64.b64decode(data) + except (ValueError, TypeError): + return None + + +def _part_dict_to_message_part(part: Dict[str, Any]) -> MessagePart: + """Convert a part dict into a util-genai message part.""" + part_type = part.get("type") + if part_type == "text": + return Text(content=part.get("content", "")) + if part_type == "tool_call": + return ToolCallRequest( + arguments=part.get("arguments", {}), + name=part.get("name", ""), + id=part.get("id"), + ) + if part_type == "tool_call_response": + return ToolCallResponse( + response=part["response"] + if "response" in part + else part.get("result", ""), + id=part.get("id"), + ) + if part_type == "reasoning": + return Reasoning(content=part.get("content", "")) + if part_type == "uri": + return Uri( + mime_type=part.get("mime_type"), + modality=part.get("modality", "image"), + uri=part.get("uri", ""), + ) + if part_type == "blob": + content = _decode_base64(part.get("content", "")) + if content is not None: + return Blob( + mime_type=part.get("media_type") + if "media_type" in part + else part.get("mime_type"), + modality=part.get("modality", "image"), + content=content, + ) + return GenericPart(value=part) + + +def convert_agentscope_messages_to_genai_format( + messages: Any, + provider_name: Optional[str] = None, +) -> List[InputMessage]: + """Convert AgentScope messages to util-genai ``InputMessage`` objects.""" + if not messages: + return [] + + if not isinstance(messages, list): + messages = [messages] + + input_messages = [] + for msg in messages: + if isinstance(msg, Msg): + msg_dict = _format_msg_to_parts(msg) + elif isinstance(msg, dict): + msg_dict = msg + else: + continue + + role = msg_dict.get("role", "user") + parts = msg_dict.get("parts", []) + + converted_parts: list[MessagePart] = [ + _part_dict_to_message_part(part) for part in parts + ] + input_messages.append(InputMessage(role=role, parts=converted_parts)) + + return input_messages + + +def get_chatmodel_output_messages(chat_response: Any) -> List[Dict[str, Any]]: + """Convert ChatResponse to standard output message dict format.""" + try: + if not isinstance(chat_response, ChatResponse): + return [] + + parts = [] + for block in chat_response.content: + part = _convert_block_to_part(block) + if part: + parts.append(part) + + if not parts: + parts.append({"type": "text", "content": ""}) + + return [ + { + "role": "assistant", + "parts": parts, + "finish_reason": "stop", + } + ] + + except Exception as e: + logger.warning( + "Error processing ChatResponse to output messages: %s", e + ) + return [ + { + "role": "assistant", + "parts": [ + {"type": "text", "content": ""} + ], + "finish_reason": "error", + } + ] + + +def convert_chatresponse_to_output_messages( + chat_response: Any, +) -> List[OutputMessage]: + """Convert ChatResponse to util-genai ``OutputMessage`` objects.""" + output_dicts = get_chatmodel_output_messages(chat_response) + if not output_dicts: + return [] + + output_messages = [] + for msg_dict in output_dicts: + role = msg_dict.get("role", "assistant") + parts_dicts = msg_dict.get("parts", []) + finish_reason = msg_dict.get("finish_reason", "stop") + + converted_parts = [ + _part_dict_to_message_part(part) for part in parts_dicts + ] + + output_messages.append( + OutputMessage( + role=role, + parts=converted_parts, + finish_reason=finish_reason, + ) + ) + + return output_messages + + +def convert_agent_response_to_output_messages( + agent_response: Any, +) -> List[OutputMessage]: + """Convert agent ``Msg`` response to util-genai ``OutputMessage`` objects.""" + if not hasattr(agent_response, "content"): + return [] + + try: + msg_dict = _format_msg_to_parts(agent_response) + parts_dicts = msg_dict.get("parts", []) + + converted_parts: list[MessagePart] = [ + _part_dict_to_message_part(part) for part in parts_dicts + ] + + if not converted_parts: + converted_parts.append(Text(content="")) + + return [ + OutputMessage( + role="assistant", + parts=converted_parts, + finish_reason="stop", + ) + ] + except Exception as e: + logger.debug("Failed to convert agent response: %s", e) + return [] + + +def start_llm_invocation( + handler: TelemetryHandler, + call_instance: ChatModelBase, + call_args: Tuple[Any, ...], + call_kwargs: Dict[str, Any], +) -> InferenceInvocation: + """Create and start an inference invocation from a chat model call.""" + provider_name = get_provider_name(call_instance) + request_model = getattr(call_instance, "model_name", "unknown_model") + + invocation = handler.inference(provider_name, request_model=request_model) + + if handler.should_capture_content(): + messages = call_args[0] if call_args else call_kwargs.get("messages") + if messages: + try: + converted_messages = get_message_converter(provider_name)( + messages + ) + invocation.input_messages = ( + convert_agentscope_messages_to_genai_format( + converted_messages, provider_name=provider_name + ) + ) + except Exception as e: + logger.warning( + "Failed to convert input messages: %s", e, exc_info=True + ) + + if call_kwargs.get("max_tokens"): + invocation.max_tokens = call_kwargs["max_tokens"] + if call_kwargs.get("temperature"): + invocation.temperature = call_kwargs["temperature"] + if call_kwargs.get("top_p"): + invocation.top_p = call_kwargs["top_p"] + + if not call_kwargs.get("structured_model", False): + invocation.tool_definitions = _build_tool_definitions( + call_kwargs.get("tools"), call_kwargs.get("tool_choice") + ) + + return invocation + + +def start_embedding_invocation( + handler: TelemetryHandler, + call_instance: EmbeddingModelBase, + call_args: Tuple[Any, ...], + call_kwargs: Dict[str, Any], +) -> EmbeddingInvocation: + """Create and start an embedding invocation from an embedding model call.""" + provider_name = get_embedding_provider_name(call_instance) + request_model = getattr(call_instance, "model_name", "unknown_model") + + invocation = handler.embedding(provider_name, request_model=request_model) + + if call_kwargs.get("encoding_formats"): + invocation.encoding_formats = call_kwargs["encoding_formats"] + + return invocation + + +def start_agent_invocation( + handler: TelemetryHandler, + reply_instance: AgentBase, + reply_args: Tuple[Any, ...], + reply_kwargs: Dict[str, Any], +) -> AgentInvocation: + """Create and start an ``invoke_agent`` invocation from a reply call.""" + provider_name = None + request_model = None + if hasattr(reply_instance, "model") and reply_instance.model: + model = reply_instance.model + request_model = getattr(model, "model_name", None) + if isinstance(model, ChatModelBase): + provider_name = get_provider_name(model) + + invocation = handler.invoke_local_agent( + request_model=request_model, + agent_name=getattr(reply_instance, "name", "unknown_agent"), + ) + invocation.provider = provider_name + invocation.agent_id = getattr(reply_instance, "id", "unknown") + invocation.agent_description = ( + inspect.getdoc(reply_instance.__class__) or "No description available" + ) + invocation.conversation_id = _config.run_id + + if handler.should_capture_content(): + msg = reply_args[0] if reply_args else reply_kwargs.get("msg") + if msg: + try: + if isinstance(msg, Msg): + invocation.input_messages = ( + convert_agentscope_messages_to_genai_format([msg]) + ) + elif isinstance(msg, list): + invocation.input_messages = ( + convert_agentscope_messages_to_genai_format(msg) + ) + except Exception as e: + logger.debug("Error converting agent input messages: %s", e) + + sys_prompt = getattr(reply_instance, "sys_prompt", None) + if sys_prompt: + if isinstance(sys_prompt, str): + invocation.system_instruction = [Text(content=sys_prompt)] + elif isinstance(sys_prompt, list): + invocation.system_instruction = sys_prompt + + return invocation diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/version.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/version.py new file mode 100644 index 000000000..8920c2929 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/src/opentelemetry/instrumentation/genai/agentscope/version.py @@ -0,0 +1,4 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +__version__ = "1.1b0.dev" diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/__init__.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/__init__.py new file mode 100644 index 000000000..e57cf4aba --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/__init__.py @@ -0,0 +1,2 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/_test_helpers.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/_test_helpers.py new file mode 100644 index 000000000..bc83276b3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/_test_helpers.py @@ -0,0 +1,78 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Test utility functions.""" + +from __future__ import annotations + +from typing import List + +from opentelemetry.sdk.trace import ReadableSpan +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + + +def find_spans_by_name_prefix( + spans: List[ReadableSpan], prefix: str +) -> List[ReadableSpan]: + """Find spans by name prefix.""" + return [span for span in spans if span.name.startswith(prefix)] + + +def find_spans_by_operation( + spans: List[ReadableSpan], operation_name: str +) -> List[ReadableSpan]: + """Find spans by the ``gen_ai.operation.name`` attribute.""" + return [ + span + for span in spans + if span.attributes + and span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME) + == operation_name + ] + + +def print_span_tree(spans: List[ReadableSpan], indent: int = 0) -> None: + """Print span tree structure for debugging.""" + sorted_spans = sorted(spans, key=lambda s: s.start_time) + + for span in sorted_spans: + print(" " * indent + f"- {span.name}") + print( + " " * indent + + f" Operation: {span.attributes.get(GenAIAttributes.GEN_AI_OPERATION_NAME)}" + ) + print( + " " * indent + + f" Model: {span.attributes.get(GenAIAttributes.GEN_AI_REQUEST_MODEL)}" + ) + + child_spans = [ + s + for s in spans + if getattr(s, "parent", None) + and s.parent + and s.parent.span_id == span.context.span_id + ] + if child_spans: + print_span_tree(child_spans, indent + 1) + + +def assert_no_removed_telemetry(spans: List[ReadableSpan]) -> None: + """Assert that removed span kinds/attributes never appear. + + The migrated instrumentation drops the ``gen_ai.span.kind`` attribute + (keeping only the standard ``gen_ai.operation.name``) and no longer emits + ``react step`` / entry spans. + """ + for span in spans: + assert "gen_ai.span.kind" not in span.attributes, ( + f"gen_ai.span.kind must not be set (span={span.name})" + ) + assert span.name != "react step", ( + "react step spans must not be emitted" + ) + assert span.attributes.get("gen_ai.operation.name") != "react", ( + "react operation must not be emitted" + ) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentAttributes.test_agent_span_attributes.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentAttributes.test_agent_span_attributes.yaml new file mode 100644 index 000000000..e52e68552 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentAttributes.test_agent_span_attributes.yaml @@ -0,0 +1,124 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a test assistant. + role: system + - content: Simple test + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Of","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":22,"output_tokens":1,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" course! What","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":25,"output_tokens":4,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" would you like","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":28,"output_tokens":7,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" to test?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":10,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" Could you provide more","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":35,"output_tokens":14,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" details or specify the type of","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":41,"output_tokens":20,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" test you're interested in?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":47,"output_tokens":26,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" For example, are","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":51,"output_tokens":30,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you looking for a math","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":56,"output_tokens":35,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" problem, a language quiz","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":61,"output_tokens":40,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:11 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":", or something else?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":66,"output_tokens":45,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + id:12 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":66,"output_tokens":45,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a99c740d-1c69-4f9d-8991-11fd3c23cd36"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:53 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943753162' + req-cost-time: + - '277' + resp-start-time: + - '1765943753440' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '270' + x-request-id: + - a99c740d-1c69-4f9d-8991-11fd3c23cd36 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_multiple_turns.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_multiple_turns.yaml new file mode 100644 index 000000000..ae621f5e3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_multiple_turns.yaml @@ -0,0 +1,294 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a helpful assistant. + role: system + - content: Hello + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":21,"output_tokens":1,"input_tokens":20,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"d53f1897-8412-4174-8152-f5e545945255"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! How can","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":24,"output_tokens":4,"input_tokens":20,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"d53f1897-8412-4174-8152-f5e545945255"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" I assist you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":27,"output_tokens":7,"input_tokens":20,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"d53f1897-8412-4174-8152-f5e545945255"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" today?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":29,"output_tokens":9,"input_tokens":20,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"d53f1897-8412-4174-8152-f5e545945255"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":29,"output_tokens":9,"input_tokens":20,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"d53f1897-8412-4174-8152-f5e545945255"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:49 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943749154' + req-cost-time: + - '307' + resp-start-time: + - '1765943749462' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '300' + x-request-id: + - d53f1897-8412-4174-8152-f5e545945255 + status: + code: 200 + message: OK +- request: + body: + input: + messages: + - content: You are a helpful assistant. + role: system + - content: Hello + role: user + - content: What's 2+2? + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":29,"output_tokens":1,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! The answer","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":32,"output_tokens":4,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" to 2","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":35,"output_tokens":7,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"+2 is","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":38,"output_tokens":10,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" 4.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":41,"output_tokens":13,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":41,"output_tokens":13,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"420c696e-af6f-4a30-a5c3-339bc447fe10"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:49 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943749802' + req-cost-time: + - '258' + resp-start-time: + - '1765943750061' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '250' + x-request-id: + - 420c696e-af6f-4a30-a5c3-339bc447fe10 + status: + code: 200 + message: OK +- request: + body: + input: + messages: + - content: You are a helpful assistant. + role: system + - content: Hello + role: user + - content: What's 2+2? + role: user + - content: Thank you + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":1,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! ","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":33,"output_tokens":3,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"2+","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":35,"output_tokens":5,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"2 equals","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":37,"output_tokens":7,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" 4. \n\n","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":41,"output_tokens":11,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"You're welcome!","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":45,"output_tokens":15,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" If you have any other questions","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":51,"output_tokens":21,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":", feel free to ask.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":57,"output_tokens":27,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":57,"output_tokens":27,"input_tokens":30,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"1770a10c-5250-46e8-b8c1-661232a794d3"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:50 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943750559' + req-cost-time: + - '305' + resp-start-time: + - '1765943750864' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '298' + x-request-id: + - 1770a10c-5250-46e8-b8c1-661232a794d3 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_simple_call.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_simple_call.yaml new file mode 100644 index 000000000..05b42d6a5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_simple_call.yaml @@ -0,0 +1,99 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a helpful assistant. + role: system + - content: Hello, how are you? + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":26,"output_tokens":1,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! I'm","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":29,"output_tokens":4,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" just fine","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":6,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":", thank you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":34,"output_tokens":9,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" for asking. How","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":38,"output_tokens":13,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" can I assist you today?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":44,"output_tokens":19,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":44,"output_tokens":19,"input_tokens":25,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"f5021c5f-021c-4e52-84fd-a15170606136"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:46 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943746426' + req-cost-time: + - '254' + resp-start-time: + - '1765943746680' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '247' + x-request-id: + - f5021c5f-021c-4e52-84fd-a15170606136 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_with_tool.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_with_tool.yaml new file mode 100644 index 000000000..7695b6543 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentBasic.test_agent_with_tool.yaml @@ -0,0 +1,112 @@ +interactions: +- request: + body: + input: + messages: + - content: You are an assistant with tool access. + role: system + - content: compute 10+20 for me using shell + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + tools: + - function: + description: 'Execute given command and return the return code, standard + output and + + error within , and + + tags.' + name: execute_shell_command + parameters: + properties: + command: + description: The shell command to execute. + type: string + timeout: + default: 300 + description: The maximum time (in seconds) allowed for the command + to run. + type: integer + required: + - command + type: object + type: function + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","tool_calls":[{"index":0,"id":"call_d69a5e709960444d939d30","type":"function","function":{"name":"execute_shell_command","arguments":"{\"command\": \""}}],"role":"assistant"},"index":0,"finish_reason":"null"}]},"usage":{"total_tokens":340,"output_tokens":16,"input_tokens":324,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5410e11b-2f6b-4c5c-9221-05b24096c8f6"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","tool_calls":[{"index":0,"id":"","type":"function","function":{"arguments":"echo $((10"}}],"role":"assistant"},"index":0,"finish_reason":"null"}]},"usage":{"total_tokens":345,"output_tokens":21,"input_tokens":324,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5410e11b-2f6b-4c5c-9221-05b24096c8f6"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","tool_calls":[{"index":0,"id":"","type":"function","function":{"arguments":"+20))\", \""}}],"role":"assistant"},"index":0,"finish_reason":"null"}]},"usage":{"total_tokens":351,"output_tokens":27,"input_tokens":324,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5410e11b-2f6b-4c5c-9221-05b24096c8f6"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","tool_calls":[{"index":0,"id":"","type":"function","function":{"arguments":"timeout\": 3"}}],"role":"assistant"},"index":0,"finish_reason":"null"}]},"usage":{"total_tokens":355,"output_tokens":31,"input_tokens":324,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5410e11b-2f6b-4c5c-9221-05b24096c8f6"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","tool_calls":[{"index":0,"id":"","type":"function","function":{"arguments":"00}"}}],"role":"assistant"},"index":0,"finish_reason":"tool_calls"}]},"usage":{"total_tokens":358,"output_tokens":34,"input_tokens":324,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5410e11b-2f6b-4c5c-9221-05b24096c8f6"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Wed, 17 Dec 2025 03:55:48 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1765943747292' + req-cost-time: + - '1052' + resp-start-time: + - '1765943748344' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '1043' + x-request-id: + - 5410e11b-2f6b-4c5c-9221-05b24096c8f6 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentError.test_agent_with_invalid_model.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentError.test_agent_with_invalid_model.yaml new file mode 100644 index 000000000..ac9da4ef3 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestAgentError.test_agent_with_invalid_model.yaml @@ -0,0 +1,126 @@ +interactions: +- request: + body: + input: + messages: + - content: Test agent + role: system + - content: Test + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "code": "InvalidApiKey", + "message": "Invalid API-key provided.", + "request_id": "90adb356-e223-4b64-88bc-d92fd7c1ce6c" + } + headers: + Content-Type: + - application/json + Date: + - Wed, 17 Dec 2025 03:55:57 GMT + Server: + - istio-envoy + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + content-length: + - '114' + req-arrive-time: + - '1765943757555' + req-cost-time: + - '8' + resp-start-time: + - '1765943757564' + x-envoy-upstream-service-time: + - '8' + x-request-id: + - 90adb356-e223-4b64-88bc-d92fd7c1ce6c + status: + code: 401 + message: Unauthorized +- request: + body: + input: + messages: + - content: Test agent + role: system + - content: Test + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.4; python/3.13.0; platform/macOS-15.3.2-arm64-arm-64bit-Mach-O; + processor/arm; incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "code": "InvalidApiKey", + "message": "Invalid API-key provided.", + "request_id": "d55d7c5f-69b1-49d7-a928-868a37724e6b" + } + headers: + Content-Type: + - application/json + Date: + - Wed, 17 Dec 2025 03:55:57 GMT + Server: + - istio-envoy + Transfer-Encoding: + - chunked + Vary: + - Accept-Encoding + content-length: + - '114' + req-arrive-time: + - '1765943757689' + req-cost-time: + - '9' + resp-start-time: + - '1765943757698' + x-envoy-upstream-service-time: + - '9' + x-request-id: + - d55d7c5f-69b1-49d7-a928-868a37724e6b + status: + code: 401 + message: Unauthorized +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_disabled.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_disabled.yaml new file mode 100644 index 000000000..46351744d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_disabled.yaml @@ -0,0 +1,89 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a test assistant. + role: system + - content: Say hello + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":22,"output_tokens":1,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a55f8dee-0384-4138-8803-abfbc93f8b00"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! How can","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":25,"output_tokens":4,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a55f8dee-0384-4138-8803-abfbc93f8b00"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" I assist","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":27,"output_tokens":6,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a55f8dee-0384-4138-8803-abfbc93f8b00"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you today?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":30,"output_tokens":9,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a55f8dee-0384-4138-8803-abfbc93f8b00"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":30,"output_tokens":9,"input_tokens":21,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"a55f8dee-0384-4138-8803-abfbc93f8b00"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Thu, 27 Nov 2025 07:57:33 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764230253164' + req-cost-time: + - '191' + resp-start-time: + - '1764230253356' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '182' + x-request-id: + - a55f8dee-0384-4138-8803-abfbc93f8b00 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_and_event.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_and_event.yaml new file mode 100644 index 000000000..ee64de29a --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_and_event.yaml @@ -0,0 +1,89 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a test assistant. + role: system + - content: What is 2+2? + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"2","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":27,"output_tokens":1,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c56c1446-14c3-4889-9973-80e53d28f53e"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"+","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":28,"output_tokens":2,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c56c1446-14c3-4889-9973-80e53d28f53e"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"2 is ","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":5,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c56c1446-14c3-4889-9973-80e53d28f53e"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"4.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":33,"output_tokens":7,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c56c1446-14c3-4889-9973-80e53d28f53e"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":33,"output_tokens":7,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c56c1446-14c3-4889-9973-80e53d28f53e"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Thu, 27 Nov 2025 07:57:32 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764230252618' + req-cost-time: + - '264' + resp-start-time: + - '1764230252883' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '257' + x-request-id: + - c56c1446-14c3-4889-9973-80e53d28f53e + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_only.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_only.yaml new file mode 100644 index 000000000..e38d03f39 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/TestSpanContentCapture.test_span_content_with_span_only.yaml @@ -0,0 +1,84 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a test assistant. + role: system + - content: Hello, please say 'Hi' to me + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hi","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":29,"output_tokens":1,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"85fef3f7-e5fa-45be-b834-76d3b707f203"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" there","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":30,"output_tokens":2,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"85fef3f7-e5fa-45be-b834-76d3b707f203"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"!","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":3,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"85fef3f7-e5fa-45be-b834-76d3b707f203"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":31,"output_tokens":3,"input_tokens":28,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"85fef3f7-e5fa-45be-b834-76d3b707f203"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Thu, 27 Nov 2025 09:01:08 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764234068335' + req-cost-time: + - '378' + resp-start-time: + - '1764234068713' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '374' + x-request-id: + - 85fef3f7-e5fa-45be-b834-76d3b707f203 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/orchestration_conformance.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/orchestration_conformance.yaml new file mode 100644 index 000000000..9be0b1b88 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/orchestration_conformance.yaml @@ -0,0 +1,321 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "You answer weather questions. Always call the get_weather tool for the requested city, then reply in one short sentence." + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "What is the weather in Hangzhou?" + } + ] + } + ], + "model": "qwen-plus", + "max_tokens": 256, + "stream": false, + "tools": [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Look up the current weather for a city.", + "parameters": { + "properties": { + "city": { + "type": "string" + } + }, + "required": [ + "city" + ], + "type": "object" + } + } + } + ], + "enable_thinking": false + } + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - + connection: + - keep-alive + content-length: + - '563' + content-type: + - application/json + host: + - dashscope.aliyuncs.com + user-agent: + - AsyncOpenAI/Python 2.44.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 2.44.0 + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.3 + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |- + { + "model": "qwen-plus", + "id": "chatcmpl-890d5345-1f24-9bfe-a0b3-c528f22749a2", + "choices": [ + { + "message": { + "content": "", + "tool_calls": [ + { + "index": 0, + "id": "call_e06556d8e6dc4974a15b75", + "type": "function", + "function": { + "name": "get_weather", + "arguments": "{\"city\": \"Hangzhou\"}" + } + } + ], + "role": "assistant" + }, + "index": 0, + "finish_reason": "tool_calls" + } + ], + "created": 1783485863, + "object": "chat.completion", + "usage": { + "total_tokens": 199, + "completion_tokens": 20, + "prompt_tokens": 179, + "prompt_tokens_details": { + "cached_tokens": 0 + } + } + } + headers: + content-length: + - '488' + content-type: + - application/json + date: + - Wed, 08 Jul 2026 04:44:24 GMT + req-arrive-time: + - '1783485863491' + req-cost-time: + - '652' + resp-start-time: + - '1783485864144' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '3600' + x-envoy-upstream-service-time: + - '652' + x-request-id: + - 890d5345-1f24-9bfe-a0b3-c528f22749a2 + status: + code: 200 + message: OK +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "You answer weather questions. Always call the get_weather tool for the requested city, then reply in one short sentence." + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "What is the weather in Hangzhou?" + } + ] + }, + { + "role": "assistant", + "content": null, + "tool_calls": [ + { + "id": "call_e06556d8e6dc4974a15b75", + "type": "function", + "function": { + "name": "get_weather", + "arguments": "{\"city\": \"Hangzhou\"}" + } + } + ] + }, + { + "role": "tool", + "tool_call_id": "call_e06556d8e6dc4974a15b75", + "content": "content=[TextBlock(type='text', text='The weather in Hangzhou is sunny with a high of 24C.', id='6cb39d766a6543e7855d19afe87e470f')] state= metadata={} id='8a83277fc8954a82a1ae99c04216f964'", + "name": "get_weather" + } + ], + "model": "qwen-plus", + "max_tokens": 256, + "stream": false, + "tools": [ + { + "type": "function", + "function": { + "name": "get_weather", + "description": "Look up the current weather for a city.", + "parameters": { + "properties": { + "city": { + "type": "string" + } + }, + "required": [ + "city" + ], + "type": "object" + } + } + } + ], + "enable_thinking": false + } + headers: + accept: + - application/json + accept-encoding: + - gzip, deflate + authorization: + - + connection: + - keep-alive + content-length: + - '1062' + content-type: + - application/json + host: + - dashscope.aliyuncs.com + user-agent: + - AsyncOpenAI/Python 2.44.0 + x-stainless-arch: + - arm64 + x-stainless-async: + - async:asyncio + x-stainless-lang: + - python + x-stainless-os: + - MacOS + x-stainless-package-version: + - 2.44.0 + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + x-stainless-runtime: + - CPython + x-stainless-runtime-version: + - 3.12.3 + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |- + { + "model": "qwen-plus", + "id": "chatcmpl-619280e8-92c8-9043-a032-747d58a72dbf", + "choices": [ + { + "message": { + "content": "The weather in Hangzhou is sunny with a high of 24\u00b0C.", + "role": "assistant" + }, + "index": 0, + "finish_reason": "stop" + } + ], + "created": 1783485864, + "object": "chat.completion", + "usage": { + "total_tokens": 331, + "completion_tokens": 16, + "prompt_tokens": 315, + "prompt_tokens_details": { + "cached_tokens": 0 + } + } + } + headers: + content-length: + - '383' + content-type: + - application/json + date: + - Wed, 08 Jul 2026 04:44:25 GMT + req-arrive-time: + - '1783485864290' + req-cost-time: + - '958' + resp-start-time: + - '1783485865248' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '3600' + x-envoy-upstream-service-time: + - '957' + x-request-id: + - 619280e8-92c8-9043-a032-747d58a72dbf + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_async.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_async.yaml new file mode 100644 index 000000000..875cfe078 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_async.yaml @@ -0,0 +1,112 @@ +interactions: +- request: + body: + input: + messages: + - content: Hello from async! + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":13,"output_tokens":1,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! It","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":15,"output_tokens":3,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"'s great","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":17,"output_tokens":5,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" to hear from","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":20,"output_tokens":8,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you. How can I assist","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":26,"output_tokens":14,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you today with anything","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":30,"output_tokens":18,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" related to async or","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":34,"output_tokens":22,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" any other topic you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":38,"output_tokens":26,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" might have in mind?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":43,"output_tokens":31,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":43,"output_tokens":31,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"863522c2-335b-428c-b79a-9a122a2af4c0"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:40 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684880505' + req-cost-time: + - '189' + resp-start-time: + - '1764684880694' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '182' + x-request-id: + - 863522c2-335b-428c-b79a-9a122a2af4c0 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_basic.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_basic.yaml new file mode 100644 index 000000000..767c71194 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_basic.yaml @@ -0,0 +1,87 @@ +interactions: +- request: + body: + input: + messages: + - content: Hello! + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":11,"output_tokens":1,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"54b57c9f-4600-455a-8e2b-3e07619dbd42"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! How can","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":14,"output_tokens":4,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"54b57c9f-4600-455a-8e2b-3e07619dbd42"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" I assist you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":17,"output_tokens":7,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"54b57c9f-4600-455a-8e2b-3e07619dbd42"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" today?","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":19,"output_tokens":9,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"54b57c9f-4600-455a-8e2b-3e07619dbd42"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":19,"output_tokens":9,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"54b57c9f-4600-455a-8e2b-3e07619dbd42"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:28 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684869022' + req-cost-time: + - '193' + resp-start-time: + - '1764684869215' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '186' + x-request-id: + - 54b57c9f-4600-455a-8e2b-3e07619dbd42 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_multiple_sequential.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_multiple_sequential.yaml new file mode 100644 index 000000000..0088bb496 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_multiple_sequential.yaml @@ -0,0 +1,367 @@ +interactions: +- request: + body: + input: + messages: + - content: First call + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":11,"output_tokens":1,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! Welcome","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":13,"output_tokens":3,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" to our service","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":16,"output_tokens":6,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":". How can","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":19,"output_tokens":9,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" I assist you today? Whether","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":25,"output_tokens":15,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you need information, help with","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":21,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" a specific task, or","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":36,"output_tokens":26,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" just want to chat about","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":41,"output_tokens":31,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" something interesting, feel free","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":46,"output_tokens":36,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" to let me know!","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":51,"output_tokens":41,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + id:11 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":51,"output_tokens":41,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"cc5957ea-1bcb-463b-98b3-65832f68e5d9"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:43 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684883588' + req-cost-time: + - '183' + resp-start-time: + - '1764684883772' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '178' + x-request-id: + - cc5957ea-1bcb-463b-98b3-65832f68e5d9 + status: + code: 200 + message: OK +- request: + body: + input: + messages: + - content: Second call + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":11,"output_tokens":1,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! It","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":13,"output_tokens":3,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" seems like","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":15,"output_tokens":5,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you mentioned","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":17,"output_tokens":7,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" \"Second call,\"","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":21,"output_tokens":11,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" but I'm not sure what","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":27,"output_tokens":17,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" specific context or information","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":21,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you're referring to.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":36,"output_tokens":26,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" Could you please provide more details","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":42,"output_tokens":32,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" or clarify your request","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":46,"output_tokens":36,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:11 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"? That way, I","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":51,"output_tokens":41,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:12 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" can better assist you.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":56,"output_tokens":46,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + id:13 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":56,"output_tokens":46,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"e452c048-5b90-4bc5-8264-73c656704bb8"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:45 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684884744' + req-cost-time: + - '392' + resp-start-time: + - '1764684885136' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '386' + x-request-id: + - e452c048-5b90-4bc5-8264-73c656704bb8 + status: + code: 200 + message: OK +- request: + body: + input: + messages: + - content: Third call + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Hello","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":11,"output_tokens":1,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"! It","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":13,"output_tokens":3,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" seems like you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":16,"output_tokens":6,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"'ve","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":17,"output_tokens":7,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" mentioned \"Third call","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":21,"output_tokens":11,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":",\" but I'm","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":25,"output_tokens":15,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" not sure about the context.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":21,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" Could you please provide more details","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":37,"output_tokens":27,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" or clarify what you need","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":42,"output_tokens":32,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" help with? This","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":46,"output_tokens":36,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:11 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" way, I can better assist","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":52,"output_tokens":42,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:12 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" you.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":54,"output_tokens":44,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + id:13 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":54,"output_tokens":44,"input_tokens":10,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"c8e93d86-a6f1-4f4d-a5fd-1d644655f06f"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:47 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684887133' + req-cost-time: + - '242' + resp-start-time: + - '1764684887376' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '236' + x-request-id: + - c8e93d86-a6f1-4f4d-a5fd-1d644655f06f + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_no_content_capture.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_no_content_capture.yaml new file mode 100644 index 000000000..49aeddafe --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_no_content_capture.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: + input: + messages: + - content: Say this is a test + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"This","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":14,"output_tokens":1,"input_tokens":13,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5be955ab-c3c0-4a3f-8b0f-123b64064524"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" is a test","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":17,"output_tokens":4,"input_tokens":13,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5be955ab-c3c0-4a3f-8b0f-123b64064524"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":".","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":18,"output_tokens":5,"input_tokens":13,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5be955ab-c3c0-4a3f-8b0f-123b64064524"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":18,"output_tokens":5,"input_tokens":13,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"5be955ab-c3c0-4a3f-8b0f-123b64064524"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:42 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684882973' + req-cost-time: + - '261' + resp-start-time: + - '1764684883235' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '254' + x-request-id: + - 5be955ab-c3c0-4a3f-8b0f-123b64064524 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_streaming.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_streaming.yaml new file mode 100644 index 000000000..8de28c35d --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_streaming.yaml @@ -0,0 +1,92 @@ +interactions: +- request: + body: + input: + messages: + - content: Count from 1 to 5 + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"Sure","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":16,"output_tokens":1,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":", here you","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":19,"output_tokens":4,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" go:\n","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":21,"output_tokens":6,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"1\n2","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":24,"output_tokens":9,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"\n3\n4\n5","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":30,"output_tokens":15,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":30,"output_tokens":15,"input_tokens":15,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"ae4166cd-9149-43bd-9be9-e80093da3480"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:41 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684881557' + req-cost-time: + - '281' + resp-start-time: + - '1764684881839' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '274' + x-request-id: + - ae4166cd-9149-43bd-9be9-e80093da3480 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_content_capture.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_content_capture.yaml new file mode 100644 index 000000000..6054e423c --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_content_capture.yaml @@ -0,0 +1,82 @@ +interactions: +- request: + body: + input: + messages: + - content: Say this is a test + role: user + model: qwen-max + parameters: + incremental_output: false + result_format: message + headers: + Accept: + - application/json + Content-Type: + - application/json + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |- + { + "output": { + "choices": [ + { + "finish_reason": "stop", + "message": { + "content": "This is a test.", + "role": "assistant" + } + } + ] + }, + "usage": { + "input_tokens": 13, + "output_tokens": 5, + "prompt_tokens_details": { + "cached_tokens": 0 + }, + "total_tokens": 18 + }, + "request_id": "8420e3d0-5a23-409b-b21d-04d1cd9d8f54" + } + headers: + Content-Type: + - application/json + Date: + - Tue, 02 Dec 2025 14:19:24 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + content-length: + - '268' + req-arrive-time: + - '1764685163852' + req-cost-time: + - '557' + resp-start-time: + - '1764685164410' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'true' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '549' + x-request-id: + - 8420e3d0-5a23-409b-b21d-04d1cd9d8f54 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_messages.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_messages.yaml new file mode 100644 index 000000000..55de36c9b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_messages.yaml @@ -0,0 +1,89 @@ +interactions: +- request: + body: + input: + messages: + - content: You are a helpful assistant. + role: system + - content: What is 1+1? + role: user + model: qwen-max + parameters: + incremental_output: true + result_format: message + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"1","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":27,"output_tokens":1,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"6b2112e5-d782-47ce-8409-9edacf44ef5f"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"+","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":28,"output_tokens":2,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"6b2112e5-d782-47ce-8409-9edacf44ef5f"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"1 equals ","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":31,"output_tokens":5,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"6b2112e5-d782-47ce-8409-9edacf44ef5f"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"2.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":33,"output_tokens":7,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"6b2112e5-d782-47ce-8409-9edacf44ef5f"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":33,"output_tokens":7,"input_tokens":26,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"6b2112e5-d782-47ce-8409-9edacf44ef5f"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:14:39 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764684879325' + req-cost-time: + - '229' + resp-start-time: + - '1764684879554' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '220' + x-request-id: + - 6b2112e5-d782-47ce-8409-9edacf44ef5f + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_parameters.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_parameters.yaml new file mode 100644 index 000000000..379cc0b04 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_model_call_with_parameters.yaml @@ -0,0 +1,155 @@ +interactions: +- request: + body: + input: + messages: + - content: Write a short poem + role: user + model: qwen-max + parameters: + incremental_output: true + max_tokens: 100 + result_format: message + temperature: 0.8 + top_p: 0.9 + headers: + Accept: + - text/event-stream + Content-Type: + - application/json + X-Accel-Buffering: + - 'no' + X-DashScope-SSE: + - enable + authorization: + - Bearer test_api_key + user-agent: + - dashscope/1.25.1; python/3.12.11; platform/macOS-15.1.1-arm64-arm-64bit; processor/arm; + incremental_to_full/0 + method: POST + uri: https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation + response: + body: + string: |+ + id:1 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"B","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":13,"output_tokens":1,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:2 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"eneath the","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":16,"output_tokens":4,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:3 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" moon's soft","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":19,"output_tokens":7,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:4 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" silver","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":20,"output_tokens":8,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:5 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" glow,\nA whisper","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":24,"output_tokens":12,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:6 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"ing wind begins to blow.\n","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":30,"output_tokens":18,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:7 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"It dances through the silent","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":35,"output_tokens":23,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:8 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" trees,\nAnd r","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":39,"output_tokens":27,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:9 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"ipples over quiet seas","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":43,"output_tokens":31,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:10 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":".\n\nThe stars,","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":47,"output_tokens":35,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:11 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" like tiny lanterns hung","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":52,"output_tokens":40,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:12 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":",\nAbove the earth in","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":57,"output_tokens":45,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:13 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" darkness strung.\n","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":61,"output_tokens":49,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:14 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"They twinkle with","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":65,"output_tokens":53,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:15 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" a gentle light,\nGuid","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":70,"output_tokens":58,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:16 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"ing dreams that take","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":74,"output_tokens":62,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:17 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":" their flight.","role":"assistant"},"finish_reason":"null"}]},"usage":{"total_tokens":77,"output_tokens":65,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + id:18 + event:result + :HTTP_STATUS/200 + data:{"output":{"choices":[{"message":{"content":"","role":"assistant"},"finish_reason":"stop"}]},"usage":{"total_tokens":77,"output_tokens":65,"input_tokens":12,"prompt_tokens_details":{"cached_tokens":0}},"request_id":"34c93a21-9ab6-496a-b8f3-5b1f7a87b038"} + + headers: + Content-Type: + - text/event-stream;charset=UTF-8 + Date: + - Tue, 02 Dec 2025 14:17:57 GMT + Server: + - istio-envoy + Set-Cookie: test_set_cookie + Transfer-Encoding: + - chunked + Vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers + req-arrive-time: + - '1764685077736' + req-cost-time: + - '261' + resp-start-time: + - '1764685077997' + x-dashscope-call-gateway: + - 'true' + x-dashscope-finished: + - 'false' + x-dashscope-timeout: + - '298' + x-envoy-upstream-service-time: + - '255' + x-request-id: + - 34c93a21-9ab6-496a-b8f3-5b1f7a87b038 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_concurrent_e2e.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_concurrent_e2e.yaml new file mode 100644 index 000000000..fcf53c5b7 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_concurrent_e2e.yaml @@ -0,0 +1,242 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "Reply with exactly one short sentence." + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Say OK for request 2." + } + ] + } + ], + "model": "qwen-plus", + "max_tokens": 16, + "stream": false, + "enable_thinking": false + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '258' + Content-Type: + - application/json + Host: + - dashscope.aliyuncs.com + User-Agent: + - AsyncOpenAI/Python 2.40.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - async:asyncio + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.40.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.11.13 + authorization: + - + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |- + { + "model": "qwen-plus", + "id": "chatcmpl-0d58865c-c0c4-97df-9ef5-841029ada056", + "choices": [ + { + "message": { + "content": "OK", + "role": "assistant" + }, + "index": 0, + "finish_reason": "stop" + } + ], + "created": 1780388664, + "object": "chat.completion", + "usage": { + "total_tokens": 28, + "completion_tokens": 1, + "prompt_tokens": 27, + "prompt_tokens_details": { + "cached_tokens": 0 + } + } + } + headers: + content-length: + - '328' + content-type: + - application/json + date: + - Tue, 02 Jun 2026 08:24:24 GMT + req-arrive-time: + - '1780388664520' + req-cost-time: + - '378' + resp-start-time: + - '1780388664899' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-envoy-upstream-service-time: + - '378' + x-request-id: + - 0d58865c-c0c4-97df-9ef5-841029ada056 + status: + code: 200 + message: OK +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "Reply with exactly one short sentence." + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Say OK for request 1." + } + ] + } + ], + "model": "qwen-plus", + "max_tokens": 16, + "stream": false, + "enable_thinking": false + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '258' + Content-Type: + - application/json + Host: + - dashscope.aliyuncs.com + User-Agent: + - AsyncOpenAI/Python 2.40.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - async:asyncio + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.40.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.11.13 + authorization: + - + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |- + { + "model": "qwen-plus", + "id": "chatcmpl-b1d9db3b-e07f-9dea-a72e-79a244bac8d2", + "choices": [ + { + "message": { + "content": "OK for request 1.", + "role": "assistant" + }, + "index": 0, + "finish_reason": "stop" + } + ], + "created": 1780388664, + "object": "chat.completion", + "usage": { + "total_tokens": 33, + "completion_tokens": 6, + "prompt_tokens": 27, + "prompt_tokens_details": { + "cached_tokens": 0 + } + } + } + headers: + content-length: + - '343' + content-type: + - application/json + date: + - Tue, 02 Jun 2026 08:24:24 GMT + req-arrive-time: + - '1780388664535' + req-cost-time: + - '510' + resp-start-time: + - '1780388665045' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-envoy-upstream-service-time: + - '509' + x-request-id: + - b1d9db3b-e07f-9dea-a72e-79a244bac8d2 + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_non_streaming_e2e.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_non_streaming_e2e.yaml new file mode 100644 index 000000000..e6cb0678f --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_non_streaming_e2e.yaml @@ -0,0 +1,122 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "Reply with exactly: OK" + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Say OK." + } + ] + } + ], + "model": "qwen-plus", + "max_tokens": 16, + "stream": false, + "enable_thinking": false + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '228' + Content-Type: + - application/json + Host: + - dashscope.aliyuncs.com + User-Agent: + - AsyncOpenAI/Python 2.40.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - async:asyncio + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.40.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.11.13 + authorization: + - + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |- + { + "model": "qwen-plus", + "id": "chatcmpl-d1fc4eda-fe73-9625-9108-2b83bca90dbb", + "choices": [ + { + "message": { + "content": "OK", + "role": "assistant" + }, + "index": 0, + "finish_reason": "stop" + } + ], + "created": 1780388663, + "object": "chat.completion", + "usage": { + "total_tokens": 22, + "completion_tokens": 1, + "prompt_tokens": 21, + "prompt_tokens_details": { + "cached_tokens": 0 + } + } + } + headers: + content-length: + - '328' + content-type: + - application/json + date: + - Tue, 02 Jun 2026 08:24:23 GMT + req-arrive-time: + - '1780388663479' + req-cost-time: + - '330' + resp-start-time: + - '1780388663810' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin,Access-Control-Request-Method,Access-Control-Request-Headers, Accept-Encoding + x-dashscope-call-gateway: + - 'true' + x-envoy-upstream-service-time: + - '330' + x-request-id: + - d1fc4eda-fe73-9625-9108-2b83bca90dbb + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_streaming_e2e.yaml b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_streaming_e2e.yaml new file mode 100644 index 000000000..36f3135a5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/cassettes/test_v2_agent_streaming_e2e.yaml @@ -0,0 +1,111 @@ +interactions: +- request: + body: |- + { + "messages": [ + { + "role": "system", + "content": [ + { + "type": "text", + "text": "Reply with a short sentence." + } + ] + }, + { + "role": "user", + "content": [ + { + "type": "text", + "text": "Say hello in one sentence." + } + ] + } + ], + "model": "qwen-plus", + "max_tokens": 16, + "stream": true, + "stream_options": { + "include_usage": true + }, + "enable_thinking": false + } + headers: + Accept: + - application/json + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '292' + Content-Type: + - application/json + Host: + - dashscope.aliyuncs.com + User-Agent: + - AsyncOpenAI/Python 2.40.0 + X-Stainless-Arch: + - arm64 + X-Stainless-Async: + - async:asyncio + X-Stainless-Lang: + - python + X-Stainless-OS: + - MacOS + X-Stainless-Package-Version: + - 2.40.0 + X-Stainless-Runtime: + - CPython + X-Stainless-Runtime-Version: + - 3.11.13 + authorization: + - + x-stainless-read-timeout: + - '600' + x-stainless-retry-count: + - '0' + method: POST + uri: https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions + response: + body: + string: |+ + data: {"model":"qwen-plus","id":"chatcmpl-23d2afca-b6f8-9fb2-9c79-a40825fe928d","created":1780388664,"object":"chat.completion.chunk","usage":null,"choices":[{"logprobs":null,"index":0,"delta":{"content":"","role":"assistant"},"finish_reason":null}]} + + data: {"model":"qwen-plus","id":"chatcmpl-23d2afca-b6f8-9fb2-9c79-a40825fe928d","choices":[{"delta":{"content":"Hello"},"index":0,"finish_reason":null,"logprobs":null}],"created":1780388664,"object":"chat.completion.chunk","usage":null} + + data: {"model":"qwen-plus","id":"chatcmpl-23d2afca-b6f8-9fb2-9c79-a40825fe928d","choices":[{"delta":{"content":"!"},"index":0,"finish_reason":null,"logprobs":null}],"created":1780388664,"object":"chat.completion.chunk","usage":null} + + data: {"model":"qwen-plus","id":"chatcmpl-23d2afca-b6f8-9fb2-9c79-a40825fe928d","choices":[{"delta":{"content":""},"index":0,"finish_reason":"stop","logprobs":null}],"created":1780388664,"object":"chat.completion.chunk","usage":null} + + data: {"model":"qwen-plus","id":"chatcmpl-23d2afca-b6f8-9fb2-9c79-a40825fe928d","choices":[],"created":1780388664,"object":"chat.completion.chunk","usage":{"total_tokens":27,"completion_tokens":2,"prompt_tokens":25,"prompt_tokens_details":{"cached_tokens":0}}} + + data: [DONE] + + headers: + content-type: + - text/event-stream;charset=utf-8 + date: + - Tue, 02 Jun 2026 08:24:24 GMT + req-arrive-time: + - '1780388663952' + req-cost-time: + - '372' + resp-start-time: + - '1780388664324' + server: + - istio-envoy + transfer-encoding: + - chunked + vary: + - Origin + x-dashscope-call-gateway: + - 'true' + x-envoy-upstream-service-time: + - '372' + x-request-id: + - 23d2afca-b6f8-9fb2-9c79-a40825fe928d + status: + code: 200 + message: OK +version: 1 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/__init__.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/__init__.py new file mode 100644 index 000000000..e57cf4aba --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/__init__.py @@ -0,0 +1,2 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/orchestration.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/orchestration.py new file mode 100644 index 000000000..6fed21513 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conformance/orchestration.py @@ -0,0 +1,148 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Conformance scenario: a DashScope-backed AgentScope v2 agent uses a tool. + +Exercises the three agent shapes a single ``Agent.reply`` produces when the +model decides to call a function tool: + +- Basic agent invocation (``invoke_agent``). +- The chat completions the agent issues to its model (``chat``) — one to + request the tool call and one to summarize the tool result. +- Function tool execution (``execute_tool``). + +The agent runs with ``PermissionMode.BYPASS`` so the recorded ReAct loop +executes the tool without a human-in-the-loop confirmation prompt. +""" + +from __future__ import annotations + +import asyncio +import os +from typing import Any +from unittest import mock + +from agentscope.agent import Agent +from agentscope.credential import DashScopeCredential +from agentscope.message import TextBlock, UserMsg +from agentscope.model import DashScopeChatModel +from agentscope.permission import PermissionContext, PermissionMode +from agentscope.state import AgentState +from agentscope.tool import FunctionTool, Toolkit, ToolResponse + +from opentelemetry.instrumentation.genai.agentscope import ( + AgentScopeInstrumentor, +) +from opentelemetry.sdk._logs import LoggerProvider +from opentelemetry.sdk.metrics import MeterProvider +from opentelemetry.sdk.trace import TracerProvider +from opentelemetry.test.weaver_live_check import LiveCheckReport +from opentelemetry.test_util_genai.conformance import Scenario +from opentelemetry.test_util_genai.instrumentor import instrument + +DEFAULT_MODEL = "qwen-plus" + + +def get_weather(city: str) -> ToolResponse: + """Look up the current weather for a city.""" + return ToolResponse( + content=[ + TextBlock( + type="text", + text=f"The weather in {city} is sunny with a high of 24C.", + ) + ] + ) + + +def _build_model() -> DashScopeChatModel: + return DashScopeChatModel( + credential=DashScopeCredential( + api_key=os.environ["DASHSCOPE_API_KEY"] + ), + model=DEFAULT_MODEL, + parameters=DashScopeChatModel.Parameters( + max_tokens=256, + thinking_enable=False, + ), + stream=False, + max_retries=0, + ) + + +def _build_agent() -> Agent: + return Agent( + name="weather_agent", + system_prompt=( + "You answer weather questions. Always call the get_weather tool " + "for the requested city, then reply in one short sentence." + ), + model=_build_model(), + toolkit=Toolkit(tools=[FunctionTool(get_weather)]), + state=AgentState( + permission_context=PermissionContext(mode=PermissionMode.BYPASS) + ), + ) + + +class OrchestrationScenario(Scenario): + expected_spans = { + "invoke_agent": 1, + # The agent issues one chat to request the tool call and one to + # summarize the tool result. + "chat": 2, + "execute_tool": 1, + } + expected_metrics = ( + "gen_ai.client.operation.duration", + "gen_ai.client.token.usage", + ) + + def run( + self, + *, + tracer_provider: TracerProvider, + meter_provider: MeterProvider, + logger_provider: LoggerProvider, + vcr: Any, + ) -> None: + key_override = ( + {} + if os.getenv("DASHSCOPE_API_KEY") + else {"DASHSCOPE_API_KEY": "test_api_key"} + ) + with mock.patch.dict(os.environ, key_override): + with instrument( + AgentScopeInstrumentor(), + tracer_provider=tracer_provider, + logger_provider=logger_provider, + meter_provider=meter_provider, + content_capture="SPAN_ONLY", + ): + with vcr.use_cassette("orchestration_conformance.yaml"): + agent = _build_agent() + asyncio.run( + agent.reply( + UserMsg( + name="user", + content="What is the weather in Hangzhou?", + ) + ) + ) + + def validate(self, report: LiveCheckReport) -> None: + super().validate(report) + # Presence of the invoke_agent, chat, and execute_tool operations is + # already enforced by ``expected_spans``; only the agent-name attribute + # needs a scenario-specific check. + agent_names = { + attr["value"] + for entry in report["samples"] + if "span" in entry + for attr in entry["span"]["attributes"] + if attr["name"] == "gen_ai.agent.name" + } + assert agent_names, ( + "invoke_agent span must carry gen_ai.agent.name; " + f"saw {sorted(agent_names)}" + ) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conftest.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conftest.py new file mode 100644 index 000000000..9c9858a7b --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/conftest.py @@ -0,0 +1,186 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Test configuration for the AgentScope instrumentation package.""" + +from __future__ import annotations + +import asyncio +import inspect +import os +from importlib.metadata import PackageNotFoundError, version +from pathlib import Path + +import pytest + +pytest_plugins = [ + "opentelemetry.test_util_genai.fixtures", + "opentelemetry.test_util_genai.vcr", +] + +# Set up DASHSCOPE_API_KEY before any dashscope modules are imported. The +# dashscope SDK reads environment variables at import time and caches them. +if "DASHSCOPE_API_KEY" not in os.environ: + os.environ["DASHSCOPE_API_KEY"] = "test_api_key" + +# vcrpy's aiohttp stub still references a mixin removed by newer aiohttp +# releases. Patch it so replay works during marker setup. +try: + import aiohttp.streams # type: ignore[import-not-found] + + if not hasattr(aiohttp.streams, "AsyncStreamReaderMixin"): + aiohttp.streams.AsyncStreamReaderMixin = object +except ImportError: + pass + +try: + import aiohttp # type: ignore[import-not-found] + import vcr.stubs.aiohttp_stubs as aiohttp_stubs + + if ( + "stream_writer" + in inspect.signature(aiohttp.ClientResponse.__init__).parameters + ): + + class _CompatStreamWriter: + output_size = 0 + + class _CompatMockClientResponse(aiohttp_stubs.MockClientResponse): + def __init__(self, method, url, request_info=None): + aiohttp.ClientResponse.__init__( + self, + method=method, + url=url, + writer=None, + continue100=None, + timer=None, + request_info=request_info, + traces=None, + loop=asyncio.get_event_loop(), + session=None, + stream_writer=_CompatStreamWriter(), + ) + + aiohttp_stubs.MockClientResponse = _CompatMockClientResponse +except ImportError: + pass + +from opentelemetry.instrumentation.genai.agentscope import ( # noqa: E402 + AgentScopeInstrumentor, +) +from opentelemetry.test_util_genai.instrumentor import ( # noqa: E402 + instrument as _instrument, +) + +_V2_TEST_FILE = "test_v2_instrumentation.py" +# Files that must also be collected under agentscope v2. test_conformance.py +# carries its own module-level skips for non-conformance envs. +_V2_EXTRA_TEST_FILES = frozenset({"test_conformance.py"}) + + +def _agentscope_major() -> int: + try: + installed_version = version("agentscope") + except PackageNotFoundError: + return 1 + try: + return int(installed_version.split(".", 1)[0]) + except ValueError: + return 1 + + +def pytest_configure(config: pytest.Config) -> None: + config.option.asyncio_mode = "auto" + os.environ["JUPYTER_PLATFORM_DIRS"] = "1" + config.option.api_key = os.environ["DASHSCOPE_API_KEY"] + + +def pytest_ignore_collect(collection_path, config): # noqa: ARG001 + path = Path(str(collection_path)) + if not path.name.startswith("test_") or path.suffix != ".py": + return None + + major = _agentscope_major() + if major >= 2: + if path.name in _V2_EXTRA_TEST_FILES: + return None + return path.name != _V2_TEST_FILE + if path.name == _V2_TEST_FILE: + return True + return None + + +@pytest.fixture(scope="module") +def vcr_config(): + from opentelemetry.test_util_genai.vcr import ( # noqa: PLC0415 + scrub_response_headers, + ) + + return { + "filter_headers": [ + ("authorization", ""), + ("api-key", ""), + ], + "decode_compressed_response": True, + "before_record_response": scrub_response_headers(["set-cookie"]), + } + + +@pytest.fixture +def dashscope_model(request): + from agentscope.model import DashScopeChatModel # noqa: PLC0415 + + return DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + + +@pytest.fixture +def instrument(tracer_provider, logger_provider, meter_provider): + with _instrument( + AgentScopeInstrumentor(), + tracer_provider=tracer_provider, + logger_provider=logger_provider, + meter_provider=meter_provider, + ) as instrumentor: + yield instrumentor + + +@pytest.fixture +def instrument_no_content(tracer_provider, logger_provider, meter_provider): + with _instrument( + AgentScopeInstrumentor(), + tracer_provider=tracer_provider, + logger_provider=logger_provider, + meter_provider=meter_provider, + content_capture="NO_CONTENT", + ) as instrumentor: + yield instrumentor + + +@pytest.fixture +def instrument_with_content(tracer_provider, logger_provider, meter_provider): + with _instrument( + AgentScopeInstrumentor(), + tracer_provider=tracer_provider, + logger_provider=logger_provider, + meter_provider=meter_provider, + content_capture="SPAN_ONLY", + ) as instrumentor: + yield instrumentor + + +@pytest.fixture +def instrument_with_content_and_events( + tracer_provider, logger_provider, meter_provider +): + with _instrument( + AgentScopeInstrumentor(), + tracer_provider=tracer_provider, + logger_provider=logger_provider, + meter_provider=meter_provider, + content_capture="SPAN_AND_EVENT", + emit_event=True, + ) as instrumentor: + yield instrumentor diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt new file mode 100644 index 000000000..14c2ee481 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt @@ -0,0 +1,43 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# ******************************** +# WARNING: NOT HERMETIC !!!!!!!!!! +# ******************************** +# +# This "requirements.txt" is installed in conjunction +# with multiple other dependencies in the top-level "tox.ini" +# file. In particular, please see: +# +# agentscope-latest: {[testenv]test_deps} +# agentscope-latest: -r {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt +# +# This provides additional dependencies, namely: +# +# opentelemetry-api +# opentelemetry-sdk +# opentelemetry-semantic-conventions +# opentelemetry-instrumentation +# +# ... with a "dev" version based on the latest distribution. + + +# This variant of the requirements aims to test the system using +# the newest supported version of external dependencies. + +agentscope >= 2.0.0, < 3.0.0 + +-e util/opentelemetry-util-genai +-e instrumentation/opentelemetry-instrumentation-genai-agentscope diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.oldest.txt b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.oldest.txt new file mode 100644 index 000000000..ceecbd576 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.oldest.txt @@ -0,0 +1,22 @@ +# Copyright The OpenTelemetry Authors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Oldest test-only dependency pins. +# +# The package's own declared deps (agentscope via the instruments extra, opentelemetry-api, +# opentelemetry-instrumentation, opentelemetry-semantic-conventions, opentelemetry-util-genai) +# are resolved to their pyproject.toml floors by UV_RESOLUTION=lowest-direct on the oldest tox +# factor, so they are NOT pinned here — pyproject.toml is the single source of truth. The +# OpenTelemetry SDK and test utilities come transitively from opentelemetry-test-util-genai, which +# every oldest env installs. Pin here only test-only deps that nothing else already provides. diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_agent.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_agent.py new file mode 100644 index 000000000..b5668b347 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_agent.py @@ -0,0 +1,183 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""AgentScope agent and tool instrumentation tests.""" + +from __future__ import annotations + +import asyncio + +import agentscope +import pytest +from agentscope.agent import ReActAgent +from agentscope.formatter import DashScopeChatFormatter +from agentscope.message import Msg +from agentscope.model import DashScopeChatModel +from agentscope.tool import Toolkit, execute_shell_command + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + +from ._test_helpers import ( + assert_no_removed_telemetry, + find_spans_by_name_prefix, +) + + +async def _drain(response): + try: + is_stream = hasattr(response, "__aiter__") + except (KeyError, AttributeError): + is_stream = False + if is_stream: + result = [] + async for chunk in response: + result.append(chunk) + return result[-1] if result else response + return response + + +async def _call_agent(agent, msg): + return await _drain(await agent(msg)) + + +class TestAgentBasic: + @pytest.mark.vcr() + def test_agent_simple_call( + self, span_exporter, instrument_with_content, dashscope_model + ): + agentscope.init(project="test_agent_simple") + agent = ReActAgent( + name="TestAgent", + sys_prompt="You are a helpful assistant.", + model=dashscope_model, + formatter=DashScopeChatFormatter(), + ) + msg = Msg("user", "Hello, how are you?", "user") + + response = asyncio.run(_call_agent(agent, msg)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + assert len(spans) >= 1 + assert len(find_spans_by_name_prefix(spans, "chat ")) > 0 + + @pytest.mark.vcr() + def test_agent_with_tool( + self, span_exporter, instrument_with_content, dashscope_model + ): + agentscope.init(project="test_agent_tool") + toolkit = Toolkit() + toolkit.register_tool_function(execute_shell_command) + agent = ReActAgent( + name="ToolAgent", + sys_prompt="You are an assistant with tool access.", + model=dashscope_model, + formatter=DashScopeChatFormatter(), + toolkit=toolkit, + ) + msg = Msg("user", "compute 10+20 for me using shell", "user") + + async def run(): + try: + return await _drain(await agent(msg)) + except Exception: + return None + + asyncio.run(run()) + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + assert len(spans) >= 1 + assert len(find_spans_by_name_prefix(spans, "chat ")) > 0 + + @pytest.mark.vcr() + def test_agent_multiple_turns( + self, span_exporter, instrument_with_content, dashscope_model + ): + agentscope.init(project="test_agent_multi_turn") + agent = ReActAgent( + name="MultiTurnAgent", + sys_prompt="You are a helpful assistant.", + model=dashscope_model, + formatter=DashScopeChatFormatter(), + ) + + async def run(message: str): + return await _drain(await agent(Msg("user", message, "user"))) + + asyncio.run(run("Hello")) + asyncio.run(run("What's 2+2?")) + asyncio.run(run("Thank you")) + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + assert len(spans) >= 3 + + +class TestAgentAttributes: + @pytest.mark.vcr() + def test_agent_span_attributes( + self, span_exporter, instrument_with_content, dashscope_model + ): + agentscope.init(project="test_agent_attrs") + agent = ReActAgent( + name="AttributeAgent", + sys_prompt="You are a test assistant.", + model=dashscope_model, + formatter=DashScopeChatFormatter(), + ) + msg = Msg("user", "Simple test", "user") + + asyncio.run(_call_agent(agent, msg)) + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + + chat_spans = find_spans_by_name_prefix(spans, "chat ") + assert len(chat_spans) > 0 + attrs = chat_spans[0].attributes + assert GenAIAttributes.GEN_AI_OPERATION_NAME in attrs + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in attrs + assert "gen_ai.provider.name" in attrs + + # invoke_agent spans carry only the standard operation-name attribute. + agent_spans = find_spans_by_name_prefix(spans, "invoke_agent") + for agent_span in agent_spans: + assert ( + agent_span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] + == "invoke_agent" + ) + assert "gen_ai.span.kind" not in agent_span.attributes + + +class TestAgentError: + @pytest.mark.vcr() + def test_agent_with_invalid_model( + self, span_exporter, instrument_with_content + ): + agentscope.init(project="test_invalid_model") + invalid_model = DashScopeChatModel( + model_name="qwen-max", + api_key="invalid_key_test", + ) + agent = ReActAgent( + name="InvalidAgent", + sys_prompt="Test agent", + model=invalid_model, + formatter=DashScopeChatFormatter(), + ) + msg = Msg("user", "Test", "user") + + async def run(): + try: + return await _drain(await agent(msg)) + except Exception: + return None + + asyncio.run(run()) + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_call_chain_reentrancy.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_call_chain_reentrancy.py new file mode 100644 index 000000000..3df3deeb6 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_call_chain_reentrancy.py @@ -0,0 +1,74 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Stacked ChatModelBase / AgentBase ``__call__`` (proxy chains) emit one span.""" + +from __future__ import annotations + +import agentscope +import pytest +from agentscope.agent import AgentBase +from agentscope.message import Msg +from agentscope.model import ChatModelBase, ChatResponse + + +@pytest.mark.asyncio +async def test_nested_chat_model_proxies_single_chat_span( + instrument_with_content, span_exporter +): + """Two ChatModelBase subclasses in a delegate chain -> one LLM span.""" + agentscope.init(project="test_nested_chat_proxy") + + class CoreModel(ChatModelBase): + def __init__(self) -> None: + super().__init__("core-model", False) + + async def __call__(self, *args, **kwargs): + return ChatResponse(content=[{"type": "text", "text": "ok"}]) + + class ProxyModel(ChatModelBase): + def __init__(self, inner: ChatModelBase) -> None: + super().__init__("proxy-model", False) + self._inner = inner + + async def __call__(self, *args, **kwargs): + return await self._inner(*args, **kwargs) + + model = ProxyModel(CoreModel()) + await model([]) + + spans = span_exporter.get_finished_spans() + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) == 1, ( + f"expected exactly 1 chat span for nested models, got {len(chat_spans)}" + ) + + +@pytest.mark.asyncio +async def test_nested_agent_proxies_single_invoke_agent_span( + instrument_with_content, span_exporter +): + """Two AgentBase subclasses where reply delegates -> one invoke_agent span.""" + agentscope.init(project="test_nested_agent_proxy") + + class LeafAgent(AgentBase): + async def reply(self, msg=None, structured_model=None): + return Msg("leaf", "done", role="assistant") + + class ProxyAgent(AgentBase): + def __init__(self, inner: AgentBase) -> None: + super().__init__() + self._inner = inner + + async def reply(self, msg=None, structured_model=None): + return await self._inner(msg, structured_model) + + agent = ProxyAgent(LeafAgent()) + await agent() + + spans = span_exporter.get_finished_spans() + invoke_spans = [s for s in spans if "invoke_agent" in s.name.lower()] + assert len(invoke_spans) == 1, ( + f"expected exactly 1 invoke_agent span for nested agents, " + f"got {len(invoke_spans)}" + ) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py new file mode 100644 index 000000000..bf42fcd89 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py @@ -0,0 +1,44 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Per-scenario conformance tests for agentscope.""" + +from __future__ import annotations + +import importlib.metadata +from typing import Any + +import pytest + +# Skip collection when weaver_live_check or OTLP exporters aren't installed +# (non-conformance envs). +pytest.importorskip("opentelemetry.test.weaver_live_check") +pytest.importorskip("opentelemetry.exporter.otlp.proto.grpc") + +agentscope = pytest.importorskip("agentscope") +if not importlib.metadata.version("agentscope").startswith("2."): + pytest.skip( + "AgentScope conformance scenarios require agentscope>=2,<3", + allow_module_level=True, + ) + +from opentelemetry.test.weaver_live_check import WeaverLiveCheck # noqa: E402 +from opentelemetry.test_util_genai.conformance import ( # noqa: E402 + Scenario, + run_conformance, +) + +from .conformance.orchestration import OrchestrationScenario # noqa: E402 + + +@pytest.mark.parametrize( + "scenario", + [ + OrchestrationScenario(), + ], + ids=lambda s: type(s).__name__, +) +def test_conformance( + scenario: Scenario, vcr: Any, weaver_live_check: WeaverLiveCheck +) -> None: + run_conformance(scenario, vcr=vcr, weaver=weaver_live_check) diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_instrumentor.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_instrumentor.py new file mode 100644 index 000000000..327958eec --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_instrumentor.py @@ -0,0 +1,95 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Tests for the AgentScope instrumentor lifecycle.""" + +from __future__ import annotations + +import unittest +from unittest.mock import patch + +import agentscope.tracing._trace as agentscope_tracing_trace +import wrapt + +from opentelemetry.instrumentation.genai.agentscope import ( + AgentScopeInstrumentor, +) +from opentelemetry.sdk.trace import TracerProvider + + +class TestAgentScopeInstrumentor(unittest.TestCase): + def setUp(self): + self.tracer_provider = TracerProvider() + self.instrumentor = AgentScopeInstrumentor() + + def tearDown(self): + try: + self.instrumentor.uninstrument() + except Exception: + pass + + def test_init(self): + self.assertIsNotNone(self.instrumentor) + self.assertIsNone(self.instrumentor._handler) + + def test_instrumentation_dependencies(self): + dependencies = self.instrumentor.instrumentation_dependencies() + self.assertIsInstance(dependencies, tuple) + self.assertTrue(any("agentscope" in dep for dep in dependencies)) + + def test_instrument_creates_handler(self): + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + self.assertIsNotNone(self.instrumentor._handler) + + def test_uninstrument_clears_handler(self): + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + self.instrumentor.uninstrument() + self.assertIsNone(self.instrumentor._handler) + + def test_uninstrument_without_instrument(self): + try: + self.instrumentor.uninstrument() + except Exception as e: # noqa: BLE001 + self.fail(f"uninstrument() raised unexpectedly: {e}") + + def test_uninstrument_exception_handling(self): + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + with patch( + "builtins.__import__", side_effect=ImportError("no module") + ): + try: + self.instrumentor.uninstrument() + except Exception as e: # noqa: BLE001 + self.fail(f"uninstrument() raised unexpectedly: {e}") + + def test_instrument_multiple_times(self): + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + self.assertIsNotNone(self.instrumentor._handler) + + def test_check_tracing_enabled_patch(self): + original_func = getattr( + agentscope_tracing_trace, "_check_tracing_enabled", None + ) + if original_func is None: + self.skipTest("_check_tracing_enabled not present in agentscope") + + # wrap_function_wrapper installs a wrapt.FunctionWrapper. Check for that + # explicitly rather than ObjectProxy: wrapt 2.x no longer makes + # FunctionWrapper a subclass of ObjectProxy. + self.assertFalse(isinstance(original_func, wrapt.FunctionWrapper)) + + self.instrumentor.instrument(tracer_provider=self.tracer_provider) + + patched_func = agentscope_tracing_trace._check_tracing_enabled + self.assertTrue(isinstance(patched_func, wrapt.FunctionWrapper)) + self.assertFalse(patched_func()) + + self.instrumentor.uninstrument() + + restored_func = agentscope_tracing_trace._check_tracing_enabled + self.assertFalse(isinstance(restored_func, wrapt.FunctionWrapper)) + + +if __name__ == "__main__": + unittest.main() diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_model.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_model.py new file mode 100644 index 000000000..ad18a328c --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_model.py @@ -0,0 +1,247 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""AgentScope chat model instrumentation tests.""" + +from __future__ import annotations + +import asyncio + +import agentscope +import pytest +from agentscope.model import DashScopeChatModel + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + +from ._test_helpers import assert_no_removed_telemetry + + +def _assert_chat_span_attributes( + span, + request_model: str, + *, + expect_input_messages: bool = False, + expect_output_messages: bool = False, +) -> None: + """Assert common chat model span attributes.""" + assert span.name.startswith("chat "), f"Unexpected span name: {span.name}" + assert request_model in span.name + + # Standard OpenTelemetry operation-name attribute is always present, and + # the removed gen_ai.span.kind attribute must never be set. + assert span.attributes[GenAIAttributes.GEN_AI_OPERATION_NAME] == "chat" + assert "gen_ai.span.kind" not in span.attributes + + assert span.attributes["gen_ai.provider.name"] == "dashscope" + assert ( + span.attributes[GenAIAttributes.GEN_AI_REQUEST_MODEL] == request_model + ) + + if expect_input_messages: + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in span.attributes + else: + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES not in span.attributes + + if expect_output_messages: + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in span.attributes + else: + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in span.attributes + + +async def _drain(response): + try: + is_stream = hasattr(response, "__aiter__") + except (KeyError, AttributeError): + is_stream = False + if is_stream: + result = [] + async for chunk in response: + result.append(chunk) + return result[-1] if result else response + return response + + +@pytest.mark.vcr() +def test_model_call_basic(instrument_no_content, span_exporter, request): + agentscope.init(project="test_basic") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + messages = [{"role": "user", "content": "Hello!"}] + + response = asyncio.run(_wrap(model, messages)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes(chat_spans[0], request_model="qwen-max") + + +async def _wrap(model, messages, **kwargs): + response = await model(messages, **kwargs) + return await _drain(response) + + +@pytest.mark.vcr() +def test_model_call_with_messages( + instrument_no_content, span_exporter, request +): + agentscope.init(project="test_messages") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + messages = [ + {"role": "system", "content": "You are a helpful assistant."}, + {"role": "user", "content": "What is 1+1?"}, + ] + + response = asyncio.run(_wrap(model, messages)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes(chat_spans[0], request_model="qwen-max") + + +@pytest.mark.vcr() +async def test_model_call_async(instrument_no_content, span_exporter, request): + agentscope.init(project="test_async") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + messages = [{"role": "user", "content": "Hello from async!"}] + + response = await _wrap(model, messages) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes(chat_spans[0], request_model="qwen-max") + + +@pytest.mark.vcr() +def test_model_call_streaming(instrument, span_exporter, request): + agentscope.init(project="test_streaming") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + stream=True, + ) + messages = [{"role": "user", "content": "Count from 1 to 5"}] + + response = asyncio.run(_wrap(model, messages)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes(chat_spans[0], request_model="qwen-max") + + +@pytest.mark.vcr() +def test_model_call_with_parameters(instrument, span_exporter, request): + agentscope.init(project="test_parameters") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + messages = [{"role": "user", "content": "Write a short poem"}] + + response = asyncio.run( + _wrap(model, messages, temperature=0.8, top_p=0.9, max_tokens=100) + ) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes(chat_spans[0], request_model="qwen-max") + + +@pytest.mark.vcr() +def test_model_call_with_content_capture( + instrument_with_content, span_exporter, request +): + agentscope.init(project="test_content_capture") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + stream=False, + ) + messages = [{"role": "user", "content": "Say this is a test"}] + + response = asyncio.run(_wrap(model, messages)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes( + chat_spans[0], + request_model="qwen-max", + expect_input_messages=True, + expect_output_messages=True, + ) + + +@pytest.mark.vcr() +def test_model_call_no_content_capture( + instrument_no_content, span_exporter, request +): + agentscope.init(project="test_no_content_capture") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + messages = [{"role": "user", "content": "Say this is a test"}] + + response = asyncio.run(_wrap(model, messages)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 1 + _assert_chat_span_attributes( + chat_spans[0], + request_model="qwen-max", + expect_input_messages=False, + expect_output_messages=False, + ) + + +@pytest.mark.vcr() +def test_model_call_multiple_sequential(instrument, span_exporter, request): + agentscope.init(project="test_multiple") + model = DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + ) + + async def call(content: str): + return await _wrap(model, [{"role": "user", "content": content}]) + + asyncio.run(call("First call")) + asyncio.run(call("Second call")) + asyncio.run(call("Third call")) + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + chat_spans = [s for s in spans if s.name.startswith("chat ")] + assert len(chat_spans) >= 3 + for chat_span in chat_spans[:3]: + _assert_chat_span_attributes(chat_span, request_model="qwen-max") diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_multimodal.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_multimodal.py new file mode 100644 index 000000000..86ba9ed0e --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_multimodal.py @@ -0,0 +1,381 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Multimodal content-type conversion tests. + +Verify the AgentScope block/message converters map onto the correct +``opentelemetry-util-genai`` message parts (``Text``/``Reasoning``/``Uri``/ +``Blob``/``ToolCallRequest``). +""" + +from __future__ import annotations + +import base64 + +from agentscope.message import ImageBlock, Msg + +from opentelemetry.instrumentation.genai.agentscope.utils import ( + _convert_block_to_part, + _format_msg_to_parts, + convert_agent_response_to_output_messages, + convert_agentscope_messages_to_genai_format, +) +from opentelemetry.util.genai.types import Blob, Text, Uri + + +class TestBlockConversion: + """Test individual block conversion to part dicts.""" + + def test_text_block_to_part(self): + block = {"type": "text", "text": "Hello world"} + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "text" + assert part["content"] == "Hello world" + + def test_image_url_block_to_uri_part(self): + block = { + "type": "image", + "source": {"type": "url", "url": "https://example.com/cat.jpg"}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "uri" + assert part["uri"] == "https://example.com/cat.jpg" + assert part["modality"] == "image" + assert part["mime_type"] == "image/jpeg" + + def test_image_base64_block_to_blob_part(self): + test_data = base64.b64encode( + bytes.fromhex( + "89504e470d0a1a0a0000000d49484452000000010000000108020000009" + "0774c53000000014944415408d76360f8ff0f00020100018d9c7d000000" + "0049454e44ae426082" + ) + ).decode("utf-8") + + block = { + "type": "image", + "source": { + "type": "base64", + "media_type": "image/png", + "data": test_data, + }, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "blob" + assert part["content"] == test_data + assert part["media_type"] == "image/png" + assert part["modality"] == "image" + + def test_audio_url_block_to_uri_part(self): + block = { + "type": "audio", + "source": {"type": "url", "url": "https://example.com/sound.mp3"}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "uri" + assert part["modality"] == "audio" + assert part["mime_type"] == "audio/mpeg" + + def test_image_url_with_query_params(self): + block = { + "type": "image", + "source": { + "type": "url", + "url": "https://oss.example.com/image.png?token=abc&expires=1", + }, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "uri" + assert part["mime_type"] == "image/png" + + def test_video_base64_block_to_blob_part(self): + block = { + "type": "video", + "source": { + "type": "base64", + "media_type": "video/mp4", + "data": "dGVzdHZpZGVv", + }, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "blob" + assert part["modality"] == "video" + assert part["media_type"] == "video/mp4" + + def test_thinking_block_to_reasoning_part(self): + block = {"type": "thinking", "thinking": "Let me think..."} + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "reasoning" + assert part["content"] == "Let me think..." + + def test_tool_use_block_to_tool_call_part(self): + block = { + "type": "tool_use", + "id": "call_123", + "name": "search", + "input": {"query": "test"}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "tool_call" + assert part["id"] == "call_123" + assert part["name"] == "search" + assert part["arguments"] == {"query": "test"} + + +class TestMsgConversion: + """Test ``Msg`` to part-dict conversion.""" + + def test_simple_text_msg(self): + msg = Msg(name="user", content="Hello", role="user") + result = _format_msg_to_parts(msg) + + assert result["role"] == "user" + assert len(result["parts"]) == 1 + assert result["parts"][0]["type"] == "text" + assert result["parts"][0]["content"] == "Hello" + + def test_msg_with_image_url(self): + msg = Msg( + name="assistant", + role="assistant", + content=[ + ImageBlock( + type="image", + source={ + "type": "url", + "url": "https://example.com/image.jpg", + }, + ) + ], + ) + result = _format_msg_to_parts(msg) + + assert result["role"] == "assistant" + assert len(result["parts"]) == 1 + assert result["parts"][0]["type"] == "uri" + assert result["parts"][0]["modality"] == "image" + + def test_msg_with_image_base64(self): + test_data = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJ" + + msg = Msg( + name="assistant", + role="assistant", + content=[ + ImageBlock( + type="image", + source={ + "type": "base64", + "media_type": "image/png", + "data": test_data, + }, + ) + ], + ) + result = _format_msg_to_parts(msg) + + assert result["role"] == "assistant" + assert len(result["parts"]) == 1 + assert result["parts"][0]["type"] == "blob" + assert result["parts"][0]["modality"] == "image" + assert result["parts"][0]["content"] == test_data + + def test_msg_with_mixed_content(self): + msg = Msg( + name="assistant", + role="assistant", + content=[ + {"type": "text", "text": "Here is the image:"}, + ImageBlock( + type="image", + source={ + "type": "url", + "url": "https://example.com/cat.jpg", + }, + ), + ], + ) + result = _format_msg_to_parts(msg) + + assert result["role"] == "assistant" + assert len(result["parts"]) == 2 + assert result["parts"][0]["type"] == "text" + assert result["parts"][1]["type"] == "uri" + + +class TestOutputMessageConversion: + """Test ``convert_agent_response_to_output_messages``.""" + + def test_convert_text_response(self): + msg = Msg(name="Bot", role="assistant", content="Hello!") + output_messages = convert_agent_response_to_output_messages(msg) + + assert len(output_messages) == 1 + assert output_messages[0].role == "assistant" + assert len(output_messages[0].parts) == 1 + assert isinstance(output_messages[0].parts[0], Text) + + def test_convert_image_url_response(self): + msg = Msg( + name="Bot", + role="assistant", + content=[ + ImageBlock( + type="image", + source={ + "type": "url", + "url": "https://example.com/image.jpg", + }, + ) + ], + ) + output_messages = convert_agent_response_to_output_messages(msg) + + assert len(output_messages) == 1 + part = output_messages[0].parts[0] + assert isinstance(part, Uri) + assert part.modality == "image" + + def test_convert_image_base64_response(self): + raw = b"fake-image-bytes" + test_data = base64.b64encode(raw).decode("utf-8") + + msg = Msg( + name="Bot", + role="assistant", + content=[ + ImageBlock( + type="image", + source={ + "type": "base64", + "media_type": "image/png", + "data": test_data, + }, + ) + ], + ) + output_messages = convert_agent_response_to_output_messages(msg) + + assert len(output_messages) == 1 + part = output_messages[0].parts[0] + assert isinstance(part, Blob) + assert part.modality == "image" + assert part.content == raw + + +class TestInputMessageConversion: + """Test ``convert_agentscope_messages_to_genai_format``.""" + + def test_convert_simple_messages(self): + messages = [ + Msg(name="user", content="Hello", role="user"), + Msg(name="assistant", content="Hi there!", role="assistant"), + ] + input_messages = convert_agentscope_messages_to_genai_format(messages) + + assert len(input_messages) == 2 + assert input_messages[0].role == "user" + assert input_messages[1].role == "assistant" + + def test_convert_messages_with_image(self): + messages = [ + Msg( + name="assistant", + role="assistant", + content=[ + {"type": "text", "text": "Generated image:"}, + ImageBlock( + type="image", + source={ + "type": "url", + "url": "https://example.com/img.png", + }, + ), + ], + ) + ] + input_messages = convert_agentscope_messages_to_genai_format(messages) + + assert len(input_messages) == 1 + assert len(input_messages[0].parts) == 2 + uri_part = input_messages[0].parts[1] + assert isinstance(uri_part, Uri) + assert uri_part.type == "uri" + + def test_convert_messages_with_blob(self): + raw = b"test" + test_data = base64.b64encode(raw).decode("utf-8") + messages = [ + { + "role": "user", + "parts": [ + { + "type": "blob", + "content": test_data, + "media_type": "image/png", + "modality": "image", + } + ], + } + ] + + input_messages = convert_agentscope_messages_to_genai_format(messages) + + assert len(input_messages) == 1 + assert len(input_messages[0].parts) == 1 + blob_part = input_messages[0].parts[0] + assert isinstance(blob_part, Blob) + assert blob_part.content == raw + assert blob_part.mime_type == "image/png" + assert blob_part.modality == "image" + + +class TestDefaultMediaType: + """Test default media-type handling for blob parts.""" + + def test_image_blob_default_media_type(self): + block = { + "type": "image", + "source": {"type": "base64", "data": "dGVzdA=="}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part["type"] == "blob" + assert part.get("media_type") == "image/jpeg" + + def test_audio_blob_default_media_type(self): + block = { + "type": "audio", + "source": {"type": "base64", "data": "dGVzdA=="}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part.get("media_type") == "audio/wav" + + def test_video_blob_default_media_type(self): + block = { + "type": "video", + "source": {"type": "base64", "data": "dGVzdA=="}, + } + part = _convert_block_to_part(block) + + assert part is not None + assert part.get("media_type") == "video/mp4" diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_span_content.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_span_content.py new file mode 100644 index 000000000..3a01a6127 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_span_content.py @@ -0,0 +1,153 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Span content-capture tests for agent and LLM layers.""" + +from __future__ import annotations + +import asyncio +import json + +import pytest +from agentscope.agent import ReActAgent +from agentscope.formatter import DashScopeChatFormatter +from agentscope.message import Msg +from agentscope.model import DashScopeChatModel +from agentscope.tool import Toolkit + +from opentelemetry.semconv._incubating.attributes import ( + gen_ai_attributes as GenAIAttributes, +) + +from ._test_helpers import ( + assert_no_removed_telemetry, + find_spans_by_operation, +) + + +class TestSpanContentCapture: + @pytest.mark.vcr() + def test_span_content_with_span_only( + self, span_exporter, instrument_with_content, request + ): + """Content captured in SPAN_ONLY mode for both agent and LLM layers.""" + toolkit = Toolkit() + agent = ReActAgent( + name="ContentTest", + sys_prompt="You are a test assistant.", + model=DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + stream=True, + ), + formatter=DashScopeChatFormatter(), + toolkit=toolkit, + ) + msg = Msg("user", "Hello, please say 'Hi' to me", "user") + + response = asyncio.run(agent(msg)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + + agent_spans = find_spans_by_operation(spans, "invoke_agent") + assert len(agent_spans) > 0 + agent_attrs = dict(agent_spans[0].attributes) + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in agent_attrs + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in agent_attrs + + chat_spans = find_spans_by_operation(spans, "chat") + assert len(chat_spans) > 0 + chat_attrs = dict(chat_spans[0].attributes) + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in chat_attrs + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in chat_attrs + + llm_input = chat_attrs[GenAIAttributes.GEN_AI_INPUT_MESSAGES] + if isinstance(llm_input, str): + input_msgs = json.loads(llm_input) + assert isinstance(input_msgs, list) + assert len(input_msgs) > 0 + + llm_output = chat_attrs[GenAIAttributes.GEN_AI_OUTPUT_MESSAGES] + if isinstance(llm_output, str): + output_msgs = json.loads(llm_output) + assert isinstance(output_msgs, list) + assert len(output_msgs) > 0 + + chat_span = chat_spans[0] + assert chat_span.parent is not None + assert chat_span.context.trace_id == agent_spans[0].context.trace_id + + @pytest.mark.vcr() + def test_span_content_with_span_and_event( + self, + span_exporter, + log_exporter, + instrument_with_content_and_events, + request, + ): + """Content captured on span in SPAN_AND_EVENT mode.""" + toolkit = Toolkit() + agent = ReActAgent( + name="EventTest", + sys_prompt="You are a test assistant.", + model=DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + stream=True, + ), + formatter=DashScopeChatFormatter(), + toolkit=toolkit, + ) + msg = Msg("user", "What is 2+2?", "user") + + response = asyncio.run(agent(msg)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + + chat_spans = find_spans_by_operation(spans, "chat") + assert len(chat_spans) > 0 + chat_attrs = dict(chat_spans[0].attributes) + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES in chat_attrs + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES in chat_attrs + + @pytest.mark.vcr() + def test_span_content_disabled( + self, span_exporter, instrument_no_content, request + ): + """No content captured on either layer when capture is disabled.""" + toolkit = Toolkit() + agent = ReActAgent( + name="NoContentTest", + sys_prompt="You are a test assistant.", + model=DashScopeChatModel( + api_key=request.config.option.api_key, + model_name="qwen-max", + stream=True, + ), + formatter=DashScopeChatFormatter(), + toolkit=toolkit, + ) + msg = Msg("user", "Say hello", "user") + + response = asyncio.run(agent(msg)) + assert response is not None + + spans = span_exporter.get_finished_spans() + assert_no_removed_telemetry(spans) + + for agent_span in find_spans_by_operation(spans, "invoke_agent"): + attrs = dict(agent_span.attributes) + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES not in attrs + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in attrs + assert GenAIAttributes.GEN_AI_OPERATION_NAME in attrs + + for chat_span in find_spans_by_operation(spans, "chat"): + attrs = dict(chat_span.attributes) + assert GenAIAttributes.GEN_AI_INPUT_MESSAGES not in attrs + assert GenAIAttributes.GEN_AI_OUTPUT_MESSAGES not in attrs + assert GenAIAttributes.GEN_AI_OPERATION_NAME in attrs + assert GenAIAttributes.GEN_AI_REQUEST_MODEL in attrs diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_utils.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_utils.py new file mode 100644 index 000000000..e78b0b968 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_utils.py @@ -0,0 +1,75 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""Unit tests for message conversion in the AgentScope utils module.""" + +from __future__ import annotations + +from agentscope.message import Msg, ToolResultBlock + +from opentelemetry.instrumentation.genai.agentscope.utils import ( + _convert_block_to_part, + convert_agentscope_messages_to_genai_format, +) +from opentelemetry.util.genai.types import ToolCallResponse + + +class TestToolResultConversion: + def test_convert_msg_with_tool_result(self): + """A ``ToolResultBlock`` maps to a ``ToolCallResponse`` part.""" + tool_result_block = ToolResultBlock( + type="tool_result", + id="call_test_123", + name="test_tool", + output="Tool execution success", + ) + # AgentScope enforces role in {'user', 'assistant', 'system'}. + msg = Msg(name="tool", role="user", content=[tool_result_block]) + + converted_messages = convert_agentscope_messages_to_genai_format([msg]) + + assert len(converted_messages) == 1 + assert converted_messages[0].role == "user" + assert len(converted_messages[0].parts) == 1 + + part = converted_messages[0].parts[0] + assert isinstance(part, ToolCallResponse) + assert part.id == "call_test_123" + assert part.response == "Tool execution success" + + def test_convert_local_result_key(self): + """The local converter emits a ``result`` key that still converts.""" + block = { + "type": "tool_result", + "id": "id_local", + "name": "tool_local", + "output": "local output", + } + part = _convert_block_to_part(block) + + assert "result" in part + assert part["result"] == "local output" + + converted = convert_agentscope_messages_to_genai_format( + {"role": "tool", "parts": [part]} + ) + assert len(converted) == 1 + part_obj = converted[0].parts[0] + assert isinstance(part_obj, ToolCallResponse) + assert part_obj.response == "local output" + + def test_convert_framework_response_key(self): + """A part dict using ``response`` (framework converter) also converts.""" + block = { + "type": "tool_call_response", + "id": "id_framework", + "response": "framework output", + } + converted = convert_agentscope_messages_to_genai_format( + {"role": "tool", "parts": [block]} + ) + + assert len(converted) == 1 + part_obj = converted[0].parts[0] + assert isinstance(part_obj, ToolCallResponse) + assert part_obj.response == "framework output" diff --git a/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_v2_instrumentation.py b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_v2_instrumentation.py new file mode 100644 index 000000000..8d49d02a5 --- /dev/null +++ b/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_v2_instrumentation.py @@ -0,0 +1,368 @@ +# Copyright The OpenTelemetry Authors +# SPDX-License-Identifier: Apache-2.0 + +"""AgentScope v2 middleware instrumentation tests.""" + +from __future__ import annotations + +import asyncio +import importlib.metadata +import os +from dataclasses import asdict +from types import SimpleNamespace + +import pytest + +agentscope = pytest.importorskip("agentscope") +if not importlib.metadata.version("agentscope").startswith("2."): + pytest.skip( + "AgentScope v2 tests require agentscope>=2,<3", allow_module_level=True + ) + +from agentscope.agent import Agent # noqa: E402 +from agentscope.credential import DashScopeCredential # noqa: E402 +from agentscope.message import ( # noqa: E402 + Msg, + TextBlock, + ToolResultBlock, + UserMsg, +) +from agentscope.model import ChatResponse, DashScopeChatModel # noqa: E402 +from agentscope.tool import ToolResponse # noqa: E402 + +from opentelemetry.instrumentation.genai.agentscope._v2_middleware import ( # noqa: E402 + AgentScopeV2Middleware, + _message_to_input, +) +from opentelemetry.instrumentation.genai.agentscope.package import ( # noqa: E402 + get_installed_instrumentation_dependencies, +) +from opentelemetry.trace.status import StatusCode # noqa: E402 +from opentelemetry.util.genai.utils import gen_ai_json_dumps # noqa: E402 + + +def test_v2_dependency_detection(): + assert get_installed_instrumentation_dependencies() == ( + "agentscope >= 2.0.0, < 3.0.0", + ) + + +def test_v2_tool_result_message_content_is_jsonable(): + msg = Msg( + name="assistant", + role="assistant", + content=[ + ToolResultBlock( + id="tool-call-content", + name="lookup_weather", + output=[TextBlock(text="sunny")], + ) + ], + ) + + input_message = _message_to_input(msg) + + assert ( + gen_ai_json_dumps([asdict(input_message)]) + == '[{"role":"assistant","parts":[{"response":[{"content":"sunny","type":"text"}],"id":"tool-call-content","type":"tool_call_response"}]}]' + ) + + +def test_instrumentor_injects_v2_middleware(instrument): + model = _make_model(stream=False) + agent = Agent( + name="middleware_probe", + system_prompt="Reply briefly.", + model=model, + ) + + assert any( + isinstance(middleware, AgentScopeV2Middleware) + for middleware in agent._reply_middlewares + ) + assert any( + isinstance(middleware, AgentScopeV2Middleware) + for middleware in agent._model_call_middlewares + ) + assert any( + isinstance(middleware, AgentScopeV2Middleware) + for middleware in agent._acting_middlewares + ) + + +def test_v2_uninstrument_removes_agent_patch(instrument): + instrument.uninstrument() + + agent = Agent( + name="uninstrument_probe", + system_prompt="Reply briefly.", + model=_make_model(stream=False), + ) + + assert not any( + isinstance(middleware, AgentScopeV2Middleware) + for middleware in agent._reply_middlewares + ) + assert not any( + isinstance(middleware, AgentScopeV2Middleware) + for middleware in agent._model_call_middlewares + ) + + +async def test_v2_existing_agent_middleware_noops_after_uninstrument( + instrument, span_exporter +): + agent = Agent( + name="existing_agent", + system_prompt="Reply briefly.", + model=_make_model(stream=False), + ) + middleware = _middleware(agent._model_call_middlewares) + instrument.uninstrument() + + async def model_handler(**kwargs): + del kwargs + return ChatResponse(content=[TextBlock(text="ok")], is_last=True) + + response = await middleware.on_model_call( + agent, + { + "current_model": agent.model, + "messages": [UserMsg(name="user", content="hello")], + }, + model_handler, + ) + + assert response.content + assert not span_exporter.get_finished_spans() + + +async def test_v2_model_call_error_path(instrument, span_exporter): + agent = Agent( + name="error_agent", + system_prompt="Reply briefly.", + model=_make_model(stream=False), + ) + middleware = _middleware(agent._model_call_middlewares) + + async def failing_handler(**kwargs): + del kwargs + raise RuntimeError("model failed") + + with pytest.raises(RuntimeError, match="model failed"): + await middleware.on_model_call( + agent, + { + "current_model": agent.model, + "messages": [UserMsg(name="user", content="fail")], + }, + failing_handler, + ) + + span = _spans_by_operation(span_exporter.get_finished_spans(), "chat")[0] + assert span.status.status_code == StatusCode.ERROR + assert span.attributes["error.type"] == "RuntimeError" + + +async def test_v2_streaming_model_call_error_path(instrument, span_exporter): + agent = Agent( + name="stream_error_agent", + system_prompt="Reply briefly.", + model=_make_model(stream=True), + ) + middleware = _middleware(agent._model_call_middlewares) + + async def failing_stream(): + yield ChatResponse(content=[TextBlock(text="partial")], is_last=False) + raise RuntimeError("stream failed") + + async def stream_handler(**kwargs): + del kwargs + return failing_stream() + + stream = await middleware.on_model_call( + agent, + { + "current_model": agent.model, + "messages": [UserMsg(name="user", content="fail")], + }, + stream_handler, + ) + + with pytest.raises(RuntimeError, match="stream failed"): + async for _ in stream: + pass + + span = _spans_by_operation(span_exporter.get_finished_spans(), "chat")[0] + assert span.status.status_code == StatusCode.ERROR + assert span.attributes["error.type"] == "RuntimeError" + + +async def test_v2_tool_acting_hook(instrument, span_exporter): + agent = Agent( + name="tool_agent", + system_prompt="Use tools.", + model=_make_model(stream=False), + ) + middleware = _middleware(agent._acting_middlewares) + tool_call = SimpleNamespace( + name="lookup_weather", + id="tool-call-1", + input='{"city": "Hangzhou"}', + ) + + async def tool_handler(**kwargs): + del kwargs + yield ToolResponse(content=[TextBlock(text="sunny")]) + + results = [ + item + async for item in middleware.on_acting( + agent, + {"tool_call": tool_call}, + tool_handler, + ) + ] + + assert results + tool_span = _spans_by_operation( + span_exporter.get_finished_spans(), "execute_tool" + )[0] + assert tool_span.attributes["gen_ai.tool.name"] == "lookup_weather" + assert tool_span.attributes["gen_ai.tool.type"] == "function" + + +async def test_v2_tool_result_content_capture( + instrument_with_content, + span_exporter, +): + agent = Agent( + name="tool_content_agent", + system_prompt="Use tools.", + model=_make_model(stream=False), + ) + middleware = _middleware(agent._acting_middlewares) + tool_call = SimpleNamespace( + name="lookup_weather", + id="tool-call-content", + input='{"city": "Hangzhou"}', + ) + + async def tool_handler(**kwargs): + del kwargs + yield ToolResponse(content=[TextBlock(text="sunny")]) + + results = [ + item + async for item in middleware.on_acting( + agent, + {"tool_call": tool_call}, + tool_handler, + ) + ] + + assert results + tool_span = _spans_by_operation( + span_exporter.get_finished_spans(), "execute_tool" + )[0] + assert tool_span.attributes["gen_ai.tool.call.result"] == ( + '[{"content":"sunny","type":"text"}]' + ) + + +@pytest.mark.vcr() +async def test_v2_agent_non_streaming_e2e(instrument, span_exporter): + model = _make_model(stream=False) + agent = Agent( + name="non_stream_agent", + system_prompt="Reply with exactly: OK", + model=model, + ) + + msg = await agent.reply(UserMsg(name="user", content="Say OK.")) + + assert msg.get_text_content() + _assert_agent_and_llm_spans(span_exporter.get_finished_spans()) + + +@pytest.mark.vcr() +async def test_v2_agent_streaming_e2e(instrument, span_exporter): + model = _make_model(stream=True) + agent = Agent( + name="stream_agent", + system_prompt="Reply with a short sentence.", + model=model, + ) + + events = [ + event + async for event in agent.reply_stream( + UserMsg(name="user", content="Say hello in one sentence.") + ) + ] + + assert events + assert any( + event.__class__.__name__ == "TextBlockDeltaEvent" for event in events + ) + _assert_agent_and_llm_spans(span_exporter.get_finished_spans()) + + +@pytest.mark.vcr() +async def test_v2_agent_concurrent_e2e(instrument, span_exporter): + async def call_agent(idx: int): + agent = Agent( + name=f"concurrent_agent_{idx}", + system_prompt="Reply with exactly one short sentence.", + model=_make_model(stream=False), + ) + return await agent.reply( + UserMsg(name="user", content=f"Say OK for request {idx}.") + ) + + results = await asyncio.gather(call_agent(1), call_agent(2)) + + assert all(result.get_text_content() for result in results) + spans = span_exporter.get_finished_spans() + agent_spans = _spans_by_operation(spans, "invoke_agent") + llm_spans = _spans_by_operation(spans, "chat") + assert len(agent_spans) == 2 + assert len(llm_spans) == 2 + agent_span_ids = {span.context.span_id for span in agent_spans} + assert {span.parent.span_id for span in llm_spans} == agent_span_ids + + +def _make_model(stream: bool): + return DashScopeChatModel( + credential=DashScopeCredential( + api_key=os.environ["DASHSCOPE_API_KEY"] + ), + model="qwen-plus", + parameters=DashScopeChatModel.Parameters( + max_tokens=16, + thinking_enable=False, + ), + stream=stream, + max_retries=0, + ) + + +def _assert_agent_and_llm_spans(spans): + assert _spans_by_operation(spans, "invoke_agent") + assert _spans_by_operation(spans, "chat") + + +def _spans_by_operation(spans, operation_name): + return [ + span + for span in spans + if span.attributes.get("gen_ai.operation.name") == operation_name + ] + + +def _middleware(middlewares): + return next( + middleware + for middleware in middlewares + if isinstance(middleware, AgentScopeV2Middleware) + ) diff --git a/pyproject.toml b/pyproject.toml index 74e2c0b04..d58b050ae 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,6 +30,7 @@ required-version = ">=0.6.0" [tool.uv.sources] opentelemetry-test-util-genai = { workspace = true } opentelemetry-util-genai = { workspace = true } +opentelemetry-instrumentation-genai-agentscope = { workspace = true } opentelemetry-instrumentation-genai-anthropic = { workspace = true } opentelemetry-instrumentation-genai-claude-agent-sdk = { workspace = true } opentelemetry-instrumentation-google-genai = { workspace = true } diff --git a/tox.ini b/tox.ini index ac839f6e5..8ed9454a3 100644 --- a/tox.ini +++ b/tox.ini @@ -43,6 +43,13 @@ envlist = # No pypy3: jiter (an anthropic dependency) ships no PyPy wheels, so it would need a Rust source build lint-instrumentation-genai-claude-agent-sdk + ; instrumentation-genai-agentscope + ; latest tracks agentscope v2 (requires-python >= 3.11); oldest tracks v1 on the minimum interpreter. + py3{11,12,13}-test-instrumentation-genai-agentscope-latest + py310-test-instrumentation-genai-agentscope-oldest + py3{12,13}-test-instrumentation-genai-agentscope-conformance + lint-instrumentation-genai-agentscope + ; instrumentation-genai-langchain py3{12,13}-test-instrumentation-genai-langchain-latest py312-test-instrumentation-genai-langchain-oldest @@ -132,6 +139,15 @@ deps = claude-agent-sdk-latest: {[testenv]pytest_deps} claude-agent-sdk-latest: -r {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests/requirements.latest.txt + agentscope-oldest: {[testenv]pytest_deps} + agentscope-oldest: -e {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope[instruments] + agentscope-oldest: -r {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.oldest.txt + agentscope-latest: {[testenv]test_deps} + agentscope-latest: {[testenv]pytest_deps} + agentscope-latest: -r {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt + agentscope-conformance: {[testenv]pytest_deps} + agentscope-conformance: -r {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/requirements.latest.txt + ; Langchain unit tests langchain-{oldest,latest}: {[testenv]pytest_deps} ; oldest: declared deps (opentelemetry-instrumentation, util-genai, langchain) resolve from PyPI to @@ -192,6 +208,10 @@ commands = test-instrumentation-genai-claude-agent-sdk: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-claude-agent-sdk/tests --vcr-record=none {posargs} lint-instrumentation-genai-claude-agent-sdk: sh -c "cd instrumentation && ruff check opentelemetry-instrumentation-genai-claude-agent-sdk" + test-instrumentation-genai-agentscope-{oldest,latest}: pytest --ignore={toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests --vcr-record=none {posargs} + test-instrumentation-genai-agentscope-conformance: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-agentscope/tests/test_conformance.py --vcr-record=none {posargs} + lint-instrumentation-genai-agentscope: sh -c "cd instrumentation && ruff check opentelemetry-instrumentation-genai-agentscope" + test-instrumentation-genai-langchain-{oldest,latest}: pytest --ignore={toxinidir}/instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_conformance.py {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-langchain/tests --vcr-record=none {posargs} test-instrumentation-genai-langchain-conformance: pytest {toxinidir}/instrumentation/opentelemetry-instrumentation-genai-langchain/tests/test_conformance.py --vcr-record=none {posargs} lint-instrumentation-genai-langchain: sh -c "cd instrumentation && ruff check opentelemetry-instrumentation-genai-langchain" diff --git a/uv.lock b/uv.lock index 94f9b8f1c..d82bc7922 100644 --- a/uv.lock +++ b/uv.lock @@ -4,14 +4,19 @@ requires-python = ">=3.10" resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", "python_full_version >= '3.14' and sys_platform != 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", "python_full_version < '3.11' and sys_platform == 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform != 'win32'", + "python_full_version == '3.11.*' and sys_platform != 'win32'", "python_full_version < '3.11' and sys_platform != 'win32'", ] [manifest] members = [ + "opentelemetry-instrumentation-genai-agentscope", "opentelemetry-instrumentation-genai-anthropic", "opentelemetry-instrumentation-genai-claude-agent-sdk", "opentelemetry-instrumentation-genai-langchain", @@ -24,6 +29,274 @@ members = [ "opentelemetry-util-genai", ] +[[package]] +name = "agentscope" +version = "1.0.21" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and sys_platform == 'win32'", + "python_full_version < '3.11' and sys_platform != 'win32'", +] +dependencies = [ + { name = "aiofiles", marker = "python_full_version < '3.11'" }, + { name = "aioitertools", marker = "python_full_version < '3.11'" }, + { name = "anthropic", marker = "python_full_version < '3.11'" }, + { name = "dashscope", marker = "python_full_version < '3.11'" }, + { name = "docstring-parser", marker = "python_full_version < '3.11'" }, + { name = "filetype", marker = "python_full_version < '3.11'" }, + { name = "json-repair", marker = "python_full_version < '3.11'" }, + { name = "json5", marker = "python_full_version < '3.11'" }, + { name = "mcp", marker = "python_full_version < '3.11'" }, + { name = "numpy", version = "2.2.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "openai", marker = "python_full_version < '3.11'" }, + { name = "opentelemetry-api", marker = "python_full_version < '3.11'" }, + { name = "opentelemetry-exporter-otlp", marker = "python_full_version < '3.11'" }, + { name = "opentelemetry-sdk", marker = "python_full_version < '3.11'" }, + { name = "opentelemetry-semantic-conventions", marker = "python_full_version < '3.11'" }, + { name = "python-datauri", marker = "python_full_version < '3.11'" }, + { name = "python-frontmatter", marker = "python_full_version < '3.11'" }, + { name = "python-socketio", marker = "python_full_version < '3.11'" }, + { name = "shortuuid", marker = "python_full_version < '3.11'" }, + { name = "sounddevice", marker = "python_full_version < '3.11'" }, + { name = "sqlalchemy", marker = "python_full_version < '3.11'" }, + { name = "tiktoken", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0a/96/45fdad50f96eeaff9bb203ab7e84ade1c69a8609f6a00934fda5f41cfc5c/agentscope-1.0.21.tar.gz", hash = "sha256:e73392ac446932fc4fe480eda6918525320b9a5701a18b2d197311d140d6d183", size = 306133, upload-time = "2026-05-25T09:36:29.902Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2c/45/b97613ee93bdcb6dcae12f9b87184a4e9a1635fec7ac8470d8785e9110fd/agentscope-1.0.21-py3-none-any.whl", hash = "sha256:4a14507be793f798b803f3fe8b18a33acea6d3dedbdbfa99d1d7500891c77323", size = 430172, upload-time = "2026-05-25T09:36:27.887Z" }, +] + +[[package]] +name = "agentscope" +version = "2.0.4.post1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform != 'win32'", + "python_full_version == '3.11.*' and sys_platform != 'win32'", +] +dependencies = [ + { name = "aiofiles", marker = "python_full_version >= '3.11'" }, + { name = "aioitertools", marker = "python_full_version >= '3.11'" }, + { name = "anthropic", marker = "python_full_version >= '3.11'" }, + { name = "dashscope", marker = "python_full_version >= '3.11'" }, + { name = "docstring-parser", marker = "python_full_version >= '3.11'" }, + { name = "filetype", marker = "python_full_version >= '3.11'" }, + { name = "httpx", marker = "python_full_version >= '3.11'" }, + { name = "jinja2", marker = "python_full_version >= '3.11'" }, + { name = "json-repair", marker = "python_full_version >= '3.11'" }, + { name = "json5", marker = "python_full_version >= '3.11'" }, + { name = "jsonschema", marker = "python_full_version >= '3.11'" }, + { name = "mcp", marker = "python_full_version >= '3.11'" }, + { name = "numpy", version = "2.4.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "openai", marker = "python_full_version >= '3.11'" }, + { name = "opentelemetry-api", marker = "python_full_version >= '3.11'" }, + { name = "opentelemetry-exporter-otlp", marker = "python_full_version >= '3.11'" }, + { name = "opentelemetry-sdk", marker = "python_full_version >= '3.11'" }, + { name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.11'" }, + { name = "python-datauri", marker = "python_full_version >= '3.11'" }, + { name = "python-frontmatter", marker = "python_full_version >= '3.11'" }, + { name = "python-socketio", marker = "python_full_version >= '3.11'" }, + { name = "shortuuid", marker = "python_full_version >= '3.11'" }, + { name = "tree-sitter", marker = "python_full_version >= '3.11'" }, + { name = "tree-sitter-bash", marker = "python_full_version >= '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/08/a1/16bb75cd5f9a354de37219070af79c1bfa2b3ec8f1e638e7f5cffc1b0472/agentscope-2.0.4.post1.tar.gz", hash = "sha256:b789b3f358341299e13548b644d44a24848e8fe51c684564bb454e7bcd54790f", size = 612584, upload-time = "2026-07-16T08:26:02.958Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/1b/ef3d91d1f075e36705f015026e34cb043e0b834c91468da7e69ed281972e/agentscope-2.0.4.post1-py3-none-any.whl", hash = "sha256:ec4fe650e0e666687bf44343cead524ac8a1b1d871061bb3bf06d148f463ecf8", size = 822481, upload-time = "2026-07-16T08:26:01.415Z" }, +] + +[[package]] +name = "aiofiles" +version = "25.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" }, +] + +[[package]] +name = "aiohappyeyeballs" +version = "2.7.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ce/f4/eec0465c2f67b2664688d0240b3212d5196fd89e741df67ddb81f8d35658/aiohappyeyeballs-2.7.1.tar.gz", hash = "sha256:065665c041c42a5938ed220bdcd7230f22527fbec085e1853d2402c8a3615d9d", size = 24757, upload-time = "2026-07-01T17:11:55.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/43/1947f06babed6b3f1d7f38b0c767f52df66bfb2bc10b468c4a7de9eceff2/aiohappyeyeballs-2.7.1-py3-none-any.whl", hash = "sha256:9243213661e29250eb41368e5daa826fc017156c3b8a11440826b2e3ed376472", size = 15038, upload-time = "2026-07-01T17:11:54.055Z" }, +] + +[[package]] +name = "aiohttp" +version = "3.14.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohappyeyeballs" }, + { name = "aiosignal" }, + { name = "async-timeout", marker = "python_full_version < '3.11'" }, + { name = "attrs" }, + { name = "frozenlist" }, + { name = "multidict" }, + { name = "propcache" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, + { name = "yarl" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/86/37/6a24e23d559bc2d042287cee15b4a6e61b46f844d2b3c96832483f854a4a/aiohttp-3.14.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ceb77c159b2b4c1a179b96a26af36bcaa68eb79c393ec4f569386a69d013cbe9", size = 765793, upload-time = "2026-07-20T19:49:37.707Z" }, + { url = "https://files.pythonhosted.org/packages/dc/14/23aa28408805efe6adc0e97048f5cd6028a2a3036d237038f45d10dc05a6/aiohttp-3.14.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3f3381f81bc1c6cbe160b2a3708d39d05014329118e6b648b95edc841eeeebd4", size = 517440, upload-time = "2026-07-20T19:49:40.182Z" }, + { url = "https://files.pythonhosted.org/packages/24/2d/7fc2d359d6702ce5299cd865ec2c70dad2fd8c1b3901bc79f83e3c61c395/aiohttp-3.14.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:483b6f964bbbdaa99a0cd7def631208c44e39d243b95cff23ebc812db8a80e03", size = 515306, upload-time = "2026-07-20T19:49:41.818Z" }, + { url = "https://files.pythonhosted.org/packages/dc/f0/fd9c7019bdfba5529c9a697621a757f0cfd92787595a04a9252923b097fc/aiohttp-3.14.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc056948b7a8a40484b4bbc69923fa25cddd80cbc5f236a3a22ad2f836baeed2", size = 1708602, upload-time = "2026-07-20T19:49:43.351Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6d/8de300d792a3b91a94533a626a835c32cda69189209ae539bebaadba88ad/aiohttp-3.14.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135570f5b470c72c4988a58986f1f847ad336721f77fcc18fda8472bd3bbe3db", size = 1673881, upload-time = "2026-07-20T19:49:44.753Z" }, + { url = "https://files.pythonhosted.org/packages/65/27/37559302e4f03e343f549ff1628295c20fb0298d603e40193db2f25f5153/aiohttp-3.14.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ee5bdd7933c653e43ef8d720704a4e228e4927121f2f5f598b7efe6a4c18633a", size = 1766985, upload-time = "2026-07-20T19:49:46.464Z" }, + { url = "https://files.pythonhosted.org/packages/df/55/29cc3691fa0bb1334352bcb61ba5f256396fd6a0603cf321b8c29bb7e1fe/aiohttp-3.14.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0baed2a2367a28456b612f4c3fd28bb86b00fadfb6454e706d8f65c21636bfd7", size = 1858788, upload-time = "2026-07-20T19:49:48.015Z" }, + { url = "https://files.pythonhosted.org/packages/71/63/36a34c0139d0b1a830e8ee130a75312e9eddccb5b234a7f56e9de5e6edd2/aiohttp-3.14.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ecdd6b8cab5b7c0ff2988378c11ba7192f076a1864e64dc3ff72f7ba05c71796", size = 1714003, upload-time = "2026-07-20T19:49:49.714Z" }, + { url = "https://files.pythonhosted.org/packages/ac/d8/c3a37079d503967a4072f8fc187c9d46c62b1eb72b25ae57dc0f2d0ddb11/aiohttp-3.14.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a3177e51e26e0158fb3376aebac97e0546c6f175c510f331f585e514a00a302b", size = 1588046, upload-time = "2026-07-20T19:49:51.209Z" }, + { url = "https://files.pythonhosted.org/packages/ba/0c/c42b45bb275983cde529a4bc0e94f23ca6cdfe2a3c97285e73a4a6b81c23/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:86861a430657bc71e0f89b195de5f8fa495c0b9b5864cf2f89bd5ec1dbb6b77a", size = 1677219, upload-time = "2026-07-20T19:49:52.89Z" }, + { url = "https://files.pythonhosted.org/packages/75/a1/bdcd55b54d6335bc33e5f1b9f8613501c7f35cd99f44bf462d540d6b30d8/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:aac1b05fc5e2ef188b6d74cf151e977db75ab281238f30c3163bbd6f797788e3", size = 1691747, upload-time = "2026-07-20T19:49:54.495Z" }, + { url = "https://files.pythonhosted.org/packages/f1/98/a0d751d3787f2ca457beb16de5774a24e53fab840a8c7cb727cf900ed301/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:89120e926c68c4e60c78514d76e16fc15689d8df35843b2a6bf6c4cc0d64b11a", size = 1735039, upload-time = "2026-07-20T19:49:56.269Z" }, + { url = "https://files.pythonhosted.org/packages/ea/7a/33b8a5d348abc7335de33f4332ec0dcedfc7d45db28fd2162802d306345d/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:82d14d66d6147441b6571833405c828980efc17bda98075a248104ffdd330c30", size = 1577209, upload-time = "2026-07-20T19:49:57.926Z" }, + { url = "https://files.pythonhosted.org/packages/a9/03/09d41c3866e2102e6679e49fd78cd928926326fd304fa4e6f1d155f8ba04/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6cde463b9dd9ce4343785c5a39127b40fce059ae6fbd320f5a045a38c3d25cd0", size = 1751303, upload-time = "2026-07-20T19:49:59.472Z" }, + { url = "https://files.pythonhosted.org/packages/eb/53/72115db0f3e4490b6c0cb063709d7553a1661ec03532b1b2f891e841af1b/aiohttp-3.14.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:2280d165ab38355144d9984cdce77ce506cee019a07390bab7fd13682248ce91", size = 1699526, upload-time = "2026-07-20T19:50:01.328Z" }, + { url = "https://files.pythonhosted.org/packages/0c/c6/9b8964be6d8d67dcf4bf32ff2380c203380322b1e23b5c1aa122c9b5a740/aiohttp-3.14.2-cp310-cp310-win32.whl", hash = "sha256:5e94a8c4445bfdaa30773c81f2be7f129673e0f528945e542b8bd024b2979134", size = 456626, upload-time = "2026-07-20T19:50:02.79Z" }, + { url = "https://files.pythonhosted.org/packages/bf/10/8dcdbbd9d83103db95ff74b255105113c1f6983865446f4facef81f0a1eb/aiohttp-3.14.2-cp310-cp310-win_amd64.whl", hash = "sha256:65cd3bb118f42fceceb9e8a615c735a01453d019c673f35c57b420601cc1a83a", size = 480367, upload-time = "2026-07-20T19:50:04.284Z" }, + { url = "https://files.pythonhosted.org/packages/14/08/b6eb0532f5ec2b202980c2d9658dd8ee3a1e21cdd0cb9d01debc0ba40045/aiohttp-3.14.2-cp310-cp310-win_arm64.whl", hash = "sha256:2a382aa6bb85347515ead043257445baeec0885d42bfedb962093b134c3b4816", size = 453374, upload-time = "2026-07-20T19:50:05.953Z" }, + { url = "https://files.pythonhosted.org/packages/f6/4a/a6c1426d2fb3cddd901575436803733caaaeb7ac0a49aa72d1930d2e3ab6/aiohttp-3.14.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:56432ee8f7abe47c97717cfbf5c32430463ea8a7138e12a87b7891fa6084c8ff", size = 764168, upload-time = "2026-07-20T19:50:07.389Z" }, + { url = "https://files.pythonhosted.org/packages/0c/62/88ae65afc3590719788cbff3b2e0f56e6850f53ca34114cbb371e677c543/aiohttp-3.14.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c244f7a65cbec04c830a301aae443c529d4dbca5fddfd4b19e5a179d896adfd", size = 516255, upload-time = "2026-07-20T19:50:08.84Z" }, + { url = "https://files.pythonhosted.org/packages/8f/bc/ad9b767785b014f2f57497a2ccf67e3d4316d153f7ed1c7715fbbd7573fe/aiohttp-3.14.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1c05afdd28ecacce5a1f63275a2e3dce09efddd3a63d143ee9799fda83989c8d", size = 514670, upload-time = "2026-07-20T19:50:10.325Z" }, + { url = "https://files.pythonhosted.org/packages/48/94/697aef63f15ef354f64723eaac6ccfb289d59b99699b3b7cb1ff663b2045/aiohttp-3.14.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a57f39d6ec155932853b6b0f130cbbafab3208240fa807f29a2c96ea52b77ae1", size = 1780650, upload-time = "2026-07-20T19:50:11.676Z" }, + { url = "https://files.pythonhosted.org/packages/99/f9/6a1994c1bf138403cf10171cb618571a330ae5683a5803b1ef29b5723d7f/aiohttp-3.14.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1fc31339824ec922cb7424d624b5b6c11d8942d077b2585e5bd602ca1a1e27ed", size = 1737710, upload-time = "2026-07-20T19:50:13.401Z" }, + { url = "https://files.pythonhosted.org/packages/8b/ba/abe8d5015148b2cd7189473789461058dcf88ae202d4cf1cbecaf291a7ef/aiohttp-3.14.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d93854e215dcc7c88e4f530827193c1a594e2662931d8dbe7cca3abf52a7082d", size = 1845568, upload-time = "2026-07-20T19:50:15.168Z" }, + { url = "https://files.pythonhosted.org/packages/c2/89/98a2688810f469f19f2d02a298426a37b6e1cc420230a8cc7d6c85af7a01/aiohttp-3.14.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87c9b03be0c18c3b3587be979149830381e37ac4a6ca8557dbe72e44fcad66c3", size = 1928485, upload-time = "2026-07-20T19:50:16.922Z" }, + { url = "https://files.pythonhosted.org/packages/5a/fd/c980f64f5e5bff22f07968bcc6af1b64167dfd21dbbffda86f2d153fc802/aiohttp-3.14.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bc1a0793dce8fa9bb6906411e57fb18a2f1c31357b04172541b92b30337362a7", size = 1786216, upload-time = "2026-07-20T19:50:18.598Z" }, + { url = "https://files.pythonhosted.org/packages/da/80/c710ce9c7f22fcbb83366aa64a5ccf03dced35ab09a6e37545656a6df01e/aiohttp-3.14.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:2f1b9540d2d0f2f95590528a1effd0ba5370f6ec189ac925e70b5eecae02dc77", size = 1636921, upload-time = "2026-07-20T19:50:20.201Z" }, + { url = "https://files.pythonhosted.org/packages/e1/b2/56ce1b0c535d188ef94c05bccbf3f5b1aaea1231fcb073318977bdd917e9/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c0a968b04fecf7c94e502015860ad1e2e112c6b761e97b6fdf65fbb374e22b73", size = 1753040, upload-time = "2026-07-20T19:50:21.857Z" }, + { url = "https://files.pythonhosted.org/packages/86/61/4318a947139a21d4e1a40e7f5a92799d0fe28feffaca6640a4a165e62b0e/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2d2eedae227cd5cbd0bccc5e759f71e1af2cd77b7f74ce413bb9a2b87f94a272", size = 1760811, upload-time = "2026-07-20T19:50:23.623Z" }, + { url = "https://files.pythonhosted.org/packages/81/b0/2012165377d029ceb925c9e5f42b0b30a39d89cf7e494c4100f3ab8d27c6/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9d3f4c68b2c2cd282b65e558cebf4b27c8b440ab511f2b938a643d3598df2ddb", size = 1819760, upload-time = "2026-07-20T19:50:25.34Z" }, + { url = "https://files.pythonhosted.org/packages/16/e5/1de93ba3bc18edb87f71594326bedafdc38fe725da8118b7d36fd56610f8/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:d32a70b8bf8836fd80d4169d9e34eb032cd2a7cbccb0b9cf00eac1f40732467c", size = 1628145, upload-time = "2026-07-20T19:50:26.992Z" }, + { url = "https://files.pythonhosted.org/packages/66/8f/adc9e8592449ee08f72fcce94b7f3f1a9bbf0591a46026e4d322e5a70d7a/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:386ce4e709b4cc40f9ef9a132ad8e672d2d164a65451305672df656e7794c68e", size = 1832577, upload-time = "2026-07-20T19:50:28.546Z" }, + { url = "https://files.pythonhosted.org/packages/9b/7f/700500700513b1b63967a24c4e189aad377e18f9d67b7387b3418d6213cb/aiohttp-3.14.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc0ed30b942c3bd755583d74bb00b90248c067d20b1f8301e4489a53a33aa65f", size = 1774814, upload-time = "2026-07-20T19:50:30.144Z" }, + { url = "https://files.pythonhosted.org/packages/a5/d6/580f9b2ab4c78d9fbf9d56c85fb7f7d4d22d667b27df8032ab9bf7140e37/aiohttp-3.14.2-cp311-cp311-win32.whl", hash = "sha256:b5ed2c7dacebf4950d6b4a1b22548e4d709bb15e0287e064a7cdb32ada65893a", size = 455968, upload-time = "2026-07-20T19:50:31.722Z" }, + { url = "https://files.pythonhosted.org/packages/96/76/33665ae48e24e01c6dfa15ed14d9d9eec1349577cef497f3b26210621f0a/aiohttp-3.14.2-cp311-cp311-win_amd64.whl", hash = "sha256:bf7951959a8e89f2d4a1e719e60d3ea4e8fc26f011ee3aed09598ad786b112f7", size = 480978, upload-time = "2026-07-20T19:50:33.299Z" }, + { url = "https://files.pythonhosted.org/packages/5e/19/00963031da42bd23716032f57b2a8414c5355eb1abc41805b2b41173040c/aiohttp-3.14.2-cp311-cp311-win_arm64.whl", hash = "sha256:c167127a3b6089ef78ac2e33582c38040d51688ee28474b5053acf55f192187b", size = 452900, upload-time = "2026-07-20T19:50:35.049Z" }, + { url = "https://files.pythonhosted.org/packages/e0/99/8737b10b6fa447371541a3b2cdbf9703c31ecf3afff4998f2f0633646a57/aiohttp-3.14.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:30e41662123806e4590a0440585122ac33c89a2465a8be81cc1b50656ca0e432", size = 754562, upload-time = "2026-07-20T19:50:36.672Z" }, + { url = "https://files.pythonhosted.org/packages/7c/e5/fd624b8b46d99dfd8f7f75111569b5ee21850539e914eed04ce39e4455ea/aiohttp-3.14.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:dbc45e2773c66d14fbd337754e9bf23932beef539bd539716a721f5b5f372034", size = 509386, upload-time = "2026-07-20T19:50:38.268Z" }, + { url = "https://files.pythonhosted.org/packages/6d/a8/473db85d08b862724c506b51af2b9c6327e9e95cbd297c4c6f33968be1a8/aiohttp-3.14.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:476cf7fac10619ad6d08e1df0225d07b5a8d57c04963a171ad845d5a349d47ef", size = 511905, upload-time = "2026-07-20T19:50:39.862Z" }, + { url = "https://files.pythonhosted.org/packages/c1/e8/aa5ebff13ac5e39ffae8add143757e936d1c2ceb726b82786e5f5cb9912c/aiohttp-3.14.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40bedff39ea83185f3f98a41155dd9da28b365c432e5bd90e7be140bcef0b7f3", size = 1764968, upload-time = "2026-07-20T19:50:41.559Z" }, + { url = "https://files.pythonhosted.org/packages/f4/22/23ec6d3d3f24f5961c7be73d5127481c992d6c92ca213f336ed8f0ff1453/aiohttp-3.14.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a26f14006883fc7662e21041b4311eac1acbc977a5c43aacb27ff17f8a4c28b2", size = 1740635, upload-time = "2026-07-20T19:50:43.363Z" }, + { url = "https://files.pythonhosted.org/packages/a0/7b/f8966d2d08f0582525ef02d5af007d2d2467cb733abf1d1f7849a02a6b98/aiohttp-3.14.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:673217cbc9370ebf8cd048b0889d7cbe922b7bb48f4e4c02d31cfefa140bd946", size = 1810447, upload-time = "2026-07-20T19:50:45.258Z" }, + { url = "https://files.pythonhosted.org/packages/39/f5/239f2a828b033ac244237074db7b560ad3279bb1e934bb462dbde19f3877/aiohttp-3.14.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:b39dbdbe30a44958d63f3f8baa2af68f24ec8a631dcd18a33dd76dfa2a0eb917", size = 1905896, upload-time = "2026-07-20T19:50:47.022Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6e/fb84b8dafc521026355aadbeed484fc1ec44a05aae927de309f204c1f0af/aiohttp-3.14.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d15f618255fcbe5f54689403aa4c2a90b6f2e6ebc96b295b1cb0e868c1c12384", size = 1792052, upload-time = "2026-07-20T19:50:48.683Z" }, + { url = "https://files.pythonhosted.org/packages/ba/c4/25b199009f164ee02599b9b0962d22e6533d212418e49df9f4fdb37fe2eb/aiohttp-3.14.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7ae767b7dffd316cc2d0abf3e1f90132b4c1a2819a32d8bcb1ba749800ea6273", size = 1590939, upload-time = "2026-07-20T19:50:50.702Z" }, + { url = "https://files.pythonhosted.org/packages/ad/f5/96d7540a52620433db3822267008a1697fc816979c109a4f535855ac893c/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3ec4b6501a076b2f73844256da17d6b7acb15bb74ee0e908a67feb9412371166", size = 1725039, upload-time = "2026-07-20T19:50:52.506Z" }, + { url = "https://files.pythonhosted.org/packages/f6/50/1a06abbeec14a2bcb46124ca6e281ed4ccb3e9006542ded6bc89a0ce5224/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:7e328d02fb46b9a8dbfa070d98967e8b7eaa1d9ee10ae03fb664bdf30d58ccf0", size = 1764748, upload-time = "2026-07-20T19:50:54.336Z" }, + { url = "https://files.pythonhosted.org/packages/70/5d/b8821b362306627ea8ca11fe49ec47cba18e7c75d975fa5f6710ad93845c/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c7f2e5fe10910d5ab76438f269cc41bb7e499fd48ded978e926360ab1790c8", size = 1777119, upload-time = "2026-07-20T19:50:56.306Z" }, + { url = "https://files.pythonhosted.org/packages/81/e5/805d9d49e66c6358574ad70dd731031585d18fe95ae65b857bc378bccc9a/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:66de80888db2176655f8df0b705b817f5ae3834e6566cc2caa89360871d90195", size = 1580047, upload-time = "2026-07-20T19:50:58.316Z" }, + { url = "https://files.pythonhosted.org/packages/c6/fa/1536f272d5ad93bf8b75043b02b94c24bf4e6b55a849d3287553ad6da97e/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f2f9950b2dd0fc896ab520ea2366b7df6484d3d164a65d5e9f28f7b0e5742d8a", size = 1796861, upload-time = "2026-07-20T19:51:00.373Z" }, + { url = "https://files.pythonhosted.org/packages/e6/f3/86dfd6152bb706351cf5c6b45f0f6a1818a4e559d1e88d899c4c673c23a8/aiohttp-3.14.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:cc4435b16dc246c5dfa7f2f8ee71b10a30765018a090ee36e99f356b1e9b75cc", size = 1768687, upload-time = "2026-07-20T19:51:02.214Z" }, + { url = "https://files.pythonhosted.org/packages/57/af/14b98e07fcd1a2b37ebb2f950309821eaa56e0eac3d32fc23dc55227e49b/aiohttp-3.14.2-cp312-cp312-win32.whl", hash = "sha256:4ca802547f1128008addfc21b24959f5cbf30a8952d365e7daa078a0d884b242", size = 451437, upload-time = "2026-07-20T19:51:03.954Z" }, + { url = "https://files.pythonhosted.org/packages/38/20/8478c05702a369b6d0800e40e0c5f9a289ff482d0921faec1eb17727339d/aiohttp-3.14.2-cp312-cp312-win_amd64.whl", hash = "sha256:e5efff8bfd27c44ce1bfdf92ce838362d9316ed8b2ed2f89f581dbe0bbe05acf", size = 476776, upload-time = "2026-07-20T19:51:05.705Z" }, + { url = "https://files.pythonhosted.org/packages/d0/d0/e550bb1cb4fc82de3bdbe2add061cc0cedb34f2e7f01ada78fba94493ca1/aiohttp-3.14.2-cp312-cp312-win_arm64.whl", hash = "sha256:0eb1c9fd51f231ac8dc9d5824d5c2efc45337d429db0123fa9d4c20f570fdfc3", size = 447928, upload-time = "2026-07-20T19:51:07.523Z" }, + { url = "https://files.pythonhosted.org/packages/96/3a/8b8779f8e813d3a33cf16bc836a7ea7bf3c27b6588d42efa36b0c32fcb58/aiohttp-3.14.2-cp313-cp313-android_21_arm64_v8a.whl", hash = "sha256:17eecd6ee9bfc8e31b6003137d74f349f0ac3797111a2df87e23acb4a7a912ea", size = 506205, upload-time = "2026-07-20T19:51:09.215Z" }, + { url = "https://files.pythonhosted.org/packages/d1/73/2f45204b37ecc4ce2c54b8b67254d70a8ea3b629c4083d58f3e2d27991cb/aiohttp-3.14.2-cp313-cp313-android_21_x86_64.whl", hash = "sha256:ce8dfb58f012f76258f29951d38935ac928b32ae24a480f30761f2ed5036fa78", size = 515116, upload-time = "2026-07-20T19:51:10.914Z" }, + { url = "https://files.pythonhosted.org/packages/f0/22/8f4424de1f50df4fbb74ea32006f9cff798ae0d346ffa6be7b6f0caca719/aiohttp-3.14.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:4181d72e0e6d1735c1fae56381193c6ae211d584d06413980c00775b9b2a176a", size = 486244, upload-time = "2026-07-20T19:51:12.878Z" }, + { url = "https://files.pythonhosted.org/packages/c2/53/60de022260f5d2d31976bc5f50db708e10671f0ac5da515402adcc6b4d4d/aiohttp-3.14.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:0e56babe35076f69ec9327833b71439eeccd10f51fe56c1a533da8f24923f014", size = 492260, upload-time = "2026-07-20T19:51:14.555Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6f/d3ccc31c15cd33888670b8f1bf1dc06f3239b4edd156fc818078e87ae628/aiohttp-3.14.2-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:6b63709e259e3b3d7922b235606564e91ed4c224e777cc0ca4cae04f5f559206", size = 502174, upload-time = "2026-07-20T19:51:16.3Z" }, + { url = "https://files.pythonhosted.org/packages/40/20/52d21e485652f4708015ce27dd3029e63140e0bdb0dcc7bf72dc0bc3f4ad/aiohttp-3.14.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f7c10c4d0b33888a68c192d883d1390d4596c116a59bf689e6d352c6739b7940", size = 750878, upload-time = "2026-07-20T19:51:18.013Z" }, + { url = "https://files.pythonhosted.org/packages/2e/49/1220bdc73d568431cc3856667405d78c2e95eb57fed2b9ffa5e825932ab2/aiohttp-3.14.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f7b19e27b78a3a927b1932af93af7645806153e8f541cee8fe856426142503f", size = 508459, upload-time = "2026-07-20T19:51:19.876Z" }, + { url = "https://files.pythonhosted.org/packages/ed/f1/39177406ce0ae5cb2782b35e848c0edf6e09d6e082df636eeacdbdfa70bd/aiohttp-3.14.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:18fcc3a5cc7dde1d8f7903e309055294c28894c9434588645817e374f3b83d03", size = 509179, upload-time = "2026-07-20T19:51:21.719Z" }, + { url = "https://files.pythonhosted.org/packages/87/f7/6d081c2ee838458492c7ae1062399bdd68f149811d257d4502e79a25b306/aiohttp-3.14.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09d1b0deec698d1198eb0b8f910dd9432d856985abbfea3f06be8b296a6619b4", size = 1761346, upload-time = "2026-07-20T19:51:23.437Z" }, + { url = "https://files.pythonhosted.org/packages/1d/ed/0befea4ae533f09c3a60f0d10b923cd4a90027a1bf49dfafaa24eeee08b8/aiohttp-3.14.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:cabaaecb4c6888bd9abafac151051377534dad4c3859a386b6325f39d3732f99", size = 1735057, upload-time = "2026-07-20T19:51:25.512Z" }, + { url = "https://files.pythonhosted.org/packages/de/03/c1d89fcd94907f93a08d4aadbb4e1d9bd3d7d6c9f94bc9c17689de38107b/aiohttp-3.14.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:114299c08cce8ad4ebb21fafe766378864109e88ad8cf63cf6acb384ff844a57", size = 1800389, upload-time = "2026-07-20T19:51:27.585Z" }, + { url = "https://files.pythonhosted.org/packages/3a/8b/edbac4d1a1cde3571588a1e5b40637df5acee43158efdf3ae9a161fde8ab/aiohttp-3.14.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6bea8451e26cd67645d9b2ee18232e438ddfc36cea35feecb4537f2359fc7030", size = 1895342, upload-time = "2026-07-20T19:51:29.794Z" }, + { url = "https://files.pythonhosted.org/packages/0c/31/2e9ca3b21c07ea8a001e2b142cb01401fd34fd07b248a0b95a04c3ebc4ec/aiohttp-3.14.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:46b8887aa303075c1e5b24123f314a1a7bbfa03d0213dff8bb70503b2148c853", size = 1789175, upload-time = "2026-07-20T19:51:31.744Z" }, + { url = "https://files.pythonhosted.org/packages/6f/91/b57d3d13a80fbf765b19ae0c38d783a3a23f35b1cb82ae3b22f91abe6c24/aiohttp-3.14.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:de3b04a3f7b40ad7f1bcd3540dd447cf9bd93d57a49969bca522cbcf01290f08", size = 1586845, upload-time = "2026-07-20T19:51:33.571Z" }, + { url = "https://files.pythonhosted.org/packages/69/e8/a2f5f9f6219cd21190e9b50e2cbc978d12a2aab748d0aa7c6ee930db15c3/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:42372e1f1a8dca0dcd5daf922849004ec1120042d0e24f14c926f97d2275ca79", size = 1724839, upload-time = "2026-07-20T19:51:35.518Z" }, + { url = "https://files.pythonhosted.org/packages/de/d4/a2b9442336051714dd8dbd419b9f4a1003c45bb850ee0f3af87f2743e867/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:7871c94f3400358530ac4906dd7a526c5a24099cd5c48f53ffc4b1cb5037d7d7", size = 1756306, upload-time = "2026-07-20T19:51:37.459Z" }, + { url = "https://files.pythonhosted.org/packages/ab/93/22c94a599b2c4ea6ab88f1b912d90883f1fba5235b587ea9f13b148e9a0f/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f8f371794319a8185e61e15ba5e1be8407b986ebce1ade11856c02d24e090577", size = 1769133, upload-time = "2026-07-20T19:51:39.9Z" }, + { url = "https://files.pythonhosted.org/packages/fe/db/a4e4c207f7023e83c281a7cf3579f227bade48f1899cb6588c0ed6ae54de/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:af63ac06bad85191e6a0c4a733cb3c55adb99f8105bc7ce9913391561159a49a", size = 1578671, upload-time = "2026-07-20T19:51:42.418Z" }, + { url = "https://files.pythonhosted.org/packages/8d/6f/33746ba4947b8193652fc7ed0533e09f93b118e39777228f3029e5677c17/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:8c2cdb684c153f377157e856257ee8535c75d8478343e4bb1e83ca73bdfa3d31", size = 1791778, upload-time = "2026-07-20T19:51:44.298Z" }, + { url = "https://files.pythonhosted.org/packages/06/41/323856cb0ec9076b1f9a135eb0684f5f984dd97989a087873768aa34ca2f/aiohttp-3.14.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ceff4f84c1d928654faa6bcb0437ed095b279baae2a35fcfe5a3cbe0d8b9725d", size = 1768490, upload-time = "2026-07-20T19:51:46.279Z" }, + { url = "https://files.pythonhosted.org/packages/39/f0/09e29e457b6fb49253cbb61354ed2541fdf23ac192bddbb57bb34bc93d9c/aiohttp-3.14.2-cp313-cp313-win32.whl", hash = "sha256:15292b08ce7dd45e268fce542228894b4735102e8ee77163bd665b35fc2b5598", size = 451064, upload-time = "2026-07-20T19:51:48.194Z" }, + { url = "https://files.pythonhosted.org/packages/0b/76/b44703eafcfe1446f4f975be1ef2406042955425eaf56450e71b50506c49/aiohttp-3.14.2-cp313-cp313-win_amd64.whl", hash = "sha256:fc2d8e7373ceba7e1c7e9dc00adac854c2701a6d443fd21d4af2e49342d727bd", size = 476140, upload-time = "2026-07-20T19:51:50.285Z" }, + { url = "https://files.pythonhosted.org/packages/72/48/b095935c9e72a253439f80ec757b91d4733e0a9a98b63e108d84aaf39b08/aiohttp-3.14.2-cp313-cp313-win_arm64.whl", hash = "sha256:70570f50bda5037b416db8fcba595cf808ecf0fdce12d64e850b5ae1db7f64d4", size = 447585, upload-time = "2026-07-20T19:51:52.333Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ca/716f720dccc3032e40dc80d0ab2d87a7365270a714976a85bdff73bc7254/aiohttp-3.14.2-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:7719cef2a9dc5e10cd5f476ec1744b25c5ac4da733a9a687d91c42de7d4afe30", size = 508899, upload-time = "2026-07-20T19:51:54.165Z" }, + { url = "https://files.pythonhosted.org/packages/f5/80/786166589e71b3f3cfce56b414170fe5008462d0bff100bd8837285632f6/aiohttp-3.14.2-cp314-cp314-android_24_x86_64.whl", hash = "sha256:3523ec0cc524a413699f25ec8340f3da368484bc9d5f2a1bf87f233ac20599bf", size = 514722, upload-time = "2026-07-20T19:51:56.208Z" }, + { url = "https://files.pythonhosted.org/packages/eb/b7/539961cf3e3d3f179ea4b20d456cbdb67d1163c68f2e95bf220438a5afd5/aiohttp-3.14.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:c8ab295ee58332ef8fbd62727df90540836dfcf7a61f545d0f2771223b80bf25", size = 488082, upload-time = "2026-07-20T19:51:58.293Z" }, + { url = "https://files.pythonhosted.org/packages/60/34/c7708eac8edacca9c049a0d6f5fa610005ac3c5634c9ea4751134263bf4e/aiohttp-3.14.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:71501bc03ede681401269c569e6f9306c761c1c7d4296675e8e78dd07147070f", size = 494140, upload-time = "2026-07-20T19:52:00.158Z" }, + { url = "https://files.pythonhosted.org/packages/d8/e1/076b88de36b4ebea62d1c0b225e32bc8a452ee71b2aded82878fa5fa7c9e/aiohttp-3.14.2-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:052478c7d01035d805302db50c2ef626b1c1ba0fe2f6d4a22ae6eaeb43bf2316", size = 502670, upload-time = "2026-07-20T19:52:02.097Z" }, + { url = "https://files.pythonhosted.org/packages/a9/71/7b7720ffe7e521aaa79a853ebff4c17937f4b5a3a586e9d13b0f38050b35/aiohttp-3.14.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:b0d49be9d9a210b2c993bf32b1eda03f949f7bcda68fc4f718ae8085ae3fb4b8", size = 756406, upload-time = "2026-07-20T19:52:04.082Z" }, + { url = "https://files.pythonhosted.org/packages/b9/9a/c67c7e22fff7d7b17387e718451b30eb89f55df6b8d13d2d7f91daba6505/aiohttp-3.14.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5fe25c4c44ea5b56fd4512e2065e09384987fc8cc98e41bc8749efe12f653abb", size = 510106, upload-time = "2026-07-20T19:52:06.001Z" }, + { url = "https://files.pythonhosted.org/packages/27/2a/3caebd640229663263585d4d31898331a3937752f2e1f5ec0af509fa31be/aiohttp-3.14.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:7e254b0d636957174a03ca210289e867a62bb9502081e1b44a8c2bb1f6266ecd", size = 512876, upload-time = "2026-07-20T19:52:08.036Z" }, + { url = "https://files.pythonhosted.org/packages/27/04/86945210e491493f5cd025efe5e6d8fc8a9e8aaf36f943c40f52c34eda7e/aiohttp-3.14.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6b0ce033d49dd3c6a2566b387e322a9f9029110d67902f0d64571c0fd4b73d8", size = 1750050, upload-time = "2026-07-20T19:52:09.998Z" }, + { url = "https://files.pythonhosted.org/packages/11/d8/356c62552b4db60af5ad8cddeafa6f837788918201f1b5f2466565c986b5/aiohttp-3.14.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41b5b66b1ac2c48b61e420691eb9741d17d9068f2bc23b5ee3e750faa564bc8f", size = 1707177, upload-time = "2026-07-20T19:52:12.39Z" }, + { url = "https://files.pythonhosted.org/packages/77/2d/41bb20bed3df1d6dc7fc231ca4ffb72177fd151bf4205a4ade7a93e03501/aiohttp-3.14.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30a5ed81f752f182961237414a3cd0af209c0f74f06d66f66f9fcb8964f4978d", size = 1803795, upload-time = "2026-07-20T19:52:14.705Z" }, + { url = "https://files.pythonhosted.org/packages/63/21/ad9fe6786a1d2758bcfdae4dbc1d6869ffc7b1e0571530a508de3cdde09b/aiohttp-3.14.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b9251f43d78ff675c0ddfcd53ba61abecc1f74eedc6287bb6657f6c6a033fe7", size = 1876539, upload-time = "2026-07-20T19:52:16.965Z" }, + { url = "https://files.pythonhosted.org/packages/0e/cb/d213f4fd7af279d82c4b46d30de22db93a01296d77a8d8e535289637da54/aiohttp-3.14.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf7930e83a12801b2e253d41cc8bf5553f61c0cfabef182a72ae13472cc81803", size = 1761130, upload-time = "2026-07-20T19:52:19.127Z" }, + { url = "https://files.pythonhosted.org/packages/46/4f/0792fe1a24c2b4b506d07350e980b0626c149fe73e68dd37dfb30ed89813/aiohttp-3.14.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:abb33120daba5e5643a757790ece44d638a5a11eb0598312e6e7ec2f1bd1a5a3", size = 1583576, upload-time = "2026-07-20T19:52:21.465Z" }, + { url = "https://files.pythonhosted.org/packages/46/ad/551c302f534f9cd6105bd16902e69dc64c726aa729127203f47ed4bddb2a/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:983a68048a48f35ed08aadfcc1ba55de9a121aa91be48a764965c9ec532b94b5", size = 1714139, upload-time = "2026-07-20T19:52:23.636Z" }, + { url = "https://files.pythonhosted.org/packages/e3/cf/a3be8601d2e80ccf7bd4f79807629cede5425d72c02636f06b1ad6a8290a/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:fef094bfc2f4e991a998af066fc6e3956a409ef799f5cbad2365175357181f2e", size = 1724352, upload-time = "2026-07-20T19:52:26.043Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b1/6b55f6448b43a3338749f37fc6a14e7ac7dad121d2d585f22c1dd3d324fe/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2f7ca81d936d820ae479971a6b6214b1b867420b5b58e54a1e7157716a943754", size = 1770749, upload-time = "2026-07-20T19:52:28.467Z" }, + { url = "https://files.pythonhosted.org/packages/39/58/b3f1cf6af47fa0b0d51c6e2b98b2bf0326b44a932d74915f3c0874413ea8/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:da4f142fa078fedbdb3f88d0542ad9315656224e167502ae274cbba818b90c90", size = 1577547, upload-time = "2026-07-20T19:52:30.658Z" }, + { url = "https://files.pythonhosted.org/packages/d4/e2/1d79f1ab35593d70dabed98936ae842ac90d12847c9a62bba4a19d6005a4/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:3d4238e50a378f5ac69a1e0162715c676bd082dede2e5c4f67ca7fd0014cb09d", size = 1781840, upload-time = "2026-07-20T19:52:33.021Z" }, + { url = "https://files.pythonhosted.org/packages/01/73/770be856c6fc861563999081a5fe2d44e16b4255f5fd94b2217a2349ca65/aiohttp-3.14.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:03330676d8caa28bb33fa7104b0d542d9aac93350abcd91bf68e64abd531c320", size = 1745757, upload-time = "2026-07-20T19:52:35.541Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/861fdbe3ff90b503a4d0a12276623f4afbe54c237ca876fc560125c270a3/aiohttp-3.14.2-cp314-cp314-win32.whl", hash = "sha256:43387429e4f2ec4047aaf9f935db003d4aa1268ea9021164877fd6b012b6396a", size = 455863, upload-time = "2026-07-20T19:52:37.634Z" }, + { url = "https://files.pythonhosted.org/packages/f7/03/cc8234d0f06fe4b0e1777c7ed313cc9014f078f72a9a0cbdc144965d1bd7/aiohttp-3.14.2-cp314-cp314-win_amd64.whl", hash = "sha256:e3a6302f47518dbf2ffd3cd518f02a1fbf53f85ffeed41a224fa4a6f6a62673b", size = 480986, upload-time = "2026-07-20T19:52:39.665Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b0/ae17dd629e22160f453b9041a4aee80a8a917ba2f44d5b3e252cc501ed2c/aiohttp-3.14.2-cp314-cp314-win_arm64.whl", hash = "sha256:8d1f3802887f0e0dc07387a081dca3ad0b5758e32bdf5fb619b12ac22b8e9b56", size = 453588, upload-time = "2026-07-20T19:52:41.634Z" }, + { url = "https://files.pythonhosted.org/packages/30/54/4bbcc00f04dbc380103ee669a56df30dea127c3686c8dc2ab86b05a1387b/aiohttp-3.14.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:9094262ae4f2902c7291c14ba915960db5567276690ef9195cdefe8b7cbb3acb", size = 791337, upload-time = "2026-07-20T19:52:43.821Z" }, + { url = "https://files.pythonhosted.org/packages/e7/37/4f95edc1488580c63c0b5baaef429afbacadc7ccd9c47431cdcce90d9e5a/aiohttp-3.14.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:165b0dcc65960ffc9c99aa4ba1c3c76dbc7a34845c3c23a0bd3fbf33b3d12569", size = 526335, upload-time = "2026-07-20T19:52:45.903Z" }, + { url = "https://files.pythonhosted.org/packages/c3/ed/1d7ae73764d135638797a427cb637ae3d98f1fd61208c25891a9f26cdd67/aiohttp-3.14.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f518d75c03cd3f7f125eca1baadb56f8b94db94602278d2d0d19af6e177650a7", size = 532102, upload-time = "2026-07-20T19:52:47.994Z" }, + { url = "https://files.pythonhosted.org/packages/e3/12/da9816eee0d81506560259e7c0af93a4aa7df98acd0fe276958abd42d7c3/aiohttp-3.14.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9b937d7864ca68f1e8a1c3a4eb2bac1de86a992f86d36492da10a135a482fab6", size = 1922727, upload-time = "2026-07-20T19:52:50.224Z" }, + { url = "https://files.pythonhosted.org/packages/2f/b9/d7ccbcde223a72c7b8f3458bdb08c2bacf5fc268a1fdd5cc29861eb0e4e2/aiohttp-3.14.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b155df7f572c73c6c4108b67be302c8639b96ae56fb02787eeae8cad0a1baf26", size = 1787202, upload-time = "2026-07-20T19:52:52.825Z" }, + { url = "https://files.pythonhosted.org/packages/c2/7c/39174069b7df18ea22b23a0fa9abffe4c091f0f86d53af83ddcbb5f44c8f/aiohttp-3.14.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0bfea68a48c8071d49aabdf5cd9a6939dcb246db65730e8dc76295fe02f7c73c", size = 1912574, upload-time = "2026-07-20T19:52:55.007Z" }, + { url = "https://files.pythonhosted.org/packages/21/ff/bd2b7473510caf352aef3f52a3d4fe10184ec22747df74ab658b4402020f/aiohttp-3.14.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8241ee6c7fff3ebb1e6b237bccc1d90b46d07c06cf978e9f2ecad43e29dac67a", size = 2005478, upload-time = "2026-07-20T19:52:57.401Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ee/db26af0acc994350b653b3a73dddf9ee9886bf2fdb68b23fc98705e76442/aiohttp-3.14.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ec64d1c4605d689ed537ba1e572138e2d4ff603a0cb2bbbfe61d4552c73d19e1", size = 1879709, upload-time = "2026-07-20T19:52:59.778Z" }, + { url = "https://files.pythonhosted.org/packages/6a/4d/592451fd40edca73fcb099d8718668cea36dc1dde873dd0f8e91a4081051/aiohttp-3.14.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0fb26fcc5ebf765095fe0c6ab7501574d3108c57fca9a0d462be15a65c9deb8d", size = 1675699, upload-time = "2026-07-20T19:53:02.11Z" }, + { url = "https://files.pythonhosted.org/packages/2a/3e/c1ce4aa13fd1f910e437684843ea6cf6e0041f91d89a1b0389dce247ee59/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ef710fbb770aefa4def5484eeddb606e70ab3492aa37390def61b35652f6820a", size = 1843542, upload-time = "2026-07-20T19:53:04.385Z" }, + { url = "https://files.pythonhosted.org/packages/aa/a4/3f9e22fda714cc38ef558166ff3326cd2f6f65c33da92ba00e3641cbea54/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:d813f54560b9e5bce170fff7b0adde54d88253928e4add447c36792f27f92125", size = 1827505, upload-time = "2026-07-20T19:53:07.072Z" }, + { url = "https://files.pythonhosted.org/packages/37/9d/260c7b8a25c7cd74bee63ce957556a2d25839a321e9107a089d4da3a51af/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1aa4f3b44563a88da4407cef8a13438e9e386967720a826a10a633493f69208f", size = 1853751, upload-time = "2026-07-20T19:53:10.012Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d6/7c3cfa191e666bf7b48b4346815900b35b85b43ffff783fd0be52e45fe09/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4610638d3135afaefadf179bffd1bbf3434d3dc7a5d0a4c4219b99fa976e944d", size = 1668850, upload-time = "2026-07-20T19:53:12.362Z" }, + { url = "https://files.pythonhosted.org/packages/c4/af/d9b8353aee9506dace04ca22c3c4e93b7375d9343c4780c8b512972fc6f9/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:6e30743bd3ab6ad98e9abbad6ccb39c52bcf6f11f9e3d4b6df97afffe8df53f3", size = 1883642, upload-time = "2026-07-20T19:53:14.664Z" }, + { url = "https://files.pythonhosted.org/packages/ed/29/ed64c0a013322570a02e5b0e359df2cfd30ae58ba045748dc78175f15826/aiohttp-3.14.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:68a6f7cd8d2c70869a2a5fe97a16e86a4e13a6ed6f0d9e6029aef7573e344cd6", size = 1844092, upload-time = "2026-07-20T19:53:16.995Z" }, + { url = "https://files.pythonhosted.org/packages/3c/74/ce6f229510fdd46ee7365fbb759ffaa3004e0bcc59fbd0ec51d8a8efc775/aiohttp-3.14.2-cp314-cp314t-win32.whl", hash = "sha256:205181d896f73436ac60cf6644e545544c759ab1c3ec8c34cc1e044689611361", size = 474098, upload-time = "2026-07-20T19:53:19.645Z" }, + { url = "https://files.pythonhosted.org/packages/72/4c/877c07a6d97a1a0e5e25a06bab76dd7449b533ff8bb6c281c5af8b09c8d9/aiohttp-3.14.2-cp314-cp314t-win_amd64.whl", hash = "sha256:312d414c294a1e26aa12888e8fd37cd2e1131e9c48ddcf2a4c6b590290d52a49", size = 500480, upload-time = "2026-07-20T19:53:22.227Z" }, + { url = "https://files.pythonhosted.org/packages/42/d8/d4c74bb7990da2ee6116fe262ace41cf376ebc6b0bda694c77eeaab5a509/aiohttp-3.14.2-cp314-cp314t-win_arm64.whl", hash = "sha256:63b840c03979732ec92e570f0bd6beb6311e2b5d19cacbfcd8cc7f6dd2693900", size = 469248, upload-time = "2026-07-20T19:53:24.622Z" }, +] + +[[package]] +name = "aioitertools" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fd/3c/53c4a17a05fb9ea2313ee1777ff53f5e001aefd5cc85aa2f4c2d982e1e38/aioitertools-0.13.0.tar.gz", hash = "sha256:620bd241acc0bbb9ec819f1ab215866871b4bbd1f73836a55f799200ee86950c", size = 19322, upload-time = "2025-11-06T22:17:07.609Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/a1/510b0a7fadc6f43a6ce50152e69dbd86415240835868bb0bd9b5b88b1e06/aioitertools-0.13.0-py3-none-any.whl", hash = "sha256:0be0292b856f08dfac90e31f4739432f4cb6d7520ab9eb73e143f4f2fa5259be", size = 24182, upload-time = "2025-11-06T22:17:06.502Z" }, +] + +[[package]] +name = "aiosignal" +version = "1.4.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "frozenlist" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, +] + +[[package]] +name = "annotated-doc" +version = "0.0.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/57/ba/046ceea27344560984e26a590f90bc7f4a75b06701f653222458922b558c/annotated_doc-0.0.4.tar.gz", hash = "sha256:fbcda96e87e9c92ad167c2e53839e57503ecfda18804ea28102353485033faa4", size = 7288, upload-time = "2025-11-10T22:07:42.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/d3/26bf1008eb3d2daa8ef4cacc7f3bfdc11818d111f7e2d0201bc6e3b49d45/annotated_doc-0.0.4-py3-none-any.whl", hash = "sha256:571ac1dc6991c450b25a9c2d84a3705e2ae7a53467b5d111c24fa8baabbed320", size = 5303, upload-time = "2025-11-10T22:07:40.673Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -78,6 +351,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5c/0a/a72d10ed65068e115044937873362e6e32fab1b7dce0046aeb224682c989/asgiref-3.11.1-py3-none-any.whl", hash = "sha256:e8667a091e69529631969fd45dc268fa79b99c92c5fcdda727757e52146ec133", size = 24345, upload-time = "2026-02-03T13:30:13.039Z" }, ] +[[package]] +name = "async-timeout" +version = "5.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, +] + [[package]] name = "attrs" version = "26.1.0" @@ -100,6 +382,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fb/95/adcb68e20c34162e9135f370d6e31737719c2b6f94bc953fe7ed1f10fe21/authlib-1.7.2-py2.py3-none-any.whl", hash = "sha256:3e1faedc9d87e7d56a164eca3ccb6ace0d61b94abe83e92242f8dc8bba9b4a9f", size = 259548, upload-time = "2026-05-06T08:10:21.436Z" }, ] +[[package]] +name = "bidict" +version = "0.23.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/9a/6e/026678aa5a830e07cd9498a05d3e7e650a4f56a42f267a53d22bcda1bdc9/bidict-0.23.1.tar.gz", hash = "sha256:03069d763bc387bbd20e7d49914e75fc4132a41937fa3405417e1a5a2d006d71", size = 29093, upload-time = "2024-02-18T19:09:05.748Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/37/e8730c3587a65eb5645d4aba2d27aae48e8003614d6aaf15dda67f702f1f/bidict-0.23.1-py3-none-any.whl", hash = "sha256:5dae8d4d79b552a71cbabc7deb25dfe8ce710b17ff41711e13010ead2abfc3e5", size = 32764, upload-time = "2024-02-18T19:09:04.156Z" }, +] + +[[package]] +name = "cached-property" +version = "2.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/76/4b/3d870836119dbe9a5e3c9a61af8cc1a8b69d75aea564572e385882d5aefb/cached_property-2.0.1.tar.gz", hash = "sha256:484d617105e3ee0e4f1f58725e72a8ef9e93deee462222dbd51cd91230897641", size = 10574, upload-time = "2024-10-25T15:43:55.667Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/0e/7d8225aab3bc1a0f5811f8e1b557aa034ac04bdf641925b30d3caf586b28/cached_property-2.0.1-py3-none-any.whl", hash = "sha256:f617d70ab1100b7bcf6e42228f9ddcb78c676ffa167278d9f730d1c2fba69ccb", size = 7428, upload-time = "2024-10-25T15:43:54.711Z" }, +] + [[package]] name = "cachetools" version = "7.1.4" @@ -421,6 +721,25 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/50/a9caea39ad19c431c1a3f8a31114df65b260cdfe67786b6c7e7c040c4c44/cryptography-49.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:be9fcb48a55f023493482827d4f459bd263cc20efde64f204b97c123201850c6", size = 3783731, upload-time = "2026-06-12T20:02:43.319Z" }, ] +[[package]] +name = "dashscope" +version = "1.26.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiohttp" }, + { name = "certifi" }, + { name = "cryptography" }, + { name = "httpx" }, + { name = "httpx-sse" }, + { name = "requests" }, + { name = "rich" }, + { name = "typer" }, + { name = "websocket-client" }, +] +wheels = [ + { url = "https://files.pythonhosted.org/packages/cc/20/4dd714b5d015f3f18bce69916d3ed3b6b0af5952664733f2c9c5ce57efbf/dashscope-1.26.4-py3-none-any.whl", hash = "sha256:d56db91aecd4d981f2fdbdf526a2646a508c2f2b45347ed451cff6166ac17e3d", size = 1526000, upload-time = "2026-07-17T08:51:55.928Z" }, +] + [[package]] name = "distlib" version = "0.4.3" @@ -453,7 +772,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -469,6 +788,136 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/60/02/be4a57b60c7149b55b9e3b3c13f609cd8eb5307c751f22bd8fb8d262e75b/filelock-3.29.7-py3-none-any.whl", hash = "sha256:987db6f789a3a2a59f55081801b2b3697cb97e2a736b5f1a9e99b559285fbc51", size = 46036, upload-time = "2026-07-08T05:46:57.53Z" }, ] +[[package]] +name = "filetype" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/bb/29/745f7d30d47fe0f251d3ad3dc2978a23141917661998763bebb6da007eb1/filetype-1.2.0.tar.gz", hash = "sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb", size = 998020, upload-time = "2022-11-02T17:34:04.141Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/79/1b8fa1bb3568781e84c9200f951c735f3f157429f44be0495da55894d620/filetype-1.2.0-py2.py3-none-any.whl", hash = "sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25", size = 19970, upload-time = "2022-11-02T17:34:01.425Z" }, +] + +[[package]] +name = "frozenlist" +version = "1.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2d/f5/c831fac6cc817d26fd54c7eaccd04ef7e0288806943f7cc5bbf69f3ac1f0/frozenlist-1.8.0.tar.gz", hash = "sha256:3ede829ed8d842f6cd48fc7081d7a41001a56f1f38603f9d49bf3020d59a31ad", size = 45875, upload-time = "2025-10-06T05:38:17.865Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/4a/557715d5047da48d54e659203b9335be7bfaafda2c3f627b7c47e0b3aaf3/frozenlist-1.8.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b37f6d31b3dcea7deb5e9696e529a6aa4a898adc33db82da12e4c60a7c4d2011", size = 86230, upload-time = "2025-10-06T05:35:23.699Z" }, + { url = "https://files.pythonhosted.org/packages/a2/fb/c85f9fed3ea8fe8740e5b46a59cc141c23b842eca617da8876cfce5f760e/frozenlist-1.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef2b7b394f208233e471abc541cc6991f907ffd47dc72584acee3147899d6565", size = 49621, upload-time = "2025-10-06T05:35:25.341Z" }, + { url = "https://files.pythonhosted.org/packages/63/70/26ca3f06aace16f2352796b08704338d74b6d1a24ca38f2771afbb7ed915/frozenlist-1.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a88f062f072d1589b7b46e951698950e7da00442fc1cacbe17e19e025dc327ad", size = 49889, upload-time = "2025-10-06T05:35:26.797Z" }, + { url = "https://files.pythonhosted.org/packages/5d/ed/c7895fd2fde7f3ee70d248175f9b6cdf792fb741ab92dc59cd9ef3bd241b/frozenlist-1.8.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f57fb59d9f385710aa7060e89410aeb5058b99e62f4d16b08b91986b9a2140c2", size = 219464, upload-time = "2025-10-06T05:35:28.254Z" }, + { url = "https://files.pythonhosted.org/packages/6b/83/4d587dccbfca74cb8b810472392ad62bfa100bf8108c7223eb4c4fa2f7b3/frozenlist-1.8.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:799345ab092bee59f01a915620b5d014698547afd011e691a208637312db9186", size = 221649, upload-time = "2025-10-06T05:35:29.454Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/fd3b9cd046ec5fff9dab66831083bc2077006a874a2d3d9247dea93ddf7e/frozenlist-1.8.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c23c3ff005322a6e16f71bf8692fcf4d5a304aaafe1e262c98c6d4adc7be863e", size = 219188, upload-time = "2025-10-06T05:35:30.951Z" }, + { url = "https://files.pythonhosted.org/packages/ce/80/6693f55eb2e085fc8afb28cf611448fb5b90e98e068fa1d1b8d8e66e5c7d/frozenlist-1.8.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8a76ea0f0b9dfa06f254ee06053d93a600865b3274358ca48a352ce4f0798450", size = 231748, upload-time = "2025-10-06T05:35:32.101Z" }, + { url = "https://files.pythonhosted.org/packages/97/d6/e9459f7c5183854abd989ba384fe0cc1a0fb795a83c033f0571ec5933ca4/frozenlist-1.8.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c7366fe1418a6133d5aa824ee53d406550110984de7637d65a178010f759c6ef", size = 236351, upload-time = "2025-10-06T05:35:33.834Z" }, + { url = "https://files.pythonhosted.org/packages/97/92/24e97474b65c0262e9ecd076e826bfd1d3074adcc165a256e42e7b8a7249/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:13d23a45c4cebade99340c4165bd90eeb4a56c6d8a9d8aa49568cac19a6d0dc4", size = 218767, upload-time = "2025-10-06T05:35:35.205Z" }, + { url = "https://files.pythonhosted.org/packages/ee/bf/dc394a097508f15abff383c5108cb8ad880d1f64a725ed3b90d5c2fbf0bb/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:e4a3408834f65da56c83528fb52ce7911484f0d1eaf7b761fc66001db1646eff", size = 235887, upload-time = "2025-10-06T05:35:36.354Z" }, + { url = "https://files.pythonhosted.org/packages/40/90/25b201b9c015dbc999a5baf475a257010471a1fa8c200c843fd4abbee725/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:42145cd2748ca39f32801dad54aeea10039da6f86e303659db90db1c4b614c8c", size = 228785, upload-time = "2025-10-06T05:35:37.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/f4/b5bc148df03082f05d2dd30c089e269acdbe251ac9a9cf4e727b2dbb8a3d/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e2de870d16a7a53901e41b64ffdf26f2fbb8917b3e6ebf398098d72c5b20bd7f", size = 230312, upload-time = "2025-10-06T05:35:39.178Z" }, + { url = "https://files.pythonhosted.org/packages/db/4b/87e95b5d15097c302430e647136b7d7ab2398a702390cf4c8601975709e7/frozenlist-1.8.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:20e63c9493d33ee48536600d1a5c95eefc870cd71e7ab037763d1fbb89cc51e7", size = 217650, upload-time = "2025-10-06T05:35:40.377Z" }, + { url = "https://files.pythonhosted.org/packages/e5/70/78a0315d1fea97120591a83e0acd644da638c872f142fd72a6cebee825f3/frozenlist-1.8.0-cp310-cp310-win32.whl", hash = "sha256:adbeebaebae3526afc3c96fad434367cafbfd1b25d72369a9e5858453b1bb71a", size = 39659, upload-time = "2025-10-06T05:35:41.863Z" }, + { url = "https://files.pythonhosted.org/packages/66/aa/3f04523fb189a00e147e60c5b2205126118f216b0aa908035c45336e27e4/frozenlist-1.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:667c3777ca571e5dbeb76f331562ff98b957431df140b54c85fd4d52eea8d8f6", size = 43837, upload-time = "2025-10-06T05:35:43.205Z" }, + { url = "https://files.pythonhosted.org/packages/39/75/1135feecdd7c336938bd55b4dc3b0dfc46d85b9be12ef2628574b28de776/frozenlist-1.8.0-cp310-cp310-win_arm64.whl", hash = "sha256:80f85f0a7cc86e7a54c46d99c9e1318ff01f4687c172ede30fd52d19d1da1c8e", size = 39989, upload-time = "2025-10-06T05:35:44.596Z" }, + { url = "https://files.pythonhosted.org/packages/bc/03/077f869d540370db12165c0aa51640a873fb661d8b315d1d4d67b284d7ac/frozenlist-1.8.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:09474e9831bc2b2199fad6da3c14c7b0fbdd377cce9d3d77131be28906cb7d84", size = 86912, upload-time = "2025-10-06T05:35:45.98Z" }, + { url = "https://files.pythonhosted.org/packages/df/b5/7610b6bd13e4ae77b96ba85abea1c8cb249683217ef09ac9e0ae93f25a91/frozenlist-1.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:17c883ab0ab67200b5f964d2b9ed6b00971917d5d8a92df149dc2c9779208ee9", size = 50046, upload-time = "2025-10-06T05:35:47.009Z" }, + { url = "https://files.pythonhosted.org/packages/6e/ef/0e8f1fe32f8a53dd26bdd1f9347efe0778b0fddf62789ea683f4cc7d787d/frozenlist-1.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fa47e444b8ba08fffd1c18e8cdb9a75db1b6a27f17507522834ad13ed5922b93", size = 50119, upload-time = "2025-10-06T05:35:48.38Z" }, + { url = "https://files.pythonhosted.org/packages/11/b1/71a477adc7c36e5fb628245dfbdea2166feae310757dea848d02bd0689fd/frozenlist-1.8.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:2552f44204b744fba866e573be4c1f9048d6a324dfe14475103fd51613eb1d1f", size = 231067, upload-time = "2025-10-06T05:35:49.97Z" }, + { url = "https://files.pythonhosted.org/packages/45/7e/afe40eca3a2dc19b9904c0f5d7edfe82b5304cb831391edec0ac04af94c2/frozenlist-1.8.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:957e7c38f250991e48a9a73e6423db1bb9dd14e722a10f6b8bb8e16a0f55f695", size = 233160, upload-time = "2025-10-06T05:35:51.729Z" }, + { url = "https://files.pythonhosted.org/packages/a6/aa/7416eac95603ce428679d273255ffc7c998d4132cfae200103f164b108aa/frozenlist-1.8.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8585e3bb2cdea02fc88ffa245069c36555557ad3609e83be0ec71f54fd4abb52", size = 228544, upload-time = "2025-10-06T05:35:53.246Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3d/2a2d1f683d55ac7e3875e4263d28410063e738384d3adc294f5ff3d7105e/frozenlist-1.8.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edee74874ce20a373d62dc28b0b18b93f645633c2943fd90ee9d898550770581", size = 243797, upload-time = "2025-10-06T05:35:54.497Z" }, + { url = "https://files.pythonhosted.org/packages/78/1e/2d5565b589e580c296d3bb54da08d206e797d941a83a6fdea42af23be79c/frozenlist-1.8.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:c9a63152fe95756b85f31186bddf42e4c02c6321207fd6601a1c89ebac4fe567", size = 247923, upload-time = "2025-10-06T05:35:55.861Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c3/65872fcf1d326a7f101ad4d86285c403c87be7d832b7470b77f6d2ed5ddc/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b6db2185db9be0a04fecf2f241c70b63b1a242e2805be291855078f2b404dd6b", size = 230886, upload-time = "2025-10-06T05:35:57.399Z" }, + { url = "https://files.pythonhosted.org/packages/a0/76/ac9ced601d62f6956f03cc794f9e04c81719509f85255abf96e2510f4265/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:f4be2e3d8bc8aabd566f8d5b8ba7ecc09249d74ba3c9ed52e54dc23a293f0b92", size = 245731, upload-time = "2025-10-06T05:35:58.563Z" }, + { url = "https://files.pythonhosted.org/packages/b9/49/ecccb5f2598daf0b4a1415497eba4c33c1e8ce07495eb07d2860c731b8d5/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:c8d1634419f39ea6f5c427ea2f90ca85126b54b50837f31497f3bf38266e853d", size = 241544, upload-time = "2025-10-06T05:35:59.719Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/ddf24113323c0bbcc54cb38c8b8916f1da7165e07b8e24a717b4a12cbf10/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1a7fa382a4a223773ed64242dbe1c9c326ec09457e6b8428efb4118c685c3dfd", size = 241806, upload-time = "2025-10-06T05:36:00.959Z" }, + { url = "https://files.pythonhosted.org/packages/a7/fb/9b9a084d73c67175484ba2789a59f8eebebd0827d186a8102005ce41e1ba/frozenlist-1.8.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:11847b53d722050808926e785df837353bd4d75f1d494377e59b23594d834967", size = 229382, upload-time = "2025-10-06T05:36:02.22Z" }, + { url = "https://files.pythonhosted.org/packages/95/a3/c8fb25aac55bf5e12dae5c5aa6a98f85d436c1dc658f21c3ac73f9fa95e5/frozenlist-1.8.0-cp311-cp311-win32.whl", hash = "sha256:27c6e8077956cf73eadd514be8fb04d77fc946a7fe9f7fe167648b0b9085cc25", size = 39647, upload-time = "2025-10-06T05:36:03.409Z" }, + { url = "https://files.pythonhosted.org/packages/0a/f5/603d0d6a02cfd4c8f2a095a54672b3cf967ad688a60fb9faf04fc4887f65/frozenlist-1.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:ac913f8403b36a2c8610bbfd25b8013488533e71e62b4b4adce9c86c8cea905b", size = 44064, upload-time = "2025-10-06T05:36:04.368Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/c2c9ab44e181f043a86f9a8f84d5124b62dbcb3a02c0977ec72b9ac1d3e0/frozenlist-1.8.0-cp311-cp311-win_arm64.whl", hash = "sha256:d4d3214a0f8394edfa3e303136d0575eece0745ff2b47bd2cb2e66dd92d4351a", size = 39937, upload-time = "2025-10-06T05:36:05.669Z" }, + { url = "https://files.pythonhosted.org/packages/69/29/948b9aa87e75820a38650af445d2ef2b6b8a6fab1a23b6bb9e4ef0be2d59/frozenlist-1.8.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:78f7b9e5d6f2fdb88cdde9440dc147259b62b9d3b019924def9f6478be254ac1", size = 87782, upload-time = "2025-10-06T05:36:06.649Z" }, + { url = "https://files.pythonhosted.org/packages/64/80/4f6e318ee2a7c0750ed724fa33a4bdf1eacdc5a39a7a24e818a773cd91af/frozenlist-1.8.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:229bf37d2e4acdaf808fd3f06e854a4a7a3661e871b10dc1f8f1896a3b05f18b", size = 50594, upload-time = "2025-10-06T05:36:07.69Z" }, + { url = "https://files.pythonhosted.org/packages/2b/94/5c8a2b50a496b11dd519f4a24cb5496cf125681dd99e94c604ccdea9419a/frozenlist-1.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f833670942247a14eafbb675458b4e61c82e002a148f49e68257b79296e865c4", size = 50448, upload-time = "2025-10-06T05:36:08.78Z" }, + { url = "https://files.pythonhosted.org/packages/6a/bd/d91c5e39f490a49df14320f4e8c80161cfcce09f1e2cde1edd16a551abb3/frozenlist-1.8.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:494a5952b1c597ba44e0e78113a7266e656b9794eec897b19ead706bd7074383", size = 242411, upload-time = "2025-10-06T05:36:09.801Z" }, + { url = "https://files.pythonhosted.org/packages/8f/83/f61505a05109ef3293dfb1ff594d13d64a2324ac3482be2cedc2be818256/frozenlist-1.8.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96f423a119f4777a4a056b66ce11527366a8bb92f54e541ade21f2374433f6d4", size = 243014, upload-time = "2025-10-06T05:36:11.394Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cb/cb6c7b0f7d4023ddda30cf56b8b17494eb3a79e3fda666bf735f63118b35/frozenlist-1.8.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3462dd9475af2025c31cc61be6652dfa25cbfb56cbbf52f4ccfe029f38decaf8", size = 234909, upload-time = "2025-10-06T05:36:12.598Z" }, + { url = "https://files.pythonhosted.org/packages/31/c5/cd7a1f3b8b34af009fb17d4123c5a778b44ae2804e3ad6b86204255f9ec5/frozenlist-1.8.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c4c800524c9cd9bac5166cd6f55285957fcfc907db323e193f2afcd4d9abd69b", size = 250049, upload-time = "2025-10-06T05:36:14.065Z" }, + { url = "https://files.pythonhosted.org/packages/c0/01/2f95d3b416c584a1e7f0e1d6d31998c4a795f7544069ee2e0962a4b60740/frozenlist-1.8.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d6a5df73acd3399d893dafc71663ad22534b5aa4f94e8a2fabfe856c3c1b6a52", size = 256485, upload-time = "2025-10-06T05:36:15.39Z" }, + { url = "https://files.pythonhosted.org/packages/ce/03/024bf7720b3abaebcff6d0793d73c154237b85bdf67b7ed55e5e9596dc9a/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:405e8fe955c2280ce66428b3ca55e12b3c4e9c336fb2103a4937e891c69a4a29", size = 237619, upload-time = "2025-10-06T05:36:16.558Z" }, + { url = "https://files.pythonhosted.org/packages/69/fa/f8abdfe7d76b731f5d8bd217827cf6764d4f1d9763407e42717b4bed50a0/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:908bd3f6439f2fef9e85031b59fd4f1297af54415fb60e4254a95f75b3cab3f3", size = 250320, upload-time = "2025-10-06T05:36:17.821Z" }, + { url = "https://files.pythonhosted.org/packages/f5/3c/b051329f718b463b22613e269ad72138cc256c540f78a6de89452803a47d/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:294e487f9ec720bd8ffcebc99d575f7eff3568a08a253d1ee1a0378754b74143", size = 246820, upload-time = "2025-10-06T05:36:19.046Z" }, + { url = "https://files.pythonhosted.org/packages/0f/ae/58282e8f98e444b3f4dd42448ff36fa38bef29e40d40f330b22e7108f565/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:74c51543498289c0c43656701be6b077f4b265868fa7f8a8859c197006efb608", size = 250518, upload-time = "2025-10-06T05:36:20.763Z" }, + { url = "https://files.pythonhosted.org/packages/8f/96/007e5944694d66123183845a106547a15944fbbb7154788cbf7272789536/frozenlist-1.8.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:776f352e8329135506a1d6bf16ac3f87bc25b28e765949282dcc627af36123aa", size = 239096, upload-time = "2025-10-06T05:36:22.129Z" }, + { url = "https://files.pythonhosted.org/packages/66/bb/852b9d6db2fa40be96f29c0d1205c306288f0684df8fd26ca1951d461a56/frozenlist-1.8.0-cp312-cp312-win32.whl", hash = "sha256:433403ae80709741ce34038da08511d4a77062aa924baf411ef73d1146e74faf", size = 39985, upload-time = "2025-10-06T05:36:23.661Z" }, + { url = "https://files.pythonhosted.org/packages/b8/af/38e51a553dd66eb064cdf193841f16f077585d4d28394c2fa6235cb41765/frozenlist-1.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:34187385b08f866104f0c0617404c8eb08165ab1272e884abc89c112e9c00746", size = 44591, upload-time = "2025-10-06T05:36:24.958Z" }, + { url = "https://files.pythonhosted.org/packages/a7/06/1dc65480ab147339fecc70797e9c2f69d9cea9cf38934ce08df070fdb9cb/frozenlist-1.8.0-cp312-cp312-win_arm64.whl", hash = "sha256:fe3c58d2f5db5fbd18c2987cba06d51b0529f52bc3a6cdc33d3f4eab725104bd", size = 40102, upload-time = "2025-10-06T05:36:26.333Z" }, + { url = "https://files.pythonhosted.org/packages/2d/40/0832c31a37d60f60ed79e9dfb5a92e1e2af4f40a16a29abcc7992af9edff/frozenlist-1.8.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:8d92f1a84bb12d9e56f818b3a746f3efba93c1b63c8387a73dde655e1e42282a", size = 85717, upload-time = "2025-10-06T05:36:27.341Z" }, + { url = "https://files.pythonhosted.org/packages/30/ba/b0b3de23f40bc55a7057bd38434e25c34fa48e17f20ee273bbde5e0650f3/frozenlist-1.8.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:96153e77a591c8adc2ee805756c61f59fef4cf4073a9275ee86fe8cba41241f7", size = 49651, upload-time = "2025-10-06T05:36:28.855Z" }, + { url = "https://files.pythonhosted.org/packages/0c/ab/6e5080ee374f875296c4243c381bbdef97a9ac39c6e3ce1d5f7d42cb78d6/frozenlist-1.8.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f21f00a91358803399890ab167098c131ec2ddd5f8f5fd5fe9c9f2c6fcd91e40", size = 49417, upload-time = "2025-10-06T05:36:29.877Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4e/e4691508f9477ce67da2015d8c00acd751e6287739123113a9fca6f1604e/frozenlist-1.8.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:fb30f9626572a76dfe4293c7194a09fb1fe93ba94c7d4f720dfae3b646b45027", size = 234391, upload-time = "2025-10-06T05:36:31.301Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/c202df58e3acdf12969a7895fd6f3bc016c642e6726aa63bd3025e0fc71c/frozenlist-1.8.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eaa352d7047a31d87dafcacbabe89df0aa506abb5b1b85a2fb91bc3faa02d822", size = 233048, upload-time = "2025-10-06T05:36:32.531Z" }, + { url = "https://files.pythonhosted.org/packages/f9/c0/8746afb90f17b73ca5979c7a3958116e105ff796e718575175319b5bb4ce/frozenlist-1.8.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:03ae967b4e297f58f8c774c7eabcce57fe3c2434817d4385c50661845a058121", size = 226549, upload-time = "2025-10-06T05:36:33.706Z" }, + { url = "https://files.pythonhosted.org/packages/7e/eb/4c7eefc718ff72f9b6c4893291abaae5fbc0c82226a32dcd8ef4f7a5dbef/frozenlist-1.8.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f6292f1de555ffcc675941d65fffffb0a5bcd992905015f85d0592201793e0e5", size = 239833, upload-time = "2025-10-06T05:36:34.947Z" }, + { url = "https://files.pythonhosted.org/packages/c2/4e/e5c02187cf704224f8b21bee886f3d713ca379535f16893233b9d672ea71/frozenlist-1.8.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29548f9b5b5e3460ce7378144c3010363d8035cea44bc0bf02d57f5a685e084e", size = 245363, upload-time = "2025-10-06T05:36:36.534Z" }, + { url = "https://files.pythonhosted.org/packages/1f/96/cb85ec608464472e82ad37a17f844889c36100eed57bea094518bf270692/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ec3cc8c5d4084591b4237c0a272cc4f50a5b03396a47d9caaf76f5d7b38a4f11", size = 229314, upload-time = "2025-10-06T05:36:38.582Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6f/4ae69c550e4cee66b57887daeebe006fe985917c01d0fff9caab9883f6d0/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:517279f58009d0b1f2e7c1b130b377a349405da3f7621ed6bfae50b10adf20c1", size = 243365, upload-time = "2025-10-06T05:36:40.152Z" }, + { url = "https://files.pythonhosted.org/packages/7a/58/afd56de246cf11780a40a2c28dc7cbabbf06337cc8ddb1c780a2d97e88d8/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:db1e72ede2d0d7ccb213f218df6a078a9c09a7de257c2fe8fcef16d5925230b1", size = 237763, upload-time = "2025-10-06T05:36:41.355Z" }, + { url = "https://files.pythonhosted.org/packages/cb/36/cdfaf6ed42e2644740d4a10452d8e97fa1c062e2a8006e4b09f1b5fd7d63/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:b4dec9482a65c54a5044486847b8a66bf10c9cb4926d42927ec4e8fd5db7fed8", size = 240110, upload-time = "2025-10-06T05:36:42.716Z" }, + { url = "https://files.pythonhosted.org/packages/03/a8/9ea226fbefad669f11b52e864c55f0bd57d3c8d7eb07e9f2e9a0b39502e1/frozenlist-1.8.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:21900c48ae04d13d416f0e1e0c4d81f7931f73a9dfa0b7a8746fb2fe7dd970ed", size = 233717, upload-time = "2025-10-06T05:36:44.251Z" }, + { url = "https://files.pythonhosted.org/packages/1e/0b/1b5531611e83ba7d13ccc9988967ea1b51186af64c42b7a7af465dcc9568/frozenlist-1.8.0-cp313-cp313-win32.whl", hash = "sha256:8b7b94a067d1c504ee0b16def57ad5738701e4ba10cec90529f13fa03c833496", size = 39628, upload-time = "2025-10-06T05:36:45.423Z" }, + { url = "https://files.pythonhosted.org/packages/d8/cf/174c91dbc9cc49bc7b7aab74d8b734e974d1faa8f191c74af9b7e80848e6/frozenlist-1.8.0-cp313-cp313-win_amd64.whl", hash = "sha256:878be833caa6a3821caf85eb39c5ba92d28e85df26d57afb06b35b2efd937231", size = 43882, upload-time = "2025-10-06T05:36:46.796Z" }, + { url = "https://files.pythonhosted.org/packages/c1/17/502cd212cbfa96eb1388614fe39a3fc9ab87dbbe042b66f97acb57474834/frozenlist-1.8.0-cp313-cp313-win_arm64.whl", hash = "sha256:44389d135b3ff43ba8cc89ff7f51f5a0bb6b63d829c8300f79a2fe4fe61bcc62", size = 39676, upload-time = "2025-10-06T05:36:47.8Z" }, + { url = "https://files.pythonhosted.org/packages/d2/5c/3bbfaa920dfab09e76946a5d2833a7cbdf7b9b4a91c714666ac4855b88b4/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:e25ac20a2ef37e91c1b39938b591457666a0fa835c7783c3a8f33ea42870db94", size = 89235, upload-time = "2025-10-06T05:36:48.78Z" }, + { url = "https://files.pythonhosted.org/packages/d2/d6/f03961ef72166cec1687e84e8925838442b615bd0b8854b54923ce5b7b8a/frozenlist-1.8.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:07cdca25a91a4386d2e76ad992916a85038a9b97561bf7a3fd12d5d9ce31870c", size = 50742, upload-time = "2025-10-06T05:36:49.837Z" }, + { url = "https://files.pythonhosted.org/packages/1e/bb/a6d12b7ba4c3337667d0e421f7181c82dda448ce4e7ad7ecd249a16fa806/frozenlist-1.8.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4e0c11f2cc6717e0a741f84a527c52616140741cd812a50422f83dc31749fb52", size = 51725, upload-time = "2025-10-06T05:36:50.851Z" }, + { url = "https://files.pythonhosted.org/packages/bc/71/d1fed0ffe2c2ccd70b43714c6cab0f4188f09f8a67a7914a6b46ee30f274/frozenlist-1.8.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:b3210649ee28062ea6099cfda39e147fa1bc039583c8ee4481cb7811e2448c51", size = 284533, upload-time = "2025-10-06T05:36:51.898Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1f/fb1685a7b009d89f9bf78a42d94461bc06581f6e718c39344754a5d9bada/frozenlist-1.8.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581ef5194c48035a7de2aefc72ac6539823bb71508189e5de01d60c9dcd5fa65", size = 292506, upload-time = "2025-10-06T05:36:53.101Z" }, + { url = "https://files.pythonhosted.org/packages/e6/3b/b991fe1612703f7e0d05c0cf734c1b77aaf7c7d321df4572e8d36e7048c8/frozenlist-1.8.0-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3ef2d026f16a2b1866e1d86fc4e1291e1ed8a387b2c333809419a2f8b3a77b82", size = 274161, upload-time = "2025-10-06T05:36:54.309Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ec/c5c618767bcdf66e88945ec0157d7f6c4a1322f1473392319b7a2501ded7/frozenlist-1.8.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5500ef82073f599ac84d888e3a8c1f77ac831183244bfd7f11eaa0289fb30714", size = 294676, upload-time = "2025-10-06T05:36:55.566Z" }, + { url = "https://files.pythonhosted.org/packages/7c/ce/3934758637d8f8a88d11f0585d6495ef54b2044ed6ec84492a91fa3b27aa/frozenlist-1.8.0-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:50066c3997d0091c411a66e710f4e11752251e6d2d73d70d8d5d4c76442a199d", size = 300638, upload-time = "2025-10-06T05:36:56.758Z" }, + { url = "https://files.pythonhosted.org/packages/fc/4f/a7e4d0d467298f42de4b41cbc7ddaf19d3cfeabaf9ff97c20c6c7ee409f9/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:5c1c8e78426e59b3f8005e9b19f6ff46e5845895adbde20ece9218319eca6506", size = 283067, upload-time = "2025-10-06T05:36:57.965Z" }, + { url = "https://files.pythonhosted.org/packages/dc/48/c7b163063d55a83772b268e6d1affb960771b0e203b632cfe09522d67ea5/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:eefdba20de0d938cec6a89bd4d70f346a03108a19b9df4248d3cf0d88f1b0f51", size = 292101, upload-time = "2025-10-06T05:36:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/9f/d0/2366d3c4ecdc2fd391e0afa6e11500bfba0ea772764d631bbf82f0136c9d/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:cf253e0e1c3ceb4aaff6df637ce033ff6535fb8c70a764a8f46aafd3d6ab798e", size = 289901, upload-time = "2025-10-06T05:37:00.811Z" }, + { url = "https://files.pythonhosted.org/packages/b8/94/daff920e82c1b70e3618a2ac39fbc01ae3e2ff6124e80739ce5d71c9b920/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:032efa2674356903cd0261c4317a561a6850f3ac864a63fc1583147fb05a79b0", size = 289395, upload-time = "2025-10-06T05:37:02.115Z" }, + { url = "https://files.pythonhosted.org/packages/e3/20/bba307ab4235a09fdcd3cc5508dbabd17c4634a1af4b96e0f69bfe551ebd/frozenlist-1.8.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:6da155091429aeba16851ecb10a9104a108bcd32f6c1642867eadaee401c1c41", size = 283659, upload-time = "2025-10-06T05:37:03.711Z" }, + { url = "https://files.pythonhosted.org/packages/fd/00/04ca1c3a7a124b6de4f8a9a17cc2fcad138b4608e7a3fc5877804b8715d7/frozenlist-1.8.0-cp313-cp313t-win32.whl", hash = "sha256:0f96534f8bfebc1a394209427d0f8a63d343c9779cda6fc25e8e121b5fd8555b", size = 43492, upload-time = "2025-10-06T05:37:04.915Z" }, + { url = "https://files.pythonhosted.org/packages/59/5e/c69f733a86a94ab10f68e496dc6b7e8bc078ebb415281d5698313e3af3a1/frozenlist-1.8.0-cp313-cp313t-win_amd64.whl", hash = "sha256:5d63a068f978fc69421fb0e6eb91a9603187527c86b7cd3f534a5b77a592b888", size = 48034, upload-time = "2025-10-06T05:37:06.343Z" }, + { url = "https://files.pythonhosted.org/packages/16/6c/be9d79775d8abe79b05fa6d23da99ad6e7763a1d080fbae7290b286093fd/frozenlist-1.8.0-cp313-cp313t-win_arm64.whl", hash = "sha256:bf0a7e10b077bf5fb9380ad3ae8ce20ef919a6ad93b4552896419ac7e1d8e042", size = 41749, upload-time = "2025-10-06T05:37:07.431Z" }, + { url = "https://files.pythonhosted.org/packages/f1/c8/85da824b7e7b9b6e7f7705b2ecaf9591ba6f79c1177f324c2735e41d36a2/frozenlist-1.8.0-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:cee686f1f4cadeb2136007ddedd0aaf928ab95216e7691c63e50a8ec066336d0", size = 86127, upload-time = "2025-10-06T05:37:08.438Z" }, + { url = "https://files.pythonhosted.org/packages/8e/e8/a1185e236ec66c20afd72399522f142c3724c785789255202d27ae992818/frozenlist-1.8.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:119fb2a1bd47307e899c2fac7f28e85b9a543864df47aa7ec9d3c1b4545f096f", size = 49698, upload-time = "2025-10-06T05:37:09.48Z" }, + { url = "https://files.pythonhosted.org/packages/a1/93/72b1736d68f03fda5fdf0f2180fb6caaae3894f1b854d006ac61ecc727ee/frozenlist-1.8.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:4970ece02dbc8c3a92fcc5228e36a3e933a01a999f7094ff7c23fbd2beeaa67c", size = 49749, upload-time = "2025-10-06T05:37:10.569Z" }, + { url = "https://files.pythonhosted.org/packages/a7/b2/fabede9fafd976b991e9f1b9c8c873ed86f202889b864756f240ce6dd855/frozenlist-1.8.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:cba69cb73723c3f329622e34bdbf5ce1f80c21c290ff04256cff1cd3c2036ed2", size = 231298, upload-time = "2025-10-06T05:37:11.993Z" }, + { url = "https://files.pythonhosted.org/packages/3a/3b/d9b1e0b0eed36e70477ffb8360c49c85c8ca8ef9700a4e6711f39a6e8b45/frozenlist-1.8.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:778a11b15673f6f1df23d9586f83c4846c471a8af693a22e066508b77d201ec8", size = 232015, upload-time = "2025-10-06T05:37:13.194Z" }, + { url = "https://files.pythonhosted.org/packages/dc/94/be719d2766c1138148564a3960fc2c06eb688da592bdc25adcf856101be7/frozenlist-1.8.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0325024fe97f94c41c08872db482cf8ac4800d80e79222c6b0b7b162d5b13686", size = 225038, upload-time = "2025-10-06T05:37:14.577Z" }, + { url = "https://files.pythonhosted.org/packages/e4/09/6712b6c5465f083f52f50cf74167b92d4ea2f50e46a9eea0523d658454ae/frozenlist-1.8.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:97260ff46b207a82a7567b581ab4190bd4dfa09f4db8a8b49d1a958f6aa4940e", size = 240130, upload-time = "2025-10-06T05:37:15.781Z" }, + { url = "https://files.pythonhosted.org/packages/f8/d4/cd065cdcf21550b54f3ce6a22e143ac9e4836ca42a0de1022da8498eac89/frozenlist-1.8.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:54b2077180eb7f83dd52c40b2750d0a9f175e06a42e3213ce047219de902717a", size = 242845, upload-time = "2025-10-06T05:37:17.037Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/f57a5c8c70cd1ead3d5d5f776f89d33110b1addae0ab010ad774d9a44fb9/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:2f05983daecab868a31e1da44462873306d3cbfd76d1f0b5b69c473d21dbb128", size = 229131, upload-time = "2025-10-06T05:37:18.221Z" }, + { url = "https://files.pythonhosted.org/packages/6c/52/232476fe9cb64f0742f3fde2b7d26c1dac18b6d62071c74d4ded55e0ef94/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:33f48f51a446114bc5d251fb2954ab0164d5be02ad3382abcbfe07e2531d650f", size = 240542, upload-time = "2025-10-06T05:37:19.771Z" }, + { url = "https://files.pythonhosted.org/packages/5f/85/07bf3f5d0fb5414aee5f47d33c6f5c77bfe49aac680bfece33d4fdf6a246/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:154e55ec0655291b5dd1b8731c637ecdb50975a2ae70c606d100750a540082f7", size = 237308, upload-time = "2025-10-06T05:37:20.969Z" }, + { url = "https://files.pythonhosted.org/packages/11/99/ae3a33d5befd41ac0ca2cc7fd3aa707c9c324de2e89db0e0f45db9a64c26/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4314debad13beb564b708b4a496020e5306c7333fa9a3ab90374169a20ffab30", size = 238210, upload-time = "2025-10-06T05:37:22.252Z" }, + { url = "https://files.pythonhosted.org/packages/b2/60/b1d2da22f4970e7a155f0adde9b1435712ece01b3cd45ba63702aea33938/frozenlist-1.8.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:073f8bf8becba60aa931eb3bc420b217bb7d5b8f4750e6f8b3be7f3da85d38b7", size = 231972, upload-time = "2025-10-06T05:37:23.5Z" }, + { url = "https://files.pythonhosted.org/packages/3f/ab/945b2f32de889993b9c9133216c068b7fcf257d8595a0ac420ac8677cab0/frozenlist-1.8.0-cp314-cp314-win32.whl", hash = "sha256:bac9c42ba2ac65ddc115d930c78d24ab8d4f465fd3fc473cdedfccadb9429806", size = 40536, upload-time = "2025-10-06T05:37:25.581Z" }, + { url = "https://files.pythonhosted.org/packages/59/ad/9caa9b9c836d9ad6f067157a531ac48b7d36499f5036d4141ce78c230b1b/frozenlist-1.8.0-cp314-cp314-win_amd64.whl", hash = "sha256:3e0761f4d1a44f1d1a47996511752cf3dcec5bbdd9cc2b4fe595caf97754b7a0", size = 44330, upload-time = "2025-10-06T05:37:26.928Z" }, + { url = "https://files.pythonhosted.org/packages/82/13/e6950121764f2676f43534c555249f57030150260aee9dcf7d64efda11dd/frozenlist-1.8.0-cp314-cp314-win_arm64.whl", hash = "sha256:d1eaff1d00c7751b7c6662e9c5ba6eb2c17a2306ba5e2a37f24ddf3cc953402b", size = 40627, upload-time = "2025-10-06T05:37:28.075Z" }, + { url = "https://files.pythonhosted.org/packages/c0/c7/43200656ecc4e02d3f8bc248df68256cd9572b3f0017f0a0c4e93440ae23/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:d3bb933317c52d7ea5004a1c442eef86f426886fba134ef8cf4226ea6ee1821d", size = 89238, upload-time = "2025-10-06T05:37:29.373Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/55c5f0689b9c0fb765055629f472c0de484dcaf0acee2f7707266ae3583c/frozenlist-1.8.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:8009897cdef112072f93a0efdce29cd819e717fd2f649ee3016efd3cd885a7ed", size = 50738, upload-time = "2025-10-06T05:37:30.792Z" }, + { url = "https://files.pythonhosted.org/packages/ba/7d/b7282a445956506fa11da8c2db7d276adcbf2b17d8bb8407a47685263f90/frozenlist-1.8.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:2c5dcbbc55383e5883246d11fd179782a9d07a986c40f49abe89ddf865913930", size = 51739, upload-time = "2025-10-06T05:37:32.127Z" }, + { url = "https://files.pythonhosted.org/packages/62/1c/3d8622e60d0b767a5510d1d3cf21065b9db874696a51ea6d7a43180a259c/frozenlist-1.8.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:39ecbc32f1390387d2aa4f5a995e465e9e2f79ba3adcac92d68e3e0afae6657c", size = 284186, upload-time = "2025-10-06T05:37:33.21Z" }, + { url = "https://files.pythonhosted.org/packages/2d/14/aa36d5f85a89679a85a1d44cd7a6657e0b1c75f61e7cad987b203d2daca8/frozenlist-1.8.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92db2bf818d5cc8d9c1f1fc56b897662e24ea5adb36ad1f1d82875bd64e03c24", size = 292196, upload-time = "2025-10-06T05:37:36.107Z" }, + { url = "https://files.pythonhosted.org/packages/05/23/6bde59eb55abd407d34f77d39a5126fb7b4f109a3f611d3929f14b700c66/frozenlist-1.8.0-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dc43a022e555de94c3b68a4ef0b11c4f747d12c024a520c7101709a2144fb37", size = 273830, upload-time = "2025-10-06T05:37:37.663Z" }, + { url = "https://files.pythonhosted.org/packages/d2/3f/22cff331bfad7a8afa616289000ba793347fcd7bc275f3b28ecea2a27909/frozenlist-1.8.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cb89a7f2de3602cfed448095bab3f178399646ab7c61454315089787df07733a", size = 294289, upload-time = "2025-10-06T05:37:39.261Z" }, + { url = "https://files.pythonhosted.org/packages/a4/89/5b057c799de4838b6c69aa82b79705f2027615e01be996d2486a69ca99c4/frozenlist-1.8.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:33139dc858c580ea50e7e60a1b0ea003efa1fd42e6ec7fdbad78fff65fad2fd2", size = 300318, upload-time = "2025-10-06T05:37:43.213Z" }, + { url = "https://files.pythonhosted.org/packages/30/de/2c22ab3eb2a8af6d69dc799e48455813bab3690c760de58e1bf43b36da3e/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:168c0969a329b416119507ba30b9ea13688fafffac1b7822802537569a1cb0ef", size = 282814, upload-time = "2025-10-06T05:37:45.337Z" }, + { url = "https://files.pythonhosted.org/packages/59/f7/970141a6a8dbd7f556d94977858cfb36fa9b66e0892c6dd780d2219d8cd8/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:28bd570e8e189d7f7b001966435f9dac6718324b5be2990ac496cf1ea9ddb7fe", size = 291762, upload-time = "2025-10-06T05:37:46.657Z" }, + { url = "https://files.pythonhosted.org/packages/c1/15/ca1adae83a719f82df9116d66f5bb28bb95557b3951903d39135620ef157/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b2a095d45c5d46e5e79ba1e5b9cb787f541a8dee0433836cea4b96a2c439dcd8", size = 289470, upload-time = "2025-10-06T05:37:47.946Z" }, + { url = "https://files.pythonhosted.org/packages/ac/83/dca6dc53bf657d371fbc88ddeb21b79891e747189c5de990b9dfff2ccba1/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:eab8145831a0d56ec9c4139b6c3e594c7a83c2c8be25d5bcf2d86136a532287a", size = 289042, upload-time = "2025-10-06T05:37:49.499Z" }, + { url = "https://files.pythonhosted.org/packages/96/52/abddd34ca99be142f354398700536c5bd315880ed0a213812bc491cff5e4/frozenlist-1.8.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:974b28cf63cc99dfb2188d8d222bc6843656188164848c4f679e63dae4b0708e", size = 283148, upload-time = "2025-10-06T05:37:50.745Z" }, + { url = "https://files.pythonhosted.org/packages/af/d3/76bd4ed4317e7119c2b7f57c3f6934aba26d277acc6309f873341640e21f/frozenlist-1.8.0-cp314-cp314t-win32.whl", hash = "sha256:342c97bf697ac5480c0a7ec73cd700ecfa5a8a40ac923bd035484616efecc2df", size = 44676, upload-time = "2025-10-06T05:37:52.222Z" }, + { url = "https://files.pythonhosted.org/packages/89/76/c615883b7b521ead2944bb3480398cbb07e12b7b4e4d073d3752eb721558/frozenlist-1.8.0-cp314-cp314t-win_amd64.whl", hash = "sha256:06be8f67f39c8b1dc671f5d83aaefd3358ae5cdcf8314552c57e7ed3e6475bdd", size = 49451, upload-time = "2025-10-06T05:37:53.425Z" }, + { url = "https://files.pythonhosted.org/packages/e0/a3/5982da14e113d07b325230f95060e2169f5311b1017ea8af2a29b374c289/frozenlist-1.8.0-cp314-cp314t-win_arm64.whl", hash = "sha256:102e6314ca4da683dca92e3b1355490fed5f313b768500084fbe6371fddfdb79", size = 42507, upload-time = "2025-10-06T05:37:54.513Z" }, + { url = "https://files.pythonhosted.org/packages/9a/9a/e35b4a917281c0b8419d4207f4334c8e8c5dbf4f3f5f9ada73958d937dcc/frozenlist-1.8.0-py3-none-any.whl", hash = "sha256:0c18a16eab41e82c295618a77502e17b195883241c563b00f0aa5106fc4eaa0d", size = 13409, upload-time = "2025-10-06T05:38:16.721Z" }, +] + [[package]] name = "fsspec" version = "2026.6.0" @@ -517,6 +966,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e0/39/00bcfd94de255d24249401efff4f48d77bf6066b46447e519fa193c0c299/google_genai-2.10.0-py3-none-any.whl", hash = "sha256:d5350311567ae660c24cbc1752aee4b3d660f89c0106d2dcd2a69978c35afe1e", size = 957974, upload-time = "2026-06-24T01:33:16.296Z" }, ] +[[package]] +name = "googleapis-common-protos" +version = "1.75.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b5/c8/f439cffde755cffa462bfbb156278fa6f9d09119719af9814b858fd4f81f/googleapis_common_protos-1.75.0.tar.gz", hash = "sha256:53a062ff3c32552fbd62c11fe23768b78e4ddf0494d5e5fd97d3f4689c75fbbd", size = 151035, upload-time = "2026-05-07T08:04:49.423Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/c8/e2645aa8ed02fd4c7a2f59d68783b65b1f3cbdfe39a6308e156509d1fee8/googleapis_common_protos-1.75.0-py3-none-any.whl", hash = "sha256:961ed60399c457ceb0ee8f285a84c870aabc9c6a832b9d37bb281b5bebde43ed", size = 300631, upload-time = "2026-05-07T08:03:30.345Z" }, +] + +[[package]] +name = "greenlet" +version = "3.5.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e2/f1/fbbfef6af0bad0548f09bc28948ea3c275b4edb19e17fc5ca9900a6a634d/greenlet-3.5.3.tar.gz", hash = "sha256:a61efc018fd3eb317eeca31aba90ee9e7f26f22884a79b6c6ec715bf71bb62f1", size = 200270, upload-time = "2026-06-26T19:28:24.832Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f5/a1/1f7f0c555f5858fd2906fe9f7b0a3554fddb85cb70df7a6aaec41dc292c2/greenlet-3.5.3-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:c180d22d325fb613956b443c3c6f4406eb70e6defc70d3974da2a7b59e06f48c", size = 285838, upload-time = "2026-06-26T18:21:05.167Z" }, + { url = "https://files.pythonhosted.org/packages/0a/29/be9f43ed61677a5759b38c8a9389248133c8c731bbfc0574ecdff66c99fc/greenlet-3.5.3-cp310-cp310-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483d08c11181c83a6ce1a7a61df0f624a208ec40817a3bb2302714592eee4f04", size = 602342, upload-time = "2026-06-26T19:07:06.908Z" }, + { url = "https://files.pythonhosted.org/packages/b9/42/ba41c97ec36aa4b3ec25e5aa691d79561254805fad7f2f826dd6770587e2/greenlet-3.5.3-cp310-cp310-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1dae6e0091eae084317e411f047f0b7cb241c6db570f7c45fd6b900a274914ce", size = 615541, upload-time = "2026-06-26T19:10:04.909Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c7/28747042e1df8a9cd120a1ebe15529fc4be3b486e13e8d551ff307a82412/greenlet-3.5.3-cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9bcd2d72ccd70a1ec68ba6ef93e7fbb4420ef9997dabc7010d893bd4015e0bec", size = 615675, upload-time = "2026-06-26T18:32:14.444Z" }, + { url = "https://files.pythonhosted.org/packages/cc/a8/b85525a6c8fba9f009a5f7c8df1545de8fb0f0bf3e0179194ef4e500317f/greenlet-3.5.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:73f152c895e09907e0dbe24f6c2db37beb085cd63db91c3825a0fcd0064124a8", size = 1575057, upload-time = "2026-06-26T19:09:00.264Z" }, + { url = "https://files.pythonhosted.org/packages/03/79/fb76edb218fe6735ab0edeba176c7ab80df9618f7c02ce4208979f3ae7db/greenlet-3.5.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8bdb43e1a1d1873721acab2be99c5befd4d2044ddfd52e4d610801019880a702", size = 1641692, upload-time = "2026-06-26T18:31:41.454Z" }, + { url = "https://files.pythonhosted.org/packages/6b/79/86fe3ee50ed55d9b3907eecd3208b5c3fe8a79515519aae98b4753c3fa1d/greenlet-3.5.3-cp310-cp310-win_amd64.whl", hash = "sha256:0909f9355a9f24845d3299f3112e266a06afb68302041989fd26bd68894933db", size = 238742, upload-time = "2026-06-26T18:20:40.758Z" }, + { url = "https://files.pythonhosted.org/packages/51/58/5404031044f55afad7aad1aff8be3f22b1bed03e237cfeabbc7e5c8cfde0/greenlet-3.5.3-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:aca9b4ce85b152b5524ef7d88170efdff80dc0032aa8b75f9aaf7f3479ea95b4", size = 287424, upload-time = "2026-06-26T18:20:31.469Z" }, + { url = "https://files.pythonhosted.org/packages/b4/bf/1c65e9b94a54d547068fa5b5a8a06f221f3316b48908e08668d29c77cb50/greenlet-3.5.3-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f71be4920368fe1fabeeaa53d1e3548337e2b223d9565f8ad5e392a75ba23fc", size = 606523, upload-time = "2026-06-26T19:07:08.859Z" }, + { url = "https://files.pythonhosted.org/packages/b8/c7/b66baacc95775ad511287acb0137b95574a9ce5491902372b7564799d790/greenlet-3.5.3-cp311-cp311-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4d77e67f65f98449e3fb83f795b5d0a8437aead2f874ca89c96576caf4be3af6", size = 618315, upload-time = "2026-06-26T19:10:06.055Z" }, + { url = "https://files.pythonhosted.org/packages/78/2b/28ed29463522fdbe4c15b1f63922041626a7478316b34ab4adda3f0a4aba/greenlet-3.5.3-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8540f1e6205bd13ca0ce685581037219ca54a1b41a0a15d228c6c9b8ad5903d7", size = 617381, upload-time = "2026-06-26T18:32:16.077Z" }, + { url = "https://files.pythonhosted.org/packages/2a/7b/ad04e9d1337fc04965dc9fc616b6a72cb65a24b800a014c011ec812f5489/greenlet-3.5.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7ef56fe650f50575bf843acde967b9c567687f3c22340941a899b7bc56e956a8", size = 1577771, upload-time = "2026-06-26T19:09:01.537Z" }, + { url = "https://files.pythonhosted.org/packages/d8/33/6c87ab7ba663f70ca21f3022aad1ffe56d3f3e0521e836c2415e13abcc3c/greenlet-3.5.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5121af01cf911e70056c00d4b46d5e9b5d1415550038573d744138bacb59e6b8", size = 1644048, upload-time = "2026-06-26T18:31:42.996Z" }, + { url = "https://files.pythonhosted.org/packages/1c/35/f0d8ee998b422cf8693b270f098e55d8d4ec8006b061b333f54f177d28d9/greenlet-3.5.3-cp311-cp311-win_amd64.whl", hash = "sha256:0f41e4a05a3c0cb31b17023eff28dd111e1d16bf7d7d00406cd7df23f31398a7", size = 239137, upload-time = "2026-06-26T18:23:21.664Z" }, + { url = "https://files.pythonhosted.org/packages/fb/96/b9820295576ef18c9edc404f10e260ae7215ceaf3781a54b720ed2627862/greenlet-3.5.3-cp311-cp311-win_arm64.whl", hash = "sha256:ec6f1af59f6b5f3fc9678e2ea062d8377d22ac644f7844cb7a292910cf12ff44", size = 237630, upload-time = "2026-06-26T18:24:00.281Z" }, + { url = "https://files.pythonhosted.org/packages/5d/6e/4c37d51a2b7f82d2ff11bb6b5f7d766d9a011726624af255e843727627a3/greenlet-3.5.3-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:719757059f5a53fd0dde23f78cffeafcdd97b21c850ddb7ca684a3c1a1f122e2", size = 288685, upload-time = "2026-06-26T18:22:08.977Z" }, + { url = "https://files.pythonhosted.org/packages/7a/73/815dd90131c1b71ebdf53dbc7c276cafec2a1173b97559f97aba72724a87/greenlet-3.5.3-cp312-cp312-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:efa9f765dd09f9d0cdac651ffdf631ee59ec5dc6ee7a73e0c012ba9c52fbdf5b", size = 604761, upload-time = "2026-06-26T19:07:10.114Z" }, + { url = "https://files.pythonhosted.org/packages/9f/57/079cfe76bcef36b153b25607ee91c6fcb58f17f8b23c86bbbeabe0c88d72/greenlet-3.5.3-cp312-cp312-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7faba15ac005376e02a0384504e0243be3370ce010296a44a820feb342b505ab", size = 617044, upload-time = "2026-06-26T19:10:07.25Z" }, + { url = "https://files.pythonhosted.org/packages/37/87/b4d095775a3fb1bcafbb483fc206b27ebb785724c83051447737085dc54e/greenlet-3.5.3-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:87142215824be6ac05e2e8e2786eec307ccbc27c36723c3881959df654af6861", size = 614244, upload-time = "2026-06-26T18:32:17.594Z" }, + { url = "https://files.pythonhosted.org/packages/8a/70/7559b609683650fa2b95b8ab84b4ab0b26556a635d19675e12aa832d826d/greenlet-3.5.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:215275b1b49320987352e6c1b054acca0064f965a2c66992bed9a6f7d913f149", size = 1574210, upload-time = "2026-06-26T19:09:03.077Z" }, + { url = "https://files.pythonhosted.org/packages/ae/73/be55392074c60fc37655ca40fa6022457bfbf6718e9e342a7b0b41f96dd2/greenlet-3.5.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6b1b0eed82364b0e32c4ea0f221452d33e6bb17ae094d9f72aed9851812747ea", size = 1638627, upload-time = "2026-06-26T18:31:44.748Z" }, + { url = "https://files.pythonhosted.org/packages/14/40/c57489acf8e37d74e2913d4eff63aa0dba17acccc4bdeef874dde2dbbec9/greenlet-3.5.3-cp312-cp312-win_amd64.whl", hash = "sha256:cde8adafa2365676f74a979744629589999093bc86e2484214f58e61df08902c", size = 239882, upload-time = "2026-06-26T18:23:27.518Z" }, + { url = "https://files.pythonhosted.org/packages/71/fd/6fea0e3d6600f785069481ee637e09378dd4118acdfd38ad88ae2db31c98/greenlet-3.5.3-cp312-cp312-win_arm64.whl", hash = "sha256:c4e7b79d83805475f0102008843f6eb45fd3bb0b2e88c774adab5fbaab27117d", size = 238211, upload-time = "2026-06-26T18:22:37.671Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ff/a620267401db30a50cc8450ee90730e2d4a85658c055c0e760d4ed47fb13/greenlet-3.5.3-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:c8d87c2134d871df96ecdea9cec7cbaab286dadab0f56476e57aaf9e8ac11550", size = 287609, upload-time = "2026-06-26T18:21:14.724Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fa/5401ac78021c826a25b6dde0c705e0a8f29b617509f9185a31dac15fbe1b/greenlet-3.5.3-cp313-cp313-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a2d185dd1621757e70c3861cceffd5317ab4e7ed7eb09c82994828468527ade5", size = 607435, upload-time = "2026-06-26T19:07:11.412Z" }, + { url = "https://files.pythonhosted.org/packages/e9/76/1dc144a2e56e65d36405078ed774224375ea520a1870a6e46e08bb4ac7bf/greenlet-3.5.3-cp313-cp313-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1c514a468149bf8fbbab874188a3535cd8a48a3e353eb53a3d424296f8dbacd3", size = 619787, upload-time = "2026-06-26T19:10:08.396Z" }, + { url = "https://files.pythonhosted.org/packages/bf/87/c298cee62df1de4ad7fec32abda73526cff347fd143a6ed4ac369246668a/greenlet-3.5.3-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:915f887cf2682b66419b879423a2e072634aa7b7dce6f3ada4957cfced3f1e9a", size = 616786, upload-time = "2026-06-26T18:32:19.128Z" }, + { url = "https://files.pythonhosted.org/packages/9e/2e/e6f009885ed0705ccf33fe0583c117cfd03cde77e31a596dd5785a30762b/greenlet-3.5.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:766cfd421c13e450feb340cd472a3ed9957d438727b7b4593ad7c76c5d2b0deb", size = 1574316, upload-time = "2026-06-26T19:09:04.273Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fe/43fd110b01e40da0adb7c90ac7ea744bef2d43dca00de5095fd2351c2a68/greenlet-3.5.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2ecda9ec22edf38fa389369eaed8c3d37c05f3c54e69f69438dbb2cc1de1458b", size = 1638614, upload-time = "2026-06-26T18:31:46.297Z" }, + { url = "https://files.pythonhosted.org/packages/0f/7c/062447147a61f8b4337b156fe70d32a165fcf2f89d7ca6255e572806705c/greenlet-3.5.3-cp313-cp313-win_amd64.whl", hash = "sha256:c82304750f057167ff60d188df1d0cc1764ce9567eadf03e6a7443bcedd0b30b", size = 239850, upload-time = "2026-06-26T18:21:54.613Z" }, + { url = "https://files.pythonhosted.org/packages/c7/7e/220a7f5824a64a60443fc03b39dfac4ea63a7fb6d481efa27eafa928e7f4/greenlet-3.5.3-cp313-cp313-win_arm64.whl", hash = "sha256:dc133a1569ee667b2a6ef56ce551084aeefd87a5acbc4736d336d1e2edc6cfc4", size = 238141, upload-time = "2026-06-26T18:22:48.507Z" }, + { url = "https://files.pythonhosted.org/packages/c3/93/43e116ee114b28737ba7e12952a0d4e2f55944d0f84e42bc91ba7192a3c9/greenlet-3.5.3-cp314-cp314-macosx_11_0_universal2.whl", hash = "sha256:fd2e02fa07485778536a036222d616ab957b1d533f36b3ed98ce725d9c9d3117", size = 288202, upload-time = "2026-06-26T18:23:49.604Z" }, + { url = "https://files.pythonhosted.org/packages/82/2f/146d218299046a43d1f029fd544b3d110d0f175a09c715c7e8da4a4a345d/greenlet-3.5.3-cp314-cp314-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:df0a0628d1597eb0897b62f55d1343f772405fd25f3b2a796c76874b0c2e22e8", size = 654096, upload-time = "2026-06-26T19:07:12.71Z" }, + { url = "https://files.pythonhosted.org/packages/a0/cc/04738cafb3f45fa991ea44f9de94c47dcec964f5a972300988a6751f49d9/greenlet-3.5.3-cp314-cp314-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ebd933a6adabc298bab47731a130fe6bfb888bd934eee37810f151159544540d", size = 666304, upload-time = "2026-06-26T19:10:09.503Z" }, + { url = "https://files.pythonhosted.org/packages/ce/aa/4e0dad5e605c270c784ab911c43da6adb136ccd4d81180f763ca429a723d/greenlet-3.5.3-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4b9d501b40e80b70e32323c799dd9b420a5577a9601469d362ae1ffb690f3a7c", size = 663635, upload-time = "2026-06-26T18:32:20.802Z" }, + { url = "https://files.pythonhosted.org/packages/d1/50/13efdbea246fe3d3b735e191fec08fb50809f53cd2383ebe123d0809e44b/greenlet-3.5.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a1fad1d11e7d6aab184107baa8e4ece11ccba3ec9599cd7efa5ff4d70d43256a", size = 1621252, upload-time = "2026-06-26T19:09:05.647Z" }, + { url = "https://files.pythonhosted.org/packages/f7/22/c0a336ae4a1410fd5f5121098e5bfbf1865f64c5ef80b4b5412886c4a332/greenlet-3.5.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:fad5aec764399f1b5cc347ad250a59660f20c8f8888ea6bae1f93b769cce1154", size = 1684824, upload-time = "2026-06-26T18:31:47.738Z" }, + { url = "https://files.pythonhosted.org/packages/7a/94/91aec0030bea75c4b3244251d0de60a1f3432d1ecb53ab6c437fb5c3ba61/greenlet-3.5.3-cp314-cp314-win_amd64.whl", hash = "sha256:7669aa24cf2a1041d6f7899575b494a3ab4cf68bfcc8609b1dc0be7272db835e", size = 240754, upload-time = "2026-06-26T18:22:15.669Z" }, + { url = "https://files.pythonhosted.org/packages/e5/06/68d0983e79e02138f64b4d303c500c27ddb48e5e77f3debb80888a921eae/greenlet-3.5.3-cp314-cp314-win_arm64.whl", hash = "sha256:5b4807c4082c9d1b6d9eed56fcd041863e37f2228106eef24c30ca096e238605", size = 239549, upload-time = "2026-06-26T18:22:42.996Z" }, + { url = "https://files.pythonhosted.org/packages/91/95/3e161213d7f1d378d15aa9e792093e9bfe01844680d04b7fd6e0107c9098/greenlet-3.5.3-cp314-cp314t-macosx_11_0_universal2.whl", hash = "sha256:271a8ea7c1024e8a0d7dd2be66dd66dda8a07193f41a17b9e924f7600f5b62be", size = 296389, upload-time = "2026-06-26T18:22:20.657Z" }, + { url = "https://files.pythonhosted.org/packages/00/92/715c44721abe2b4d1ae9abde4179411868a5bff312479f54e105d372f131/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:19131729ae0ddc3c2e1ef85e650169b5e37ee32e400f215f78b94d7b0d567310", size = 653382, upload-time = "2026-06-26T19:07:14.209Z" }, + { url = "https://files.pythonhosted.org/packages/a0/83/37a10372a1090a6624cca8e74c12df1a36c2dc36429ed0255b7fb1aeee23/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1540dd8e5fc2a5aec40fbb98ef8e149fa47c89a4b4a1cf2575a14d3d1869d7a8", size = 659401, upload-time = "2026-06-26T19:10:10.876Z" }, + { url = "https://files.pythonhosted.org/packages/db/e2/d1509cad4207da559cc42986ecdd8fc67ad0d1bba2bf03023c467fd5e0f3/greenlet-3.5.3-cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e81fa194a1d20967877bdf9c7794db2bc99063e5be36aee710c08f04c5bb087f", size = 656969, upload-time = "2026-06-26T18:32:22.272Z" }, + { url = "https://files.pythonhosted.org/packages/86/7d/eaf70de20aadca3a5884aec58362861c64ce45e7b277f47ed026926a3b89/greenlet-3.5.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:55cf4d777485d43110e47133cbba6d74a8885a87ec1227ef0267f9ee80c5aa21", size = 1617822, upload-time = "2026-06-26T19:09:06.893Z" }, + { url = "https://files.pythonhosted.org/packages/8a/f9/414d38fc400ae4350d4185eaad1827676f7cf5287b9136e0ed1cbbe20a7f/greenlet-3.5.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:12a248ba75f6a9a236375f52296c498c89ff1d8badf32deb9eca7abd5853f7da", size = 1677983, upload-time = "2026-06-26T18:31:49.396Z" }, + { url = "https://files.pythonhosted.org/packages/e4/15/7edb977e08f9bff702fe42d6c902702786ff6b9694058b4e6a2a6ac90e57/greenlet-3.5.3-cp314-cp314t-win_amd64.whl", hash = "sha256:efc6bd60ea02e085862c74a3ef64b147ffc6f1a5ea7d9f26e7a939943f68c1e3", size = 243626, upload-time = "2026-06-26T18:24:41.485Z" }, + { url = "https://files.pythonhosted.org/packages/2c/8a/93928dce91e6b3598b5e779e8d1fd6576a504640c58e78627077f6a7a91a/greenlet-3.5.3-cp315-cp315-macosx_11_0_universal2.whl", hash = "sha256:ea03f2f04367845d6b58eeed276e1e56e51f0b97d8ad5a88a7d20a91dc9056cc", size = 288860, upload-time = "2026-06-26T18:22:48.07Z" }, + { url = "https://files.pythonhosted.org/packages/4f/ca/69db42d447a1378043e2c8f19c09cbbd1263371505053c496b49066d3d16/greenlet-3.5.3-cp315-cp315-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:78dbef602fda6d97d957eb7937f70c9ce9e9527330347f8f6b6f9e554a9e7a47", size = 659747, upload-time = "2026-06-26T19:07:15.565Z" }, + { url = "https://files.pythonhosted.org/packages/a8/0b/af7ac2ef8dd41e3da1a40dda6305c23b9a03e13ba975ec916357b50f8575/greenlet-3.5.3-cp315-cp315-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6f73857adb8fee13fa56c172bd11262f888c0c648f9fea113e777bb2c7904a81", size = 670419, upload-time = "2026-06-26T19:10:12.293Z" }, + { url = "https://files.pythonhosted.org/packages/51/1e/1d51640cacbfc455dbe9f9a9f594c49e4e244f63b9971a2f4764e46cc53d/greenlet-3.5.3-cp315-cp315-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:232fec92e823addaf02d9472cf7381e24a1d046a6ced1103c5caa4c21b9dfc1d", size = 668787, upload-time = "2026-06-26T18:32:24.298Z" }, + { url = "https://files.pythonhosted.org/packages/21/66/4030d5b0b5894500023f003bb054d9bb354dfbd1e186c3a296759172f5f5/greenlet-3.5.3-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:2421c3564da9429d5586d46ca31ebb26516b5498a802cf65c041a8e8a8980d34", size = 1626305, upload-time = "2026-06-26T19:09:08.281Z" }, + { url = "https://files.pythonhosted.org/packages/0e/50/5221371c7550108dfa3c378debc41d032aa9c78e89abb01d8011cfc93289/greenlet-3.5.3-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:e0f0d160f0b2e558e6c75f7930967183255dc9735e5f5b8cae58ee09c9576d8b", size = 1688631, upload-time = "2026-06-26T18:31:51.278Z" }, + { url = "https://files.pythonhosted.org/packages/68/5d/00d469daae3c65d2bf620b10eee82eb022127d483c6bc8c69fae6f3fbf17/greenlet-3.5.3-cp315-cp315-win_amd64.whl", hash = "sha256:dd99329bbc15ca78dcc583dba05d0b1b0bae01ab6c2174989f5aaee3e41ac930", size = 241027, upload-time = "2026-06-26T18:22:38.203Z" }, + { url = "https://files.pythonhosted.org/packages/e7/e8/883785b44c5780ed71e83d3e4437e710470be17a2e181e8b601e2da0dc4a/greenlet-3.5.3-cp315-cp315-win_arm64.whl", hash = "sha256:499fef2acede88c1864a57bb586b4bf533c81e1b82df7ab93451cdb47dfec227", size = 240085, upload-time = "2026-06-26T18:23:54.217Z" }, + { url = "https://files.pythonhosted.org/packages/1c/da/4f4a8450962fad137c1c8981a3f1b8919d06c829993d4d476f9c525d5173/greenlet-3.5.3-cp315-cp315t-macosx_11_0_universal2.whl", hash = "sha256:176bc16a721fa5fc294d70b87b4dfa5fbdd251b3da5d5372735ecef9bd7d6d0c", size = 297221, upload-time = "2026-06-26T18:23:27.176Z" }, + { url = "https://files.pythonhosted.org/packages/57/66/b3bfae3e220a9b63ea539a0eea681800c69ab1aada757eae8789f183e7ce/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:629b614d2b786e89c50440e246f33eea78f58a962d0bdbbcc809e6d13605903f", size = 657221, upload-time = "2026-06-26T19:07:16.973Z" }, + { url = "https://files.pythonhosted.org/packages/7b/81/b6d4d73a709684fc77e7fa034d7c2fe82cffa9fc920fadcaa659c2626213/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2b2e857ae16f5f72142edf75f9f176fe7526ba19a2841df1420516f83831c9f2", size = 663226, upload-time = "2026-06-26T19:10:13.723Z" }, + { url = "https://files.pythonhosted.org/packages/f5/07/e210b02b589f16e74ff48b730690e4a34ffe984219fce4f3c1a0e7ec8545/greenlet-3.5.3-cp315-cp315t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e515757e2e36bcbf1fad09a46e1557e8b1ae1797d4b44d09da7deed88ad28608", size = 660802, upload-time = "2026-06-26T18:32:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/eb/2e/5303eb3fa06bca089060f479707182a93e360683bc252acf846c3090d34e/greenlet-3.5.3-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:b363d46ed1ea431825fdb01471bb024fc08399bad1572a616e853c7684415adb", size = 1622157, upload-time = "2026-06-26T19:09:09.527Z" }, + { url = "https://files.pythonhosted.org/packages/54/70/50de47a488f14df260b50ae34fb5d56016e308b098eab02c878b5223c26a/greenlet-3.5.3-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:e44da2f5bbdaabaf7d80b73dbb430c7035771e9f244e3c8b769715c9d8fa0a16", size = 1681159, upload-time = "2026-06-26T18:31:52.986Z" }, + { url = "https://files.pythonhosted.org/packages/a7/13/1055e1dda7882073eda533e2b96c62e55bbd2db7fda6d5ece992febc7071/greenlet-3.5.3-cp315-cp315t-win_amd64.whl", hash = "sha256:8ff8bed3e3baa20a3ea261ce00526f1898ad4801d4886fd2220580ee0ad8fadf", size = 244007, upload-time = "2026-06-26T18:22:04.353Z" }, + { url = "https://files.pythonhosted.org/packages/b4/0d/ca7d15afbdc397e3401134c9e1800d51d12b829661786187a4ad08fe484f/greenlet-3.5.3-cp315-cp315t-win_arm64.whl", hash = "sha256:b7068bd09f761f3f5b4d214c2bed063186b2a86148c740b3873e3f56d79bac31", size = 242586, upload-time = "2026-06-26T18:23:37.93Z" }, +] + [[package]] name = "griffelib" version = "2.1.0" @@ -783,6 +1314,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7d/f5/650b59d1b74f5befb7a7a7e7d7c92a26b94256df3541e2b4914152cd177a/joserfc-1.7.3-py3-none-any.whl", hash = "sha256:7c39f3f2c943dbc03122747fa8ebbd8e156e54904cf25651b452f4d2634a6075", size = 70982, upload-time = "2026-07-08T12:41:41.521Z" }, ] +[[package]] +name = "json-repair" +version = "0.61.6" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/de/27/b34afa132d79c2a73e944d91df2141d145163e863aa9cb6db99a3956cdee/json_repair-0.61.6.tar.gz", hash = "sha256:b10cf0c1570d9eac407520d1f164bc88316692f5bf83fbe35e69c9000c3ae5bc", size = 51428, upload-time = "2026-07-19T17:35:29.252Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/74/8a/c39e1500b09241eb56a41c42bf591f72308d5a33e8755fa6156b8d514b47/json_repair-0.61.6-py3-none-any.whl", hash = "sha256:00858025b19a1a6708f1b1311b76ca6e58e5628c3ba633583dcf2bd05a66333a", size = 49951, upload-time = "2026-07-19T17:35:27.875Z" }, +] + +[[package]] +name = "json5" +version = "0.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/e4/7d/05c46a96a78147ae3bf99c2f4169ce144a70220b8d6fcd56f6ec368b8ce9/json5-0.15.0.tar.gz", hash = "sha256:7424d1f1eb1d56da6e3d70643f53619862b4ce81440bdb8ecfd6f875e5ba4a71", size = 53278, upload-time = "2026-06-19T20:08:27.716Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/eb/be/59527c99478aade6bb33a68d72e6e18dd4e6ff6eacfc7d01bdb15bc76912/json5-0.15.0-py3-none-any.whl", hash = "sha256:56636a30c0e8a4665fe2179c0212f32eae3796dea89ea6f649b9436ecdb39618", size = 36570, upload-time = "2026-06-19T20:08:26.748Z" }, +] + [[package]] name = "jsonpatch" version = "1.33" @@ -962,6 +1511,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/64/cf/41d4077d82dce88fb8f6c02938dd5937b5a74cd67bfd7bdb5206277752ca/langsmith-0.10.0-py3-none-any.whl", hash = "sha256:63aec1105b776b8c65a32b002b29ada02469cd26c91beeb2fc2831b247f4da27", size = 652557, upload-time = "2026-07-08T13:28:26.366Z" }, ] +[[package]] +name = "markdown-it-py" +version = "4.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "mdurl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz", hash = "sha256:04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49", size = 82454, upload-time = "2026-05-07T12:08:28.36Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl", hash = "sha256:9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a", size = 91687, upload-time = "2026-05-07T12:08:27.182Z" }, +] + [[package]] name = "markupsafe" version = "3.0.3" @@ -1072,6 +1633,153 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e2/5e/d118fce19f87a2e7d8101c35c8ae0ec289098a4df0ff244cec23e415aca0/mcp-1.28.1-py3-none-any.whl", hash = "sha256:2726bca5e7193f61c5dde8b12500a6de2d9acf6d1a1c0be9e8c2e706437991df", size = 222620, upload-time = "2026-06-26T12:57:27.218Z" }, ] +[[package]] +name = "mdurl" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, +] + +[[package]] +name = "multidict" +version = "6.7.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1a/c2/c2d94cbe6ac1753f3fc980da97b3d930efe1da3af3c9f5125354436c073d/multidict-6.7.1.tar.gz", hash = "sha256:ec6652a1bee61c53a3e5776b6049172c53b6aaba34f18c9ad04f82712bac623d", size = 102010, upload-time = "2026-01-26T02:46:45.979Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/84/0b/19348d4c98980c4851d2f943f8ebafdece2ae7ef737adcfa5994ce8e5f10/multidict-6.7.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:c93c3db7ea657dd4637d57e74ab73de31bccefe144d3d4ce370052035bc85fb5", size = 77176, upload-time = "2026-01-26T02:42:59.784Z" }, + { url = "https://files.pythonhosted.org/packages/ef/04/9de3f8077852e3d438215c81e9b691244532d2e05b4270e89ce67b7d103c/multidict-6.7.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:974e72a2474600827abaeda71af0c53d9ebbc3c2eb7da37b37d7829ae31232d8", size = 44996, upload-time = "2026-01-26T02:43:01.674Z" }, + { url = "https://files.pythonhosted.org/packages/31/5c/08c7f7fe311f32e83f7621cd3f99d805f45519cd06fafb247628b861da7d/multidict-6.7.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cdea2e7b2456cfb6694fb113066fd0ec7ea4d67e3a35e1f4cbeea0b448bf5872", size = 44631, upload-time = "2026-01-26T02:43:03.169Z" }, + { url = "https://files.pythonhosted.org/packages/b7/7f/0e3b1390ae772f27501199996b94b52ceeb64fe6f9120a32c6c3f6b781be/multidict-6.7.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17207077e29342fdc2c9a82e4b306f1127bf1ea91f8b71e02d4798a70bb99991", size = 242561, upload-time = "2026-01-26T02:43:04.733Z" }, + { url = "https://files.pythonhosted.org/packages/dd/f4/8719f4f167586af317b69dd3e90f913416c91ca610cac79a45c53f590312/multidict-6.7.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d4f49cb5661344764e4c7c7973e92a47a59b8fc19b6523649ec9dc4960e58a03", size = 242223, upload-time = "2026-01-26T02:43:06.695Z" }, + { url = "https://files.pythonhosted.org/packages/47/ab/7c36164cce64a6ad19c6d9a85377b7178ecf3b89f8fd589c73381a5eedfd/multidict-6.7.1-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a9fc4caa29e2e6ae408d1c450ac8bf19892c5fca83ee634ecd88a53332c59981", size = 222322, upload-time = "2026-01-26T02:43:08.472Z" }, + { url = "https://files.pythonhosted.org/packages/f5/79/a25add6fb38035b5337bc5734f296d9afc99163403bbcf56d4170f97eb62/multidict-6.7.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c5f0c21549ab432b57dcc82130f388d84ad8179824cc3f223d5e7cfbfd4143f6", size = 254005, upload-time = "2026-01-26T02:43:10.127Z" }, + { url = "https://files.pythonhosted.org/packages/4a/7b/64a87cf98e12f756fc8bd444b001232ffff2be37288f018ad0d3f0aae931/multidict-6.7.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7dfb78d966b2c906ae1d28ccf6e6712a3cd04407ee5088cd276fe8cb42186190", size = 251173, upload-time = "2026-01-26T02:43:11.731Z" }, + { url = "https://files.pythonhosted.org/packages/4b/ac/b605473de2bb404e742f2cc3583d12aedb2352a70e49ae8fce455b50c5aa/multidict-6.7.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9b0d9b91d1aa44db9c1f1ecd0d9d2ae610b2f4f856448664e01a3b35899f3f92", size = 243273, upload-time = "2026-01-26T02:43:13.063Z" }, + { url = "https://files.pythonhosted.org/packages/03/65/11492d6a0e259783720f3bc1d9ea55579a76f1407e31ed44045c99542004/multidict-6.7.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:dd96c01a9dcd4889dcfcf9eb5544ca0c77603f239e3ffab0524ec17aea9a93ee", size = 238956, upload-time = "2026-01-26T02:43:14.843Z" }, + { url = "https://files.pythonhosted.org/packages/5f/a7/7ee591302af64e7c196fb63fe856c788993c1372df765102bd0448e7e165/multidict-6.7.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:067343c68cd6612d375710f895337b3a98a033c94f14b9a99eff902f205424e2", size = 233477, upload-time = "2026-01-26T02:43:16.025Z" }, + { url = "https://files.pythonhosted.org/packages/9c/99/c109962d58756c35fd9992fed7f2355303846ea2ff054bb5f5e9d6b888de/multidict-6.7.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5884a04f4ff56c6120f6ccf703bdeb8b5079d808ba604d4d53aec0d55dc33568", size = 243615, upload-time = "2026-01-26T02:43:17.84Z" }, + { url = "https://files.pythonhosted.org/packages/d5/5f/1973e7c771c86e93dcfe1c9cc55a5481b610f6614acfc28c0d326fe6bfad/multidict-6.7.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8affcf1c98b82bc901702eb73b6947a1bfa170823c153fe8a47b5f5f02e48e40", size = 249930, upload-time = "2026-01-26T02:43:19.06Z" }, + { url = "https://files.pythonhosted.org/packages/5d/a5/f170fc2268c3243853580203378cd522446b2df632061e0a5409817854c7/multidict-6.7.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0d17522c37d03e85c8098ec8431636309b2682cf12e58f4dbc76121fb50e4962", size = 243807, upload-time = "2026-01-26T02:43:20.286Z" }, + { url = "https://files.pythonhosted.org/packages/de/01/73856fab6d125e5bc652c3986b90e8699a95e84b48d72f39ade6c0e74a8c/multidict-6.7.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:24c0cf81544ca5e17cfcb6e482e7a82cd475925242b308b890c9452a074d4505", size = 239103, upload-time = "2026-01-26T02:43:21.508Z" }, + { url = "https://files.pythonhosted.org/packages/e7/46/f1220bd9944d8aa40d8ccff100eeeee19b505b857b6f603d6078cb5315b0/multidict-6.7.1-cp310-cp310-win32.whl", hash = "sha256:d82dd730a95e6643802f4454b8fdecdf08667881a9c5670db85bc5a56693f122", size = 41416, upload-time = "2026-01-26T02:43:22.703Z" }, + { url = "https://files.pythonhosted.org/packages/68/00/9b38e272a770303692fc406c36e1a4c740f401522d5787691eb38a8925a8/multidict-6.7.1-cp310-cp310-win_amd64.whl", hash = "sha256:cf37cbe5ced48d417ba045aca1b21bafca67489452debcde94778a576666a1df", size = 46022, upload-time = "2026-01-26T02:43:23.77Z" }, + { url = "https://files.pythonhosted.org/packages/64/65/d8d42490c02ee07b6bbe00f7190d70bb4738b3cce7629aaf9f213ef730dd/multidict-6.7.1-cp310-cp310-win_arm64.whl", hash = "sha256:59bc83d3f66b41dac1e7460aac1d196edc70c9ba3094965c467715a70ecb46db", size = 43238, upload-time = "2026-01-26T02:43:24.882Z" }, + { url = "https://files.pythonhosted.org/packages/ce/f1/a90635c4f88fb913fbf4ce660b83b7445b7a02615bda034b2f8eb38fd597/multidict-6.7.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7ff981b266af91d7b4b3793ca3382e53229088d193a85dfad6f5f4c27fc73e5d", size = 76626, upload-time = "2026-01-26T02:43:26.485Z" }, + { url = "https://files.pythonhosted.org/packages/a6/9b/267e64eaf6fc637a15b35f5de31a566634a2740f97d8d094a69d34f524a4/multidict-6.7.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:844c5bca0b5444adb44a623fb0a1310c2f4cd41f402126bb269cd44c9b3f3e1e", size = 44706, upload-time = "2026-01-26T02:43:27.607Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a4/d45caf2b97b035c57267791ecfaafbd59c68212004b3842830954bb4b02e/multidict-6.7.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f2a0a924d4c2e9afcd7ec64f9de35fcd96915149b2216e1cb2c10a56df483855", size = 44356, upload-time = "2026-01-26T02:43:28.661Z" }, + { url = "https://files.pythonhosted.org/packages/fd/d2/0a36c8473f0cbaeadd5db6c8b72d15bbceeec275807772bfcd059bef487d/multidict-6.7.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:8be1802715a8e892c784c0197c2ace276ea52702a0ede98b6310c8f255a5afb3", size = 244355, upload-time = "2026-01-26T02:43:31.165Z" }, + { url = "https://files.pythonhosted.org/packages/5d/16/8c65be997fd7dd311b7d39c7b6e71a0cb449bad093761481eccbbe4b42a2/multidict-6.7.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2e2d2ed645ea29f31c4c7ea1552fcfd7cb7ba656e1eafd4134a6620c9f5fdd9e", size = 246433, upload-time = "2026-01-26T02:43:32.581Z" }, + { url = "https://files.pythonhosted.org/packages/01/fb/4dbd7e848d2799c6a026ec88ad39cf2b8416aa167fcc903baa55ecaa045c/multidict-6.7.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:95922cee9a778659e91db6497596435777bd25ed116701a4c034f8e46544955a", size = 225376, upload-time = "2026-01-26T02:43:34.417Z" }, + { url = "https://files.pythonhosted.org/packages/b6/8a/4a3a6341eac3830f6053062f8fbc9a9e54407c80755b3f05bc427295c2d0/multidict-6.7.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6b83cabdc375ffaaa15edd97eb7c0c672ad788e2687004990074d7d6c9b140c8", size = 257365, upload-time = "2026-01-26T02:43:35.741Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a2/dd575a69c1aa206e12d27d0770cdf9b92434b48a9ef0cd0d1afdecaa93c4/multidict-6.7.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:38fb49540705369bab8484db0689d86c0a33a0a9f2c1b197f506b71b4b6c19b0", size = 254747, upload-time = "2026-01-26T02:43:36.976Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/21b27c560c13822ed93133f08aa6372c53a8e067f11fbed37b4adcdac922/multidict-6.7.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:439cbebd499f92e9aa6793016a8acaa161dfa749ae86d20960189f5398a19144", size = 246293, upload-time = "2026-01-26T02:43:38.258Z" }, + { url = "https://files.pythonhosted.org/packages/5a/a4/23466059dc3854763423d0ad6c0f3683a379d97673b1b89ec33826e46728/multidict-6.7.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6d3bc717b6fe763b8be3f2bee2701d3c8eb1b2a8ae9f60910f1b2860c82b6c49", size = 242962, upload-time = "2026-01-26T02:43:40.034Z" }, + { url = "https://files.pythonhosted.org/packages/1f/67/51dd754a3524d685958001e8fa20a0f5f90a6a856e0a9dcabff69be3dbb7/multidict-6.7.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:619e5a1ac57986dbfec9f0b301d865dddf763696435e2962f6d9cf2fdff2bb71", size = 237360, upload-time = "2026-01-26T02:43:41.752Z" }, + { url = "https://files.pythonhosted.org/packages/64/3f/036dfc8c174934d4b55d86ff4f978e558b0e585cef70cfc1ad01adc6bf18/multidict-6.7.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0b38ebffd9be37c1170d33bc0f36f4f262e0a09bc1aac1c34c7aa51a7293f0b3", size = 245940, upload-time = "2026-01-26T02:43:43.042Z" }, + { url = "https://files.pythonhosted.org/packages/3d/20/6214d3c105928ebc353a1c644a6ef1408bc5794fcb4f170bb524a3c16311/multidict-6.7.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:10ae39c9cfe6adedcdb764f5e8411d4a92b055e35573a2eaa88d3323289ef93c", size = 253502, upload-time = "2026-01-26T02:43:44.371Z" }, + { url = "https://files.pythonhosted.org/packages/b1/e2/c653bc4ae1be70a0f836b82172d643fcf1dade042ba2676ab08ec08bff0f/multidict-6.7.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:25167cc263257660290fba06b9318d2026e3c910be240a146e1f66dd114af2b0", size = 247065, upload-time = "2026-01-26T02:43:45.745Z" }, + { url = "https://files.pythonhosted.org/packages/c8/11/a854b4154cd3bd8b1fd375e8a8ca9d73be37610c361543d56f764109509b/multidict-6.7.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:128441d052254f42989ef98b7b6a6ecb1e6f708aa962c7984235316db59f50fa", size = 241870, upload-time = "2026-01-26T02:43:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/13/bf/9676c0392309b5fdae322333d22a829715b570edb9baa8016a517b55b558/multidict-6.7.1-cp311-cp311-win32.whl", hash = "sha256:d62b7f64ffde3b99d06b707a280db04fb3855b55f5a06df387236051d0668f4a", size = 41302, upload-time = "2026-01-26T02:43:48.753Z" }, + { url = "https://files.pythonhosted.org/packages/c9/68/f16a3a8ba6f7b6dc92a1f19669c0810bd2c43fc5a02da13b1cbf8e253845/multidict-6.7.1-cp311-cp311-win_amd64.whl", hash = "sha256:bdbf9f3b332abd0cdb306e7c2113818ab1e922dc84b8f8fd06ec89ed2a19ab8b", size = 45981, upload-time = "2026-01-26T02:43:49.921Z" }, + { url = "https://files.pythonhosted.org/packages/ac/ad/9dd5305253fa00cd3c7555dbef69d5bf4133debc53b87ab8d6a44d411665/multidict-6.7.1-cp311-cp311-win_arm64.whl", hash = "sha256:b8c990b037d2fff2f4e33d3f21b9b531c5745b33a49a7d6dbe7a177266af44f6", size = 43159, upload-time = "2026-01-26T02:43:51.635Z" }, + { url = "https://files.pythonhosted.org/packages/8d/9c/f20e0e2cf80e4b2e4b1c365bf5fe104ee633c751a724246262db8f1a0b13/multidict-6.7.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a90f75c956e32891a4eda3639ce6dd86e87105271f43d43442a3aedf3cddf172", size = 76893, upload-time = "2026-01-26T02:43:52.754Z" }, + { url = "https://files.pythonhosted.org/packages/fe/cf/18ef143a81610136d3da8193da9d80bfe1cb548a1e2d1c775f26b23d024a/multidict-6.7.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3fccb473e87eaa1382689053e4a4618e7ba7b9b9b8d6adf2027ee474597128cd", size = 45456, upload-time = "2026-01-26T02:43:53.893Z" }, + { url = "https://files.pythonhosted.org/packages/a9/65/1caac9d4cd32e8433908683446eebc953e82d22b03d10d41a5f0fefe991b/multidict-6.7.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0fa96985700739c4c7853a43c0b3e169360d6855780021bfc6d0f1ce7c123e7", size = 43872, upload-time = "2026-01-26T02:43:55.041Z" }, + { url = "https://files.pythonhosted.org/packages/cf/3b/d6bd75dc4f3ff7c73766e04e705b00ed6dbbaccf670d9e05a12b006f5a21/multidict-6.7.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:cb2a55f408c3043e42b40cc8eecd575afa27b7e0b956dfb190de0f8499a57a53", size = 251018, upload-time = "2026-01-26T02:43:56.198Z" }, + { url = "https://files.pythonhosted.org/packages/fd/80/c959c5933adedb9ac15152e4067c702a808ea183a8b64cf8f31af8ad3155/multidict-6.7.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb0ce7b2a32d09892b3dd6cc44877a0d02a33241fafca5f25c8b6b62374f8b75", size = 258883, upload-time = "2026-01-26T02:43:57.499Z" }, + { url = "https://files.pythonhosted.org/packages/86/85/7ed40adafea3d4f1c8b916e3b5cc3a8e07dfcdcb9cd72800f4ed3ca1b387/multidict-6.7.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c3a32d23520ee37bf327d1e1a656fec76a2edd5c038bf43eddfa0572ec49c60b", size = 242413, upload-time = "2026-01-26T02:43:58.755Z" }, + { url = "https://files.pythonhosted.org/packages/d2/57/b8565ff533e48595503c785f8361ff9a4fde4d67de25c207cd0ba3befd03/multidict-6.7.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9c90fed18bffc0189ba814749fdcc102b536e83a9f738a9003e569acd540a733", size = 268404, upload-time = "2026-01-26T02:44:00.216Z" }, + { url = "https://files.pythonhosted.org/packages/e0/50/9810c5c29350f7258180dfdcb2e52783a0632862eb334c4896ac717cebcb/multidict-6.7.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da62917e6076f512daccfbbde27f46fed1c98fee202f0559adec8ee0de67f71a", size = 269456, upload-time = "2026-01-26T02:44:02.202Z" }, + { url = "https://files.pythonhosted.org/packages/f3/8d/5e5be3ced1d12966fefb5c4ea3b2a5b480afcea36406559442c6e31d4a48/multidict-6.7.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bfde23ef6ed9db7eaee6c37dcec08524cb43903c60b285b172b6c094711b3961", size = 256322, upload-time = "2026-01-26T02:44:03.56Z" }, + { url = "https://files.pythonhosted.org/packages/31/6e/d8a26d81ac166a5592782d208dd90dfdc0a7a218adaa52b45a672b46c122/multidict-6.7.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3758692429e4e32f1ba0df23219cd0b4fc0a52f476726fff9337d1a57676a582", size = 253955, upload-time = "2026-01-26T02:44:04.845Z" }, + { url = "https://files.pythonhosted.org/packages/59/4c/7c672c8aad41534ba619bcd4ade7a0dc87ed6b8b5c06149b85d3dd03f0cd/multidict-6.7.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:398c1478926eca669f2fd6a5856b6de9c0acf23a2cb59a14c0ba5844fa38077e", size = 251254, upload-time = "2026-01-26T02:44:06.133Z" }, + { url = "https://files.pythonhosted.org/packages/7b/bd/84c24de512cbafbdbc39439f74e967f19570ce7924e3007174a29c348916/multidict-6.7.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:c102791b1c4f3ab36ce4101154549105a53dc828f016356b3e3bcae2e3a039d3", size = 252059, upload-time = "2026-01-26T02:44:07.518Z" }, + { url = "https://files.pythonhosted.org/packages/fa/ba/f5449385510825b73d01c2d4087bf6d2fccc20a2d42ac34df93191d3dd03/multidict-6.7.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a088b62bd733e2ad12c50dad01b7d0166c30287c166e137433d3b410add807a6", size = 263588, upload-time = "2026-01-26T02:44:09.382Z" }, + { url = "https://files.pythonhosted.org/packages/d7/11/afc7c677f68f75c84a69fe37184f0f82fce13ce4b92f49f3db280b7e92b3/multidict-6.7.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:3d51ff4785d58d3f6c91bdbffcb5e1f7ddfda557727043aa20d20ec4f65e324a", size = 259642, upload-time = "2026-01-26T02:44:10.73Z" }, + { url = "https://files.pythonhosted.org/packages/2b/17/ebb9644da78c4ab36403739e0e6e0e30ebb135b9caf3440825001a0bddcb/multidict-6.7.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc5907494fccf3e7d3f94f95c91d6336b092b5fc83811720fae5e2765890dfba", size = 251377, upload-time = "2026-01-26T02:44:12.042Z" }, + { url = "https://files.pythonhosted.org/packages/ca/a4/840f5b97339e27846c46307f2530a2805d9d537d8b8bd416af031cad7fa0/multidict-6.7.1-cp312-cp312-win32.whl", hash = "sha256:28ca5ce2fd9716631133d0e9a9b9a745ad7f60bac2bccafb56aa380fc0b6c511", size = 41887, upload-time = "2026-01-26T02:44:14.245Z" }, + { url = "https://files.pythonhosted.org/packages/80/31/0b2517913687895f5904325c2069d6a3b78f66cc641a86a2baf75a05dcbb/multidict-6.7.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcee94dfbd638784645b066074b338bc9cc155d4b4bffa4adce1615c5a426c19", size = 46053, upload-time = "2026-01-26T02:44:15.371Z" }, + { url = "https://files.pythonhosted.org/packages/0c/5b/aba28e4ee4006ae4c7df8d327d31025d760ffa992ea23812a601d226e682/multidict-6.7.1-cp312-cp312-win_arm64.whl", hash = "sha256:ba0a9fb644d0c1a2194cf7ffb043bd852cea63a57f66fbd33959f7dae18517bf", size = 43307, upload-time = "2026-01-26T02:44:16.852Z" }, + { url = "https://files.pythonhosted.org/packages/f2/22/929c141d6c0dba87d3e1d38fbdf1ba8baba86b7776469f2bc2d3227a1e67/multidict-6.7.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:2b41f5fed0ed563624f1c17630cb9941cf2309d4df00e494b551b5f3e3d67a23", size = 76174, upload-time = "2026-01-26T02:44:18.509Z" }, + { url = "https://files.pythonhosted.org/packages/c7/75/bc704ae15fee974f8fccd871305e254754167dce5f9e42d88a2def741a1d/multidict-6.7.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:84e61e3af5463c19b67ced91f6c634effb89ef8bfc5ca0267f954451ed4bb6a2", size = 45116, upload-time = "2026-01-26T02:44:19.745Z" }, + { url = "https://files.pythonhosted.org/packages/79/76/55cd7186f498ed080a18440c9013011eb548f77ae1b297206d030eb1180a/multidict-6.7.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:935434b9853c7c112eee7ac891bc4cb86455aa631269ae35442cb316790c1445", size = 43524, upload-time = "2026-01-26T02:44:21.571Z" }, + { url = "https://files.pythonhosted.org/packages/e9/3c/414842ef8d5a1628d68edee29ba0e5bcf235dbfb3ccd3ea303a7fe8c72ff/multidict-6.7.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:432feb25a1cb67fe82a9680b4d65fb542e4635cb3166cd9c01560651ad60f177", size = 249368, upload-time = "2026-01-26T02:44:22.803Z" }, + { url = "https://files.pythonhosted.org/packages/f6/32/befed7f74c458b4a525e60519fe8d87eef72bb1e99924fa2b0f9d97a221e/multidict-6.7.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e82d14e3c948952a1a85503817e038cba5905a3352de76b9a465075d072fba23", size = 256952, upload-time = "2026-01-26T02:44:24.306Z" }, + { url = "https://files.pythonhosted.org/packages/03/d6/c878a44ba877f366630c860fdf74bfb203c33778f12b6ac274936853c451/multidict-6.7.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4cfb48c6ea66c83bcaaf7e4dfa7ec1b6bbcf751b7db85a328902796dfde4c060", size = 240317, upload-time = "2026-01-26T02:44:25.772Z" }, + { url = "https://files.pythonhosted.org/packages/68/49/57421b4d7ad2e9e60e25922b08ceb37e077b90444bde6ead629095327a6f/multidict-6.7.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d540e51b7e8e170174555edecddbd5538105443754539193e3e1061864d444d", size = 267132, upload-time = "2026-01-26T02:44:27.648Z" }, + { url = "https://files.pythonhosted.org/packages/b7/fe/ec0edd52ddbcea2a2e89e174f0206444a61440b40f39704e64dc807a70bd/multidict-6.7.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:273d23f4b40f3dce4d6c8a821c741a86dec62cded82e1175ba3d99be128147ed", size = 268140, upload-time = "2026-01-26T02:44:29.588Z" }, + { url = "https://files.pythonhosted.org/packages/b0/73/6e1b01cbeb458807aa0831742232dbdd1fa92bfa33f52a3f176b4ff3dc11/multidict-6.7.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9d624335fd4fa1c08a53f8b4be7676ebde19cd092b3895c421045ca87895b429", size = 254277, upload-time = "2026-01-26T02:44:30.902Z" }, + { url = "https://files.pythonhosted.org/packages/6a/b2/5fb8c124d7561a4974c342bc8c778b471ebbeb3cc17df696f034a7e9afe7/multidict-6.7.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:12fad252f8b267cc75b66e8fc51b3079604e8d43a75428ffe193cd9e2195dfd6", size = 252291, upload-time = "2026-01-26T02:44:32.31Z" }, + { url = "https://files.pythonhosted.org/packages/5a/96/51d4e4e06bcce92577fcd488e22600bd38e4fd59c20cb49434d054903bd2/multidict-6.7.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:03ede2a6ffbe8ef936b92cb4529f27f42be7f56afcdab5ab739cd5f27fb1cbf9", size = 250156, upload-time = "2026-01-26T02:44:33.734Z" }, + { url = "https://files.pythonhosted.org/packages/db/6b/420e173eec5fba721a50e2a9f89eda89d9c98fded1124f8d5c675f7a0c0f/multidict-6.7.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:90efbcf47dbe33dcf643a1e400d67d59abeac5db07dc3f27d6bdeae497a2198c", size = 249742, upload-time = "2026-01-26T02:44:35.222Z" }, + { url = "https://files.pythonhosted.org/packages/44/a3/ec5b5bd98f306bc2aa297b8c6f11a46714a56b1e6ef5ebda50a4f5d7c5fb/multidict-6.7.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5c4b9bfc148f5a91be9244d6264c53035c8a0dcd2f51f1c3c6e30e30ebaa1c84", size = 262221, upload-time = "2026-01-26T02:44:36.604Z" }, + { url = "https://files.pythonhosted.org/packages/cd/f7/e8c0d0da0cd1e28d10e624604e1a36bcc3353aaebdfdc3a43c72bc683a12/multidict-6.7.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:401c5a650f3add2472d1d288c26deebc540f99e2fb83e9525007a74cd2116f1d", size = 258664, upload-time = "2026-01-26T02:44:38.008Z" }, + { url = "https://files.pythonhosted.org/packages/52/da/151a44e8016dd33feed44f730bd856a66257c1ee7aed4f44b649fb7edeb3/multidict-6.7.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:97891f3b1b3ffbded884e2916cacf3c6fc87b66bb0dde46f7357404750559f33", size = 249490, upload-time = "2026-01-26T02:44:39.386Z" }, + { url = "https://files.pythonhosted.org/packages/87/af/a3b86bf9630b732897f6fc3f4c4714b90aa4361983ccbdcd6c0339b21b0c/multidict-6.7.1-cp313-cp313-win32.whl", hash = "sha256:e1c5988359516095535c4301af38d8a8838534158f649c05dd1050222321bcb3", size = 41695, upload-time = "2026-01-26T02:44:41.318Z" }, + { url = "https://files.pythonhosted.org/packages/b2/35/e994121b0e90e46134673422dd564623f93304614f5d11886b1b3e06f503/multidict-6.7.1-cp313-cp313-win_amd64.whl", hash = "sha256:960c83bf01a95b12b08fd54324a4eb1d5b52c88932b5cba5d6e712bb3ed12eb5", size = 45884, upload-time = "2026-01-26T02:44:42.488Z" }, + { url = "https://files.pythonhosted.org/packages/ca/61/42d3e5dbf661242a69c97ea363f2d7b46c567da8eadef8890022be6e2ab0/multidict-6.7.1-cp313-cp313-win_arm64.whl", hash = "sha256:563fe25c678aaba333d5399408f5ec3c383ca5b663e7f774dd179a520b8144df", size = 43122, upload-time = "2026-01-26T02:44:43.664Z" }, + { url = "https://files.pythonhosted.org/packages/6d/b3/e6b21c6c4f314bb956016b0b3ef2162590a529b84cb831c257519e7fde44/multidict-6.7.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:c76c4bec1538375dad9d452d246ca5368ad6e1c9039dadcf007ae59c70619ea1", size = 83175, upload-time = "2026-01-26T02:44:44.894Z" }, + { url = "https://files.pythonhosted.org/packages/fb/76/23ecd2abfe0957b234f6c960f4ade497f55f2c16aeb684d4ecdbf1c95791/multidict-6.7.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:57b46b24b5d5ebcc978da4ec23a819a9402b4228b8a90d9c656422b4bdd8a963", size = 48460, upload-time = "2026-01-26T02:44:46.106Z" }, + { url = "https://files.pythonhosted.org/packages/c4/57/a0ed92b23f3a042c36bc4227b72b97eca803f5f1801c1ab77c8a212d455e/multidict-6.7.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e954b24433c768ce78ab7929e84ccf3422e46deb45a4dc9f93438f8217fa2d34", size = 46930, upload-time = "2026-01-26T02:44:47.278Z" }, + { url = "https://files.pythonhosted.org/packages/b5/66/02ec7ace29162e447f6382c495dc95826bf931d3818799bbef11e8f7df1a/multidict-6.7.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3bd231490fa7217cc832528e1cd8752a96f0125ddd2b5749390f7c3ec8721b65", size = 242582, upload-time = "2026-01-26T02:44:48.604Z" }, + { url = "https://files.pythonhosted.org/packages/58/18/64f5a795e7677670e872673aca234162514696274597b3708b2c0d276cce/multidict-6.7.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:253282d70d67885a15c8a7716f3a73edf2d635793ceda8173b9ecc21f2fb8292", size = 250031, upload-time = "2026-01-26T02:44:50.544Z" }, + { url = "https://files.pythonhosted.org/packages/c8/ed/e192291dbbe51a8290c5686f482084d31bcd9d09af24f63358c3d42fd284/multidict-6.7.1-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b4c48648d7649c9335cf1927a8b87fa692de3dcb15faa676c6a6f1f1aabda43", size = 228596, upload-time = "2026-01-26T02:44:51.951Z" }, + { url = "https://files.pythonhosted.org/packages/1e/7e/3562a15a60cf747397e7f2180b0a11dc0c38d9175a650e75fa1b4d325e15/multidict-6.7.1-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:98bc624954ec4d2c7cb074b8eefc2b5d0ce7d482e410df446414355d158fe4ca", size = 257492, upload-time = "2026-01-26T02:44:53.902Z" }, + { url = "https://files.pythonhosted.org/packages/24/02/7d0f9eae92b5249bb50ac1595b295f10e263dd0078ebb55115c31e0eaccd/multidict-6.7.1-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1b99af4d9eec0b49927b4402bcbb58dea89d3e0db8806a4086117019939ad3dd", size = 255899, upload-time = "2026-01-26T02:44:55.316Z" }, + { url = "https://files.pythonhosted.org/packages/00/e3/9b60ed9e23e64c73a5cde95269ef1330678e9c6e34dd4eb6b431b85b5a10/multidict-6.7.1-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6aac4f16b472d5b7dc6f66a0d49dd57b0e0902090be16594dc9ebfd3d17c47e7", size = 247970, upload-time = "2026-01-26T02:44:56.783Z" }, + { url = "https://files.pythonhosted.org/packages/3e/06/538e58a63ed5cfb0bd4517e346b91da32fde409d839720f664e9a4ae4f9d/multidict-6.7.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:21f830fe223215dffd51f538e78c172ed7c7f60c9b96a2bf05c4848ad49921c3", size = 245060, upload-time = "2026-01-26T02:44:58.195Z" }, + { url = "https://files.pythonhosted.org/packages/b2/2f/d743a3045a97c895d401e9bd29aaa09b94f5cbdf1bd561609e5a6c431c70/multidict-6.7.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:f5dd81c45b05518b9aa4da4aa74e1c93d715efa234fd3e8a179df611cc85e5f4", size = 235888, upload-time = "2026-01-26T02:44:59.57Z" }, + { url = "https://files.pythonhosted.org/packages/38/83/5a325cac191ab28b63c52f14f1131f3b0a55ba3b9aa65a6d0bf2a9b921a0/multidict-6.7.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:eb304767bca2bb92fb9c5bd33cedc95baee5bb5f6c88e63706533a1c06ad08c8", size = 243554, upload-time = "2026-01-26T02:45:01.054Z" }, + { url = "https://files.pythonhosted.org/packages/20/1f/9d2327086bd15da2725ef6aae624208e2ef828ed99892b17f60c344e57ed/multidict-6.7.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c9035dde0f916702850ef66460bc4239d89d08df4d02023a5926e7446724212c", size = 252341, upload-time = "2026-01-26T02:45:02.484Z" }, + { url = "https://files.pythonhosted.org/packages/e8/2c/2a1aa0280cf579d0f6eed8ee5211c4f1730bd7e06c636ba2ee6aafda302e/multidict-6.7.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:af959b9beeb66c822380f222f0e0a1889331597e81f1ded7f374f3ecb0fd6c52", size = 246391, upload-time = "2026-01-26T02:45:03.862Z" }, + { url = "https://files.pythonhosted.org/packages/e5/03/7ca022ffc36c5a3f6e03b179a5ceb829be9da5783e6fe395f347c0794680/multidict-6.7.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:41f2952231456154ee479651491e94118229844dd7226541788be783be2b5108", size = 243422, upload-time = "2026-01-26T02:45:05.296Z" }, + { url = "https://files.pythonhosted.org/packages/dc/1d/b31650eab6c5778aceed46ba735bd97f7c7d2f54b319fa916c0f96e7805b/multidict-6.7.1-cp313-cp313t-win32.whl", hash = "sha256:df9f19c28adcb40b6aae30bbaa1478c389efd50c28d541d76760199fc1037c32", size = 47770, upload-time = "2026-01-26T02:45:06.754Z" }, + { url = "https://files.pythonhosted.org/packages/ac/5b/2d2d1d522e51285bd61b1e20df8f47ae1a9d80839db0b24ea783b3832832/multidict-6.7.1-cp313-cp313t-win_amd64.whl", hash = "sha256:d54ecf9f301853f2c5e802da559604b3e95bb7a3b01a9c295c6ee591b9882de8", size = 53109, upload-time = "2026-01-26T02:45:08.044Z" }, + { url = "https://files.pythonhosted.org/packages/3d/a3/cc409ba012c83ca024a308516703cf339bdc4b696195644a7215a5164a24/multidict-6.7.1-cp313-cp313t-win_arm64.whl", hash = "sha256:5a37ca18e360377cfda1d62f5f382ff41f2b8c4ccb329ed974cc2e1643440118", size = 45573, upload-time = "2026-01-26T02:45:09.349Z" }, + { url = "https://files.pythonhosted.org/packages/91/cc/db74228a8be41884a567e88a62fd589a913708fcf180d029898c17a9a371/multidict-6.7.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:8f333ec9c5eb1b7105e3b84b53141e66ca05a19a605368c55450b6ba208cb9ee", size = 75190, upload-time = "2026-01-26T02:45:10.651Z" }, + { url = "https://files.pythonhosted.org/packages/d5/22/492f2246bb5b534abd44804292e81eeaf835388901f0c574bac4eeec73c5/multidict-6.7.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:a407f13c188f804c759fc6a9f88286a565c242a76b27626594c133b82883b5c2", size = 44486, upload-time = "2026-01-26T02:45:11.938Z" }, + { url = "https://files.pythonhosted.org/packages/f1/4f/733c48f270565d78b4544f2baddc2fb2a245e5a8640254b12c36ac7ac68e/multidict-6.7.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0e161ddf326db5577c3a4cc2d8648f81456e8a20d40415541587a71620d7a7d1", size = 43219, upload-time = "2026-01-26T02:45:14.346Z" }, + { url = "https://files.pythonhosted.org/packages/24/bb/2c0c2287963f4259c85e8bcbba9182ced8d7fca65c780c38e99e61629d11/multidict-6.7.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:1e3a8bb24342a8201d178c3b4984c26ba81a577c80d4d525727427460a50c22d", size = 245132, upload-time = "2026-01-26T02:45:15.712Z" }, + { url = "https://files.pythonhosted.org/packages/a7/f9/44d4b3064c65079d2467888794dea218d1601898ac50222ab8a9a8094460/multidict-6.7.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:97231140a50f5d447d3164f994b86a0bed7cd016e2682f8650d6a9158e14fd31", size = 252420, upload-time = "2026-01-26T02:45:17.293Z" }, + { url = "https://files.pythonhosted.org/packages/8b/13/78f7275e73fa17b24c9a51b0bd9d73ba64bb32d0ed51b02a746eb876abe7/multidict-6.7.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6b10359683bd8806a200fd2909e7c8ca3a7b24ec1d8132e483d58e791d881048", size = 233510, upload-time = "2026-01-26T02:45:19.356Z" }, + { url = "https://files.pythonhosted.org/packages/4b/25/8167187f62ae3cbd52da7893f58cb036b47ea3fb67138787c76800158982/multidict-6.7.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:283ddac99f7ac25a4acadbf004cb5ae34480bbeb063520f70ce397b281859362", size = 264094, upload-time = "2026-01-26T02:45:20.834Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e7/69a3a83b7b030cf283fb06ce074a05a02322359783424d7edf0f15fe5022/multidict-6.7.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:538cec1e18c067d0e6103aa9a74f9e832904c957adc260e61cd9d8cf0c3b3d37", size = 260786, upload-time = "2026-01-26T02:45:22.818Z" }, + { url = "https://files.pythonhosted.org/packages/fe/3b/8ec5074bcfc450fe84273713b4b0a0dd47c0249358f5d82eb8104ffe2520/multidict-6.7.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7eee46ccb30ff48a1e35bb818cc90846c6be2b68240e42a78599166722cea709", size = 248483, upload-time = "2026-01-26T02:45:24.368Z" }, + { url = "https://files.pythonhosted.org/packages/48/5a/d5a99e3acbca0e29c5d9cba8f92ceb15dce78bab963b308ae692981e3a5d/multidict-6.7.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa263a02f4f2dd2d11a7b1bb4362aa7cb1049f84a9235d31adf63f30143469a0", size = 248403, upload-time = "2026-01-26T02:45:25.982Z" }, + { url = "https://files.pythonhosted.org/packages/35/48/e58cd31f6c7d5102f2a4bf89f96b9cf7e00b6c6f3d04ecc44417c00a5a3c/multidict-6.7.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:2e1425e2f99ec5bd36c15a01b690a1a2456209c5deed58f95469ffb46039ccbb", size = 240315, upload-time = "2026-01-26T02:45:27.487Z" }, + { url = "https://files.pythonhosted.org/packages/94/33/1cd210229559cb90b6786c30676bb0c58249ff42f942765f88793b41fdce/multidict-6.7.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:497394b3239fc6f0e13a78a3e1b61296e72bf1c5f94b4c4eb80b265c37a131cd", size = 245528, upload-time = "2026-01-26T02:45:28.991Z" }, + { url = "https://files.pythonhosted.org/packages/64/f2/6e1107d226278c876c783056b7db43d800bb64c6131cec9c8dfb6903698e/multidict-6.7.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:233b398c29d3f1b9676b4b6f75c518a06fcb2ea0b925119fb2c1bc35c05e1601", size = 258784, upload-time = "2026-01-26T02:45:30.503Z" }, + { url = "https://files.pythonhosted.org/packages/4d/c1/11f664f14d525e4a1b5327a82d4de61a1db604ab34c6603bb3c2cc63ad34/multidict-6.7.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:93b1818e4a6e0930454f0f2af7dfce69307ca03cdcfb3739bf4d91241967b6c1", size = 251980, upload-time = "2026-01-26T02:45:32.603Z" }, + { url = "https://files.pythonhosted.org/packages/e1/9f/75a9ac888121d0c5bbd4ecf4eead45668b1766f6baabfb3b7f66a410e231/multidict-6.7.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f33dc2a3abe9249ea5d8360f969ec7f4142e7ac45ee7014d8f8d5acddf178b7b", size = 243602, upload-time = "2026-01-26T02:45:34.043Z" }, + { url = "https://files.pythonhosted.org/packages/9a/e7/50bf7b004cc8525d80dbbbedfdc7aed3e4c323810890be4413e589074032/multidict-6.7.1-cp314-cp314-win32.whl", hash = "sha256:3ab8b9d8b75aef9df299595d5388b14530839f6422333357af1339443cff777d", size = 40930, upload-time = "2026-01-26T02:45:36.278Z" }, + { url = "https://files.pythonhosted.org/packages/e0/bf/52f25716bbe93745595800f36fb17b73711f14da59ed0bb2eba141bc9f0f/multidict-6.7.1-cp314-cp314-win_amd64.whl", hash = "sha256:5e01429a929600e7dab7b166062d9bb54a5eed752384c7384c968c2afab8f50f", size = 45074, upload-time = "2026-01-26T02:45:37.546Z" }, + { url = "https://files.pythonhosted.org/packages/97/ab/22803b03285fa3a525f48217963da3a65ae40f6a1b6f6cf2768879e208f9/multidict-6.7.1-cp314-cp314-win_arm64.whl", hash = "sha256:4885cb0e817aef5d00a2e8451d4665c1808378dc27c2705f1bf4ef8505c0d2e5", size = 42471, upload-time = "2026-01-26T02:45:38.889Z" }, + { url = "https://files.pythonhosted.org/packages/e0/6d/f9293baa6146ba9507e360ea0292b6422b016907c393e2f63fc40ab7b7b5/multidict-6.7.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0458c978acd8e6ea53c81eefaddbbee9c6c5e591f41b3f5e8e194780fe026581", size = 82401, upload-time = "2026-01-26T02:45:40.254Z" }, + { url = "https://files.pythonhosted.org/packages/7a/68/53b5494738d83558d87c3c71a486504d8373421c3e0dbb6d0db48ad42ee0/multidict-6.7.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:c0abd12629b0af3cf590982c0b413b1e7395cd4ec026f30986818ab95bfaa94a", size = 48143, upload-time = "2026-01-26T02:45:41.635Z" }, + { url = "https://files.pythonhosted.org/packages/37/e8/5284c53310dcdc99ce5d66563f6e5773531a9b9fe9ec7a615e9bc306b05f/multidict-6.7.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:14525a5f61d7d0c94b368a42cff4c9a4e7ba2d52e2672a7b23d84dc86fb02b0c", size = 46507, upload-time = "2026-01-26T02:45:42.99Z" }, + { url = "https://files.pythonhosted.org/packages/e4/fc/6800d0e5b3875568b4083ecf5f310dcf91d86d52573160834fb4bfcf5e4f/multidict-6.7.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:17307b22c217b4cf05033dabefe68255a534d637c6c9b0cc8382718f87be4262", size = 239358, upload-time = "2026-01-26T02:45:44.376Z" }, + { url = "https://files.pythonhosted.org/packages/41/75/4ad0973179361cdf3a113905e6e088173198349131be2b390f9fa4da5fc6/multidict-6.7.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a7e590ff876a3eaf1c02a4dfe0724b6e69a9e9de6d8f556816f29c496046e59", size = 246884, upload-time = "2026-01-26T02:45:47.167Z" }, + { url = "https://files.pythonhosted.org/packages/c3/9c/095bb28b5da139bd41fb9a5d5caff412584f377914bd8787c2aa98717130/multidict-6.7.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5fa6a95dfee63893d80a34758cd0e0c118a30b8dcb46372bf75106c591b77889", size = 225878, upload-time = "2026-01-26T02:45:48.698Z" }, + { url = "https://files.pythonhosted.org/packages/07/d0/c0a72000243756e8f5a277b6b514fa005f2c73d481b7d9e47cd4568aa2e4/multidict-6.7.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a0543217a6a017692aa6ae5cc39adb75e587af0f3a82288b1492eb73dd6cc2a4", size = 253542, upload-time = "2026-01-26T02:45:50.164Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6b/f69da15289e384ecf2a68837ec8b5ad8c33e973aa18b266f50fe55f24b8c/multidict-6.7.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f99fe611c312b3c1c0ace793f92464d8cd263cc3b26b5721950d977b006b6c4d", size = 252403, upload-time = "2026-01-26T02:45:51.779Z" }, + { url = "https://files.pythonhosted.org/packages/a2/76/b9669547afa5a1a25cd93eaca91c0da1c095b06b6d2d8ec25b713588d3a1/multidict-6.7.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9004d8386d133b7e6135679424c91b0b854d2d164af6ea3f289f8f2761064609", size = 244889, upload-time = "2026-01-26T02:45:53.27Z" }, + { url = "https://files.pythonhosted.org/packages/7e/a9/a50d2669e506dad33cfc45b5d574a205587b7b8a5f426f2fbb2e90882588/multidict-6.7.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e628ef0e6859ffd8273c69412a2465c4be4a9517d07261b33334b5ec6f3c7489", size = 241982, upload-time = "2026-01-26T02:45:54.919Z" }, + { url = "https://files.pythonhosted.org/packages/c5/bb/1609558ad8b456b4827d3c5a5b775c93b87878fd3117ed3db3423dfbce1b/multidict-6.7.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:841189848ba629c3552035a6a7f5bf3b02eb304e9fea7492ca220a8eda6b0e5c", size = 232415, upload-time = "2026-01-26T02:45:56.981Z" }, + { url = "https://files.pythonhosted.org/packages/d8/59/6f61039d2aa9261871e03ab9dc058a550d240f25859b05b67fd70f80d4b3/multidict-6.7.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ce1bbd7d780bb5a0da032e095c951f7014d6b0a205f8318308140f1a6aba159e", size = 240337, upload-time = "2026-01-26T02:45:58.698Z" }, + { url = "https://files.pythonhosted.org/packages/a1/29/fdc6a43c203890dc2ae9249971ecd0c41deaedfe00d25cb6564b2edd99eb/multidict-6.7.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:b26684587228afed0d50cf804cc71062cc9c1cdf55051c4c6345d372947b268c", size = 248788, upload-time = "2026-01-26T02:46:00.862Z" }, + { url = "https://files.pythonhosted.org/packages/a9/14/a153a06101323e4cf086ecee3faadba52ff71633d471f9685c42e3736163/multidict-6.7.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9f9af11306994335398293f9958071019e3ab95e9a707dc1383a35613f6abcb9", size = 242842, upload-time = "2026-01-26T02:46:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/604ae839e64a4a6efc80db94465348d3b328ee955e37acb24badbcd24d83/multidict-6.7.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b4938326284c4f1224178a560987b6cf8b4d38458b113d9b8c1db1a836e640a2", size = 240237, upload-time = "2026-01-26T02:46:05.898Z" }, + { url = "https://files.pythonhosted.org/packages/5f/60/c3a5187bf66f6fb546ff4ab8fb5a077cbdd832d7b1908d4365c7f74a1917/multidict-6.7.1-cp314-cp314t-win32.whl", hash = "sha256:98655c737850c064a65e006a3df7c997cd3b220be4ec8fe26215760b9697d4d7", size = 48008, upload-time = "2026-01-26T02:46:07.468Z" }, + { url = "https://files.pythonhosted.org/packages/0c/f7/addf1087b860ac60e6f382240f64fb99f8bfb532bb06f7c542b83c29ca61/multidict-6.7.1-cp314-cp314t-win_amd64.whl", hash = "sha256:497bde6223c212ba11d462853cfa4f0ae6ef97465033e7dc9940cdb3ab5b48e5", size = 53542, upload-time = "2026-01-26T02:46:08.809Z" }, + { url = "https://files.pythonhosted.org/packages/4c/81/4629d0aa32302ef7b2ec65c75a728cc5ff4fa410c50096174c1632e70b3e/multidict-6.7.1-cp314-cp314t-win_arm64.whl", hash = "sha256:2bbd113e0d4af5db41d5ebfe9ccaff89de2120578164f86a5d17d5a576d1e5b2", size = 44719, upload-time = "2026-01-26T02:46:11.146Z" }, + { url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" }, +] + [[package]] name = "nodeenv" version = "1.10.0" @@ -1081,6 +1789,214 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/b2/d0896bdcdc8d28a7fc5717c305f1a861c26e18c05047949fb371034d98bd/nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827", size = 23438, upload-time = "2025-12-20T14:08:52.782Z" }, ] +[[package]] +name = "numpy" +version = "2.2.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and sys_platform == 'win32'", + "python_full_version < '3.11' and sys_platform != 'win32'", +] +sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3e/ed6db5be21ce87955c0cbd3009f2803f59fa08df21b5df06862e2d8e2bdd/numpy-2.2.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b412caa66f72040e6d268491a59f2c43bf03eb6c96dd8f0307829feb7fa2b6fb", size = 21165245, upload-time = "2025-05-17T21:27:58.555Z" }, + { url = "https://files.pythonhosted.org/packages/22/c2/4b9221495b2a132cc9d2eb862e21d42a009f5a60e45fc44b00118c174bff/numpy-2.2.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e41fd67c52b86603a91c1a505ebaef50b3314de0213461c7a6e99c9a3beff90", size = 14360048, upload-time = "2025-05-17T21:28:21.406Z" }, + { url = "https://files.pythonhosted.org/packages/fd/77/dc2fcfc66943c6410e2bf598062f5959372735ffda175b39906d54f02349/numpy-2.2.6-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:37e990a01ae6ec7fe7fa1c26c55ecb672dd98b19c3d0e1d1f326fa13cb38d163", size = 5340542, upload-time = "2025-05-17T21:28:30.931Z" }, + { url = "https://files.pythonhosted.org/packages/7a/4f/1cb5fdc353a5f5cc7feb692db9b8ec2c3d6405453f982435efc52561df58/numpy-2.2.6-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:5a6429d4be8ca66d889b7cf70f536a397dc45ba6faeb5f8c5427935d9592e9cf", size = 6878301, upload-time = "2025-05-17T21:28:41.613Z" }, + { url = "https://files.pythonhosted.org/packages/eb/17/96a3acd228cec142fcb8723bd3cc39c2a474f7dcf0a5d16731980bcafa95/numpy-2.2.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:efd28d4e9cd7d7a8d39074a4d44c63eda73401580c5c76acda2ce969e0a38e83", size = 14297320, upload-time = "2025-05-17T21:29:02.78Z" }, + { url = "https://files.pythonhosted.org/packages/b4/63/3de6a34ad7ad6646ac7d2f55ebc6ad439dbbf9c4370017c50cf403fb19b5/numpy-2.2.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc7b73d02efb0e18c000e9ad8b83480dfcd5dfd11065997ed4c6747470ae8915", size = 16801050, upload-time = "2025-05-17T21:29:27.675Z" }, + { url = "https://files.pythonhosted.org/packages/07/b6/89d837eddef52b3d0cec5c6ba0456c1bf1b9ef6a6672fc2b7873c3ec4e2e/numpy-2.2.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74d4531beb257d2c3f4b261bfb0fc09e0f9ebb8842d82a7b4209415896adc680", size = 15807034, upload-time = "2025-05-17T21:29:51.102Z" }, + { url = "https://files.pythonhosted.org/packages/01/c8/dc6ae86e3c61cfec1f178e5c9f7858584049b6093f843bca541f94120920/numpy-2.2.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8fc377d995680230e83241d8a96def29f204b5782f371c532579b4f20607a289", size = 18614185, upload-time = "2025-05-17T21:30:18.703Z" }, + { url = "https://files.pythonhosted.org/packages/5b/c5/0064b1b7e7c89137b471ccec1fd2282fceaae0ab3a9550f2568782d80357/numpy-2.2.6-cp310-cp310-win32.whl", hash = "sha256:b093dd74e50a8cba3e873868d9e93a85b78e0daf2e98c6797566ad8044e8363d", size = 6527149, upload-time = "2025-05-17T21:30:29.788Z" }, + { url = "https://files.pythonhosted.org/packages/a3/dd/4b822569d6b96c39d1215dbae0582fd99954dcbcf0c1a13c61783feaca3f/numpy-2.2.6-cp310-cp310-win_amd64.whl", hash = "sha256:f0fd6321b839904e15c46e0d257fdd101dd7f530fe03fd6359c1ea63738703f3", size = 12904620, upload-time = "2025-05-17T21:30:48.994Z" }, + { url = "https://files.pythonhosted.org/packages/da/a8/4f83e2aa666a9fbf56d6118faaaf5f1974d456b1823fda0a176eff722839/numpy-2.2.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f9f1adb22318e121c5c69a09142811a201ef17ab257a1e66ca3025065b7f53ae", size = 21176963, upload-time = "2025-05-17T21:31:19.36Z" }, + { url = "https://files.pythonhosted.org/packages/b3/2b/64e1affc7972decb74c9e29e5649fac940514910960ba25cd9af4488b66c/numpy-2.2.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c820a93b0255bc360f53eca31a0e676fd1101f673dda8da93454a12e23fc5f7a", size = 14406743, upload-time = "2025-05-17T21:31:41.087Z" }, + { url = "https://files.pythonhosted.org/packages/4a/9f/0121e375000b5e50ffdd8b25bf78d8e1a5aa4cca3f185d41265198c7b834/numpy-2.2.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3d70692235e759f260c3d837193090014aebdf026dfd167834bcba43e30c2a42", size = 5352616, upload-time = "2025-05-17T21:31:50.072Z" }, + { url = "https://files.pythonhosted.org/packages/31/0d/b48c405c91693635fbe2dcd7bc84a33a602add5f63286e024d3b6741411c/numpy-2.2.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:481b49095335f8eed42e39e8041327c05b0f6f4780488f61286ed3c01368d491", size = 6889579, upload-time = "2025-05-17T21:32:01.712Z" }, + { url = "https://files.pythonhosted.org/packages/52/b8/7f0554d49b565d0171eab6e99001846882000883998e7b7d9f0d98b1f934/numpy-2.2.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b64d8d4d17135e00c8e346e0a738deb17e754230d7e0810ac5012750bbd85a5a", size = 14312005, upload-time = "2025-05-17T21:32:23.332Z" }, + { url = "https://files.pythonhosted.org/packages/b3/dd/2238b898e51bd6d389b7389ffb20d7f4c10066d80351187ec8e303a5a475/numpy-2.2.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba10f8411898fc418a521833e014a77d3ca01c15b0c6cdcce6a0d2897e6dbbdf", size = 16821570, upload-time = "2025-05-17T21:32:47.991Z" }, + { url = "https://files.pythonhosted.org/packages/83/6c/44d0325722cf644f191042bf47eedad61c1e6df2432ed65cbe28509d404e/numpy-2.2.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd48227a919f1bafbdda0583705e547892342c26fb127219d60a5c36882609d1", size = 15818548, upload-time = "2025-05-17T21:33:11.728Z" }, + { url = "https://files.pythonhosted.org/packages/ae/9d/81e8216030ce66be25279098789b665d49ff19eef08bfa8cb96d4957f422/numpy-2.2.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9551a499bf125c1d4f9e250377c1ee2eddd02e01eac6644c080162c0c51778ab", size = 18620521, upload-time = "2025-05-17T21:33:39.139Z" }, + { url = "https://files.pythonhosted.org/packages/6a/fd/e19617b9530b031db51b0926eed5345ce8ddc669bb3bc0044b23e275ebe8/numpy-2.2.6-cp311-cp311-win32.whl", hash = "sha256:0678000bb9ac1475cd454c6b8c799206af8107e310843532b04d49649c717a47", size = 6525866, upload-time = "2025-05-17T21:33:50.273Z" }, + { url = "https://files.pythonhosted.org/packages/31/0a/f354fb7176b81747d870f7991dc763e157a934c717b67b58456bc63da3df/numpy-2.2.6-cp311-cp311-win_amd64.whl", hash = "sha256:e8213002e427c69c45a52bbd94163084025f533a55a59d6f9c5b820774ef3303", size = 12907455, upload-time = "2025-05-17T21:34:09.135Z" }, + { url = "https://files.pythonhosted.org/packages/82/5d/c00588b6cf18e1da539b45d3598d3557084990dcc4331960c15ee776ee41/numpy-2.2.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:41c5a21f4a04fa86436124d388f6ed60a9343a6f767fced1a8a71c3fbca038ff", size = 20875348, upload-time = "2025-05-17T21:34:39.648Z" }, + { url = "https://files.pythonhosted.org/packages/66/ee/560deadcdde6c2f90200450d5938f63a34b37e27ebff162810f716f6a230/numpy-2.2.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:de749064336d37e340f640b05f24e9e3dd678c57318c7289d222a8a2f543e90c", size = 14119362, upload-time = "2025-05-17T21:35:01.241Z" }, + { url = "https://files.pythonhosted.org/packages/3c/65/4baa99f1c53b30adf0acd9a5519078871ddde8d2339dc5a7fde80d9d87da/numpy-2.2.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:894b3a42502226a1cac872f840030665f33326fc3dac8e57c607905773cdcde3", size = 5084103, upload-time = "2025-05-17T21:35:10.622Z" }, + { url = "https://files.pythonhosted.org/packages/cc/89/e5a34c071a0570cc40c9a54eb472d113eea6d002e9ae12bb3a8407fb912e/numpy-2.2.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:71594f7c51a18e728451bb50cc60a3ce4e6538822731b2933209a1f3614e9282", size = 6625382, upload-time = "2025-05-17T21:35:21.414Z" }, + { url = "https://files.pythonhosted.org/packages/f8/35/8c80729f1ff76b3921d5c9487c7ac3de9b2a103b1cd05e905b3090513510/numpy-2.2.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2618db89be1b4e05f7a1a847a9c1c0abd63e63a1607d892dd54668dd92faf87", size = 14018462, upload-time = "2025-05-17T21:35:42.174Z" }, + { url = "https://files.pythonhosted.org/packages/8c/3d/1e1db36cfd41f895d266b103df00ca5b3cbe965184df824dec5c08c6b803/numpy-2.2.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd83c01228a688733f1ded5201c678f0c53ecc1006ffbc404db9f7a899ac6249", size = 16527618, upload-time = "2025-05-17T21:36:06.711Z" }, + { url = "https://files.pythonhosted.org/packages/61/c6/03ed30992602c85aa3cd95b9070a514f8b3c33e31124694438d88809ae36/numpy-2.2.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:37c0ca431f82cd5fa716eca9506aefcabc247fb27ba69c5062a6d3ade8cf8f49", size = 15505511, upload-time = "2025-05-17T21:36:29.965Z" }, + { url = "https://files.pythonhosted.org/packages/b7/25/5761d832a81df431e260719ec45de696414266613c9ee268394dd5ad8236/numpy-2.2.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fe27749d33bb772c80dcd84ae7e8df2adc920ae8297400dabec45f0dedb3f6de", size = 18313783, upload-time = "2025-05-17T21:36:56.883Z" }, + { url = "https://files.pythonhosted.org/packages/57/0a/72d5a3527c5ebffcd47bde9162c39fae1f90138c961e5296491ce778e682/numpy-2.2.6-cp312-cp312-win32.whl", hash = "sha256:4eeaae00d789f66c7a25ac5f34b71a7035bb474e679f410e5e1a94deb24cf2d4", size = 6246506, upload-time = "2025-05-17T21:37:07.368Z" }, + { url = "https://files.pythonhosted.org/packages/36/fa/8c9210162ca1b88529ab76b41ba02d433fd54fecaf6feb70ef9f124683f1/numpy-2.2.6-cp312-cp312-win_amd64.whl", hash = "sha256:c1f9540be57940698ed329904db803cf7a402f3fc200bfe599334c9bd84a40b2", size = 12614190, upload-time = "2025-05-17T21:37:26.213Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5c/6657823f4f594f72b5471f1db1ab12e26e890bb2e41897522d134d2a3e81/numpy-2.2.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0811bb762109d9708cca4d0b13c4f67146e3c3b7cf8d34018c722adb2d957c84", size = 20867828, upload-time = "2025-05-17T21:37:56.699Z" }, + { url = "https://files.pythonhosted.org/packages/dc/9e/14520dc3dadf3c803473bd07e9b2bd1b69bc583cb2497b47000fed2fa92f/numpy-2.2.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:287cc3162b6f01463ccd86be154f284d0893d2b3ed7292439ea97eafa8170e0b", size = 14143006, upload-time = "2025-05-17T21:38:18.291Z" }, + { url = "https://files.pythonhosted.org/packages/4f/06/7e96c57d90bebdce9918412087fc22ca9851cceaf5567a45c1f404480e9e/numpy-2.2.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:f1372f041402e37e5e633e586f62aa53de2eac8d98cbfb822806ce4bbefcb74d", size = 5076765, upload-time = "2025-05-17T21:38:27.319Z" }, + { url = "https://files.pythonhosted.org/packages/73/ed/63d920c23b4289fdac96ddbdd6132e9427790977d5457cd132f18e76eae0/numpy-2.2.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:55a4d33fa519660d69614a9fad433be87e5252f4b03850642f88993f7b2ca566", size = 6617736, upload-time = "2025-05-17T21:38:38.141Z" }, + { url = "https://files.pythonhosted.org/packages/85/c5/e19c8f99d83fd377ec8c7e0cf627a8049746da54afc24ef0a0cb73d5dfb5/numpy-2.2.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f92729c95468a2f4f15e9bb94c432a9229d0d50de67304399627a943201baa2f", size = 14010719, upload-time = "2025-05-17T21:38:58.433Z" }, + { url = "https://files.pythonhosted.org/packages/19/49/4df9123aafa7b539317bf6d342cb6d227e49f7a35b99c287a6109b13dd93/numpy-2.2.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bc23a79bfabc5d056d106f9befb8d50c31ced2fbc70eedb8155aec74a45798f", size = 16526072, upload-time = "2025-05-17T21:39:22.638Z" }, + { url = "https://files.pythonhosted.org/packages/b2/6c/04b5f47f4f32f7c2b0e7260442a8cbcf8168b0e1a41ff1495da42f42a14f/numpy-2.2.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e3143e4451880bed956e706a3220b4e5cf6172ef05fcc397f6f36a550b1dd868", size = 15503213, upload-time = "2025-05-17T21:39:45.865Z" }, + { url = "https://files.pythonhosted.org/packages/17/0a/5cd92e352c1307640d5b6fec1b2ffb06cd0dabe7d7b8227f97933d378422/numpy-2.2.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b4f13750ce79751586ae2eb824ba7e1e8dba64784086c98cdbbcc6a42112ce0d", size = 18316632, upload-time = "2025-05-17T21:40:13.331Z" }, + { url = "https://files.pythonhosted.org/packages/f0/3b/5cba2b1d88760ef86596ad0f3d484b1cbff7c115ae2429678465057c5155/numpy-2.2.6-cp313-cp313-win32.whl", hash = "sha256:5beb72339d9d4fa36522fc63802f469b13cdbe4fdab4a288f0c441b74272ebfd", size = 6244532, upload-time = "2025-05-17T21:43:46.099Z" }, + { url = "https://files.pythonhosted.org/packages/cb/3b/d58c12eafcb298d4e6d0d40216866ab15f59e55d148a5658bb3132311fcf/numpy-2.2.6-cp313-cp313-win_amd64.whl", hash = "sha256:b0544343a702fa80c95ad5d3d608ea3599dd54d4632df855e4c8d24eb6ecfa1c", size = 12610885, upload-time = "2025-05-17T21:44:05.145Z" }, + { url = "https://files.pythonhosted.org/packages/6b/9e/4bf918b818e516322db999ac25d00c75788ddfd2d2ade4fa66f1f38097e1/numpy-2.2.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0bca768cd85ae743b2affdc762d617eddf3bcf8724435498a1e80132d04879e6", size = 20963467, upload-time = "2025-05-17T21:40:44Z" }, + { url = "https://files.pythonhosted.org/packages/61/66/d2de6b291507517ff2e438e13ff7b1e2cdbdb7cb40b3ed475377aece69f9/numpy-2.2.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fc0c5673685c508a142ca65209b4e79ed6740a4ed6b2267dbba90f34b0b3cfda", size = 14225144, upload-time = "2025-05-17T21:41:05.695Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/480387655407ead912e28ba3a820bc69af9adf13bcbe40b299d454ec011f/numpy-2.2.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:5bd4fc3ac8926b3819797a7c0e2631eb889b4118a9898c84f585a54d475b7e40", size = 5200217, upload-time = "2025-05-17T21:41:15.903Z" }, + { url = "https://files.pythonhosted.org/packages/aa/4a/6e313b5108f53dcbf3aca0c0f3e9c92f4c10ce57a0a721851f9785872895/numpy-2.2.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:fee4236c876c4e8369388054d02d0e9bb84821feb1a64dd59e137e6511a551f8", size = 6712014, upload-time = "2025-05-17T21:41:27.321Z" }, + { url = "https://files.pythonhosted.org/packages/b7/30/172c2d5c4be71fdf476e9de553443cf8e25feddbe185e0bd88b096915bcc/numpy-2.2.6-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e1dda9c7e08dc141e0247a5b8f49cf05984955246a327d4c48bda16821947b2f", size = 14077935, upload-time = "2025-05-17T21:41:49.738Z" }, + { url = "https://files.pythonhosted.org/packages/12/fb/9e743f8d4e4d3c710902cf87af3512082ae3d43b945d5d16563f26ec251d/numpy-2.2.6-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f447e6acb680fd307f40d3da4852208af94afdfab89cf850986c3ca00562f4fa", size = 16600122, upload-time = "2025-05-17T21:42:14.046Z" }, + { url = "https://files.pythonhosted.org/packages/12/75/ee20da0e58d3a66f204f38916757e01e33a9737d0b22373b3eb5a27358f9/numpy-2.2.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:389d771b1623ec92636b0786bc4ae56abafad4a4c513d36a55dce14bd9ce8571", size = 15586143, upload-time = "2025-05-17T21:42:37.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/95/bef5b37f29fc5e739947e9ce5179ad402875633308504a52d188302319c8/numpy-2.2.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8e9ace4a37db23421249ed236fdcdd457d671e25146786dfc96835cd951aa7c1", size = 18385260, upload-time = "2025-05-17T21:43:05.189Z" }, + { url = "https://files.pythonhosted.org/packages/09/04/f2f83279d287407cf36a7a8053a5abe7be3622a4363337338f2585e4afda/numpy-2.2.6-cp313-cp313t-win32.whl", hash = "sha256:038613e9fb8c72b0a41f025a7e4c3f0b7a1b5d768ece4796b674c8f3fe13efff", size = 6377225, upload-time = "2025-05-17T21:43:16.254Z" }, + { url = "https://files.pythonhosted.org/packages/67/0e/35082d13c09c02c011cf21570543d202ad929d961c02a147493cb0c2bdf5/numpy-2.2.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6031dd6dfecc0cf9f668681a37648373bddd6421fff6c66ec1624eed0180ee06", size = 12771374, upload-time = "2025-05-17T21:43:35.479Z" }, + { url = "https://files.pythonhosted.org/packages/9e/3b/d94a75f4dbf1ef5d321523ecac21ef23a3cd2ac8b78ae2aac40873590229/numpy-2.2.6-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0b605b275d7bd0c640cad4e5d30fa701a8d59302e127e5f79138ad62762c3e3d", size = 21040391, upload-time = "2025-05-17T21:44:35.948Z" }, + { url = "https://files.pythonhosted.org/packages/17/f4/09b2fa1b58f0fb4f7c7963a1649c64c4d315752240377ed74d9cd878f7b5/numpy-2.2.6-pp310-pypy310_pp73-macosx_14_0_x86_64.whl", hash = "sha256:7befc596a7dc9da8a337f79802ee8adb30a552a94f792b9c9d18c840055907db", size = 6786754, upload-time = "2025-05-17T21:44:47.446Z" }, + { url = "https://files.pythonhosted.org/packages/af/30/feba75f143bdc868a1cc3f44ccfa6c4b9ec522b36458e738cd00f67b573f/numpy-2.2.6-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ce47521a4754c8f4593837384bd3424880629f718d87c5d44f8ed763edd63543", size = 16643476, upload-time = "2025-05-17T21:45:11.871Z" }, + { url = "https://files.pythonhosted.org/packages/37/48/ac2a9584402fb6c0cd5b5d1a91dcf176b15760130dd386bbafdbfe3640bf/numpy-2.2.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d042d24c90c41b54fd506da306759e06e568864df8ec17ccc17e9e884634fd00", size = 12812666, upload-time = "2025-05-17T21:45:31.426Z" }, +] + +[[package]] +name = "numpy" +version = "2.4.6" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform != 'win32'", +] +sdist = { url = "https://files.pythonhosted.org/packages/d0/ad/fed0499ce6a338d2a03ebae59cd15093910c8875328855781952abf6c2fe/numpy-2.4.6.tar.gz", hash = "sha256:f3a3570c4a2a16746ac2c31a7c7c7b0c186b95ce902e33db6f28094ed7387dda", size = 20735807, upload-time = "2026-05-18T23:37:14.07Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/49/ec46835a70be8fa6446c495126ac84fdb28cb2558e1620ffb87a10c8b64c/numpy-2.4.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0280e0356c0829a18d9de1cb7eee50ec22ca639878d7240307ca0943d73cd2c4", size = 16969194, upload-time = "2026-05-18T23:33:13.503Z" }, + { url = "https://files.pythonhosted.org/packages/0e/0d/f5957185c0ee2f3e12f78715aa9e3b353fd83633316c8532b38faa37e3f6/numpy-2.4.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:110f8b71aacb688ec69062bb7f6938a0f8acb01b7c1c4beb453c65b6d234584d", size = 14964111, upload-time = "2026-05-18T23:33:17.795Z" }, + { url = "https://files.pythonhosted.org/packages/ad/40/40a40ee0ddf7ceb782c49af278894b686e586d65d8c1889c8b5da01a3d7d/numpy-2.4.6-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:4cfe66903cc32a9921a6733d96b19bb6abf310397581bbad89c228f5abaf0ee8", size = 5469159, upload-time = "2026-05-18T23:33:20.654Z" }, + { url = "https://files.pythonhosted.org/packages/63/13/f9a8046535cb21deae82f8d03de9617e08882d274fad2539630761888228/numpy-2.4.6-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:8155154c7c691289fe18f510b5d4657c68c67989f293f0535a91360392ff6538", size = 6798936, upload-time = "2026-05-18T23:33:22.987Z" }, + { url = "https://files.pythonhosted.org/packages/33/a8/6fa8c1a345a8c85dbb21932c447bee07c30a2c2a3f31e369c0a84b300147/numpy-2.4.6-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ab0a9c4ffb1a6d95ef519fe4247dba8eb6b18ad93999f76b7f657039acabd47", size = 15966692, upload-time = "2026-05-18T23:33:26.62Z" }, + { url = "https://files.pythonhosted.org/packages/02/03/74fe2a4cb3817d94d86402f2506554130a2f01414e299b5a843e5a8a957f/numpy-2.4.6-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:89cd468399cfd2504718f0ba50e410dca55a170b61a02ad92bb18c8a65186e93", size = 16918164, upload-time = "2026-05-18T23:33:29.955Z" }, + { url = "https://files.pythonhosted.org/packages/c5/80/3615be3313f7e7696609bc194b9f0101da809df79e859bdb84e0cd043f46/numpy-2.4.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c2d37ab77531417474168eb79d6d80b14f821a966818505d03013d0833edb7a8", size = 17322877, upload-time = "2026-05-18T23:33:34.724Z" }, + { url = "https://files.pythonhosted.org/packages/ca/ac/a691e0fe2675e370d0e08ff905adc49a1c8830e8cae03efe4477e92cd55d/numpy-2.4.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f407cb6b8e9d6d8c626bc73c945db1706035af8fd632295547bf1c9e46d092d6", size = 18651487, upload-time = "2026-05-18T23:33:38.217Z" }, + { url = "https://files.pythonhosted.org/packages/15/a7/9bc1cd626d7bf6869bfedf27b91b6ab5dd607758bf8e959d6fa80c6a59cb/numpy-2.4.6-cp311-cp311-win32.whl", hash = "sha256:ddea102b48f9e339f3948bf22040944184627a30fdf7f858667673b9c5f033c8", size = 6233945, upload-time = "2026-05-18T23:33:41.331Z" }, + { url = "https://files.pythonhosted.org/packages/c5/31/7fc6239c12bce7e931463251cca4426c465e1876ba3cc785402ef4dd8f4e/numpy-2.4.6-cp311-cp311-win_amd64.whl", hash = "sha256:1e254a00cdf42b1e4d5b3d68d33af63268d41340d8885df2ab6470f2e1500147", size = 12608406, upload-time = "2026-05-18T23:33:44.131Z" }, + { url = "https://files.pythonhosted.org/packages/27/83/140f85a466595a16382996a1bf06b2b54bcd597488921b0c9daaeeda72af/numpy-2.4.6-cp311-cp311-win_arm64.whl", hash = "sha256:ed9749eef4cbd126da3dc1d6bcb3a57f5eb7ac6a6484146bdbf743f552dfc577", size = 10479528, upload-time = "2026-05-18T23:33:50.725Z" }, + { url = "https://files.pythonhosted.org/packages/95/2a/3d7b5ac8aac24feaf9ad7ed58f45b0bbc06d37e4338ae84c9f2298b570f9/numpy-2.4.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:001fbb8e08d942dd57599e781f2472269ee7f2755fae407b4f67b2f0b17da3f1", size = 16689119, upload-time = "2026-05-18T23:33:54.065Z" }, + { url = "https://files.pythonhosted.org/packages/ea/12/92c4c131527599e8288d6918e888d88726f84d805d784b771f32408aeaef/numpy-2.4.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ebfb099f8dcf083deef3ac1ca4c1503f387cf76296fcb3816b66f5ecb5f54fdb", size = 14699246, upload-time = "2026-05-18T23:33:57.621Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fe/c0a6b7b2ca128a8fb228575147073b660656734b8ebe4d76c8fd748dcc79/numpy-2.4.6-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:3213d622a0283a39a93d188f3cf72b26862df52fbb4ca3697f51705016523d41", size = 5204410, upload-time = "2026-05-18T23:34:00.302Z" }, + { url = "https://files.pythonhosted.org/packages/f3/d4/9770d14ba719432bb90a421bfd443872ed0f70f7264b64bec12ea363d5fd/numpy-2.4.6-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:357cc07a6d7b0b182ff02249616a03742827ebb1277546b5c7cd7f7620a45698", size = 6551240, upload-time = "2026-05-18T23:34:02.852Z" }, + { url = "https://files.pythonhosted.org/packages/c9/c6/50a46a6205feba2343f1d6d17438107c5dc491ed1c736e6ea68689fd906b/numpy-2.4.6-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5f9fb9157b4ce2971008323afe46053787b526ef624fea915b261468a8421a0f", size = 15671012, upload-time = "2026-05-18T23:34:05.485Z" }, + { url = "https://files.pythonhosted.org/packages/99/60/14115e6364fa676c5397c2ad3004e527e9aa487abf5d0706ec81bbd08529/numpy-2.4.6-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:90f9849678c75fe7afa2d348ac842c168b0a4d3d61919687216dfc547976d853", size = 16645538, upload-time = "2026-05-18T23:34:09.265Z" }, + { url = "https://files.pythonhosted.org/packages/ae/c5/693cbe59e57db94d2231fa519ca3978dc9e19da5a8f088588f5c6e947ff2/numpy-2.4.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c1a2af6c6ef86344a6b0db6b97834208bf598db514f2b155042439b62605601a", size = 17020706, upload-time = "2026-05-18T23:34:13.053Z" }, + { url = "https://files.pythonhosted.org/packages/ef/fc/85b7c4eff9b4966ade25c2273cf7e7012e92366c032058653934b37de044/numpy-2.4.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e5805d5a22fd19c8ccff10a9561f9df94436b0545619ea579db2d3c35294bce2", size = 18368541, upload-time = "2026-05-18T23:34:17.024Z" }, + { url = "https://files.pythonhosted.org/packages/f6/81/e1b27545deedce7f4a0b348618c6b62d74e36a4dc9ccd42f3eb2f85eee32/numpy-2.4.6-cp312-cp312-win32.whl", hash = "sha256:e3eeb0aabd6bd5ce64faae67e9935203a6991b4bc2a485a767fbafb2c5125f45", size = 5962825, upload-time = "2026-05-18T23:34:20.3Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ca/feab00bd44aa5fe1ad2c18f08b4d3bb92e26484b0b1d1443897809ed528c/numpy-2.4.6-cp312-cp312-win_amd64.whl", hash = "sha256:d8e8286dd7cea7895157318d1b91cdacac64c479f3cbc8dce548331728484751", size = 12321687, upload-time = "2026-05-18T23:34:23.095Z" }, + { url = "https://files.pythonhosted.org/packages/63/cf/5a6d34850a39d1093558564f77ee8e8e0bee5061151b8f05a55711001ec7/numpy-2.4.6-cp312-cp312-win_arm64.whl", hash = "sha256:4081eb135ac24158bd51cdfbef16f1c64df7063b1143f24731387137c092bec8", size = 10221482, upload-time = "2026-05-18T23:34:25.876Z" }, + { url = "https://files.pythonhosted.org/packages/fb/82/bdab26d7438c6791ca31b7c024ca37c1eab8b726ba236129005cd4a06e45/numpy-2.4.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:511dbaf848decaaaf4b4ca48032619fb3138710c4bf7da7617765edad1ef96b0", size = 16684648, upload-time = "2026-05-18T23:34:29.41Z" }, + { url = "https://files.pythonhosted.org/packages/1b/30/a80189bcc7f5e4258b3fbc3968d909d1756f54d023299ecc39ad6fdb9ef8/numpy-2.4.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:bf162abab1c1a736333192707cef898e735a5ca00f38f27eeedf44b39d9e85eb", size = 14693902, upload-time = "2026-05-18T23:34:33.013Z" }, + { url = "https://files.pythonhosted.org/packages/97/12/70b5d0d7c15e1ebb8a6a84a8caa1d19e181d84fb58bb6d70aca29099dec1/numpy-2.4.6-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:043191bfa8eab18c776647b62723ac9dddece59743b13f49b2016094129c2b3f", size = 5198992, upload-time = "2026-05-18T23:34:36.132Z" }, + { url = "https://files.pythonhosted.org/packages/ba/8c/ebd2a8f8a83541f8d38cc5667e8c2b69cecfd30da6e45693e8158857d44b/numpy-2.4.6-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:6180d8b35af935aed8ece3a85e0a43f87393ae0ac87c8d2c8bd2c993f7270ef3", size = 6546944, upload-time = "2026-05-18T23:34:38.484Z" }, + { url = "https://files.pythonhosted.org/packages/bb/c5/7b863a97a91671a0338f4253bd3b5a3d3852f0692dae91711c9f4a10e787/numpy-2.4.6-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:72fbe16c6fac95aedf5937fa873445cec2110be35d8a4e9433d7501fd98dae6b", size = 15669392, upload-time = "2026-05-18T23:34:41.257Z" }, + { url = "https://files.pythonhosted.org/packages/a5/9d/3584b9984ca4c047aea75214ce1a4c4c73d849bd71b604264b7f5653f8a8/numpy-2.4.6-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a7830bab239b79cda9c08c2da014761cafb48da6150e1da17ac06283f43b6089", size = 16633220, upload-time = "2026-05-18T23:34:45.075Z" }, + { url = "https://files.pythonhosted.org/packages/05/ae/7c67fba23bd98caec7c99261f3a16072ade14813486b0282cb29846de832/numpy-2.4.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ef4aea96ce4d3b074422cb4f2f64e216bf9e213004bb58ecfdf50ea02ea8eb9a", size = 17020800, upload-time = "2026-05-18T23:34:49.065Z" }, + { url = "https://files.pythonhosted.org/packages/d9/5d/3b6725cb31d983c5e66916f5d36f6d7e5521129e4c4404d64f918292a5b6/numpy-2.4.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dfa20cc6ca228e6b155b11da03825975ce66aea520985dbbddf0f2a5a495c605", size = 18357600, upload-time = "2026-05-18T23:34:52.709Z" }, + { url = "https://files.pythonhosted.org/packages/f7/da/2ccc6c2fe8898dee01d90c75c5f5f914a23daf99e3e0f59516a08760c8b5/numpy-2.4.6-cp313-cp313-win32.whl", hash = "sha256:56b39e5e0622a09a25bf5baf62f4bcf0cb8a41ae6e2819cf49bbc5a74c083f91", size = 5961134, upload-time = "2026-05-18T23:34:55.618Z" }, + { url = "https://files.pythonhosted.org/packages/b5/cd/9cc4dc876fb065d5c220aae4d5e14826b2715331bb7618ce1fb07a679d99/numpy-2.4.6-cp313-cp313-win_amd64.whl", hash = "sha256:c4fc99836233ea196540b17ab0983aff60ed07941751930f5f4d05bc3b3b7359", size = 12318598, upload-time = "2026-05-18T23:34:58.928Z" }, + { url = "https://files.pythonhosted.org/packages/39/1e/c0bcba1f8694116485fe28fd1be698c278fcda4141c5b0e53a2aed8b12a8/numpy-2.4.6-cp313-cp313-win_arm64.whl", hash = "sha256:a7c711e21628b52034bb5ab8d1bce291f752fcc5e92accc615778acee1ff4778", size = 10222272, upload-time = "2026-05-18T23:35:02.167Z" }, + { url = "https://files.pythonhosted.org/packages/63/6d/cc5619247c8f4204e507f5883528372e4ac4bb189e579fb859a12e480b1f/numpy-2.4.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:112b06a867b235ef466ed3508ddf0238050df9c727cafb5301ac385b899189a1", size = 14821197, upload-time = "2026-05-18T23:35:05.468Z" }, + { url = "https://files.pythonhosted.org/packages/00/58/f1c39161c87d9e9bed660f1ed4bafc0e403d5ec9650b6dd77aead07d489b/numpy-2.4.6-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:eaf7fa2de5c0be8ae6ff8e9bea2ccd725e980541244521d8d4b5f3354a27babe", size = 5326287, upload-time = "2026-05-18T23:35:08.693Z" }, + { url = "https://files.pythonhosted.org/packages/af/57/3917ab0fd97f271a8694513581b8a36c655f111c446852c302f04ccdb6fc/numpy-2.4.6-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:7265a2f3d436e54ef9f2b52b5c937e6be778781bd97a590319d7348f1c1ca997", size = 6646763, upload-time = "2026-05-18T23:35:11.459Z" }, + { url = "https://files.pythonhosted.org/packages/eb/0f/037e64c494b67581ae18193d770adef354c41f3f2c8ebf865602d949bf8f/numpy-2.4.6-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f74a575920ab21fe304421a3fc28793d82e299cae9eccb37084e9fc7f3617c20", size = 15728070, upload-time = "2026-05-18T23:35:14.79Z" }, + { url = "https://files.pythonhosted.org/packages/21/a6/5d2bae9c9542eb4df16dc9c46dc79c186e9bad53805dfa5399a6023c6db0/numpy-2.4.6-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ede83e07a75dd06bc501566c1eca2afc0d61677c1472ac9ad93fdee6e638a48d", size = 16681752, upload-time = "2026-05-18T23:35:18.836Z" }, + { url = "https://files.pythonhosted.org/packages/92/14/23d1dfb410ae362cd59ce53e936b1513d545eb40db3949ced632e19a459e/numpy-2.4.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:68bb27509ac1b9a3443094260f6326150663b06abe40b73a2f81160623da5b67", size = 17086024, upload-time = "2026-05-18T23:35:22.52Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6e/23595a2c642cdf3bc567877064bdd7f91c8b0038a4453cf2daf7248eafe9/numpy-2.4.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:a0df0043bdb289bde1f62da130d20df23d58b45429f752bc7a8fc5325a225ecd", size = 18403398, upload-time = "2026-05-18T23:35:26.398Z" }, + { url = "https://files.pythonhosted.org/packages/8a/90/0ac3bc947217e66dec77e7cbc6a1979d1af70b6461b82f620d3bccd5e4c8/numpy-2.4.6-cp313-cp313t-win32.whl", hash = "sha256:29a287e0cf63ff528da061de6b9f64a4618da591ca1046aafc54062e40ca7eab", size = 6084971, upload-time = "2026-05-18T23:35:29.387Z" }, + { url = "https://files.pythonhosted.org/packages/77/71/5673e351671a1d2bd6063b91b44f70c0affea7d1516fa7a6572941ba4aa1/numpy-2.4.6-cp313-cp313t-win_amd64.whl", hash = "sha256:25c692919ac5a01f170a3bfcd62d745b24fd095c353d50812637d6fcab442e75", size = 12458532, upload-time = "2026-05-18T23:35:32.175Z" }, + { url = "https://files.pythonhosted.org/packages/3f/88/19d3503c5046e688f049274b27a3ef3d771152fa80d3ba3d01a3dff61abe/numpy-2.4.6-cp313-cp313t-win_arm64.whl", hash = "sha256:1e978ec1e8bd0e0e4de6bb75de9d30cbb74db6b6a2bb727618613703ca0167dd", size = 10291881, upload-time = "2026-05-18T23:35:35.465Z" }, + { url = "https://files.pythonhosted.org/packages/f8/91/3ab2044d05fd16d343c5ac2e69b127f1b2854040dd20b193257c78028bd3/numpy-2.4.6-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:06ca2f61ec4385a07a6977c55ba998a4466c123642b4a32694d3128fce18c079", size = 16683458, upload-time = "2026-05-18T23:35:38.353Z" }, + { url = "https://files.pythonhosted.org/packages/8e/62/764ce66fa4147ae6d73071a3abf804ffe606f174618697c571acdf26a7c9/numpy-2.4.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:38efbc8de75c7a0fc1ac190162d892787f3f47b57cc291231aafee36b80982b7", size = 14704559, upload-time = "2026-05-18T23:35:42.14Z" }, + { url = "https://files.pythonhosted.org/packages/60/61/23f27c172f022e04025b7dc2367f4d63c1a398120607ec896228649a6f48/numpy-2.4.6-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:d581b735e177fdcdce6fed8e7e8880a3fb6ee4e3653a3ac6af01c6f4c03effc5", size = 5209716, upload-time = "2026-05-18T23:35:45.377Z" }, + { url = "https://files.pythonhosted.org/packages/03/71/21cf70dc6ea3e3acb95fc53a265b2fc248b981f0194ceb5b475271b8809d/numpy-2.4.6-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:0a041d3d761dc3c35cc56ce0351506a02bcbc25f7b169f652435141a17db9096", size = 6543947, upload-time = "2026-05-18T23:35:47.926Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/64288395ee1799bd2e0b04a305dce9666da90c961e1f3fe982a05ee1c036/numpy-2.4.6-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:40fdc1ae7125e518ea98e53e69a4ebc27e1fd50510c47b7ea130cf21e5e1d42b", size = 15685197, upload-time = "2026-05-18T23:35:50.863Z" }, + { url = "https://files.pythonhosted.org/packages/f3/eb/ebffaa97dc55502df69584a8f0dcf07f69a3e0b3e2323670a2722db9aa39/numpy-2.4.6-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a2c306dea656c12c68f51f4cea133cbe78ca7435eb28c735eac1d3ebe73be6e8", size = 16638245, upload-time = "2026-05-18T23:35:54.752Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0b/54f9da33128d7e350fab89c7455902eeae70349ee52bddb448dc4a576f45/numpy-2.4.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:33111801a01c12a8a1e3721f0a9232f8cfc8ae2c6b7098167e6f623c6073f402", size = 17036587, upload-time = "2026-05-18T23:35:58.355Z" }, + { url = "https://files.pythonhosted.org/packages/b6/f0/fdebc1052db1cc37c64beb22072d67cd6d1c71adca1299f53dec2b5e20d3/numpy-2.4.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae506e6902902557576a26ff33eda8695e7ecb3cb36c3b573a0765dee114ebdb", size = 18363226, upload-time = "2026-05-18T23:36:02.845Z" }, + { url = "https://files.pythonhosted.org/packages/aa/b4/298628d98c72b57e57f7165ae6a481a1deaf6f3c28262a6e4c739c275930/numpy-2.4.6-cp314-cp314-win32.whl", hash = "sha256:aaf159caa35993cb1f56fb9b8e4610d35758e7ca005412eb1daa856a78c9c4b1", size = 6010196, upload-time = "2026-05-18T23:36:05.92Z" }, + { url = "https://files.pythonhosted.org/packages/df/ac/46de6dda46478f7942f839e094970be2d4a861e005c4b3bf07c92e291a09/numpy-2.4.6-cp314-cp314-win_amd64.whl", hash = "sha256:b507f5c4c1d508876d1819b6bf9a49d365b96320b5d4993426b33a23ca4b8261", size = 12450334, upload-time = "2026-05-18T23:36:09.107Z" }, + { url = "https://files.pythonhosted.org/packages/78/92/b8b798ac784102c0da830d2257d59358e3d3d90d1e2b3f2575dad976c5cf/numpy-2.4.6-cp314-cp314-win_arm64.whl", hash = "sha256:6f41ae150c4e32db4f3310cdaf64b1593a03dbabe29eec77fc9b50fe64061df6", size = 10495678, upload-time = "2026-05-18T23:36:12.766Z" }, + { url = "https://files.pythonhosted.org/packages/30/34/ec28d1aa8115971537c01469ab2011ee96827930f0a124de1000cc2a7ed7/numpy-2.4.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ece3d2cfe132e7d51f44a832b303895e6f2d499c5e74dfbdb06ee246147a304a", size = 14823672, upload-time = "2026-05-18T23:36:16.473Z" }, + { url = "https://files.pythonhosted.org/packages/16/bd/f6d1fede4e54e8042a7ff97bb495510f3c220f94bcd9e8b228e87c92cc0d/numpy-2.4.6-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:e3e5193ef5a3dc73bceee50f7fdc2c90dbb76c42df8d8fae3d1067a583df579e", size = 5328731, upload-time = "2026-05-18T23:36:19.767Z" }, + { url = "https://files.pythonhosted.org/packages/f4/f0/e105b9e2fd728a9910103884decd6951d9dd73896b914a98d9a231de02ee/numpy-2.4.6-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:17f9ade344e7d9b464a084d69bcf18fc691cb1db67c62ed80820bf4926d78f0e", size = 6649805, upload-time = "2026-05-18T23:36:22.266Z" }, + { url = "https://files.pythonhosted.org/packages/82/dd/1206a7ca6ab15e3f02069707ca96222e202af681bb73756da7527f3cb837/numpy-2.4.6-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd5ffd25db4e7ba6a375693b3fc0fc1791ec636c17db3720da19bde7180ec43", size = 15730496, upload-time = "2026-05-18T23:36:25.713Z" }, + { url = "https://files.pythonhosted.org/packages/51/e7/38d3ea825dcab85a591734decb2f6c67caa7c8367d374df1a1c3842f9b07/numpy-2.4.6-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7d92c3819208a60205a12a245c91ad70cb0a85336659b19b834205573ac8456e", size = 16679616, upload-time = "2026-05-18T23:36:29.652Z" }, + { url = "https://files.pythonhosted.org/packages/93/b7/caabfdf53edf663e0b4eb74d7d405d83baef09eb5e83bcd32d601d72b93e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e85b752a1e912b70eaad4fafbd4d1238007ab221de2009b9a2f5ae7461239895", size = 17085145, upload-time = "2026-05-18T23:36:33.449Z" }, + { url = "https://files.pythonhosted.org/packages/f9/45/68d7c33a6bcf3e5aa3bdbd57a367e6f615286dfd6482f97e8ffeb734306e/numpy-2.4.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:29cb7f67d10b479ff07c17d33e39f78c07f71c40ef30d63c153d340e96cd3fb4", size = 18403813, upload-time = "2026-05-18T23:36:37.369Z" }, + { url = "https://files.pythonhosted.org/packages/9c/50/0753655aa844c99cd9e018aacf76f130f1bd81d881bb74bc0aef5d73a8ba/numpy-2.4.6-cp314-cp314t-win32.whl", hash = "sha256:260a5d70215b61ab4fadf5c7baacd64821842975eea312125ed3c39a6391b063", size = 6156982, upload-time = "2026-05-18T23:36:40.817Z" }, + { url = "https://files.pythonhosted.org/packages/b2/d4/7c67becf668f973cb490cec3e98dfd799d866f9c989a54d355672cfa0db6/numpy-2.4.6-cp314-cp314t-win_amd64.whl", hash = "sha256:81a1cca95ed5bb92aa8b10dd2cdc9a0d3853a50fad926c28b5d7e8ea54389627", size = 12638908, upload-time = "2026-05-18T23:36:43.996Z" }, + { url = "https://files.pythonhosted.org/packages/43/bb/e1c71a4295b1b1d1393d50dbb4f2a36283c6859d9d3892e84f00ec5a91d5/numpy-2.4.6-cp314-cp314t-win_arm64.whl", hash = "sha256:0c9136e14ed34a9e343a31c533d78a9813a69a3148332bce5e9821cb2f996e66", size = 10565867, upload-time = "2026-05-18T23:36:47.114Z" }, + { url = "https://files.pythonhosted.org/packages/de/12/b422cc84439adc0d00de605bf4a308890ae5c26f2c71fbd73e5d08fbb0dd/numpy-2.4.6-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:55cced7c52e981362f708ad635198e97a752dfba412cc03c23bbf3bd8d5cd662", size = 16847511, upload-time = "2026-05-18T23:36:50.673Z" }, + { url = "https://files.pythonhosted.org/packages/44/53/f481bef68011740f8849418d82db07230e825013f31f4eef5ba5b805316a/numpy-2.4.6-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d6da64deb6b8ed903e7560180a92f2d804ee1ba5eeb849ac2748b8c1aba1f6d7", size = 14889064, upload-time = "2026-05-18T23:36:53.879Z" }, + { url = "https://files.pythonhosted.org/packages/7f/57/42ed575c10ced8af951d426bc4e1f8aff16fd851db33f067036215a7f860/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:68a5124b13fa6cc2086764a20005d30bc0548146f7f5322f02fce212ca14317f", size = 5394157, upload-time = "2026-05-18T23:36:57.194Z" }, + { url = "https://files.pythonhosted.org/packages/6a/ef/f66cc724fcc36c1e364c67f51ae9146090b8b584f27d58b97fdae3edd737/numpy-2.4.6-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:948424b06129ce883307e8cff868c31396d8dc7630a59c61d70d98dbe70f222c", size = 6708728, upload-time = "2026-05-18T23:36:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/1a/9c/c531f2293b91265d8b48e9b329f54fdd7ffae73cb4134ea10cca4237e9cc/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbbdb29840ca3d91ee0fece42fc29278886d908280bfec0a5846c6f901a3eb0", size = 15798374, upload-time = "2026-05-18T23:37:02.674Z" }, + { url = "https://files.pythonhosted.org/packages/1a/b0/413077f6b1153ed3cba361401c6783bbad6114804a000cc22eb71c13e190/numpy-2.4.6-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ad03c0965fb3c692200e74d458ca28c1dbb4ce96f9a479a8aa041ad5fabca02", size = 16747286, upload-time = "2026-05-18T23:37:06.327Z" }, + { url = "https://files.pythonhosted.org/packages/15/ce/e5ec180bc41812edcd8daeb8639d205622c0e8c02259d8ab25a0201b3c2a/numpy-2.4.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:2803abfebfc990042cd494d8ce2d5f82e9d847af6d35ec486923aa19dbad5e73", size = 12504263, upload-time = "2026-05-18T23:37:09.715Z" }, +] + +[[package]] +name = "numpy" +version = "2.5.1" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.14' and sys_platform == 'win32'", + "python_full_version >= '3.14' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform != 'win32'", +] +sdist = { url = "https://files.pythonhosted.org/packages/22/fd/89965aa4ac08c74998539fcbf24fa3540f3e15237fbeb6bcf9c908f4aade/numpy-2.5.1.tar.gz", hash = "sha256:a48a113e6afea91f5608793bafa7ef2ad481fefbda87ec5069f483de61cb9fa3", size = 20755553, upload-time = "2026-07-04T17:08:00.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7b/14687aa674250e5e546f616f486b0d56d3631cd5b2415739141ce40bdcea/numpy-2.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:2c889b56fe48b1018f764b0eec8df59ab654e9148aa91faa12596043500de277", size = 16801574, upload-time = "2026-07-04T17:06:12.423Z" }, + { url = "https://files.pythonhosted.org/packages/e1/19/cc5bb2a3f2913d27d6dbb2c78d25921fabaedc6741d4a5a615a11f3c5bf3/numpy-2.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ab451b59c5643c570974c43aef780703ef1d3b4965d2be07afd530615a9358d1", size = 11772250, upload-time = "2026-07-04T17:06:15.726Z" }, + { url = "https://files.pythonhosted.org/packages/42/77/fdf34a71dd30f54979b18603bee915e0aaf825b07afe79acd60b04b691e2/numpy-2.5.1-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:78798bd5b9ad744056af8efa90e3b9ddaa53272a0848a483084a1cc0a13b2dc0", size = 5331516, upload-time = "2026-07-04T17:06:17.913Z" }, + { url = "https://files.pythonhosted.org/packages/ce/e2/eb7efa015b4cce41e2517bf182a7fce0d7d5b9d9ed76a29bfa0f4fe4505c/numpy-2.5.1-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:2ae0ca40bcb22d6ba59c1dfd5446f49940b0f2d821fde133f10dda11f816b84e", size = 6664863, upload-time = "2026-07-04T17:06:20.02Z" }, + { url = "https://files.pythonhosted.org/packages/a9/4b/a2b32dd94ee9ffbeecb28152240042a3949db33b1c834d44090b80e1b3b8/numpy-2.5.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61ac47e772e6b8ea489e1d2f441a34c5c3ac17327e7ce294cbdf535795ad4e75", size = 15167977, upload-time = "2026-07-04T17:06:21.621Z" }, + { url = "https://files.pythonhosted.org/packages/b8/a9/6e73d68500f80773f65f0654ea932019d6694329a0eb0ed0533de38df376/numpy-2.5.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:59fda5e192b570217ec2580c96f00e9a7e12ef6866a900eb089b62c1a32545ca", size = 16672469, upload-time = "2026-07-04T17:06:24.064Z" }, + { url = "https://files.pythonhosted.org/packages/24/7d/ad3e59015135f5261c95fd4cafeff159c955febd83a99a1d9250c4233815/numpy-2.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f7119ebff1a9829e9f431a4f9d28e703023bb6b9fe7c8f724467dbfc27c94ab3", size = 16527531, upload-time = "2026-07-04T17:06:26.69Z" }, + { url = "https://files.pythonhosted.org/packages/83/d0/a39b2fbcde9cb17a1dac678f254b33a6336298af9df338824c685425d5e8/numpy-2.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e824c2acf8862052246be5a44c15da1777940c60d010dd2aab897824d9c430f9", size = 18431940, upload-time = "2026-07-04T17:06:29.521Z" }, + { url = "https://files.pythonhosted.org/packages/04/12/cff070947791c1ed425ff76413189adbdc2fbe215eba7ce7fa454a03c7f8/numpy-2.5.1-cp312-cp312-win32.whl", hash = "sha256:08d60c810432eb83360958dea0999ac4cfb94531ea8efcbf0b7f277c2068aeb2", size = 6066764, upload-time = "2026-07-04T17:06:32.571Z" }, + { url = "https://files.pythonhosted.org/packages/65/66/53f31807a48a750f9d748da273bc3fcedd12b27ff1f3e373bfec55ef2dc0/numpy-2.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:f7d60026c0bdb1380e83bfa7a0419c4577ee4b9a08880afcb6dadeb74c649fa2", size = 12430966, upload-time = "2026-07-04T17:06:34.926Z" }, + { url = "https://files.pythonhosted.org/packages/2b/2a/d1a88066b1c14186f5d3c0d18c94f17b064511982bab0578d49ee9d43c29/numpy-2.5.1-cp312-cp312-win_arm64.whl", hash = "sha256:17a25e09640602e10bc8de0e6fa2b3fd68eedd84ba6d7842dc8f32f9ab87bd0b", size = 10350488, upload-time = "2026-07-04T17:06:37.785Z" }, + { url = "https://files.pythonhosted.org/packages/eb/07/ec2a3f0c91761581d4b7104a740791800025983f9a4dc4e73f91a99aeac4/numpy-2.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0bfebd8695f9863592fe744be833a258120b14a9f39da255e8aa8fade2c0ddd1", size = 16796419, upload-time = "2026-07-04T17:06:40.37Z" }, + { url = "https://files.pythonhosted.org/packages/ab/ab/ddb499fc4f8780354395face5b65c7fd107bcd6e1d667a5f07d046956f6f/numpy-2.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:30b44a6b53a7ae63c54c089a8726e5563ed302716c5b7ccc85afade40b0e7ff6", size = 11765832, upload-time = "2026-07-04T17:06:42.768Z" }, + { url = "https://files.pythonhosted.org/packages/88/b3/3c28c558a09fc72100c646dac6d2fce8e834c471b0edca01a29996706117/numpy-2.5.1-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:6165343f81b56ef8f514f396989e529b61d9dc709b99421b07e9f3e698e2287d", size = 5325143, upload-time = "2026-07-04T17:06:45.466Z" }, + { url = "https://files.pythonhosted.org/packages/5e/0e/ce19b985bb15c596f4f05954e76cccc77c845083b3b8f938a6c68e523128/numpy-2.5.1-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:4939237038ada79308dda3204ac6462df056b5672b2e25db1149cf873668b3e1", size = 6659749, upload-time = "2026-07-04T17:06:47.288Z" }, + { url = "https://files.pythonhosted.org/packages/2e/20/1ee6614d64332a1bba6411f38e68cb79eec1b2459e20a623777c5c5492a2/numpy-2.5.1-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c6759f538fb912fc46de0a6b1758ccf7b57bc7c7ebebc23974fdac3de8db0cd", size = 15164716, upload-time = "2026-07-04T17:06:49.494Z" }, + { url = "https://files.pythonhosted.org/packages/ed/a7/2bcd3fdbb87804755c35b729bf8709d62025c5f4cfd7d5b2415997097515/numpy-2.5.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9726558e8db4a5bf7929a70ae50f63abda4daf0efe810e3bfbab95976f75fc1a", size = 16661440, upload-time = "2026-07-04T17:06:52.061Z" }, + { url = "https://files.pythonhosted.org/packages/fc/d7/a41e3310c886fe457d36e670bbf24fae411aca8a7b6ad92a32afd924077c/numpy-2.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3935f3b419b244a02732676fa5317a9193cc596a4c0646db07e5b421229ac9f7", size = 16526305, upload-time = "2026-07-04T17:06:54.605Z" }, + { url = "https://files.pythonhosted.org/packages/53/75/4333a9a707c1edd3a4e1a0c58eca52c0f31e55089fa80db02b5565b24df7/numpy-2.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:dc932a65ded7ce9013d120845a2514dcccb1a67bfc8deb8d37633762951904a6", size = 18423008, upload-time = "2026-07-04T17:06:57.54Z" }, + { url = "https://files.pythonhosted.org/packages/ee/90/e314a32b1c11a2ffe818ddad3a57b50b4b6e1b6c487192eb50cdef0415d0/numpy-2.5.1-cp313-cp313-win32.whl", hash = "sha256:4b4ff1608417eb7a59da7b967bbb798cacfe071d2caf526a24281cd562072ed9", size = 6063885, upload-time = "2026-07-04T17:07:00.14Z" }, + { url = "https://files.pythonhosted.org/packages/10/70/800b3fca480af32df9e8ea9f3d4a0c8feb4b32d7f195d174eabbda4829ad/numpy-2.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:6c3fe51bc6a16453d452997053454f309e8e0ed7b42d6b361ce4ac8c32913d74", size = 12425674, upload-time = "2026-07-04T17:07:02.387Z" }, + { url = "https://files.pythonhosted.org/packages/8b/0b/196350c122f50f6ca56846f2d71efd5e0d24b7b2e07355e019b2e2c7a11e/numpy-2.5.1-cp313-cp313-win_arm64.whl", hash = "sha256:f7feb014281029e628ba2d5a007407443b06e418b6fe451d1e2adcbc8eba0107", size = 10350256, upload-time = "2026-07-04T17:07:04.878Z" }, + { url = "https://files.pythonhosted.org/packages/db/f4/731b6085a83faf6ca843394cbd5e217280c214399f7e8b21b9f552af0ae2/numpy-2.5.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:7c786fe9a5bbe360022e584c5a34cf6b54265c71bd7ec8ac3d8fec38968071f8", size = 16795063, upload-time = "2026-07-04T17:07:07.374Z" }, + { url = "https://files.pythonhosted.org/packages/bf/64/0e215f2048dd11a55bb989ed41b3585ef57452404e638d703a211a3e4157/numpy-2.5.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:32985c896d897419ef8da6917872d80b78ad0ea26d85b23245c7366ffde76d75", size = 11776652, upload-time = "2026-07-04T17:07:09.907Z" }, + { url = "https://files.pythonhosted.org/packages/b5/59/2b844c7a6e9deff69b404a66221e1542937734f65d5e6e39411876053862/numpy-2.5.1-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:efd736408cc97c79b9e6917338dfc8f06013b2274f992e96b1d9a81a71e2a2c2", size = 5335944, upload-time = "2026-07-04T17:07:12.227Z" }, + { url = "https://files.pythonhosted.org/packages/86/51/9bf7cb2cabcebc9e017e4ec7e6322b378317a542c08b4cb68479c1efc716/numpy-2.5.1-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:ab84dc6b074fa881cae55bea94cc4f68e285181ba7f32497bf7dee6b1496165b", size = 6656266, upload-time = "2026-07-04T17:07:14.368Z" }, + { url = "https://files.pythonhosted.org/packages/83/3e/fb7615b211b82a32f44d5180a6d421b61f84d4fadd578b48ba4ac34e189f/numpy-2.5.1-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:caf3e317d33d60c37986b452613f4ab51246d0691350c03d0cb4a898627f4a95", size = 15179720, upload-time = "2026-07-04T17:07:16.272Z" }, + { url = "https://files.pythonhosted.org/packages/41/5f/0f992cb24560673496c5d68de61913b57166ce530ffda07c1f280e0cc464/numpy-2.5.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:54ad769f17bc2d833b620851989f62054fb9ab93c969d9e1dc3c8e3d56beea21", size = 16664835, upload-time = "2026-07-04T17:07:19.021Z" }, + { url = "https://files.pythonhosted.org/packages/a2/2f/97d6475ee91afe2587797d09446f9d3e475ad4cb681662d824809327b75a/numpy-2.5.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c12afb53450fa976d4c681c50a7423729a4c51c0465ed9f32b8a9cabbc472373", size = 16539135, upload-time = "2026-07-04T17:07:22.015Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5b/4db81e4ba0be7e2776b1de68c82aa862c7f8ec27e1b4927d4ae075e20678/numpy-2.5.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:e8c11c405efc5ff6816d5983c96cdfa215bab3428961243af3ff59b228490438", size = 18426684, upload-time = "2026-07-04T17:07:24.941Z" }, + { url = "https://files.pythonhosted.org/packages/1f/64/c0ba2d90724d450279a7df8f32057241070250a26a7e2b5337d77347f481/numpy-2.5.1-cp314-cp314-win32.whl", hash = "sha256:f2479a47f8d5932d1718168a681ad6e536a9df484c83cfcf9de365e164537ace", size = 6116103, upload-time = "2026-07-04T17:07:27.622Z" }, + { url = "https://files.pythonhosted.org/packages/c1/1a/837f9ed7405adcd7a40538792eb169eddd8fa5630c16a1ef49dae71a30f4/numpy-2.5.1-cp314-cp314-win_amd64.whl", hash = "sha256:24d0eb82c0541d3415a33425db64ae439dffccd7b4dbcb30e7c35120205c506a", size = 12562177, upload-time = "2026-07-04T17:07:29.887Z" }, + { url = "https://files.pythonhosted.org/packages/22/ed/49707938b6dd0a78a9178dd93227dc89e4c11af47f5c798d70366e8d0483/numpy-2.5.1-cp314-cp314-win_arm64.whl", hash = "sha256:5a4c988b38d261deeeaad9954e3deb091ad905c94e8bb6708654ef1d97f286b0", size = 10627739, upload-time = "2026-07-04T17:07:32.568Z" }, + { url = "https://files.pythonhosted.org/packages/a6/c7/bb4b882cfe7f299cbc8b66e42e7dd78cf9d14e40f9469fc5e3db7e15b3bd/numpy-2.5.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a33276be12fa045805f477f22482088b66bb758ffbe89a9d21457de863a32e22", size = 11894709, upload-time = "2026-07-04T17:07:34.941Z" }, + { url = "https://files.pythonhosted.org/packages/40/3f/5af7f4a7f6224aef48017aa82bb6174c7a659d724be0c75017b7e64a55b4/numpy-2.5.1-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:f089d7b00756190aacf1f5d34bdf38c3c430ac82b4f868f8cede73380460fce7", size = 5453810, upload-time = "2026-07-04T17:07:37.495Z" }, + { url = "https://files.pythonhosted.org/packages/20/c9/3474309bc94d634d3f9c3eddf03250ecb8c22cd948ef16fef69a77cc5d7b/numpy-2.5.1-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:09e9bfd8d2cf479c7d174804fb3811c53a8e9f20a37444008606b57d6b7a826d", size = 6761189, upload-time = "2026-07-04T17:07:39.563Z" }, + { url = "https://files.pythonhosted.org/packages/90/8a/558ae39fdd55d7e7f7fef9a84a6e964ac6b23edbd2a07e52bb084500507d/numpy-2.5.1-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e68d8dd1e7eba712948f2053a29ec86917bc70ba1358df869d9f06649ef9cf09", size = 15225039, upload-time = "2026-07-04T17:07:41.682Z" }, + { url = "https://files.pythonhosted.org/packages/63/27/ca7392b2d030277bdf0273e7d23255b3ee57d57a7c170a6f4fb3981e1e5d/numpy-2.5.1-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99d5095fa265a0c4152e7bb12759e14381ef5496152f1ce58f44bdf55c44beb4", size = 16701306, upload-time = "2026-07-04T17:07:44.611Z" }, + { url = "https://files.pythonhosted.org/packages/02/42/03d53ae7996c44d4374a8262e9dc41671fd56cbb98f7d47ef85cf5da4c6b/numpy-2.5.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ab87a91b3cc3382b8956095bd8f95e00cf679bb81554339be1a2ba404a1473c1", size = 16589955, upload-time = "2026-07-04T17:07:47.694Z" }, + { url = "https://files.pythonhosted.org/packages/7b/15/6c1784ae469640e65db111e9a34b3d0f14d91e8a38b9ce34810ced370dbb/numpy-2.5.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:224ca51130ef7da85bea2191625181cb4f337f9cb64b471f10c1a12aa8b60077", size = 18464252, upload-time = "2026-07-04T17:07:50.684Z" }, + { url = "https://files.pythonhosted.org/packages/94/a8/f98e50356cf167df656c526c2dfeec2d7dde182f2a3da4b458a5938e2776/numpy-2.5.1-cp314-cp314t-win32.whl", hash = "sha256:6eab239876581b2b3c5a242281b6007bbdbcd1c7085d7709bb57c5929b11e6bf", size = 6263298, upload-time = "2026-07-04T17:07:53.445Z" }, + { url = "https://files.pythonhosted.org/packages/72/ac/96ae880cdecad0b3275d9359fcec72667b49a4863c9f12942e43679dda02/numpy-2.5.1-cp314-cp314t-win_amd64.whl", hash = "sha256:83ce9c80d5b521b0d77ddcbe5447c218d247929b6cc056ca5351342accfff0af", size = 12748623, upload-time = "2026-07-04T17:07:55.384Z" }, + { url = "https://files.pythonhosted.org/packages/a1/5a/4d2b1601df3602dba7a14f3348ba9bfe94a18adb428e693df6154c293831/numpy-2.5.1-cp314-cp314t-win_arm64.whl", hash = "sha256:5a6db61f9aaa57e369905c67d852045d3c4f7126405b29d09b19dec118e9c9cb", size = 10697674, upload-time = "2026-07-04T17:07:58.506Z" }, +] + [[package]] name = "openai" version = "2.44.0" @@ -1130,6 +2046,67 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/17/83/6dba32b85f31868400440dc7ad2ca1eab94cbbf3a7b0459ed39f8311a9e2/opentelemetry_api-1.43.0-py3-none-any.whl", hash = "sha256:20acf45e9b21851926835292e4045d290acade1edd2ff3de86d2f069687ba1fd", size = 61912, upload-time = "2026-06-24T15:19:35.434Z" }, ] +[[package]] +name = "opentelemetry-exporter-otlp" +version = "1.43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-exporter-otlp-proto-grpc" }, + { name = "opentelemetry-exporter-otlp-proto-http" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/ee/47/b77366bcbe719373a8cac2b4e8ad01f8ff3c9f2c223374d77ece280aae6f/opentelemetry_exporter_otlp-1.43.0.tar.gz", hash = "sha256:65aded6c50ee7dd2b9948c9d0e59ddb4ed4eea6e8532fba95cbe6a4a64a566ba", size = 6086, upload-time = "2026-06-24T15:19:58.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d9/26/d28cc854d2eb779f91351216c51ed0d54886f89f2dd56db9d493ba9fd429/opentelemetry_exporter_otlp-1.43.0-py3-none-any.whl", hash = "sha256:70f3fe740a64596d4157588a2ee7e4fd37d2acc0c0f522a2882b8c29316cd0f0", size = 6726, upload-time = "2026-06-24T15:19:38.437Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-common" +version = "1.43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "opentelemetry-proto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/c1/e8098490ab15abf116dcaf9fa89ededcb35547c7d08d4b5a62f573dc1e63/opentelemetry_exporter_otlp_proto_common-1.43.0.tar.gz", hash = "sha256:c4e32ba6d6b13bdb2b8f6764c4fd28d00192826561aa04f6d14eedfce7ac076f", size = 20197, upload-time = "2026-06-24T15:20:00.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/d0/b2/41ebc74ae1d5859901f1b69305de58724bf043381103d6ef413521cbc35a/opentelemetry_exporter_otlp_proto_common-1.43.0-py3-none-any.whl", hash = "sha256:123c3f9cc87218562490c63b36f497bf3a722faf174a515d1443f31ababa6264", size = 17048, upload-time = "2026-06-24T15:19:41.264Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-grpc" +version = "1.43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "grpcio" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e2/1d/6336453716ca0a240d4417d19e6d5b77a5e7163e5670ec4f7ec4d3ede7bf/opentelemetry_exporter_otlp_proto_grpc-1.43.0.tar.gz", hash = "sha256:1b3e0627daa9bc21884d4a13946807c255eb558bfe5bdd543dffb6f4c9faee0d", size = 27213, upload-time = "2026-06-24T15:20:00.907Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6d/74/2700b5d5c946bf2dba87073fce3dfc198c46bc92ea3d5693f54bc51c90b1/opentelemetry_exporter_otlp_proto_grpc-1.43.0-py3-none-any.whl", hash = "sha256:6a10d1feacffffda19acacbf277b736094b1e2f4dbb98c90ccb2c6e1962e2ec6", size = 19626, upload-time = "2026-06-24T15:19:42.233Z" }, +] + +[[package]] +name = "opentelemetry-exporter-otlp-proto-http" +version = "1.43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "googleapis-common-protos" }, + { name = "opentelemetry-api" }, + { name = "opentelemetry-exporter-otlp-proto-common" }, + { name = "opentelemetry-proto" }, + { name = "opentelemetry-sdk" }, + { name = "requests" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fc/92/0b9f56412483a8891d4843890294796c9df8ab42417bd9bad8035d840cb3/opentelemetry_exporter_otlp_proto_http-1.43.0.tar.gz", hash = "sha256:fa8a42bb7d00ee5391f4c0b04d8e6a46c03caa437903296ab73a81dc11ba118f", size = 25406, upload-time = "2026-06-24T15:20:01.515Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/20/b685ed7af2e17c29ffc8af56f1fa8bc2033258fc30fb0d2b722f49d13ba0/opentelemetry_exporter_otlp_proto_http-1.43.0-py3-none-any.whl", hash = "sha256:647f603aa8efdbdb4dbff842e0729d0406a6fff26b295a72d3d60e7d963b2610", size = 21795, upload-time = "2026-06-24T15:19:43.164Z" }, +] + [[package]] name = "opentelemetry-instrumentation" version = "0.64b0" @@ -1145,6 +2122,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d2/0c/cb9fe342de5299c7af24582eb7d788661cc53a1c4b904da92309caaa9417/opentelemetry_instrumentation-0.64b0-py3-none-any.whl", hash = "sha256:133ab7ffca796557aec059bf6be3190a34b6dea987f25be3d9409e230cbdad8b", size = 35880, upload-time = "2026-06-24T15:18:17.277Z" }, ] +[[package]] +name = "opentelemetry-instrumentation-genai-agentscope" +source = { editable = "instrumentation/opentelemetry-instrumentation-genai-agentscope" } +dependencies = [ + { name = "opentelemetry-api" }, + { name = "opentelemetry-instrumentation" }, + { name = "opentelemetry-semantic-conventions" }, + { name = "opentelemetry-util-genai" }, +] + +[package.optional-dependencies] +instruments = [ + { name = "agentscope", version = "1.0.21", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "agentscope", version = "2.0.4.post1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] + +[package.metadata] +requires-dist = [ + { name = "agentscope", marker = "extra == 'instruments'", specifier = ">=1.0.0,<3.0.0" }, + { name = "opentelemetry-api", specifier = "~=1.43" }, + { name = "opentelemetry-instrumentation", specifier = ">=0.64b0,<1" }, + { name = "opentelemetry-semantic-conventions", specifier = ">=0.64b0,<1" }, + { name = "opentelemetry-util-genai", editable = "util/opentelemetry-util-genai" }, +] +provides-extras = ["instruments"] + [[package]] name = "opentelemetry-instrumentation-genai-anthropic" source = { editable = "instrumentation/opentelemetry-instrumentation-genai-anthropic" } @@ -1316,6 +2319,18 @@ requires-dist = [ ] provides-extras = ["instruments"] +[[package]] +name = "opentelemetry-proto" +version = "1.43.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "protobuf" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e0/b9/d357faefb40bda1d4799913e6af611171ff22a2dedcb93576bc92242d056/opentelemetry_proto-1.43.0.tar.gz", hash = "sha256:224778df17e1f3fafeaaa21d874236ca5f6ffc2f86e0899298ec7351aac27924", size = 46481, upload-time = "2026-06-24T15:20:07.625Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ed/a7/3e5308cf548b8f72529c7db1afdb3a404211982376a12927fd7759f77bf3/opentelemetry_proto-1.43.0-py3-none-any.whl", hash = "sha256:c58f1f7ef84bc7dc2834016c0c37fe0081dde7ca9f6339be1970fbf9cdaaa90d", size = 72489, upload-time = "2026-06-24T15:19:51.164Z" }, +] + [[package]] name = "opentelemetry-python-genai" version = "0.0.0" @@ -1649,6 +2664,134 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/80/6e/4b28b62ecb6aae56769c34a8ff1d661473ec1e9519e2d5f8b2c150086b26/pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b", size = 226472, upload-time = "2026-04-21T20:31:40.092Z" }, ] +[[package]] +name = "propcache" +version = "0.5.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ec/44/c87281c333769159c50594f22610f77398a47ccbfbbf23074e744e86f87c/propcache-0.5.2.tar.gz", hash = "sha256:01c4fc7480cd0598bb4b57022df55b9ca296da7fc5a8760bd8451a7e63a7d427", size = 50208, upload-time = "2026-05-08T21:02:12.199Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/56/030b7b4719d53085722893e0009dffb9236aa10bca1b12121bdc5626ef16/propcache-0.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d5a81be28596d6559f6131ef33e10200de6e17643b3c74ce03f9eb103be6ae8b", size = 93417, upload-time = "2026-05-08T20:59:15.597Z" }, + { url = "https://files.pythonhosted.org/packages/1a/55/1140a8e067b8ec093a18a4ae7bb0045d9db65da38a08618ddc5e2f1994aa/propcache-0.5.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29cbaac5ea0212663e6845e04b5e188d5a6ae6dd919810ac835bf1d3b42c3f4c", size = 53847, upload-time = "2026-05-08T20:59:17.096Z" }, + { url = "https://files.pythonhosted.org/packages/20/42/0e7443c90310498561addf346e7d57fe3c6ba1914e1ba938b5464c7bbfd2/propcache-0.5.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6bf3be92233808fcd338eba0fb4d0b59ec5772af4f4ecfcec450d1bfc0f8b5eb", size = 53512, upload-time = "2026-05-08T20:59:18.64Z" }, + { url = "https://files.pythonhosted.org/packages/b7/db/cf51a71bab2009517d1a7f0ee07657e3bd446c4d69f67e6966cf17bcf956/propcache-0.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f8ea531c794b9d6274acd4e8d2c2ebcac590a4361d27482edd3010b79f1325e", size = 58068, upload-time = "2026-05-08T20:59:20.683Z" }, + { url = "https://files.pythonhosted.org/packages/b7/43/39b6bdee9699fa1e1641c519feeb64a67e2a9f93bb465c70776b37a7333f/propcache-0.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:decfca4c79dd53ebab484b00cc4b6717d8c369f86e74aa4ca395a64ac651495e", size = 61020, upload-time = "2026-05-08T20:59:22.112Z" }, + { url = "https://files.pythonhosted.org/packages/26/0b/843726fbb0a29a8c5684fdb25971823638399f31e52e9d1f06a02dc9aa6b/propcache-0.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4621064bbf28fa77ff64dd5d94367c04684c67d3a5bf1dff25f0cd0d98a38f3b", size = 62732, upload-time = "2026-05-08T20:59:23.805Z" }, + { url = "https://files.pythonhosted.org/packages/39/6e/899fed76dc1942b8a64193a4f059d7f1a2c7ef65085e8a9366ed8ec0d199/propcache-0.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b96db7141a592cbc968daf1feea83a118e6ab378af4abbc72b248c895414c22d", size = 60140, upload-time = "2026-05-08T20:59:25.389Z" }, + { url = "https://files.pythonhosted.org/packages/ab/09/3da4be9b5b879219ad234aa535b3dd4a080ed1ad48d3a73ca07a9e798f22/propcache-0.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1ca071adabaab6e9219924bbe00af821f1ee7de113a9eca1cdc292de3d120f4d", size = 60400, upload-time = "2026-05-08T20:59:27.238Z" }, + { url = "https://files.pythonhosted.org/packages/60/2f/09b72b874a9aa0044faf52a69807a6ed618e267ceaa9ec4a63195fa5b504/propcache-0.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:e4294d04a94dcab1b3bccd8b66d962dcad411a1d19414b2a41d1445f1de32ad0", size = 58155, upload-time = "2026-05-08T20:59:28.48Z" }, + { url = "https://files.pythonhosted.org/packages/8a/37/97489848c54c95578045473954f10956d619ce6a09e7ac137b71cdcb698b/propcache-0.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:a0e399a2eccb91ed18721f86aa85757727400b6865c89e88934781deb9c8498b", size = 57037, upload-time = "2026-05-08T20:59:30.146Z" }, + { url = "https://files.pythonhosted.org/packages/22/db/6c695285ccfc49012743ee9c98212b8c5dd0aed7b63cfd816d4a0f7a1601/propcache-0.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:823581fd5cb08b12a48bfa11fe962a7916766b6170c17b028fbdf762b85eb9bf", size = 61103, upload-time = "2026-05-08T20:59:31.626Z" }, + { url = "https://files.pythonhosted.org/packages/98/a9/1e500401ca593b0bdb6bf75a70bc2d723835fd53360edff6af70692c7546/propcache-0.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:949c91d1a990cf3b2e8188dfcfb25005e0b834a06c63fa4ef9f360878ce21ecf", size = 60394, upload-time = "2026-05-08T20:59:32.829Z" }, + { url = "https://files.pythonhosted.org/packages/1f/87/f638b6e375eae0f30a1a2325d8b34fd85fdc785bb9960cf805f3bf1ec69a/propcache-0.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:cc1177027eda740fdb152706bd215a3f124e3eea15afc39f2cb9fe351b50619e", size = 63084, upload-time = "2026-05-08T20:59:35.964Z" }, + { url = "https://files.pythonhosted.org/packages/f6/18/884573f5d97b6d9eba68de759a82c901b7e39d7904d30f7b8d58d42d2a12/propcache-0.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b05d643f944a8c3c4bd86d65ffd87bf3264b617f87791940302bc474d2ff5274", size = 60999, upload-time = "2026-05-08T20:59:38.481Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1a/c3915eb059ceec9e758a56e4cfd955292bc0f201be2176a46b76d94b303a/propcache-0.5.2-cp310-cp310-win32.whl", hash = "sha256:8114f28879e0904748e831c3a7774261bd9e75f49be089f389a76f959dcd13fe", size = 39036, upload-time = "2026-05-08T20:59:40.323Z" }, + { url = "https://files.pythonhosted.org/packages/5b/02/1dfd5607501a602d19c1c449d2d193b7d1c611f9246b4059026a1189a80e/propcache-0.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:5fcb98e7598b1ee0addab320d90f65b530297a867dbfe9de52ea838077e16e3d", size = 42190, upload-time = "2026-05-08T20:59:42.232Z" }, + { url = "https://files.pythonhosted.org/packages/57/93/f71588ad08b3e6f4b555b5ef215808a3c02b042d0151ad82fa6f15be677a/propcache-0.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:04dc2390d9edbbaef7461f33322555976ffddf0b650a038649d026358714e6c5", size = 38545, upload-time = "2026-05-08T20:59:44.087Z" }, + { url = "https://files.pythonhosted.org/packages/e7/f1/8a8cc1c2c7e7934ab77e0163414f736fadbc0f5e8dd9673b952355ac175b/propcache-0.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:74b70780220e2dd89175ca24b81b68b67c83db499ae611e7f2313cb329801c78", size = 90744, upload-time = "2026-05-08T20:59:45.799Z" }, + { url = "https://files.pythonhosted.org/packages/c2/f4/651b1225e976bd1a2ba5cfba0c29d096581c2636b437e3a9a7ab6276270a/propcache-0.5.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a4840ab0ae0216d952f4b53dc6d0b992bfc2bedbfe360bdd9b548bc184c08959", size = 52033, upload-time = "2026-05-08T20:59:47.408Z" }, + { url = "https://files.pythonhosted.org/packages/15/a8/8ede85d6aa1f79fc7dc2f8fd2c8d65920b8272c3892903c8a1affde48cfb/propcache-0.5.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6844ba6364fb12f403928a82cfd295ab103a2b315c77c747b2dbe4a41894ea7", size = 52754, upload-time = "2026-05-08T20:59:49.202Z" }, + { url = "https://files.pythonhosted.org/packages/7d/fe/b3551b41bbc2f5b5bb088fc6920567cd43101253e68fbaa261339eb96fe1/propcache-0.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2293949b855ce597f2826452d17c2d545fb5622379c4ea6fdf525e9b8e8a2511", size = 57573, upload-time = "2026-05-08T20:59:50.778Z" }, + { url = "https://files.pythonhosted.org/packages/83/27/ab851ebd1b7172e3e161f5f8d39e315d54a91bea246f01f4d872d3376aef/propcache-0.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:0fd59b5af35f74da48d905dcbad55449ba13be91823cb05a9bd590bbf5b61660", size = 60645, upload-time = "2026-05-08T20:59:52.227Z" }, + { url = "https://files.pythonhosted.org/packages/95/7d/466b3d18022e9897cbda9c735c493c5bd747d7a4c6f5ea1480b4cec434b6/propcache-0.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29f9309a2e42b0d273be006fdb4be2d6c39a47f6f57d8fb1cf9f81481df81b66", size = 61563, upload-time = "2026-05-08T20:59:53.866Z" }, + { url = "https://files.pythonhosted.org/packages/27/1b/16ab7f2cf2041da2f60d156ba64c2484eadf9168075b4ff43c3ef60045af/propcache-0.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5aaa2b923c1944ac8febd6609cb373540a5563e7cbcb0fd770f75dace2eb817b", size = 58888, upload-time = "2026-05-08T20:59:55.457Z" }, + { url = "https://files.pythonhosted.org/packages/0a/67/bb777ffd907633563bf35fd859c4ce97b0512c32f4633cf5d1eb7c33512b/propcache-0.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:66ea454f095ddf5b6b14f56c064c0941c4788be11e18d2464cf643bf7203ff67", size = 59253, upload-time = "2026-05-08T20:59:57.075Z" }, + { url = "https://files.pythonhosted.org/packages/b9/42/64f8d90b73fd9cdc1499b48057ff6d9cd2a98a25734c9bb62ecf07e87061/propcache-0.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:95f1e3f4760d404b13c9976c0229b2b49a3c8e2c62a9ce92efdd2b11ada75e3f", size = 57558, upload-time = "2026-05-08T20:59:58.602Z" }, + { url = "https://files.pythonhosted.org/packages/eb/02/dba5bc03c9041f2092ea55a449caf5dfe68352c6654511b29ba0654ddb69/propcache-0.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:85341b12b9d55bad0bded24cac341bb34289469e03a11f3f583ea1cc1db0326c", size = 55007, upload-time = "2026-05-08T20:59:59.837Z" }, + { url = "https://files.pythonhosted.org/packages/14/c0/43f649c7aa2a77a3b100d84e9dea3a483120ecb608bfe36ce49eaff517fe/propcache-0.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:26a4dca084132874e639895c3135dfad5eb20bae209f62d1aeb31b03e601c3c0", size = 60355, upload-time = "2026-05-08T21:00:01.144Z" }, + { url = "https://files.pythonhosted.org/packages/83/c0/435dafd27f1cb4a495381dae60e25883ccfe4020bb72818e8184c1678092/propcache-0.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:3b199b9b2b3d6a7edf3183ba8a9a137a22b97f7df525feb5ae1eccf026d2a9c6", size = 59057, upload-time = "2026-05-08T21:00:02.401Z" }, + { url = "https://files.pythonhosted.org/packages/53/ae/6e292df9135d659944e96cb3389258e4a663e5b2b5f6c217ef0ddc8d2f73/propcache-0.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:e59bc9e66329185b93dab73f210f1a37f81cb40f321501db8017c9aea15dba27", size = 61938, upload-time = "2026-05-08T21:00:03.638Z" }, + { url = "https://files.pythonhosted.org/packages/0b/42/314ebc50d8159055411fd6b0bda322ff510e4b1f7d2e4927940ad0f6af20/propcache-0.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:552ffadf6ad409844bc5919c42a0a83d88314cedddaea0e41e80a8b8fffe881f", size = 59731, upload-time = "2026-05-08T21:00:04.881Z" }, + { url = "https://files.pythonhosted.org/packages/b8/9b/2da6dee38871c3c8772fabc2758325a5c9077d6d18c597737dc04dd884cd/propcache-0.5.2-cp311-cp311-win32.whl", hash = "sha256:cd416c1de191973c52ff1a12a57446bfc7642797b282d7caf2162d7d1b8aa9a0", size = 38966, upload-time = "2026-05-08T21:00:06.511Z" }, + { url = "https://files.pythonhosted.org/packages/42/4e/f17363fb58c0afe05b067361cb6d86ed2d29de6506779a27547c4d183075/propcache-0.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:44e488ef40dbb452700b2b1f8188934121f6648f52c295055662d2191959ff82", size = 42135, upload-time = "2026-05-08T21:00:08.088Z" }, + { url = "https://files.pythonhosted.org/packages/c6/eb/6af6685077d22e8b33358d3c548e3282706a0b3cd85044ffba4e5dd08e3b/propcache-0.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:54adaa85a22078d1e306304a40984dc5be99d599bf3dc0a24dc98f7daeab89ab", size = 38381, upload-time = "2026-05-08T21:00:09.692Z" }, + { url = "https://files.pythonhosted.org/packages/4a/cb/e27bc2b2737a0bb49962b275efa051e8f1c35a936df7d5139b6b658b7dc9/propcache-0.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:806719138ecd720339a12410fb9614ac9b2b2d3a5fdf8235d56981c36f4039ba", size = 95887, upload-time = "2026-05-08T21:00:11.277Z" }, + { url = "https://files.pythonhosted.org/packages/e6/13/b8ae04c59392f8d11c6cd9fb4011d1dc7c86b81225c770280300e259ffe1/propcache-0.5.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:db2b80ea58eab4f86b2beec3cc8b39e8ff9276ac20e96b7cce43c8ae84cd6b5a", size = 54654, upload-time = "2026-05-08T21:00:12.604Z" }, + { url = "https://files.pythonhosted.org/packages/2c/7d/49777a3e20b55863d4794384a38acd460c04157b0a00f8602b0d508b8431/propcache-0.5.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e5cbfac9f61484f7e9f3597775500cd3ebe8274e9b050c38f9525c77c97520bf", size = 55190, upload-time = "2026-05-08T21:00:13.935Z" }, + { url = "https://files.pythonhosted.org/packages/44/c7/085d0cd63062e84044e3f05797749c3f8e3938ff3aeb0eb2f69d43fafc91/propcache-0.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5dbc581d2814337da56222fab8dc5f161cd798a434e49bac27930aaef798e144", size = 59995, upload-time = "2026-05-08T21:00:15.526Z" }, + { url = "https://files.pythonhosted.org/packages/9c/42/32cf8e3009e92b2645cf1e944f701e8ea4e924dffde1ee26db860bcbf7e4/propcache-0.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:857187f381f88c8e2fa2fe56ab94879d011b883d5a2ee5a1b60a8cd2a06846d9", size = 63422, upload-time = "2026-05-08T21:00:16.824Z" }, + { url = "https://files.pythonhosted.org/packages/9e/1b/f112433f99fc979431b87a39ef169e3f8df070d99a72792c56d6937ac48b/propcache-0.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:178b4a2cdaac1818e2bf1c5a99b94383fa73ea5382e032a48dec07dc5668dc42", size = 64342, upload-time = "2026-05-08T21:00:18.362Z" }, + { url = "https://files.pythonhosted.org/packages/14/15/5574111ae50dd6e879456888c0eadd4c5a869959775854e18e18a6b345f3/propcache-0.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f328175a2cde1f0ff2c4ed8ce968b9dcfb55f3a7153f39e2957ed994da13476", size = 61639, upload-time = "2026-05-08T21:00:19.692Z" }, + { url = "https://files.pythonhosted.org/packages/cc/da/4d775080b1490c0ae604acda868bd71aabe3a89ed16f2aa4339eb8a283e7/propcache-0.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5671d09a36b06d0fd4a3da0fccbcae360e9b1570924171a15e9e0997f0249fba", size = 61588, upload-time = "2026-05-08T21:00:21.155Z" }, + { url = "https://files.pythonhosted.org/packages/04/ac/f076982cbe2195ee9cf32de5a1e46951d9fb399fc207f390562dd0fd8fb2/propcache-0.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:80168e2ebe4d3ec6599d10ad8f520304ae1cad9b6c5a95372aef1b66b7bfb53a", size = 60029, upload-time = "2026-05-08T21:00:22.713Z" }, + { url = "https://files.pythonhosted.org/packages/70/60/189be62e0dd898dce3b331e1b8c7a543cd3a405ac0c81fe8ee8a9d5d77e1/propcache-0.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:45f11346f884bc47444f6e6647131055844134c3175b629f84952e2b5cd62b64", size = 56774, upload-time = "2026-05-08T21:00:24.001Z" }, + { url = "https://files.pythonhosted.org/packages/ea/9e/93377b9c7939c1ffae98f878dee955efadfd638078bc86dbc21f9d52f651/propcache-0.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8e778ebd44ef4f66ed60a0416b06b489687db264a9c0b3620362f26489492913", size = 63532, upload-time = "2026-05-08T21:00:25.545Z" }, + { url = "https://files.pythonhosted.org/packages/14/f9/590ef6cfb9b8028d516d287812ece32bb0bc5f11fbb9c8bf6b2e6313fec8/propcache-0.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:c0cb9ed24c8964e172768d455a38254c2dd8a552905729ce006cad3d3dda59b1", size = 61592, upload-time = "2026-05-08T21:00:27.186Z" }, + { url = "https://files.pythonhosted.org/packages/b4/5e/70958b3034c297a630bba2f17ca7abc2d5f39a803ad7e370ab79d1ecd022/propcache-0.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:1d1ad32d9d4355e2be65574fd0bfd3677e7066b009cd5b9b2dee8aa6a6393b33", size = 64788, upload-time = "2026-05-08T21:00:28.8Z" }, + { url = "https://files.pythonhosted.org/packages/12/fd/77fe5936d8c3086ca9048f7f415f122ed82e53884a9ec193646b42deef06/propcache-0.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c80f4ba3e8f00189165999a742ee526ebeccedf6c3f7beb0c7df821e9772435a", size = 62514, upload-time = "2026-05-08T21:00:30.098Z" }, + { url = "https://files.pythonhosted.org/packages/cf/74/66bd798b5b3be70aa1b391f5cc9d6a0a5532d7fd3b19ec0b213e72e6ad9d/propcache-0.5.2-cp312-cp312-win32.whl", hash = "sha256:8c7972d8f193740d9175f0998ab38717e6cd322d5935c5b0fef8c0d323fd9031", size = 39018, upload-time = "2026-05-08T21:00:31.622Z" }, + { url = "https://files.pythonhosted.org/packages/61/7c/5c0d34aa3024694d6dcb9271cdbdd08c4e47c1c0ad95ec7e7bc74cdea145/propcache-0.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:d9ee8826a7d47863a08ac44e1a5f611a462eefc3a194b492da242128bec75b42", size = 42322, upload-time = "2026-05-08T21:00:32.918Z" }, + { url = "https://files.pythonhosted.org/packages/4d/91/875812f1a3feb20ceba818ef39fbe4d92f1081e04ac815c822496d0d038b/propcache-0.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:2800a4a8ead6b28cccd1ec54b59346f0def7922ee1c7598e8499c733cfbb7c84", size = 38172, upload-time = "2026-05-08T21:00:35.124Z" }, + { url = "https://files.pythonhosted.org/packages/c5/09/f049e45385503fe67db75a6b6186a7b9f0c3930366dc960522c312a825b1/propcache-0.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:099aaf4b4d1a02265b92a977edf00b5c4f63b3b17ac6de39b0d637c9cac0188a", size = 94457, upload-time = "2026-05-08T21:00:36.355Z" }, + { url = "https://files.pythonhosted.org/packages/6b/65/83d1d05655baf63113731bd5a1008435e14f8d1e5a06cbe4ec5b23ad7a31/propcache-0.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:68ce1c44c7a813a7f71ea04315a8c7b330b63db99d059a797a4651bb6f69f117", size = 53835, upload-time = "2026-05-08T21:00:38.072Z" }, + { url = "https://files.pythonhosted.org/packages/a9/12/a6ba6482bb5ea3260c000c9b20881c95fa11c6b30173715668259f844ed7/propcache-0.5.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fc299c129490f55f254cd90be0deca4764e36e9a7c08b4aa588479a3bbed3098", size = 54545, upload-time = "2026-05-08T21:00:39.319Z" }, + { url = "https://files.pythonhosted.org/packages/a9/19/7fa086f5764c59ec8a8e157cd93aa8497acc00aba9dcdec56bfffb32602d/propcache-0.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a6ae2198be502c10f09b2516e7b5d019816924bc3183a43ce792a7bd6625e6f4", size = 59886, upload-time = "2026-05-08T21:00:40.621Z" }, + { url = "https://files.pythonhosted.org/packages/a1/e4/5d7663dc8235956c8f5281698a3af1d351d8820341ddd890f59d9a9127f2/propcache-0.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6041d31504dc1779d700e1edcfb08eea334b357620b06681a4eabb57a74e574e", size = 63261, upload-time = "2026-05-08T21:00:41.775Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/15a03adee24d6350da4292caeac44c34c033d2afe5e87eb370f38854560f/propcache-0.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f7eabc04151c78a9f4d5bbb5f1faf571e4defeb4b585e0fe95b60ff2dbe4d3d7", size = 64184, upload-time = "2026-05-08T21:00:43.018Z" }, + { url = "https://files.pythonhosted.org/packages/8b/c6/979176efdaa3d239e36d503d5af63a0a773b36662ed8f52e5b6a6d9fd40e/propcache-0.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4db0ba63d693afd40d249bd93f842b5f144f8fcbb83de05660373bcf30517b1d", size = 61534, upload-time = "2026-05-08T21:00:44.507Z" }, + { url = "https://files.pythonhosted.org/packages/c8/22/63e8cd1bae4c2d2be6493b6b7d10566ddafad88137cfbc99964a1119853c/propcache-0.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1dbcf7675229b35d31abb6547d8ebc8c27a830ac3f9a794edff6254873ec7c0a", size = 61500, upload-time = "2026-05-08T21:00:45.796Z" }, + { url = "https://files.pythonhosted.org/packages/60/5a/28e5d9acbac1cc9ccb67045e8c1b943aa8d79fdf39c93bd73cacd68008ea/propcache-0.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d310c013aad2c72f1c3f2f8dd3279d460a858c551f97aeb8c63e4693cca7b4d2", size = 59994, upload-time = "2026-05-08T21:00:47.093Z" }, + { url = "https://files.pythonhosted.org/packages/f3/40/db650677f554a95b9c01a7c9d93d629e93a15562f5deb4573c9ee136fed2/propcache-0.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:06187263ddad280d05b4d8a8b3bb7d164cbebd469236544a42e6d9b28ac6a4fa", size = 56884, upload-time = "2026-05-08T21:00:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/80/45/70b39b89516ff8b96bf732fa6fded8cef20f293cb1508690101c3c07ec51/propcache-0.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3115559b8effafd63b142ea5ed53d63a16ea6469cbc63dce4ee194b42db5d853", size = 63464, upload-time = "2026-05-08T21:00:49.954Z" }, + { url = "https://files.pythonhosted.org/packages/f9/e2/fa59d3a89eac5534293124af4f1d0d0ada091ce4a0ab4610ce03fd2bdd8d/propcache-0.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:c60462af8e6dc30c35407c7237ea908d777b22862bbee27bc4699c0d8bcdc45a", size = 61588, upload-time = "2026-05-08T21:00:51.281Z" }, + { url = "https://files.pythonhosted.org/packages/0b/97/efb547a55c4bc7381cfb202d6a2239ac621045277bc1ea5dfd3a7f0516c0/propcache-0.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:40314bca9ac559716fe374094fc81c11dcc34b64fd6c585360f5775690505704", size = 64667, upload-time = "2026-05-08T21:00:52.602Z" }, + { url = "https://files.pythonhosted.org/packages/92/56/f5c7d9b4b7595d5127da38974d791b2153f3d1eae6c674af3583ace92ad3/propcache-0.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cfa21e036ce1e1db2be04ba3b85d2df1bb1702fa01932d984c5464c665228ff4", size = 62463, upload-time = "2026-05-08T21:00:54.303Z" }, + { url = "https://files.pythonhosted.org/packages/bd/3b/484a3a65fc9f9f60c41dcd17b428bace5389544e2c680994534a20755066/propcache-0.5.2-cp313-cp313-win32.whl", hash = "sha256:f156a3529f38063b6dbaf356e15602a7f95f8055b1295a438433a6386f10463d", size = 38621, upload-time = "2026-05-08T21:00:55.808Z" }, + { url = "https://files.pythonhosted.org/packages/1c/fd/3f0f10dba4dabad3bf53102be007abf55481067952bde0fdddff439e7c61/propcache-0.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:dfed59d0a5aeb01e242e66ff0300bc4a265a7c05f612d30016f0b60b1017d757", size = 41649, upload-time = "2026-05-08T21:00:57.061Z" }, + { url = "https://files.pythonhosted.org/packages/90/ec/6ce619cc32bb500a482f811f9cd509368b4e58e638d13f2c68f370d6b475/propcache-0.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:ba338430e87ceb9c8f0cf754de38a9860560261e56c00376debd628698a7364f", size = 37636, upload-time = "2026-05-08T21:00:58.646Z" }, + { url = "https://files.pythonhosted.org/packages/1b/82/c1d268bbbf2ef981c5bf0fbbe746db617c66e3bcefe431a1aa8943fbe23a/propcache-0.5.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a592f5f3da71c8691c788c13cb6734b6d17663d2e1cb8caddf0673d01ef8847d", size = 98872, upload-time = "2026-05-08T21:00:59.889Z" }, + { url = "https://files.pythonhosted.org/packages/f4/d4/52c871e73e864e6b34c0e2d58ac1ec5ccd149497ddc7ad2137ae98323a35/propcache-0.5.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6a997d0489e9668a384fcfd5061b857aa5361de73191cac204d04b889cfbbafa", size = 56257, upload-time = "2026-05-08T21:01:01.195Z" }, + { url = "https://files.pythonhosted.org/packages/67/f0/9b90ca2a210b3d09bcfcd96ecd0f55545c091535abce2a45de2775cfd357/propcache-0.5.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:10734b5484ea113152ee25a91dccedf81631791805d2c9ccb054958e51842c94", size = 56696, upload-time = "2026-05-08T21:01:02.941Z" }, + { url = "https://files.pythonhosted.org/packages/9d/0e/6e9d4ba07c8e56e21ddec1e75f12148142b21ca83a51871babce095334f4/propcache-0.5.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cafca7e56c12bb02ae16d283742bef25a61122e9dab2b5b3f2ccbe589ce32164", size = 62378, upload-time = "2026-05-08T21:01:04.475Z" }, + { url = "https://files.pythonhosted.org/packages/65/19/c10badaa463dde8a27ce884f8ee2ec37e6035b7c9f5ff0c8f74f06f08dac/propcache-0.5.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f064f8d2b59177878b7615df1735cd8fe3462ed6be8c7b217d17a276489c2b7f", size = 65283, upload-time = "2026-05-08T21:01:05.959Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b6/93bea99ca80e19cef6512a8580e5b7857bbe09422d9daa7fd4ef5723306c/propcache-0.5.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f78abfa8dfc32376fd1aacf597b2f2fbbe0ea751419aee718af5d4f82537ef8c", size = 66616, upload-time = "2026-05-08T21:01:07.228Z" }, + { url = "https://files.pythonhosted.org/packages/83/e4/5c7462e50625f051f37fb38b8224f7639f667184bbd34424ec83819bb1b7/propcache-0.5.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f7467da8a9822bf1a55336f877340c5bcbd3c482afc43a99771169f74a26dedc", size = 63773, upload-time = "2026-05-08T21:01:08.514Z" }, + { url = "https://files.pythonhosted.org/packages/ca/b6/99238894047b13c823be25027e736626cd414a52a5e30d2c3347c2733529/propcache-0.5.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a6ddc6ac9e25de626c1f129c1b467d7ecd33ce2237d3fd0c4e429feef0a7ee1f", size = 63664, upload-time = "2026-05-08T21:01:09.874Z" }, + { url = "https://files.pythonhosted.org/packages/85/1e/a3a1a63116a2b8edb415a8bb9a6f0c34bd03830b1e18e8ce2904e1dc1cf4/propcache-0.5.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:2f22cbbac9e26a8e864c0985ff1268d5d939d53d9d9411a9824279097e03a2cb", size = 62643, upload-time = "2026-05-08T21:01:11.132Z" }, + { url = "https://files.pythonhosted.org/packages/e4/03/893cf147de2fc6543c5eaa07ad833170e7e2a2385725bbebe8c0503723bb/propcache-0.5.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:fc76378c62a0f04d0cd82fbb1a2cd2d7e28fcb40d5873f28a6c44e388aaa2751", size = 59595, upload-time = "2026-05-08T21:01:12.387Z" }, + { url = "https://files.pythonhosted.org/packages/86/3b/04c1a2e12c57766568ba75ba72b3bf2042818d4c1425fab6fc07155c7cff/propcache-0.5.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:acd2c8edba48e31e58a363b8cf4e5c7db3b04b3f9e371f601df30d9b0d244836", size = 65711, upload-time = "2026-05-08T21:01:13.676Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/80f8d0099f8d6bacc4de1624c85672681c8cd1149ca2da0e38fd120b817f/propcache-0.5.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:452b5065457eb9991ec5eb38ff41d6cd4c991c9ac7c531c4d5849ae473a9a13f", size = 64247, upload-time = "2026-05-08T21:01:14.936Z" }, + { url = "https://files.pythonhosted.org/packages/f3/1a/8b08f3a5f1037e9e370c55883ceeeee0f6dd0416fb2d2d67b8bfc91f2a79/propcache-0.5.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:3430bb2bfe1331885c427745a751e774ee679fd4344f80b97bf879815fe8fa55", size = 67102, upload-time = "2026-05-08T21:01:16.281Z" }, + { url = "https://files.pythonhosted.org/packages/34/68/8bdb7bb7756d76e005490649d10e4a8369e610c74d619f71e1aedf889e9c/propcache-0.5.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cef6cea3922890dd6c9654971001fa797b526c16ab5e1e46c05fd6f877be7568", size = 64964, upload-time = "2026-05-08T21:01:17.57Z" }, + { url = "https://files.pythonhosted.org/packages/0a/aa/50fb0b5d3968b61a510926ff8b8465f1d6e976b3ab74496d7a4b9fc42515/propcache-0.5.2-cp313-cp313t-win32.whl", hash = "sha256:72d61e16dd78228b58c5d47be830ff3da7e5f139abdf0aef9d86cde1c5cf2191", size = 42546, upload-time = "2026-05-08T21:01:18.946Z" }, + { url = "https://files.pythonhosted.org/packages/ae/4c/0ddbae64321bd4a95bcbfc19307238016b5b1fee645c84626c8d539e5b74/propcache-0.5.2-cp313-cp313t-win_amd64.whl", hash = "sha256:0958834041a0166d343b8d2cedcd8bcbaeb4fdbe0cf08320c5379f143c3be6e7", size = 46330, upload-time = "2026-05-08T21:01:20.162Z" }, + { url = "https://files.pythonhosted.org/packages/00/d9/9cddc8efb78d8af264c5ec9f6d10b62f57c515feda8d321595f56010fb23/propcache-0.5.2-cp313-cp313t-win_arm64.whl", hash = "sha256:6de8bd93ddde9b992cf2b2e0d796d501a19026b5b9fd87356d7d0779531a8d96", size = 40521, upload-time = "2026-05-08T21:01:21.399Z" }, + { url = "https://files.pythonhosted.org/packages/e2/ea/23ee535d90ce8bcc465a3028eb3cc0ce3bd1005f4bb27710b30587de798d/propcache-0.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:46088abff4cba581dea21ae0467a480526cb25aa5f3c269e909f800328bc3999", size = 94662, upload-time = "2026-05-08T21:01:22.683Z" }, + { url = "https://files.pythonhosted.org/packages/b5/06/c5a52f419b5d8972f8d46a7577476090d8e3263ff589ce40b5ca4968d5be/propcache-0.5.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:fc88b26f08d634f7bc819a7852e5214f5802641ab8d9fd5326892292eee1993e", size = 53928, upload-time = "2026-05-08T21:01:23.986Z" }, + { url = "https://files.pythonhosted.org/packages/63/b1/4260d67d6bd85e58a66b72d54ce15d5de789b6f3870cc6bedf8ff9667401/propcache-0.5.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:97797ebb098e670a2f92dd66f32897e30d7615b14e7f59711de23e30a9072539", size = 54650, upload-time = "2026-05-08T21:01:25.305Z" }, + { url = "https://files.pythonhosted.org/packages/70/06/2f46c318e3307cd7a6a7481def374ce838c0fe20084b39dd54b0879d0e99/propcache-0.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ba57fffe4ac99c5d30076161b5866336d97600769bad35cc68f7774b15298a4e", size = 59912, upload-time = "2026-05-08T21:01:26.545Z" }, + { url = "https://files.pythonhosted.org/packages/4c/29/fe1aebec2ce57ab985a9c382bded1124431f85078113aa222c5d278430d4/propcache-0.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:583c19759d9eec1e5b69e2fbef36a7d9c326041be9746cb822d335c8cedc2979", size = 63300, upload-time = "2026-05-08T21:01:27.937Z" }, + { url = "https://files.pythonhosted.org/packages/b4/18/2334b26768b6c82be8c69e83671b767d5ef426aa09b0cba6c2ea47816774/propcache-0.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:d0326e2e5e1f3163fa306c834e48e8d490e5fae607a097a40c0648109b47ba80", size = 64208, upload-time = "2026-05-08T21:01:29.484Z" }, + { url = "https://files.pythonhosted.org/packages/2b/76/7f1bfd6afff4c5e38e36a3c6d68eb5f4b7311ea80baf693db78d95b603c4/propcache-0.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e00820e192c8dbebcafb383ebbf99030895f09905e7a0eb2e0340a0bcc2bc825", size = 61633, upload-time = "2026-05-08T21:01:31.068Z" }, + { url = "https://files.pythonhosted.org/packages/c4/46/b3ff8aba2b4953a3e50de2cf72f1b5748b8eca93b15f3dc2c84339084c09/propcache-0.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c66afea89b1e43725731d2004732a046fe6fe955d51f952c3e95a7314a284a39", size = 61724, upload-time = "2026-05-08T21:01:32.374Z" }, + { url = "https://files.pythonhosted.org/packages/c5/01/814cfcafbcff954f94c01cf30e097ddc88a076b5440fbcf4570753437d40/propcache-0.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d4dc37dec6c6cdad0b57881a5658fd14fbf53e333b1a86cf86559f190e1d9ec4", size = 60069, upload-time = "2026-05-08T21:01:33.67Z" }, + { url = "https://files.pythonhosted.org/packages/da/68/5c6f7622d510cc666a300687e06fd060c1a43361c0c9b20d284f06d8096a/propcache-0.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5570dbcc97571c15f68068e529c92715a12f8d54030e272d264b377e22bd17a5", size = 57099, upload-time = "2026-05-08T21:01:34.915Z" }, + { url = "https://files.pythonhosted.org/packages/55/27/9cb0b4c679124085327957d42521c99dba04c88c90c3e55a6f0b633ebccc/propcache-0.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f814362777a9f841adddb200ecdf8f5cb1e5a3c4b7a86378edbd6ccb26edd702", size = 63391, upload-time = "2026-05-08T21:01:36.231Z" }, + { url = "https://files.pythonhosted.org/packages/f0/9d/7258aaa5bdf60fc6f27591eef6fe52768cb0beda7140be477c8b12c9794a/propcache-0.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:196913dea116aeb5a2ba95af4ddcb7ea85559ae07d8eee8751688310d09168c3", size = 61626, upload-time = "2026-05-08T21:01:37.545Z" }, + { url = "https://files.pythonhosted.org/packages/8e/0d/41c602003e8a9b16fe1e7eadf62c7bfba9d5474370b24200bf48b315f45f/propcache-0.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:6e7b8719005dd1175be4ab1cd25e9b98659a5e0347331506ec6760d2773a7fb5", size = 64781, upload-time = "2026-05-08T21:01:38.83Z" }, + { url = "https://files.pythonhosted.org/packages/8b/f3/38e66b1856e9bd079deea015bc4a55f7767c0e4db2f7dcf69e7e680ba4ce/propcache-0.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:51f96d685ab16e88cab128cd37a52c5da540809c8b879fa047731bfcb4ad35a4", size = 62570, upload-time = "2026-05-08T21:01:40.415Z" }, + { url = "https://files.pythonhosted.org/packages/95/ca/bbfe9b910ce57dde8bb4876b4520fc02a4e89497c10de26be936758a3aaa/propcache-0.5.2-cp314-cp314-win32.whl", hash = "sha256:cc6fc3cc62e8501d3ed62894425040d2728ecddb1ed072737a5c70bd537aa9f0", size = 39436, upload-time = "2026-05-08T21:01:41.654Z" }, + { url = "https://files.pythonhosted.org/packages/61/d2/45c9defbaa1ea297035d9d4cce9e8f80daafbf19319c6007f157c6256ea9/propcache-0.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:81e3a30b0bb60caa22033dd0f8a3618d1d67356212514f62c57db75cb0ef410c", size = 42373, upload-time = "2026-05-08T21:01:43.041Z" }, + { url = "https://files.pythonhosted.org/packages/44/68/9ea5103f41d5217d7d6ec24db90018e23aebec070c3f9a6e54d12b841fd8/propcache-0.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:0d2c9bf8528f135dbb805ce027567e09164f7efa51a2be07458a2c0420f292d0", size = 38554, upload-time = "2026-05-08T21:01:44.336Z" }, + { url = "https://files.pythonhosted.org/packages/8a/81/fadf555f42d3b762eea8a53950b0489fdc0aa9da5f8ed9e10ce0a4e01b48/propcache-0.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:4bc8ff1feffc6a61c7002ffe84634c41b822e104990ae009f44a0834430070bb", size = 99395, upload-time = "2026-05-08T21:01:45.883Z" }, + { url = "https://files.pythonhosted.org/packages/f5/c9/c61e134a686949cf7971af3a390148b1156f7be81c73bc0cd12c873e2d48/propcache-0.5.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79aa3ff0a9b566633b642fa9caf7e21ed1c13d6feca718187873f199e1514078", size = 56653, upload-time = "2026-05-08T21:01:47.307Z" }, + { url = "https://files.pythonhosted.org/packages/cb/73/daf935ea7048ddd7ec8eec5345b4a40b619d2d178b3c0a0900796bc3c794/propcache-0.5.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1b31822f4474c4036bae62de9402710051d431a606d6a0f907fec79935a071aa", size = 56914, upload-time = "2026-05-08T21:01:48.573Z" }, + { url = "https://files.pythonhosted.org/packages/79/9f/aba959b435ea18617edd7cf0a7ad0b9c574b8fc7e3d2cd55fb59cb255d33/propcache-0.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13fef48778b5a2a756523fdb781326b028ca75e32858b04f2cdd19f394564917", size = 62567, upload-time = "2026-05-08T21:01:49.903Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a1/859942de9a791ff42f6141736f5b37749b8f53e65edfa49638c67dd67e6a/propcache-0.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b73ab70f1a3351fbc71f663b3e645af6dd0329100c353081cf69c37433fc6fe", size = 65542, upload-time = "2026-05-08T21:01:51.204Z" }, + { url = "https://files.pythonhosted.org/packages/b5/61/315bc0fd6c0fc7f80a528b8afd209e5fc4a875ea79571b91b8f50f442907/propcache-0.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5538d2c13d93e4698af7e092b57bc7298fd35d1d58e656ae18f23ee0d0378e03", size = 66845, upload-time = "2026-05-08T21:01:52.539Z" }, + { url = "https://files.pythonhosted.org/packages/47/f7/9f8122e3132e8e354ac41975ef8f1099be7d5a16bc7ae562734e993665c0/propcache-0.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cd645f03898405cabe694fb8bc35241e3a9c332ec85627584fe3de201452b335", size = 63985, upload-time = "2026-05-08T21:01:53.847Z" }, + { url = "https://files.pythonhosted.org/packages/c8/54/c317819ec157cbf6f35df9df9657a6f82daf34d5faf15948b2f639c2192e/propcache-0.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a473b3440261e0c60706e732b2ed2f517857344fc21bf48fdfe211e2d98eb285", size = 63999, upload-time = "2026-05-08T21:01:55.179Z" }, + { url = "https://files.pythonhosted.org/packages/5a/56/387e3f7dfce0a9233df41fb888aa1c30222cb4bbbf09537c02dd9bd85fe2/propcache-0.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7afa37062e6650640e932e4cc9297d81f9f42d9944029cc386b8247dea4da837", size = 62779, upload-time = "2026-05-08T21:01:57.489Z" }, + { url = "https://files.pythonhosted.org/packages/a1/9c/596784cb5824ed61ee960d3f8655a3f0993e107c6e98ab6c818b7fb92ccb/propcache-0.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:8a90efd5777e996e42d568db9ac740b944d691e565cbfd31b2f7832f9184b2b8", size = 59796, upload-time = "2026-05-08T21:01:58.736Z" }, + { url = "https://files.pythonhosted.org/packages/c2/3d/1a6cfa1726a48542c1e8784a0761421476a5b68e09b7f36bf95eb954aaba/propcache-0.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:f19bb891234d72535764d703bfed1153cc34f4214d5bd7150aee1eec9e8f4366", size = 66023, upload-time = "2026-05-08T21:02:00.228Z" }, + { url = "https://files.pythonhosted.org/packages/e4/0e/05fd6990369477076e4e280bcb970de760fddf0161a46e988bc95f7940ec/propcache-0.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:32775082acd2d807ee3db715c7770d38767b817870acfa08c29e057f3c4d5b56", size = 64448, upload-time = "2026-05-08T21:02:01.888Z" }, + { url = "https://files.pythonhosted.org/packages/cd/86/5f8da315a4309c62c10c0b2516b17492d5d3bbe1bb862b96604db67e2a37/propcache-0.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:9282fb1a3bccd038da9f768b927b24a0c753e466c086b7c4f3c6982851eefb2d", size = 67329, upload-time = "2026-05-08T21:02:03.484Z" }, + { url = "https://files.pythonhosted.org/packages/da/d3/3368efe79ab21f0cdf86ef49895811c9cc933131d4cde1f28a624e22e712/propcache-0.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:cc49723e2f60d6b32a0f0b08a3fd6d13203c07f1cd9566cfce0f12a917c967a2", size = 65172, upload-time = "2026-05-08T21:02:04.745Z" }, + { url = "https://files.pythonhosted.org/packages/d5/07/127e8b0bacfb325396196f9d976a22453049b89b9b2b08477cc3145faa44/propcache-0.5.2-cp314-cp314t-win32.whl", hash = "sha256:2d7aa89ebca5acc98cba9d1472d976e394782f587bad6661003602a619fd1821", size = 43813, upload-time = "2026-05-08T21:02:06.025Z" }, + { url = "https://files.pythonhosted.org/packages/88/fb/46dad6c0ae49ed230ab1b16c890c2b6314e2403e6c412976f4a72d64a527/propcache-0.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:d447bb0b3054be5818458fbb171208b1d9ff11eba14e18ca18b90cbb45767370", size = 47764, upload-time = "2026-05-08T21:02:07.353Z" }, + { url = "https://files.pythonhosted.org/packages/e7/c4/a47d0a63aa309d10d59ede6e9d4cff03a344a79d1f0f4cd0cd74997b53e0/propcache-0.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:fe67a3d11cd9b4efabfa45c3d00ffba2b26811442a73a581a94b67c2b5faccf6", size = 41140, upload-time = "2026-05-08T21:02:09.065Z" }, + { url = "https://files.pythonhosted.org/packages/3a/ed/1cdcab6ba3d6ab7feca11fc14f0eeea80755bb53ef4e892079f31b10a25f/propcache-0.5.2-py3-none-any.whl", hash = "sha256:be1ddfcbb376e3de5d2e2db1d58d6d67463e6b4f9f040c000de8e300295465fe", size = 14036, upload-time = "2026-05-08T21:02:10.673Z" }, +] + [[package]] name = "protobuf" version = "6.33.6" @@ -1896,6 +3039,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" }, ] +[[package]] +name = "python-datauri" +version = "3.0.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cached-property" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/7c/3b/8a9a2ec12424a8617678d663fa70de43d917d3590416d3a2b9c7fc065d5b/python_datauri-3.0.2.tar.gz", hash = "sha256:d77c37f1f734fc035de424e643464990b2b840e9b8c7c1817c11fca19b71eeb7", size = 9746, upload-time = "2025-01-03T16:22:56.143Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bc/b6/3332df034d7f322506f2267517b051cd3605e129ecc7f9d46a6fbd540279/python_datauri-3.0.2-py2.py3-none-any.whl", hash = "sha256:b365690a1d7d1b7777009eb11a86bd069db4f194e50f4f871a47302f0587c144", size = 5803, upload-time = "2025-01-03T16:22:53.899Z" }, +] + [[package]] name = "python-discovery" version = "1.4.3" @@ -1918,6 +3074,30 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, ] +[[package]] +name = "python-engineio" +version = "4.13.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "simple-websocket" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/fb/a0/f75491f942184d9960b15e763270f765fe9f239745ca5f9e16289011aed4/python_engineio-4.13.3.tar.gz", hash = "sha256:572b7783e341fed21edbc7cea297ccd378dad79265fdde96aa4664420a7c06c9", size = 79734, upload-time = "2026-06-20T22:53:52.197Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/5b/96/82f6328e410515fab21d5602ba35b9377a47b5a141a0c1f9efa00ce21eb4/python_engineio-4.13.3-py3-none-any.whl", hash = "sha256:1f60ecaf1358190f0e26c48c578a60428dc02a8f1295bc3dbf53d1b31116821f", size = 59993, upload-time = "2026-06-20T22:53:50.775Z" }, +] + +[[package]] +name = "python-frontmatter" +version = "1.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pyyaml" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/9d/e8/79cbe69864d44f3b48e70ebee0a872a7d5a4e7150c9f8577ed7a5beefff0/python_frontmatter-1.3.0.tar.gz", hash = "sha256:acc73e477a568dc2a25c9e130c6c68ae8daa8c204c8f7e813db47d6a7280dcf2", size = 8322, upload-time = "2026-05-20T19:21:44.164Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/a3/17c284b4f4d8ad50f0f9ba70ad8fcc35c777aeafcdbbffdd91bbdc5ab379/python_frontmatter-1.3.0-py3-none-any.whl", hash = "sha256:9f7dd9260bec99044219159a329f64f039087f9d1a2124c9442556f2fe6f82ec", size = 10562, upload-time = "2026-05-20T19:21:43.323Z" }, +] + [[package]] name = "python-multipart" version = "0.0.32" @@ -1927,6 +3107,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/04/e8135ebd1ad02c56ec633277529b2602ff99ff634be76cdba5744cf554fd/python_multipart-0.0.32-py3-none-any.whl", hash = "sha256:ff6d3f776f16878c894e52e107296ffc890e913c611b1a4ec6c44e2821fe2e23", size = 30042, upload-time = "2026-06-04T16:18:57.319Z" }, ] +[[package]] +name = "python-socketio" +version = "5.16.3" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bidict" }, + { name = "python-engineio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/2d/ffce71017c106b75099fea569df6518c63fee5d6202ce0cfe7b01e6f22c3/python_socketio-5.16.3.tar.gz", hash = "sha256:89b136f677ae65607a84cecda9b4d6c5377b40a97582c504c25df89af16d520e", size = 128095, upload-time = "2026-06-15T22:07:04.003Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0a/38/8c5e72d53ff8eb27497c4f268a7f6d9121e727a50b65248288ad79a93053/python_socketio-5.16.3-py3-none-any.whl", hash = "sha256:e7ad14202a5e6448824c7c2f86161d04e13dec05992257df5c709e6a2798c041", size = 82087, upload-time = "2026-06-15T22:07:02.498Z" }, +] + [[package]] name = "pywin32" version = "312" @@ -2031,6 +3224,127 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/58/ca301544e1fa93ed4f80d724bf5b194f6e4b945841c5bfd555878eea9fcb/referencing-0.37.0-py3-none-any.whl", hash = "sha256:381329a9f99628c9069361716891d34ad94af76e461dcb0335825aecc7692231", size = 26766, upload-time = "2025-10-13T15:30:47.625Z" }, ] +[[package]] +name = "regex" +version = "2026.7.19" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/20/98/04b13f1ddfb63158025291c02e03eb42fbb7acb51d091d541050eb4e35e8/regex-2026.7.19.tar.gz", hash = "sha256:7e77b324909c1617cbb4c668677e2c6ae13f44d7c1de0d4f15f2e3c10f3315b5", size = 416440, upload-time = "2026-07-19T00:19:48.923Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/24/13/bbf7d9d1887fe4a3693527c6caa232c197ea9da91f1212e9672eff60329d/regex-2026.7.19-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:555497390743af1a65045fa4527782d10ff5b88970359412baa4a1e628fe393b", size = 494009, upload-time = "2026-07-19T00:16:13.602Z" }, + { url = "https://files.pythonhosted.org/packages/a3/19/783688e75a2bec15d50aec0d5e7e317d363808bc82a6eb6750b897bfcd7b/regex-2026.7.19-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:343a4504e3fb688c47cad451221ca5d4814f42b1e16c0065bde9cbf7f473bd52", size = 295287, upload-time = "2026-07-19T00:16:15.702Z" }, + { url = "https://files.pythonhosted.org/packages/16/01/cefe4f051302ca298d3f3e79ed6dbd933ac84485b9515acdd6a52d70cef7/regex-2026.7.19-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ebee1ee89c39c953baac6924fcde08c5bb427c4057510862f9d7c7bdb3d8665", size = 290633, upload-time = "2026-07-19T00:16:17.182Z" }, + { url = "https://files.pythonhosted.org/packages/ae/1e/1045ca2cabb12e8ec41ad0d138e9f3ff1eb079d30a6f51ccf7d709b44aad/regex-2026.7.19-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:062f8cb7a9739c4835d22bd96f370c59aba89f257adcfa53be3cc209e08d3ae0", size = 785300, upload-time = "2026-07-19T00:16:18.505Z" }, + { url = "https://files.pythonhosted.org/packages/d5/4a/20e5bca184e90bf1bd187efdb53363f4a7b7b34f01d54ced5740caf104bd/regex-2026.7.19-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1123ef4211d763ee771d47916a1596e2f4915794f7aabdc1adcb20e4249a6951", size = 854079, upload-time = "2026-07-19T00:16:19.909Z" }, + { url = "https://files.pythonhosted.org/packages/09/9b/5a2e59678be3b24aa6a42b2c6d66a48daa212593e9f4096fe7ba577fa9b1/regex-2026.7.19-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:6e44c0e7c5664be20aee92085153150c0a7967310a73a43c0f832b7cd35d0dd3", size = 899496, upload-time = "2026-07-19T00:16:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/48/9a/7317f14ed8ed9fd998d1978b4802b07bc4d79216353c435dbcc1ddd1301f/regex-2026.7.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:98c6ac18480fcdb33f35439183f1d2e79760ab41930309c6d951cb1f8e46694c", size = 793541, upload-time = "2026-07-19T00:16:22.991Z" }, + { url = "https://files.pythonhosted.org/packages/6f/53/833c2db3e274d3c191f4c42fe5bfa358e4c8b617d5d7312d31334965fc46/regex-2026.7.19-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4458124d71339f505bf1fb94f69fd1bb8fa9d2481eebfef27c10ef4f2b9e12f6", size = 785515, upload-time = "2026-07-19T00:16:24.654Z" }, + { url = "https://files.pythonhosted.org/packages/8d/b9/efb2f9fa151d71db09d4015e1fb92fee47416f01c12164836bbd23e2f3c2/regex-2026.7.19-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fbf300e2070bb35038660b3be1be4b91b0024edb41517e6996320b49b92b4175", size = 769556, upload-time = "2026-07-19T00:16:26.207Z" }, + { url = "https://files.pythonhosted.org/packages/81/4d/45610c263f8eadb84e4a1fabd904d81d5176226faa9104ef498bf8a8b285/regex-2026.7.19-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b2b506b1788df5fecd270a10d5e70a95fe77b87ea2b370a318043f6f5f817ee6", size = 774130, upload-time = "2026-07-19T00:16:27.786Z" }, + { url = "https://files.pythonhosted.org/packages/40/95/1b40d87c7a9e5480bec7a87bce9fd67fc3f14b5f106c8ee66d660249072f/regex-2026.7.19-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:52579c60a6078be70a0e49c81d6e56d677f34cd439af281a0083b8c7bc75c095", size = 848694, upload-time = "2026-07-19T00:16:29.412Z" }, + { url = "https://files.pythonhosted.org/packages/17/8b/bb45968addd5b394ef9cd9184bd9c65ade1a819dbb2b92b71ad52a0c7907/regex-2026.7.19-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:2955907b7157a6660f27079edf7e0229e9c9c5325c77a2ef6a890cba91efa6f0", size = 758505, upload-time = "2026-07-19T00:16:31.006Z" }, + { url = "https://files.pythonhosted.org/packages/bf/6f/33386c672fbf43e21602135a0f29a97ee251a483f007fe51d10e9b2dbc93/regex-2026.7.19-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:89dfee3319f5ae3f75ebd5c2445a809bb320252ba5529ffdafea4ef25d79cf1a", size = 836985, upload-time = "2026-07-19T00:16:32.459Z" }, + { url = "https://files.pythonhosted.org/packages/22/f1/9112b86e9bb075619862e8e42b604794389f1958faa68fb69bde505dd90e/regex-2026.7.19-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d3143f159261b1ce5b24c261c590e5913370c3200c5e9ebbb92b5aa5e111902", size = 782610, upload-time = "2026-07-19T00:16:33.857Z" }, + { url = "https://files.pythonhosted.org/packages/3a/f9/13d460d8a385ca0b0be9e6be80a90968b9293b3e30895543ad2d1d1653e4/regex-2026.7.19-cp310-cp310-win32.whl", hash = "sha256:64729333167c2dcaaa56a331d40ee097bd9c5617ffd51dabb09eaddafb1b532e", size = 266772, upload-time = "2026-07-19T00:16:35.194Z" }, + { url = "https://files.pythonhosted.org/packages/9f/90/29addd7a03e1aea402c1f31467e25c80caabc8c3735b88a23cf73b0aa9c2/regex-2026.7.19-cp310-cp310-win_amd64.whl", hash = "sha256:1c398716054621aa300b3d411f467dda903806c5da0df6945ab73982b8d115db", size = 277967, upload-time = "2026-07-19T00:16:36.847Z" }, + { url = "https://files.pythonhosted.org/packages/8c/ba/ecfce06fe66c122bc6f77ae284887a9282e4411fe1e6268c5266611ca054/regex-2026.7.19-cp310-cp310-win_arm64.whl", hash = "sha256:064f1760a5a4ade65c5419be23e782f29147528e8a66e0c42dd4cedb8d4e9fc6", size = 276963, upload-time = "2026-07-19T00:16:38.315Z" }, + { url = "https://files.pythonhosted.org/packages/05/e5/cef4de2bac939280b68d32adc659478845238a8274f2f79c465063f590ad/regex-2026.7.19-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:ac777001cdfc28b72477d93c8564bb7583081ea8fb45cdca3d568e0a4f87183c", size = 494012, upload-time = "2026-07-19T00:16:39.927Z" }, + { url = "https://files.pythonhosted.org/packages/ff/87/e86f51eb117457bb7803132ffe5cb6e2841e2b5bea4cc85d397f3c6e257d/regex-2026.7.19-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59787bd5f8c70aa339084e961d2996b53fbdeab4d5393bba5c1fe1fc32e02bae", size = 295281, upload-time = "2026-07-19T00:16:41.433Z" }, + { url = "https://files.pythonhosted.org/packages/41/2e/2360c41d8080a3d9ec7e5c90fad6eab3b50192869d10e9a5609e48c8177b/regex-2026.7.19-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:90c633e7e8d6bf4e992b8b36ce69e018f834b641dd6de8cea6d78c06ffa119c5", size = 290615, upload-time = "2026-07-19T00:16:43.058Z" }, + { url = "https://files.pythonhosted.org/packages/cf/69/b65ba4344efbc771b28fe5dde84cbbb6c8f9551165952fe78def5b9dde6a/regex-2026.7.19-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:87ccab0db8d5f4fbb0272642113c1adb2ffc698c16d3a0944580222331fa7a20", size = 791804, upload-time = "2026-07-19T00:16:44.662Z" }, + { url = "https://files.pythonhosted.org/packages/81/b6/a40dfa0dc6224b36f620c00296eacc830489cbf8c2837b6750dfe6170375/regex-2026.7.19-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e50d748a32da622f256e8d505867f5d3c43a837c6a9f0efb149655fadd1042a", size = 861723, upload-time = "2026-07-19T00:16:46.412Z" }, + { url = "https://files.pythonhosted.org/packages/e3/02/735991dee71abd83196a7962f7ed8bf5aa05720ff06e2d3ff896a85e2bbb/regex-2026.7.19-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:bf1516fe58fc104f39b2d1dbe2d5e27d0cd45c4be2e42ba6ee0cc763701ec3c7", size = 905932, upload-time = "2026-07-19T00:16:47.956Z" }, + { url = "https://files.pythonhosted.org/packages/45/6c/e7098d8b846ccdbf431d8c081b61e496526a27a28094ed09e0dce21b3f54/regex-2026.7.19-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:09f3e5287f94f17b709dc9a9e70865855feee835c861613be144218ce4ca82cc", size = 801407, upload-time = "2026-07-19T00:16:49.43Z" }, + { url = "https://files.pythonhosted.org/packages/8a/18/34b69274e2649bcc7d9b089c2b2983fb2632d8ecf667e359593be9072e79/regex-2026.7.19-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6383cd2ed53a646c659ba1fe65727db76437fdaa069e697a0b44a51d5843d864", size = 774448, upload-time = "2026-07-19T00:16:51.352Z" }, + { url = "https://files.pythonhosted.org/packages/bb/e6/0a72247d025585fd3800b98e040b84d562a88af6303347100484849f4f01/regex-2026.7.19-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:09d3007fc76249a83cdd33de160d50e6cb77f54e09d8fa9e7148e10607ce24af", size = 783297, upload-time = "2026-07-19T00:16:53.071Z" }, + { url = "https://files.pythonhosted.org/packages/b1/aa/c4f65ae7dd02a36b323a70c4cff326e1f3442361aaebc9311100a130d54f/regex-2026.7.19-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:6f8c6e7a1cfa3dc9d0ee2de0e65e834537fa29992cc3976ffec914afc35c5dd5", size = 854736, upload-time = "2026-07-19T00:16:54.607Z" }, + { url = "https://files.pythonhosted.org/packages/62/c3/668082bcc817b9e694189b84997aeba7385b7779faa6711788679c482e35/regex-2026.7.19-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:b2ea4a3e8357be8849e833beeae757ac3c7a6b3fc055c03c808a53c91ad30d82", size = 763298, upload-time = "2026-07-19T00:16:56.289Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fb/2d07ad555e7af88aa5f867fdafa47a8d945ee237c20af3ebceb46a820835/regex-2026.7.19-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:80115dd39481fd3a4b4080220799dbcacb921a844de4b827264ececacbe17c78", size = 844430, upload-time = "2026-07-19T00:16:57.933Z" }, + { url = "https://files.pythonhosted.org/packages/51/15/c82a471fe3dce56f03745635b43aa456c40dc0db089e07ef148b331507d1/regex-2026.7.19-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6ce43a0269d68cee79a7d1ade7def53c20f8f2a047b92d7b5d5bcc73ae88327", size = 789683, upload-time = "2026-07-19T00:16:59.583Z" }, + { url = "https://files.pythonhosted.org/packages/b5/f4/7532a2c59d56f5398902c20de60f0c9a5d1cd364e42a051b48e1b210be7b/regex-2026.7.19-cp311-cp311-win32.whl", hash = "sha256:9be2a6647740dd3cca6acb24e87f03d7632cd280dbce9bbe40c26353a215a45d", size = 266778, upload-time = "2026-07-19T00:17:01.032Z" }, + { url = "https://files.pythonhosted.org/packages/83/2b/cf1bc631db154eb95520d9d5dbc2371ff77a0f014bbf7d748fed8496aa63/regex-2026.7.19-cp311-cp311-win_amd64.whl", hash = "sha256:8d3469c91dd92ee41b7c95280edbd975ef1ba9195086686623a1c6e8935ce965", size = 277983, upload-time = "2026-07-19T00:17:02.571Z" }, + { url = "https://files.pythonhosted.org/packages/8d/bd/56ceaf170e875d5a6761bf2bfd0d040f1cacc896850d5e40cb29b11bbd06/regex-2026.7.19-cp311-cp311-win_arm64.whl", hash = "sha256:36aacfb15faaff3ced55afbf35ec72f50d4aee22082c4f7fe0573a33e2fca92e", size = 276961, upload-time = "2026-07-19T00:17:04.135Z" }, + { url = "https://files.pythonhosted.org/packages/3b/b9/d11d7e501ac8fd7d617684423ebb9561e0b998481c1e4cbc0cb212c5d74a/regex-2026.7.19-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:2cc3460cedf7579948486eab03bc9ad7089df4d7281c0f47f4afe03e8d13f02d", size = 496778, upload-time = "2026-07-19T00:17:05.677Z" }, + { url = "https://files.pythonhosted.org/packages/3f/a9/a5ab6f312f24318019170dc485d5421fe4f89e43a98640da50d95a8a7041/regex-2026.7.19-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0e9554c8785eac5cffe6300f69a91f58ba72bc88a5f8d661235ad7c6aa5b8ccd", size = 297122, upload-time = "2026-07-19T00:17:07.59Z" }, + { url = "https://files.pythonhosted.org/packages/b3/63/4cab4d7f2d384a144d420b763d97674cb70619c878ea6fcd7640d0e62143/regex-2026.7.19-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d7da47a0f248977f08e2cb659ff3c17ddc13a4d39b3a7baa0a81bf5b415430f6", size = 292009, upload-time = "2026-07-19T00:17:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/22/85/102a81b218298957d4ea7d2f084fae537a71add9d6ff93c8e67284c5f45e/regex-2026.7.19-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:93db40c8de0815baab96a06e08a984bac71f989d13bab789e382158c5d426797", size = 796708, upload-time = "2026-07-19T00:17:11.542Z" }, + { url = "https://files.pythonhosted.org/packages/78/b5/dc136af5629938a037cd2b304c12240e132ec92f38be8ff9cc89af2a1f2d/regex-2026.7.19-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:66bd62c59a5427746e8c44becae1d9b99d22fb13f30f492083dfb9ad7c45cc18", size = 865651, upload-time = "2026-07-19T00:17:13.312Z" }, + { url = "https://files.pythonhosted.org/packages/e0/75/67402ae3cd9c8c988a4c805d15ee3eef015e7ca4cb112cf3e640fc1f4153/regex-2026.7.19-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:1649eb39fcc9ea80c4d2f110fde2b8ab2aef3877b98f02ab9b14e961f418c511", size = 911756, upload-time = "2026-07-19T00:17:15.015Z" }, + { url = "https://files.pythonhosted.org/packages/2a/8e/096d00c7c480ef2ff4265349b14e2261d4ab787ba1f74e2e80d1c58079c3/regex-2026.7.19-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9dce8ec9695f531a1b8a6f314fd4b393adcccf2ea861db480cdf97a301d01a68", size = 801798, upload-time = "2026-07-19T00:17:17.208Z" }, + { url = "https://files.pythonhosted.org/packages/f0/41/e7ecac6edb5722417f85cc67eaf386322fbe8acf6918ec2fdc37c20dd9d0/regex-2026.7.19-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3080a7fd38ef049bd489e01c970c97dd84ff446a885b0f1f6b26d9b1ad13ce11", size = 776933, upload-time = "2026-07-19T00:17:19.347Z" }, + { url = "https://files.pythonhosted.org/packages/6f/69/03c9b3f058d66403e0ca2c938696e81d51cd4c6d47ec5265f02f96948d9a/regex-2026.7.19-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1d793a7988e04fcb1e2e135567443d82173225d657419ec09414a9b5a145b986", size = 784338, upload-time = "2026-07-19T00:17:21.057Z" }, + { url = "https://files.pythonhosted.org/packages/f6/f7/b38ab3d43f284afbb618fcd15d0e77eb786ae461ce1f6bc7494619ddc0f2/regex-2026.7.19-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:e8b0abe7d870f53ca5143895fef7d1041a0c831a140d3dc2c760dd7ba25d4a8b", size = 860452, upload-time = "2026-07-19T00:17:23.119Z" }, + { url = "https://files.pythonhosted.org/packages/15/5c/ff60ef0571121714f3cf9920bc183071e384a10b556d042e0fdb06cc07a5/regex-2026.7.19-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:4e5413bd5f13d3a4e3539ca98f70f75e7fca92518dd7f117f030ebedd10b60cb", size = 765958, upload-time = "2026-07-19T00:17:24.81Z" }, + { url = "https://files.pythonhosted.org/packages/aa/0f/bd34021162c0ab47f9a315bd56cd5642e920c8e5668a75ef6c6a6fca590d/regex-2026.7.19-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:73b133a9e6fb512858e7f065e96f1180aa46646bc74a83aea62f1d314f3dd035", size = 851765, upload-time = "2026-07-19T00:17:26.993Z" }, + { url = "https://files.pythonhosted.org/packages/2a/20/a2ca43edade0595cccfdc98636739f536d9e26898e7dbddc2b9e98898953/regex-2026.7.19-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dbe6493fbd27321b1d1f2dd4f5c7e5bd4d8b1d7cab7f32fd67db3d0b2ed8248a", size = 789714, upload-time = "2026-07-19T00:17:28.699Z" }, + { url = "https://files.pythonhosted.org/packages/5d/47/e02db4015d424fc83c00ea0ac8c5e5ec14397943de9abf909d5ce3a25931/regex-2026.7.19-cp312-cp312-win32.whl", hash = "sha256:ddd67571c10869f65a5d7dde536d1e066e306cc90de57d7de4d5f34802428bb5", size = 267157, upload-time = "2026-07-19T00:17:31.051Z" }, + { url = "https://files.pythonhosted.org/packages/08/8e/c780c131f79b42ed22d1bd7da4096c2c35f813e835acd02ef0f018bd892c/regex-2026.7.19-cp312-cp312-win_amd64.whl", hash = "sha256:e30d40268a28d54ce0437031750497004c22602b8e3ab891f759b795a003b312", size = 277777, upload-time = "2026-07-19T00:17:32.848Z" }, + { url = "https://files.pythonhosted.org/packages/3e/4c/e4d7e086449bdf379d89774bf1f89dc4a41943f3c5a6125a03905b34b5fb/regex-2026.7.19-cp312-cp312-win_arm64.whl", hash = "sha256:de9208bb427130c82a5dbfd104f92c8876fc9559278c880b3002755bbbe9c83d", size = 277136, upload-time = "2026-07-19T00:17:34.803Z" }, + { url = "https://files.pythonhosted.org/packages/5d/3d/84165e4299ff76f3a40fe1f2abf939e976f693383a08d2beea6af62bd2c1/regex-2026.7.19-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f035d9dc1d25eff9d361456572231c7d27b5ccd473ca7dc0adfce732bd006d40", size = 496552, upload-time = "2026-07-19T00:17:36.808Z" }, + { url = "https://files.pythonhosted.org/packages/02/a2/a65293e6e4cf28eb7ee1be5335a5386c40d6742e9f47fafc8fec785e16c7/regex-2026.7.19-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c42572142ed0b9d5d261ba727157c426510da78e20828b66bbb855098b8a4e38", size = 296983, upload-time = "2026-07-19T00:17:38.816Z" }, + { url = "https://files.pythonhosted.org/packages/95/47/2d0564e93d87bc48618360ddca232a2ca612bbdf53ce8465d45ca5ce14ee/regex-2026.7.19-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:40b34dd88658e4fedd2fddbf0275ac970d00614b731357f425722a3ed1983d11", size = 291832, upload-time = "2026-07-19T00:17:40.726Z" }, + { url = "https://files.pythonhosted.org/packages/07/cd/42dfbabff3dfc9603c501c0e2e2c5adbb09d127b267bf5348de0af338c15/regex-2026.7.19-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c41c63992bf1874cebb6e7f56fd7d3c007924659a604ae3d90e427d40d4fd13", size = 796775, upload-time = "2026-07-19T00:17:42.382Z" }, + { url = "https://files.pythonhosted.org/packages/df/5d/f6a4839f2b934e3eed5973fd07f5929ee97d4c98939fb275ea23c274ee16/regex-2026.7.19-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d3372064506b94dd2c67c845f2db8062e9e9ba84d04e33cb96d7d33c11fe1ae", size = 865687, upload-time = "2026-07-19T00:17:44.185Z" }, + { url = "https://files.pythonhosted.org/packages/14/b0/b47d6c36049bc59806a50bd4c86ced70bbe058d787f80281b1d7a9b0e024/regex-2026.7.19-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fce7760bf283405b2c7999cab3da4e72f7deca6396013115e3f7a955db9760da", size = 911962, upload-time = "2026-07-19T00:17:46.442Z" }, + { url = "https://files.pythonhosted.org/packages/2a/be/ff61f28f9273658cfe23acbbac5217221f6519960ed401e61dfdab12bc35/regex-2026.7.19-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c0d702548d89d572b2929879bc883bb7a4c4709efafe4512cadee56c55c9bd15", size = 801817, upload-time = "2026-07-19T00:17:48.25Z" }, + { url = "https://files.pythonhosted.org/packages/c3/bb/8b4f7f26b333f9f79e1b453613c39bb4776f51d38ae66dd0ba31d6b354ca/regex-2026.7.19-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d446c6ac40bb6e05025ccee55b84d80fe9bf8e93010ffc4bb9484f13d498835f", size = 776908, upload-time = "2026-07-19T00:17:50.183Z" }, + { url = "https://files.pythonhosted.org/packages/09/13/610110fc5921d380516d03c26b652555f08aa0d23ea78a771231873c3638/regex-2026.7.19-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4c3501bfa814ab07b5580741f9bf78dfdfe146a04057f82df9e2402d2a975939", size = 784426, upload-time = "2026-07-19T00:17:52.454Z" }, + { url = "https://files.pythonhosted.org/packages/ca/f5/1ef9e2a83a5947c57ebff0b377cb5727c3d5ec1992317a320d035cd0dbb6/regex-2026.7.19-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c4585c3e64b4f9e583b4d2683f18f5d5d872b3d71dcf24594b74ecc23602fa96", size = 860600, upload-time = "2026-07-19T00:17:54.229Z" }, + { url = "https://files.pythonhosted.org/packages/a0/02/073af33a3ec149241d11c80acea91e722aa0adbf05addd50f251c4fe89c3/regex-2026.7.19-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:571fde9741eb0ccde23dd4e0c1d50fbae910e901fa7e629faf39b2dda740d220", size = 765950, upload-time = "2026-07-19T00:17:56.041Z" }, + { url = "https://files.pythonhosted.org/packages/81/a9/d1e9f819dc394a568ef370cd56cf25394e957a2235f8370f23b576e5a475/regex-2026.7.19-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:15b364b9b98d6d2fe1a85034c23a3180ff913f46caddc3895f6fd65186255ccc", size = 851794, upload-time = "2026-07-19T00:17:57.897Z" }, + { url = "https://files.pythonhosted.org/packages/03/3a/8ae83eda7579feacdf984e71fb9e70635fb6f832eeddca58427ec4fca926/regex-2026.7.19-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffd8893ccc1c2fce6e0d6ca402d716fe1b29db70c7132609a05955e31b2aa8f2", size = 789845, upload-time = "2026-07-19T00:17:59.97Z" }, + { url = "https://files.pythonhosted.org/packages/4b/23/c195cbfe5a75fdec64d8f6554fd15237b837919d2c61bdc141d7c807b08b/regex-2026.7.19-cp313-cp313-win32.whl", hash = "sha256:f0fa4fa9c3632d708742baf2282f2055c11d888a790362670a403cbf48a2c404", size = 267135, upload-time = "2026-07-19T00:18:01.958Z" }, + { url = "https://files.pythonhosted.org/packages/b2/80/a11de8404b7272b70acb45c1c05987cce60b45d5693da2e176f0e390d564/regex-2026.7.19-cp313-cp313-win_amd64.whl", hash = "sha256:d51ffd3427640fa2da6ade574ceba932f210ad095f65fcc450a2b0a0d454868e", size = 277747, upload-time = "2026-07-19T00:18:04.121Z" }, + { url = "https://files.pythonhosted.org/packages/d1/29/0f5c8eff1b4f1f3d83276d365fccecf666afcc7d947420943bf394d07adb/regex-2026.7.19-cp313-cp313-win_arm64.whl", hash = "sha256:c670fe7be5b6020b76bc6e8d2196074657e1327595bca93a389e1a76ab130ad8", size = 277129, upload-time = "2026-07-19T00:18:05.821Z" }, + { url = "https://files.pythonhosted.org/packages/dc/4c/44b74742052cedda40f9ae469532a037112f7311a36669a891fba8984bb0/regex-2026.7.19-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:db47b561c9afd884baa1f96f797c9ca369872c4b65912bc691cfa99e68340af2", size = 501134, upload-time = "2026-07-19T00:18:07.567Z" }, + { url = "https://files.pythonhosted.org/packages/f0/45/bbd038b5e39ee5613a5a689290145b40058cc152c41de9cc23639d2b9734/regex-2026.7.19-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:65dcd28d3eba2ab7c2fd906485cc301392b47cc2234790d27d4e4814e02cdfda", size = 299418, upload-time = "2026-07-19T00:18:09.38Z" }, + { url = "https://files.pythonhosted.org/packages/65/38/c5bde94b4cedfd5850d64c3f08222d8e1600e84f6ee71d9b44b4b8163f74/regex-2026.7.19-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:f2e7f8e2ab6c2922be02c7ec45185aa5bd771e2e57b95455ee343a44d8130dff", size = 294486, upload-time = "2026-07-19T00:18:11.188Z" }, + { url = "https://files.pythonhosted.org/packages/d7/6a/2f5e107cb26c960b781967178899daf2787a7ab151844ed3c01d6fc95474/regex-2026.7.19-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fe31f28c94402043161876a258a9c6f757cb485905c7614ce8d6cd40e6b7bdc1", size = 811643, upload-time = "2026-07-19T00:18:12.975Z" }, + { url = "https://files.pythonhosted.org/packages/37/d4/a2f963406d7d73a62eed84ba05a258afb6cad1b21aa4517443ce40506b78/regex-2026.7.19-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f8f6fa298bb4f7f58a33334406218ba74716e68feddf5e4e54cd5d8082705abf", size = 871081, upload-time = "2026-07-19T00:18:14.733Z" }, + { url = "https://files.pythonhosted.org/packages/45/a3/44be546340bedb15f13063f5e7fe16793ea4d9ea2e805d09bd174ac27724/regex-2026.7.19-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:cc1b2440423a851fad781309dd87843868f4f66a6bcd1ddb9225cf4ec2c84732", size = 917372, upload-time = "2026-07-19T00:18:16.724Z" }, + { url = "https://files.pythonhosted.org/packages/f8/f6/e0870b0fd2a40dba0074e4b76e514b21313d37946c9248453e34ec43923e/regex-2026.7.19-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8ac59a0900474a52b7c04af8196affc22bd9842acb0950df12f7b813e983609a", size = 816089, upload-time = "2026-07-19T00:18:18.617Z" }, + { url = "https://files.pythonhosted.org/packages/ae/27/957e8e22690ad6634572b39b71f130a6105f4d0718bb16849eac00fff147/regex-2026.7.19-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4896db1f4ce0576765b8272aa922df324e0f5b9bb2c3d03044ff32a7234a9aba", size = 785206, upload-time = "2026-07-19T00:18:20.464Z" }, + { url = "https://files.pythonhosted.org/packages/76/a4/186e410941e731037c01166069ab86da9f65e8f8110c18009ccf4bd623ee/regex-2026.7.19-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4e6883a021db30511d9fb8cfb0f222ce1f2c369f7d4d8b0448f449a93ba0bdfc", size = 800431, upload-time = "2026-07-19T00:18:22.716Z" }, + { url = "https://files.pythonhosted.org/packages/73/9f/e4e10e023d291d64a33e246610b724493bf1ce98e0e59c9b7c837e5acfb7/regex-2026.7.19-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:09523a592938aa9f587fb74467c63ff0cf88fc3df14c82ab0f0517dcf76aaa62", size = 864906, upload-time = "2026-07-19T00:18:24.772Z" }, + { url = "https://files.pythonhosted.org/packages/24/57/ccb20b6be5f1f52a053d1ba2a8f7a077edb9d918248b8490d7506c6832b3/regex-2026.7.19-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:1ebac3474b8589fce2f9b225b650afd61448f7c73a5d0255a10cc6366471aed1", size = 773559, upload-time = "2026-07-19T00:18:27.008Z" }, + { url = "https://files.pythonhosted.org/packages/a3/82/f3b263cf8fad927dc102891da8502e718b7ff9d19af7a2a07c03865d7188/regex-2026.7.19-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4a0530bb1b8c1c985e7e2122e2b4d3aedd8a3c21c6bfddae6767c4405668b56e", size = 857739, upload-time = "2026-07-19T00:18:29.107Z" }, + { url = "https://files.pythonhosted.org/packages/47/2e/1687bd1b6c2aed5e672ccf845fc11557821fe7366d921b50889ea5ce57bf/regex-2026.7.19-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2ef7eeb108c47ce7bcc9513e51bcb1bf57e8f483d52fce68a8642e3527141ae0", size = 804522, upload-time = "2026-07-19T00:18:31.362Z" }, + { url = "https://files.pythonhosted.org/packages/76/7c/cc4e7655181b2d9235b704f2c5e19d8eff002bbc437bae59baee0e381aca/regex-2026.7.19-cp313-cp313t-win32.whl", hash = "sha256:64b6ca7391a1395c2638dd5c7456d67bea44fc6c5e8e92c5dc8aa6a8f23292b4", size = 269141, upload-time = "2026-07-19T00:18:33.479Z" }, + { url = "https://files.pythonhosted.org/packages/bb/14/961b4c7b05a2391c32dbc85e27773076671ef8f97f36cec70fe414734c02/regex-2026.7.19-cp313-cp313t-win_amd64.whl", hash = "sha256:f04b9f56b0e0614c0126be12c2c2d9f8850c1e57af302bd0a63bed379d4af974", size = 280036, upload-time = "2026-07-19T00:18:35.419Z" }, + { url = "https://files.pythonhosted.org/packages/ce/67/795644550d788ddbb6dc458c95895f8009978ea6d6ea76b005eb3f45e8c9/regex-2026.7.19-cp313-cp313t-win_arm64.whl", hash = "sha256:fcee38cd8e5089d6d4f048ba1233b3ad76e5954f545382180889112ff5cb712d", size = 279394, upload-time = "2026-07-19T00:18:37.454Z" }, + { url = "https://files.pythonhosted.org/packages/d2/25/0c4c452f8ef3efe456745b2f33195f5904b573fb4c2ff3f0cb9ec188461e/regex-2026.7.19-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:a81758ed242b861b72e778ba34d41366441a2e10b16b472784c88da2dea7e2dd", size = 496750, upload-time = "2026-07-19T00:18:39.633Z" }, + { url = "https://files.pythonhosted.org/packages/24/9e/b70ca6c1704f6c7cd32a9e143c86cc5968d10981eca284bad670c245ea7d/regex-2026.7.19-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4aa5435cdb3eb6f55fe98a171b05e3fbcd95fadaa4aa32acf62afd9b0cfdbcac", size = 297093, upload-time = "2026-07-19T00:18:41.583Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/0b692da2520d51fbff19c88b83d97e4c702909dd02386c585998b7e2dbed/regex-2026.7.19-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:60be8693a1dadc210bbcbc0db3e26da5f7d01d1d5a3da594e99b4fa42df404f5", size = 292043, upload-time = "2026-07-19T00:18:43.347Z" }, + { url = "https://files.pythonhosted.org/packages/e3/a7/1d478e614016045a33feae57446215f9fd65b665a5ceb2f891fb3183bc52/regex-2026.7.19-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19662dbedbe783d323196312d38f5ba53cf56296378252171985da6899887d3", size = 797214, upload-time = "2026-07-19T00:18:45.362Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ae/11b9c9411d92c30e3d2db32df5a31133e4a99a8fc397a604fd08f6c4bffb/regex-2026.7.19-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d15df07081d91b76ff20d43f94592ee110330152d617b730fdbe5ef9fb680053", size = 866433, upload-time = "2026-07-19T00:18:47.315Z" }, + { url = "https://files.pythonhosted.org/packages/b1/62/2b2efc4992f91d6d204b24c647c9f9412e85379d92b7c0ab9fdae622327e/regex-2026.7.19-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:56ad4d9f77df871a99e25c37091052a02528ec0eb059de928ee33956b854b45b", size = 911360, upload-time = "2026-07-19T00:18:49.588Z" }, + { url = "https://files.pythonhosted.org/packages/14/71/986ceea9aa3da548bf1357cad89b63915ec6d21ec957c8113b29ece567df/regex-2026.7.19-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7322ec6cc9fba9d49ab888bb82d67ac5625627aa168f0165139b17018df3fb8a", size = 801275, upload-time = "2026-07-19T00:18:51.767Z" }, + { url = "https://files.pythonhosted.org/packages/15/be/ce9d9534b2cda96eab32c548261224b9b4e220a4126f098f60f42ae7b4cd/regex-2026.7.19-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9c7472192ebfad53a6be7c4a8bfb2d64b81c0e93a1fc8c57e1dd0b638297b5d1", size = 777131, upload-time = "2026-07-19T00:18:54.053Z" }, + { url = "https://files.pythonhosted.org/packages/61/2b/58b5c710f2c3929515a25f3a1ca0dad0dcd4518d4fff3cf23bc7adb8dcd2/regex-2026.7.19-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c10b82c2634df08dfb13b1f04e38fe310d086ee092f4f69c0c8da234251e556e", size = 785020, upload-time = "2026-07-19T00:18:56.579Z" }, + { url = "https://files.pythonhosted.org/packages/84/03/5fe091935b74f15fe0f97998c215cae418d1c0413f6258c7d4d2e83aa37f/regex-2026.7.19-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:17ed5692f6acc4183e98331101a5f9e4f64d72fe58b753da4d444a2c77d05b12", size = 861263, upload-time = "2026-07-19T00:18:58.64Z" }, + { url = "https://files.pythonhosted.org/packages/d8/fa/d60bf82e10841eef62a9e32aac401468f05fddfbcb2942e342b1ba3d2433/regex-2026.7.19-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:22a992de9a0d91bda927bf02b94351d737a0302905432c88a53de7c4b9ce62e2", size = 766199, upload-time = "2026-07-19T00:19:00.705Z" }, + { url = "https://files.pythonhosted.org/packages/bf/5d/11e64d151b0662b81d6bf644c74dc118d461df85bdf2577fadbbf751788a/regex-2026.7.19-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:618a0aed532be87294c4477b0481f3aa0f1520f4014a4374dd4cf789b4cd2c97", size = 851317, upload-time = "2026-07-19T00:19:03.015Z" }, + { url = "https://files.pythonhosted.org/packages/7c/34/532efb87488d90807bae6a443d357ee5e2728a478c597619c8aaa17cc0bd/regex-2026.7.19-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2ce9e679f776649746729b6c86382da519ef649c8e34cc41df0d2e5e0f6c36d4", size = 789557, upload-time = "2026-07-19T00:19:05.338Z" }, + { url = "https://files.pythonhosted.org/packages/d6/90/3a8d5ca977171ec3ae21a71207d2228b2663bde14d7f7ef0e6363ecf9290/regex-2026.7.19-cp314-cp314-win32.whl", hash = "sha256:73f272fba87b8ccfe70a137d02a54af386f6d27aa509fbffdd978f5947aae1aa", size = 272531, upload-time = "2026-07-19T00:19:07.487Z" }, + { url = "https://files.pythonhosted.org/packages/96/e1/8862885e70409de70e8c005f57fb2e7be8d9ef0317250d60f4c9660a300d/regex-2026.7.19-cp314-cp314-win_amd64.whl", hash = "sha256:d721e53758b2cca74990185eb0671dd466d7a388a1a45d0c6f4c13cef41a68ac", size = 280831, upload-time = "2026-07-19T00:19:09.46Z" }, + { url = "https://files.pythonhosted.org/packages/08/82/2693e53e29f9104d9de95d37ce4dd826bd32d5f9c0085d3aa6ac042675c4/regex-2026.7.19-cp314-cp314-win_arm64.whl", hash = "sha256:65fa6cb38ed5e9c3637e68e544f598b39c3b86b808ed0627a67b68320384b459", size = 281099, upload-time = "2026-07-19T00:19:11.398Z" }, + { url = "https://files.pythonhosted.org/packages/92/b7/9a01aa16461a18cde9d7b9c3ab21e501db2ce33725f53014342b91df2b0a/regex-2026.7.19-cp314-cp314t-macosx_10_13_universal2.whl", hash = "sha256:5a2721c8720e2cb3c209925dfb9200199b4b07361c9e01d321719404b21458b3", size = 501121, upload-time = "2026-07-19T00:19:13.425Z" }, + { url = "https://files.pythonhosted.org/packages/f3/5e/bbaeca815dc9191c424c94a4fdc5c87c75748a64a6271821212ebdd4e1a3/regex-2026.7.19-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:199535629f25caf89698039af3d1ad5fcae7f933e2112c73f1cdf49165c99518", size = 299415, upload-time = "2026-07-19T00:19:15.43Z" }, + { url = "https://files.pythonhosted.org/packages/cd/d6/0dd1a321afaab95eb7ff44aa0f637301786f1dc71c6b797b9ed236ed8890/regex-2026.7.19-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:9b60d7814174f059e5de4ab98271cc5ba9259cfea55273a81544dceea32dc8d9", size = 294483, upload-time = "2026-07-19T00:19:17.879Z" }, + { url = "https://files.pythonhosted.org/packages/92/5f/40bacf91d0904f812e13bbbab3864604c463eced8afdc54aeaa50492ea95/regex-2026.7.19-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbece16025afda5e3031af0c4059207e61dcf73ef13af844964f57f387d1c435", size = 811833, upload-time = "2026-07-19T00:19:20.102Z" }, + { url = "https://files.pythonhosted.org/packages/94/7c/4902744261f775aeede8b5627314b38482da29cf49a57b66a6fb753246c5/regex-2026.7.19-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d24ecb4f5e009ea0bd275ee37ad9953b32005e2e5e60f8bbae16da0dbbf0d3a0", size = 871270, upload-time = "2026-07-19T00:19:22.365Z" }, + { url = "https://files.pythonhosted.org/packages/16/70/6980c9be6bf21c0a60ed3e0aea39cf419ecf3b08d1d9947bc56e196ef186/regex-2026.7.19-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8cae6fd77a5b72dae505084b1a2ee0360139faf72fedbab667cd7cc65aae7a6a", size = 917534, upload-time = "2026-07-19T00:19:24.529Z" }, + { url = "https://files.pythonhosted.org/packages/52/92/8b2bd872782ce8c42691e39acb38eb8efe014e5ddb78ad7d943d6f197ce9/regex-2026.7.19-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9724e6cb5e478cd7d8cabf027826178739cb18cf0e117d0e32814d479fa02276", size = 816135, upload-time = "2026-07-19T00:19:26.919Z" }, + { url = "https://files.pythonhosted.org/packages/de/2d/33a602f657bdc4041f17d79f92ab18261d255d91a06117a6e29df023e5e2/regex-2026.7.19-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:572fc57b0009c735ee56c175ea021b637a15551a312f56734277f923d6fd0f6c", size = 785492, upload-time = "2026-07-19T00:19:29.192Z" }, + { url = "https://files.pythonhosted.org/packages/9e/36/0987cf4cb271680064a70d24a475873775a151d0b7058698a006cb0cae4a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:20568e182eb82d39a6bf7cff3fd58566f14c75c6f74b2c8c96537eecf9010e3a", size = 800658, upload-time = "2026-07-19T00:19:31.392Z" }, + { url = "https://files.pythonhosted.org/packages/a8/24/c14f31c135e1ba55fa4f9a58ca98d0842512bf6188230763c31c8f449e3b/regex-2026.7.19-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:1d58561843f0ff7dc78b4c28b5e2dc388f3eff94ebc8a232a3adba961fc00009", size = 865073, upload-time = "2026-07-19T00:19:33.485Z" }, + { url = "https://files.pythonhosted.org/packages/14/85/181a12211f22469f24d2de1ebddfe397d2396e2c29013b9a58134a91069a/regex-2026.7.19-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:61bb1bd45520aacd56dd80943bd34991fb5350afdd1f36f2282230fd5154a218", size = 773684, upload-time = "2026-07-19T00:19:35.599Z" }, + { url = "https://files.pythonhosted.org/packages/23/58/bd1a0c1a62251366f8d21f41b1ea3c76994962071b8b6ea42f72d505c0f0/regex-2026.7.19-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:cd3584591ea4429026cdb931b054342c2bcf189b44ff367f8d5c15bc092a2966", size = 857769, upload-time = "2026-07-19T00:19:37.738Z" }, + { url = "https://files.pythonhosted.org/packages/e4/4f/f7e2dad6756b2fe1fe75dd90a628c3b45f249d39f948dd90cd2476325417/regex-2026.7.19-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5cc26a66e212fa5d6c6170c3a40d99d888db3020c6fdab1523250d4341382e44", size = 804546, upload-time = "2026-07-19T00:19:40.229Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d7/01d31d5bdb09bc026fab77f59a371fdf8f9b292e4810546c56182ca70498/regex-2026.7.19-cp314-cp314t-win32.whl", hash = "sha256:2c4e61e2e1be56f63ec3cc618aa9e0de81ef6f43d177205451840022e24f5b78", size = 274526, upload-time = "2026-07-19T00:19:42.398Z" }, + { url = "https://files.pythonhosted.org/packages/52/0e/cea4ce73bc0a8247a0748228ae6669984c7e1f8134b6fa66e59c0572e0ea/regex-2026.7.19-cp314-cp314t-win_amd64.whl", hash = "sha256:c639ea314df70a7b2811e8020448c75af8c9445f5a60f8a4ced81c306a9380c2", size = 283763, upload-time = "2026-07-19T00:19:44.644Z" }, + { url = "https://files.pythonhosted.org/packages/6f/b6/26e41975febae63b7a6e3e02f32cff6cff2e4f10d19c929082f56aebf7c6/regex-2026.7.19-cp314-cp314t-win_arm64.whl", hash = "sha256:9a15e785f244f3e07847b984ce8773fc3da10a9f3c131cc49a4c5b4d672b4547", size = 283451, upload-time = "2026-07-19T00:19:46.639Z" }, +] + [[package]] name = "requests" version = "2.34.2" @@ -2058,6 +3372,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06", size = 54481, upload-time = "2023-05-01T04:11:28.427Z" }, ] +[[package]] +name = "rich" +version = "15.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz", hash = "sha256:edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36", size = 230680, upload-time = "2026-04-12T08:24:00.75Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl", hash = "sha256:33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb", size = 310654, upload-time = "2026-04-12T08:24:02.83Z" }, +] + [[package]] name = "rpds-py" version = "0.30.0" @@ -2191,8 +3518,12 @@ source = { registry = "https://pypi.org/simple" } resolution-markers = [ "python_full_version >= '3.14' and sys_platform == 'win32'", "python_full_version >= '3.14' and sys_platform != 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform == 'win32'", - "python_full_version >= '3.11' and python_full_version < '3.14' and sys_platform != 'win32'", + "python_full_version == '3.13.*' and sys_platform == 'win32'", + "python_full_version == '3.12.*' and sys_platform == 'win32'", + "python_full_version == '3.11.*' and sys_platform == 'win32'", + "python_full_version == '3.13.*' and sys_platform != 'win32'", + "python_full_version == '3.12.*' and sys_platform != 'win32'", + "python_full_version == '3.11.*' and sys_platform != 'win32'", ] sdist = { url = "https://files.pythonhosted.org/packages/aa/2a/9618a122aeb2a169a28b03889a2995fe297588964333d4a7d67bdf46e147/rpds_py-2026.6.3.tar.gz", hash = "sha256:1cebd1337c242e4ec2293e541f712b2da849b29f48f0c293684b71c0632625d4", size = 64051, upload-time = "2026-06-30T07:17:53.009Z" } wheels = [ @@ -2313,6 +3644,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/10/85/48f0abdcef5cce4e034c7a5b0ceeceba0b01bf0d942824f4bb720afe2dec/rpds_py-2026.6.3-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:8e65860d238379ed982fd9ba690579b5e95af2f4840f99c772816dbe573cb826", size = 586486, upload-time = "2026-06-30T07:17:51.141Z" }, ] +[[package]] +name = "shellingham" +version = "1.5.4" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, +] + +[[package]] +name = "shortuuid" +version = "1.0.13" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/e2/bcf761f3bff95856203f9559baf3741c416071dd200c0fc19fad7f078f86/shortuuid-1.0.13.tar.gz", hash = "sha256:3bb9cf07f606260584b1df46399c0b87dd84773e7b25912b7e391e30797c5e72", size = 9662, upload-time = "2024-03-11T20:11:06.879Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c0/44/21d6bf170bf40b41396480d8d49ad640bca3f2b02139cd52aa1e272830a5/shortuuid-1.0.13-py3-none-any.whl", hash = "sha256:a482a497300b49b4953e15108a7913244e1bb0d41f9d332f5e9925dba33a3c5a", size = 10529, upload-time = "2024-03-11T20:11:04.807Z" }, +] + +[[package]] +name = "simple-websocket" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "wsproto" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/b0/d4/bfa032f961103eba93de583b161f0e6a5b63cebb8f2c7d0c6e6efe1e3d2e/simple_websocket-1.1.0.tar.gz", hash = "sha256:7939234e7aa067c534abdab3a9ed933ec9ce4691b0713c78acb195560aa52ae4", size = 17300, upload-time = "2024-10-10T22:39:31.412Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/52/59/0782e51887ac6b07ffd1570e0364cf901ebc36345fea669969d2084baebb/simple_websocket-1.1.0-py3-none-any.whl", hash = "sha256:4af6069630a38ed6c561010f0e11a5bc0d4ca569b36306eb257cd9a192497c8c", size = 13842, upload-time = "2024-10-10T22:39:29.645Z" }, +] + [[package]] name = "sniffio" version = "1.3.1" @@ -2322,6 +3683,77 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, ] +[[package]] +name = "sounddevice" +version = "0.5.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/2a/f9/2592608737553638fca98e21e54bfec40bf577bb98a61b2770c912aab25e/sounddevice-0.5.5.tar.gz", hash = "sha256:22487b65198cb5bf2208755105b524f78ad173e5ab6b445bdab1c989f6698df3", size = 143191, upload-time = "2026-01-23T18:36:43.529Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1e/0a/478e441fd049002cf308520c0d62dd8333e7c6cc8d997f0dda07b9fbcc46/sounddevice-0.5.5-py3-none-any.whl", hash = "sha256:30ff99f6c107f49d25ad16a45cacd8d91c25a1bcdd3e81a206b921a3a6405b1f", size = 32807, upload-time = "2026-01-23T18:36:35.649Z" }, + { url = "https://files.pythonhosted.org/packages/56/f9/c037c35f6d0b6bc3bc7bfb314f1d6f1f9a341328ef47cd63fc4f850a7b27/sounddevice-0.5.5-py3-none-macosx_10_6_x86_64.macosx_10_6_universal2.whl", hash = "sha256:05eb9fd6c54c38d67741441c19164c0dae8ce80453af2d8c4ad2e7823d15b722", size = 108557, upload-time = "2026-01-23T18:36:37.41Z" }, + { url = "https://files.pythonhosted.org/packages/88/a1/d19dd9889cd4bce2e233c4fac007cd8daaf5b9fe6e6a5d432cf17be0b807/sounddevice-0.5.5-py3-none-win32.whl", hash = "sha256:1234cc9b4c9df97b6cbe748146ae0ec64dd7d6e44739e8e42eaa5b595313a103", size = 317765, upload-time = "2026-01-23T18:36:39.047Z" }, + { url = "https://files.pythonhosted.org/packages/c3/0e/002ed7c4c1c2ab69031f78989d3b789fee3a7fba9e586eb2b81688bf4961/sounddevice-0.5.5-py3-none-win_amd64.whl", hash = "sha256:cfc6b2c49fb7f555591c78cb8ecf48d6a637fd5b6e1db5fec6ed9365d64b3519", size = 365324, upload-time = "2026-01-23T18:36:40.496Z" }, + { url = "https://files.pythonhosted.org/packages/4e/39/a61d4b83a7746b70d23d9173be688c0c6bfc7173772344b7442c2c155497/sounddevice-0.5.5-py3-none-win_arm64.whl", hash = "sha256:3861901ddd8230d2e0e8ae62ac320cdd4c688d81df89da036dcb812f757bb3e6", size = 317115, upload-time = "2026-01-23T18:36:42.235Z" }, +] + +[[package]] +name = "sqlalchemy" +version = "2.0.51" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "greenlet", marker = "(python_full_version < '3.11' and platform_machine == 'AMD64') or (python_full_version < '3.11' and platform_machine == 'WIN32') or (python_full_version < '3.11' and platform_machine == 'aarch64') or (python_full_version < '3.11' and platform_machine == 'amd64') or (python_full_version < '3.11' and platform_machine == 'ppc64le') or (python_full_version < '3.11' and platform_machine == 'win32') or (python_full_version < '3.11' and platform_machine == 'x86_64')" }, + { name = "typing-extensions", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/02/f1/a7a892f18d4d224e6b26f706531eafccc41e37594d37d304786969ee13cb/sqlalchemy-2.0.51.tar.gz", hash = "sha256:804dccd8a4a6242c4e30ad961e540e18a588f6527202f2d6791b01845d59fdc9", size = 9912201, upload-time = "2026-06-15T15:41:20.012Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/71/76/b3ea1d8842e7b62c718a88d302809003d65ed82011460ca48907dde658c4/sqlalchemy-2.0.51-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e8203d2fbd5c6254692ef0a72c740d75b2f3c7ca345404f4c1a4604813c77c0", size = 2162087, upload-time = "2026-06-15T16:05:15.795Z" }, + { url = "https://files.pythonhosted.org/packages/6c/22/f19552eb7876774d50cfd025337ef5d67acc10cd8f29adab7716cf47c352/sqlalchemy-2.0.51-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1af05726b3d0cdba1c55284bf408fd3b792e690fe2399bfb8304565551cda652", size = 3244579, upload-time = "2026-06-15T16:10:36.165Z" }, + { url = "https://files.pythonhosted.org/packages/fc/97/e4a2eb5a8ec5cd3c2a0615a2f15f0afca89ac039229599b9ed0c0ed28e5e/sqlalchemy-2.0.51-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e54ff2dd657f2e3e0fbf2b097db1182f7bfea263eca4353f00065bae2a67c3d", size = 3243515, upload-time = "2026-06-15T16:12:22.627Z" }, + { url = "https://files.pythonhosted.org/packages/74/c6/5900ec624fab3360aa2ec59b99bb2046dd79799e310bb78a0514eaa4038e/sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1e47b1199c2e832e325eacabc8d32d2487f58c9358f97e9a00f5eb93c5680d84", size = 3195492, upload-time = "2026-06-15T16:10:38.097Z" }, + { url = "https://files.pythonhosted.org/packages/8f/41/2ee3c4e1ac4fd22309349823fe13f33febeab1a71db1d7e9d60293a07dcb/sqlalchemy-2.0.51-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c68568f3facf8f66fa76c60e0ced69b67666ffa9941d1d0a3756fda196049080", size = 3215782, upload-time = "2026-06-15T16:12:24.051Z" }, + { url = "https://files.pythonhosted.org/packages/ce/1c/3bd72c341f1cb5faed5a7457ea840228a46be51cfbaf31a9db72fc963f11/sqlalchemy-2.0.51-cp310-cp310-win32.whl", hash = "sha256:0592bdadf86ddcabfd72d9ab66ea8a5d8d2cc6be1cc51fa7e66c03868ac5eac1", size = 2122119, upload-time = "2026-06-15T16:13:26.915Z" }, + { url = "https://files.pythonhosted.org/packages/2a/63/b6dfdd646abf91c3bedb13727226a5e765e5f8365e898d43818e6672fa46/sqlalchemy-2.0.51-cp310-cp310-win_amd64.whl", hash = "sha256:740cf6f35351b1ac3d82369152acf1d51d37e3dcf85d4dc0a22ca01410eabe2a", size = 2145158, upload-time = "2026-06-15T16:13:28.386Z" }, + { url = "https://files.pythonhosted.org/packages/3a/69/a67c69e5f28fc9c99d6f7bd60bd50e91f2fed2423e3b30fb228fa00e51f3/sqlalchemy-2.0.51-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1aa10c0daee6705294d181daadaa793221e1a59ed55000a3fab1d42b088ce4ba", size = 2161838, upload-time = "2026-06-15T16:05:17.144Z" }, + { url = "https://files.pythonhosted.org/packages/9a/a4/c8c22b8438bddc0a030157c6ec0f6ef97b3c38effa444bdab2a27af04090/sqlalchemy-2.0.51-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a5b2ed6d828f1f09bd812861f4f59ca3bc3803f9df871f4555187f0faf018604", size = 3319402, upload-time = "2026-06-15T16:10:40.002Z" }, + { url = "https://files.pythonhosted.org/packages/90/54/44012d32fd77d991256d2ff793ba3807c51d40cb27a85b4796224f6744df/sqlalchemy-2.0.51-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:436728ce18a80f6951a1e11cc6112c2ede9faf20766f1a26195a7c441ca12dbd", size = 3319675, upload-time = "2026-06-15T16:12:25.658Z" }, + { url = "https://files.pythonhosted.org/packages/29/a5/de0592acaf5906cd7430874392d6f7e8b4a7c8437610953ee2d1501c0b44/sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:dc261707bf5739aea8a541593f3cc1d463c2701fb05fbcbba0ce031b69a21260", size = 3270777, upload-time = "2026-06-15T16:10:42.125Z" }, + { url = "https://files.pythonhosted.org/packages/cb/14/a44c90739c780b362238e4ac3cb19dd0ca40d13e6ddc5daa112166ddab4f/sqlalchemy-2.0.51-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a6d26094615306d116dd5e4a51b0304c99dd2356fc569eed6922a80a6bd3b265", size = 3293940, upload-time = "2026-06-15T16:12:27.156Z" }, + { url = "https://files.pythonhosted.org/packages/65/eb/fbd0f206a330e66f8c602a99c37c4e731f107faed62954b41b01f16dd9d9/sqlalchemy-2.0.51-cp311-cp311-win32.whl", hash = "sha256:ca8435d13829b92f4a97362d91975154a4015db3a2634154e1754e9a915e6b86", size = 2121183, upload-time = "2026-06-15T16:13:29.905Z" }, + { url = "https://files.pythonhosted.org/packages/ad/fd/005bf80f3cf6e5c62b5dd68616280f51cd012c60840fa74781b3ed7b1623/sqlalchemy-2.0.51-cp311-cp311-win_amd64.whl", hash = "sha256:4a011ea4510683319ce4ed274b56ee05194b39b6da9d09ca7a39388f0fa84dcc", size = 2145796, upload-time = "2026-06-15T16:13:31.283Z" }, + { url = "https://files.pythonhosted.org/packages/d5/70/e868bc5412acd101a8280f25c95f10eeae0771c4eb806b02491142810ee8/sqlalchemy-2.0.51-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7d78702b26ba1c18b2d0fb2ea940ba7f17a9581b42e8361ff93920ebbee1235a", size = 2160291, upload-time = "2026-06-15T16:08:48.918Z" }, + { url = "https://files.pythonhosted.org/packages/e5/1c/71ee0f8a6b9d7316a1ccd30430b4c62b6c2e36adc96017a4e3a72dce49d6/sqlalchemy-2.0.51-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:581921d849d6e6f994d560389192955e80e2950e18fcdfe2ccea863e01158e6e", size = 3343835, upload-time = "2026-06-15T16:19:42.613Z" }, + { url = "https://files.pythonhosted.org/packages/2b/7c/7ab9f9aadc5944fdd06612484ed7918fe376ad871a5f50404dc1536e0194/sqlalchemy-2.0.51-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1d21ce524ab86c23046e992a5b81cb54c21079c6df6e78b8fc77d77cac70a6b9", size = 3358470, upload-time = "2026-06-15T16:26:38.011Z" }, + { url = "https://files.pythonhosted.org/packages/d0/7d/ff77169fee6186de145a7f2b87006c39638391130abbab2b1f63ac6ea583/sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c5d98a2709840027f5a347c3af0a7c3d5f6c1ff93af2ca1c54494e23cba8f389", size = 3289874, upload-time = "2026-06-15T16:19:45.212Z" }, + { url = "https://files.pythonhosted.org/packages/6f/3b/6c505903710d781b55bc3141ee34a062bf9745a6b5bc7333305b9ed63b33/sqlalchemy-2.0.51-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1181256e0f16479691b5616d36375dc2620ad8332b25978763c3d206ad3f3f1d", size = 3321692, upload-time = "2026-06-15T16:26:39.747Z" }, + { url = "https://files.pythonhosted.org/packages/3c/b7/c5ffe50aa2f4d947c9250e1519d939260329a07fe6272edfccd784b3d007/sqlalchemy-2.0.51-cp312-cp312-win32.whl", hash = "sha256:9f380393be5abeb6815f68fd39271b95127173511b6706b0a630a9995d53f8f5", size = 2119674, upload-time = "2026-06-15T16:23:09.543Z" }, + { url = "https://files.pythonhosted.org/packages/25/dc/46a65916af68a06ef6b972c6050ba4c8f97070fe3fb33097d34229d9bef6/sqlalchemy-2.0.51-cp312-cp312-win_amd64.whl", hash = "sha256:2cf39aabdf48e87c1c2c2ed6d20d33ffa0733b3071ce9c5f66357947dd009080", size = 2146670, upload-time = "2026-06-15T16:23:11.048Z" }, + { url = "https://files.pythonhosted.org/packages/54/fe/a210d52fd1a90ecfae8a78e9d8b27e18d733d60818a8bf250ff690b75120/sqlalchemy-2.0.51-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7c2056838b6685b72fdb36c99996cf862753461a62f2e84f4196371d3b2d6a07", size = 2157184, upload-time = "2026-06-15T16:08:50.374Z" }, + { url = "https://files.pythonhosted.org/packages/17/6b/2dce8369b199cb855110e056032f94a9f66dacc2237d3d39c115a86eac56/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:483b11bd46bf35fc14c52faf338b04300c9e6ce554bce9b11be85bfec3bc3195", size = 3284735, upload-time = "2026-06-15T16:19:46.934Z" }, + { url = "https://files.pythonhosted.org/packages/53/ff/dbc495b8a14da840faffb353857a72d4190113cac33727906fb997047f0f/sqlalchemy-2.0.51-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1bed1ee8b01da6088210aa9412023326fb98a599ba502e6118308601dcbef77f", size = 3302756, upload-time = "2026-06-15T16:26:41.336Z" }, + { url = "https://files.pythonhosted.org/packages/cf/d5/fde8f4dddcf518ee15ab35a7c6a28acc32c8ba548d1d2aa451f96e6dbb0b/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72ca54c952107ba5cd58854b67a5a6268631289d21651a1235396f3b98b47400", size = 3232055, upload-time = "2026-06-15T16:19:49.286Z" }, + { url = "https://files.pythonhosted.org/packages/67/d1/43d3a0ac955a58601c24fa23038b1c55ee3a1ec02c0f96ebb1eae2bcf614/sqlalchemy-2.0.51-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:b3e693d15533a45cd5906f0589f9c35090bef6ef45bf1e8195c424aa0ae06a8d", size = 3269850, upload-time = "2026-06-15T16:26:43.017Z" }, + { url = "https://files.pythonhosted.org/packages/94/df/de669c7054cd47c4439ac34b1b2ee8b804a794791fbb10720e997a2c87c7/sqlalchemy-2.0.51-cp313-cp313-win32.whl", hash = "sha256:b93ab07b5292dbe7e6b8da89475275e7042744283921344b56105f3eeb0f828b", size = 2117721, upload-time = "2026-06-15T16:23:12.36Z" }, + { url = "https://files.pythonhosted.org/packages/d0/8a/403c51d064196bae20a0bc2476577f83a3f8dd299719a97417086b7f2ec5/sqlalchemy-2.0.51-cp313-cp313-win_amd64.whl", hash = "sha256:0f053118c30e53161857a953e4de667d90e274980dccbe5dd3829bbbeece72a5", size = 2143615, upload-time = "2026-06-15T16:23:13.906Z" }, + { url = "https://files.pythonhosted.org/packages/b1/49/a739be2e1d02a96a658eb71ab45d921c874249252358ad24a5bffdd02525/sqlalchemy-2.0.51-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6ea306caaae6bd5afd0a46050003c88f6bf33227377a49298c498c3cb88ff491", size = 2158999, upload-time = "2026-06-15T16:08:51.759Z" }, + { url = "https://files.pythonhosted.org/packages/23/6b/2e0e38cf75c8780eca78d9b2e78164f8bcfd70125e5caa588ff5cbb9c9f4/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c45a496d6bc05dec41dcd4c3a2b183723f47473255c159cd80b503c8f246424d", size = 3282539, upload-time = "2026-06-15T16:19:51.065Z" }, + { url = "https://files.pythonhosted.org/packages/dd/a1/e77854cb5336fd37dc3c6ae3b71de242c98caac5725120be0b526b31cbd0/sqlalchemy-2.0.51-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4004ada0aafe8ae1991b2cd1d99c6d9146126e123bd6f883c260d974aa012e54", size = 3287545, upload-time = "2026-06-15T16:26:44.735Z" }, + { url = "https://files.pythonhosted.org/packages/f6/ab/9e17272fd4dac8df3b83c4fbe52b998a1c9d89a843c8c35ff29b74ff7364/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0f6bcad487aee1c638d707235682fc96f741de00663619881ab235400d03289e", size = 3230929, upload-time = "2026-06-15T16:19:52.625Z" }, + { url = "https://files.pythonhosted.org/packages/02/3c/52f408ea701781caee975606beccc48845f2aee8711ac29843d612c0306c/sqlalchemy-2.0.51-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:39a76529db6305693d8d4affa58ad5b5e2e18edd62daea628b29b97930b3513d", size = 3252888, upload-time = "2026-06-15T16:26:46.454Z" }, + { url = "https://files.pythonhosted.org/packages/24/16/3efd2ee6bc4ca4693a30a1dd17a91b606cae15d517d2a4746611d9b73ce8/sqlalchemy-2.0.51-cp314-cp314-win32.whl", hash = "sha256:08a204d8b5638717c26a24df18fcf40af45a6b22e35b70b1d62f0113c2e278e8", size = 2120551, upload-time = "2026-06-15T16:23:15.629Z" }, + { url = "https://files.pythonhosted.org/packages/7b/78/55b12e70f45bccc40d9e483925c065027b3b98ea4cbbdf6f8c2546feaf6c/sqlalchemy-2.0.51-cp314-cp314-win_amd64.whl", hash = "sha256:96747bfbadb055466e5b46d572618170046b45ce5a4879167f50d70a5319a499", size = 2146318, upload-time = "2026-06-15T16:23:17.108Z" }, + { url = "https://files.pythonhosted.org/packages/21/db/a9574ed40fed418924b1b1a3e54f47ee3963053b3d3d325a0d36b41f2c08/sqlalchemy-2.0.51-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1a213be1fcd5e49d9904c3b9939211ded90bc2a64e93f4c01963474285de", size = 2178920, upload-time = "2026-06-15T15:59:56.285Z" }, + { url = "https://files.pythonhosted.org/packages/bf/90/a1bb5c7cbba76b7bc1fbd586d0a5479a7bc9c27b4a8298f22ec9423b2bb3/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7c6b36ed71f41942bdcd2ad2522be46bfce09d5705be5640ecf19bbc7660e4b7", size = 3566534, upload-time = "2026-06-15T15:58:35.024Z" }, + { url = "https://files.pythonhosted.org/packages/15/4b/481f1fed30e0e9e8dd24aecbb49f29eb57fe7657ece5cf06ee9b84bb97d8/sqlalchemy-2.0.51-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0c2c62877097e1a0db401fba5cb4debee33265e5b2a55c4ccb489c02c53b4f72", size = 3535844, upload-time = "2026-06-15T16:02:43.973Z" }, + { url = "https://files.pythonhosted.org/packages/02/71/0aa64aeda645510af0a43f7d9ee70932f0d1dc4263aed34c50ee891d9df3/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0378d055e9e8cd6ce4d8dff683bdd3d7d413533c4ee51d67a2b1e0f9eacc0f23", size = 3475355, upload-time = "2026-06-15T15:58:36.592Z" }, + { url = "https://files.pythonhosted.org/packages/05/db/6061db32316446135a3abae5f308d144ab988a34234726042da3e58b1c63/sqlalchemy-2.0.51-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6e46fc36029eff666391e0531e5387b62ce6c4f1d8e50b3fb3099eaca1b42522", size = 3486591, upload-time = "2026-06-15T16:02:45.346Z" }, + { url = "https://files.pythonhosted.org/packages/0d/c9/f14fdf71bb8957e0c7e39db69bbdf12b5c80f4ef775fdfa127bf4e0d6760/sqlalchemy-2.0.51-cp314-cp314t-win32.whl", hash = "sha256:9161cfc9efce70d1715f47d6ff40f79c6778c00d53be4fbc09d70301e4b83ba7", size = 2151313, upload-time = "2026-06-15T16:03:39.127Z" }, + { url = "https://files.pythonhosted.org/packages/6a/c6/673e618e6f4f297e126d9b56ea2f6478708f6c1af4e3223835c22e2c3697/sqlalchemy-2.0.51-cp314-cp314t-win_amd64.whl", hash = "sha256:159bb6ba32059f57ad7375a8f50d844dd2f19d14954ecf820cd33e20debd46b2", size = 2186280, upload-time = "2026-06-15T16:03:40.569Z" }, + { url = "https://files.pythonhosted.org/packages/e2/22/dbf013a12ec759e54a34a119e9e217435b3f71b2dd5c61a7ade0a25dae87/sqlalchemy-2.0.51-py3-none-any.whl", hash = "sha256:bb024d8b621d0be75f4f44ecc7c950450026e76d66dc8f791bb5331d7fed59d5", size = 1944334, upload-time = "2026-06-15T16:09:22.418Z" }, +] + [[package]] name = "sse-starlette" version = "3.4.5" @@ -2357,6 +3789,67 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d7/c1/eb8f9debc45d3b7918a32ab756658a0904732f75e555402972246b0b8e71/tenacity-9.1.4-py3-none-any.whl", hash = "sha256:6095a360c919085f28c6527de529e76a06ad89b23659fa881ae0649b867a9d55", size = 28926, upload-time = "2026-02-07T10:45:32.24Z" }, ] +[[package]] +name = "tiktoken" +version = "0.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "regex", marker = "python_full_version < '3.11'" }, + { name = "requests", marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e4/e5/5f3cb2159769d0f4324c0e9e87f9de3c4b1cd45848a96b2eb3566ad5ca77/tiktoken-0.13.0.tar.gz", hash = "sha256:c9435714c3a84c2319499de9a300c0e604449dd0799ff246458b3bb6a7f433c1", size = 38986, upload-time = "2026-05-15T04:51:27.153Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/38/e3/03c90dadcf5b3f82b83cee9adee60ef666b329c654f58c066af44eae0287/tiktoken-0.13.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:47b1df8d73390a24f94980c75158cdd5c56d256f16d55f30cb49c230caba9ba4", size = 1036627, upload-time = "2026-05-15T04:50:11.229Z" }, + { url = "https://files.pythonhosted.org/packages/5e/30/760463e5b2e8ad2bc229ae0a17ecb06727b6cbc094f08d8f65844315632e/tiktoken-0.13.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7d40c6c5aab171dcd6eb8455bc567bde404bb9def60cdb8c1299cc782b242bb9", size = 984699, upload-time = "2026-05-15T04:50:12.874Z" }, + { url = "https://files.pythonhosted.org/packages/de/8a/8895f342a6b6aabd1a358e672f6f077b3ae51d0c63ca605d142db3bcd8ab/tiktoken-0.13.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:9b842981fa91accdffd48ff6408a977b7a91c3fbda55d353c3c68114d5c9d69e", size = 1118690, upload-time = "2026-05-15T04:50:14.234Z" }, + { url = "https://files.pythonhosted.org/packages/51/e0/92557768fb0801f0d9dd9243cb9b6d342900b05e4b1006d4771f49ce233e/tiktoken-0.13.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ed5a30027cb4d8c7ca8b273d4766f3db3cf58fad9e9f3b1a68a351ffb54873d5", size = 1138423, upload-time = "2026-05-15T04:50:15.668Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b9/a3d99feeedb032ffd09cd6652077f86bdee9a70dd0b990b2b272b445d4c3/tiktoken-0.13.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7ab10f4a21c2999846940113f6dbd72e0fa06a24119feddd74cc47e85818e06d", size = 1185077, upload-time = "2026-05-15T04:50:17.19Z" }, + { url = "https://files.pythonhosted.org/packages/cc/93/bab868277d475dc6d2aaacd34cdd239c282f4908dcc8702e0a3311a8e032/tiktoken-0.13.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a2937ad042d49d50eac6e1ba07c5661d4bd3942a5b1e0c0d08475c4df83676e1", size = 1241702, upload-time = "2026-05-15T04:50:18.772Z" }, + { url = "https://files.pythonhosted.org/packages/c3/16/27e9f7e0ed76e501cfefc9fb2112df4c7bf70ca96945b15ecb7615aac860/tiktoken-0.13.0-cp310-cp310-win_amd64.whl", hash = "sha256:44733b99bfd72b590cd0936b1c01b3b4dd73122db2d544bc1ceeb18a7678c910", size = 876565, upload-time = "2026-05-15T04:50:20.268Z" }, + { url = "https://files.pythonhosted.org/packages/1a/4c/1bc81f4cd53e827c4ee67ca951b5935724716049452d8dfa09b8b82372bb/tiktoken-0.13.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:7bfe1849caa65d1e1d9871817170ec497bbb7984e182012e1bdce72f66608cdb", size = 1036353, upload-time = "2026-05-15T04:50:21.757Z" }, + { url = "https://files.pythonhosted.org/packages/75/91/10b9c7076bc02c246c853201fdbbe300a4b8c5ed7b84c25f7403f4e32655/tiktoken-0.13.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:91c180fe255bd5a86d8316210d2833a1d4d33d026cd86a67812f4773743c8d26", size = 984644, upload-time = "2026-05-15T04:50:23.256Z" }, + { url = "https://files.pythonhosted.org/packages/4e/e4/fceae98015fab47fcd49b8bd7f46145bcd187a47e0add1e5378ed67ef980/tiktoken-0.13.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:059c8ecf554eb5b41e6e054ba467b871b03277d267dee7244380aca4359747d4", size = 1119261, upload-time = "2026-05-15T04:50:24.348Z" }, + { url = "https://files.pythonhosted.org/packages/f9/39/fe42ad00de01a8c4a49ad8649a2c8a316835a9cad5961b11d21eac0020a5/tiktoken-0.13.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:36217497eaffc158607a3b26f065300db2aefd43b115263f3b9688ce38146173", size = 1138253, upload-time = "2026-05-15T04:50:25.505Z" }, + { url = "https://files.pythonhosted.org/packages/03/c4/ccee1ecccca107e9a16efcecdeeb964c325305038554d466ece65b42338f/tiktoken-0.13.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:303f7d91b4fce3baddbcde05c139091d4caa5026ac7214c1dc7ff7a71ee429ff", size = 1185747, upload-time = "2026-05-15T04:50:27.02Z" }, + { url = "https://files.pythonhosted.org/packages/9d/03/cd0cba295522b91eb55c6b2704f1df895f8226cfe60ab10d4d51d0cc9e69/tiktoken-0.13.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5d48843bee149630eb735a99e1f4a85b47308d21868ea63163f6e87768d3cfed", size = 1241265, upload-time = "2026-05-15T04:50:28.815Z" }, + { url = "https://files.pythonhosted.org/packages/7e/25/a10efd564402d82c2ff50d12057353ace447aa8007deceaa48641f63d35c/tiktoken-0.13.0-cp311-cp311-win_amd64.whl", hash = "sha256:fc1c44cd37b43fc46bae593129164f4f281e82ea116b57a85aa81bda57eafc94", size = 876509, upload-time = "2026-05-15T04:50:30.026Z" }, + { url = "https://files.pythonhosted.org/packages/85/8e/144bde4e01df66b34bb865557c7cd754ed08b036217ebd79c9db5e9048a9/tiktoken-0.13.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:32ac870a806cfb260a02d0cb70426aef02e038297f8ad50df5040bb5af360791", size = 1034888, upload-time = "2026-05-15T04:50:31.579Z" }, + { url = "https://files.pythonhosted.org/packages/36/18/d4ac9d20956cdebca04841316660ed584c2fecdc2b81722a28bc7ad3b1e4/tiktoken-0.13.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4d9980f11429ed2d737c463bb1fb78cf330caa026adf002f714aced7849a687b", size = 982970, upload-time = "2026-05-15T04:50:32.961Z" }, + { url = "https://files.pythonhosted.org/packages/74/ed/6bb8d05b9f731f749fee5c6f5ca63e981143c826a5985877330507bd13b7/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:3f277ebea5edd7b8bf03c6f9431e1d67d517530115572b2dc1d465326e8f88c7", size = 1115741, upload-time = "2026-05-15T04:50:34.475Z" }, + { url = "https://files.pythonhosted.org/packages/34/de/2ca96b07a82d972b74fe4b46de055b79c904e45c7eab699354a0bfa697dc/tiktoken-0.13.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:a116178fa7e1b4065bff05214360373a65cac22f965be7b3f73d00a0dbfe7649", size = 1136523, upload-time = "2026-05-15T04:50:35.782Z" }, + { url = "https://files.pythonhosted.org/packages/ee/dc/9dafec002c2d4424378563cf4cf5c7fb93631d2a55013c8b87554ee4012c/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2c397ddda233208345b01bd30f2fca79ff730e55731d0108a603f9bc57f6af3b", size = 1181954, upload-time = "2026-05-15T04:50:36.99Z" }, + { url = "https://files.pythonhosted.org/packages/a1/d0/1f8578c45b2f24759b46f0b50d31878c63c73e6bf0f2227e10ec5c5408dc/tiktoken-0.13.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:95097e4f89b06403976e498abf61a0ee73a7497e73fb599cb211d8197a054d91", size = 1240069, upload-time = "2026-05-15T04:50:38.221Z" }, + { url = "https://files.pythonhosted.org/packages/aa/90/28d7f154888610aa9237e541986beb62b479df29d193a5a0617dbb1514d0/tiktoken-0.13.0-cp312-cp312-win_amd64.whl", hash = "sha256:8f2d16e7a7c783ad81f36e457d046d1f1c8af70b22aec8a13238efe531977c41", size = 874748, upload-time = "2026-05-15T04:50:39.587Z" }, + { url = "https://files.pythonhosted.org/packages/9c/83/b096c859c2a47c11731bf2f5885f4028b809dfe2396582883eed9cae372f/tiktoken-0.13.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5df5d1507bd245f1ccad4a074698240021239e455eb0bb4ced4e3d7181872154", size = 1034228, upload-time = "2026-05-15T04:50:40.988Z" }, + { url = "https://files.pythonhosted.org/packages/53/61/c68e123b6d753e3fc2751e9b18e732c9d8bf1e1926762e736eee935d931c/tiktoken-0.13.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8fe806a50664e83a6ffd56cbd1e4f5dcc6cd32a3e7538f70dc38b1a271384545", size = 982978, upload-time = "2026-05-15T04:50:42.195Z" }, + { url = "https://files.pythonhosted.org/packages/ef/8b/96cc178cc584e65d363134500f297790b06cd48cdeb1e8fcf7bbe60f4715/tiktoken-0.13.0-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:125bc05005e747f993a83dc67934249932d6e4209854452cd4c0b1d53fba3ba2", size = 1116355, upload-time = "2026-05-15T04:50:43.564Z" }, + { url = "https://files.pythonhosted.org/packages/86/f5/bab735d2c72ea55404b295d02d092644eb5f7cc6205e34d35eb9abfb9ab2/tiktoken-0.13.0-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:5e6358911cab4adee6712da27d65573496a4f68cf8a2b5fca6a4ad10fc5748cf", size = 1135772, upload-time = "2026-05-15T04:50:44.782Z" }, + { url = "https://files.pythonhosted.org/packages/4e/b9/6de04ebdf904edfaad87788011b3735087a0c9ea671b9027e1e4e965e8c8/tiktoken-0.13.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:975cbd78d085d75d26b59660e262736dcaed1e35f8f142cd6291025c01d25486", size = 1182415, upload-time = "2026-05-15T04:50:46.422Z" }, + { url = "https://files.pythonhosted.org/packages/0d/9c/470a05f3b1caf038f44880e334d47ab674e0c80d514c66b375d14d5afa10/tiktoken-0.13.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:75ab9bc99fa020a4c283424590ecd7f3afd70c1c281cb3fa3192a6c3af9f9615", size = 1239879, upload-time = "2026-05-15T04:50:48.052Z" }, + { url = "https://files.pythonhosted.org/packages/42/a6/c1936d16055436cb32e6c6128d68629622e00f4768562f55653752d34768/tiktoken-0.13.0-cp313-cp313-win_amd64.whl", hash = "sha256:6b1615f0ff71953d19729ceb18865429c185b0a23c5353f1bbca34a394bf60f7", size = 874829, upload-time = "2026-05-15T04:50:49.202Z" }, + { url = "https://files.pythonhosted.org/packages/d6/07/acb5992c3772b5a36284f742cfb7a5895aa4471d1848ac31464ad50d7fdf/tiktoken-0.13.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6eb4a5bfbc6426938026b1a334e898ac53541360d62d8c689870160cc80abd67", size = 1033600, upload-time = "2026-05-15T04:50:50.4Z" }, + { url = "https://files.pythonhosted.org/packages/14/e9/742e9aec30f59b9f161f7ff7cd072e02ea836c9e1c0854a8076dfcd40d5c/tiktoken-0.13.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:43cee3e5400573b2046fbf092cc7a5bc30164f9e4c95ce20714da929df48737a", size = 982516, upload-time = "2026-05-15T04:50:52.03Z" }, + { url = "https://files.pythonhosted.org/packages/72/74/ca1541b053e7648254d2e4b42a253e1bb4359f2c91a0a8d49228c794e1a0/tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_aarch64.whl", hash = "sha256:7de52e3f566d19b3b11bd37eea552c6c305ad74081f736882bd44d148ed4c48d", size = 1115518, upload-time = "2026-05-15T04:50:53.543Z" }, + { url = "https://files.pythonhosted.org/packages/46/e3/93825eaf5a4a504795b787e5d5dea07fbeb3dabf97aa7b450be8bde59c89/tiktoken-0.13.0-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:51384448aa508e4df84c0f7c1dc3211c7f7b8096325660ee5fc82f3e11b381ce", size = 1136867, upload-time = "2026-05-15T04:50:55.191Z" }, + { url = "https://files.pythonhosted.org/packages/8c/46/002b68de6827091d5ae90b048f326e8aad8d953520950e5ce1508879414f/tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:e28157350f7ebf35008dd8e9e0fdb621f976e4230c881099c85e8cf07eaa50e2", size = 1181826, upload-time = "2026-05-15T04:50:56.296Z" }, + { url = "https://files.pythonhosted.org/packages/db/c6/d393e3185a276505182f7abd93fe714f3c444a2be9180798fa052347504e/tiktoken-0.13.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:165cf1820ea4a354985c2490a5205d4cc74661c934aca79dd0368232fff94e0f", size = 1239489, upload-time = "2026-05-15T04:50:57.918Z" }, + { url = "https://files.pythonhosted.org/packages/b7/4d/bc07d1f1635d4897a202acc0ae11c2886eaa7325c359ba4741b47bf8e225/tiktoken-0.13.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6c43a675ca14f6f2749ba7f12075d37456015a24b859f2517b9beb4ef30807ec", size = 873820, upload-time = "2026-05-15T04:50:59.528Z" }, + { url = "https://files.pythonhosted.org/packages/8c/93/0dd6adca026a616c3a92974566b43381eea4b475ce1f36c062b8271a9ac5/tiktoken-0.13.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaaaef47c2406277181d2086484c317bf7fc433e2d5d03ff94f56b0dcec87471", size = 1034977, upload-time = "2026-05-15T04:51:00.957Z" }, + { url = "https://files.pythonhosted.org/packages/d9/77/5ec6e6bc5b30bed6d93f7f2162d8f6b32437b3ba27cb527cfe004f6109c9/tiktoken-0.13.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ca8b310bd93b3772cb1b7922d915446864860f562bdfe4825c63a0aed3fb28cd", size = 983635, upload-time = "2026-05-15T04:51:02.629Z" }, + { url = "https://files.pythonhosted.org/packages/94/b0/c8ae9aff00d625c50659b4513e707a0462c4bf5d4d6cc1b802103225c02e/tiktoken-0.13.0-cp314-cp314-manylinux_2_28_aarch64.whl", hash = "sha256:32e0c12305105002c047b3bb1070b0dd9a73b0cb3b2856a8972b810e7a4f5881", size = 1116036, upload-time = "2026-05-15T04:51:04.082Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ac/6a5dddd1d0a6018ecb389bd0353e6b4a515eb4d2286611bd0ace1937b9e1/tiktoken-0.13.0-cp314-cp314-manylinux_2_28_x86_64.whl", hash = "sha256:5ba5fd62507a932d1241346179e3b39bc7bf7408f03c272652d93b3bedf5db24", size = 1135544, upload-time = "2026-05-15T04:51:05.229Z" }, + { url = "https://files.pythonhosted.org/packages/f4/b8/585032b4384b2f7dcdaddcb52865c83a701a420d09e3c2b4a2be1c450c57/tiktoken-0.13.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:d108bc2d470fc53c8ecd24f2c0fd2b5f98c33e87cdb6aa2e9b8c5dced703d273", size = 1182217, upload-time = "2026-05-15T04:51:06.517Z" }, + { url = "https://files.pythonhosted.org/packages/cd/b6/993ff1ded3958215fd341a847b8e5ffeb5de473f435296870d314fc91ac4/tiktoken-0.13.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:cb99cb5127449f58d0a2d5f5ccfb390d8dbdfd919c221246caaee29d8725ed51", size = 1239404, upload-time = "2026-05-15T04:51:07.843Z" }, + { url = "https://files.pythonhosted.org/packages/dd/3d/fef7e06e3b33e7538db0ced734cf9fe23b6832d2ac4990c119c377aec55e/tiktoken-0.13.0-cp314-cp314-win_amd64.whl", hash = "sha256:115c4f26ffa11caac8b54eea35c2ad38c612c20a48d35dd15d70a02ac6f51f58", size = 918686, upload-time = "2026-05-15T04:51:08.925Z" }, + { url = "https://files.pythonhosted.org/packages/c1/82/a7fc44582bc32ab00de988a2299bf77c077f59068b233109e34b7d6ca7e6/tiktoken-0.13.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:472527e9132952f2fbf77cd290658bacf003d4d5a3fabc18e5fbd407cbae4d9b", size = 1034454, upload-time = "2026-05-15T04:51:10.035Z" }, + { url = "https://files.pythonhosted.org/packages/37/d0/24d8a890c14f432a05cea669c17bebeaa99f96a7c79523b590f564246411/tiktoken-0.13.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:4e2f67d27c9626cdd25fe33d9313c5cdb3d8d82da646b68d6eb8e7e9c20e6448", size = 982976, upload-time = "2026-05-15T04:51:11.23Z" }, + { url = "https://files.pythonhosted.org/packages/49/b7/2ab43f62788a9266187a9bfc1d3af99ad83e5eaa25fbef168a69cd5ad14f/tiktoken-0.13.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:2b920b35805cd64585a37c3dc7ce65fba4d2d36016be01e1d7942482ca29093a", size = 1115526, upload-time = "2026-05-15T04:51:12.608Z" }, + { url = "https://files.pythonhosted.org/packages/64/39/1494321ed323ce7a14d88e3cd6cb9058625977df1c6961ddc492bd10a9f3/tiktoken-0.13.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:493af3aa28a4aaf2e3d2600a2ee717252c9bf5ab38fff94eb5a02db5ab77e5ad", size = 1136466, upload-time = "2026-05-15T04:51:13.926Z" }, + { url = "https://files.pythonhosted.org/packages/96/d9/dfd086aa2d918c563a140720e0ce296cada1634efd2783d5cf51e05f984e/tiktoken-0.13.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6644c9c2b5cf3916f5a3641d7d12fdb3f006a7b3d9ff6acdaec44e29ab1ff91e", size = 1181863, upload-time = "2026-05-15T04:51:15.025Z" }, + { url = "https://files.pythonhosted.org/packages/2f/68/a18b4f307086954fdae32714cb4f85562e34f9d34ab206e61f1816aa6018/tiktoken-0.13.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5cb65b60b9408563676d874a3a4ee573370066f0dc4e29d84e82e989c6517424", size = 1239218, upload-time = "2026-05-15T04:51:16.103Z" }, + { url = "https://files.pythonhosted.org/packages/16/5b/f2aa703a4fc5d2dff73460a7d46cc2f3f44aa0f3dd8eeb20d2a0ecf68862/tiktoken-0.13.0-cp314-cp314t-win_amd64.whl", hash = "sha256:85b78cc3a2c3d48723ca751fa981f1fedccd54194ca0471b957364353a898b07", size = 918110, upload-time = "2026-05-15T04:51:17.237Z" }, +] + [[package]] name = "tomli" version = "2.4.1" @@ -2495,6 +3988,85 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/22/2a/5e5e750890ada51017d18d0d4c30da696e5b5bd3180947729927628fc3cb/tqdm-4.68.4-py3-none-any.whl", hash = "sha256:5168118b2368f48c561afda8020fd79195b1bdb0bdf8086b88442c267a315dc2", size = 676612, upload-time = "2026-07-07T09:58:16.256Z" }, ] +[[package]] +name = "tree-sitter" +version = "0.26.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/03/5600b84aff2e6c4fe80cfebb4063fe2f50299521befe5f6092ab8c082f4a/tree_sitter-0.26.0.tar.gz", hash = "sha256:b40c219edccc4564530c96f8f1556f6202b37cda964d1cbd7bd2b7e68b40a245", size = 191423, upload-time = "2026-06-30T12:14:27.933Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/2f/201c33ea65875d8e4ec73e4d1949718ec49780d84c0adf19793ef75d99a2/tree_sitter-0.26.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ff527388df14cb5009f9274faf78cc69a7393ae6acf3b04784b8acca249519c5", size = 148676, upload-time = "2026-06-30T12:13:42.718Z" }, + { url = "https://files.pythonhosted.org/packages/9e/db/05b9d45dd2b9827bf91b6819e749227ca6d686d58658292c0f149294b18e/tree_sitter-0.26.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7bcbadfa614326debef581957d5c780a9d7f66065c13deea61aa21d1dd36263f", size = 140757, upload-time = "2026-06-30T12:13:44.007Z" }, + { url = "https://files.pythonhosted.org/packages/b9/08/1e1da65c1585b8d70130b26d65b41a71737ab623c1fab1008479c2b95b50/tree_sitter-0.26.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2f941cea06128c1f74f8937a8e2a90c7db49cf4be6647cd9e07d92a306d91517", size = 631526, upload-time = "2026-06-30T12:13:45.008Z" }, + { url = "https://files.pythonhosted.org/packages/b0/b7/06353044a80ee58a71e884b4a9b2913705849d81025d87308abdfef8f883/tree_sitter-0.26.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e9e46b664887d8c1014f1fb33e09454bbdd9ec1fe29b7fd02dde7b46bc1bb81a", size = 658688, upload-time = "2026-06-30T12:13:46.491Z" }, + { url = "https://files.pythonhosted.org/packages/df/56/c4b22ccbc4f89ae507c0b76e29f363ad4f16eb38c43f7392b3eb9afec64e/tree_sitter-0.26.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:763627db05db34f12333081bd7422cc1c675893d373cc870b3e9249e200700e4", size = 644399, upload-time = "2026-06-30T12:13:47.719Z" }, + { url = "https://files.pythonhosted.org/packages/b5/b7/6b3f0192d5b9b49a199cb0dcd5e45dd1327a82c52c80a49edd790e3a2d9b/tree_sitter-0.26.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:17a1c5cfd3a05d5c7c86bf4282b6ef8092c91dc0a98390499669c3fedb7d1814", size = 655316, upload-time = "2026-06-30T12:13:49.03Z" }, + { url = "https://files.pythonhosted.org/packages/a5/6b/f7475c8f8d699671c2a80c3ed16f5cddd161280c6ed5b845117179c66075/tree_sitter-0.26.0-cp310-cp310-win_amd64.whl", hash = "sha256:f289be0225ba2ace8e87d6c9639b2bc9ff2b5271afb7c5d39282a4a00e248682", size = 129494, upload-time = "2026-06-30T12:13:50.242Z" }, + { url = "https://files.pythonhosted.org/packages/f6/20/0df8dd708638cba7ef875fff4ce80122af7f604f1f0b566de2164108bc01/tree_sitter-0.26.0-cp310-cp310-win_arm64.whl", hash = "sha256:526a165a2cb1d1f79e247d400f0e0acd8d49a817d6f312d543513af200b1f886", size = 116486, upload-time = "2026-06-30T12:13:51.21Z" }, + { url = "https://files.pythonhosted.org/packages/41/18/78aae7e4b5a36daaebb0276e4b07d084d45298758000787838e89329e11f/tree_sitter-0.26.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1d6fe0e8fb4df77b5ee816228e2c4475a63d8cc1d4d3a7ffd7097b2b87fc3e95", size = 148679, upload-time = "2026-06-30T12:13:52.27Z" }, + { url = "https://files.pythonhosted.org/packages/24/e4/b371b9553b0e47d130fc2073e56cab94fecc868be04666bf5bbd1fcd1cc9/tree_sitter-0.26.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:514a9bf8993e5210e7970736aaf6020d1759b670e195ef17b1c48f586aa30736", size = 140759, upload-time = "2026-06-30T12:13:53.221Z" }, + { url = "https://files.pythonhosted.org/packages/22/7d/266fb0f2c41e6fb00b0f40e7a3338cdf99651e6a6511ca72bc78fc697636/tree_sitter-0.26.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10f0d4eb94aa7242dcb7f554bcd24dd7ba1c114f00d58759ba08c7a46c8ec51a", size = 637206, upload-time = "2026-06-30T12:13:54.334Z" }, + { url = "https://files.pythonhosted.org/packages/40/9f/47cf22febb47132d5b3a507a27bb99ef89fe5c8ec420a13c6daa9b64f782/tree_sitter-0.26.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:335294ce0504fcefde5245dff596778ffaf820205b98ae0b549c72e48855f1d8", size = 664758, upload-time = "2026-06-30T12:13:55.42Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4d/8d144ca3beb46a62a5102b6deac76bb0da55235c2c7840faf3b12f2e9d97/tree_sitter-0.26.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f9997ba61368c48ed54e715676afadf703947a1542464e39d047764fb3624b01", size = 647438, upload-time = "2026-06-30T12:13:56.523Z" }, + { url = "https://files.pythonhosted.org/packages/4d/ed/ed1d6e78520c4fb64ed52fec3f2947bf8c1fbad7bc24e282c56193c9ba42/tree_sitter-0.26.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c56581ad256c4195a21bfe449fed5d44a02fe83a4a7d6e70e6ec302c881191c7", size = 661944, upload-time = "2026-06-30T12:13:57.82Z" }, + { url = "https://files.pythonhosted.org/packages/10/83/45f5bd43db1b8248d2fd08ef6cbe43e2725c539e09a2cfb8bc2818646788/tree_sitter-0.26.0-cp311-cp311-win_amd64.whl", hash = "sha256:0f8793fd18ad7eec276ed4b51c097b4bf2002b357259b66b0d75db1f3f41c754", size = 129496, upload-time = "2026-06-30T12:13:59.216Z" }, + { url = "https://files.pythonhosted.org/packages/f1/8d/be68e6c04563eb54145424cc83fe0aa8b0ba6c90d8989cf8a032671b5f16/tree_sitter-0.26.0-cp311-cp311-win_arm64.whl", hash = "sha256:dea4b4e27d49e9ec5b785d4f994da000e6726882fcc6ad05ec98478500c71aef", size = 116484, upload-time = "2026-06-30T12:14:00.147Z" }, + { url = "https://files.pythonhosted.org/packages/87/ca/565702c44815393e3a973552ad546db4e5ca081ca8698640b4e93d809f51/tree_sitter-0.26.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6cb2bd20efb2544c19ac54486ab7cb8ec7b36f913bbe1ce95df84acb96743d9c", size = 148934, upload-time = "2026-06-30T12:14:01.188Z" }, + { url = "https://files.pythonhosted.org/packages/54/6f/8bb61957f16ec1b1d92410a006cdc84a952b6352a7313b2ad299f2d21484/tree_sitter-0.26.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:918d89529786873f0982a0f59c2a303cd065fbfd1b903d71a8e4e1584f67b42e", size = 140820, upload-time = "2026-06-30T12:14:02.087Z" }, + { url = "https://files.pythonhosted.org/packages/78/0a/8a6f08559182643a814a4ab559948ae817b2851890fd9b995a4fff6541ce/tree_sitter-0.26.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:30a88be89ff1f2755297f81e8080d88b795dd98720c3f9fa2acf93873182cc95", size = 638844, upload-time = "2026-06-30T12:14:03.428Z" }, + { url = "https://files.pythonhosted.org/packages/8a/2f/6e6781b31677231366cb3cf27bc8269157f6d4b03c9032865a4f5f2bbe7e/tree_sitter-0.26.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5a6b333b0282d8bb0af741f9b018bd2523d4eecb2686bf6717066a625fecfaa4", size = 667487, upload-time = "2026-06-30T12:14:04.669Z" }, + { url = "https://files.pythonhosted.org/packages/02/0b/0483078c8567445557a7015b0e5b187f6d7d4fda73464df9c4bdea7f7f3c/tree_sitter-0.26.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3f3c44339dd34fe8eb2b8d5aa7610660499a795f70376b130bbee7a437337280", size = 647975, upload-time = "2026-06-30T12:14:05.797Z" }, + { url = "https://files.pythonhosted.org/packages/27/68/da83ca72c984e96ab4eb3bee0db1a6ffb5de1c8c455f92bd9f420cde7f0e/tree_sitter-0.26.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:94550e13b6ae576969da40246f4c4abb206380b5375ad43f26dd9151d55438e3", size = 665018, upload-time = "2026-06-30T12:14:07.278Z" }, + { url = "https://files.pythonhosted.org/packages/d1/36/4d67927fd47b89af4a00f65f55a7370e28778cd50e972c2430487e3ecc27/tree_sitter-0.26.0-cp312-cp312-win_amd64.whl", hash = "sha256:ca89e361a276dbc934b28a43dd881199e25d34ff5493ee0ce45f3c52a6124a37", size = 129619, upload-time = "2026-06-30T12:14:08.373Z" }, + { url = "https://files.pythonhosted.org/packages/ed/72/cdefad523eb78710679c6da6a79e3d90f5afd32b1c6aa5a17bac7eef99f6/tree_sitter-0.26.0-cp312-cp312-win_arm64.whl", hash = "sha256:bc6cb01d5ee75c85424aa1f1c72a82d8f07fd52539a0f3c4a6ed3e8721079b84", size = 116545, upload-time = "2026-06-30T12:14:09.273Z" }, + { url = "https://files.pythonhosted.org/packages/cb/b0/465257cf8f972ad9f9812ec1cbaa8ec210ebebb601ade9a15881aa2436b4/tree_sitter-0.26.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ed0889dbed843ce45ede9f5169c0b2dea2222f12685844a03fadb81f12705867", size = 148893, upload-time = "2026-06-30T12:14:10.541Z" }, + { url = "https://files.pythonhosted.org/packages/a1/ec/19d093e854b45e807fecfdd26105c266f43aeecc39c4dc97992a7074ad5a/tree_sitter-0.26.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6189c6c340c7384357711e3d92645e96bfb79f7a502f86de1ebdb23eb43f7dab", size = 140829, upload-time = "2026-06-30T12:14:11.626Z" }, + { url = "https://files.pythonhosted.org/packages/9b/ee/87e74671ed63a837e7a1f17ab94aa3913871e033b27523d8e7b83d6f7ad0/tree_sitter-0.26.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ff2e0750b7daa722302838356d7b65e303829b7eb73c915df127ddba115e1d1", size = 639334, upload-time = "2026-06-30T12:14:12.836Z" }, + { url = "https://files.pythonhosted.org/packages/66/e7/f7e04cd9dff6b6ac0adf23922796fbc76accd4cf4bcda50542748d485679/tree_sitter-0.26.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7075ef857ef86f327dbb72d1e2574dda78db5754b3a1fca6506acd7fe5d561a7", size = 668102, upload-time = "2026-06-30T12:14:14.035Z" }, + { url = "https://files.pythonhosted.org/packages/d3/90/0bfb16b7894fea728c774a89d5af421a9368a2f913bbd4e8dcab7caaecfb/tree_sitter-0.26.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:26c996c1edfee86e977bb3f5462e74fcec0d0b0db1e85a3c475875763caa03be", size = 648560, upload-time = "2026-06-30T12:14:15.302Z" }, + { url = "https://files.pythonhosted.org/packages/cd/e6/0fe05ba396e9623b0ae40ccf34171336b8701ec8d7bd0ee9f5224d638665/tree_sitter-0.26.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:00289bfe7978f3e0dc0ce69813a20fa9f44ea4c100b3ec62043e5eb74ccfc3a2", size = 665121, upload-time = "2026-06-30T12:14:16.403Z" }, + { url = "https://files.pythonhosted.org/packages/eb/d2/a944b1ca35bed6068dc84a9967aaf3049d8cc0b7a36179eea8787270a6ab/tree_sitter-0.26.0-cp313-cp313-win_amd64.whl", hash = "sha256:93e220cab7e6a823efeb2046c49171427de92ef71c7c681c01820d14d8d3721f", size = 129615, upload-time = "2026-06-30T12:14:17.463Z" }, + { url = "https://files.pythonhosted.org/packages/09/ef/c7ca48293580d2249f36940c4eed5b4ddeb9ce75baf9a4ef30621987e0c7/tree_sitter-0.26.0-cp313-cp313-win_arm64.whl", hash = "sha256:b31a8195d2f224224c530ac814632d98c1dcc123d227442c07c736e86b70d564", size = 116525, upload-time = "2026-06-30T12:14:18.53Z" }, + { url = "https://files.pythonhosted.org/packages/c5/7a/4d84e6f6ae2c3e757490dd84de251712c31e293dfe31f28da1ec019cefa2/tree_sitter-0.26.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:5a3c93a352b7e6f70f73e121bbfa2d0117ba7478bd51114ed35c91b0b78814fa", size = 148901, upload-time = "2026-06-30T12:14:19.452Z" }, + { url = "https://files.pythonhosted.org/packages/b0/d9/efe62ec65dc9d096e834d27b8c058127e2146e42ff3380b822a233f016a6/tree_sitter-0.26.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5fc2f41bf246ff2f70a9cc3690be35ec7580a4923151873d898c8bcb1a4503d3", size = 140805, upload-time = "2026-06-30T12:14:20.478Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2c/c82326b7b97e3c485c18679883b16f89e5e913c639d3b219d3da70c9e67e/tree_sitter-0.26.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8ea92a255c91671a7ec4625aba3ab7bb5220c423630ffbf83c45d7312abe084", size = 640586, upload-time = "2026-06-30T12:14:21.527Z" }, + { url = "https://files.pythonhosted.org/packages/e2/7a/f56e7d8282859452611024c7cbc623bfba5b24b8cb9b8f8bc88c5219fe9a/tree_sitter-0.26.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f665510f0fcf4636fb9696f1f7853bed7a3bd764b7bb0cb8494e619c14ed5a0c", size = 668300, upload-time = "2026-06-30T12:14:22.728Z" }, + { url = "https://files.pythonhosted.org/packages/91/51/240ee81b9d5e9ca0a6cb1528e8605ffa70ab58c89ce126631be96d3e4bae/tree_sitter-0.26.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:253df7ab82cc0a9d311cd65f06e9f99fb3eac55996ae9fc94da22f123a861b90", size = 649627, upload-time = "2026-06-30T12:14:23.819Z" }, + { url = "https://files.pythonhosted.org/packages/6a/54/760035cefedf9eb44f0f84c4ac22f1322e73155853e272576ee876336312/tree_sitter-0.26.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ff80d4833d330a73184a3ac5132abe93c575d2dea31975c6f15c0d21fef238aa", size = 664885, upload-time = "2026-06-30T12:14:25.064Z" }, + { url = "https://files.pythonhosted.org/packages/c9/1b/0b36fe2a984ecedc4ce6aefd5d56447a6626a8e9b595c4e48658510ce8f8/tree_sitter-0.26.0-cp314-cp314-win_amd64.whl", hash = "sha256:a4033fecc8f606c7f2e8b8014d0057b74668a7f0152763606f7bc25c5f9ec64c", size = 132688, upload-time = "2026-06-30T12:14:26.106Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/ebc041a13fbf40144afdb0d4b447e48e0b4012ca866c63de8b48f801f0c1/tree_sitter-0.26.0-cp314-cp314-win_arm64.whl", hash = "sha256:823251c4b6725a7c03ed497a339135ede7ae4bdde75bb8be7ef5e305aeb4ff52", size = 120287, upload-time = "2026-06-30T12:14:26.991Z" }, +] + +[[package]] +name = "tree-sitter-bash" +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8e/0e/f0108be910f1eef6499eabce517e79fe3b12057280ed398da67ce2426cba/tree_sitter_bash-0.25.1.tar.gz", hash = "sha256:bfc0bdaa77bc1e86e3c6652e5a6e140c40c0a16b84185c2b63ad7cd809b88f14", size = 419703, upload-time = "2025-12-02T17:01:08.849Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/30/8e/37e7364d9c9c58da89e05c510671d8c45818afd7b31c6939ab72f8dc6c04/tree_sitter_bash-0.25.1-cp310-abi3-macosx_10_9_x86_64.whl", hash = "sha256:0e6235f59e366d220dde7d830196bed597d01e853e44d8ccd1a82c5dd2500acf", size = 194160, upload-time = "2025-12-02T17:00:59.047Z" }, + { url = "https://files.pythonhosted.org/packages/23/bb/2d2cfbb1f89aaeb1ec892624f069d92d058d06bb66f16b9ec9fb5873ab60/tree_sitter_bash-0.25.1-cp310-abi3-macosx_11_0_arm64.whl", hash = "sha256:f4a34a6504c7c5b2a9b8c5c4065531dea19ca2c35026e706cf2eeeebe2c92512", size = 202659, upload-time = "2025-12-02T17:01:00.275Z" }, + { url = "https://files.pythonhosted.org/packages/25/f0/1bb25519be27460255d3899db677313cfa1e6306988fbf456a3d7e211bbb/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e76c4cfb20b076552406782b7f8c2a3946835993df0a44df006de54b7030c7dc", size = 230596, upload-time = "2025-12-02T17:01:01.759Z" }, + { url = "https://files.pythonhosted.org/packages/d7/22/9f70bc3d3b942ab9fc0f89c1dc9e087519a3a94f64ae6b7377aae3a7a0f0/tree_sitter_bash-0.25.1-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3f484c4bb8796cde7a87ca351e6116f09653edac0eb3c6d238566359dd28b117", size = 231981, upload-time = "2025-12-02T17:01:02.859Z" }, + { url = "https://files.pythonhosted.org/packages/7a/c3/f1540e42cd41b323c6821e45e52e1aed6ed386209aad52db996f05703963/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5e76af6df46d958c7f5b6d5884c9743218e3902a00ccb493ec92728b1084430b", size = 228364, upload-time = "2025-12-02T17:01:03.997Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a0/c3050a6277dfcac8c480f514dc4fe49f3f65f0eac68b4702cbaca2584e85/tree_sitter_bash-0.25.1-cp310-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a3332d71c7b7d5f78259b19d02d0ea111fcb82b72712ee4a93aaa5b226d3f0a8", size = 230074, upload-time = "2025-12-02T17:01:05.05Z" }, + { url = "https://files.pythonhosted.org/packages/71/0f/203fe6b27211387f4b9ba8c4a321567ca4ded2624dae6ccdbd2b6e940e17/tree_sitter_bash-0.25.1-cp310-abi3-win_amd64.whl", hash = "sha256:52a6802d9218f86278aa3e8b459c3abdad67eed0fde1f9f13aca5b6c634217a6", size = 195574, upload-time = "2025-12-02T17:01:06.412Z" }, + { url = "https://files.pythonhosted.org/packages/47/75/4ca1a9fabd8fb5aea78cea70f7837ce4dbf2afae115f62051e5fa99cba1c/tree_sitter_bash-0.25.1-cp310-abi3-win_arm64.whl", hash = "sha256:59115057ec2bae319e8082ff29559861045002964c3431ccb0fc92aa4bc9bccb", size = 191196, upload-time = "2025-12-02T17:01:07.486Z" }, +] + +[[package]] +name = "typer" +version = "0.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "rich" }, + { name = "shellingham" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/78/fda3361b56efc27944f24225f6ecd13d96d6fcfe37bd0eb34e2f4c63f9fc/typer-0.27.0.tar.gz", hash = "sha256:629bd12ea5d13a17148125d9a264f949eb171fb3f120f9b04d85873cab054fa5", size = 203430, upload-time = "2026-07-15T19:21:07.007Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/40/03/26a383c9e58c213199d1aad1c3d353cfc22d4444ec6d2c0bf8ad02523843/typer-0.27.0-py3-none-any.whl", hash = "sha256:6f4b27631e47f077871b7dc30e933ec0131c1390fbe0e387ea5574b5bac9ccf1", size = 122716, upload-time = "2026-07-15T19:21:05.553Z" }, +] + [[package]] name = "typing-extensions" version = "4.16.0" @@ -2708,6 +4280,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e1/a3/27353ea3fbf9e7d4f03375176a838c632d009f5167d801adcbb5f6d3bd07/weaviate_client-4.22.0-py3-none-any.whl", hash = "sha256:ff2dbc8d1fc25739942402c22d1aba2350a16ba4a6b6ed0ba140689c70adf1d9", size = 652691, upload-time = "2026-06-18T06:08:28.622Z" }, ] +[[package]] +name = "websocket-client" +version = "1.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/41/aa4bf9664e4cda14c3b39865b12251e8e7d239f4cd0e3cc1b6c2ccde25c1/websocket_client-1.9.0.tar.gz", hash = "sha256:9e813624b6eb619999a97dc7958469217c3176312b3a16a4bd1bc7e08a46ec98", size = 70576, upload-time = "2025-10-07T21:16:36.495Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/34/db/b10e48aa8fff7407e67470363eac595018441cf32d5e1001567a7aeba5d2/websocket_client-1.9.0-py3-none-any.whl", hash = "sha256:af248a825037ef591efbf6ed20cc5faa03d3b47b9e5a2230a529eeee1c1fc3ef", size = 82616, upload-time = "2025-10-07T21:16:34.951Z" }, +] + [[package]] name = "websockets" version = "15.0.1" @@ -2853,6 +4434,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6e/d2/6317eb6d4554855bbf12d61857774af34747bf88a42c19bf306de67e2fa3/wrapt-2.2.2-py3-none-any.whl", hash = "sha256:5bad217350f19ce99ca5b5e71d406765ea86fe541628426772b657375ee1c048", size = 61460, upload-time = "2026-06-20T23:49:42.966Z" }, ] +[[package]] +name = "wsproto" +version = "1.3.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c7/79/12135bdf8b9c9367b8701c2c19a14c913c120b882d50b014ca0d38083c2c/wsproto-1.3.2.tar.gz", hash = "sha256:b86885dcf294e15204919950f666e06ffc6c7c114ca900b060d6e16293528294", size = 50116, upload-time = "2025-11-20T18:18:01.871Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a4/f5/10b68b7b1544245097b2a1b8238f66f2fc6dcaeb24ba5d917f52bd2eed4f/wsproto-1.3.2-py3-none-any.whl", hash = "sha256:61eea322cdf56e8cc904bd3ad7573359a242ba65688716b0710a5eb12beab584", size = 24405, upload-time = "2025-11-20T18:18:00.454Z" }, +] + [[package]] name = "xxhash" version = "3.8.1" @@ -3010,6 +4603,122 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6b/57/5c6e0908a47f61dca96d01c8ee6fce01ed1050611eb779083ba8758fed81/xxhash-3.8.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:345b07b78e2bf583d71682aa34ae5b5fab575f7a1cb31e10263ebbc6f89f8c42", size = 32869, upload-time = "2026-07-06T10:49:55.972Z" }, ] +[[package]] +name = "yarl" +version = "1.24.5" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "idna" }, + { name = "multidict" }, + { name = "propcache" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/31/33/ebe9e3d1f86c7a0b51094c0a146392045ca1631d2664889539dec8088a33/yarl-1.24.5.tar.gz", hash = "sha256:e81b83143bee16329c23db3c1b2d82b29892fcbcb849186d2f6e98a5abe9a57f", size = 228679, upload-time = "2026-07-20T02:07:45.435Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/ac/cacdda1f0a90441297210bc34cf7e4ac1b7318c8030ebd83bdf6fe82f1db/yarl-1.24.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:88f50c94e21a0a7f14042c015b0eba1881af78562e7bf007e0033e624da59750", size = 135466, upload-time = "2026-07-20T02:04:21.695Z" }, + { url = "https://files.pythonhosted.org/packages/c0/a5/1b2ceace0230e40c52ab1b263148059a43a6303219b996affc68f8381836/yarl-1.24.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6efbccc3d7f75d5b03105172a8dc86d82ba4da86817952529dd93185f4a88be2", size = 97291, upload-time = "2026-07-20T02:04:24.045Z" }, + { url = "https://files.pythonhosted.org/packages/59/1d/340d1a0db7bbce1f291afc044255ebf4ebbce2b25ab1b3f7d3d069080f5d/yarl-1.24.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0ebfaffe1a16cb72141c8e09f18cc76856dbe58639f393a4f2b26e474b96b871", size = 97154, upload-time = "2026-07-20T02:04:25.761Z" }, + { url = "https://files.pythonhosted.org/packages/05/41/25596a33c2fb5098dca8dc3773b04221db64ded0b7f8f09885647d864610/yarl-1.24.5-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8ac73abdc7ab75610f95a8fd994c6457e87752b02a63987e188f937a1fc180f0", size = 109196, upload-time = "2026-07-20T02:04:27.543Z" }, + { url = "https://files.pythonhosted.org/packages/f2/df/dd9f2fb8a5c6054fbefd1538d2b9b1127e612d2ee64b307a070173b57afd/yarl-1.24.5-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4d97a951a81039050e45f04e96689b58b8243fa5e62aa14fe67cb6075300885e", size = 102556, upload-time = "2026-07-20T02:04:29.16Z" }, + { url = "https://files.pythonhosted.org/packages/cb/57/4754b9d2c8945880290ecba0864e8b0441e117bba70534fe819e3645e174/yarl-1.24.5-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fe7b7bb170daccbba19ad33012d2b15f1e7942296fd4d45fc1b79013da8cc0f2", size = 117965, upload-time = "2026-07-20T02:04:30.845Z" }, + { url = "https://files.pythonhosted.org/packages/74/b5/6a9ece27d2043c3386f902dd078ab35d29ef5126b3206ebffb673283a7cb/yarl-1.24.5-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:89a1bbb58e0e3f7a283653d854b1e95d65e5cfd4af224dac5f02629ec1a3e621", size = 116266, upload-time = "2026-07-20T02:04:32.573Z" }, + { url = "https://files.pythonhosted.org/packages/9e/bc/a6653249f6ee59ec85dcfec008d9cbc16586dad613963bb17a91b2b993a5/yarl-1.24.5-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7fa5e51397466ea7e98de493fa2ff1b8193cfef8a7b0f9b4842f92d342df0dba", size = 110758, upload-time = "2026-07-20T02:04:34.235Z" }, + { url = "https://files.pythonhosted.org/packages/65/7e/c5a12fb8208df7b981bc82256e7831ce428eeaf893f7bbe6179c57bb9252/yarl-1.24.5-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4103b77b8a8225e413107d2349b65eb3c1c52627b5cc5c3c4c1c6a798b218950", size = 110120, upload-time = "2026-07-20T02:04:35.85Z" }, + { url = "https://files.pythonhosted.org/packages/04/6c/1b659b964626694667b3ec01bf4bcff564b73ae7c48ea1fbfe588b78b461/yarl-1.24.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f9f3e9c8a9ecffa57bef8fb4fa19e5fa4d2d8307cf6bac5b1fca5e5860f4ba00", size = 108834, upload-time = "2026-07-20T02:04:37.67Z" }, + { url = "https://files.pythonhosted.org/packages/74/a6/bf48f55c2104e40c15b7b13fad0a5756a11552a55f01c90bc90a66ab81c3/yarl-1.24.5-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0ebc836c47a6477e182169c6a476fc691d12b518894bf7dd2572f0d59f1c7ed", size = 103442, upload-time = "2026-07-20T02:04:39.576Z" }, + { url = "https://files.pythonhosted.org/packages/37/ac/84b273ac133ecdce598fc1f4140a08a1bf2044048bff8106371d207d105f/yarl-1.24.5-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:96d30286dd02679e32a39aa8f0b7498fc847fcda46cfc09df5513e82ce252440", size = 117413, upload-time = "2026-07-20T02:04:41.549Z" }, + { url = "https://files.pythonhosted.org/packages/a4/55/9307e03977d3b290dfa42e5d2bae7b6140808fd1786fbe70cd9d3bee53c5/yarl-1.24.5-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:fd8c81f346b58f45818d09ea11db69a8d5fd34a224b79871f6d44f12cd7977b1", size = 109498, upload-time = "2026-07-20T02:04:43.468Z" }, + { url = "https://files.pythonhosted.org/packages/fc/be/791a6f314cb4c989c19f8e3a10271f1e469c077143915e52474d80f26b4b/yarl-1.24.5-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:5c55256dee8f4b27bfbf636c8363383c7c8db7890c7cba5217d7bd5f5f21dab6", size = 116062, upload-time = "2026-07-20T02:04:45.319Z" }, + { url = "https://files.pythonhosted.org/packages/19/1a/ddd3807b86055010e2f99aa89b3c640effdb65696766c20597f696f48a1c/yarl-1.24.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9f4d8cf085a4c6a40fb97ea0f46938a8df43c85d31f9d45e2a8867ea9293790d", size = 110941, upload-time = "2026-07-20T02:04:47.054Z" }, + { url = "https://files.pythonhosted.org/packages/6d/03/f34271bba042d2187508bf62aea20a14129efb5a1acfc6a2efe7544630b4/yarl-1.24.5-cp310-cp310-win_amd64.whl", hash = "sha256:240cbec09667c1fed4c6cd0060b9ec57332427d7441289a2ed8875dc9fb2b224", size = 97534, upload-time = "2026-07-20T02:04:48.774Z" }, + { url = "https://files.pythonhosted.org/packages/e4/02/ecc8dc31b9f355731e700f8402b8075d2ea1737dbc4baf4abf0f0fc64288/yarl-1.24.5-cp310-cp310-win_arm64.whl", hash = "sha256:8a6987eaad834cb32dd57d9d582225f0054a5d1af706ccfbbdba735af4927e13", size = 93603, upload-time = "2026-07-20T02:04:50.686Z" }, + { url = "https://files.pythonhosted.org/packages/fe/db/3cb5df059756a45761cc3dee8fd25ec82b83a6585ea3542b969fda850f99/yarl-1.24.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2c1fe720934a16ea8e7146175cba2126f87f54912c8c5435e7f7c7a51ef808d3", size = 135043, upload-time = "2026-07-20T02:04:52.39Z" }, + { url = "https://files.pythonhosted.org/packages/44/f8/767d6bd5a03db63bc467df2fb56d6fafeae9667d74aea92cd6af399f828b/yarl-1.24.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c687ed078e145f5fd53a14854beff320e1d2ab76df03e2009c98f39a0f68f39a", size = 96942, upload-time = "2026-07-20T02:04:54.26Z" }, + { url = "https://files.pythonhosted.org/packages/ce/97/10b939c44d7b28d1dbc389cfc7012306d1ea8dba01eaef44b39fffaee52a/yarl-1.24.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:709f1efed56c4a145793c046cd4939f9959bcd818979a787b77d8e09c57a0840", size = 97046, upload-time = "2026-07-20T02:04:56.638Z" }, + { url = "https://files.pythonhosted.org/packages/5b/7a/b410dbe39b6255c55fb2a2bcee96eb844d0789235ddc381a889a90dc72d6/yarl-1.24.5-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:874019bd513008b009f58657134e5d0c5e030b3559bd0553976837adf52fe966", size = 110512, upload-time = "2026-07-20T02:04:58.955Z" }, + { url = "https://files.pythonhosted.org/packages/83/c7/da591971f78a5617e1f21f5699858ebccd836fe181a6493788ffc91ba69b/yarl-1.24.5-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4582acf7ef76482f6f511ebaf1946dae7f2e85ec4728b81a678c01df63bd723", size = 102454, upload-time = "2026-07-20T02:05:00.623Z" }, + { url = "https://files.pythonhosted.org/packages/c4/8e/73b0ed4de47289a78a96045d76d1cfe5e41848bf0da59ce25b2ec87ee05d/yarl-1.24.5-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2cabe6546e41dabe439999a23fcb5246e0c3b595b4315b96ef755252be90caeb", size = 117617, upload-time = "2026-07-20T02:05:02.325Z" }, + { url = "https://files.pythonhosted.org/packages/cf/14/b744747bc4f57a8d55bd744df463457524583e1e9f7538b5ace0346ab92e/yarl-1.24.5-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:17f57620f5475b3c69109376cc87e42a7af5db13c9398e4292772a706ff10780", size = 116135, upload-time = "2026-07-20T02:05:04.05Z" }, + { url = "https://files.pythonhosted.org/packages/66/ca/95aa4d0e5b7ea4f20e4d577c42d001ed9df207569fdb063cc5ed4ebb496b/yarl-1.24.5-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:570fec8fbd22b032733625f03f10b7ff023bc399213db15e72a7acaef28c2f4e", size = 111935, upload-time = "2026-07-20T02:05:05.738Z" }, + { url = "https://files.pythonhosted.org/packages/72/0d/d2ad8d6b147832d177a4e720ba1962fe686eb0913b74503b3eca094b8bba/yarl-1.24.5-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5fede79c6f73ff2c3ef822864cb1ada23196e62756df53bc6231d351a49516a2", size = 110010, upload-time = "2026-07-20T02:05:07.471Z" }, + { url = "https://files.pythonhosted.org/packages/50/18/eb335e4120903903f4865041355ae46256a2406eb2865bc24827f4f27b61/yarl-1.24.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8ccf9aca873b767977c73df497a85dbedee4ee086ae9ae49dc461333b9b79f58", size = 110058, upload-time = "2026-07-20T02:05:09.246Z" }, + { url = "https://files.pythonhosted.org/packages/44/70/97353add32c62ad6f206d948ac5a5ee84398225e534dc6ed6433d1b335b6/yarl-1.24.5-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:ad5d8201d310b031e6cd839d9bac2d4e5a01533ce5d3d5b50b7de1ef3af1de61", size = 103308, upload-time = "2026-07-20T02:05:11.31Z" }, + { url = "https://files.pythonhosted.org/packages/68/39/5e7398d4b6f6b3c9062823ebc60802df5b272e3fe9e788f9734c6ee46c85/yarl-1.24.5-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:841f0852f48fefea3b12c9dfec00704dfa3aef5215d0e3ce564bb3d7cd8d57c6", size = 116898, upload-time = "2026-07-20T02:05:13.099Z" }, + { url = "https://files.pythonhosted.org/packages/e4/c9/09e52f2239e8b96357eccca05915382e4ba5405ebfb623b6036040d99654/yarl-1.24.5-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:9baafc71b04f8f4bb0703b21d6fc9f0c30b346c636a532ff16ec8491a5ea4b1f", size = 109400, upload-time = "2026-07-20T02:05:14.821Z" }, + { url = "https://files.pythonhosted.org/packages/4b/6a/e94133d4c2d1a14d2384310bf3e79d9cf32c9d1eae1c6f034fb80d098fa1/yarl-1.24.5-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d897129df1a22b12aeed2c2c98df0785a2e8e6e0bde87b389491d0025c187077", size = 115934, upload-time = "2026-07-20T02:05:17.78Z" }, + { url = "https://files.pythonhosted.org/packages/4e/3c/34955ed967b976fc38edcbb6d538dee79dbda4cb7fc7f72a0907a7c78e0f/yarl-1.24.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dd625535328fd9882374356269227670189adfcc6a2d90284f323c05862eecbd", size = 112178, upload-time = "2026-07-20T02:05:19.675Z" }, + { url = "https://files.pythonhosted.org/packages/f5/46/d7bd3a8859d47dcfaffd7127af7076032a7da278a9a02e17b5f37bfb6712/yarl-1.24.5-cp311-cp311-win_amd64.whl", hash = "sha256:f4239bbec5a3577ddb49e4b50aeb32d8e5792098262ae2f63723f916a29b1a25", size = 97544, upload-time = "2026-07-20T02:05:21.523Z" }, + { url = "https://files.pythonhosted.org/packages/01/69/c1bfd21e32c638974ea2c542a0b8c53ef1fa9eff336020f5d014f9503ff2/yarl-1.24.5-cp311-cp311-win_arm64.whl", hash = "sha256:3ac6aff147deb9c09461b2d4bbdf6256831198f5d8a23f5d37138213090b6d8a", size = 93359, upload-time = "2026-07-20T02:05:23.493Z" }, + { url = "https://files.pythonhosted.org/packages/1b/84/71d051c850b5af41d168c679d9eb67eb7c55283ac4ee131673edf134bc4e/yarl-1.24.5-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:d693396e5aea78db03decd60aec9ece16c9b40ba00a587f089615ff4e718a81d", size = 136035, upload-time = "2026-07-20T02:05:25.489Z" }, + { url = "https://files.pythonhosted.org/packages/03/4d/8ad27f9a1b7e69313cca5d695b925b48efe51208d3490e0844bae97cabc0/yarl-1.24.5-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:3363fcc96e665878946ad7a106b9a13eac0541766a690ef287c0232ac768b6ec", size = 97642, upload-time = "2026-07-20T02:05:27.429Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b4/05b4131c407006cd1e410e9c6539f16a0945724677e5364447313c15ea3e/yarl-1.24.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9d399bdcfb4a0f659b9b3788bbc89babe63d9a6a65aacdf4d4e7065ff2e6316c", size = 97323, upload-time = "2026-07-20T02:05:29.441Z" }, + { url = "https://files.pythonhosted.org/packages/20/16/e618c875c73e0e39611f20a581b3d5e8d59b8857bf001bee3263044c6deb/yarl-1.24.5-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90333fd89b43c0d08ac85f3f1447593fc2c66de18c3d6378d7125ea118dc7a54", size = 107741, upload-time = "2026-07-20T02:05:31.367Z" }, + { url = "https://files.pythonhosted.org/packages/d9/9a/c4defeaf3ed33fcb346aacf9c6e971a8d4e2bde04a0310e79abb208e7965/yarl-1.24.5-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:665b0a2c463cc9423dd647e0bfd9f4ccc9b50f768c55304d5e9f80b177c1de12", size = 103570, upload-time = "2026-07-20T02:05:33.303Z" }, + { url = "https://files.pythonhosted.org/packages/5f/e7/0e0e0de5865ebd5914537ef486f36c727a59865c3ac0cf5ff1b32aececbf/yarl-1.24.5-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e006d3a974c4ee19512e5f058abedb6eef36a5e553c14812bdeba1758d812e6d", size = 115815, upload-time = "2026-07-20T02:05:35.292Z" }, + { url = "https://files.pythonhosted.org/packages/2b/27/ca56b700cb170aba25a3893b75355b213935657dc5714d2383354a270e62/yarl-1.24.5-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e7d42c531243450ef0d4d9c172e7ed6ef052640f195629065041b5add4e058d1", size = 116025, upload-time = "2026-07-20T02:05:37.503Z" }, + { url = "https://files.pythonhosted.org/packages/d6/d0/d56c859b8222116f5d68459199f48359e0bf121b6f65a69bf329b3602ba0/yarl-1.24.5-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f08c7513ecef5aad65687bfdf6bc601ae9fccd04a42904501f8f7141abad9eb9", size = 109835, upload-time = "2026-07-20T02:05:39.506Z" }, + { url = "https://files.pythonhosted.org/packages/70/a2/3a35557e4d1a79425040eba202ccaf08bdc8717680fc77e2498a1ad2e0a5/yarl-1.24.5-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6c95b17fe34ed802f17e205112e6e10db92275c34fee290aa9bdc55a9c724027", size = 108884, upload-time = "2026-07-20T02:05:41.584Z" }, + { url = "https://files.pythonhosted.org/packages/e4/35/ef4c26356b7913c68983bac2d72a4212b3347af551cb8d250b99b5ed7b7f/yarl-1.24.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:56b149b22de33b23b0c6077ab9518c6dcb538ad462e1830e68d06591ccf6e38b", size = 107308, upload-time = "2026-07-20T02:05:43.697Z" }, + { url = "https://files.pythonhosted.org/packages/d5/91/ff0dc66c2ccf3e0153ab97ff61eabab4400e6a5264af427ab30cd69f1857/yarl-1.24.5-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:a8fe66b8f300da93798025a785a5b90b42f3810dc2b72283ff84a41aaaebc293", size = 103646, upload-time = "2026-07-20T02:05:45.895Z" }, + { url = "https://files.pythonhosted.org/packages/74/f0/33b9271c7f881766359d58266fa0811d2e5210ed860e28da7dc6d7786344/yarl-1.24.5-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:377fe3732edbaf78ee74efdf2c9f49f6e99f20e7f9d2649fda3eb4badd77d76e", size = 115305, upload-time = "2026-07-20T02:05:47.832Z" }, + { url = "https://files.pythonhosted.org/packages/ef/65/fd79fb1868c4a80db8661091de525bf430f63c3bea1b20e8b6a84fc7d359/yarl-1.24.5-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e8ffa78582120024f476a611d7befc123cee59e47e8309d470cf667d806e613b", size = 108404, upload-time = "2026-07-20T02:05:49.604Z" }, + { url = "https://files.pythonhosted.org/packages/ff/ba/dbabe6b262f17a816c70cfc09558dbf03ece3ec76684d02f911a3d3a189c/yarl-1.24.5-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:daba5e594f06114e37db186efd2dd916609071e59daca901a0a2e71f02b142ce", size = 115940, upload-time = "2026-07-20T02:05:51.741Z" }, + { url = "https://files.pythonhosted.org/packages/a5/43/fab2d1dad9d340a268cdde63756a123d069723efff6a372d123fa74a9517/yarl-1.24.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:65be18ec59496c13908f02a2472751d9ef840b4f3fb5726f129306bf6a2a7bba", size = 110006, upload-time = "2026-07-20T02:05:53.554Z" }, + { url = "https://files.pythonhosted.org/packages/c4/27/41eb51bbd1b8d89546b83897cfb0164f1e109304fd408dbb151b639eec0f/yarl-1.24.5-cp312-cp312-win_amd64.whl", hash = "sha256:a929d878fec099030c292803b31e5d5540a7b6a31e6a3cc76cb4685fc2a2f51b", size = 97618, upload-time = "2026-07-20T02:05:55.57Z" }, + { url = "https://files.pythonhosted.org/packages/3c/25/b2553764b3d65db711d8f45416351ec4f420847558eb669edcbcaadf5780/yarl-1.24.5-cp312-cp312-win_arm64.whl", hash = "sha256:7ce27823052e2013b597e0c738b13e7e36b8ccb9400df8959417b052ab0fd92c", size = 93018, upload-time = "2026-07-20T02:05:57.554Z" }, + { url = "https://files.pythonhosted.org/packages/e1/63/64ef361967cc983573149dc1515d531db5da8a4c92d22bb833d59e01b313/yarl-1.24.5-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:79af890482fc94648e8cde4c68620378f7fef60932710fa17a66abc039244da2", size = 135075, upload-time = "2026-07-20T02:05:59.671Z" }, + { url = "https://files.pythonhosted.org/packages/bb/89/55920fd853ce43e608adbc3962456f0d649d6bb15250dc2988321da0fe1c/yarl-1.24.5-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:46c2f213e23a04b93a392942d782eb9e413e6ef6bf7c8c53884e599a5c174dcb", size = 97225, upload-time = "2026-07-20T02:06:01.769Z" }, + { url = "https://files.pythonhosted.org/packages/15/f0/7688d3f2cfff7590df2af38ec46d969f4281a4dddb08a9ad2eafbcdddf98/yarl-1.24.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92ab3e11448f2ff7bf53c5a26eff0edc086898ec8b21fb154b85839ce1d88075", size = 96751, upload-time = "2026-07-20T02:06:03.676Z" }, + { url = "https://files.pythonhosted.org/packages/05/1a/a851a0f94aaaf379dd4f901bfc80f634280bec51eb260b47363e2a4cd62e/yarl-1.24.5-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ebb0ec7f17803063d5aeb982f3b1bd2b2f4e4fae6751226cbd6ba1fcfe9e63ff", size = 107960, upload-time = "2026-07-20T02:06:05.699Z" }, + { url = "https://files.pythonhosted.org/packages/6c/a8/faea066c12f9c77ca0de90641f1655f9dd7b412477bf28c76d692f3aecff/yarl-1.24.5-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:82632daed195dcc8ea664e8556dc9bdbd671960fb3776bd92806ce05792c2448", size = 103500, upload-time = "2026-07-20T02:06:07.556Z" }, + { url = "https://files.pythonhosted.org/packages/fb/9c/1e67084c2a6e2f2db0e3be798328cb3be42c0119b621d25461479a224d21/yarl-1.24.5-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:53e549287ef628fecba270045c9701b0c564563a9b0577d24a4ec75b8ab8040f", size = 115780, upload-time = "2026-07-20T02:06:09.599Z" }, + { url = "https://files.pythonhosted.org/packages/58/86/1f94664e147474337e3359f52012cf3d02f825f694317b178bfba1078c62/yarl-1.24.5-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fcd3b77e2f17bbe4ca56ec7bcb07992647d19d0b9c05d84886dcd6f9eb810afd", size = 115308, upload-time = "2026-07-20T02:06:11.352Z" }, + { url = "https://files.pythonhosted.org/packages/0a/43/8e55ae7538ba5f28ccb3c845c6dd4549cf7016d5992e5326512519107cdd/yarl-1.24.5-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d46b86567dd4e248c6c159fcbcdcce01e0a5c8a7cd2334a0fff759d0fa075b16", size = 110574, upload-time = "2026-07-20T02:06:13.129Z" }, + { url = "https://files.pythonhosted.org/packages/ce/ba/a889ec8765cedcf2ac44dcb02d6a21e4861399b243b263c5f2dde27ee740/yarl-1.24.5-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7f72c74aa99359e27a2ee8d6613fefa28b5f76a983c083074dfc2aaa4ab46213", size = 109914, upload-time = "2026-07-20T02:06:15.243Z" }, + { url = "https://files.pythonhosted.org/packages/9c/c3/e45f821af67b791c2dbbe4a9f4137a1d33f8d386654a05a0c3f47bdfa25d/yarl-1.24.5-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3f45789ce415a7ec0820dc4f82925f9b5f7732070be1dec1f5f23ec381435a24", size = 107712, upload-time = "2026-07-20T02:06:17.443Z" }, + { url = "https://files.pythonhosted.org/packages/02/00/2ab0f42c9857fcb490bfaa6647b14540b53d241ab209f23220b958cc5832/yarl-1.24.5-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6e73e7fe93f17a7b191f52ec9da9dd8c06a8fe735a1ecbd13b97d1c723bff385", size = 104251, upload-time = "2026-07-20T02:06:19.259Z" }, + { url = "https://files.pythonhosted.org/packages/7a/70/709d9a286e98af2c7fd8e4e6cada658b5c0e30d87dd7e2a63c2fb5767217/yarl-1.24.5-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4a36f9becdd4c5c52a20c3e9484128b070b1dcfc8944c006f3a528295a359a9c", size = 115319, upload-time = "2026-07-20T02:06:21.207Z" }, + { url = "https://files.pythonhosted.org/packages/5c/6c/3eaa515142991fe84cfc483ff986492211f1978f90161ccefdbec919d09b/yarl-1.24.5-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:7bcbe0fcf850eae67b6b01749815a4f7161c560a844c769ad7b48fcd99f791c4", size = 109163, upload-time = "2026-07-20T02:06:23.006Z" }, + { url = "https://files.pythonhosted.org/packages/bb/64/711dafce66c323a3144d470547a71c5384c57623308ac8bb5e4b903ac148/yarl-1.24.5-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:24e861e9630e0daddcb9191fb187f60f034e17a4426f8101279f0c475cd74144", size = 115435, upload-time = "2026-07-20T02:06:24.923Z" }, + { url = "https://files.pythonhosted.org/packages/cf/f3/9b9d0e6d84bea851eb1ba99e4bdc755b86fd813e49ec86dfe42f26befdef/yarl-1.24.5-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9335a099ad87287c37fe5d1a982ff392fa5efe5d14b40a730b1ec1d6a41382b4", size = 110691, upload-time = "2026-07-20T02:06:26.973Z" }, + { url = "https://files.pythonhosted.org/packages/86/e4/62a06b7e87c4246ac76b7c2da136f972eb4a3a1fc94abb07e7022d6fdb0a/yarl-1.24.5-cp313-cp313-win_amd64.whl", hash = "sha256:2dbe06fc16bc91502bca713704022182e5729861ae00277c3a23354b40929740", size = 97454, upload-time = "2026-07-20T02:06:29.163Z" }, + { url = "https://files.pythonhosted.org/packages/9e/c9/5fc8025b318ab10db413b61056bd0d95c557a70e8df4210c7511f866329c/yarl-1.24.5-cp313-cp313-win_arm64.whl", hash = "sha256:6b8536851f9f65e7f00c7a1d49ba7f2be0ffe2c11555367fc9f50d9f842410a1", size = 92813, upload-time = "2026-07-20T02:06:31.113Z" }, + { url = "https://files.pythonhosted.org/packages/a9/08/5f3085fef9564217074db9dd8573de1795bc82cde61a7ad10b6a7234a569/yarl-1.24.5-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:2729fcfc4f6a596fb0c50f32090400aa9367774ac296a00387e65098c0befa76", size = 135680, upload-time = "2026-07-20T02:06:33.273Z" }, + { url = "https://files.pythonhosted.org/packages/98/35/ba9436e579bd48a8801f2021d842d9ab4994c26e4c7dd3a4c1f1bcb57a9e/yarl-1.24.5-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ff330d3c30db4eb6b01d79e29d2d0b407a7ecad39cfd9ec993ece57396a2ec0d", size = 97395, upload-time = "2026-07-20T02:06:35.259Z" }, + { url = "https://files.pythonhosted.org/packages/18/a9/a07f76f3c44e02b25cc743af5ef93eef27f7013eadca770451b6a6ccb5db/yarl-1.24.5-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:e42d75862735da90e7fc5a7b23db0c976f737113a54b3c9777a9b665e9cbff75", size = 97223, upload-time = "2026-07-20T02:06:37.216Z" }, + { url = "https://files.pythonhosted.org/packages/77/f7/a9a1d6fa7dd9e388f95b30f6ad3ec4e285f6c8f61f44ce16070c3fcfe414/yarl-1.24.5-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a3732e66413163e72508da9eff9ce9d2846fde51fae45d3605393d3e6cd303e9", size = 108777, upload-time = "2026-07-20T02:06:39.292Z" }, + { url = "https://files.pythonhosted.org/packages/2f/44/e0b86c302471fabd6f02808ecf2ac52b8412b624787849d4bf2cdb466f6f/yarl-1.24.5-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5b8ee53be440a0cffc991a27be3057e0530122548dbe7c0892df08822fce5ede", size = 103119, upload-time = "2026-07-20T02:06:41.456Z" }, + { url = "https://files.pythonhosted.org/packages/d1/16/9c16d180bf8faaf223225eb50e1245870ff1ae0e302a27153988e65c51fd/yarl-1.24.5-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:af3aefa655adb5869491fa907e652290386800ae99cc50095cba71e2c6aefdca", size = 116471, upload-time = "2026-07-20T02:06:43.696Z" }, + { url = "https://files.pythonhosted.org/packages/d2/8d/b219b9df28a02ce95cfbdd41d2f7caa5669d0ff979c1c9975697145e33c5/yarl-1.24.5-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2120b96872df4a117cde97d270bac96aea7cc52205d305cf4611df694a487027", size = 115974, upload-time = "2026-07-20T02:06:45.874Z" }, + { url = "https://files.pythonhosted.org/packages/9b/e8/f20557aca240d88e69850ad1ee91756821d094bb1310565c04d25c6682a2/yarl-1.24.5-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:66410eb6345d467151934b49bfa70fb32f5b35a6140baa40ad97d6436abea2e9", size = 110830, upload-time = "2026-07-20T02:06:47.852Z" }, + { url = "https://files.pythonhosted.org/packages/db/18/199b85109a53eeca64ee19c9cca228287e8e4ab0cc1a09b28f530e65cce0/yarl-1.24.5-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4af7b7e1be0a69bee8210735fe6dcfc38879adfac6d62e789d53ba432d1ffa41", size = 110054, upload-time = "2026-07-20T02:06:49.84Z" }, + { url = "https://files.pythonhosted.org/packages/aa/2f/ed28147f8cd7f48c49367c90713b30a555284b6105a6a56f3a05568da795/yarl-1.24.5-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:fa139875ff98ab97da323cfadfaff08900d1ad42f1b5087b0b812a55c5a06373", size = 108312, upload-time = "2026-07-20T02:06:51.835Z" }, + { url = "https://files.pythonhosted.org/packages/c5/c5/55e16ae0a5c227cea8df1c6871ba57d614a34243146c05729caf2a1bd9c5/yarl-1.24.5-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:0055afc45e864b92729ac7600e2d102c17bef060647e74bca75fa84d66b9ff36", size = 103662, upload-time = "2026-07-20T02:06:54.061Z" }, + { url = "https://files.pythonhosted.org/packages/8d/ea/dbd7c2caec459c9a426f18b02688ecbfb58620d0f6a3422d24769fbaf8ab/yarl-1.24.5-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f0e466ed7511fe9d459a819edbc6c2585c0b6eabde9fa8a8947552468a7a6ef0", size = 116090, upload-time = "2026-07-20T02:06:56.015Z" }, + { url = "https://files.pythonhosted.org/packages/06/84/39ce4ce3059e07fece5fbdbee8c4053406af9aca911ce9fa5f8548aab6af/yarl-1.24.5-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:f141474e85b7e54998ec5180530a7cda99ab29e282fa50e0756d89981a9b43c5", size = 109523, upload-time = "2026-07-20T02:06:57.926Z" }, + { url = "https://files.pythonhosted.org/packages/a9/8b/71ff44137b405c64a7788075669c24010019f57a7464b78c3a6cbee539d9/yarl-1.24.5-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:e2935f8c39e3b03e83519292d78f075189978f3f4adc15a78144c7c8e2a1cba5", size = 116084, upload-time = "2026-07-20T02:06:59.868Z" }, + { url = "https://files.pythonhosted.org/packages/62/c0/423078fdd4042e1862c11f0ffd977a0ffa393783c12bee94685923bc189e/yarl-1.24.5-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:9d1216a7f6f77836617dba35687c5b78a4170afc3c3f18fc788f785ba26565c4", size = 111006, upload-time = "2026-07-20T02:07:01.907Z" }, + { url = "https://files.pythonhosted.org/packages/cf/52/6daa2ee9d95e5c98b8128f8df91eb692eb423ab274b8cf08db52152fad26/yarl-1.24.5-cp314-cp314-win_amd64.whl", hash = "sha256:5ba4f78df2bcc19f764a4b26a8a4f5049c110090ad5825993aacb052bf8003ad", size = 99215, upload-time = "2026-07-20T02:07:03.852Z" }, + { url = "https://files.pythonhosted.org/packages/ec/0e/464a847d7359e0da75dd9fc5c1d1aa35d0159ea31e5f8e66a3c1c29ff3d0/yarl-1.24.5-cp314-cp314-win_arm64.whl", hash = "sha256:9e4e16c73d717c5cf27626c524d0a2e261ad20e46932b2670f64ad5dde23e26f", size = 94566, upload-time = "2026-07-20T02:07:06.074Z" }, + { url = "https://files.pythonhosted.org/packages/e2/55/e03acc4446772660bc335e86e41ef31e4d0d838fd641531a11a5ee33b493/yarl-1.24.5-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:e1ae548a9d901adca07899a4147a7c826bbcc06239d3ce9a59f57886a28a4c88", size = 142533, upload-time = "2026-07-20T02:07:08.284Z" }, + { url = "https://files.pythonhosted.org/packages/ae/71/4acd3a1fc7cf14345cdb302665ecd2097f62c365b4f14ca17d4f37775cf9/yarl-1.24.5-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:ff405d91509d88e8d44129cd87b18d70acd1f0c1aeabd7bc3c46792b1fe2acba", size = 100776, upload-time = "2026-07-20T02:07:10.197Z" }, + { url = "https://files.pythonhosted.org/packages/ff/0b/cfb76b7fe99686db264bff829779a539d923e7564ffd7ef18da6c54c3774/yarl-1.24.5-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:47e98aab9d8d82ff682e7b0b5dded33bf138a32b817fcf7fa3b27b2d7c412928", size = 100913, upload-time = "2026-07-20T02:07:12.357Z" }, + { url = "https://files.pythonhosted.org/packages/8b/3f/7116e782992abbd4fb6948488aec72078895e929a23078290739e8396fce/yarl-1.24.5-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0a658a6d3fafee5c6f63c58f3e785c8c43c93fbc02bf9f2b6663f8185e0971f", size = 106507, upload-time = "2026-07-20T02:07:14.173Z" }, + { url = "https://files.pythonhosted.org/packages/33/90/d4d2d73ee78229cc889872eb8e085d8f5c6f51abdb178409fd9b23cf74fd/yarl-1.24.5-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:4377407001ca3c057773f44d8ddd6358fa5f691407c1ba92210bd3cf8d9e4c95", size = 99219, upload-time = "2026-07-20T02:07:16.019Z" }, + { url = "https://files.pythonhosted.org/packages/3e/fa/a6df1a9bccd644eec00abee0dff4277416222cec435330fd1f2858523ec1/yarl-1.24.5-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7c0494a31a1ac5461a226e7947a9c9b78c44e1dc7185164fa7e9651557a5d9bc", size = 111804, upload-time = "2026-07-20T02:07:18.141Z" }, + { url = "https://files.pythonhosted.org/packages/8a/9e/7b2a1f4bcc20e9447156dd2b1c4d01f70d9df0759025ee7d09a84ffae134/yarl-1.24.5-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a7cff474ab7cd149765bb784cf6d78b32e18e20473fb7bda860bce98ab58e9da", size = 110943, upload-time = "2026-07-20T02:07:20.06Z" }, + { url = "https://files.pythonhosted.org/packages/08/ff/22c92affb0f9b623ca753d27d968b5625b868f12c6378d049d55ae247643/yarl-1.24.5-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cbb833ccacdb5519eff9b8b71ee618cc2801c878e77e288775d77c3a2ced858a", size = 108251, upload-time = "2026-07-20T02:07:22.217Z" }, + { url = "https://files.pythonhosted.org/packages/45/44/5769b96298c1e195fb412997b6090af2a84105cf59c17613558a2d011d1f/yarl-1.24.5-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:82f75e05912e84b7a0fe57075d9c59de3cb352b928330f2eb69b2e1f54c3e1f0", size = 106025, upload-time = "2026-07-20T02:07:24.083Z" }, + { url = "https://files.pythonhosted.org/packages/4c/40/009e8e791fd9762c0e1567e69248acb4f49064597e1680874c16dd8bb798/yarl-1.24.5-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:16a2f5010280020e90f5330257e6944bc33e73593b136cc5a241e6c1dc292498", size = 106573, upload-time = "2026-07-20T02:07:26.248Z" }, + { url = "https://files.pythonhosted.org/packages/20/c6/b7480578f8a0a80946f36ad6df547ecec704f9ba69d2de60f8aa6f1c1cbf/yarl-1.24.5-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:ffcd54362564dc1a30fb74d8b8a6e5a6b11ebd5e27266adc3b7427a21a6c9104", size = 100751, upload-time = "2026-07-20T02:07:28.098Z" }, + { url = "https://files.pythonhosted.org/packages/d4/27/4476f3360b91a48c5cf125e91f59a3bd35299d84a431a258d57f5977bb11/yarl-1.24.5-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0465ec8cedc2349b97a6b595ace64084a50c6e839eca40aa0626f38b8350e331", size = 111643, upload-time = "2026-07-20T02:07:30.88Z" }, + { url = "https://files.pythonhosted.org/packages/4c/4b/5cdd3e5ee944e8af31e52f6cd3d3af5fd7b937e036ccbbba2c9ffebede95/yarl-1.24.5-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:4db9aecb141cb7a5447171b57aa1ed3a8fee06af40b992ffc31206c0b0121550", size = 106312, upload-time = "2026-07-20T02:07:33.06Z" }, + { url = "https://files.pythonhosted.org/packages/18/86/f406b0c2a6f99575de2da671ef47aa06f89a5be83a27a46971c3b86cecdb/yarl-1.24.5-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:f540c013589084679a6c7fac07096b10159737918174f5dfc5e11bf5bca4dfe6", size = 110379, upload-time = "2026-07-20T02:07:35.155Z" }, + { url = "https://files.pythonhosted.org/packages/f0/6c/9f3adfbd3b30b4fa0f7ccb3a83eba2c1152d3fff554d535e640ba0f7ba2b/yarl-1.24.5-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a61834fb15d81322d872eaafd333838ae7c9cea84067f232656f75965933d047", size = 108497, upload-time = "2026-07-20T02:07:37.35Z" }, + { url = "https://files.pythonhosted.org/packages/dd/37/91eb2e5ca883a529c1b390348a74cd9fc0512171727f547ce70bfe02be5c/yarl-1.24.5-cp314-cp314t-win_amd64.whl", hash = "sha256:5c88e5815a49d289e599f3513aa7fde0bc2092ff188f99c940f007f90f53d104", size = 102450, upload-time = "2026-07-20T02:07:39.578Z" }, + { url = "https://files.pythonhosted.org/packages/bf/f4/ed5c402ac8fde4403ed3366c2716bfddc8a6677ebd59f3d62772cc7fe468/yarl-1.24.5-cp314-cp314t-win_arm64.whl", hash = "sha256:cf139c02f5f23ef6532040a30ff662c00a318c952334f211046b8e60b7f17688", size = 97222, upload-time = "2026-07-20T02:07:41.55Z" }, + { url = "https://files.pythonhosted.org/packages/61/02/962c1cbfc401a30c1d034dc67ff395f64b52302c6d62de556c1fca99acc0/yarl-1.24.5-py3-none-any.whl", hash = "sha256:a33700d13d9b7d84fd10947b09ff69fb9a792e519c8cb9764a3ca70baa6c23a7", size = 58612, upload-time = "2026-07-20T02:07:43.461Z" }, +] + [[package]] name = "zstandard" version = "0.25.0"